diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..73f5da6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local +.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + + +#firebase +.firebase + +serviceAccount.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..79e6165 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +
+ +# [Witit: AI powered social media](https://witit-dcc9d.web.app/) + +
+ +![Witit](https://imgur.com/ghWBCmq.png) + +Witit - AI powered social media app that helps creators make more money by renting out their ai models. It has offline storage for images + feed. I have implemented offline storage with the package called Isar with the custom built syncing solution to mongoDB. + +![Witit](https://imgur.com/5ArWUcw.png) + +# Features ✨ + +- **Generate Stunning AI-Generated Images:** Craft stunning images that captivate and inspire with advanced AI technology. + +- **Create Engaging Posts:** Craft compelling posts that resonate with your audience and spark conversation. + +- **Level Up Your AI:** Explore the limitless possibilities of AI to unleash your creativity. + +- **Advanced Creation Tools:** Access a suite of powerful tools to elevate your content creation game. + +- **Earn Cash From Your AI:** Monetize your AI-generated creations and turn your passion into profit. + +- **AI Integration Into Posts:** Embed AI into your posts. + +- **Subscription Includes 20 Photo Creations a Day:** Create up to 20 breathtaking AI-enhanced photos every day. + +- **Get Verified:** Earn the prestigious verification badge to showcase user credibility. + +- **Create and View Content With Fewer Restrictions:** Enjoy more freedom in content creation and viewing. + +- **Transform Ordinary Photos Into Extraordinary AI Masterpieces:** Create AI photos in various photography styles. + +- **Bank Account Linking & Withdraw Funds:** Connect your bank account for transactions and Withdraw funds hassle-free with intuitive withdrawal options. + +- **Verify Identity:** Confirm your identity for security. + +- **Renew Plan:** Renew your subscription plan seamlessly without any hassle. + +- **Send and Receive Credits Seamlessly:** Exchange credits with other users. + +- **Organize With Member Circles:** Create and manage member circles for streamlined collaboration and communication. + +- **Engage With Powerful Messaging:** Stay connected with fellow creators through robust messaging features. + +- **Master Advanced Recreation Settings:** Adjust settings for photo recreations. + +## Tech Stack 💻 + +**Witit is built using the following technologies:** + +- **Next.js:** Witit is built using the Next.js framework, which provides a seamless and efficient development experience for creating modern web applications. + +- **Tailwind CSS:** The user interface of Witit is designed using Tailwind CSS, a highly customizable CSS framework that enables rapid and responsive UI development. + +- **OpenAI API:** Witit leverages the OpenAI API to access state-of-the-art language models that power the core paraphrasing and grammar correction functionality. + +- **Firebase:** Firebase is utilized in the application to provide instant notifications, ensuring real-time communication and updates for users. + +- **API Integration:** API Integration is implemented for interaction with external services, enabling data sharing and functionality enhancement for a comprehensive, interconnected user experience. + +- **Stripe Integration:** Stripe is used in Witit for handling online payments, providing a secure and efficient way to process transactions within the application. + +- **Socket.IO:** Socket.IO enables real-time, bidirectional and event-based communication between the browser and the server. + +- **TypeScript:** Witit is developed using TypeScript, a statically typed superset of JavaScript that enhances code quality, maintainability, and developer productivity. + +- **Next Auth:** Next Auth is utilized for implementing user authentication and authorization in Witit, allowing users to securely access the application and their personalized data. + +- **React:** The user interface components of Witit are built using React, a popular JavaScript library for building interactive and reusable UI components. + +- **HTML:** Witit utilizes HTML for structuring and presenting the application's content, ensuring a semantic and accessible web experience. + +
+ +### Click [here](https://witit-dcc9d.web.app/) to visit the live demo website. + +
diff --git a/api/activity/getActivity.ts b/api/activity/getActivity.ts new file mode 100644 index 0000000..d682f98 --- /dev/null +++ b/api/activity/getActivity.ts @@ -0,0 +1,39 @@ +import { Axios } from "../axiosConfig"; +import { Activity } from "@/types/activity"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; +}; + +type Res = { + status: number; + data: Activity[]; + error: any; +}; + +export const getActivity = async ({ limit, lastDocId, user_id }: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get("/activity", { + params: { + limit, + ...(lastDocId && { lastDocId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + console.log(error); + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/activity/readActivity.ts b/api/activity/readActivity.ts new file mode 100644 index 0000000..d268f64 --- /dev/null +++ b/api/activity/readActivity.ts @@ -0,0 +1,32 @@ +import { Axios } from "../axiosConfig"; +import { Activity } from "@/types/activity"; + +type Props = { + user_id: string; +}; + +type Res = { + status: number; + data: Activity[]; + error: any; +}; + +export const readActivity = async ({ user_id }: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.post("/activity/read", { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/deleteAiModel.ts b/api/ai/deleteAiModel.ts new file mode 100644 index 0000000..142f7cc --- /dev/null +++ b/api/ai/deleteAiModel.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + modelId: number | string; +}; +type Res = { + status: number; + data: string | null; + error: any; +}; + +const deleteAiModel = async ({ user_id, modelId }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const result = await Axios.delete("/ai/model", { + params: { + modelId, + }, + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.message; + } catch (error: any) { + res.status = 200; + res.error = error; + } + return res; +}; + +export default deleteAiModel; diff --git a/api/ai/generateTextToImage.ts b/api/ai/generateTextToImage.ts new file mode 100644 index 0000000..89c6b2e --- /dev/null +++ b/api/ai/generateTextToImage.ts @@ -0,0 +1,66 @@ +import { Axios } from "../axiosConfig"; +import { + AiCharges, + CreationSettings, + GetAiGeneration, + RecreationSettings, + SuperShoot, +} from "@/types/ai"; + +type GenerationBody = { + prompt: string; + modelId: number | string; + numberOfGenerations: number; + superShoot: boolean; + negativePrompt: string[]; + creationSettings: CreationSettings; + recreationSettings: RecreationSettings | null; + postId: string | null; + image: string | null; +}; + +type Props = { + user_id: string; + generationBody: GenerationBody; +}; + +type Res = { + status: number; + data: GetAiGeneration | null; + error: any; +}; + +export const generateAiImage = async ({ user_id, generationBody }: Props) => { + let res: Res = { + status: 0, + data: null, + error: "", + }; + + try { + const result = await Axios.post( + "/ai/runpod/generate", + { + ...generationBody, + ...(!generationBody.image && { + image: undefined, + postId: undefined, + recreationSettings: undefined, + }), + }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/getAiModelApplications.ts b/api/ai/getAiModelApplications.ts new file mode 100644 index 0000000..8f3cd86 --- /dev/null +++ b/api/ai/getAiModelApplications.ts @@ -0,0 +1,42 @@ +import { Axios } from "../axiosConfig"; +import { AiApplication } from "@/types/ai"; + +type Props = { + user_id: string; + limit?: number; + lastDocId?: string; +}; + +type Res = { + status: number; + data: AiApplication[]; + error: any; +}; + +export const getAiModelApplications = async ({ + user_id, + limit, + lastDocId, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get("/user/ai_model/applications", { + params: { + limit, + ...(lastDocId && { lastDocId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/getBaseAndSelfModels.ts b/api/ai/getBaseAndSelfModels.ts new file mode 100644 index 0000000..f92c92f --- /dev/null +++ b/api/ai/getBaseAndSelfModels.ts @@ -0,0 +1,42 @@ +import { Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; +import { GetAiGeneration, BaseModel, UserModel } from "@/types/ai"; + +type Props = { + user_id: string; +}; + +type Data = { + baseModelList: BaseModel[]; + userModelList: UserModel[]; +}; + +type Res = { + status: number; + data: Data; + error: any; +}; + +export const getBaseAndSelfModels = async ({ user_id }: Props) => { + let res: Res = { + status: 0, + data: { baseModelList: [], userModelList: [] }, + error: "", + }; + + try { + const result = await Axios.get("/ai/models", { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/getFriendAiModels.ts b/api/ai/getFriendAiModels.ts new file mode 100644 index 0000000..50eec7b --- /dev/null +++ b/api/ai/getFriendAiModels.ts @@ -0,0 +1,58 @@ +import { Axios } from "../axiosConfig"; +import { BaseModel, FriendModel, UserModel } from "@/types/ai"; + +type LastDoc = { + lastDocId: string; + searchScore: number; +}; + +type Props = { + user_id: string; + search?: string; + lastDoc?: LastDoc; + limit: number; +}; + +type Data = { + friendsModelList: FriendModel[]; +}; + +type Res = { + status: number; + data: Data; + error: any; +}; + +export const getFriendAiModels = async ({ + user_id, + search, + limit, + lastDoc, +}: Props) => { + let res: Res = { + status: 0, + data: { friendsModelList: [] }, + error: "", + }; + + try { + const result = await Axios.get("/ai/friends", { + params: { + search: search && search.length > 2 ? search : "", + ...(lastDoc && lastDoc), + limit, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/getGenerationCharge.ts b/api/ai/getGenerationCharge.ts new file mode 100644 index 0000000..dc0f0d8 --- /dev/null +++ b/api/ai/getGenerationCharge.ts @@ -0,0 +1,53 @@ +import { Axios } from "../axiosConfig"; +import { + AiCharges, + CreationSettings, + GetAiGeneration, + SuperShoot, +} from "@/types/ai"; + +type Props = { + user_id: string; + modelId: string; + creationSettings: CreationSettings; + postId: string | null; +}; + +type Res = { + status: number; + data: { charges: AiCharges; superShoot: SuperShoot } | null; + error: any; +}; + +export const getGenerationCharge = async ({ + user_id, + modelId, + creationSettings, + postId, +}: Props) => { + let res: Res = { + status: 0, + data: null, + error: "", + }; + + try { + const result = await Axios.post( + "/ai/cost_of_generation", + { modelId, creationSettings, postId }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/getGenerations.ts b/api/ai/getGenerations.ts new file mode 100644 index 0000000..989a7c5 --- /dev/null +++ b/api/ai/getGenerations.ts @@ -0,0 +1,39 @@ +import { Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; +import { GetAiGeneration } from "@/types/ai"; + +type Props = { + user_id: string; + limit?: number; + lastDocId?: string; +}; + +type Res = { + status: number; + data: GetAiGeneration[]; + error: any; +}; + +export const getGenerations = async ({ user_id, limit, lastDocId }: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get("/ai/generations", { + params: { + limit, + ...(lastDocId && { lastDocId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/ai/updateAiModelDetails.ts b/api/ai/updateAiModelDetails.ts new file mode 100644 index 0000000..17383bb --- /dev/null +++ b/api/ai/updateAiModelDetails.ts @@ -0,0 +1,33 @@ +import { UserModel } from "@/types/ai"; +import { Axios } from "../axiosConfig"; + +type Res = { + status: number; + data: string; + error: any; +}; + +type Props = { + user_id: string; + data: Partial; +}; + +export const updateAiModelDetails = async ({ user_id, data }: Props) => { + let res: Res = { status: 0, data: "", error: "" }; + + try { + const result = await Axios.patch("/ai/model", data, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/axiosConfig.ts b/api/axiosConfig.ts new file mode 100644 index 0000000..385e543 --- /dev/null +++ b/api/axiosConfig.ts @@ -0,0 +1,10 @@ +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import axios from "axios"; + +export const Axios = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL, + headers: { + api_key: process.env.NEXT_PUBLIC_API_KEY, + is_mobile_app: true, + }, +}); diff --git a/api/circle/getCircleFeed.ts b/api/circle/getCircleFeed.ts new file mode 100644 index 0000000..ae9927d --- /dev/null +++ b/api/circle/getCircleFeed.ts @@ -0,0 +1,50 @@ +import { DiscoverPost, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + category?: string[]; + rank?: number; +}; + +type Res = { + status: number; + data: Post[]; + error: any; +}; + +export const getCircleFeed = async ({ + limit, + lastDocId, + user_id, + category, + rank, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + try { + const result = await Axios.post( + "/circle/feed", + { + limit, + ...(lastDocId && { lastDocId }), + ...(rank && { rank }), + ...(category && { category }), + }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/cricle/getAllFriends.ts b/api/cricle/getAllFriends.ts new file mode 100644 index 0000000..476287a --- /dev/null +++ b/api/cricle/getAllFriends.ts @@ -0,0 +1,55 @@ +import { FriendsList } from "@/types/circle"; +import { Axios } from "../axiosConfig"; + +type Props = { + search: string; + user_id: string | undefined; + searchScore?: number; + lastDocId?: string; + limit: number; +}; + +type data = { + friends: FriendsList[]; +}; + +type res = { + status: number; + data: data | null; + error: any; +}; +const getAllFriends = async ({ + search, + searchScore, + lastDocId, + user_id, + limit, +}: Props) => { + let res: res = { + status: 0, + data: null, + error: "", + }; + + try { + const response = await Axios.get("circle/friends", { + params: { + limit, + search, + ...(lastDocId && { lastDocId }), + ...(searchScore && { searchScore }), + }, + headers: { + user_id, + }, + }); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default getAllFriends; diff --git a/api/cricle/joinOrLeaveCircle.ts b/api/cricle/joinOrLeaveCircle.ts new file mode 100644 index 0000000..38edb79 --- /dev/null +++ b/api/cricle/joinOrLeaveCircle.ts @@ -0,0 +1,55 @@ +import { Axios } from "../axiosConfig"; +import { + AiCharges, + CreationSettings, + GetAiGeneration, + RecreationSettings, + SuperShoot, +} from "@/types/ai"; + +type Props = { + user_id: string; + isJoiningCircle: boolean; + friendId: string; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const joinOrLeaveCircle = async ({ + user_id, + friendId, + isJoiningCircle, +}: Props) => { + let res: Res = { + status: 0, + data: null, + error: "", + }; + + try { + const result = await Axios.post( + "/circle/join-or-leave", + { + friendId, + isJoiningCircle, + }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/discover/getDiscoverFeed.ts b/api/discover/getDiscoverFeed.ts new file mode 100644 index 0000000..34b8dde --- /dev/null +++ b/api/discover/getDiscoverFeed.ts @@ -0,0 +1,48 @@ +import { DiscoverPost, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; +import { Category } from "@/types/common"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + category?: string[]; +}; + +type Res = { + status: number; + data: DiscoverPost[]; + error: any; +}; + +export const getDiscoverFeed = async ({ + limit, + lastDocId, + user_id, + category, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + try { + const result = await Axios.post( + "/discover/feed", + { + limit, + ...(lastDocId && { lastDocId }), + ...(category && { category }), + }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/discover/getDiscoverSearchPostByContent.ts b/api/discover/getDiscoverSearchPostByContent.ts new file mode 100644 index 0000000..f4c5c43 --- /dev/null +++ b/api/discover/getDiscoverSearchPostByContent.ts @@ -0,0 +1,51 @@ +import { DiscoverPost, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + search?: string; +}; + +type Res = { + status: number; + data: DiscoverPost[]; + error: any; +}; + +export const getDiscoverSearchPostByContent = async ({ + limit, + lastDocId, + user_id, + search, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get( + "/discover/content", + + { + params: { + limit, + search: search && search.length > 2 ? search : "", + + ...(lastDocId && { lastDocId }), + // ...(search && { search }), + }, + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/discover/getSimilerFeed.ts b/api/discover/getSimilerFeed.ts new file mode 100644 index 0000000..3dfe594 --- /dev/null +++ b/api/discover/getSimilerFeed.ts @@ -0,0 +1,54 @@ +import { DiscoverPost, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; + description?: string; + limit: number; + lastDocId?: string; + searchScore?: number; +}; + +type Res = { + status: number; + data: DiscoverPost[]; + error: any; +}; + +export const getSimilerFeed = async ({ + user_id, + limit, + lastDocId, + searchScore, + postId, + description, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.post( + "/discover/similar_feed", + { + limit, + ...(lastDocId && { lastDocId }), + ...(searchScore && { searchScore }), + ...(postId && { postId }), + ...(description && { description }), + }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/message/getMessages.ts b/api/message/getMessages.ts new file mode 100644 index 0000000..3406f7d --- /dev/null +++ b/api/message/getMessages.ts @@ -0,0 +1,47 @@ +import { Message } from "./../../types/message"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + receiverId: string | undefined; + limit: number; + lastDocId?: string | null; +}; +type res = { + status: number; + data: Message[] | null; + error: any; +}; + +const getMessages = async ({ + receiverId, + user_id, + limit, + lastDocId, +}: Props) => { + const res: res | null = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.get("message", { + params: { + receiverId, + limit, + ...(lastDocId && { lastDocId }), + }, + headers: { + user_id, + }, + }); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default getMessages; diff --git a/api/message/getrecentmessages.ts b/api/message/getrecentmessages.ts new file mode 100644 index 0000000..1d4f591 --- /dev/null +++ b/api/message/getrecentmessages.ts @@ -0,0 +1,36 @@ +import { RecentMessage } from "@/types/message"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + lastDocId: string | undefined; +}; + +type res = { + status: number; + data: RecentMessage[]; + error: any; +}; +const getrecentmessages = async ({ user_id, lastDocId }: Props) => { + const res: res = { + status: 0, + data: [], + error: "", + }; + try { + const response = await Axios.get("message/recent_messages", { + headers: { + user_id, + ...(lastDocId && { lastDocId }), + }, + }); + res.status = 200; + res.data = response?.data?.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default getrecentmessages; diff --git a/api/message/sendMessage.ts b/api/message/sendMessage.ts new file mode 100644 index 0000000..74288dc --- /dev/null +++ b/api/message/sendMessage.ts @@ -0,0 +1,54 @@ +import { Message } from "@/types/message"; +import { Axios } from "../axiosConfig"; +import { Image } from "@/types/post"; + +type res = { + status: number; + data: Message | null; + error: any; +}; +export type Props = { + messageId: string; + user_id: string | undefined; + receiverId: string; + message: string | null; + image: Partial[] | null; +}; + +const sendMessage = async ({ + messageId, + user_id, + receiverId, + message, + image, +}: Props) => { + const res: res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.post( + "message", + { + messageId, + receiverId, + message, + image, + }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default sendMessage; diff --git a/api/offering/changeOfferingLikeStatus.ts b/api/offering/changeOfferingLikeStatus.ts new file mode 100644 index 0000000..5c26e3d --- /dev/null +++ b/api/offering/changeOfferingLikeStatus.ts @@ -0,0 +1,43 @@ +import { Axios } from "../axiosConfig"; + +type OfferingUpdateLikeData = { + offeringId: string; + isLike: boolean; +}; +type Props = { + offeringUpdateLikeData: OfferingUpdateLikeData; + user_id: string | undefined; +}; +type Res = { + status: number; + data: any; + error: any; +}; +const changeOfferingLikeStatus = async ({ + offeringUpdateLikeData, + user_id, +}: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const result = await Axios.post( + "/offering/changeLikeStatus", + offeringUpdateLikeData, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = result.data.data; + } catch (error) { + res.error = error; + } + return res; +}; + +export default changeOfferingLikeStatus; diff --git a/api/offering/createOffering.ts b/api/offering/createOffering.ts new file mode 100644 index 0000000..34c8701 --- /dev/null +++ b/api/offering/createOffering.ts @@ -0,0 +1,33 @@ +import { Axios } from "../axiosConfig"; +import { CreateOffering, OfferingData } from "@/types/offering"; + +type Props = { + offeringDetails: CreateOffering; + user_id: string | undefined; +}; +type Res = { + status: number; + data: OfferingData | null; + error: any; +}; +const createOffering = async ({ offeringDetails, user_id }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const result = await Axios.post("/offering", offeringDetails, { + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.data; + } catch (error) { + res.error = error; + } + return res; +}; + +export default createOffering; diff --git a/api/offering/deleteOffering.ts b/api/offering/deleteOffering.ts new file mode 100644 index 0000000..131568b --- /dev/null +++ b/api/offering/deleteOffering.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + offeringId: number | string; +}; +type Res = { + status: number; + data: string | null; + error: any; +}; + +const deleteOffering = async ({ user_id, offeringId }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const result = await Axios.delete("/offering", { + params: { + offeringId, + }, + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.message; + } catch (error: any) { + res.status = 200; + res.error = error; + } + return res; +}; + +export default deleteOffering; diff --git a/api/offering/getCreatedOffers.ts b/api/offering/getCreatedOffers.ts new file mode 100644 index 0000000..89273c7 --- /dev/null +++ b/api/offering/getCreatedOffers.ts @@ -0,0 +1,49 @@ +import { Offer } from "@/types/offering"; +import { Axios } from "../axiosConfig"; + +type Res = { + status: number; + data: Offer[]; + error: any; +}; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + status?: "ACCEPTED" | "ALL"; +}; + +export const getCreatedOffers = async ({ + user_id, + limit, + lastDocId, + status, +}: Props) => { + const res: Res = { + status: 0, + data: [], + error: "", + }; + + try { + const result = await Axios.get("/offering/user/offers", { + params: { + limit, + ...(lastDocId && { lastDocId }), + ...(status && { status }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/offering/getOfferNotifications.ts b/api/offering/getOfferNotifications.ts new file mode 100644 index 0000000..9892337 --- /dev/null +++ b/api/offering/getOfferNotifications.ts @@ -0,0 +1,46 @@ +import { Axios } from "../axiosConfig"; +import { Activity } from "@/types/activity"; + +type Res = { + status: number; + data: Activity[]; + error: any; +}; + +type Props = { + user_id: string; + limit: number; + offerId: string; +}; + +export const getOfferNotifications = async ({ + user_id, + limit, + offerId, +}: Props) => { + const res: Res = { + status: 0, + data: [], + error: "", + }; + + try { + const result = await Axios.get("/offering/offer/notifications", { + params: { + limit, + offerId: offerId, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/offering/getOfferings.ts b/api/offering/getOfferings.ts new file mode 100644 index 0000000..a8bc167 --- /dev/null +++ b/api/offering/getOfferings.ts @@ -0,0 +1,49 @@ +import { Post, PostComment } from "@/types/post"; +import { Axios } from "../axiosConfig"; +import { OfferingData } from "@/types/offering"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + lastPendingOffers?: number; + otherUserId?: string; +}; + +type Res = { + status: number; + data: OfferingData[]; + error: any; +}; + +export const getOfferings = async ({ + limit, + lastDocId, + user_id, + lastPendingOffers, + otherUserId, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get("/offering/all", { + params: { + limit, + ...(lastDocId && { lastDocId }), + ...(lastPendingOffers && { lastPendingOffers }), + ...(otherUserId && { otherUserId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/offering/readOfferNotifications.ts b/api/offering/readOfferNotifications.ts new file mode 100644 index 0000000..ef7536b --- /dev/null +++ b/api/offering/readOfferNotifications.ts @@ -0,0 +1,41 @@ +import { Axios } from "../axiosConfig"; +import { Activity } from "@/types/activity"; + +type Res = { + status: number; + data: string | null; + error: any; +}; + +type Props = { + user_id: string; + offerId: string; +}; + +export const readOfferNotifications = async ({ user_id, offerId }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + + try { + const result = await Axios.post( + "/offering/offer/read", + { offerId }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/offering/reportOffer.ts b/api/offering/reportOffer.ts new file mode 100644 index 0000000..373cb8a --- /dev/null +++ b/api/offering/reportOffer.ts @@ -0,0 +1,35 @@ +import { UpateOffering } from "@/types/offering"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + body: { + offerId: string; + reportFor: string; + }; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const reportOffer = async ({ user_id, body }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post("/offering/offer/report", body, { + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/offering/updateOffer.ts b/api/offering/updateOffer.ts new file mode 100644 index 0000000..ff5e7ad --- /dev/null +++ b/api/offering/updateOffer.ts @@ -0,0 +1,35 @@ +import { UpateOffering } from "@/types/offering"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + body: { + offerId: string; + status: "CANCELLED_BY_USER"; + }; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const updateOfferAsUser = async ({ user_id, body }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.patch("/offering/user/offer", body, { + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/offering/updateOffering.ts b/api/offering/updateOffering.ts new file mode 100644 index 0000000..e744a74 --- /dev/null +++ b/api/offering/updateOffering.ts @@ -0,0 +1,35 @@ +import { UpateOffering } from "@/types/offering"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + UpdateOfferingData: UpateOffering; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const updateOffering = async ({ + user_id, + UpdateOfferingData, +}: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.patch("/offering", UpdateOfferingData, { + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/createPost.ts b/api/post/createPost.ts new file mode 100644 index 0000000..3394bfd --- /dev/null +++ b/api/post/createPost.ts @@ -0,0 +1,32 @@ +import { DefaultValues } from "@/types/createPostType"; +import { Axios } from "../axiosConfig"; +type Props = { + postObject: Partial; + user_id: string | undefined; +}; +type Res = { + status: number; + data: null; + error: any; +}; +const createPost = async ({ postObject, user_id }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const result = await Axios.post("/post/create", postObject, { + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.data; + } catch (error) { + res.error = error; + } + return res; +}; + +export default createPost; diff --git a/api/post/deletePost.ts b/api/post/deletePost.ts new file mode 100644 index 0000000..1a8eece --- /dev/null +++ b/api/post/deletePost.ts @@ -0,0 +1,34 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: any; + error: any; +}; + +export const deletePost = async ({ user_id, postId }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.delete("/post/delete", { + params: { + ...(postId && { postId }), + }, + headers: { + user_id, + }, + }); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/doRepost.ts b/api/post/doRepost.ts new file mode 100644 index 0000000..3057394 --- /dev/null +++ b/api/post/doRepost.ts @@ -0,0 +1,35 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: any; + error: any; +}; + +export const doRepost = async ({ user_id, postId }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post( + "/post/repost", + { postId }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getAccessToViewPromptOfPost.ts b/api/post/getAccessToViewPromptOfPost.ts new file mode 100644 index 0000000..30e4404 --- /dev/null +++ b/api/post/getAccessToViewPromptOfPost.ts @@ -0,0 +1,39 @@ +import { PromptDetail, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: PromptDetail | null; + error: any; +}; + +export const getAccessToViewPromptOfPost = async ({ + postId, + user_id, +}: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.get("/post/access-prompt", { + params: { + ...(postId && { postId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data.promptDetails; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getComments.ts b/api/post/getComments.ts new file mode 100644 index 0000000..9693f16 --- /dev/null +++ b/api/post/getComments.ts @@ -0,0 +1,45 @@ +import { Post, PostComment } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + postId?: string; +}; + +type Res = { + status: number; + data: PostComment[]; + error: any; +}; + +export const getComments = async ({ + limit, + lastDocId, + user_id, + postId, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get("/post/comment", { + params: { + limit, + ...(lastDocId && { lastDocId }), + ...(postId && { postId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getOwnerPost.ts b/api/post/getOwnerPost.ts new file mode 100644 index 0000000..3ee386f --- /dev/null +++ b/api/post/getOwnerPost.ts @@ -0,0 +1,36 @@ +import { OwnerPost, Post, PostComment } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: OwnerPost | null; + error: any; +}; + +export const getOwnerPost = async ({ user_id, postId }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.get("post/owner", { + params: { + postId, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getPromptChargeOfPost.ts b/api/post/getPromptChargeOfPost.ts new file mode 100644 index 0000000..783d31b --- /dev/null +++ b/api/post/getPromptChargeOfPost.ts @@ -0,0 +1,36 @@ +import { PromptDetail, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: string; + error: any; +}; + +export const getPromptChargeOfPost = async ({ postId, user_id }: Props) => { + let res: Res = { status: 0, data: "", error: "" }; + + try { + const result = await Axios.get("/post/prompt/charge", { + params: { + ...(postId && { postId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data.creditPerPromptView; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getPromptOfPost.ts b/api/post/getPromptOfPost.ts new file mode 100644 index 0000000..87b53ed --- /dev/null +++ b/api/post/getPromptOfPost.ts @@ -0,0 +1,36 @@ +import { PromptDetail, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: PromptDetail | null; + error: any; +}; + +export const getPromptOfPost = async ({ postId, user_id }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.get("/post/prompt", { + params: { + ...(postId && { postId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data.promptDetails; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getSinglePostById.ts b/api/post/getSinglePostById.ts new file mode 100644 index 0000000..57562aa --- /dev/null +++ b/api/post/getSinglePostById.ts @@ -0,0 +1,36 @@ +import { Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: Post | null; + error: any; +}; + +export const getSinglePostById = async ({ postId, user_id }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.get("/post/single", { + params: { + postId, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/getUserPosts.ts b/api/post/getUserPosts.ts new file mode 100644 index 0000000..facfea9 --- /dev/null +++ b/api/post/getUserPosts.ts @@ -0,0 +1,55 @@ +import { OtherUserPost, Post } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + limit: number; + lastDocId?: string; + profilerId?: string; +}; + +type Res = { + status: number; + data: Post[]; + error: any; +}; + +export const getUserPosts = async ({ + limit, + lastDocId, + user_id, + profilerId, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + let url = "/post/user/all"; + + if (profilerId) { + url = "/post/other-user/all"; + } + + try { + const result = await Axios.get(url, { + params: { + limit, + ...(lastDocId && { lastDocId }), + ...(profilerId && { profilerId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + if (result.data.data.length >= 0) { + res.data = result.data.data; + } else { + res.data = result.data.data.postData; + } + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/likePost.ts b/api/post/likePost.ts new file mode 100644 index 0000000..da52ec0 --- /dev/null +++ b/api/post/likePost.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; + isLiked: boolean; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const likePost = async ({ user_id, postId, isLiked }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post( + "/post/changeLikeStatus", + { postId, isLiked }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/postComment.ts b/api/post/postComment.ts new file mode 100644 index 0000000..22de7aa --- /dev/null +++ b/api/post/postComment.ts @@ -0,0 +1,41 @@ +import { DiscoverPost, Post, PostComment } from "@/types/post"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; + comment: string; +}; + +type Res = { + status: number; + data: PostComment | null; + error: any; +}; + +export const postComment = async ({ user_id, postId, comment }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post( + "/post/comment", + { + ...(postId && { postId }), + ...(comment && { comment }), + }, + { + headers: { + user_id, + }, + } + ); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/reportPost.ts b/api/post/reportPost.ts new file mode 100644 index 0000000..05a95f3 --- /dev/null +++ b/api/post/reportPost.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Data = { + postId: string; + reportFor: string; +}; + +type Props = { + user_id: string; + data: Data; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const reportPost = async ({ user_id, data }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post("/report/post", data, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/updatePost.ts b/api/post/updatePost.ts new file mode 100644 index 0000000..443bb2a --- /dev/null +++ b/api/post/updatePost.ts @@ -0,0 +1,42 @@ +import { DefaultValues } from "@/types/createPostType"; +import { Axios } from "../axiosConfig"; + +type Data = { + category: string[]; + postId: string; + caption: string | null; +}; + +type Props = { + user_id: string | undefined; + data: Data; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const updatePost = async ({ user_id, data }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.patch( + "/post/update", + data , + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/post/viewPost.ts b/api/post/viewPost.ts new file mode 100644 index 0000000..d232015 --- /dev/null +++ b/api/post/viewPost.ts @@ -0,0 +1,35 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + postId: string; +}; + +type Res = { + status: number; + data: any; + error: any; +}; + +export const viewPost = async ({ user_id, postId }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post( + "/post/view", + { postId, isViewed: true }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/public/checkUsernameExist.ts b/api/public/checkUsernameExist.ts new file mode 100644 index 0000000..198ee81 --- /dev/null +++ b/api/public/checkUsernameExist.ts @@ -0,0 +1,17 @@ +import { Axios } from "../axiosConfig"; + +export const checkUsernameExist = async (userName: string) => { + let res = { status: 0, data: { isAvailable: false }, error: "" }; + + try { + const result = await Axios.get("/checkUserNameExist?userName=" + userName); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/public/getProfileDynamicLink.ts b/api/public/getProfileDynamicLink.ts new file mode 100644 index 0000000..a63d9ca --- /dev/null +++ b/api/public/getProfileDynamicLink.ts @@ -0,0 +1,27 @@ +import { Axios } from "../axiosConfig"; + +type Data = { + dynamicProfileLink: string; +}; + +type Res = { + status: number; + data: Data; + error: string; +}; + +export const getProfileDynamicLink = async (userName: string) => { + let res: Res = { status: 0, data: { dynamicProfileLink: "" }, error: "" }; + + try { + const result = await Axios.get("/getProfileLink?userName=" + userName); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/public/getPrompt.ts b/api/public/getPrompt.ts new file mode 100644 index 0000000..2ad1549 --- /dev/null +++ b/api/public/getPrompt.ts @@ -0,0 +1,28 @@ +import { Axios } from "../axiosConfig"; +import { Activity } from "@/types/activity"; + +type Props = { + path: "Man" | "Woman" | "Base" | "Style"; +}; + +type Res = { + status: number; + data: { prompt: string }; + error: any; +}; + +export const getPrompt = async ({ path }: Props) => { + let res: Res = { status: 0, data: { prompt: "" }, error: "" }; + + try { + const result = await Axios.get("/prompt/" + path.toLowerCase()); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/question/askQuestion.ts b/api/question/askQuestion.ts new file mode 100644 index 0000000..4b2f855 --- /dev/null +++ b/api/question/askQuestion.ts @@ -0,0 +1,43 @@ +import { QuestionType } from "@/types/question"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + creatorId: string | undefined; + question: string | null; +}; + +type Res = { + status: number; + data: QuestionType | null; + error: any; +}; +const askQuestion = async ({ user_id, creatorId, question }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.post( + "/question", + { + creatorId, + question, + }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.status; + res.error = error.response.data.error; + } + return res; +}; + +export default askQuestion; diff --git a/api/question/changeQuestionLikeStatus.ts b/api/question/changeQuestionLikeStatus.ts new file mode 100644 index 0000000..a69a2f0 --- /dev/null +++ b/api/question/changeQuestionLikeStatus.ts @@ -0,0 +1,47 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + questionId: string | undefined; + isLike: boolean; +}; + +type Res = { + status: number; + data: null; + error: any; +}; +const changeQuestionLikeStatus = async ({ + user_id, + questionId, + isLike, +}: Props) => { + + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.post( + "/question/changeLikeStatus", + { + questionId, + isLike, + }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.status; + res.error = error.response.data.error; + } + return res; +}; + +export default changeQuestionLikeStatus; diff --git a/api/question/deleteQuestion.ts b/api/question/deleteQuestion.ts new file mode 100644 index 0000000..fb0da30 --- /dev/null +++ b/api/question/deleteQuestion.ts @@ -0,0 +1,39 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + questionId: string | undefined; +}; + +type Res = { + status: number; + data: null; + error: any; +}; +const deleteQuestion = async ({ user_id, questionId }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.delete( + "/question", + + { + params: { questionId }, + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.status; + res.error = error.response.data.error; + } + return res; +}; + +export default deleteQuestion; diff --git a/api/question/getQuestions.ts b/api/question/getQuestions.ts new file mode 100644 index 0000000..9c44164 --- /dev/null +++ b/api/question/getQuestions.ts @@ -0,0 +1,48 @@ +import { QuestionType } from "@/types/question"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + lastDocId?: string | undefined; + otherUserId?: string; + isLastReplyGiven?: boolean; +}; + +type Res = { + status: number; + data: QuestionType[] | null; + error: any; +}; +const getQuestions = async ({ + user_id, + lastDocId, + otherUserId, + isLastReplyGiven, +}: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.get("question/all", { + params: { + limit: 10, + ...(lastDocId && { lastDocId }), + ...(otherUserId && { otherUserId }), + ...(isLastReplyGiven && { isLastReplyGiven }), + }, + headers: { + user_id, + }, + }); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default getQuestions; diff --git a/api/question/updateReply.ts b/api/question/updateReply.ts new file mode 100644 index 0000000..c8d188b --- /dev/null +++ b/api/question/updateReply.ts @@ -0,0 +1,43 @@ +import { QuestionType } from "@/types/question"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string | undefined; + questionId: string | undefined; + reply: string | null; +}; + +type Res = { + status: number; + data: QuestionType[] | null; + error: any; +}; +const updateReply = async ({ user_id, questionId, reply }: Props) => { + const res: Res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.patch( + "/question", + { + questionId, + reply, + }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = response.data.data; + } catch (error: any) { + res.status = error.status; + res.error = error.response.data.error; + } + return res; +}; + +export default updateReply; diff --git a/api/stripe/createCheckoutSession.ts b/api/stripe/createCheckoutSession.ts new file mode 100644 index 0000000..8805133 --- /dev/null +++ b/api/stripe/createCheckoutSession.ts @@ -0,0 +1,48 @@ +import { Result } from "postcss"; +import { Axios } from "../axiosConfig"; +import { Session } from "@/types/stripe"; + +type props = { + credit: number; + url: string; + userid: string | undefined; +}; +type Data = { + credit: number; + redirectUrl: string; +}; +type res = { + status: number; + data: Session; + error: any; +}; +const createCheckoutSession = async ({ credit, url, userid }: props) => { + const data: Data = { + credit, + redirectUrl: url, + }; + const res: res = { + status: 0, + data: { + sessionId: "", + sessionUrl: "", + }, + error: "", + }; + try { + const result = await Axios.post("stripe/create_checkout_session", data, { + headers: { + user_id: userid, + }, + }); + res.status = 200; + res.data = result.data.data; + }catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; + +export default createCheckoutSession; diff --git a/api/stripe/getAmountFromCredit.ts b/api/stripe/getAmountFromCredit.ts new file mode 100644 index 0000000..e2ffa2e --- /dev/null +++ b/api/stripe/getAmountFromCredit.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Props = { + credit: number; + actionType: "ADD" | "WITHDRAWAL"; + user_id: string | undefined; +}; + +type Res = { status: number; data: { amount: number }; error: any }; + +export const getAmountFromCredit = async ({ + credit, + actionType, + user_id, +}: Props) => { + let res: Res = { status: 0, data: { amount: 0 }, error: "" }; + + try { + const result = await Axios.get(`/stripe/get_amount_from_credit`, { + params: { + credit: credit, + actionType: actionType, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response?.status; + res.error = error.response?.data.error; + } + + return res; +}; diff --git a/api/stripe/getBankDashboardUrl.ts b/api/stripe/getBankDashboardUrl.ts new file mode 100644 index 0000000..2f264ca --- /dev/null +++ b/api/stripe/getBankDashboardUrl.ts @@ -0,0 +1,27 @@ +import { Axios } from "../axiosConfig"; + +type Res = { status: number; data: { url: string }; error: any }; + +export const getBankDashboardUrl = async ({ + user_id, +}: { + user_id: string | undefined; +}) => { + let res: Res = { status: 0, data: { url: "" }, error: "" }; + + try { + const result = await Axios.get(`/stripe/get_bank_dashboard_url`, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response?.status; + res.error = error.response?.data.error; + } + + return res; +}; diff --git a/api/stripe/getBankSetupUrl.ts b/api/stripe/getBankSetupUrl.ts new file mode 100644 index 0000000..98b3763 --- /dev/null +++ b/api/stripe/getBankSetupUrl.ts @@ -0,0 +1,36 @@ +import { Axios } from "../axiosConfig"; + +type Res = { status: number; data: { url: string }; error: any }; + +type Props = { + user_id: string | undefined; + returnUrl: string; + refreshUrl: string; +}; +export const getBankSetupUrl = async ({ + user_id, + returnUrl, + refreshUrl, +}: Props) => { + let res: Res = { status: 0, data: { url: "" }, error: "" }; + + try { + const result = await Axios.get(`/stripe/get_bank_satup_url`, { + params: { + returnUrl, + refreshUrl, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response?.status; + res.error = error.response?.data.error; + } + + return res; +}; diff --git a/api/stripe/getBankStatus.ts b/api/stripe/getBankStatus.ts new file mode 100644 index 0000000..cb3fb9b --- /dev/null +++ b/api/stripe/getBankStatus.ts @@ -0,0 +1,23 @@ +import { Axios } from "../axiosConfig"; + +type Res = { status: number; data: { status: string }; error: any }; + +export const getBankStatus = async ({ user_id }: { user_id: string | undefined }) => { + let res: Res = { status: 0, data: { status: "" }, error: "" }; + + try { + const result = await Axios.get(`/stripe/get_bank_status`, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response?.status; + res.error = error.response?.data.error; + } + + return res; +}; diff --git a/api/stripe/sendCredit.ts b/api/stripe/sendCredit.ts new file mode 100644 index 0000000..e47827b --- /dev/null +++ b/api/stripe/sendCredit.ts @@ -0,0 +1,50 @@ +import { Message } from "@/types/message"; +import { Axios } from "../axiosConfig"; + +type CreditDetails = { + creatorId: string; + messageId: string; + user_id: string | undefined; + credit: number; +}; +type res = { + status: number; + data: Message | null; + error: any; +}; + +const sendCredit = async ({ + creatorId, + messageId, + user_id, + credit, +}: CreditDetails) => { + const res: res = { + status: 0, + data: null, + error: "", + }; + try { + const result = await Axios.post( + "message/send_credit", + { + creatorId: creatorId, + messageId: messageId, + credit: credit, + }, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default sendCredit; diff --git a/api/stripe/withdrawCredit.ts b/api/stripe/withdrawCredit.ts new file mode 100644 index 0000000..672b526 --- /dev/null +++ b/api/stripe/withdrawCredit.ts @@ -0,0 +1,34 @@ +import { Axios } from "../axiosConfig"; + +type Details = { + credit: number; + user_id: string | undefined; +}; +type res = { + status: number; + error: any; + data: string; +}; +const withdrawCredit = async ({ credit, user_id }: Details) => { + let res: res = { + status: 0, + error: "", + data: "", + }; + try { + const result = await Axios.get(`stripe/withdraw_credit?credit=${credit}`, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default withdrawCredit; diff --git a/api/support/sendSupportEmail.ts b/api/support/sendSupportEmail.ts new file mode 100644 index 0000000..95e5462 --- /dev/null +++ b/api/support/sendSupportEmail.ts @@ -0,0 +1,35 @@ +import { Axios } from "../axiosConfig"; + +type data = { + message: string; + subject: string; +}; +type Props = { + user_Id: string; + data: data; +}; + +type res = { + status: number; +}; +const sendSupportEmail = async ({ data, user_Id }: Props) => { + const res = { + status: 0, + data: null, + error: "", + }; + try { + const response = await Axios.post("support/contact", data, { + headers: { + user_Id, + }, + }); + res.status = 200; + res.data = response.data.message; + } catch (err: any) { + res.error = err; + } + return res; +}; + +export default sendSupportEmail; diff --git a/api/user/CreateAImodelApplication.ts b/api/user/CreateAImodelApplication.ts new file mode 100644 index 0000000..0594aa6 --- /dev/null +++ b/api/user/CreateAImodelApplication.ts @@ -0,0 +1,39 @@ +import { Aimodel, AimodelRes } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Props = { + data: Aimodel; + user_id: string | undefined; +}; + +const createAImodelApplication = async ({ data, user_id }: Props) => { + const res: AimodelRes = { + status: 0, + data: { + selectedPhotos: [], + audioURL: null, + generationSettings: { + bannedWords: [], + allowGenerationOnModel: false, + creditPerPhoto: 0, + }, + }, + error: "", + }; + try { + const result = await Axios.post("user/ai_model/create_application", data, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res +}; + +export default createAImodelApplication; diff --git a/api/user/CreateVerificationApplication.ts b/api/user/CreateVerificationApplication.ts new file mode 100644 index 0000000..3dfc092 --- /dev/null +++ b/api/user/CreateVerificationApplication.ts @@ -0,0 +1,46 @@ +import React from "react"; +import { Axios } from "../axiosConfig"; +type Doc = { + documentName: string; + documentImages: (string | null)[]; +}; + +type ResType = { + status: number; + data: Doc; + error: any; +}; + +type Props = { + data: Doc; + user_id: string | undefined; +}; +const createVerificationApplication = async ({ data, user_id }: Props) => { + const res: ResType = { + status: 0, + data: { + documentName: "", + documentImages: [], + }, + error: "", + }; + try { + const result = await Axios.post( + "user/verification/create_application", + data, + { + headers: { + user_id, + }, + } + ); + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + return res; +}; + +export default createVerificationApplication; diff --git a/api/user/blockOrUnblockUser.ts b/api/user/blockOrUnblockUser.ts new file mode 100644 index 0000000..e2bb22e --- /dev/null +++ b/api/user/blockOrUnblockUser.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Data = { + blockedUserId: string; + isBlock: boolean; +}; + +type Props = { + user_id: string; + data: Data; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const blockOrUnblockUser = async ({ user_id, data }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post("/block/change_block_status", data, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/createUser.ts b/api/user/createUser.ts new file mode 100644 index 0000000..1ccfb8e --- /dev/null +++ b/api/user/createUser.ts @@ -0,0 +1,46 @@ +import { ReduxUser } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Params = { + data: Record; + user_id: string; +}; + +type Res = { + status: number; + data: ReduxUser | null; + error: string; +}; + +export const createUser = async ({ data, user_id }: Params) => { + let res: Res = { status: 0, data: null, error: "" }; + const body = { + userName: data?.userName, + email: data?.email, + phone: null, + generalInfo: { + firstName: data?.firstName, + lastName: data?.lastName, + profileImage: data?.image || null, + bio: null, + DOB: data?.DOB || null, + describedWord: data?.describedWord, + }, + }; + + try { + const result = await Axios.post("/user", body, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/getBlocklist.ts b/api/user/getBlocklist.ts new file mode 100644 index 0000000..652febd --- /dev/null +++ b/api/user/getBlocklist.ts @@ -0,0 +1,38 @@ +import { BlockedUser, UserBaseInfo } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + limit?: number; + lastDocId?: string; +}; + +type Res = { + status: number; + data: BlockedUser[]; + error: any; +}; + +export const getBlocklist = async ({ user_id, limit, lastDocId }: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + + try { + const result = await Axios.get("/block", { + params: { + ...(lastDocId && { lastDocId }), + ...(limit && { limit }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/getFollowers.ts b/api/user/getFollowers.ts new file mode 100644 index 0000000..f6ac188 --- /dev/null +++ b/api/user/getFollowers.ts @@ -0,0 +1,51 @@ +import { UserBaseInfo } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + search?: string; + limit?: number; + lastDocId?: string; + searchScore?: number; +}; + +type InitialData = { + followers: UserBaseInfo[]; +}; + +type Res = { + status: number; + data: InitialData; + error: any; +}; + +export const getFollowers = async ({ + user_id, + search, + limit, + lastDocId, + searchScore, +}: Props) => { + let res: Res = { status: 0, data: { followers: [] }, error: "" }; + + try { + const result = await Axios.get("/circle/followers", { + params: { + search: !search || search.length < 3 ? "" : search, + ...(lastDocId && { lastDocId, searchScore }), + ...(limit && { limit }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/getFollowings.ts b/api/user/getFollowings.ts new file mode 100644 index 0000000..fbc04fe --- /dev/null +++ b/api/user/getFollowings.ts @@ -0,0 +1,51 @@ +import { UserBaseInfo } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Props = { + user_id: string; + search?: string; + limit?: number; + lastDocId?: string; + searchScore?: number; +}; + +type InitialData = { + followings: UserBaseInfo[]; +}; + +type Res = { + status: number; + data: InitialData; + error: any; +}; + +export const getFollowings = async ({ + user_id, + search, + limit, + lastDocId, + searchScore, +}: Props) => { + let res: Res = { status: 0, data: { followings: [] }, error: "" }; + + try { + const result = await Axios.get("/circle/followings", { + params: { + search: !search || search.length < 3 ? "" : search, + ...(lastDocId && { lastDocId, searchScore }), + ...(limit && { limit }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/getGenerationSetting.ts b/api/user/getGenerationSetting.ts new file mode 100644 index 0000000..e682391 --- /dev/null +++ b/api/user/getGenerationSetting.ts @@ -0,0 +1,38 @@ +import { generationSettingsUnit } from "@/types/user"; +import { Axios } from "../axiosConfig"; + + +type Props = { + creatorId:string, + user_id:string | undefined +} +type Res = { + status:number; + data : generationSettingsUnit | null + error:any +} + +const getGenerationSetting = async({ creatorId,user_id }:Props) => { + let res: Res = { status: 0, data: null,error:""} + + try { + const result = await Axios.get("user/generation-setting", { + params: { + creatorId, + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; + +export default getGenerationSetting; diff --git a/api/user/getOtherUser.ts b/api/user/getOtherUser.ts new file mode 100644 index 0000000..adf6339 --- /dev/null +++ b/api/user/getOtherUser.ts @@ -0,0 +1,36 @@ +import { ReduxUser } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Res = { + status: number; + data: ReduxUser | null; + error: any; +}; + +type Props = { + user_id: string; + profilerId: string; +}; + +export const getOtherUser = async ({ user_id, profilerId }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.get("/user/other-user-profile", { + params: { + ...(profilerId && { profilerId }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/getUser.ts b/api/user/getUser.ts new file mode 100644 index 0000000..df178bc --- /dev/null +++ b/api/user/getUser.ts @@ -0,0 +1,29 @@ +import { ReduxUser } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Res = { + status: number; + data: ReduxUser | null; + error: any; +}; + +export const getUser = async (user_id: string) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.get("/user", { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + console.log(error, "error"); + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/reportUser.ts b/api/user/reportUser.ts new file mode 100644 index 0000000..4aeb3ca --- /dev/null +++ b/api/user/reportUser.ts @@ -0,0 +1,37 @@ +import { Axios } from "../axiosConfig"; + +type Data = { + reportedUserId: string; + reportFor: string; +}; + +type Props = { + user_id: string; + data: Data; +}; + +type Res = { + status: number; + data: null; + error: any; +}; + +export const reportUser = async ({ user_id, data }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.post("/report/user", data, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/searchCreatorUser.ts b/api/user/searchCreatorUser.ts new file mode 100644 index 0000000..72289d5 --- /dev/null +++ b/api/user/searchCreatorUser.ts @@ -0,0 +1,52 @@ +import { SearchCreator } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Res = { + status: number; + data: SearchCreator[]; + error: any; +}; + +type Props = { + user_id: string; + search?: string; + limit?: number; + paginationInfo?: { + lastDocId: string; + searchScore: number; + followerCount: number; + }; +}; +export const searchCreatorUser = async ({ + user_id, + search, + paginationInfo, + limit, +}: Props) => { + let res: Res = { status: 0, data: [], error: "" }; + try { + const result = await Axios.get("/discover/user", { + params: { + search, + ...(paginationInfo && { + lastDocId: paginationInfo.lastDocId, + searchScore: paginationInfo.searchScore, + followerCount: paginationInfo.followerCount, + }), + + ...(limit && { limit }), + }, + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/api/user/updateUser.ts b/api/user/updateUser.ts new file mode 100644 index 0000000..fb763c1 --- /dev/null +++ b/api/user/updateUser.ts @@ -0,0 +1,33 @@ +import { ReduxUser } from "@/types/user"; +import { Axios } from "../axiosConfig"; + +type Props = { + data: Partial; + user_id: string | undefined; +}; + +type Res = { + status: number; + data: ReduxUser | null; + error: any; +}; + +export const updateUser = async ({ data, user_id }: Props) => { + let res: Res = { status: 0, data: null, error: "" }; + + try { + const result = await Axios.patch("/user", data, { + headers: { + user_id, + }, + }); + + res.status = 200; + res.data = result.data.data; + } catch (error: any) { + res.status = error.response.status; + res.error = error.response.data.error; + } + + return res; +}; diff --git a/components/accountSetup/ConfirmPasswordDialog.tsx b/components/accountSetup/ConfirmPasswordDialog.tsx new file mode 100644 index 0000000..121b8e6 --- /dev/null +++ b/components/accountSetup/ConfirmPasswordDialog.tsx @@ -0,0 +1,111 @@ +import { Box, Dialog, Typography } from "@mui/material"; +import { Controller, useForm, useWatch } from "react-hook-form"; +import CustomInputTextField from "../shared/CustomInputTextField"; +import CustomButton from "../shared/CustomButton"; +import CustomLink from "../shared/CustomLink"; +import { LockOutlined, Visibility, VisibilityOff } from "@mui/icons-material"; +import { useEffect, useState } from "react"; +import { LoginToAccount } from "@/service/firebase/auth"; +import getFirebaseErrorMessage from "@/service/firebase/errorCode"; +import { useDispatch } from "react-redux"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomDialog from "../shared/dialog/CustomDialog"; + +type Props = { + email: string; + setIsLoginRequired: any; +}; + +export default function ConfirmPasswordDialog({ + email, + setIsLoginRequired, +}: Props) { + const [passwordVisibility, setPasswordVisibility] = useState(false); + + const { sendNotification } = useAuthContext(); + + useEffect(() => { + if (email) { + setValue("email", email); + } + }, [email]); + + const { + handleSubmit, + control, + setValue, + reset, + setError, + clearErrors, + getValues, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + email: "", + password: "", + }, + mode: "onChange", + }); + + const onSubmit = async (data: Record) => { + const user: any = await LoginToAccount(data?.email, data?.password); + + if (user?.status === 200) { + setIsLoginRequired(false); + } else { + const errorMessage = await getFirebaseErrorMessage(user?.error); + sendNotification({ type: "ERROR", message: errorMessage }); + } + }; + + const OnPasswordVisibility = () => { + setPasswordVisibility(!passwordVisibility); + }; + return ( + + Confirm Your Identity + + Confirm Your Password For {""} + {email} + +
+ ( + } + EndIcon={!passwordVisibility ? : } + EndIconHandleEvent={OnPasswordVisibility} + visibility={passwordVisibility} + /> + )} + /> +
+ + +
+ +
+ ); +} diff --git a/components/accountSetup/CongratulationsBox.tsx b/components/accountSetup/CongratulationsBox.tsx new file mode 100644 index 0000000..bde0949 --- /dev/null +++ b/components/accountSetup/CongratulationsBox.tsx @@ -0,0 +1,35 @@ +import congratulations from "../../utils/images/congratulations.png"; +import Image from "next/image"; +import { Box } from "@mui/system"; +import CustomButton from "@/components/shared/CustomButton"; +import { useRouter } from "next/router"; +import CustomDialog from "../shared/dialog/CustomDialog"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { CustomImagePreview } from "../shared/CustomImagePreview"; + +export default function CongratulationsDialog() { + const router = useRouter(); + const signUpComplete = () => { + router.push(appConstant.pageRoute.create); + }; + + return ( + +
+ +
+

+ Congratulations!
+ You’re all set! +

+ + + signUpComplete()} + type="button" + name="Get Started!" + /> + +
+ ); +} diff --git a/components/aiModelTraining/components/AIRequestSubmitted.tsx b/components/aiModelTraining/components/AIRequestSubmitted.tsx new file mode 100644 index 0000000..debe5b0 --- /dev/null +++ b/components/aiModelTraining/components/AIRequestSubmitted.tsx @@ -0,0 +1,24 @@ +import Lottie from "lottie-react"; +import React from "react"; +import verificationSuccessLottie from "@/utils/lottie/successLottie.json"; + +const AIRequestSubmitted = () => { + return ( +
+
+ +
+

+ Your AI request has been + submitted +

+

+ Your AI model will begin training automatically once we have verified + your request. You can expect to hear back from us regarding the status + within the next 24 hours. +

+
+ ); +}; + +export default AIRequestSubmitted; diff --git a/components/aiModelTraining/components/ChooseClass.tsx b/components/aiModelTraining/components/ChooseClass.tsx new file mode 100644 index 0000000..e684388 --- /dev/null +++ b/components/aiModelTraining/components/ChooseClass.tsx @@ -0,0 +1,180 @@ +import React, { useEffect, useState } from "react"; +import ManVector from "@/utils/images/aiModelTraining/ManVector.svg"; +import WomanVector from "@/utils/images/aiModelTraining/WomanVector.svg"; +import Image from "next/image"; +import { Control, UseFormGetValues } from "react-hook-form/dist/types"; +import { UseFormSetValue, Controller } from "react-hook-form"; +import { Aimodel } from "@/types/user"; +import CustomButton from "@/components/shared/CustomButton"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; + +type Props = { + getValues: UseFormGetValues; + setCurrentState: React.Dispatch>; + currentState: number; + setErrorMessage: React.Dispatch>; + control: Control; +}; + +const ChooseClass = ({ setCurrentState, control, getValues }: Props) => { + const [hoveredClass, setHoveredClass] = useState(null); + const [seletType, setSelectType] = useState("Man"); + const user = useSelector((state: RootState) => state.user); + + useEffect(() => { + setSelectType(getValues("classType")); + }, []); + return ( +
+
+

+ Choose the gender you most biologically resemble this is +
used for AI training purposes. +

+
+ ( +
setHoveredClass(1)} + onMouseLeave={() => setHoveredClass(null)} + onClick={() => { + field.onChange((field.value = "Man")); + setSelectType("Man"); + }} + > +
+ +
+

+ Man +

+ {hoveredClass === 1 || seletType === "Man" ? ( +
+ ) : null} +
+ )} + /> + ( +
setHoveredClass(2)} + onMouseLeave={() => setHoveredClass(null)} + onClick={() => { + field.onChange((field.value = "Woman")); + setSelectType("Woman"); + }} + > +
+ +
+

+ Woman +

+ {hoveredClass === 2 ? ( +
+ ) : null}{" "} +
+ )} + /> +
+ +
+

+ Why are there only two gender options? +

+

+ At Witit, we value diversity and inclusiveness and acknowledge that + gender is a personal and complex aspect of ones identity. If you + choose to participate in one of Witit’s offerings for using AI to + generate likeness, In order to accurately generate your likeness, we + ask for your biological gender or for the gender that best + represents you out of these options. However, we recognize that + gender can encompass a range of identities and expressions, and our + current technology is limited in its ability to capture these + nuances. +

+

+ We use the gender information you provide to help our AI understand + the basic physical characteristics of your appearance, but we + understand that it may not fully represent your gender identity. We + do not showcase your gender anywhere else so you will never be + misrepresented to the public. We are committed to working towards a + future where our technology can better reflect the diversity of + gender identities and expressions, and we appreciate your + understanding in the meantime. +

+
+
+
+

+ AI Yourself Will Cost you{" "} + {450 Credits.} +

+ + +
+ } + type="submit" + name="Next" + className={`w-[60%] py-2 max-w-[370px] mt-2`} + handleEvent={() => setCurrentState((preState) => preState + 1)} + /> +

+
+ + ); +}; + +export default ChooseClass; diff --git a/components/aiModelTraining/components/ModelVerification.tsx b/components/aiModelTraining/components/ModelVerification.tsx new file mode 100644 index 0000000..2853235 --- /dev/null +++ b/components/aiModelTraining/components/ModelVerification.tsx @@ -0,0 +1,181 @@ +import React, { useEffect, useState } from "react"; +import CustomCheckbox from "../../shared/CustomCheckbox"; +import ImagePlaceHolderGalleryIcon from "@/utils/icons/createPost/ImagePlaceHolderGalleryIcon"; +import { ImageState } from "@/types/post"; +import { Aimodel, AimodelRes } from "@/types/user"; +import { UseFormHandleSubmit } from "react-hook-form/dist"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import CheckBoxTickCheckedIcon from "@/utils/icons/shared/CheckBoxTickCheckedIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import InputCropSingleImage from "@/components/shared/cropImage/singleCropImage/InputCropSingleImage"; + +type Props = { + frontSite: ImageState | null; + backSite: ImageState | null; + setBackSite: React.Dispatch>; + setFrontSite: React.Dispatch>; + currentState: number; + handleSubmit: UseFormHandleSubmit; + fillVerificationForm: (data: Aimodel) => Promise; + isButtonLoading: Boolean; + errorMessage: string | null; + setErrorMessage: React.Dispatch>; + setPolicy: React.Dispatch>; +}; + +const ModelVerification = ({ + errorMessage, + frontSite, + backSite, + setBackSite, + setFrontSite, + handleSubmit, + isButtonLoading, + fillVerificationForm, + setPolicy, +}: Props) => { + const [checked, setchecked] = useState(false); + const [isDisabled, setisDisabled] = useState(true); + + const { setCustomDialogType } = useAuthContext(); + useEffect(() => { + if ( + checked?.target?.checked && + frontSite?.imagePreview && + backSite?.imagePreview + ) { + setisDisabled(false); + return; + } + + setisDisabled(true); + }, [frontSite, backSite, checked]); + return ( +
+
+
+

+ We do this to protect you and keep Witit safe. You wouldn’t want + someone creating +
unwanted photos of you on here would you? +

+
+
+
+ + +
+ ), + placeholderTitle: ( + <> +

+ Upload a photo of yourself holding up 3 fingers +

+ + ), + }} + /> +
+
+ + +
+ ), + placeholderTitle: ( + <> +

+ Upload a photo of yourself holding up 3 fingers +

+ + ), + }} + /> +
+
+ +
+
+ } + onChange={setchecked} + /> +
+

+ I agree to be bound by Witit’s{" "} + { + setPolicy("TERMS_OF_SERVICE"); + }} + > + Terms of Service + + , + { + setPolicy("CONTENT_POLICY"); + }} + > + Content Policy + + , and + { + setPolicy("PRIVACY_POLICY"); + }} + > + Privacy Policy. + +

+
+ +
+

+ AI Yourself Will Cost you{" "} + 450 Credits. +

+ { + handleSubmit(fillVerificationForm)(); + }} + /> + +

{errorMessage}

+
+ + ); +}; + +export default ModelVerification; diff --git a/components/aiModelTraining/components/PhotosQualityRange.tsx b/components/aiModelTraining/components/PhotosQualityRange.tsx new file mode 100644 index 0000000..490a506 --- /dev/null +++ b/components/aiModelTraining/components/PhotosQualityRange.tsx @@ -0,0 +1,90 @@ +import React from "react"; +import Slider from "@mui/material/Slider"; +import { theme } from "@/theme"; +import RangeTrueIcon from "@/utils/icons/setting/aiModelTranning/RangeTrueIcon"; +type Props = { + photosLength: number; +}; + +const PhotosQualityRange = ({ photosLength }: Props) => { + const sldiers = [{ offset: 10 }, { offset: 20 }, { offset: 30 }]; + + const SliderComponent = () => { + return ( + <> + {sldiers.map((_, index) => ( + 0 + ? 10 + : 10 + (photosLength - (index + 1) * 10) + } + max={10} + disabled + sx={{ + width: 30, + height: 6, + "& .MuiSlider-thumb": { + display: "none", + }, + "& .MuiSlider-track": { + color: + photosLength <= 10 + ? theme.palette.error.main + : photosLength <= 20 + ? theme.palette.orange.main + : theme.palette.success.main, + border: "0px", + }, + }} + /> + ))} + + ); + }; + + return ( + <> +
+
+

+ Number of qualified photos :{" "} + + {photosLength <= 10 + ? "Low" + : photosLength <= 20 + ? "Medium" + : "Good"} + +

+ ​ +
+
+ +
+
+ +
+
+
+

+ By submitting more photos, you can improve the AI Yourself quality and + make it better. +

+
+ + ); +}; +export default PhotosQualityRange; diff --git a/components/aiModelTraining/components/UploadGuidance.tsx b/components/aiModelTraining/components/UploadGuidance.tsx new file mode 100644 index 0000000..5099ff3 --- /dev/null +++ b/components/aiModelTraining/components/UploadGuidance.tsx @@ -0,0 +1,161 @@ +import React from "react"; +import CheckIcon from "@/utils/icons/shared/CheckIcon"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import highQulity from "@/utils/images/aiModelTraining/highQulity.jpg"; +import varietyOfAngles from "@/utils/images/aiModelTraining/varietyOfAngles.jpg"; +import varietyOfLighting from "@/utils/images/aiModelTraining/varietyOfLighting.jpg"; +import varietyOfLocations from "@/utils/images/aiModelTraining/varietyOfLocations.jpg"; +import blurry from "@/utils/images/aiModelTraining/blurry.jpg"; +import multiplePeople from "@/utils/images/aiModelTraining/multiplePeople.jpg"; +import farAway from "@/utils/images/aiModelTraining/farAway.jpg"; +import CoveringFace from "@/utils/images/aiModelTraining/CoveringFace.jpg"; +import selfies from "@/utils/images/aiModelTraining/selfies.jpg"; +import sitting from "@/utils/images/aiModelTraining/sitting.jpg"; +import landscapeOriantation from "@/utils/images/aiModelTraining/landscapeOriantation.jpg"; +import Image from "next/image"; + +const PhotosToUseList = [ + { name: "High Quality", image: highQulity }, + { name: "Varity of Lighting", image: varietyOfLighting }, + { name: "Varity of Angles", image: varietyOfAngles }, + { name: "Varity of Locations", image: varietyOfLocations }, +]; +const PhotosToAvoidList = [ + { name: "Blurry", image: blurry }, + { name: "Multiple People", image: multiplePeople }, + { name: "Far Away", image: farAway }, + { name: "Covering Your Face", image: CoveringFace }, +]; +const CouldProduceMixedResults = [ + { name: "Selfies", image: selfies }, + { name: "Sitting", image: sitting }, + { name: "Landscape Orientation", image: landscapeOriantation }, +]; + +const UploadGuidance = () => { + return ( +
+
+
+
+ +
+

Photos to use

+
+
+
+ {" "} + {PhotosToUseList.map((photo, index) => { + return ( +
+
+ +
+ +
+ ); + })} +
+ +

+ For optimal results, please use photos similar in style to those + provided in the above section. +

+
+
+ +
+
+
+ +
+

Photos to Avoid

+
+ +
+ {" "} +
+ {PhotosToAvoidList.map((photo, index) => { + return ( +
+
+ +
+ +
+ ); + })} +
+

+ For optimal results, please avoid using photos that are similar in + style to those provided in the above section. +

+
+
+ +
+
+
+ ! +
+

Photos to Avoid

+
+
+
+ {CouldProduceMixedResults.map((photo, index) => { + return ( +
+ {index < CouldProduceMixedResults.length - 1 ? ( +
+
+ ! +
+ +
+ ) : null} +
+ ); + })} +
+
+
+ ! +
+ +

+ {CouldProduceMixedResults[2].name} +

+
+

+ Utilizing photos similar in style to those provided in the above + section may yield mixed results.photos similar in style to those + provided in the above section. +

+
+
+
+ ); +}; + +export default UploadGuidance; + +const PhotoGuideItem = ({ photo }: any) => { + return ( +
+ +

+ {photo.name} +

+
+ ); +}; diff --git a/components/aiModelTraining/index.tsx b/components/aiModelTraining/index.tsx new file mode 100644 index 0000000..fa83106 --- /dev/null +++ b/components/aiModelTraining/index.tsx @@ -0,0 +1,382 @@ +import React, { useEffect, useState } from "react"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import UploadGuidance from "./components/UploadGuidance"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import ChooseClass from "./components/ChooseClass"; +import { useAuthContext } from "@/context/AuthContext"; +import ModelVerification from "./components/ModelVerification"; +import AIRequestSubmitted from "./components/AIRequestSubmitted"; +import CustomButton from "../shared/CustomButton"; +import { useDispatch, useSelector } from "react-redux"; +import { Divider } from "@mui/material"; +import { theme } from "@/theme"; +import { ImageInfo } from "@/types"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { ImageState } from "@/types/post"; +import { RootState } from "@/redux/store"; +import { Aimodel } from "@/types/user"; +import { useForm } from "react-hook-form"; +import createAImodelApplication from "@/api/user/CreateAImodelApplication"; +import TermsOfServices from "../footerDialogs/TermsOfServices"; +import PrivacyPolicy from "../footerDialogs/PrivacyPolicy"; +import ContentPolicy from "../footerDialogs/ContentPolicy"; +import ModifyImages from "../shared/cropImage/multipleCropImage/ModifyImages"; +import InputCropMultiImages from "../shared/cropImage/multipleCropImage/InputCropMultiImages"; +import PhotosQualityRange from "./components/PhotosQualityRange"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; + +const AIYourselfSteps = [ + "Guidance", + "Upload Images", + "Select Gender", + "Verification", +]; + +type Props = { + setIsTrainModelDialogOpen: React.Dispatch>; +}; + +const AIModelTraining = ({ setIsTrainModelDialogOpen }: Props) => { + const [currentState, setCurrentState] = useState(0); + const [createPostImages, setCreatePostImages] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + const [frontSite, setFrontSite] = useState(null); + const [backSite, setBackSite] = useState(null); + const [tabCurrentState, setTabCurrentState] = useState(0); + const [errorMessage, setErrorMessage] = useState(null); + const [isButtonLoading, setIsButtonLoading] = useState(false); + const [policy, setPolicy] = useState(null); + + const user = useSelector((state: RootState) => state.user); + const { setCustomDialogType, customDialogType } = useAuthContext(); + const { firebaseUser } = useAuthContext(); + const dispatch = useDispatch(); + + const defaultValues = { + selectedPhotos: [], + verificationImages: [], + audioURL: null, + generationSettings: { + bannedWords: [], + allowGenerationOnModel: false, + creditPerPhoto: 0, + }, + classType: "Man", + }; + + const { + control, + getValues, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues, + }); + + useEffect(() => { + if (createPostImages.length > 0) { + setCurrentState(2); + } + }, [createPostImages]); + + useEffect(() => { + if (currentState === 0) { + setTabCurrentState(currentState); + } else if (currentState === 1 || currentState === 2) { + setTabCurrentState(1); + } else if (currentState) { + setTabCurrentState(currentState - 1); + } + }, [currentState]); + + const fillVerificationForm = async (data: Aimodel) => { + const getFirebaseImages: Blob[] = []; + + setIsButtonLoading(true); + setErrorMessage(null); + + for (const val of createPostImages) { + const imageInfo = val.image.croppedImageSrc; + const response = await fetch(imageInfo); + const file = await response.blob(); + getFirebaseImages.push(file); + } + + const selectedPhotosList = await Promise.all( + getFirebaseImages.map((file) => { + const folderName = "update_ai_images"; + return file + ? uploadImageToStorage({ + folderName, + file, + metadata: { + userId: firebaseUser?.uid, + }, + }) + : null; + }) + ); + + data.selectedPhotos = selectedPhotosList; + + const figerphotolist = [frontSite?.file, frontSite?.file]; + + const folderName = "creator_verification_image"; + + const verificationImagesList = await Promise.all( + figerphotolist.map((file) => { + return file + ? uploadImageToStorage({ + folderName, + file, + metadata: { + userId: firebaseUser?.uid, + }, + }) + : null; + }) + ); + + data.verificationImages = verificationImagesList; + const response = await createAImodelApplication({ + data, + user_id: user?.userId, + }); + setIsButtonLoading(false); + if (response.status === 200 && user?.credit && user) { + setCurrentState(5); + return; + } + if (response.status === 403) { + setCustomDialogType("CREDITS-GETCREDITS"); + setErrorMessage(response.error); + return; + } + return response; + }; + + return ( + <> + +
e.preventDefault()} className="w-full"> +
+
+
+
+

AI Yourself

+
+
{ + setIsTrainModelDialogOpen(false); + }} + > + +
+
+ + +
+ {AIYourselfSteps.map((step, index) => { + return ( +
= index && "cursor-pointer" + }`} + onClick={() => { + if (currentState > index && index != 0) { + setCurrentState(index + 1); + } else if (index === 0) { + setCurrentState(index); + } + setErrorMessage(null); + }} + > +

+ {index + 1} +

+

{step}

+
+ ); + })} +
+ +
= 3 && "overflow-y-hidden h-[595px]"} + rounded-lg `} + > + {currentState === 0 ? : null} + {currentState === 1 ? ( +
+
+ +
+
+ ) : null} + + {currentState == 2 ? ( +
setErrorMessage(null)} + > +

+ Please{" "} + + Upload 10 to 30 Images + + , We will used to generate your model only. +

+ +
+ ) : null} + + {currentState === 3 ? ( + + ) : null} + {currentState === 4 ? ( + + ) : null} + {currentState === 5 ? : null} +
+ + {currentState === 0 || + currentState === 1 || + currentState === 2 ? ( + <> + {currentState == 2 && ( + + )} +
+

+ AI Yourself Will Cost you{" "} + { + + 450 Credits. + + } +

+ + +
+ } + type="submit" + name="Next" + className={`w-[60%] py-2 max-w-[370px]`} + handleEvent={() => { + if (currentState < 1) { + setCurrentState((preState) => preState + 1); + return; + } + if (currentState === 2) { + createPostImages.length >= 10 + ? (setCurrentState((preState) => preState + 1), + setErrorMessage(null)) + : setErrorMessage( + "Please select atlest 10 to 30 pictures" + ); + setCustomDialogType(null); + return; + } + }} + /> +

+ {errorMessage} +

+
+ + ) : null} +
+ +
+
+ + + {customDialogType === "TERMS_OF_SERVICE" ? ( + { + setPolicy(null); + }} + /> + ) : customDialogType === "PRIVACY_POLICY" ? ( + { + setPolicy(null); + }} + /> + ) : customDialogType === "CONTENT_POLICY" ? ( + { + setPolicy(null); + }} + /> + ) : null} + + + ); +}; + +export default AIModelTraining; diff --git a/components/circle/CirclePost.tsx b/components/circle/CirclePost.tsx new file mode 100644 index 0000000..a2665e9 --- /dev/null +++ b/components/circle/CirclePost.tsx @@ -0,0 +1,648 @@ +import React, { useEffect, useState } from "react"; +import VerificationIcon from "@/utils/icons/circle/VerifiedIcon"; +import SynchronizeIcon from "@/utils/icons/circle/SynchronizeIcon"; +import CommentQuestionIcon from "@/utils/icons/shared/CommentQuestionIcon"; +import CommentMessageIcon from "@/utils/icons/shared/CommentMessageIcon"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import { Checkbox, CircularProgress, Divider, IconButton } from "@mui/material"; +import { theme } from "@/theme"; +import { Favorite, FavoriteBorder } from "@mui/icons-material"; +import { DropDownItem } from "@/types"; +import ShareIcon from "@/utils/icons/shared/ShareIcon"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; +import { IconDropDown } from "../shared/dropDown/IconDropDown"; +import { getRecentTimeFromTimeStamp } from "@/service/shared/getRecentTimeFromTimeStamp"; +import { formatLargeNumber } from "@/service/shared/formatLargeNumber"; +import ThreeVerticalDots from "@/utils/icons/circle/ThreeVerticalDots"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { CustomImagePreview } from "../shared/CustomImagePreview"; +import { Blurhash } from "react-blurhash"; +import { addViewedNSFWPost } from "@/redux/slices/viewedNSFWSlice"; +import VisibilityOffIcon from "@/utils/icons/shared/VisibilityOffIcon"; +import CustomButton from "../shared/CustomButton"; +import DeleteIcon from "@/utils/icons/shared/DeleteIcon"; +import { Post, PromptDetail } from "@/types/post"; +import { UserBaseInfo } from "@/types/user"; +import { useAuthContext } from "@/context/AuthContext"; +import { set } from "react-hook-form"; +import { useRouter } from "next/router"; +import CopyIcon from "@/utils/icons/shared/CopyIcon"; +import LinkCopyIcon from "@/utils/icons/shared/LinkCopyIcon"; +import EditIcon from "@/utils/icons/shared/EditIcon"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import ReportDialog from "../shared/ReportDialog"; + +type Props = { + postId?: string; + selectedPost: Post; + similarPostId?: string | null; + setSelectedImageIndex: React.Dispatch>; + setDeletingPostIndex: React.Dispatch>; + setReportingPostIndex: React.Dispatch>; + handleChange: (event: React.ChangeEvent) => void; + handleRepost: (event: React.MouseEvent) => void; + handleEdit?: (selectedPost: Post) => void; + handlePostClicked: ( + event: React.MouseEvent, + postId: string + ) => void; + setCreditDialogInfo: React.Dispatch< + React.SetStateAction<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null> + >; + creditDialogInfo: { + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null; + + promptDetails: PromptDetail | null; +}; + +const CirclePost = ({ + handleEdit, + handleChange, + handleRepost, + selectedPost, + postId, + setSelectedImageIndex, + setReportingPostIndex, + setDeletingPostIndex, + setCreditDialogInfo, + creditDialogInfo, + promptDetails, + handlePostClicked, +}: Props) => { + const dispatch = useDispatch(); + const { sendNotification } = useAuthContext(); + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + + const isViewdPost = viewedNsfwList.find( + (post) => post === selectedPost.postId + ); + const [isNSFWVisible, setIsNSFWVisible] = useState(false); + const [menuList, setmenuList] = useState([]); + const [recentInfo, setRecentInfo] = useState<{ + like: { isLiked: boolean; count: number }; + repost: { isReposted: boolean; count: number }; + postId: string; + }>({ + like: { + isLiked: selectedPost.userActivity.isLiked, + count: selectedPost.counts.like, + }, + repost: { + isReposted: selectedPost.userActivity.isReposted, + count: selectedPost.counts.repost, + }, + postId: selectedPost.postId, + }); + const [isLoading, setIsLoading] = useState(false); + + const handleCopyLink = () => { + navigator.clipboard.writeText( + window.location.protocol + + "//" + + window.location.host + + `/discover/post?postId=${selectedPost.postId}` + ); + sendNotification({ type: "SUCCESS", message: "Post Coppied!!" }); + }; + + const handleItemSelect = (type: string) => { + if (selectedPost) { + if (type === "EDIT") { + if (handleEdit) { + handleEdit(selectedPost); + } + } + if (type === "DELETE") { + setDeletingPostIndex(selectedPost.postId); + } + if (type === "COPY") { + handleCopyLink(); + } + if (type === "REPORT") { + setReportingPostIndex(selectedPost.postId); + } + } + }; + + const handleLikeChange = (e: React.ChangeEvent) => { + setRecentInfo((prev) => { + return { + isUpdated: true, + postId: selectedPost.postId, + like: { + isLiked: !prev.like.isLiked ? true : false, + count: !prev.like.isLiked + ? prev.like.count + 1 + : prev.like.count !== 0 + ? prev.like.count - 1 + : 0, + }, + repost: { + isReposted: prev.repost.isReposted, + count: prev.repost.count, + }, + }; + }); + handleChange(e); + }; + + useEffect(() => { + if (selectedPost) { + if (isViewdPost) { + setIsNSFWVisible(false); + } else { + setIsNSFWVisible(selectedPost.category.includes("NSFW")); + } + } + }, [selectedPost, isViewdPost]); + + useEffect(() => { + const baseMenu = [ + { + startIcon: ( +
+ +
+ ), + title: "Copy Post Link", + actionType: "COPY", + }, + ]; + if (selectedPost && selectedPost.postedBy.userId === user?.userId) { + baseMenu.push({ + startIcon: , + title: "Edit", + actionType: "EDIT", + }); + baseMenu.push({ + startIcon: , + title: "Delete", + actionType: "DELETE", + }); + } else { + baseMenu.push({ + startIcon: , + title: "Report", + actionType: "REPORT", + }); + } + setmenuList(baseMenu); + + if ( + (selectedPost.userActivity.isLiked !== recentInfo.like.isLiked || + selectedPost.userActivity.isReposted !== + recentInfo.repost.isReposted) && + selectedPost.postId !== "" + ) { + setRecentInfo(() => { + return { + postId: selectedPost.postId, + like: { + isLiked: selectedPost.userActivity.isLiked, + count: selectedPost.counts.like, + }, + + repost: { + isReposted: selectedPost.userActivity.isReposted, + count: selectedPost.counts.repost, + }, + }; + }); + } + }, [selectedPost]); + + useEffect(() => { + if (selectedPost.postId === recentInfo.postId) { + } + }, [selectedPost, recentInfo]); + + useEffect(() => { + setIsLoading(false); + if (promptDetails) { + } + }, [promptDetails]); + + useEffect(() => { + if (creditDialogInfo) { + if (creditDialogInfo === null && promptDetails === null) { + setIsLoading(false); + } else if ( + creditDialogInfo?.isPostAccessed === true && + creditDialogInfo && + promptDetails === null + ) { + setIsLoading(true); + } else if ( + creditDialogInfo?.isPostAccessed === true && + creditDialogInfo && + promptDetails + ) { + setIsLoading(false); + } + if ( + creditDialogInfo?.isPostAccessed === false && + creditDialogInfo && + promptDetails === null + ) { + setIsLoading(false); + } + } + }, [creditDialogInfo, promptDetails]); + + return ( + <> + {selectedPost ? ( +
+
+
+
{ + e.stopPropagation(); + router.push( + redirectTouserProfile( + selectedPost.postedBy.userId, + user?.userId + ) + ); + }} + > + +
+ +
+
+

{ + e.stopPropagation(); + router.push( + redirectTouserProfile( + selectedPost.postedBy.userId, + user?.userId + ) + ); + }} + > + {selectedPost.postedBy.userName} +

+ {selectedPost.postedBy.userType === "VERIFIED" ? ( +
+ +
+ ) : null} +
+ {selectedPost.repostedBy === null && + selectedPost.generatedFrom === null ? null : ( +
{ + e.stopPropagation(); + }} + > + {selectedPost.generatedFrom?.postId !== null && + selectedPost.generatedFrom !== null ? ( +
+ +
+ ) : null} + +
+ {selectedPost.repostedBy !== null ? ( + <> + Reposted by{" "} + { + e.stopPropagation(); + if ( + selectedPost.repostedBy && + selectedPost.repostedBy.userId !== user?.userId + ) { + router.push( + redirectTouserProfile( + selectedPost.repostedBy.userId, + user?.userId + ) + ); + } else { + if (user) + //to returen same profile + router.push("/profile"); + } + }} + > + {selectedPost.repostedBy.userName} + + + ) : null} + {selectedPost.generatedFrom?.postId !== null && + selectedPost.generatedFrom !== null ? ( + <> + Recreated from Here + + ) : null} +
+
+ )} +
+
+
+ + +
+ } + handleItemSelect={handleItemSelect} + /> +
+ {getRecentTimeFromTimeStamp(selectedPost.createdAt)} +
+
+
+ {selectedPost.caption && selectedPost.caption.length > 0 ? ( +

+ {selectedPost.caption} +

+ ) : null} + {/*

+ {selectedPost.caption} +

*/} +
handlePostClicked(e, selectedPost.postId)} + > + {selectedPost.image.map((postImage, index) => { + if (index < 5) { + return ( +
{ + setSelectedImageIndex(index); + }} + className={`${ + selectedPost.image.length === 1 + ? "col-span-6 row-span-4" + : selectedPost.image.length === 2 + ? "col-span-3 row-span-4" + : selectedPost.image.length === 3 + ? index === 0 + ? "col-span-3 row-span-4" + : "col-span-3 row-span-2" + : selectedPost.image.length === 4 + ? "col-span-3 row-span-2" + : selectedPost.image.length === 5 + ? index === 0 || index === 1 + ? "col-span-3 row-span-2" + : "col-span-2 row-span-2" + : index === 0 || index === 1 + ? "col-span-3 row-span-2" + : "col-span-2 row-span-2" + } `} + > +
+ {selectedPost.image.length > 5 && index === 4 ? ( +
+ +{selectedPost.image.length - 5} +
+ ) : null} + +
5 + ? "opacity-30" + : "opacity-100" + }`} + > +
+ +
+ {!isNSFWVisible ? ( + + ) : null} +
+
+
+ ); + } + })} + {isNSFWVisible ? ( +
+
+ +
+
+
+ +
+

NSFW

+

+ Sensitive content, viewer discretion advised. +

+ ) => { + e.stopPropagation(); + dispatch(addViewedNSFWPost({ postId: postId })); + setIsNSFWVisible(!isNSFWVisible); + }} + /> +
+
+ ) : null} +
+ +
+

+ {formatLargeNumber(selectedPost.counts.view)} Views +

+ {isLoading && creditDialogInfo?.postId === selectedPost.postId ? ( +
+ +
+ ) : null} + {(selectedPost.isPromptAvailable && + creditDialogInfo?.postId !== selectedPost.postId) || + (!isLoading && creditDialogInfo) ? ( + { + e.stopPropagation(); + setIsLoading(true); + + setCreditDialogInfo({ + userInfo: selectedPost.postedBy, + postId: selectedPost.postId, + isPostAccessed: selectedPost.userActivity + .isAccessToViewPrompt + ? true + : false, + }); + }} + > + + + ) : null} +
+ + +
+
+
+
+ { + e.stopPropagation(); + }} + onChange={handleLikeChange} + icon={} + checkedIcon={} + checked={ + selectedPost.postId === recentInfo.postId + ? recentInfo.like.isLiked + : selectedPost.userActivity.isLiked + } + /> +
+

+ {formatLargeNumber( + selectedPost.postId === recentInfo.postId + ? recentInfo.like.count + : selectedPost.counts.like + )} +

+
+
+
+ +
+

+ {formatLargeNumber(selectedPost.counts.comment)} +

+
+ + {selectedPost.postedBy.userId !== user?.userId ? ( +
+
+ +
+

+ {formatLargeNumber( + selectedPost.postId === recentInfo.postId + ? recentInfo.repost.count + : selectedPost.counts.repost + )} +

+
+ ) : null} +
+ {selectedPost.allowGenerations ? ( +
+
+ +
+ {/*

+ {formatLargeNumber(selectedPost.counts.recreation)} +

*/} +
+ ) : null} +
+ + ) : null} + + ); +}; + +export default CirclePost; diff --git a/components/circle/CirclePostInfoDialog/components/CurrentUserCommentItem.tsx b/components/circle/CirclePostInfoDialog/components/CurrentUserCommentItem.tsx new file mode 100644 index 0000000..6c1317c --- /dev/null +++ b/components/circle/CirclePostInfoDialog/components/CurrentUserCommentItem.tsx @@ -0,0 +1,121 @@ +import { useAuthContext } from "@/context/AuthContext"; +import Image from "next/image"; +import React, { useEffect, useState } from "react"; +import tempuser from "@/utils/images/tempuser.jpg"; +import { PostComment } from "@/types/post"; +import { type } from "os"; +import { getRecentTimeFromTimeStamp } from "@/service/shared/getRecentTimeFromTimeStamp"; +import { theme } from "@/theme"; +import { useRouter } from "next/router"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; + +type Props = { + comment: PostComment; +}; +const CurrentUserCommentItem = ({ comment }: Props) => { + const router = useRouter(); + const user = useSelector((state: RootState) => state.user); + + const [initialTime, setInitialTime] = useState(""); + + useEffect(() => { + setInitialTime(getRecentTimeFromTimeStamp(comment?.createdAt)); + }, [comment]); + return ( +
+
+
+

{initialTime}

+
+

+ {comment.comment.split(" ").map((word, index) => { + const match = word.match(/@(\S+)/); + + if ( + match && + comment.tag.find((text) => text.userName === match[1])?.userId + ) { + const username = match[1]; + return ( + { + comment?.tag?.map((tagInfo, index) => { + if (tagInfo.userName === username && tagInfo.userId) { + router.push( + redirectTouserProfile(tagInfo.userId, user?.userId) + ); + } + }); + }} + > + {word}{" "} + + ); + } else { + return {word} ; + } + })} + {/* {comment.comment.split(" ").map((word, index) => { + if (word.startsWith("@")) { + return ( + { + comment?.tag?.map((tagInfo, index) => { + if (tagInfo.userName === word.split("@")[1]) { + router.push( + redirectTouserProfile(tagInfo.userId, user?.userId) + ); + } + }); + }} + > + {word}{" "} + + ); + } else { + return {word} ; + } + })} */} +

+
+ //
+ //
+ // + //
+ + //
+ //
+ //

{comment?.commenter?.userName}

+ //
+ //
+ //

+ // {getRecentTimeFromTimeStamp(comment?.createdAt)} + //

+ //
+ //
+ + //

+ // {comment.comment} + //

+ //
+ // {customDialogType === "CREDITS-VIEWPROMPT" ? : null} + //
+ ); +}; + +export default CurrentUserCommentItem; diff --git a/components/circle/CirclePostInfoDialog/components/FriendInfoItem.tsx b/components/circle/CirclePostInfoDialog/components/FriendInfoItem.tsx new file mode 100644 index 0000000..97bb1bb --- /dev/null +++ b/components/circle/CirclePostInfoDialog/components/FriendInfoItem.tsx @@ -0,0 +1,35 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { FriendsList } from "@/types/circle"; +import { UserType } from "@/types/user"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import React from "react"; + +type Props = { + friendInfo: FriendsList; +}; +const FriendInfoItem = ({ friendInfo }: Props) => { + return ( +
+
+ +
+

+ {friendInfo?.userName} + {friendInfo?.userType === UserType.VERIFIED ? ( + + + + ) : null} +

+
+ ); +}; + +export default FriendInfoItem; diff --git a/components/circle/CirclePostInfoDialog/components/OtherUserCommentItem.tsx b/components/circle/CirclePostInfoDialog/components/OtherUserCommentItem.tsx new file mode 100644 index 0000000..0a07880 --- /dev/null +++ b/components/circle/CirclePostInfoDialog/components/OtherUserCommentItem.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { PostComment } from "@/types/post"; +import { getRecentTimeFromTimeStamp } from "@/service/shared/getRecentTimeFromTimeStamp"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import { useRouter } from "next/router"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; + +type Props = { + comment: PostComment; +}; +const OtherUserCommentItem = ({ comment }: Props) => { + const router = useRouter(); + const user = useSelector((state: RootState) => state.user); + + return ( +
+
+
+ +
+
+ +
+
+

{comment?.commenter?.userName}

+
+
+

+ {getRecentTimeFromTimeStamp(comment?.createdAt)} +

+
+
+ +

+ {comment.comment.split(" ").map((word, index) => { + const match = word.match(/@(\S+)/); + + if ( + match && + comment.tag.find((text) => text.userName === match[1])?.userId + ) { + const username = match[1]; + return ( + { + comment?.tag?.map((tagInfo, index) => { + if (tagInfo.userName === username && tagInfo.userId) { + router.push( + redirectTouserProfile(tagInfo.userId, user?.userId) + ); + } + }); + }} + > + {word}{" "} + + ); + } else { + return {word} ; + } + })} +

+
+
+ ); +}; + +export default OtherUserCommentItem; diff --git a/components/circle/CirclePostInfoDialog/index.tsx b/components/circle/CirclePostInfoDialog/index.tsx new file mode 100644 index 0000000..5f99fac --- /dev/null +++ b/components/circle/CirclePostInfoDialog/index.tsx @@ -0,0 +1,983 @@ +import React, { useEffect, useRef, useState } from "react"; +import VerificationIcon from "@/utils/icons/circle/VerifiedIcon"; +import CommentQuestionIcon from "@/utils/icons/shared/CommentQuestionIcon"; +import CommentMessageIcon from "@/utils/icons/shared/CommentMessageIcon"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import { Checkbox, CircularProgress, Divider, IconButton } from "@mui/material"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import { theme } from "@/theme"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import SynchronizeIcon from "@/utils/icons/circle/SynchronizeIcon"; +import Slider from "react-slick"; +import { Favorite, FavoriteBorder } from "@mui/icons-material"; +import { DropDownItem } from "@/types"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; +import ShareIcon from "@/utils/icons/shared/ShareIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import { IconDropDown } from "@/components/shared/dropDown/IconDropDown"; +import { Post, PostComment, PromptDetail } from "@/types/post"; +import { getRecentTimeFromTimeStamp } from "@/service/shared/getRecentTimeFromTimeStamp"; +import ThreeVerticalDots from "@/utils/icons/circle/ThreeVerticalDots"; +import { getComments } from "@/api/post/getComments"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import OtherUserCommentItem from "./components/OtherUserCommentItem"; +import CurrentUserCommentItem from "./components/CurrentUserCommentItem"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { postComment } from "@/api/post/postComment"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { formatLargeNumber } from "@/service/shared/formatLargeNumber"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import DeleteIcon from "@/utils/icons/shared/DeleteIcon"; +import { UserBaseInfo } from "@/types/user"; +import { useRouter } from "next/router"; +import LinkCopyIcon from "@/utils/icons/shared/LinkCopyIcon"; +import EditIcon from "@/utils/icons/shared/EditIcon"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { noCommentFound } from "@/utils/images"; +import { useDebounceEffect } from "@/hooks/useDebounceEffect"; +import getAllFriends from "@/api/cricle/getAllFriends"; +import { FriendsList } from "@/types/circle"; +import FriendInfoItem from "./components/FriendInfoItem"; +import OutsideClickHandler from "react-outside-click-handler"; + +type Res = { + status: number; + data: PostComment[]; + error: any; +}; +type GetCommentsProps = { + lastDocId?: string; + res?: Res; + postId?: string; +}; +type PostCommentRes = { + status: number; + data: PostComment; + error: any; +}; + +type Props = { + selectedPost: Post; + selectedImageIndex?: number; + handleEdit?: (selectedPost: Post) => void; + setSelectedPost: React.Dispatch>; + setDeletingPostIndex: React.Dispatch>; + setReportingPostIndex: React.Dispatch>; + handleChange: (event: React.ChangeEvent) => void; + handleRepost: (event: React.MouseEvent) => void; + handleCommentCount: (postId: string) => void; + setCreditDialogInfo: React.Dispatch< + React.SetStateAction<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null> + >; + creditDialogInfo: { + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null; + promptDetails: PromptDetail | null; +}; + +const CirclePostInfoDialog = ({ + selectedPost, + selectedImageIndex, + setSelectedPost, + setDeletingPostIndex, + handleChange, + handleRepost, + handleEdit, + handleCommentCount, + setCreditDialogInfo, + setReportingPostIndex, + promptDetails, + creditDialogInfo, +}: Props) => { + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + + const { sendNotification } = useAuthContext(); + const ref = useRef(null); + + const [menuList, setmenuList] = useState([]); + const [currentslide, setCurrentslide] = useState(1); + const [comments, setComments] = useState([]); + const [hasMoreComments, setHasMoreComments] = useState(true); + const [hasMoreFriends, setHasMoreFriends] = useState(true); + const [friendsList, setFriendsList] = useState([]); + + const [inputComment, setInputComment] = useState(""); + const [lastWord, setLastWord] = useState<{ + word: string | null; + tagged: boolean; + } | null>({ word: null, tagged: false }); + + const [isCommentButtonEnabled, setIsCommentButtonEnabled] = useState(true); + const [isCommentsFetched, setIsCommentsFetched] = useState(false); + const [recentInfo, setRecentInfo] = useState<{ + like: { isLiked: boolean; count: number }; + postId: string; + repost: { isReposted: boolean; count: number }; + }>({ + like: { + isLiked: selectedPost.userActivity.isLiked, + count: selectedPost.counts.like, + }, + postId: selectedPost.postId, + repost: { + isReposted: selectedPost.userActivity.isReposted, + count: selectedPost.counts.repost, + }, + }); + const [isLoading, setIsLoading] = useState(false); + + var sliderSettings = { + dots: false, + infinite: true, + speed: 500, + slidesToShow: 1, + slidesToScroll: 1, + afterChange: (currentSlide: number) => { + setCurrentslide(currentSlide + 1); // +1 since slide indexing starts from 0 + }, + + prevArrow: ( +
+ + + +
+ ), + nextArrow: ( +
+ + + +
+ ), + }; + + const handleLikeChange = (e: React.ChangeEvent) => { + setRecentInfo((prev) => { + return { + postId: selectedPost.postId, + like: { + isLiked: !prev.like.isLiked ? true : false, + count: !prev.like.isLiked + ? prev.like.count + 1 + : prev.like.count !== 0 + ? prev.like.count - 1 + : 0, + }, + repost: { + isReposted: prev.repost.isReposted, + count: prev.repost.count, + }, + }; + }); + handleChange(e); + }; + + const fetchComments = async ({ postId, lastDocId }: GetCommentsProps) => { + if (!user) return; + const res = await getComments({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + ...(postId && { postId }), + }); + + setIsCommentsFetched(true); + saveComments({ res, lastDocId }); + }; + + const saveComments = ({ lastDocId, res }: GetCommentsProps) => { + if (!res) return; + if (res.status === 200) { + if (res?.data.length < 20) { + setHasMoreComments(false); + } else { + setHasMoreComments(true); + } + if (res.data.length > 0) { + setComments((prev) => { + if (lastDocId) { + return prev.concat(res.data); + } else { + return res.data; + } + }); + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const fetchMoreComments = async () => { + const lastDocId = comments[comments.length - 1]?.commentId; + fetchComments({ lastDocId, postId: selectedPost?.postId }); + setIsCommentsFetched(false); + }; + + const sendComment = async () => { + if (!user) return; + + if (isCommentButtonEnabled) { + const res = await postComment({ + user_id: user.userId, + postId: selectedPost?.postId, + comment: inputComment, + }); + if (res.status === 200) { + setInputComment(""); + fetchComments({ postId: selectedPost?.postId }); + increaseCommentsTotal(); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + } + }; + + const increaseCommentsTotal = () => { + if (selectedPost) handleCommentCount(selectedPost.postId); + }; + + const handleItemSelect = (type: string) => { + if (selectedPost) { + if (type === "DELETE") { + setDeletingPostIndex(selectedPost.postId); + } + if (type === "EDIT") { + if (handleEdit) { + handleEdit(selectedPost); + } + } + if (type === "COPY") { + handleCopyLink(); + } + if (type === "REPORT") { + setReportingPostIndex(selectedPost.postId); + } + } + }; + + const handleCopyLink = () => { + navigator.clipboard.writeText( + window.location.protocol + + "//" + + window.location.host + + `/discover/post?postId=${selectedPost.postId}` + ); + sendNotification({ type: "SUCCESS", message: "Post Coppied!!" }); + }; + + const getFriendsList = async (searchScore?: number, lastDocId?: string) => { + if (!lastWord?.word) return; + const response = await getAllFriends({ + user_id: user?.userId, + search: lastWord.word, + searchScore: searchScore, + lastDocId: lastDocId, + limit: 20, + }); + + if (response.status === 200 && response.data) { + if (response.data.friends.length < 20) { + setHasMoreFriends(false); + } else { + setHasMoreFriends(true); + } + + setFriendsList((prevFriends) => [ + ...prevFriends, + ...(response.data?.friends || []), + ]); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + + const fetchMoreFriends = async () => { + const searchScore = friendsList[friendsList.length - 1].searchScore; + const lastDocId = friendsList[friendsList.length - 1].userId; + getFriendsList(searchScore, lastDocId); + }; + + useEffect(() => { + const baseMenu = [ + { + startIcon: ( +
+ +
+ ), + title: "Copy Post Link", + actionType: "COPY", + }, + ]; + if (selectedPost && selectedPost.postedBy.userId === user?.userId) { + baseMenu.push({ + startIcon: , + title: "Edit", + actionType: "EDIT", + }); + baseMenu.push({ + startIcon: , + title: "Delete", + actionType: "DELETE", + }); + } else { + baseMenu.push({ + startIcon: , + title: "Report", + actionType: "REPORT", + }); + } + + setmenuList(baseMenu); + if (selectedPost && selectedPost.counts.comment != 0) { + fetchComments({ postId: selectedPost.postId }); + } + + if ( + (selectedPost.userActivity.isLiked !== recentInfo.like.isLiked || + selectedPost.userActivity.isReposted !== + recentInfo.repost.isReposted) && + selectedPost.postId !== "" + ) { + setRecentInfo(() => { + return { + postId: selectedPost.postId, + like: { + isLiked: selectedPost.userActivity.isLiked, + count: selectedPost.counts.like, + }, + repost: { + isReposted: selectedPost.userActivity.isReposted, + count: selectedPost.counts.repost, + }, + }; + }); + } + }, [selectedPost]); + + useEffect(() => { + if (inputComment.includes("@") && inputComment.length === 1) { + setFriendsList([]); + setHasMoreFriends(true); + setLastWord({ word: null, tagged: false }); + } + if (inputComment.length > 2) setIsCommentButtonEnabled(true); + const words = inputComment.split(" "); + const word = words[words.length - 1]; + + if (word.includes("@") && word.length > 2) { + const lastWordWithoutAt = word.replace("@", ""); + + if (!lastWord?.tagged) { + setLastWord({ word: lastWordWithoutAt, tagged: false }); + } else { + setLastWord({ word: null, tagged: false }); + } + } else { + setLastWord({ word: null, tagged: false }); + } + }, [inputComment]); + + useEffect(() => { + if (lastWord) { + getFriendsList(); + } else { + setFriendsList([]); + setHasMoreFriends(true); + setLastWord({ word: null, tagged: false }); + } + }, [lastWord]); + + useEffect(() => { + if (selectedImageIndex) setCurrentslide(selectedImageIndex + 1); + }, [selectedImageIndex]); + + useEffect(() => { + setIsLoading(false); + }, [promptDetails]); + + useEffect(() => { + if (creditDialogInfo) { + if (creditDialogInfo === null && promptDetails === null) { + setIsLoading(false); + } else if ( + creditDialogInfo?.isPostAccessed === true && + creditDialogInfo && + promptDetails === null + ) { + setIsLoading(true); + } else if ( + creditDialogInfo?.isPostAccessed === true && + creditDialogInfo && + promptDetails + ) { + setIsLoading(false); + } + if ( + creditDialogInfo?.isPostAccessed === false && + creditDialogInfo && + promptDetails === null + ) { + setIsLoading(false); + } + } + }, [creditDialogInfo, promptDetails]); + + // useEffect(() => { + // if (debouncedComment.includes("@") && debouncedComment.length > 2) { + // getFriendsList(); + // } else { + // setFriendsList([]); + // } + // }, [debouncedComment]); + + return ( + <> + {selectedPost ? ( + { + setSelectedPost(null); + }} + > +
+
+
+
{ + e.stopPropagation(); + router.push( + redirectTouserProfile( + selectedPost.postedBy.userId, + user?.userId + ) + ); + }} + > + +
+
+
+

{ + e.stopPropagation(); + router.push( + redirectTouserProfile( + selectedPost.postedBy.userId, + user?.userId + ) + ); + }} + > + {selectedPost.postedBy.userName} +

+ + {selectedPost.postedBy.userType === "VERIFIED" ? ( +
+ +
+ ) : null} +
+ + {selectedPost.repostedBy === null && + selectedPost.generatedFrom === null ? null : ( +
{ + e.stopPropagation(); + }} + > + {selectedPost.generatedFrom?.postId !== null && + selectedPost.generatedFrom !== null ? ( +
+ +
+ ) : null} + +
+ {selectedPost.repostedBy !== null ? ( + <> + Reposted by{" "} + { + e.stopPropagation(); + if ( + selectedPost.repostedBy && + selectedPost.repostedBy.userId !== + user?.userId + ) { + router.push( + redirectTouserProfile( + selectedPost.repostedBy.userId, + user?.userId + ) + ); + } else { + if (user) router.push("/profile"); + } + }} + > + {selectedPost.repostedBy.userName} + + + ) : null} + {selectedPost.generatedFrom?.postId !== null && + selectedPost.generatedFrom !== null ? ( + <> + Recreated from{" "} + Here + + ) : null} +
+
+ )} +
+
+ +
+ + +
+ } + handleItemSelect={handleItemSelect} + /> +
+ {getRecentTimeFromTimeStamp(selectedPost.createdAt)} +
+
+
+ {selectedPost.caption && selectedPost.caption.length > 0 ? ( +

+ {selectedPost.caption} +

+ ) : null} + +
+
+
+ (slider = slider)} + {...sliderSettings} + className=" slick_slider_arrow w-[342px] h-[445px] flex flex-row justify-start items-center rounded-md overflow-hidden" + > + {selectedPost.image.map((postImage, index) => { + return ( +
+ +
+ ); + })} +
+ + {selectedPost.image.length > 1 ? ( +

+ {currentslide} of {selectedPost.image.length} +

+ ) : null} +
+
+
+

+ {formatLargeNumber(selectedPost.counts.view)} Views +

+ + {isLoading ? ( +
+ +
+ ) : null} + {selectedPost.isPromptAvailable && !isLoading ? ( + { + e.stopPropagation(); + setIsLoading(true); + + setCreditDialogInfo({ + userInfo: selectedPost.postedBy, + postId: selectedPost.postId, + isPostAccessed: selectedPost.userActivity + .isAccessToViewPrompt + ? true + : false, + }); + // setCustomDialogType("CREDITS-VIEWPROMPT"); + }} + > + + + ) : null} +
+ +
+
+
+
+ { + e.stopPropagation(); + }} + onChange={handleLikeChange} + icon={ + + } + checkedIcon={} + checked={ + selectedPost.postId === recentInfo.postId + ? recentInfo.like.isLiked + : selectedPost.userActivity.isLiked + } + /> +
+

+ {formatLargeNumber( + selectedPost.postId === recentInfo.postId + ? recentInfo.like.count + : selectedPost.counts.like + )} +

+
+
+
+ +
+

+ {formatLargeNumber(selectedPost.counts.comment)} +

+
+ + {selectedPost.postedBy.userId !== user?.userId ? ( +
+
+ +
+

+ {formatLargeNumber( + selectedPost.postId === recentInfo.postId + ? recentInfo.repost.count + : selectedPost.counts.repost + )} +

+
+ ) : null} +
{" "} + {selectedPost.allowGenerations ? ( +
+
+ +
+ {/*

+ {formatLargeNumber(selectedPost.counts.recreation)} +

*/} +
+ ) : null} +
+
+
+
+
+
+

Comments

+

+ ({formatLargeNumber(selectedPost.counts.comment)}) +

+
+ +
+
+
+ {selectedPost.counts.comment === 0 || + (comments.length === 0 && isCommentsFetched) ? ( +
+ {/* change size of nocommentfound image */} + + +
+ } + title="No Comments Yet" + description="Begin the conversation.." + /> +
+ ) : ( +
+ + +
+ } + style={{ + display: "flex", + flexDirection: "column-reverse", + gap: "1.25rem", + }} + scrollableTarget="commentsScrollableDiv" + > + {comments.map((comment, index) => { + return ( +
+ {comment.commenter.userId === user?.userId ? ( + + ) : ( + + )} +
+ ); + })} + +
+ )} +
+
+ {lastWord?.word ? ( +
+ { + setFriendsList([]); + setLastWord({ word: null, tagged: false }); + setHasMoreFriends(true); + }} + > + {" "} +
+ {friendsList.length === 0 && !hasMoreFriends ? ( + + ) : ( +
+ + +
+ } + scrollableTarget="friendListScrollableDiv" + style={ + hasMoreFriends ? {} : { overflow: "hidden" } + } + > +
+ {friendsList.map((friend, index) => ( +
{ + const segments = + inputComment.split("@"); + const lastSegment = + segments[segments.length - 1]; + const newComment = + inputComment.replace( + `@${lastSegment}`, + `@${friend.userName}` + ); + setInputComment(newComment); + setFriendsList([]); + setLastWord({ + word: null, + tagged: false, + }); + setHasMoreFriends(true); + setLastWord((prev) => { + if (!prev) return null; + return { ...prev, tagged: true }; + }); + // setHasMoreFriends(true); + }} + > + +
+ ))} +
+ +
+ )} +
+ +
+ ) : null} + + 2 + ? "text-primary-main" + : "text-grey-300 cursor-default" + }`} + > + +
+ } + EndIconStyle=" cursor-pointer text-grey-100" + className={` border-none ${ + lastWord?.word ? "rounded-t-none " : "" + } `} + onChange={(e: React.ChangeEvent) => { + setInputComment(e.target.value); + }} + EndIconHandleEvent={() => { + if (inputComment.length > 2) { + sendComment(); + setIsCommentButtonEnabled(false); + } + }} + /> + + + + + +
+ ) : null} + + ); +}; + +export default CirclePostInfoDialog; diff --git a/components/circle/CreditViewPromptDialog.tsx b/components/circle/CreditViewPromptDialog.tsx new file mode 100644 index 0000000..27fcade --- /dev/null +++ b/components/circle/CreditViewPromptDialog.tsx @@ -0,0 +1,133 @@ +import { useAuthContext } from "@/context/AuthContext"; +import { theme } from "@/theme"; +import { Divider, IconButton } from "@mui/material"; +import React from "react"; +import CreditTopBg from "@/utils/images/CreditTopBg.png"; +import Image from "next/image"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import tempboy from "@/utils/images/tempboy.jpg"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import CustomButton from "@/components/shared/CustomButton"; + +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import CustomDialog from "../shared/dialog/CustomDialog"; + +const CreditViewPromptDialog = () => { + const { customDialogType, setCustomDialogType, setCustomDrawerType } = + useAuthContext(); + + const user = useSelector((state: RootState) => state.user); + + return ( + // customDialogType != null + + {/* top common layout */} +
+
+ { + setCustomDialogType(null); + }} + > + + + + +
+
+

Total Credit Balance

+
+

10

+
+ +
+
+
+
+
+
+ +
+ {/* circle -> viewprompt */} +
+
+

Credit Amount

+
+

6.50

+
+ +
+
+
+ +
+ +
+
+ +
+
+

Gerdes

+
+ +
+
+

+ My favorite color is every color and none of the colors all at + once but also it not even a moment. Does that definitely make + sense? +

+
+
+
+ +
+ { + setCustomDialogType(null); + setCustomDrawerType("CREDITDRAWER-VIEWPROMPT"); + }} + /> +

+ By submitting this request you agree to witit’s +

+

+ + Privacy Policy + {" "} + and + + Terms of Use + +

+
+
+
+ ); +}; + +export default CreditViewPromptDialog; diff --git a/components/create/components/BottomBar.tsx b/components/create/components/BottomBar.tsx new file mode 100644 index 0000000..6c934ed --- /dev/null +++ b/components/create/components/BottomBar.tsx @@ -0,0 +1,203 @@ +import { CircularProgress, IconButton } from "@mui/material"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; +import CustomInputTextField from "../../shared/CustomInputTextField"; +import LampIcon from "@/utils/icons/shared/LampIcon"; +import FilterIcon from "@/utils/icons/shared/FilterIcon"; +import { CustomImagePreview } from "../../shared/CustomImagePreview"; +import { useAuthContext } from "@/context/AuthContext"; +import { defaultImageConstant } from "@/utils/constants/withoutHtml/appConstant"; +import { ImageInfo } from "@/types"; +import { useEffect, useState } from "react"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import DeleteIcon from "@/utils/icons/shared/DeleteIcon"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import { getPrompt } from "@/api/public/getPrompt"; +import { CreateDrawerType } from "@/pages/create"; +import { Control, Controller, UseFormSetValue } from "react-hook-form"; +import { Model, PostAiGeneration } from "@/types/ai"; +import { useGenerationContext } from "../context/GenerationContext"; +import InputCropSingleImage from "@/components/shared/cropImage/singleCropImage/InputCropSingleImage"; + +type Props = { + handleChangeDrawerType: (type: CreateDrawerType) => void; + control: Control; + setValue: UseFormSetValue; + handleGetGenerationCharge: () => void; + isGetChargeLoading: boolean; +}; + +export const BottomBar = ({ + handleChangeDrawerType, + control, + setValue, + handleGetGenerationCharge, + isGetChargeLoading, +}: Props) => { + const [isPromptLoading, setIsPromptLoading] = useState(false); + const [isShowDeleteIcon, setIsShowDeleteIcon] = useState(false); + + const { customDrawerType, sendNotification } = useAuthContext(); + + const { selectedModel, selectedImage, setSelectedImage } = + useGenerationContext(); + + const getMyPrompt = async () => { + setIsPromptLoading(true); + const res = await getPrompt({ + path: selectedModel?.classType ?? "Man", + }); + + if (res.status === 200) { + setValue("prompt", res.data.prompt); + setIsPromptLoading(false); + return; + } + + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + setValue("prompt", ""); + () => setValue("prompt", ""); + }, [selectedModel?.classType]); + + useEffect(() => { + setIsShowDeleteIcon(false); + }, [selectedImage]); + + return ( +
+
{ + if (!isPromptLoading) getMyPrompt(); + }} + > + {isPromptLoading ? ( + + + + ) : ( + + + + )} +
+
+ {!selectedImage ? ( + + + +
+ ), + placeholderTitle: <>, + }} + /> + + ) : ( +
{ + setSelectedImage(null); + setIsShowDeleteIcon(false); + }} + onMouseEnter={() => setIsShowDeleteIcon(true)} + onMouseLeave={() => setIsShowDeleteIcon(false)} + > + {isShowDeleteIcon ? ( +
+ +
+ ) : null} + +
+ )} +
+
+ ( + ) => { + field.onChange(e.target.value); + }} + placeholder="What you want to create..?" + EndIcon={ + isGetChargeLoading ? ( + + + + ) : ( + 3 + ? "text-primary-main cursor-pointer" + : "text-grey-300 cursor-default" + } + > + + + ) + } + EndIconHandleEvent={() => { + if (field.value && field.value.split(" ").length > 3) { + handleGetGenerationCharge(); + } + }} + className="text-grey-100 hover:text-primary-main rounded-xl bg-grey-900 border-0 h-full py-2 min-h-[60px]" + /> + )} + /> +
+
+
{ + handleChangeDrawerType("MODEL_SELECTION"); + }} + className="flex gap-3 h-full items-center bg-grey-900 rounded-xl text-common-white text-sm tracking-widest cursor-pointer font-light p-4" + > + {selectedModel?.modelName} + +
+ +
+
+
+ { + handleChangeDrawerType("FILTER"); + }} + > + + +
+ + ); +}; diff --git a/components/create/components/FilterDrawer/components/Creations.tsx b/components/create/components/FilterDrawer/components/Creations.tsx new file mode 100644 index 0000000..81c1517 --- /dev/null +++ b/components/create/components/FilterDrawer/components/Creations.tsx @@ -0,0 +1,358 @@ +import { useGenerationContext } from "@/components/create/context/GenerationContext"; +import CustomButton from "@/components/shared/CustomButton"; +import CustomCheckbox from "@/components/shared/CustomCheckbox"; +import { CustomSlider } from "@/components/shared/CustomSlider"; +import { RootState } from "@/redux/store"; +import { CreationSettings } from "@/types/ai"; +import { imageSizes } from "@/utils/constants/withoutHtml/ai"; +import { aspectRatioList } from "@/utils/constants/withoutHtml/common"; +import CheckBoxEmptyIcon from "@/utils/icons/shared/CheckBoxEmptyIcon"; +import CheckBoxFillCheckedIcon from "@/utils/icons/shared/CheckBoxFillCheckedIcon"; +import CheckBoxTickCheckedIcon from "@/utils/icons/shared/CheckBoxTickCheckedIcon"; +import { ChangeEvent } from "react"; +import { useSelector } from "react-redux"; + +type Props = { + creationSettings: CreationSettings; + setCreationSetting: (creationSettings: CreationSettings) => void; +}; + +export const Creations = ({ creationSettings, setCreationSetting }: Props) => { + const baseModels = useSelector( + (state: RootState) => state.models.baseModelList + ); + const { selectedModel } = useGenerationContext(); + + const handleCreationSettingChange = (changes: Partial) => { + setCreationSetting({ + ...creationSettings, + ...changes, + }); + }; + + return ( +
+ {baseModels.filter((model) => model.modelId === selectedModel?.modelId) + .length > 0 && ( +
+
Image Size
+
+ {imageSizes.slice(0, 2).map((item, index) => { + return ( +
+ + handleCreationSettingChange({ imageSize: item.tag }) + } + /> +
+ ); + })} +
+
+ )} + +
+
Aspect Ratio
+
+ {aspectRatioList.map((item, index) => { + return ( +
+ + handleCreationSettingChange({ aspectRatio: item.tag }) + } + /> +
+ ); + })} +
+
+
+
+
+
Prompt Strength
+

+ This determines how much Witit’s AI should stick too your prompt. + Too much or too little can create and undesirable effect. +

+
+
+ `${value * 10}%`} + aria-label="pretto slider" + value={creationSettings.promptStrength} + step={1} + max={10} + min={0} + onChange={(event, newVal) => + handleCreationSettingChange({ + promptStrength: newVal as number, + }) + } + /> +
+
+
+
+
Defination
+

+ This will increase the number of iterations our AI will make when + producing your photos. This can change your cost per creation. +

+
+
+ `${value}%`} + aria-label="pretto slider" + value={creationSettings.definition} + step={10} + max={100} + min={0} + onChange={(event, newVal) => + handleCreationSettingChange({ + definition: newVal as number, + }) + } + /> +
+
+
+
+ } + checkedIcon={} + checked={creationSettings.restoreFace} + onChange={(e: ChangeEvent) => + handleCreationSettingChange({ + restoreFace: e.target.checked, + }) + } + /> +
+
+ handleCreationSettingChange({ + restoreFace: !creationSettings.restoreFace, + }) + } + > + Restore Faces +
+

+ Runs Another AI Model on top to create the face in the image. +

+
+
+ +
+ } + checkedIcon={} + checked={creationSettings.preserveFaceDetails ? true : false} + onChange={(e: ChangeEvent) => + handleCreationSettingChange({ + preserveFaceDetails: e.target.checked + ? { preservationStrength: 0.5, definition: 50 } + : null, + }) + } + /> +
+
{ + handleCreationSettingChange({ + preserveFaceDetails: creationSettings.preserveFaceDetails + ? null + : { preservationStrength: 0.5, definition: 50 }, + }); + }} + > + Preserve Face Details +
+

+ Run the AI creation process one more time but only on your face to + ensure high quality results. +

+ {creationSettings.preserveFaceDetails ? ( +
+
+
+ Face Preservation Strength +
+

+ too much or too little may cause undesirable effects +

+ `${value * 100}%`} + aria-label="pretto slider" + value={ + creationSettings.preserveFaceDetails?.preservationStrength + } + step={0.1} + max={1} + min={0} + onChange={(event, newVal) => { + if (creationSettings.preserveFaceDetails) { + handleCreationSettingChange({ + ...creationSettings, + preserveFaceDetails: { + ...creationSettings.preserveFaceDetails, + preservationStrength: newVal as number, + }, + }); + } + }} + /> +
+
+
+ Definition +
+

+ This will increase the number of iterations our AI will make + when producing your photos. +

+ `${value}%`} + aria-label="pretto slider" + value={creationSettings.preserveFaceDetails?.definition} + step={10} + max={100} + min={0} + onChange={(event, newVal) => { + if (creationSettings.preserveFaceDetails) { + handleCreationSettingChange({ + ...creationSettings, + preserveFaceDetails: { + ...creationSettings.preserveFaceDetails, + definition: newVal as number, + }, + }); + } + }} + /> +
+
+ ) : null} +
+
+
+ } + checkedIcon={} + checked={creationSettings.preserveHandDetails ? true : false} + onChange={(e: ChangeEvent) => + handleCreationSettingChange({ + preserveHandDetails: e.target.checked + ? { preservationStrength: 0.5, definition: 50 } + : null, + }) + } + /> +
+
{ + handleCreationSettingChange({ + preserveHandDetails: creationSettings.preserveHandDetails + ? null + : { preservationStrength: 0.5, definition: 50 }, + }); + }} + > + Preserve Hand Details +
+

+ Run the AI creation process one more time but only on your hand to + ensure high quality results. +

+ {creationSettings.preserveHandDetails ? ( +
+
+
+ Hand Preservation Strength{" "} +
+

+ too much or too little may cause undesirable effects{" "} +

+ `${value * 100}%`} + aria-label="pretto slider" + value={ + creationSettings.preserveHandDetails?.preservationStrength + } + step={0.1} + max={1} + min={0} + onChange={(event, newVal) => { + if (creationSettings.preserveHandDetails) { + handleCreationSettingChange({ + ...creationSettings, + preserveHandDetails: { + ...creationSettings.preserveHandDetails, + preservationStrength: newVal as number, + }, + }); + } + }} + /> +
+
+
+ Definition +
+

+ This will increase the number of iterations our AI will make + when producing your photos. +

+ `${value}%`} + aria-label="pretto slider" + value={creationSettings.preserveHandDetails?.definition} + step={10} + max={100} + min={0} + onChange={(event, newVal) => { + if (creationSettings.preserveHandDetails) { + handleCreationSettingChange({ + ...creationSettings, + preserveHandDetails: { + ...creationSettings.preserveHandDetails, + definition: newVal as number, + }, + }); + } + }} + /> +
+
+ ) : null} +
+
+
+ ); +}; diff --git a/components/create/components/FilterDrawer/components/Inpainting.tsx b/components/create/components/FilterDrawer/components/Inpainting.tsx new file mode 100644 index 0000000..59d7d32 --- /dev/null +++ b/components/create/components/FilterDrawer/components/Inpainting.tsx @@ -0,0 +1,41 @@ +import React, { useState } from "react"; +import CustomCheckbox from "@/components/shared/CustomCheckbox"; +import CheckBoxEmptyIcon from "@/utils/icons/shared/CheckBoxEmptyIcon"; +import CheckBoxTickCheckedIcon from "@/utils/icons/shared/CheckBoxTickCheckedIcon"; +import { ChangeEvent } from "react"; +import { InPaintingSettings } from "@/types/ai"; + +const InPainting = () => { + const [isMaskOnly, setIsMaskOnly] = useState(false); + return ( +
+
+ } + checkedIcon={} + checked={isMaskOnly} + onChange={(e: ChangeEvent) => { + setIsMaskOnly(e.target.checked); + }} + /> +
+
{ + setIsMaskOnly(!isMaskOnly); + }} + > + Recreate Mask Only{" "} +
+

+ Toggle this checkbox to inpaint 'Only Masked' areas or leave + unchecked for 'Whole Picture' processing. +

+
+
+
+ ); +}; + +export default InPainting; diff --git a/components/create/components/FilterDrawer/components/PowerUpscale.tsx b/components/create/components/FilterDrawer/components/PowerUpscale.tsx new file mode 100644 index 0000000..f365424 --- /dev/null +++ b/components/create/components/FilterDrawer/components/PowerUpscale.tsx @@ -0,0 +1,157 @@ +import { HiResSettings } from "@/types/ai"; +import React from "react"; +import CustomButton from "@/components/shared/CustomButton"; +import CustomCheckbox from "@/components/shared/CustomCheckbox"; +import { CustomSlider } from "@/components/shared/CustomSlider"; +import { imageSizes } from "@/utils/constants/withoutHtml/ai"; +import { + ResolutionList, + aspectRatioList, +} from "@/utils/constants/withoutHtml/common"; +import CheckBoxEmptyIcon from "@/utils/icons/shared/CheckBoxEmptyIcon"; +import CheckBoxTickCheckedIcon from "@/utils/icons/shared/CheckBoxTickCheckedIcon"; +import { ChangeEvent } from "react"; + +type Props = { + hiResSettings: HiResSettings | null; + setHiResSettings: (creationSettings: HiResSettings | null) => void; +}; + +const PowerUpscale = ({ hiResSettings, setHiResSettings }: Props) => { + const handleCreationSettingChange = (changes: Partial) => { + if (!hiResSettings) return; + + setHiResSettings({ + ...hiResSettings, + ...changes, + }); + }; + return ( +
+
+ } + checkedIcon={} + checked={hiResSettings ? true : false} + onChange={(e: ChangeEvent) => { + if (e.target.checked) { + setHiResSettings({ + definition: 50, + similarityStrength: 0.5, + increaseResolution: 1, + }); + } else { + setHiResSettings(null); + } + }} + /> +
+
{ + if (hiResSettings) { + setHiResSettings(null); + } else { + setHiResSettings({ + definition: 50, + similarityStrength: 0.5, + increaseResolution: 1, + }); + } + }} + > + Configure Advance Recreation Settings +
+
+
+ + {hiResSettings ? ( +
+
+
+
Defination
+

+ This will increase the number of iterations our AI will make + when producing your photos. This can change your cost per + creation. +

+
+
+ `${value}%`} + aria-label="pretto slider" + value={hiResSettings?.definition} + step={10} + max={100} + min={0} + onChange={(event, newVal) => + handleCreationSettingChange({ + definition: newVal as number, + }) + } + /> +
+
{" "} +
+
+
Similarity Strength
+

+ This determines how much Witit’s AI should stick too your + prompt. Too much or too little can create and undesirable + effect. +

+
+
+ {/* reverted */} + + (Math.round(v * 10) / 10) * 100 + "%"} + aria-label="pretto slider" + value={1 - hiResSettings?.similarityStrength} + step={0.1} + max={1} + min={0} + onChange={(event, newVal) => + handleCreationSettingChange({ + similarityStrength: + Math.round((1 - (newVal as number)) * 10) / 10, + }) + } + /> +
+
{" "} +
+
Increase Resolution
+
+ {ResolutionList.map((item, index) => { + return ( +
+ + handleCreationSettingChange({ + increaseResolution: item.tag, + }) + } + /> +
+ ); + })} +
+
+
+ ) : null} +
+ ); +}; + +export default PowerUpscale; diff --git a/components/create/components/FilterDrawer/components/Recreations.tsx b/components/create/components/FilterDrawer/components/Recreations.tsx new file mode 100644 index 0000000..bde6654 --- /dev/null +++ b/components/create/components/FilterDrawer/components/Recreations.tsx @@ -0,0 +1,228 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { CustomSlider } from "@/components/shared/CustomSlider"; +import CustomToggleSwitch from "@/components/shared/CustomToggleSwitch"; +import { RecreationSettings } from "@/types/ai"; +import { useEffect, useState } from "react"; + +type Props = { + recreationSettings: RecreationSettings | null; + setRecreationSetting: (creationSettings: RecreationSettings) => void; +}; + +type RecreationItem = { + displayName: string; + tag: string; +}; + +const recreationTypeList: RecreationItem[] = [ + { + displayName: "Copy Depth", + tag: "depth", + }, + { + displayName: "Copy Pose", + tag: "pose", + }, + { + displayName: "Copy Edges", + tag: "canny", + }, +]; + +export const Recreations = ({ + recreationSettings, + setRecreationSetting, +}: Props) => { + const [isShowAdvanceSettings, setIsShowAdvanceSettings] = useState( + recreationSettings?.recreationType ? true : false + ); + + useEffect(() => { + setIsShowAdvanceSettings(recreationSettings?.recreationType ? true : false); + }, [recreationSettings?.recreationType]); + + const handleRecreationSettingChange = ( + changes: Partial + ) => { + if (!recreationSettings) return; + setRecreationSetting({ + ...recreationSettings, + ...changes, + }); + }; + + const handleToggleAdvanceConfig = () => { + if (isShowAdvanceSettings) { + handleRecreationSettingChange({ + recreationType: null, + recreationTypeStrength: null, + }); + setIsShowAdvanceSettings(false); + return; + } + + handleRecreationSettingChange({ + recreationType: "depth", + recreationTypeStrength: 0.6, + }); + setIsShowAdvanceSettings(true); + }; + + if (!recreationSettings) return <>; + + return ( + <> +
+
+

Configure Advance Recreation Settings

+ handleToggleAdvanceConfig()} + /> +
+ {recreationSettings.recreationType ? ( +
+
Recreation Type
+
+ {recreationTypeList.map((item, index) => { + return ( +
+ + handleRecreationSettingChange({ + recreationType: item.tag, + }) + } + /> +
+ ); + })} +
+
+ ) : null} + {recreationSettings.recreationTypeStrength ? ( +
+
+
+ Recreation Type Strength +
+

+ Recreation type provides additional control over how you’d like + to recreate a photo. +

+
+
+ `${value * 100}%`} + aria-label="pretto slider" + value={recreationSettings.recreationTypeStrength} + step={0.1} + max={1} + min={0} + onChange={(event, newVal) => + handleRecreationSettingChange({ + recreationTypeStrength: newVal as number, + }) + } + /> +
+
+ ) : null} +
+
+
Recreation Strength
+

+ Recreation Strength is a value that determines how much Witit’s AI + will take the recreated photo into account. +

+
+
+ {/* reverted */} + (Math.round(v * 10) / 10) * 100 + "%"} + marks={false} + valueLabelDisplay="auto" + aria-label="pretto slider" + value={1 - recreationSettings.recreationStrength} + step={0.1} + max={1} + min={0} + onChange={(event, newVal) => + handleRecreationSettingChange({ + recreationStrength: + Math.round((1 - (newVal as number)) * 10) / 10, + }) + } + /> +
+
+
+ {/*
+
+
Recreation Type
+
+ + + +
+
+
+
+
+
Recreation Type Strength
+

+ Recreation type provides additional control over how you’d like + to recreate a photo. +

+
+
+ +
+
+
+
+
Recreation Strength
+

+ Recreation Strength is a value that determines how much Witit’s + AI will take the recreated photo into account. +

+
+
+ +
+
+
+
*/} + + ); +}; diff --git a/components/create/components/FilterDrawer/index.tsx b/components/create/components/FilterDrawer/index.tsx new file mode 100644 index 0000000..d8849a1 --- /dev/null +++ b/components/create/components/FilterDrawer/index.tsx @@ -0,0 +1,180 @@ +import React, { useEffect } from "react"; +import CustomButton from "@/components/shared/CustomButton"; +import { IconButton, List } from "@mui/material"; +import Image from "next/image"; +import { useState } from "react"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import CustomInputTag from "@/components/shared/CustomInputTag"; +import { filterImage } from "@/utils/images"; +import { Creations } from "./components/Creations"; +import { Recreations } from "./components/Recreations"; +import { GenerationSetting } from "@/types/ai"; +import { initialGenerationSetting } from "@/utils/constants/withoutHtml/ai"; +import PowerUpscale from "./components/PowerUpscale"; +import Inpainting from "./components/Inpainting"; +import CustomAccordion from "@/components/shared/CustomAccordion"; +import CustomCheckbox from "@/components/shared/CustomCheckbox"; +import CheckBoxEmptyIcon from "@/utils/icons/shared/CheckBoxEmptyIcon"; +import CheckBoxTickCheckedIcon from "@/utils/icons/shared/CheckBoxTickCheckedIcon"; +import ReverseIcon from "@/utils/icons/shared/ReverseIcon"; + +const menuOptions = [ + { name: "Negative Prompts", key: "NEGATIVE_PROMPTS" }, + { name: "Creations", key: "CREATIONS" }, + { name: "Recreations", key: "RECREATIONS" }, + { name: "Power Upscale", key: "POWER_UPSCALE" }, + { name: "Inpainting", key: "INPAINTING" }, +]; + +type Props = { + handleCloseDrawer: () => void; + generationSetting: GenerationSetting; + setGenerationSetting: React.Dispatch>; +}; + +const FilterDrawer = ({ + handleCloseDrawer, + generationSetting, + setGenerationSetting, +}: Props) => { + const [selectedOption, setSelectedOption] = + useState("NEGATIVE_PROMPTS"); + const [tempGenerationSetting, setTempGenerationSetting] = + useState(generationSetting); + + const handleChangeGenerationSetting = ( + changes: Partial + ) => { + setTempGenerationSetting((preSetting) => { + return { + ...preSetting, + ...changes, + }; + }); + }; + + const handleChanges = ({ isSet }: { isSet: boolean }) => { + if (isSet) { + setGenerationSetting(tempGenerationSetting); + handleCloseDrawer(); + return; + } + + setGenerationSetting(initialGenerationSetting); + setTempGenerationSetting(initialGenerationSetting); + }; + + useEffect(() => { + setTempGenerationSetting(generationSetting); + }, [generationSetting]); + + return ( + <> +
+
+ +

Filters

+
+
+ +
+
+
+
+ + handleChangeGenerationSetting({ negativePrompt }) + } + /> + } + /> + + handleChangeGenerationSetting({ creationSettings }) + } + /> + } + /> + + handleChangeGenerationSetting({ recreationSettings }) + } + /> + } + /> + + + handleChangeGenerationSetting({ hiResSettings }) + } + /> + } + /> + } + /> +
+ +
+
+
+ } + checkedIcon={} + checked={true} + /> +
+
+ Make this filter default{" "} +
+

+ So that next time our AI wil automatically use this setting. +

+
+
+
+ handleChanges({ isSet: false })} + disableRipple + > +
+ +
+

Reset to defaults

+
+ handleChanges({ isSet: true })} + /> +
+
+
+
+ + ); +}; + +export default FilterDrawer; diff --git a/components/create/components/GenerationCreditDialog.tsx b/components/create/components/GenerationCreditDialog.tsx new file mode 100644 index 0000000..9a21e0a --- /dev/null +++ b/components/create/components/GenerationCreditDialog.tsx @@ -0,0 +1,286 @@ +import { Divider, IconButton } from "@mui/material"; +import CustomToggleSwitch from "../../shared/CustomToggleSwitch"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import { theme } from "@/theme"; +import React, { useEffect, useState } from "react"; +import CustomDialog from "../../shared/dialog/CustomDialog"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { creditDialogBg } from "@/utils/images"; +import CustomButton from "../../shared/CustomButton"; +import { + Control, + Controller, + UseFormGetValues +} from "react-hook-form"; +import { AiCharges, PostAiGeneration } from "@/types/ai"; +import RocketIcon from "@/utils/icons/shared/RocketIcon"; +import { CustomImagePreview } from "../../shared/CustomImagePreview"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import TermsOfServices from "@/components/footerDialogs/TermsOfServices"; +import PrivacyPolicy from "@/components/footerDialogs/PrivacyPolicy"; +import { useGenerationContext } from "../context/GenerationContext"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomInsufficientCredit from "@/components/shared/CustomInsufficientCredit"; + +type Props = { + setIsCreditDialogOpen: React.Dispatch>; + handleSubmit: () => void; + generationCharge: AiCharges; + control: Control; + getValues: UseFormGetValues; + isButtonLoading: boolean; + isnotEnoughCredit: boolean; + setIsnotEnoughCredit: React.Dispatch>; +}; + +export const GenerationCreditDialog = ({ + setIsCreditDialogOpen, + isnotEnoughCredit, + handleSubmit, + setIsnotEnoughCredit, + generationCharge, + control, + getValues, + isButtonLoading, +}: Props) => { + const user = useSelector((state: RootState) => state.user); + + const { setCalculatedCharge, calculatedCharge } = useGenerationContext(); + const { setCustomDialogType } = useAuthContext(); + + const [policy, setPolicy] = useState(null); + + const handleChargeChange = () => { + const [numberOfGenerations, superShoot] = getValues([ + "numberOfGenerations", + "superShoot", + ]); + + const { creditPerGeneration } = superShoot + ? generationCharge.withSuperShoot + : generationCharge.withOutSuperShoot; + + const divisibleFactor = + generationCharge.numberOfGeneration / numberOfGenerations; + + setCalculatedCharge(creditPerGeneration / divisibleFactor); + }; + + useEffect(() => { + handleChargeChange(); + }, []); + + if (!user?.credit) return <>; + + const { nonTransferableCredit, tempCredit, transferableCredit } = user.credit; + const openGetCreditDialog = () => { + setCustomDialogType("CREDITS-GETCREDITS"); + }; + + const closeDialoag = () => { + setIsnotEnoughCredit(false); + }; + return ( + <> + setIsCreditDialogOpen(false)} + className="w-full max-w-[430px] h-fit flex flex-col gap-5 max-h-[630px] justify-start items-center" + > +
+
+ setIsCreditDialogOpen(false)} + > + + +
+ +
+
+
+

Total Credit Balance

+
+

+ {tempCredit + transferableCredit + nonTransferableCredit} +

+
+ +
+
+
+
+
+
+
+
+

Number of photos

+ ( +
+ {[2, 4, 8].map((item, index) => { + return ( +
+ { + field.onChange(item); + handleChargeChange(); + }} + /> +
+ ); + })} +
+ + // { + // field.onChange(field.value === 4 ? 8 : 4); + // handleChargeChange(); + // }} + // startNumber={4} + // endNumber={8} + // /> + )} + /> +
+
+
+

Super Shoot

+

+ 10x the number of images created +

+

+ 10% off with supershoot +

+
+ ( + { + field.onChange(!field.value); + handleChargeChange(); + }} + startIcon={ +
+ +
+ } + endIcon={ +
+ +
+ } + /> + )} + /> +
+ +
+

Total Order Amount

+
+

+ {calculatedCharge} +

+
+ +
+
+
+ +
+
+ handleSubmit()} + loading={isButtonLoading} + /> +

+ By submitting this request you agree to witit’s +

+

+ { + setPolicy("PRIVACY_POLICYS"); + }} + > + Privacy Policy + + and + { + setPolicy("TERMS_OF_SERVICES"); + }} + > + Terms of Use + +

+
+ {isnotEnoughCredit && ( +
+ +
+ )} +
+ {policy && ( + + {policy === "TERMS_OF_SERVICES" ? ( + { + setPolicy(null); + }} + /> + ) : policy === "PRIVACY_POLICYS" ? ( + { + setPolicy(null); + }} + /> + ) : null} + + )} + + ); +}; diff --git a/components/create/components/Generations/components/GenerationItem/components/ImageContainer/components/ImageItem.tsx b/components/create/components/Generations/components/GenerationItem/components/ImageContainer/components/ImageItem.tsx new file mode 100644 index 0000000..85fb84a --- /dev/null +++ b/components/create/components/Generations/components/GenerationItem/components/ImageContainer/components/ImageItem.tsx @@ -0,0 +1,84 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { CustomTooltip } from "@/components/shared/CustomTooltip"; +import { IconDropDown } from "@/components/shared/dropDown/IconDropDown"; +import { useAuthContext } from "@/context/AuthContext"; +import { Image } from "@/types/post"; +import { GenerationActionList } from "@/utils/constants/withHtml/ai"; +import { Box, IconButton } from "@mui/material"; +import React, { useState } from "react"; + +type Props = { + image: Image; + setImageView: React.Dispatch>; + handleImageAction: ({ type }: { type: string }) => void; + handleSelect: (item: string, image: Image) => void; +}; + +export const ImageItem = ({ + image, + setImageView, + handleImageAction, + handleSelect, +}: Props) => { + const [isImageHover, setIsImageHover] = useState(false); + const { setCustomDialogType } = useAuthContext(); + + return ( +
setIsImageHover(true)} + onMouseLeave={() => setIsImageHover(false)} + > + {isImageHover ? ( +
{ + setImageView(image); + }} + > +
+ {GenerationActionList.slice(0, 2).map((item, index) => { + return ( + + ) => { + e.stopPropagation(); + handleImageAction({ type: item.actionType || "MESSAGE" }); + }} + className=" w-[30px] h-[30px] rounded-lg text-common-white bg-secondary-main hover:bg-primary-main hover:bg-opacity-100 bg-opacity-80 p-0 m-0 " + > + {item.startIcon} + + + ); + })} +
) => { + e.stopPropagation(); + setIsImageHover(false); + }} + className="w-[30px] aspect-square flex justify-center items-center rounded-lg bg-secondary-main hover:bg-primary-main hover:bg-opacity-100 bg-opacity-80" + > + { + handleSelect(item, image); + }} + position={{ vertical: "top", horizontal: "left" }} + listItems={GenerationActionList.slice( + 2, + GenerationActionList.length + )} + /> +
+
+
+ ) : null} + + + +
+ ); +}; diff --git a/components/create/components/Generations/components/GenerationItem/components/ImageContainer/components/ImagePreview.tsx b/components/create/components/Generations/components/GenerationItem/components/ImageContainer/components/ImagePreview.tsx new file mode 100644 index 0000000..d6d5879 --- /dev/null +++ b/components/create/components/Generations/components/GenerationItem/components/ImageContainer/components/ImagePreview.tsx @@ -0,0 +1,54 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { CustomTooltip } from "@/components/shared/CustomTooltip"; +import { Image } from "@/types/post"; +import { GenerationActionList } from "@/utils/constants/withHtml/ai"; +import { Box, Dialog, IconButton } from "@mui/material"; + +type Props = { + handleClose: () => void; + aspectRatio: string; + imageView: Image; + handleImageAction: ({ type }: { type: string }) => void; +}; + +export const ImagePreview = ({ + handleClose, + aspectRatio, + imageView, + handleImageAction, +}: Props) => { + return ( + +
+ + + +
+ {GenerationActionList.map((item, index) => { + return ( + + + handleImageAction({ + type: item.actionType ? item.actionType : "", + }) + } + > + {item.startIcon} + + + ); + })} +
+
+
+ ); +}; diff --git a/components/create/components/Generations/components/GenerationItem/components/ImageContainer/index.tsx b/components/create/components/Generations/components/GenerationItem/components/ImageContainer/index.tsx new file mode 100644 index 0000000..6b11c74 --- /dev/null +++ b/components/create/components/Generations/components/GenerationItem/components/ImageContainer/index.tsx @@ -0,0 +1,151 @@ +import { GetAiGeneration } from "@/types/ai"; +import { CircularProgress, Grid } from "@mui/material"; +import { useState } from "react"; +import { ImageItem } from "./components/ImageItem"; +import { ImagePreview } from "./components/ImagePreview"; +import { Image } from "@/types/post"; +import { useGenerationContext } from "@/components/create/context/GenerationContext"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { getImageObject } from "@/service/shared/getImageObject"; +import { useAuthContext } from "@/context/AuthContext"; + +const styles = { + responsiveGrid: { + xxl: 1, + xl: 1, + // lg: 5, + md: 1, + sm: 1, + xs: 1, + }, +}; + +type HandleImageActionProps = { + type: string; + image: Image; +}; + +type Props = { + generation: GetAiGeneration; +}; + +export const ImageContainer = ({ generation }: Props) => { + const models = useSelector((state: RootState) => state.models); + + const { setSelectedImage, setPrompt } = useGenerationContext(); + const { setGenerationPost, setCustomDialogType, generationPost } = + useAuthContext(); + const [imageView, setImageView] = useState(null); + + const handleClose = () => { + setImageView(null); + }; + + const handleDownloadImage = async ({ image }: { image: Image }) => { + const a = document.createElement("a"); + a.href = (await getImageObject(image.url)).blob; + a.download = + "witit_" + + (Math.floor(Math.random() * 90000) + 10000).toString() + + "_" + + Date.now() + + ".jpeg"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + + const handleRecreateImage = async ({ image }: { image: Image }) => { + const { file } = await getImageObject(image.url); + + setSelectedImage({ imagePreview: image.url, file }); + setPrompt( + generation.modelDetails.id === models.baseModelList[0]?.modelId + ? generation.prompt + : generation.prompt.split(" ").slice(4).join(" ") + ); + }; + + const handleImageAction = ({ type, image }: HandleImageActionProps) => { + switch (type) { + case "DOWNLOAD": + handleDownloadImage({ image }); + break; + case "RECREATE": + handleRecreateImage({ image }); + break; + case "POST": + setGenerationPost({ ...generation, generationImages: [image] }); + setCustomDialogType("POST"); + break; + + default: + break; + } + }; + + if (generation.status === "FAILURE") { + return ( +
+

Failed To Generate

+

{generation.message}

+
+ ); + } + const handleSelect = (item: string, image: Image) => { + if (item === "POST") { + setCustomDialogType("POST"); + setGenerationPost({ ...generation, generationImages: [image] }); + console.log(image); + } + }; + + return ( +
+ + {generation.generationImages + .filter((image) => image.url) + .map((image, index) => ( + + + handleImageAction({ type, image }) + } + /> + + ))} + {Array(generation.remainingGeneration) + .fill("") + .map((blank, index) => ( + +
+ +
+
+ ))} +
+ {imageView ? ( + { + handleImageAction({ type, image: imageView }); + setImageView(null); + }} + /> + ) : null} +
+ ); +}; diff --git a/components/create/components/Generations/components/GenerationItem/components/ModelContainer.tsx b/components/create/components/Generations/components/GenerationItem/components/ModelContainer.tsx new file mode 100644 index 0000000..0760378 --- /dev/null +++ b/components/create/components/Generations/components/GenerationItem/components/ModelContainer.tsx @@ -0,0 +1,147 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { GetAiGeneration } from "@/types/ai"; +import CopyIcon from "@/utils/icons/shared/CopyIcon"; +import RocketIcon from "@/utils/icons/shared/RocketIcon"; +import { IconButton } from "@mui/material"; +import dayjs from "dayjs"; +import { useSelector } from "react-redux"; + +const sliderSettings = { + dots: false, + infinite: true, + speed: 500, + slidesToShow: 5, + slidesToScroll: 1, + rtl: true, + variableWidth: true, + prevArrow: ( + + + + ), + nextArrow: ( + + + + ), +}; + +type Props = { + generation: GetAiGeneration; +}; + +export const ModelContainer = ({ generation }: Props) => { + const user = useSelector((state: RootState) => state.user); + + const { sendNotification } = useAuthContext(); + + const handleCopyProps = () => { + // Copy profile link + navigator.clipboard.writeText(generation.prompt); + + sendNotification({ type: "SUCCESS", message: "Prompt Coppied!!" }); + }; + + return ( +
+
+
+ {generation.modelDetails.name} +
+ {generation.generatedFrom?.image ? ( +
+ +
+ ) : null} +
+
+
+ handleCopyProps()} + > + + +
+
0 + ? "border-b border-b-grey-400" + : "" + }`} + > +

+ {generation.prompt} +

+
+ {generation.negativePrompt.length > 0 ? ( + //
+ // + // {generation.negativePrompt.map((name, index) => { + // return ( + //
+ // + //
+ // ); + // })} + //
+ //
+
+ {generation.negativePrompt.map((name, index) => { + return ( +
+
+ {name} +
+
+ ); + })} +
+ ) : null} +
+
+
+ {generation.superShoot ? ( +
+ +
+ ) : null} +

+ {dayjs(generation.createdAt).format("hh:mm A")} +

+
+
+
+ ); +}; diff --git a/components/create/components/Generations/components/GenerationItem/index.tsx b/components/create/components/Generations/components/GenerationItem/index.tsx new file mode 100644 index 0000000..75a3172 --- /dev/null +++ b/components/create/components/Generations/components/GenerationItem/index.tsx @@ -0,0 +1,72 @@ +import { getDayFromTimeStamp } from "@/service/shared/getDayFromTimeStamp"; +import { theme } from "@/theme"; +import { Divider } from "@mui/material"; +import { ImageContainer } from "./components/ImageContainer"; +import { ModelContainer } from "./components/ModelContainer"; +import { GetAiGeneration } from "@/types/ai"; +import React, { useEffect, useState } from "react"; + +type DayItem = { + id: string; + day: string; +}; + +type Props = { + generation: GetAiGeneration; + listOfDays: DayItem[]; + setListOfDays: React.Dispatch>; +}; + +export const GenerationItem = ({ + generation, + listOfDays, + setListOfDays, +}: Props) => { + const getDayFromGenerationTime = (time: string) => { + const resDay = getDayFromTimeStamp({ time }); + + if (listOfDays.filter((item) => item.day === resDay).length === 0) { + setListOfDays((preDays) => { + return [...preDays, { id: generation.Id, day: resDay }]; + }); + } else { + const updatedListItems: DayItem[] = listOfDays.map((item) => { + if (item.day === resDay) { + return { ...item, id: generation.Id }; + } + return item; + }); + + setListOfDays(updatedListItems); + } + }; + + useEffect(() => { + const resDay = getDayFromGenerationTime(generation.createdAt); + + return () => resDay; + }, []); + + return ( + <> +
+ + +
+ {/* {listOfDays.filter((item) => item.id === generation.Id).length > 0 ? ( + + {listOfDays.filter((item) => item.id === generation.Id)[0].day} + + ) : null} */} + + ); +}; diff --git a/components/create/components/Generations/index.tsx b/components/create/components/Generations/index.tsx new file mode 100644 index 0000000..6e297ce --- /dev/null +++ b/components/create/components/Generations/index.tsx @@ -0,0 +1,128 @@ +import { CircularProgress } from "@mui/material"; +import { useEffect, useRef, useState } from "react"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { getGenerations } from "@/api/ai/getGenerations"; +import { useAuthContext } from "@/context/AuthContext"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { GenerationItem } from "./components/GenerationItem"; +import { useGenerationContext } from "../../context/GenerationContext"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import CreateIcon from "@/utils/icons/navbar/CreateIcon"; + +type GenerationApiProps = { + lastDocId?: string; +}; + +type DayItem = { + id: string; + day: string; +}; + +let docLimit = 10; + +export const GenerationList = () => { + const { sendNotification } = useAuthContext(); + const { generations, setGenerations } = useGenerationContext(); + + const user = useSelector((state: RootState) => state.user); + + const [hasMoreGeneration, setHasMoreGeneration] = useState(true); + const [listOfDays, setListOfDays] = useState([]); + + const ref = useRef(null); + + const generationApi = async ({ lastDocId }: GenerationApiProps) => { + if (!user) return; + + const result = await getGenerations({ + user_id: user.userId, + limit: docLimit, + ...(lastDocId && { lastDocId }), + }); + + if (result.status === 200) { + const currentGenerations = result.data; + if (currentGenerations.length < docLimit) { + setHasMoreGeneration(false); + } + if (currentGenerations.length > 0) { + if (lastDocId) { + setGenerations([...generations, ...currentGenerations]); + return; + } + setGenerations(currentGenerations); + } + return; + } + + sendNotification({ type: "ERROR", message: result.error }); + }; + + useEffect(() => { + generationApi({}); + + // return () => { + // generationApi({}); + // }; + }, []); + + const fetchMoreGeneration = async () => { + const lastDocId = generations[generations.length - 1].Id; + + generationApi({ + lastDocId, + }); + }; + + if (generations.length === 0 && !hasMoreGeneration) + return ( +
+ + +
+ } + title="No Creation yet" + description="Haven't made anything yet. Start making cool AI images!" + /> + + ); + + return ( + <> +
+
+ + +
+ } + style={{ display: "flex", flexDirection: "column-reverse" }} + scrollableTarget="generationScrollableDiv" + > + {generations.map((generation, index) => ( + + ))} + +
+ + + ); +}; diff --git a/components/create/components/ModelSelectionDrawer/components/FriendModels/components/FriendModelItem/components/FriendInfo.tsx b/components/create/components/ModelSelectionDrawer/components/FriendModels/components/FriendModelItem/components/FriendInfo.tsx new file mode 100644 index 0000000..436075a --- /dev/null +++ b/components/create/components/ModelSelectionDrawer/components/FriendModels/components/FriendModelItem/components/FriendInfo.tsx @@ -0,0 +1,40 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { FriendModel } from "@/types/ai"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import { profilePlaceholderImage } from "@/utils/images"; +import { IconButton } from "@mui/material"; +import React from "react"; + +type Props = { + isOpen: boolean; + item: FriendModel; +}; + +export const FriendInfo = ({ isOpen, item }: Props) => { + return ( + <> +
+
+ +
+
+

{item.userName}

+

+ {item.models.length} {item.models.length > 1 ? "Models" : "Model"} +

+
+
+ +
+ +
+
+ + ); +}; diff --git a/components/create/components/ModelSelectionDrawer/components/FriendModels/components/FriendModelItem/index.tsx b/components/create/components/ModelSelectionDrawer/components/FriendModels/components/FriendModelItem/index.tsx new file mode 100644 index 0000000..54f376b --- /dev/null +++ b/components/create/components/ModelSelectionDrawer/components/FriendModels/components/FriendModelItem/index.tsx @@ -0,0 +1,61 @@ +import { FriendModel, Model } from "@/types/ai"; +import { FriendInfo } from "./components/FriendInfo"; +import { Collapse } from "@mui/material"; +import { useEffect, useState } from "react"; +import { ModelListItem } from "../../../ModelItem"; +import { useGenerationContext } from "@/components/create/context/GenerationContext"; + +type Props = { + item: FriendModel; +}; + +export const FriendModelItem = ({ item }: Props) => { + const [isCollapse, setIsCollapse] = useState(false); + + const { selectedModel, setSelectedModel } = useGenerationContext(); + + useEffect(() => { + if ( + selectedModel && + item.models.filter((data) => data.modelId === selectedModel.modelId) + .length > 0 + ) { + setIsCollapse(true); + } + }, []); + + return ( +
+
setIsCollapse(!isCollapse)} + > + +
+ +
+ {item.models.map((model, index) => ( + + setSelectedModel({ + modelId: model.modelId, + modelName: model.modelName, + classType: model.classType, + }) + } + modelName={model.modelName} + className="border-grey-600 py-3" + /> + ))} +
+
+
+ ); +}; diff --git a/components/create/components/ModelSelectionDrawer/components/FriendModels/index.tsx b/components/create/components/ModelSelectionDrawer/components/FriendModels/index.tsx new file mode 100644 index 0000000..ecc927f --- /dev/null +++ b/components/create/components/ModelSelectionDrawer/components/FriendModels/index.tsx @@ -0,0 +1,152 @@ +import { getFriendAiModels } from "@/api/ai/getFriendAiModels"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import SearchIcon from "@/utils/icons/topbar/SearchIcon"; +import React, { ChangeEvent, useEffect, useRef, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { FriendModelItem } from "./components/FriendModelItem"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { CircularProgress } from "@mui/material"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import { updateModels } from "@/redux/slices/modelSlice"; + +type Props = { + handleScrollTop: () => void; +}; + +type LastDoc = { + lastDocId: string; + searchScore: number; +}; + +type GetFriendModelProps = { + lastDoc?: LastDoc; + search: string; +}; + +let docLimit = 10; + +export const FriendModelContainer = ({ handleScrollTop }: Props) => { + const dispatch = useDispatch(); + + const user = useSelector((state: RootState) => state.user); + const models = useSelector((state: RootState) => state.models); + + const { sendNotification } = useAuthContext(); + + const [hasMoreModel, setHasMoreModel] = useState(true); + const [friendSearch, setFriendSearch] = useState(""); + + const ref = useRef(null); + + const getFriendModels = async ({ lastDoc, search }: GetFriendModelProps) => { + if (!user) return; + + const res = await getFriendAiModels({ + user_id: user.userId, + limit: docLimit, + ...(lastDoc && { lastDoc }), + search, + }); + + if (res.status === 200) { + const currentFriendModelList = res.data.friendsModelList; + if (currentFriendModelList.length < docLimit) { + setHasMoreModel(false); + } + + if (currentFriendModelList.length > 0) { + if (lastDoc) { + if (models.friendModelList !== currentFriendModelList) { + dispatch( + updateModels({ + friendModelList: [ + ...models.friendModelList, + ...currentFriendModelList, + ], + }) + ); + } + return; + } + dispatch(updateModels({ friendModelList: currentFriendModelList })); + } + return; + } + + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + let timerId: any; + + clearTimeout(timerId); + + timerId = setTimeout(() => { + setHasMoreModel(true); + dispatch(updateModels({ friendModelList: [] })); + getFriendModels({ search: friendSearch }); + }, 1000); + + return () => { + clearTimeout(timerId); + }; + }, [friendSearch]); + + const fetchMoreModel = async () => { + const lastDoc = { + lastDocId: friendModelList[friendModelList.length - 1].userId, + searchScore: friendModelList[friendModelList.length - 1].searchScore, + }; + + getFriendModels({ + lastDoc, + search: friendSearch, + }); + }; + + const { friendModelList = [] } = models; + + return ( +
+
+
+

Friends Model

+
handleScrollTop()}> + +
+
+ + +
+ } + placeholder="Search Model" + onChange={(e: ChangeEvent) => + setFriendSearch(e.target.value) + } + /> +
+
+ + +
+ } + scrollableTarget="friendModelScrollableDiv" + > + {friendModelList.map((item, index) => ( + + ))} + + + + ); +}; diff --git a/components/create/components/ModelSelectionDrawer/components/ModelItem.tsx b/components/create/components/ModelSelectionDrawer/components/ModelItem.tsx new file mode 100644 index 0000000..8411b28 --- /dev/null +++ b/components/create/components/ModelSelectionDrawer/components/ModelItem.tsx @@ -0,0 +1,54 @@ +import { theme } from "@/theme"; +import { LockIcon } from "@/utils/icons/shared"; +import { Box } from "@mui/material"; + +type Props = { + modelName: string; + startIcon?: JSX.Element; + handleSelectModel: () => void; + isSelected: boolean; + className?: string; + isActive: boolean; +}; + +export const ModelListItem = ({ + modelName, + startIcon, + handleSelectModel, + isSelected, + className = "", + isActive, +}: Props) => { + return ( + handleSelectModel()} + > + {!isActive ? ( +
+ +
+ ) : null} + {startIcon && startIcon} +

{modelName}

+
+ ); +}; diff --git a/components/create/components/ModelSelectionDrawer/index.tsx b/components/create/components/ModelSelectionDrawer/index.tsx new file mode 100644 index 0000000..5c4e3cf --- /dev/null +++ b/components/create/components/ModelSelectionDrawer/index.tsx @@ -0,0 +1,116 @@ +import React, { useRef } from "react"; +import WititLogoIcon from "@/utils/icons/shared/WititLogoIcon"; +import OpenLockIcon from "@/utils/icons/shared/OpenLockIcon"; +import CustomButton from "../../../shared/CustomButton"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import { Model } from "@/types/ai"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; +import { FriendModelContainer } from "./components/FriendModels"; +import { ModelListItem } from "./components/ModelItem"; +import { useGenerationContext } from "../../context/GenerationContext"; +import { it } from "node:test"; + +type Props = { + handleCloseDrawer: () => void; +}; + +const ModelSelectionDrawer = ({ handleCloseDrawer }: Props) => { + const ref = useRef(null); + + const { selectedModel, setSelectedModel } = useGenerationContext(); + + const models = useSelector((state: RootState) => state.models); + + if (!selectedModel) return <>; + + const handleScrollTop = () => { + if (!ref.current) return; + ref.current.scrollTo({ top: 0, behavior: "smooth" }); + }; + + return ( +
+
+

Select Model

+
handleCloseDrawer()} + > + +
+
+
+
+
+ {models.baseModelList.map((item, index) => ( + } + handleSelectModel={() => + setSelectedModel({ + modelId: item.modelId, + modelName: item.modelName, + classType: "Style", + }) + } + /> + ))} +
+
+

Your Model

+
+ {models.userModelList.map((item, index) => ( + { + if (item.isActive) { + setSelectedModel({ + modelId: item.modelId, + modelName: item.modelName, + classType: item.classType, + }); + } + }} + /> + ))} +
+
+
+ + +
+ } + className="lg:px-10 px-5 py-3 text-sm bg-primary-main bg-opacity-[0.16] rounded-lg text-primary-light" + /> +
+
+
+ +
+
+ handleCloseDrawer()} + /> +
+
+ + ); +}; + +export default ModelSelectionDrawer; diff --git a/components/create/context/GenerationContext.tsx b/components/create/context/GenerationContext.tsx new file mode 100644 index 0000000..a0942ad --- /dev/null +++ b/components/create/context/GenerationContext.tsx @@ -0,0 +1,105 @@ +import { createContext, useContext, useEffect, useState } from "react"; +import { ImageInfo } from "@/types"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import { GetAiGeneration, Model, PostAiGeneration } from "@/types/ai"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { io } from "socket.io-client"; +import { useForm } from "react-hook-form"; + +type SelectedImage = { + imagePreview: string; + file: File; +}; + +type ContextType = { + selectedImage: SelectedImage | null; + setSelectedImage: React.Dispatch>; + selectedModel: Model | null; + setSelectedModel: React.Dispatch>; + generations: GetAiGeneration[]; + setGenerations: React.Dispatch>; + prompt: string | null; + setPrompt: React.Dispatch>; + calculatedCharge: number; + setCalculatedCharge: React.Dispatch>; +}; + +const defaultContext: ContextType = { + selectedImage: null, + setSelectedImage: () => {}, + selectedModel: null, + setSelectedModel: () => {}, + generations: [], + setGenerations: () => {}, + prompt: null, + setPrompt: () => {}, + calculatedCharge: 0, + setCalculatedCharge: () => {}, +}; + +const Context = createContext(defaultContext); + +function GenerationContext({ children }: { children: React.ReactNode }) { + const [selectedModel, setSelectedModel] = useState(null); + const [generations, setGenerations] = useState([]); + const [prompt, setPrompt] = useState(null); + const [calculatedCharge, setCalculatedCharge] = useState(0); + const [selectedImage, setSelectedImage] = useState( + null + ); + + const user = useSelector((state: RootState) => state.user); + + useEffect(() => { + if (!user) return; + + const socket = io(appConstant.backendUrl, { + path: "/socket.io", + query: { + userId: user.userId, + }, + transports: ["websocket"], + }); + + socket.on("ImageGenerationResponse", (response: GetAiGeneration) => { + setGenerations((generations) => { + return generations.map((generation) => { + if (generation.Id === response.Id) { + return response; + } + return generation; + }); + }); + }); + + return () => { + socket.disconnect(); + }; + }, []); + + return ( + + {children} + + ); +} + +export default GenerationContext; + +export const useGenerationContext = () => useContext(Context); diff --git a/components/create/index.tsx b/components/create/index.tsx new file mode 100644 index 0000000..70ebee3 --- /dev/null +++ b/components/create/index.tsx @@ -0,0 +1,287 @@ +import { generateAiImage } from "@/api/ai/generateTextToImage"; +import { getBaseAndSelfModels } from "@/api/ai/getBaseAndSelfModels"; +import { getGenerationCharge } from "@/api/ai/getGenerationCharge"; +import { useAuthContext } from "@/context/AuthContext"; +import { CreateDrawerType } from "@/pages/create"; +import { updateModels } from "@/redux/slices/modelSlice"; +import { RootState } from "@/redux/store"; +import { AiCharges, PostAiGeneration } from "@/types/ai"; +import { useState, useEffect } from "react"; +import { useForm } from "react-hook-form"; +import { useDispatch, useSelector } from "react-redux"; +import { BottomBar } from "./components/BottomBar"; +import FilterDrawer from "./components/FilterDrawer"; +import { GenerationCreditDialog } from "./components/GenerationCreditDialog"; +import { GenerationList } from "./components/Generations"; +import ModelSelectionDrawer from "./components/ModelSelectionDrawer"; +import { useGenerationContext } from "./context/GenerationContext"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { initialGenerationSetting } from "@/utils/constants/withoutHtml/ai"; + +const defaultValues = { + prompt: "", + numberOfGenerations: 4, + superShoot: false, + image: null, + postId: null, +}; + +export const Create = () => { + const dispatch = useDispatch(); + + const user = useSelector((state: RootState) => state.user); + const baseModels = useSelector( + (state: RootState) => state.models.baseModelList + ); + + const { + selectedModel, + setSelectedModel, + setGenerations, + selectedImage, + setSelectedImage, + prompt, + calculatedCharge, + } = useGenerationContext(); + + const [drawerType, setDrawerType] = useState(null); + const [isCreditDialogOpen, setIsCreditDialogOpen] = useState(false); + const [isGetChargeLoading, setIsGetChargeLoading] = useState(false); + const [isGenerationSubmitting, setIsGenerationSubmitting] = useState(false); + const [isnotEnoughCredit, setIsnotEnoughCredit] = useState(false); + const [generationSetting, setGenerationSetting] = useState( + initialGenerationSetting + ); + const [generationCharge, setGenerationCharge] = useState( + null + ); + + const { + control, + setValue, + handleSubmit, + watch, + getValues, + reset, + resetField, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues, + }); + + const { sendNotification } = useAuthContext(); + + const getUserModels = async () => { + if (!user) return; + + const res = await getBaseAndSelfModels({ user_id: user.userId }); + if (res.status === 200) { + dispatch( + updateModels({ + baseModelList: res.data.baseModelList, + userModelList: res.data.userModelList, + }) + ); + + setSelectedModel({ + modelId: res.data.baseModelList[0].modelId.toString(), + modelName: res.data.baseModelList[0].modelName, + classType: "Base", + }); + return; + } + + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + getUserModels(); + + // return () => { + // getUserModels(); + // }; + }, []); + + useEffect(() => { + setValue("negativePrompt", generationSetting.negativePrompt); + setValue("creationSettings", generationSetting.creationSettings); + setValue("recreationSettings", generationSetting.recreationSettings); + setValue("hiResSettings", generationSetting.hiResSettings); + setValue("inPaintingSettings", generationSetting.inPaintingSettings); + }, [generationSetting]); + + useEffect(() => { + if (selectedModel) { + setValue("modelId", selectedModel.modelId.toString()); + } + }, [selectedModel]); + + useEffect(() => { + if (prompt) { + setValue("prompt", prompt); + } + }, [prompt]); + + useEffect(() => { + if (!isCreditDialogOpen) { + setIsGenerationSubmitting(false); + } + }, [isCreditDialogOpen]); + + const handleGetGenerationCharge = async () => { + if (!user || !selectedModel) return; + + let newCreationSettings = { ...generationSetting.creationSettings }; + newCreationSettings.imageSize = baseModels.find( + (model) => model.modelId === selectedModel?.modelId + ) + ? newCreationSettings.imageSize || "md" + : "lg"; + + setIsGetChargeLoading(true); + const result = await getGenerationCharge({ + user_id: user.userId, + modelId: selectedModel.modelId.toString(), + creationSettings: newCreationSettings, + postId: null, + }); + + if (result.status === 200 && result.data) { + setGenerationCharge(result.data.charges); + setIsCreditDialogOpen(true); + setIsGetChargeLoading(false); + return; + } + if (result.status === 403) { + setIsnotEnoughCredit(true); + return; + } + sendNotification({ type: "ERROR", message: result.error }); + }; + + const onGenerate = async (data: PostAiGeneration) => { + if (!user) return; + + data.creationSettings.imageSize = baseModels.find( + (model) => model.modelId === selectedModel?.modelId + ) + ? data.creationSettings.imageSize + : "lg"; + + setIsGenerationSubmitting(true); + + if (selectedImage) { + const image = await uploadImageToStorage({ + folderName: "generation_images", + file: selectedImage.file, + metadata: { + userId: user.userId, + }, + }); + + data.image = image; + } + + const result = await generateAiImage({ + user_id: user.userId, + generationBody: data, + }); + + if (result.status === 200) { + setGenerations((preData) => { + if (result.data) { + return [result.data, ...preData]; + } else { + return preData; + } + }); + + setIsCreditDialogOpen(false); + // reset(); + resetField("image"); + resetField("postId"); + resetField("numberOfGenerations"); + resetField("prompt"); + resetField("superShoot"); + + setSelectedImage(null); + + return; + } + + setIsGenerationSubmitting(false); + sendNotification({ type: "ERROR", message: result.error }); + }; + + return ( +
e.preventDefault()} + > +
+
+ +
+
+ setDrawerType(type)} + control={control} + setValue={setValue} + handleGetGenerationCharge={() => handleGetGenerationCharge()} + isGetChargeLoading={isGetChargeLoading} + /> + {isCreditDialogOpen && generationCharge ? ( + + ) : null} + + {drawerType ? ( +
+
setDrawerType(null)} + >
+
+ {drawerType === "MODEL_SELECTION" ? ( + setDrawerType(null)} + /> + ) : ( + setDrawerType(null)} + /> + )} +
+
+ ) : null} + + ); +}; diff --git a/components/discover/FeedItem.tsx b/components/discover/FeedItem.tsx new file mode 100644 index 0000000..28a89dd --- /dev/null +++ b/components/discover/FeedItem.tsx @@ -0,0 +1,129 @@ +import { DiscoverPost } from "@/types/post"; +import TravelCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/TravelCategoryIcon"; +import { ListItem, Grid, Tooltip } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import ImagePreviewBox from "./ImagePreviewBox"; +import { CustomTooltip } from "../shared/CustomTooltip"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +type Props = { + post: DiscoverPost; + height?: number; +}; + +const FeedItem = ({ post, height }: Props) => { + const [isImageHovered, setisImageHovered] = useState(false); + // const aspectRatio = post.image[0].width / post.image[0].height; + + // useEffect(() => { + // setTimeout(() => { + // setIsShowImage(true); + // }, 1000); + // }, []); + + return ( + + {/* {isShowImage ? ( + <> */} + {post.category.includes("NSFW") ? ( + + ) : ( +
{ + setisImageHovered(true); + }} + onMouseLeave={() => { + setisImageHovered(false); + }} + > + + + {isImageHovered && post.category.length > 0 ? ( +
+ {post.category.slice(0, 3).map((catName, index) => { + const icon = CategoryList.filter( + (category) => category.name === catName + ); + const isLastCat = + post.category.length <= 3 + ? index === post.category.length - 1 + : index === 2; + return ( + +
+ {icon.length > 0 ? ( + icon[0].startIcon + ) : ( + + )} +
+
+ ); + })} +
+ ) : null} + + {/* {isImageHovered ? ( + +
+
+ {post.category.map((cat_name, index) => { + return ( + <> + {index < 3 ? ( + +
+
+
+ +
+
+
+
+ ) : null} + + ); + })} +
+
+ +

Jenny Wilson

+
+
+
+ ) : null} */} +
+ )} + {/* + ) : null} */} +
+ ); +}; + +export default FeedItem; diff --git a/components/discover/ImagePreviewBox.tsx b/components/discover/ImagePreviewBox.tsx new file mode 100644 index 0000000..4edcb30 --- /dev/null +++ b/components/discover/ImagePreviewBox.tsx @@ -0,0 +1,75 @@ +import VisibilityOffIcon from "@/utils/icons/shared/VisibilityOffIcon"; +import TravelCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/TravelCategoryIcon"; +import { CircularProgress, Grid } from "@mui/material"; +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { Blurhash } from "react-blurhash"; +import { CustomImagePreview } from "../shared/CustomImagePreview"; +import CustomButton from "../shared/CustomButton"; +import { useDispatch, useSelector } from "react-redux"; +import { addViewedNSFWPost } from "@/redux/slices/viewedNSFWSlice"; +import { RootState } from "@/redux/store"; +import { set } from "react-hook-form"; + +type Image = { + url: string; + width: number; + height: number; + blurhash: string; +}; + +type Props = { + image: Image; + isNSFW: boolean; + postId: string; + // setImageData: React.Dispatch>; +}; + +const ImagePreviewBox = ({ image, isNSFW, postId }: Props) => { + const dispatch = useDispatch(); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + + const isViewdPost = viewedNsfwList.find((post) => post === postId); + const [isNSFWVisible, setIsNSFWVisible] = useState(false); + useEffect(() => { + if (isViewdPost) { + setIsNSFWVisible(false); + } else { + setIsNSFWVisible(isNSFW); + } + }, [isNSFW, isViewdPost]); + + return ( +
+
+ +
+ {isNSFWVisible ? ( +
+
+ +
+

NSFW

+

+ Sensitive content, viewer discretion advised. +

+ ) => { + e.stopPropagation(); + dispatch(addViewedNSFWPost({ postId: postId })); + setIsNSFWVisible(!isNSFWVisible); + }} + /> +
+ ) : ( +
+ +
+ )} +
+ ); +}; + +export default ImagePreviewBox; diff --git a/components/discover/ViewPromptDrawer.tsx b/components/discover/ViewPromptDrawer.tsx new file mode 100644 index 0000000..81d88a8 --- /dev/null +++ b/components/discover/ViewPromptDrawer.tsx @@ -0,0 +1,239 @@ +import CreateIcon from "@/utils/icons/navbar/CreateIcon"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import CommentQuestionIcon from "@/utils/icons/shared/CommentQuestionIcon"; +import CopyIcon from "@/utils/icons/shared/CopyIcon"; +import DashIcon from "@/utils/icons/shared/DashIcon"; +import React, { useEffect } from "react"; +import CustomButton from "../shared/CustomButton"; +import CustomDrawer from "../shared/drawer/CustomDrawer"; +import { PromptDetail } from "@/types/post"; +import { imageSizes } from "@/utils/constants/withoutHtml/ai"; +import { IconButton } from "@mui/material"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import MomentsIcon from "@/utils/icons/profile/MomentsIcon"; + +type Props = { + setPromptDetails: React.Dispatch>; + promptDetails: PromptDetail; +}; +const ViewPromptDrawer = ({ setPromptDetails, promptDetails }: Props) => { + const { discoverSearch, sendNotification } = useAuthContext(); + + useEffect(() => { + if (discoverSearch?.search && discoverSearch.search.length > 0) { + setPromptDetails(null); + } + }, [discoverSearch]); + + const handleCopyPrompt = () => { + navigator.clipboard.writeText(promptDetails.prompt); + sendNotification({ type: "SUCCESS", message: "Prompt Coppied!!" }); + }; + return ( + setPromptDetails(null)} + > +
+
+
+
+ +
+
Prompt
+
+ { + setPromptDetails(null); + }} + > + + +
+ +
+
+
+
+

Prompts Used

+ handleCopyPrompt()} + > + + +
+
+ {promptDetails.prompt} +
+
+
+

Model Name

+

{promptDetails.modelName}

+
+
+ {promptDetails.negativePrompt && + promptDetails.negativePrompt.length > 0 ? ( +
+
+ +
+
+

Negative Prompts

+

+ {promptDetails.negativePrompt.map( + (prompt, index) => + prompt + + (index < promptDetails.negativePrompt.length - 1 + ? ", " + : "") + )} +

+
+
+ ) : null} + {promptDetails.creationSettings ? ( +
+
+ +
+
+

Creation Settings

+
+ {/* when imagesize.tag is same as promptDetails.creationSettings.imageSize.toString() that tiem i want tp return imagesize.name + write a code */} + + + value.tag === + promptDetails.creationSettings.imageSize.toString() + )?.name || "-" + } + /> + + + + + +
+
+
+ ) : null}{" "} + {promptDetails.recreationSettings ? ( +
+
+ +
+
+

Recreation Settings

+ + {promptDetails.recreationSettings.recreationType ? ( + + ) : null} + + {promptDetails.recreationSettings.recreationTypeStrength ? ( + + ) : null} +
+
+ ) : null} + {promptDetails.hiResSettings ? ( +
+
+ +
+
+

Power Upscale Settings

+ + {promptDetails.hiResSettings.similarityStrength ? ( + + ) : null} + + {promptDetails.hiResSettings.increaseResolution ? ( + + ) : null} +
+
+ ) : null} +
+
+ + {/*
+ { + setPromptDetails(null); + }} + /> +
*/} +
+
+
+ ); +}; + +export default ViewPromptDrawer; + +type ViewPromptModelItemProps = { + title: string; + value: string; +}; + +const ViewPromptModelItem = ({ title, value }: ViewPromptModelItemProps) => { + return ( +
+

{title}

+

{value}

+
+ ); +}; diff --git a/components/footerDialogs/ContactUs.tsx b/components/footerDialogs/ContactUs.tsx new file mode 100644 index 0000000..8cc8417 --- /dev/null +++ b/components/footerDialogs/ContactUs.tsx @@ -0,0 +1,120 @@ +import React, { useState } from "react"; +import CustomInputTextField from "../shared/CustomInputTextField"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomDialogCommonTopBar from "../shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +import { SelectDropDown } from "../shared/dropDown/SelectDropDown"; +import { Controller, useForm } from "react-hook-form"; +import CustomLoadingButton from "../shared/CustomLoadingButton"; +import sendSupportEmail from "@/api/support/sendSupportEmail"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; + +const info = ["General", "Account", "Contact", "NSFW Content", "About Witit"]; +type Props = { + onCancel: () => void; +}; + +const ContactUs = ({ onCancel }: Props) => { + const [isLoading, setIsLoading] = useState(false); + const { + handleSubmit, + control, + setValue, + getValues, + formState: { errors }, + } = useForm({ + defaultValues: { + subject: "General", + message: "", + }, + }); + const { sendNotification } = useAuthContext(); + const user = useSelector((state: RootState) => state.user); + + const handleSelect = (target: string) => { + setValue("subject", target); + }; + + const sendContact = async (data: { message: string; subject: string }) => { + setIsLoading(true); + if (!user) { + return; + } + const response = await sendSupportEmail({ data, user_Id: user.userId }); + if (response.status === 200) { + sendNotification({ type: "SUCCESS", message: "Email Send Successfully" }); + setIsLoading(false); + onCancel(); + return; + } + setIsLoading(false); + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( +
+ +
+
+
+ Subject +
+ +
+ +
+ { + return ( + <> + + + ); + }} + /> +

+ {errors.message?.message} +

+
+

+ We value all of our users, their thoughts, concerns, and support. + However we aren’t able to get back to everyone. We will do our best to + review your message as soon as we can. +

+
+ +
+ { + handleSubmit(sendContact)(); + }} + /> +
+
+ ); +}; + +export default ContactUs; diff --git a/components/footerDialogs/ContentPolicy.tsx b/components/footerDialogs/ContentPolicy.tsx new file mode 100644 index 0000000..cacbdf7 --- /dev/null +++ b/components/footerDialogs/ContentPolicy.tsx @@ -0,0 +1,111 @@ + +import React from "react"; +import CustomDialogCommonTopBar from "../shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; + +type Props = { + onCancel: () => void; +}; +const ContentPolicy = ({ onCancel }: Props) => { + return ( +
+ + +
+
+ Introduction: +
+
+ Witit is a social media platform leveraging artificial intelligence + (“AI”) to enable users to create and share distinctive content, such + as AI-generated photographs. We aim to create a safe, respectful + community and uphold standards for appropriate content. This Content + Policy guides users in understanding the type of content that can be + shared on the platform, in alignment with all applicable laws and + regulations. +
{" "} +
+ Prohibited Content: +
+
+ To maintain a positive user experience, we prohibit sharing of content + that is illegal, harmful, threatening, abusive, harassing, defamatory, + obscene, or offensive, which includes but is not limited to: +
+
    +
  • + Content promoting or glorifying hate, violence, or discrimination + based on race, ethnicity, religion, gender, sexual orientation, or + any other characteristic. +
  • +
  • Content depicting or glorifying violence or self-harm.
  • +
  • Harassing, bullying, or defamatory content.
  • +
  • Illegal content or content encouraging illegal activities.
  • +
  • + Content infringing on the intellectual property rights of third + parties. +
  • +
+
+ Witit retains the right to remove any content that violates this + Content Policy and may terminate the accounts of users engaging in + prohibited conduct. +
+
+ Reporting Prohibited Content: +
+
+ If you come across content you believe infringes upon this Content + Policy, please report it to us at support@witit.com. We'll review + all reported content and take appropriate action, including, but not + limited to, removing the content or terminating the user's + account. +
+
+ Disclaimer of Responsibility: +
+
+ While we aim to provide a safe platform, Witit is not responsible for + content uploaded, posted, or shared by its users. We do not endorse or + guarantee the accuracy, completeness, or reliability of any content. + Users bear the responsibility for their own content and the + repercussions of sharing it. +
{" "} +
+ Use of AI-generated Content: +
+
+ Content created using our AI is subject to the same guidelines as any + other user-generated content on our platform. Users are solely + responsible for how they use and share AI-generated content. +
{" "} +
+ Verification and Training Data: +
+
+ As part of our user verification process, we may use identification + documents and personal photos. However, these are used strictly for + verification and AI training and must not be shared or posted as + content on our platform. +
+
+ Changes to Content Policy: +
+
+ Witit reserves the right to amend this Content Policy as required. We + encourage users to review this policy regularly to stay informed about + changes. Continued use of the Witit platform after modifications + implies acceptance of the revised Content Policy. +
+
+ Contact Information: +
+
+ Should you have any queries or concerns related to this Content Policy + or the Witit platform, kindly reach out to us at support@witit.com. +
+
+
+ ); +}; + +export default ContentPolicy; diff --git a/components/footerDialogs/PrivacyPolicy.tsx b/components/footerDialogs/PrivacyPolicy.tsx new file mode 100644 index 0000000..5aa3deb --- /dev/null +++ b/components/footerDialogs/PrivacyPolicy.tsx @@ -0,0 +1,124 @@ +import { theme } from "@/theme"; +import { Divider } from "@mui/material"; +import React from "react"; +import CustomDialogCommonTopBar from "../shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; + +type Props = { + onCancel?: () => void; +}; +const PrivacyPolicy = ({ onCancel }: Props) => { + return ( +
+ + +
+
+ Introduction: +
+
+ Witit is a social media platform that employs artificial intelligence + (“AI”) to enable users to create and share unique content, such as + AI-generated images. Upholding the privacy and trust of our users is + at the heart of our operations, and this Privacy Policy outlines our + data collection, usage, and sharing practices. +
+
+ Information Collection and Use: +
+
+ To deliver our services and enhance the Witit platform, we gather and + utilize personal data. This might encompass information like your + name, email address, payment details, and content you generate, post, + or share on the platform. +
+
+ We also assemble data regarding your interactions with the platform + and other users, which assists us in improving our services and + ensuring compliance with our Terms of Service. +
+
+ Information Sharing and Disclosure: +
+
+ We respect your privacy and do not sell or rent your personal + information to third parties for marketing purposes. However, we may + share your information with affiliates and service providers as + necessary for the provision and operation of our services. +
+
+ In certain cases, Witit may disclose personal information in + accordance with legal requirements, such as a court order or subpoena, + or in response to a law enforcement agency’s request. We may also + release such data if we believe it necessary to uphold our rights, + safeguard your security or the safety of others, investigate potential + fraudulent activity, or answer a government request. +
+
+ Security: +
+
+ Witit takes comprehensive measures, including encryption and secure + servers, to ensure the security of your personal information. + Nonetheless, no method of transmission over the internet or method of + electronic storage is completely secure, hence we cannot guarantee the + absolute security of your data. +
+
+ User Verification Information: +
+
+ To maintain the integrity of our platform, we collect identification + documents, such as driver's licenses, during our user + verification process. However, this information is used solely for + verification purposes and is not used or disclosed for any other + purpose. +
+
+ AI Training Data: +
+
+ We may use the content you upload to Witit as training data for our + AI. We are committed to handling this data responsibly and will not + use it for purposes beyond improving our AI capabilities. +
+
+ Off-Platform Content Distribution: +
+
+ Please note that we are not responsible for any content generated on + Witit that is shared or distributed off our platform. Our commitment + to user privacy extends only to data and content shared within our + platform. +
+
+ Cookies: +
+
+ Witit may employ cookies and similar technologies to monitor and + gather data about your usage of the Witit platform. You can manage the + use of cookies via your browser settings. +
+
+ Changes to Privacy Policy: +
+
+ Witit may periodically update this Privacy Policy. We recommend you + review this policy regularly to stay informed about our practices. + Your continued use of the Witit platform following any modifications + indicates your acceptance of the updated Privacy Policy. +
+
+ Contact Information: +
+
+ For any queries or concerns regarding this Privacy Policy or the Witit + platform, please reach out to us at support@witit.com. Your privacy + matters to us, and we're committed to addressing your concerns + promptly. +
+
+
+ ); +}; + +export default PrivacyPolicy; diff --git a/components/footerDialogs/TermsOfServices.tsx b/components/footerDialogs/TermsOfServices.tsx new file mode 100644 index 0000000..2e4de5f --- /dev/null +++ b/components/footerDialogs/TermsOfServices.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import CustomDialogCommonTopBar from "../shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +type Props = { + onCancel?: () => void; +}; + +const TermsOfServices = ({ onCancel }: Props) => { + return ( +
+ + +
+

+ What is NSFW Content? +

+
+ NSFW is an abbreviation for the phrases such as: “Not Safe For Wife”, + “Not Suitable For Work”, but mostly used as “Not Safe For Work” +
+
+ It is an internet slang that is often used to describe internet posts + and content that is mainly involves nudity, sexual activity, heavy + profanity and more... +
+
+ With Witit, we want to provide a safe place for people to freely + express art or interests that they couldn’t otherwise share on other + platforms. However doing so comes with some requirements, such as + needing to turn on the ability to see and post NSFW content. +
+
+ NSFW is also not a free pass to post anything you want, we at Witit + just allow you fewer restricts than our social media companions. We + still do not tolerate obscene violence or illegal activity of any + sort. +
+
+ Accounts that post NSFW content have been marked with a red + verification badge. +
+
+
+ ); +}; + +export default TermsOfServices; diff --git a/components/home/ForgetPassword.tsx b/components/home/ForgetPassword.tsx new file mode 100644 index 0000000..e2bb782 --- /dev/null +++ b/components/home/ForgetPassword.tsx @@ -0,0 +1,100 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { ResetAccountPassword } from "@/service/firebase/auth"; +import { useDispatch } from "react-redux"; +import { Controller, useForm } from "react-hook-form"; +import { Box } from "@mui/material"; +import getFirebaseErrorMessage from "@/service/firebase/errorCode"; +import LoginTag from "@/components/shared/LoginTag"; + +import CustomInputTextField from "../shared/CustomInputTextField"; +import { useAuthContext } from "@/context/AuthContext"; +import { EmailIcon } from "@/utils/icons/shared"; + +type Props = { + setActiveStep: React.Dispatch>; +}; + +export default function ForgetPasswordBox({ setActiveStep }: Props) { + let dispatch = useDispatch(); + + const { sendNotification } = useAuthContext(); + + const { + handleSubmit, + control, + setValue, + reset, + setError, + clearErrors, + getValues, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + email: "", + }, + mode: "onChange", + }); + + const onSubmit = async (data: any) => { + sendNotification({ type: "LOADING" }); + const result = await ResetAccountPassword(data?.email); + if (result.status === 200) { + sendNotification({ type: "SUCCESS", message: "Check Your Email" }); + setActiveStep(-1); + } else { + const errorMessage = await getFirebaseErrorMessage(result?.error); + sendNotification({ type: "ERROR", message: errorMessage }); + } + }; + + return ( +
+
+ + + ( + } + /> + )} + /> + +
+ +
+

+ Don’t have an account? + setActiveStep(0)} + className="font-semibold ml-1 leading-6 text-primary-main hover:underline cursor-pointer " + > + Sign up + +

+ +
+ ); +} diff --git a/components/home/ImageSliderAnimationShowBox.tsx b/components/home/ImageSliderAnimationShowBox.tsx new file mode 100644 index 0000000..0ec5bab --- /dev/null +++ b/components/home/ImageSliderAnimationShowBox.tsx @@ -0,0 +1,130 @@ +/* eslint-disable @next/next/no-img-element */ +import React, { useEffect, useState } from "react"; + +import Image from "next/image"; +import { + image1, + image2, + image3, + image4, + image5, + image6, + image7, + image8, + image9, + image10, + image11, + image12, + image13, + image14, + image15, + image16, +} from "@/utils/constants/withoutHtml/loginImages"; +import { CustomImagePreview } from "../shared/CustomImagePreview"; + +const ImageLine = ({ imageList }: { imageList: string[] }) => { + return ( + <> +
+ {imageList.map((image, index) => { + return ( +
+ +
+ ); + })} +
+
+ {imageList.map((image, index) => { + return ( +
+ +
+ ); + })} +
+ + ); +}; + +export const ImageSliderAnimationShowBox = () => { + return ( + <> +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+

+ Some Images which are generate through witit +

+
+ + ); +}; diff --git a/components/home/LoginBox.tsx b/components/home/LoginBox.tsx new file mode 100644 index 0000000..4573e28 --- /dev/null +++ b/components/home/LoginBox.tsx @@ -0,0 +1,194 @@ +import VisibilityIcon from "@mui/icons-material/Visibility"; +import CustomButton from "@/components/shared/CustomButton"; +import { useState } from "react"; +import { LoginToAccount } from "@/service/firebase/auth"; +import CustomLink from "@/components/shared/CustomLink"; +import { getUser } from "@/api/user/getUser"; +import { useDispatch } from "react-redux"; +import { useRouter } from "next/router"; +import { Controller, useForm } from "react-hook-form"; +import { Box, Stack, Typography } from "@mui/material"; +import getFirebaseErrorMessage from "@/service/firebase/errorCode"; +import LoginTag from "@/components/shared/LoginTag"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomInputTextField from "../shared/CustomInputTextField"; +import { setReduxUser } from "@/redux/slices/userSlice"; +import VisibilityOffIcon from "@/utils/icons/shared/VisibilityOffIcon"; +import { EmailIcon, LockIcon } from "@/utils/icons/shared"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { VisibilityOff } from "@mui/icons-material"; + +type Props = { + setActiveStep: React.Dispatch>; +}; + +export default function LoginBox({ setActiveStep }: Props) { + let dispatch = useDispatch(); + const router = useRouter(); + + const { sendNotification, lastVisitedPage } = useAuthContext(); + + const [passwordVisibility, setPasswordVisibility] = useState(false); + + const { + handleSubmit, + control, + setValue, + reset, + setError, + clearErrors, + getValues, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + email: "", + password: "", + }, + mode: "onChange", + }); + + const onSubmit = async (data: any) => { + sendNotification({ type: "LOADING" }); + + // login to firebase + const user: any = await LoginToAccount(data?.email, data?.password); + if (user.status !== 200) { + const errorMessage = await getFirebaseErrorMessage(user?.error); + sendNotification({ type: "ERROR", message: errorMessage }); + return; + } + + // send to verification screen if email not verified + if (!user?.data?.emailVerified) { + sendNotification({ type: "REMOVE" }); + setActiveStep(1); + return; + } + + const userId = user?.data?.uid; + + const userData = await getUser(userId); + // if account not found then redirect to account-setup screen + if (userData?.status === 404) { + sendNotification({ type: "REMOVE" }); + router.push(appConstant.pageRoute.accountSetup); + return; + } + + // if user found redirect to setting screen + if (user.status === 200) { + dispatch(setReduxUser(userData.data)); + sendNotification({ + type: "SUCCESS", + message: "You have Successfully Login", + }); + if ( + lastVisitedPage === appConstant.pageRoute.login || + lastVisitedPage === null + ) { + router.push(appConstant.pageRoute.create); + } else { + router.push(lastVisitedPage); + } + } else { + sendNotification({ type: "ERROR", message: userData?.error }); + } + }; + const OnEndIconClick = () => { + setPasswordVisibility(!passwordVisibility); + }; + return ( +
+
+ + + + ( + } + /> + )} + /> + + + ( + } + EndIcon={ + !passwordVisibility ? : + } + EndIconHandleEvent={OnEndIconClick} + visibility={passwordVisibility} + /> + )} + /> + + + + +

setActiveStep(-2)} + className=" text-error-main text-[0.9rem] cursor-pointer" + > + Forgot Password ? +

+
+
+ +
+

+ New Member? + setActiveStep(0)} + className="font-semibold ml-1 leading-6 text-primary-main hover:underline cursor-pointer " + > + Sign up + +

+
+
+ ); +} diff --git a/components/home/SignUp.tsx b/components/home/SignUp.tsx new file mode 100644 index 0000000..678c222 --- /dev/null +++ b/components/home/SignUp.tsx @@ -0,0 +1,201 @@ +import CustomButton from "@/components/shared/CustomButton"; +import VisibilityIcon from "@mui/icons-material/Visibility"; +import VisibilityOffIcon from "@mui/icons-material/VisibilityOff"; + +import { Box, Dialog, Stack, Typography } from "@mui/material"; +import { useState } from "react"; + +import { Controller, useForm, useWatch } from "react-hook-form"; +import { signUpToFirebase } from "@/service/firebase/auth"; +import { useDispatch } from "react-redux"; +import getFirebaseErrorMessage from "@/service/firebase/errorCode"; +import CustomCheckbox from "@/components/shared/CustomCheckbox"; +import LoginTag from "@/components/shared/LoginTag"; + +import CustomInputTextField from "../shared/CustomInputTextField"; +import { useAuthContext } from "@/context/AuthContext"; +import { EmailIcon, LockIcon } from "@/utils/icons/shared"; + +type Props = { + setActiveStep: React.Dispatch>; +}; + +export default function SignUpBox({ setActiveStep }: Props) { + let dispatch = useDispatch(); + + const { sendNotification } = useAuthContext(); + + const [passwordVisibility, setPasswordVisibility] = useState(false); + const [reTypePasswordvisibility, setReTypePasswordvisibility] = + useState(false); + + const { + handleSubmit, + control, + setValue, + reset, + setError, + clearErrors, + getValues, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + email: "", + password: "", + confirmPassword: "", + }, + mode: "onChange", + }); + + const onSubmit = async (data: Record) => { + sendNotification({ type: "LOADING" }); + + const verifyEmail = await signUpToFirebase(data?.email, data?.password); + if (verifyEmail.status === 200) { + sendNotification({ type: "SUCCESS", message: "Check Your Email" }); + setActiveStep(1); + } else { + const errorMessage = await getFirebaseErrorMessage(verifyEmail?.error); + sendNotification({ type: "ERROR", message: errorMessage }); + } + }; + + const email = useWatch({ + control, + name: "email", + }); + + const OnPasswordVisibilitychange = () => { + setPasswordVisibility(!passwordVisibility); + }; + + const setResetPassword = () => { + setReTypePasswordvisibility(!reTypePasswordvisibility); + }; + return ( + <> +
+
+
+ + + ( + } + /> + )} + /> + + ( + } + EndIcon={ + passwordVisibility ? ( + + ) : ( + + ) + } + EndIconHandleEvent={OnPasswordVisibilitychange} + visibility={passwordVisibility} + /> + )} + /> + + + + value === password || "Passwords do not match", + }} + render={({ field }) => ( + } + EndIcon={ + reTypePasswordvisibility ? ( + + ) : ( + + ) + } + EndIconHandleEvent={setResetPassword} + visibility={reTypePasswordvisibility} + /> + )} + /> + + +
+ +
+
+
+

+ Already have an account? + setActiveStep(-1)} + className="font-semibold ml-1 leading-6 text-primary-main hover:underline cursor-pointer" + > + Login + +

+
+ + ); +} diff --git a/components/home/VerifyEmail.tsx b/components/home/VerifyEmail.tsx new file mode 100644 index 0000000..03a1d28 --- /dev/null +++ b/components/home/VerifyEmail.tsx @@ -0,0 +1,90 @@ +import { Box } from "@mui/material"; +import CustomButton from "@/components/shared/CustomButton"; +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { useAuthContext } from "@/context/AuthContext"; +import { sendEmail } from "@/service/firebase/auth"; +import getFirebaseErrorMessage from "@/service/firebase/errorCode"; +import LoginTag from "@/components/shared/LoginTag"; +import { ExternalLinkIcon, RefreshIcon } from "@/utils/icons/shared"; + +export default function VerifyEmail() { + let dispatch = useDispatch(); + const [isEmailSend, setIsEmailSend] = useState(false); + + const { firebaseUser } = useAuthContext(); + + const { sendNotification } = useAuthContext(); + + useEffect(() => { + if (isEmailSend) { + setTimeout(() => { + setIsEmailSend(false); + }, 60000); + } + }, [isEmailSend]); + + const resendEmail = async () => { + if (!firebaseUser) return; + if (!isEmailSend) { + sendNotification({ type: "LOADING" }); + const result = await sendEmail(firebaseUser); + if (result.status === 200) { + setIsEmailSend(true); + sendNotification({ type: "SUCCESS", message: "Check Your email" }); + } else { + const errorMessage = await getFirebaseErrorMessage(result?.error); + sendNotification({ type: "ERROR", message: errorMessage }); + } + } + }; + + return ( +
+ + +
+

Verification mail sent to

+

+ {firebaseUser?.email} +

+
+ + } + className=" py-2" + type="button" + name="Open Gmail" + disabled={isEmailSend} + /> + +
+ +
resendEmail()} + className={`m-auto flex w-fit flex-row items-center gap-2 text-grey-100 justify-center ${ + !isEmailSend ? "cursor-pointer" : "cursor-not-allowed" + }`} + > + +

Send a new Link

+
+ {/*

|

+
+ +

+ Use different mail +

+
*/} +
+
+ ); +} diff --git a/components/message/PersonalChat/components/ChatBottomBar.tsx b/components/message/PersonalChat/components/ChatBottomBar.tsx new file mode 100644 index 0000000..bd3dcd4 --- /dev/null +++ b/components/message/PersonalChat/components/ChatBottomBar.tsx @@ -0,0 +1,292 @@ +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { useAuthContext } from "@/context/AuthContext"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import { CircularProgress, IconButton } from "@mui/material"; +import React, { useEffect, useRef, useState } from "react"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { Image, ImageState } from "@/types/post"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import sendMessage from "@/api/message/sendMessage"; +import { Message } from "@/types/message"; +import { ReduxUser } from "@/types/user"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { createImage } from "@/service/imageCropper/cropImage"; +import CustomCreditMessageDrower from "./CustomCreditMessageDrower"; +import { useMessageContext } from "../../context/MessageContext"; +import { ObjectId } from "bson"; +import { useDispatch } from "react-redux"; +import SelectMultipleImages from "./SelectMultipleImages"; +import { ImageInfo } from "@/types"; + +type Props = { + user: ReduxUser | null; + setMessages: React.Dispatch>; + messages: Message[]; + otherUserDetails: ReduxUser | null; +}; + +const ChatBottomBar = ({ + user, + setMessages, + messages, + otherUserDetails, +}: Props) => { + const [messageImage, setMessageImage] = useState(null); + const [textMessage, setTextMessage] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [createPostImages, setCreatePostImages] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + const { selectedUser } = useMessageContext(); + const dispatch = useDispatch(); + const inputRef = useRef(null); + const { + setCustomDialogType, + croppingImage, + setCroppingImage, + firebaseUser, + customDialogType, + } = useAuthContext(); + + const { sendNotification } = useAuthContext(); + + useEffect(() => { + setCreatePostImages([]); + }, [selectedUser]); + + useEffect(() => { + if (createPostImages?.length > 0) { + inputRef.current?.focus(); + } + }, [createPostImages]); + + if (!user || !selectedUser) { + return <>; + } + + const sendMessages = async () => { + let FirebaseImage: Partial[] = []; + const id = new ObjectId().toString(); + setIsLoading(true); + + if (createPostImages.length > 0) { + const getFirebaseImages: Blob[] = []; + + for (const val of createPostImages) { + const imageInfo = val.image.croppedImageSrc; + const response = await fetch(imageInfo); + const file = await response.blob(); + getFirebaseImages.push(file); + } + + const selectedPhotosList = await Promise.all( + getFirebaseImages.map((file) => { + const folderName = "chat_images"; + return file + ? uploadImageToStorage({ + folderName, + file, + metadata: { + userId: firebaseUser?.uid, + }, + }) + : null; + }) + ); + + const iamgesList = await Promise.all( + selectedPhotosList.map(async (value) => { + const image = value && (await createImage(value)); + + return { + url: value, + width: (image as HTMLImageElement).width, + height: (image as HTMLImageElement).height, + }; + }) + ); + + FirebaseImage = iamgesList as Partial[]; + } + + const responseMessage = await sendMessage({ + receiverId: selectedUser.id, + image: FirebaseImage.length > 0 ? FirebaseImage : null, + user_id: user?.userId, + messageId: id.toString(), + message: textMessage, + }); + + if (responseMessage.status === 200 && responseMessage.data) { + setMessages([responseMessage.data, ...messages]); + setTextMessage(null); + setIsLoading(false); + setMessageImage(null); + setCreatePostImages([]); + + return; + } + sendNotification({ type: "ERROR", message: responseMessage.error }); + setIsLoading(false); + }; + + let messageId = ""; + const id = new ObjectId(); + messageId = id.toString(); + + const selectImages = (images: { image: ImageInfo; index: number }[]) => { + if (createPostImages.length < 0) { + setCreatePostImages(images); + } else { + setCreatePostImages([...createPostImages, ...images]); + } + }; + + const haldleremoveImages = (index: number) => { + const removeImages = createPostImages.filter((val, id) => index !== id); + setCreatePostImages(removeImages); + }; + + return ( +
+ {/* {croppingImage?.image?.src != "" ? ( +
{ + setisImageHovered(true); + }} + onMouseLeave={() => { + setisImageHovered(false); + }} + onClick={() => { + // setCustomDialogType("CROPSINGLEIMG"); + }} + > + {isImageHovered ? ( +
{ + setCroppingImage(defaultImageConstant); + }} + > + +
+ ) : null} +
+ +
+
+ ) : null} */} + {createPostImages?.length > 0 && ( +
+
+ {createPostImages.map((value, index) => { + return ( + <> +
+
haldleremoveImages(index)} + > + +
+ +
+ + ); + })} +
+
{ + setCreatePostImages([]); + }} + > + +
+
+ )} +
+
+ {!messageImage && ( + + + + )} +
+ +
+ ) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + if (textMessage || createPostImages.length > 0) { + sendMessages(); + } + } + }} + EndIcon={ + { + if (textMessage || createPostImages.length > 0) { + sendMessages(); + } + }} + className={ + textMessage || createPostImages.length > 0 + ? "text-primary-main cursor-pointer" + : "text-grey-300 cursor-default" + } + > + {isLoading ? ( + + ) : ( + + )} + + } + className="bg-grey-700 border-none rounded-xl h-fit" + onChange={(e: any) => { + setTextMessage(e.target.value); + }} + /> +
+ + { + setCustomDialogType("CREDITS-MESSAGE"); + }} + className=" bg-grey-700 text-grey-100 hover:text-primary-main w-[60px] h-[60px] rounded-xl flex items-center justify-center" + > + + +
+ {customDialogType === "CREDITS-MESSAGE" ? ( + + ) : null} +
+ ); +}; + +export default ChatBottomBar; diff --git a/components/message/PersonalChat/components/ChatTopbar.tsx b/components/message/PersonalChat/components/ChatTopbar.tsx new file mode 100644 index 0000000..2909d8f --- /dev/null +++ b/components/message/PersonalChat/components/ChatTopbar.tsx @@ -0,0 +1,171 @@ +import { IconDropDown } from "@/components/shared/dropDown/IconDropDown"; +import { theme } from "@/theme"; +import MyProfileIcon from "@/utils/icons/navbar/MyProfileIcon"; +import BlockIcon from "@/utils/icons/shared/BlockIcon"; +import LinkCopyIcon from "@/utils/icons/shared/LinkCopyIcon"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; +import { useMediaQuery } from "@mui/material"; +import { profilePlaceholderImage } from "@/utils/images"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { useMessageContext } from "../../context/MessageContext"; +import { useAuthContext } from "@/context/AuthContext"; +import { useRouter } from "next/router"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { ReduxUser } from "@/types/user"; + +type Props = { + otherUserDetails: ReduxUser | null; + isDataLoading: boolean; + setIsBlockDialogOpen: React.Dispatch>; + setReportingPostIndex: React.Dispatch>; +}; +const ChatTopbar = ({ + otherUserDetails, + isDataLoading, + setIsBlockDialogOpen, + setReportingPostIndex, +}: Props) => { + const isSmallScreen = useMediaQuery(theme.breakpoints.down("xl")); + const { selectedUser, messageCredit } = useMessageContext(); + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + const router = useRouter(); + const url = + window.location.protocol + + "//" + + window.location.host + + `/profile?user=${selectedUser?.id}`; + + const handleCopyProps = () => { + navigator.clipboard.writeText(url); + + sendNotification({ type: "SUCCESS", message: "Link Coppied!!" }); + }; + + const handleItemSelect = (Event: string) => { + if (Event === "Copy Profile Link") { + handleCopyProps(); + return; + } + + if (Event === "Go To Profile") { + router.push(url); + } + if (Event === "Block") { + setIsBlockDialogOpen(true); + } + if (Event === "Report") { + setReportingPostIndex(true); + } + }; + + const menuList = [ + { + icon: , + title: "Go To Profile", + actionType: "Go To Profile", + }, + { + icon: ( +
+ +
+ ), + title: "Copy Profile Link", + actionType: "Copy Profile Link", + }, + { + icon: ( +
+ +
+ ), + title: "Block", + actionType: "Block", + }, + { + icon: ( +
+ +
+ ), + title: "Report", + actionType: "Report", + }, + ]; + + if (!user || !selectedUser) { + return <>; + } + + if (!selectedUser || !otherUserDetails) { + return <>; + } + + return ( +
+
+
+ {isSmallScreen ? ( +
setisMessageListOpen(true)} + > + +
+ ) : null} +
+ {/*
*/} +
+ +
+
+ +
+

+ {selectedUser.userName} + {selectedUser.userType === "VERIFIED" && ( + + + + )} +

+ {!isDataLoading && + user.userType !== "VERIFIED" && + !otherUserDetails.isMyFollower && + otherUserDetails.generationSettings?.creditPerMessage && + otherUserDetails.generationSettings.creditPerMessage > 0 && + !otherUserDetails.blockedBy && ( +

+ {otherUserDetails.generationSettings.creditPerMessage} credit + / message +

+ )} +
+
+
+ {selectedUser?.id !== user?.userId && otherUserDetails?.blockedBy ? ( + <> + ) : ( + + )} +
+
+
+ ); +}; + +export default ChatTopbar; diff --git a/components/message/PersonalChat/components/CustomCreditMessageDrower.tsx b/components/message/PersonalChat/components/CustomCreditMessageDrower.tsx new file mode 100644 index 0000000..88c056f --- /dev/null +++ b/components/message/PersonalChat/components/CustomCreditMessageDrower.tsx @@ -0,0 +1,235 @@ +import { useAuthContext } from "@/context/AuthContext"; +import { theme } from "@/theme"; +import { Divider, IconButton } from "@mui/material"; +import React, { useState } from "react"; +import CreditTopBg from "@/utils/images/CreditTopBg.png"; +import Image from "next/image"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import Slider from "react-slick"; +import CustomButton from "@/components/shared/CustomButton"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import sendCredit from "@/api/stripe/sendCredit"; +import { generateArray } from "@/service/manageCredit/createCreditArray"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import { Message } from "@/types/message"; +import TermsOfServices from "@/components/footerDialogs/TermsOfServices"; +import PrivacyPolicy from "@/components/footerDialogs/PrivacyPolicy"; +import CustomInsufficientCredit from "@/components/shared/CustomInsufficientCredit"; + +var sliderSettings = { + centerMode: true, + centerPadding: "60px", + slidesToShow: 3, + speed: 500, + swipeToSlide: true, + focusOnSelect: true, +}; +type props = { + messageId: string; + creatorId: string; + messages: Message[]; + setMessages: React.Dispatch>; +}; + +const CustomCreditMessageDrower = ({ + messageId, + creatorId, + messages, + setMessages, +}: props) => { + const [currentSlide, setCurrentSlide] = useState(10); + const [policy, setPolicy] = useState(null); + const dispatch = useDispatch(); + const { customDialogType, setCustomDialogType } = useAuthContext(); + const finalArray = generateArray(10, 10000); + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + const [isnotEnoughCredit, setIsnotEnoughCredit] = useState(false); + const settings = { + afterChange: (index: number) => { + finalArray?.map((val, id) => { + if (index === id) { + setCurrentSlide(val); + } + }); + }, + }; + + const postCredits = async () => { + if (!user) { + return; + } + const messageCredit = await sendCredit({ + creatorId, + messageId, + user_id: user?.userId, + credit: currentSlide, + }); + + setCustomDialogType(null); + + if (messageCredit.status === 403) { + setIsnotEnoughCredit(true); + return; + } + sendNotification({ type: "ERROR", message: messageCredit.error }); + }; + + const openGetCreditDialog = () => { + setCustomDialogType("CREDITS-GETCREDITS"); + }; + + const closeDialoag = () => { + setIsnotEnoughCredit(false); + }; + return ( + <> + + {/* top common layout */} +
+
+ { + setCustomDialogType(null); + }} + > + + + + +
+
+

Total Credit Balance

+
+

+ {user?.credit && + user.credit.transferableCredit + + user.credit.nonTransferableCredit + + user.credit.tempCredit} +

+
+ +
+
+
+
+
+
+ +
+
+ + +
+
+
+ (slider = slider)} + {...sliderSettings} + className="slick-slider_center-mode w-full flex flex-row" + > + {finalArray?.map((val, index) => { + return ( +
+

{val}

+
+ ); + })} +
+
+
+ +
+
+ { + postCredits(); + }} + /> +

+ By submitting this request you agree to witit’s +

+

+ { + setPolicy("PRIVACY_POLICYS"); + }} + > + Privacy Policy + {" "} + and + { + setPolicy("TERMS_OF_SERVICES"); + }} + > + Terms of Use + +

+
+
+ {isnotEnoughCredit && ( +
+ +
+ )} +
+ + {policy && ( + + {policy === "TERMS_OF_SERVICES" ? ( + { + setPolicy(null); + }} + /> + ) : policy === "PRIVACY_POLICYS" ? ( + { + setPolicy(null); + }} + /> + ) : null} + + )} + + ); +}; + +export default CustomCreditMessageDrower; diff --git a/components/message/PersonalChat/components/ImageItem.tsx b/components/message/PersonalChat/components/ImageItem.tsx new file mode 100644 index 0000000..4e692a1 --- /dev/null +++ b/components/message/PersonalChat/components/ImageItem.tsx @@ -0,0 +1,119 @@ +import React from "react"; +import { Message } from "@/types/message"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import dayjs from "dayjs"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; + +type Props = { + msg: Message; +}; + +const ImageItem = ({ msg }: Props) => { + let bgColor: string = "bg-primary-main"; + let position: string = "justify-end"; + let isMsg: boolean = false; + let borderStyle = "rounded-br-lg rounded-t-lg"; + + const user = useSelector((state: RootState) => state.user); + + if (msg.receiverId !== user?.userId) { + bgColor = "bg-primary-main"; + position = "items-end"; + borderStyle = "rounded-bl-lg rounded-t-lg"; + } else { + bgColor = "bg-grey-700"; + position = "items-start"; + borderStyle = "rounded-br-lg rounded-t-lg"; + } + + if (msg.type === "MWITHI") { + isMsg = true; + } else { + isMsg = false; + } + return ( +
+
+ {/* {msg.image.map((val) => { + return ( + <> +
+ +
+ + ); + })} */} +
+ {msg.image.map((postImage, index) => { + if (index < 5) { + return ( +
+
+ {msg.image.length > 5 && index === 4 ? ( +
+ +{msg.image.length - 5} +
+ ) : null} + +
5 + ? "opacity-30" + : "opacity-100" + }`} + > + +
+
+
+ ); + } + })} +
+ {isMsg && ( +
+ {msg.message} +
+ )} +
+

+ {dayjs(msg?.createdAt).format("hh:mm A")} +

+
+ ); +}; + +export default ImageItem; diff --git a/components/message/PersonalChat/components/MessageItem.tsx b/components/message/PersonalChat/components/MessageItem.tsx new file mode 100644 index 0000000..9a93e47 --- /dev/null +++ b/components/message/PersonalChat/components/MessageItem.tsx @@ -0,0 +1,41 @@ +import { RootState } from "@/redux/store"; +import { Message } from "@/types/message"; +import dayjs from "dayjs"; +import React, { useEffect } from "react"; +import { useSelector } from "react-redux"; +type Props = { + msg: Message; +}; +const MessageItem = ({ msg }: Props) => { + const user = useSelector((state: RootState) => state.user); + let bgColor: string = "bg-primary-main"; + let position: string = "justify-end"; + let borderStyle = "rounded-br-lg rounded-t-lg"; + + if (msg.receiverId !== user?.userId) { + bgColor = "bg-primary-main"; + position = "items-end"; + borderStyle = "rounded-bl-lg rounded-lg overflow-hidden"; + } else { + bgColor = "bg-grey-700"; + position = "items-start"; + borderStyle = "rounded-br-lg rounded-lg overflow-hidden"; + } + + return ( +
+
+

+ {msg.message} +

+
+

+ {dayjs(msg?.createdAt).format("hh:mm A")}{" "} +

+
+ ); +}; + +export default MessageItem; diff --git a/components/message/PersonalChat/components/SelectMultipleImages.tsx b/components/message/PersonalChat/components/SelectMultipleImages.tsx new file mode 100644 index 0000000..e3f966f --- /dev/null +++ b/components/message/PersonalChat/components/SelectMultipleImages.tsx @@ -0,0 +1,141 @@ +/* eslint-disable @next/next/no-img-element */ +"use client"; +import React, { useState, useRef, useEffect, forwardRef } from "react"; +import { ImageInfo } from "@/types"; +import ImagePlaceHolderGalleryIcon from "@/utils/icons/createPost/ImagePlaceHolderGalleryIcon"; +import Lottie from "lottie-react"; +import ImagePlaceholderLottie from "@/utils/lottie/ImagePlaceholderLottie.json"; +import DisplayMultipleImages from "@/service/imageCropper/DisplayMultipleImages"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; + +type Props = { + setSelectdImgs: ( + images: { + image: ImageInfo; + index: number; + }[] + ) => void; + isSmall: boolean; + isEnabled: boolean; +}; + +const SelectMultipleImages = forwardRef( + ({ setSelectdImgs, isSmall, isEnabled }: Props, ref) => { + const [multiImages, setMultiImages] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + + const imageInputRef = useRef(null); + + useEffect(() => { + if (multiImages.length !== 0) setSelectdImgs(multiImages); + }, [multiImages]); + + const handleImageSelection = ( + event: React.ChangeEvent + ) => { + const files = event.target.files; + if (files) { + // setMultiImages([]); + DisplayMultipleImages(Array.from(files), setMultiImages); + } + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + }; + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + const files = event.dataTransfer.files; + if (files) { + // setMultiImages([]); + DisplayMultipleImages(Array.from(files), setMultiImages); + } + }; + + const handleResetInputValue = (event: any) => { + event.target.value = null; + }; + + const handleImageContainerClick = () => { + if (imageInputRef.current) { + imageInputRef.current.click(); + } + // setTempObjectfit(undefined); + }; + + + + return ( +
+ + {/* */} + + {isSmall ? ( +
+ +
+ ) : ( +
+
+ +
+ + {/*
+
+ {isSmall ? ( + + ) : ( +
+ +
+ )} +
+
+ Drag profile pic here,or + browse +
+
*/} +
+ )} + {/*
*/} +
+ ); + } +); + +SelectMultipleImages.displayName = "images"; + +export default SelectMultipleImages; diff --git a/components/message/PersonalChat/components/SendCreditItem.tsx b/components/message/PersonalChat/components/SendCreditItem.tsx new file mode 100644 index 0000000..b29dd5f --- /dev/null +++ b/components/message/PersonalChat/components/SendCreditItem.tsx @@ -0,0 +1,62 @@ +import React from "react"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import dayjs from "dayjs"; +import { Message } from "@/types/message"; +import { useMessageContext } from "../../context/MessageContext"; + +type Props = { + msg: Message; +}; +const SendCreditItem = ({ msg }: Props) => { + const { selectedUser } = useMessageContext(); + const user = useSelector((state: RootState) => state.user); + + let bgColor: string = "bg-primary-main"; + let position: string = "justify-end"; + let creditPosition: string = "flex-row-reverse"; + let borderStyle = "rounded-br-lg rounded-t-lg"; + + if (msg.receiverId !== user?.userId) { + bgColor = "bg-primary-main"; + creditPosition = "flex-row-reverse"; + position = "items-end"; + borderStyle = "rounded-bl-lg rounded-t-lg overflow-hidden "; + } else { + bgColor = "bg-grey-700"; + position = "items-start"; + creditPosition = "flex-row-reverse"; + borderStyle = "rounded-br-lg rounded-t-lg overflow-hidden "; + } + + return ( +
+
+
+ {msg.receiverId === user?.userId && ( +

Hurray!! Credits Sent to You.

+ )} + {msg.receiverId !== user?.userId && ( + <> +

Oops!! You send Credits.

+

+ To {selectedUser?.userName} +

+ + )} +
+
+

{msg.credit}

+
+
+

+ {dayjs(msg?.createdAt).format("hh:mm A")} +

+
+ ); +}; + +export default SendCreditItem; diff --git a/components/message/PersonalChat/index.tsx b/components/message/PersonalChat/index.tsx new file mode 100644 index 0000000..c425ed7 --- /dev/null +++ b/components/message/PersonalChat/index.tsx @@ -0,0 +1,434 @@ +import React, { useEffect, useRef, useState } from "react"; +import { CircularProgress } from "@mui/material"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { useAuthContext } from "@/context/AuthContext"; +import MessageItem from "./components/MessageItem"; +import ImageItem from "./components/ImageItem"; +import SendCreditItem from "./components/SendCreditItem"; +import { Message } from "@/types/message"; +import getMessages from "@/api/message/getMessages"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import ChatTopbar from "./components/ChatTopbar"; +import ChatBottomBar from "./components/ChatBottomBar"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { io } from "socket.io-client"; +import { useMessageContext } from "../context/MessageContext"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { messageNotFound } from "@/utils/images/message"; +import { getOtherUser } from "@/api/user/getOtherUser"; +import { ReduxUser } from "@/types/user"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import { blockOrUnblockUser } from "@/api/user/blockOrUnblockUser"; +import { blockUserIllustrator } from "@/utils/images"; +import ReportDialog from "@/components/shared/ReportDialog"; +import { reportUser } from "@/api/user/reportUser"; + +const PersonalChat = () => { + const [hasMoreMessage, setHasMoreMessage] = useState(true); + const [messages, setMessages] = useState([]); + const [isBlockDialogOpen, setIsBlockDialogOpen] = useState(false); + const [otherUserDetails, setOtherUserDetails] = useState( + null + ); + const [isDataLoading, setIsDataLoading] = useState(false); + const [isUnBlock, setisUnBlock] = useState(true); + const [reportingPostIndex, setReportingPostIndex] = useState(false); + const { sendNotification } = useAuthContext(); + const { selectedUser } = useMessageContext(); + const user = useSelector((state: RootState) => state.user); + const ref = useRef(null); + + const getMessageList = async (lastDocId?: string) => { + if (!selectedUser) { + return <>; + } + + const response = await getMessages({ + user_id: user?.userId, + receiverId: selectedUser.id, + limit: 10, + ...(lastDocId && { lastDocId }), + }); + + if (response.status === 200 && response.data) { + if (response.data.length < 10) { + setHasMoreMessage(false); + } else { + setHasMoreMessage(true); + } + + if (response.data.length > 0) { + if (lastDocId) { + setMessages([...messages, ...response.data]); + return; + } + } + + setMessages(response.data); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + + const fetchMoreGeneration = async () => { + const lastDocId = messages[messages.length - 1].messageId; + + getMessageList(lastDocId); + }; + + useEffect(() => { + if (!user) return; + + const socket = io(appConstant.backendUrl, { + path: "/socket.io", + query: { + userId: user.userId, + }, + transports: ["websocket", "polling"], + }); + + console.log("message socket connected", socket); + + socket.on("MessageResponse", (response: Message) => { + if (!selectedUser) { + return <>; + } + + if ( + response.receiverId === user.userId && + selectedUser.id === response.senderId + ) { + setMessages((message) => { + if (message.find((d) => d.messageId === response.messageId)) { + return message; + } + return [response, ...message]; + }); + + const data = { + senderId: response.senderId, + receiverId: response.receiverId, + }; + + socket.emit("ReadMessage", data, (error: any) => { + console.log("Message sent successfully"); + if (error) { + console.error("Error sending message:", error); + } + }); + } + }); + + return () => { + socket.disconnect(); + }; + }, [selectedUser]); + + useEffect(() => { + if (otherUserDetails?.blockedBy) { + } else { + getMessageList(); + } + + fetchOtherUser(); + }, [selectedUser, isUnBlock, isBlockDialogOpen]); + + const fetchOtherUser = async () => { + if (!selectedUser || !user) { + return; + } + setIsDataLoading(true); + + const response = await getOtherUser({ + user_id: user.userId, + profilerId: selectedUser.id, + }); + setIsDataLoading(false); + if (response.status === 200 && user) { + setOtherUserDetails(response.data); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + const blockUser = async () => { + if (!user) return; + if (!selectedUser) return; + + const res = await blockOrUnblockUser({ + user_id: user?.userId, + data: { + isBlock: true, + blockedUserId: selectedUser.id, + }, + }); + if (res.status === 200) { + sendNotification({ type: "SUCCESS", message: "User Blocked" }); + setIsBlockDialogOpen(false); + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + + const unblockUser = async () => { + if (!user || !selectedUser) { + return; + } + + const res = await blockOrUnblockUser({ + user_id: user.userId, + data: { + isBlock: false, + blockedUserId: selectedUser?.id, + }, + }); + + if (res.status === 200) { + setisUnBlock(!isUnBlock); + sendNotification({ type: "SUCCESS", message: "User UnBlocked" }); + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + + const submitReport = async (inputText: string) => { + if (!user || !selectedUser) return; + + const res = await reportUser({ + user_id: user.userId, + data: { reportFor: inputText, reportedUserId: selectedUser.id }, + }); + + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + setReportingPostIndex(false); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + return ( + <> +
+ + {isBlockDialogOpen ? ( + { + setIsBlockDialogOpen(false); + }} + onConform={() => { + blockUser(); + }} + title={{ + titleMain: "Block " + selectedUser?.userName + "?", + title2: + selectedUser?.userName + + " won't be able to send you messages, see your posts, connect with members, or join your circle. They won't receive a notification that you've blocked them.", + confirmButton: "Block", + }} + /> + ) : null} + {selectedUser?.id !== user?.userId && + otherUserDetails?.blockedBy && + otherUserDetails?.blockedBy !== user?.userId && ( + + +
+ } + title="User has blocked you" + description="it looks like you are unable to view a profile of this user because they blocked you." + /> + )} + {selectedUser?.id !== user?.userId && + otherUserDetails?.blockedBy && + otherUserDetails.blockedBy === user?.userId ? ( + + +
+ } + title="You have blocked the user" + description="it looks like you are unable to view a profile of this user because you blocked this user." + buttonName="Unblock" + handleEvent={unblockUser} + /> + ) : null}{" "} + {!otherUserDetails?.blockedBy && ( + <> +
+ {messages.length > 1 && ( +
+ + +
+ } + style={{ display: "flex", flexDirection: "column-reverse" }} + scrollableTarget="MessagesScrollableDiv" + > + {messages.map((msg, index) => { + return ( +
+ {msg.type === "MESSAGE" && } + {(msg.type === "IMAGE" || msg.type === "MWITHI") && ( + + )} + {msg.type === "CREDIT" && ( + + )} +
+ ); + })} + +
+ )} + {messages.length < 2 && !hasMoreMessage && ( +
+ + +
+ } + title="No Chat Found" + description="Start Chatting with your witit friends!" + /> + + )} + + + + + )} + + {reportingPostIndex && ( + submitReport(inputText)} + onCancel={() => { + setReportingPostIndex(false); + }} + /> + )} + + ); +}; + +export default PersonalChat; +{ + /* {/* {isDragging ? ( +
+
+ + +
+ ), + placeholderTitle: ( + <> +

+ Drag profile pic here, +

+

+ or browse +

+ + ), + }} + /> +
+ */ +} + +{ + /* ) : null} */ +} + +// const [isDragging, setisDragging] = useState(false); +// const [finalMsgImage, setFinalMsgImage] = useState<{ +// image: ImageInfo; +// index: number; +// }>(defaultImageConstant); +// const { +// setCustomDialogType, +// customDialogType, +// croppingImage, +// setCroppingImage, +// } = useAuthContext(); +// const handleDragOver = (event: React.DragEvent) => { +// event.preventDefault(); +// setisDragging(true); +// }; +// const handleLeave = (event: React.DragEvent) => { +// event.preventDefault(); +// setisDragging(false); +// setCustomDialogType(null); +// }; + +// const handleDrop = (event: React.DragEvent) => { +// event.preventDefault(); +// setisDragging(false); +// const file = event.dataTransfer.files[0]; +// displaySingleImage(file, setCroppingImage); +// }; diff --git a/components/message/RecentMessageListDrawer/components/RecentMessageItem.tsx b/components/message/RecentMessageListDrawer/components/RecentMessageItem.tsx new file mode 100644 index 0000000..53c9cd8 --- /dev/null +++ b/components/message/RecentMessageListDrawer/components/RecentMessageItem.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import { RecentMessage } from "@/types/message"; +import { profilePlaceholderImage } from "@/utils/images"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import dayjs from "dayjs"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; + +type Props = { + profileChat: RecentMessage; +}; +const RecentMessageItem = ({ profileChat }: Props) => { + const user = useSelector((state: RootState) => state.user); + let type; + if (profileChat.receiver.id !== user?.userId) { + type = profileChat.receiver.userType; + } else { + type = profileChat.sender.userType; + } + return ( +
+
+ +
+
+
+

+ {profileChat.receiver.id !== user?.userId + ? profileChat.receiver.userName + : profileChat.sender.userName} + {type === "VERIFIED" && ( + + + + )}{" "} +

{" "} +

+ {dayjs(profileChat?.createdAt).format("hh:mm A")} +

+
+ {profileChat.receiver?.id === user?.userId && + profileChat.messageStatus === "READ" && ( +

+ {profileChat.lastMessage} +

+ )} + {profileChat.receiver?.id === user?.userId && + profileChat.messageStatus === "SENT" && ( +

+ {profileChat.lastMessage} +

+ )} + {profileChat.sender?.id === user?.userId && + profileChat.messageStatus === "SENT" && ( +

+ Sent +

+ )} + {profileChat.sender?.id === user?.userId && + profileChat.messageStatus === "READ" && ( +

+ Seen +

+ )} +
+
+ ); +}; + +export default RecentMessageItem; diff --git a/components/message/RecentMessageListDrawer/components/search/components/SearchUserItem.tsx b/components/message/RecentMessageListDrawer/components/search/components/SearchUserItem.tsx new file mode 100644 index 0000000..48592ce --- /dev/null +++ b/components/message/RecentMessageListDrawer/components/search/components/SearchUserItem.tsx @@ -0,0 +1,40 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { FriendsList } from "@/types/circle"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import { profilePlaceholderImage } from "@/utils/images"; +import React from "react"; + +type Props = { + profileChat: FriendsList; +}; +const SearchUserItem = ({ profileChat }: Props) => { + + + return ( +
+
+ +
+
+
+

+ {profileChat.userName} + {profileChat.userType === "VERIFIED" && ( + + + + )} +

{" "} +
+
+
+ ); +}; + +export default SearchUserItem; diff --git a/components/message/RecentMessageListDrawer/components/search/index.tsx b/components/message/RecentMessageListDrawer/components/search/index.tsx new file mode 100644 index 0000000..a3870e2 --- /dev/null +++ b/components/message/RecentMessageListDrawer/components/search/index.tsx @@ -0,0 +1,199 @@ +import getAllFriends from "@/api/cricle/getAllFriends"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { theme } from "@/theme"; +import { FriendsList } from "@/types/circle"; +import LeftArrow from "@/utils/icons/message/LeftArrow"; +import SearchIcon from "@/utils/icons/topbar/SearchIcon"; +import { CircularProgress, Divider } from "@mui/material"; +import React, { useEffect, useRef, useState } from "react"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { useSelector } from "react-redux"; +import SearchUserItem from "./components/SearchUserItem"; +import { useMessageContext } from "@/components/message/context/MessageContext"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { searchUserNotFound } from "@/utils/images/message"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { useDebounceEffect } from "@/hooks/useDebounceEffect"; + +type Props = { + setisOpenSearchBar: React.Dispatch>; + setIsMessageBoxOpen: React.Dispatch>; +}; + +const RecentMessageSearch = ({ + setisOpenSearchBar, + setIsMessageBoxOpen, +}: Props) => { + const [getSearchUserList, setGetSearchUserList] = useState([]); + const [searchText, setSearchText] = useState(""); + const [hasMoreSearchUser, sethasMoreSearchUser] = useState(true); + + const { setSelectedUser } = useMessageContext(); + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + const ref = useRef(null); + const debouncedSearch = useDebounceEffect(searchText, 2000); + + const getSearchList = async (searchScore?: number, lastDocId?: string) => { + const response = await getAllFriends({ + user_id: user?.userId, + search: debouncedSearch.length > 1 ? debouncedSearch : "", + searchScore: searchScore, + lastDocId: lastDocId, + limit: 12, + }); + + if (response.status === 200 && response.data) { + if (response.data.friends.length < 10) { + sethasMoreSearchUser(false); + } else { + sethasMoreSearchUser(true); + } + if (response.data.friends.length >= 0) { + if (lastDocId) { + setGetSearchUserList([ + ...getSearchUserList, + ...response.data.friends, + ]); + return; + } + } + + setGetSearchUserList(response.data.friends); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + + useEffect(() => { + if (searchText === debouncedSearch) { + sethasMoreSearchUser(false); + } else if (searchText && searchText.length > 2) { + sethasMoreSearchUser(true); + + setGetSearchUserList([]); + } + }, [searchText, debouncedSearch]); + + useEffect(() => { + getSearchList(); + sethasMoreSearchUser(true); + }, [debouncedSearch]); + + const SelectChatProfile = (Item: FriendsList) => { + const data = { + id: Item.userId, + userName: Item.userName, + userType: Item.userType, + profileImage: Item.profileImage, + }; + + setSelectedUser(data); + }; + + const fetchMoreSearchlist = () => { + const searchScore = + getSearchUserList[getSearchUserList.length - 1].searchScore; + const lastDocId = getSearchUserList[getSearchUserList.length - 1].userId; + getSearchList(searchScore, lastDocId); + }; + + return ( +
+
+
+
{ + setisOpenSearchBar(false); + }} + > + +
+

Messages

+
+ ) => { + setSearchText(e.target.value); + }} + StartIcon={ +
+ +
+ } + placeholder="Search Chat" + /> +
+ +
+
+ + +
+ } + style={{ + display: "flex", + flexDirection: "column", + width: "100%", + }} + scrollableTarget="RecentMessageScrollableDivTag" + > + {getSearchUserList?.map((item, index) => { + return ( +
{ + SelectChatProfile(item), setIsMessageBoxOpen(true); + }} + > + + +
+ ); + })} + +
+
+ {getSearchUserList.length < 1 && !hasMoreSearchUser && ( +
+ + +
+ } + title="No Chat Found" + description="Start Chatting with your witit friends!" + /> + + )} + + ); +}; + +export default RecentMessageSearch; diff --git a/components/message/RecentMessageListDrawer/index.tsx b/components/message/RecentMessageListDrawer/index.tsx new file mode 100644 index 0000000..5373db1 --- /dev/null +++ b/components/message/RecentMessageListDrawer/index.tsx @@ -0,0 +1,210 @@ +import React, { useEffect, useRef, useState } from "react"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import { CircularProgress, Divider, IconButton } from "@mui/material"; +import { useAuthContext } from "@/context/AuthContext"; +import { theme } from "@/theme"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import RecentMessageItem from "./components/RecentMessageItem"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import getrecentmessages from "@/api/message/getrecentmessages"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { io } from "socket.io-client"; +import RecentMessageSearch from "./components/search"; +import TwoUserIcon from "@/utils/icons/message/TwoUserIcon"; +import { useMessageContext } from "../context/MessageContext"; +import { RecentMessage } from "@/types/message"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { searchUserNotFound } from "@/utils/images/message"; + +type Props = { + setIsMessageBoxOpen: React.Dispatch>; +}; +const RecentMessageListDrawer = ({ setIsMessageBoxOpen }: Props) => { + const [recentMessages, setRecentMessages] = useState([]); + const [hasMoreMessage, setHasMoreMessage] = useState(true); + const [isOpenSearchBar, setisOpenSearchBar] = useState(false); + + const { sendNotification } = useAuthContext(); + const { setSelectedUser, } = useMessageContext(); + const { setCroppingImage } = useAuthContext(); + const user = useSelector((state: RootState) => state.user); + const ref = useRef(null); + + const getRecentMessageList = async (lastDocId?: string | undefined) => { + const response = await getrecentmessages({ + user_id: user?.userId, + lastDocId, + }); + + if (response.status === 200) { + if (response.data.length < 10) { + setHasMoreMessage(false); + } else { + setHasMoreMessage(true); + } + if (response.data.length >= 0) { + if (lastDocId) { + setRecentMessages([...recentMessages, ...response.data]); + return; + } + } + + setRecentMessages(response?.data); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + + const fetchMoreMessage = () => { + const lastDocId = recentMessages[recentMessages.length - 1].receiver.id; + getRecentMessageList(lastDocId); + }; + + useEffect(() => { + getRecentMessageList(); + }, []); + + useEffect(() => { + if (!user) return; + + const socket = io(appConstant.backendUrl, { + path: "/socket.io", + query: { + userId: user.userId, + }, + transports: ["websocket"], + }); + + socket.on("RecentMessageResponse", (response: RecentMessage) => { + setRecentMessages((prevMessages) => { + const restData = prevMessages.filter( + (item) => item.messageId !== response.messageId + ); + + return [response, ...restData]; + }); + }); + + return () => { + socket.disconnect(); + }; + }, []); + + const SelectChatProfile = (item: RecentMessage) => { + let selectedUser; + + if (item?.receiver.id === user?.userId) { + selectedUser = item?.sender; + } else { + selectedUser = item?.receiver; + } + + setSelectedUser(selectedUser); + setIsMessageBoxOpen(true); + }; + + return ( + <> +
+ {!isOpenSearchBar && ( +
+
+
+
+ +

Messages

+
+
{ + setisOpenSearchBar(true); + }} + > + +
+
+
+ +
+
+ + +
+ } + style={{ + display: "flex", + flexDirection: "column", + width: "100%", + }} + scrollableTarget="RecentMessageScrollableDiv" + > + {recentMessages.map((item, index) => { + return ( +
{ + setCroppingImage(defaultImageConstant); + SelectChatProfile(item); + }} + > + + +
+ ); + })} + +
+
+ {recentMessages.length < 1 && !hasMoreMessage && ( +
+ + +
+ } + title="No Chat Found" + description="Start Chatting with your witit friends!" + /> +
+ )} + + )} + {isOpenSearchBar && ( + + )} + + + ); +}; + +export default RecentMessageListDrawer; diff --git a/components/message/context/MessageContext.tsx b/components/message/context/MessageContext.tsx new file mode 100644 index 0000000..165fd1e --- /dev/null +++ b/components/message/context/MessageContext.tsx @@ -0,0 +1,71 @@ +import { createContext, useContext, useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { UserInfo } from "@/types/message"; +import getGenerationSetting from "@/api/user/getGenerationSetting"; +import { generationSettingsUnit } from "@/types/user"; +import { useAuthContext } from "@/context/AuthContext"; + +type ContextType = { + selectedUser: UserInfo | null; + setSelectedUser: React.Dispatch>; + messageCredit: generationSettingsUnit | null; + setMessageCredit: React.Dispatch< + React.SetStateAction + >; +}; + +const defaultContext: ContextType = { + selectedUser: null, + setSelectedUser: () => {}, + messageCredit: null, + setMessageCredit: () => {}, +}; + +const Context = createContext(defaultContext); + +function MessageContext({ children }: { children: React.ReactNode }) { + const [selectedUser, setSelectedUser] = useState(null); + const [messageCredit, setMessageCredit] = + useState(null); + + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + + const getMessageGenerationCredit = async () => { + if (!selectedUser) { + return <>; + } + + const response = await getGenerationSetting({ + creatorId: selectedUser.id, + user_id: user?.userId, + }); + + if (response.status === 200) { + setMessageCredit(response.data); + return <>; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + useEffect(() => { + getMessageGenerationCredit(); + }, []); + + return ( + + {children} + + ); +} + +export default MessageContext; +export const useMessageContext = () => useContext(Context); diff --git a/components/profile/Feed/components/PostGridView/components/PostItem.tsx b/components/profile/Feed/components/PostGridView/components/PostItem.tsx new file mode 100644 index 0000000..5d43cbd --- /dev/null +++ b/components/profile/Feed/components/PostGridView/components/PostItem.tsx @@ -0,0 +1,83 @@ +import React, { useState } from "react"; +import ImagePreviewBox from "@/components/discover/ImagePreviewBox"; +import TravelCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/TravelCategoryIcon"; +import { Post } from "@/types/post"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import { CustomTooltip } from "@/components/shared/CustomTooltip"; +import SynchronizeIcon from "@/utils/icons/circle/SynchronizeIcon"; +import { useProfileContext } from "@/components/profile/Profile/context/ProfileContext"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; + +type Props = { + post: Post; +}; + +const PostItem = ({ post }: Props) => { + const { currentUser } = useProfileContext(); + + const user = useSelector((state: RootState) => state.user); + const [isImageHovered, setisImageHovered] = useState(false); + + // const aspectRatio = post.image[0].width / post.image[0].height; + + const handleHover = (isHover: boolean) => { + if (post.category.length > 0 && !post.category.includes("NSFW")) { + setisImageHovered(isHover); + } + }; + + return ( +
{ + handleHover(true); + }} + onMouseLeave={() => { + handleHover(false); + }} + > + + {isImageHovered && post.category.length > 0 ? ( +
+ {post.category.slice(0, 3).map((catName, index) => { + const icon = CategoryList.filter( + (category) => category.name === catName + ); + const isLastCat = + post.category.length <= 3 + ? index === post.category.length - 1 + : index === 2; + return ( + +
+ {icon.length > 0 ? icon[0].startIcon : } +
+
+ ); + })} +
+ ) : null} + + {post.userActivity.isReposted && user?.userId === currentUser?.userId && ( +
+ +
+ )} +
+ ); +}; + +export default PostItem; diff --git a/components/profile/Feed/components/PostGridView/index.tsx b/components/profile/Feed/components/PostGridView/index.tsx new file mode 100644 index 0000000..5af2748 --- /dev/null +++ b/components/profile/Feed/components/PostGridView/index.tsx @@ -0,0 +1,87 @@ +import { Post } from "@/types/post"; +import PostItem from "./components/PostItem"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { CircularProgress, Grid } from "@mui/material"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { postNotFoundSloth } from "@/utils/images"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; + +type GetPostsProps = { + lastDocId?: string; +}; + +type Props = { + posts: Post[]; + getPosts: ({ lastDocId }: GetPostsProps) => void; + hasMorePost: boolean; + setSelectedPostId: React.Dispatch>; +}; + +const responsiveGrid = { + xl: 4, + lg: 5, + md: 5, + sm: 10, + xs: 10, +}; + +export const PostGridView = ({ + posts, + getPosts, + hasMorePost, + setSelectedPostId, +}: Props) => { + const fetchMorePost = async () => { + if (posts.length > 0) { + const lastDocId = posts[posts.length - 1].postId; + getPosts({ lastDocId }); + } + }; + + return ( +
+ {/* max-w-lg md:max-w-2xl lg:max-w-4xl xl:max-w-5xl 2xl:max-w-6xl */} +
+ + +
+ } + scrollableTarget="postScrollableDiv" + style={hasMorePost ? {} : { overflow: "hidden" }} + > + {/* */} + + {posts.map((post, index) => ( + +
{ + setSelectedPostId(post.postId); + }} + > + +
+
+ ))} +
+ + {/*
*/} + +
+ + ); +}; diff --git a/components/profile/Feed/components/profileFeed/index.tsx b/components/profile/Feed/components/profileFeed/index.tsx new file mode 100644 index 0000000..64f21fa --- /dev/null +++ b/components/profile/Feed/components/profileFeed/index.tsx @@ -0,0 +1,535 @@ +import React, { useEffect, useState } from "react"; +import { Post, PromptDetail } from "@/types/post"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import { useAuthContext } from "@/context/AuthContext"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { CircularProgress } from "@mui/material"; +import { deletePost } from "@/api/post/deletePost"; +import { likePost } from "@/api/post/likePost"; +import { doRepost } from "@/api/post/doRepost"; +import { ReduxUser, UserBaseInfo } from "@/types/user"; +import { getPromptOfPost } from "@/api/post/getPromptOfPost"; +import { viewPost } from "@/api/post/viewPost"; +import CirclePost from "@/components/circle/CirclePost"; +import CirclePostInfoDialog from "@/components/circle/CirclePostInfoDialog"; +import ViewPromptDrawer from "@/components/discover/ViewPromptDrawer"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import CreditViewPrompt from "@/components/shared/credit/CreditViewPrompt"; +import Creadit from "@/components/shared/credit/Index"; +import { getUserPosts } from "@/api/post/getUserPosts"; +import { + addUserPost, + deleteUserPost, + updateUserPostCommentCount, + updateUserPostLikeStatus, + updateUserPostRepostStatus, + updateUserPostView, + updateUserPostViewPrompt, +} from "@/redux/slices/userPostSlice"; +import { getUser } from "@/api/user/getUser"; +import { useRouter } from "next/router"; +import ReportDialog from "@/components/shared/ReportDialog"; +import { reportPost } from "@/api/post/reportPost"; +import EditPostDialog from "@/components/shared/CustomEditPostDialog/index"; +import EditGenerationPostPrompt from "@/components/shared/CustomEditPostFromGenetation/index"; + +type LikePostProps = { postId: string; isLiked: boolean; res?: Res }; + +type Res = { + status: number; + data: Post[]; + error: any; +}; +type GetPostsProps = { + lastDocId?: string; + search?: string | null; + res?: Res; +}; + +type Props = { + selectedPostId: string | null; + hasMorePost: boolean; +}; +const ProfileFeed = ({ selectedPostId, hasMorePost }: Props) => { + const dispatch = useDispatch(); + const { asPath } = useRouter(); + const router = useRouter(); + + const { sendNotification } = useAuthContext(); + + const userPosts = useSelector((state: RootState) => state.userPosts); + const user = useSelector((state: RootState) => state.user); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + + const [hasMoreFeed, setHasMoreFeed] = useState(hasMorePost); + const [selectedImageIndex, setSelectedImageIndex] = useState(0); + const [deletingPostIndex, setDeletingPostIndex] = useState( + null + ); + const [isOpenEditPost, setIsOpenEditPost] = useState(true); + const [selectedPost, setSelectedPost] = useState(null); + const [creditDialogInfo, setCreditDialogInfo] = useState<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null>(null); + const [promptDetails, setPromptDetails] = useState(null); + const [reportingPostIndex, setReportingPostIndex] = useState( + null + ); + const [currentUser, setCurrentUser] = useState(null); + const [editPostValue, setEditPostValue] = useState(null); + + const getUserData = async () => { + const userId = router.query.user; + + if (userId) { + const res = await getUser(userId as string); + if (res.status === 200) { + setCurrentUser(res.data); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + } else { + setCurrentUser(user); + } + }; + + useEffect(() => { + getUserData(); + }, [asPath]); + + const handleLikePost = async ({ postId, isLiked }: LikePostProps) => { + if (!user) return; + const res = await likePost({ + user_id: user.userId, + postId, + isLiked, + }); + + if (!res) return; + if (res.status === 200) { + dispatch(updateUserPostLikeStatus({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleRepost = async ( + event: React.MouseEvent, + postId: string, + isReposted: boolean + ) => { + event.stopPropagation(); + if (!user) return; + sendNotification({ type: "LOADING" }); + let res; + if (isReposted) { + res = await deletePost({ + user_id: user.userId, + postId, + }); + } else { + res = await doRepost({ + user_id: user.userId, + postId, + }); + } + if (!res) return; + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: isReposted + ? "Post Deleted Successfully" + : "Reposted Successfully", + }); + dispatch(updateUserPostRepostStatus({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleChange = ( + event: React.ChangeEvent, + postId: string + ) => { + handleLikePost({ + postId: postId, + isLiked: event.target.checked, + }); + }; + + const getuserPosts = async ({ lastDocId }: GetPostsProps) => { + if (!user) return; + + const res = await getUserPosts({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + }); + setSimilarFeed({ res, lastDocId }); + }; + + const setSimilarFeed = ({ lastDocId, res }: GetPostsProps) => { + if (!res) return; + + if (res.status === 200) { + if (res?.data.length < 20) { + setHasMoreFeed(false); + } else { + setHasMoreFeed(true); + } + if (res.data.length > 0) { + if (lastDocId) { + dispatch(addUserPost([...userPosts, ...res.data])); + } else { + dispatch(addUserPost(res.data)); + } + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleCommentCount = (postId: string) => { + dispatch(updateUserPostCommentCount({ postId })); + }; + + const fetchMorePost = async () => { + const lastDocId = userPosts[userPosts.length - 1]?.postId; + getuserPosts({ lastDocId }); + }; + + const handleDeletePostFromMenu = async (postId: string) => { + if (!user) return; + const selectedPost = userPosts.find((post) => post.postId === postId); + if (!selectedPost) return; + + sendNotification({ type: "LOADING" }); + const res = await deletePost({ + user_id: user.userId, + postId, + }); + + if (res.status === 200) { + dispatch(deleteUserPost({ postId: selectedPost?.postId })); + + sendNotification({ + type: "SUCCESS", + message: "Post Deleted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + setHasMoreFeed(false); + }; + + const getPromptDetails = async () => { + if (!user) return; + if (!creditDialogInfo) return; + const res = await getPromptOfPost({ + user_id: user.userId, + postId: creditDialogInfo.postId, + }); + + if (res.status === 200) { + setPromptDetails(res.data); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const viewPostCount = async (postId: string) => { + if (!user) return; + const res = await viewPost({ + user_id: user.userId, + postId, + }); + if (res.status === 200) { + dispatch(updateUserPostView({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handlePostClicked = ( + event: React.MouseEvent, + postId: string + ) => { + event.stopPropagation(); + + const clickedPost = userPosts.find((post) => post.postId === postId); + if (clickedPost) { + const isViewdPost = viewedNsfwList.includes(clickedPost.postId); + if (!clickedPost.category.includes("NSFW")) { + setSelectedPost(clickedPost); + } else if (isViewdPost && clickedPost.category.includes("NSFW")) { + setSelectedPost(clickedPost); + } + } + }; + + const submitReport = async (inputText: string) => { + if (!user) return; + if (!reportingPostIndex) return; + + const res = await reportPost({ + user_id: user.userId, + data: { reportFor: inputText, postId: reportingPostIndex }, + }); + + if (res.status === 200) { + setReportingPostIndex(null); + + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + useEffect(() => { + if (userPosts) + setSelectedPost((prev) => { + const matchedPost = userPosts.find( + (post) => post.postId === prev?.postId + ); + return matchedPost ? matchedPost : null; + }); + }, [userPosts]); + + useEffect(() => { + if (creditDialogInfo?.isPostAccessed) { + getPromptDetails(); + } + }, [creditDialogInfo]); + + // get visible post on screen + useEffect(() => { + if (!userPosts) { + return; + } + + const options = { + root: null, + rootMargin: "0px", + threshold: 1, + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if ( + !userPosts.filter((post) => post.postId === entry.target.id)[0] + .userActivity.isViewed + ) { + viewPostCount(entry.target.id); + } + } + }); + }, options); + + document.querySelectorAll(".post-item").forEach((postElement) => { + observer.observe(postElement); + }); + + return () => { + observer.disconnect(); + }; + }, [userPosts]); + + useEffect(() => { + //open perticular post invisible scrolling "auto" + if (selectedPostId !== null) { + const card = document.getElementById(selectedPostId); + if (card != null) card.scrollIntoView({ behavior: "auto" }); + } + }, [selectedPostId]); + + useEffect(() => { + if (currentUser) { + setDeletingPostIndex(null); + setPromptDetails(null); + setCreditDialogInfo(null); + } + }, [currentUser]); + + useEffect(() => { + if (promptDetails) { + setCreditDialogInfo(null); + dispatch( + updateUserPostViewPrompt({ postId: selectedPost?.postId || "" }) + ); + } + }, [promptDetails]); + + const handleEdit = (selectedPost: Post) => { + setIsOpenEditPost(true); + if (selectedPost) { + setEditPostValue(selectedPost); + } + }; + + return ( +
+ {userPosts.length === 0 && !hasMoreFeed ? ( +
+ No Similar Post found +
+ ) : ( +
+ + +
+ } + scrollableTarget="similarFeedScrollableDiv" + style={hasMoreFeed ? {} : { overflow: "hidden" }} + > +
+ {userPosts.map((post, index) => { + return ( +
+ + ) => { + handleChange(event, post.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + post.postId, + post.userActivity.isReposted + ); + }} + selectedPost={post} + setSelectedImageIndex={setSelectedImageIndex} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + handlePostClicked={handlePostClicked} + promptDetails={promptDetails} + creditDialogInfo={creditDialogInfo} + setReportingPostIndex={setReportingPostIndex} + /> +
+ ); + })} +
+ +
+ )} + + {selectedPost ? ( + ) => { + handleChange(event, selectedPost.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + selectedPost.postId, + selectedPost.userActivity.isReposted + ); + }} + selectedPost={selectedPost} + selectedImageIndex={selectedImageIndex} + setSelectedPost={setSelectedPost} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + promptDetails={promptDetails} + creditDialogInfo={creditDialogInfo} + setReportingPostIndex={setReportingPostIndex} + /> + ) : null} + {deletingPostIndex ? ( + { + setDeletingPostIndex(null); + }} + onConform={() => { + handleDeletePostFromMenu(deletingPostIndex); + setDeletingPostIndex(null); + }} + title={{ + titleMain: "Delete Post?", + title1: "Sure You Want to Delete This Offer From Your Account?", + title2: " You will not be able to recover them again.", + confirmButton: "Delete", + }} + /> + ) : null} + {reportingPostIndex ? ( + submitReport(inputText)} + onCancel={() => { + setReportingPostIndex(null); + }} + /> + ) : null} + {creditDialogInfo && !creditDialogInfo.isPostAccessed ? ( + + + + ) : null} + + {promptDetails ? ( + + ) : null} + {editPostValue && editPostValue.generatedFrom && ( + + )} + {editPostValue?.generatedFrom === null ? ( + + ) : null} + + ); +}; + +export default ProfileFeed; diff --git a/components/profile/Feed/index.tsx b/components/profile/Feed/index.tsx new file mode 100644 index 0000000..3fe2fb0 --- /dev/null +++ b/components/profile/Feed/index.tsx @@ -0,0 +1,144 @@ +import React, { useEffect, useState } from "react"; +import { getUserPosts } from "@/api/post/getUserPosts"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { addUserPost } from "@/redux/slices/userPostSlice"; +import { PostGridView } from "./components/PostGridView"; +import { useAuthContext } from "@/context/AuthContext"; +import ProfileFeed from "./components/profileFeed"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { postNotFoundSloth } from "@/utils/images"; +import { useProfileContext } from "../Profile/context/ProfileContext"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; + +type GetPostsProps = { + lastDocId?: string; +}; +type Props = { + postId: string | null; + setPostId: React.Dispatch>; +}; + +const Feed = ({ postId, setPostId }: Props) => { + const dispatch = useDispatch(); + + const { sendNotification } = useAuthContext(); + const { currentUser } = useProfileContext(); + + const userPosts = useSelector((state: RootState) => state.userPosts); + const user = useSelector((state: RootState) => state.user); + + const [selectedPostId, setSelectedPostId] = useState(null); + const [hasMorePost, setHasMorePost] = useState(true); + + const getPosts = async ({ lastDocId }: GetPostsProps) => { + if (!user || !currentUser) return; + + const res = await getUserPosts({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + ...(currentUser.userId !== user.userId && { + profilerId: currentUser?.userId, + }), + }); + + if (res.status === 200 && res?.data) { + if (res?.data.length < 20) { + setHasMorePost(false); + } else { + setHasMorePost(true); + } + if (res.data.length > 0) { + if (lastDocId) { + dispatch(addUserPost([...userPosts, ...res.data])); + } else { + dispatch(addUserPost(res.data)); + } + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + useEffect(() => { + setHasMorePost(true); + setSelectedPostId(null); + dispatch(addUserPost([])); + getPosts({}); + }, [currentUser]); + + useEffect(() => { + if (postId === null) { + setSelectedPostId(null); + } + }, [postId]); + + useEffect(() => { + setPostId(selectedPostId); + }, [selectedPostId]); + + const handleClick = () => { + //send it to Create post + }; + + if ( + !hasMorePost && + userPosts.length === 0 && + user?.userId === currentUser?.userId + ) { + return ( + + + + } + description="It looks like you haven't post anything. Let’s upload your first feed.." + buttonName="Create Post" + handleEvent={handleClick} + /> + ); + } + + if ( + !hasMorePost && + userPosts.length === 0 && + user?.userId !== currentUser?.userId + ) { + return ( + + + + } + description="It looks like user haven't post anything." + /> + ); + } + + return ( +
+ {/*
*/} + {selectedPostId ? ( + + ) : ( + + )} + {/*
*/} +
+ ); +}; + +export default Feed; diff --git a/components/profile/Moments/index.tsx b/components/profile/Moments/index.tsx new file mode 100644 index 0000000..8464ee4 --- /dev/null +++ b/components/profile/Moments/index.tsx @@ -0,0 +1,167 @@ +import React, { useState } from "react"; +import { Checkbox, Divider, Grid } from "@mui/material"; +import Image from "next/image"; +import temp1 from "@/utils/images/temp4.jpg"; +import CreateMomentIcon from "@/utils/icons/profile/CreateMomentIcon"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import LikeIcon from "@/utils/icons/shared/LikeIcon"; +import CasualCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon"; +import { theme } from "@/theme"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import { Favorite, FavoriteBorder } from "@mui/icons-material"; +import { ComingSoon } from "@/components/shared/ComingSoon"; + +const MomentList = ["1", "2", "3", "4", "5", "6"]; + +const styles = { + responsiveGrid: { + xxl: 2, + xl: 3, + lg: 6, + md: 6, + sm: 6, + xs: 6, + }, +}; +const Moments = () => { + const [isMomentHoverd, setisMomentHoverd] = useState({ + isHover: false, + index: 0, + }); + const { setCustomDialogType } = useAuthContext(); + + return ( +
+ +
+ ); + + return ( +
+ + +
{ + // setCustomDialogType("CREATEMOMENT"); + }} + > +
+ +
+

Create New Moment

+
+
+ {MomentList.map((Moment, index) => { + return ( + +
+ setisMomentHoverd({ isHover: true, index: index }) + } + onMouseLeave={() => + setisMomentHoverd({ isHover: false, index: index }) + } + > +
+ {isMomentHoverd.isHover && isMomentHoverd.index === index ? ( +
{}} + className={`bg-gradient-to-b from-[#121315] via-[#17181b00] to-[#17181b00] w-full h-full + flex absolute z-20 top-0 right-0 justify-end p-3 rounded-md `} + > +
+
+ { + e.stopPropagation(); + }} + icon={ + + } + checkedIcon={} + /> +

123

+
+
+
+ +
+

123

+
+
+
+ ) : null} +
+ {MomentList.map((image, index) => { + return ( +
+ {index < 4 ? ( + + ) : ( + <> + )} + {MomentList.length > 4 && index === 3 ? ( +
+
+ +{MomentList.length - 4} +
+
+ ) : null} +
+ ); + })} +
+
{" "} + +
+
+ +
+
+
+

Gerdes

+
+ +
+
+
+
+

+ 1 min ago +

+
+
+

+ Currently out doing things and stuff. May want to do + more stuff, idk.{" "} +

+
+
+
+
+
+ ); + })} +
+
+ ); +}; + +export default Moments; diff --git a/components/profile/Profile/components/Members/components/Member.tsx b/components/profile/Profile/components/Members/components/Member.tsx new file mode 100644 index 0000000..8ef35d0 --- /dev/null +++ b/components/profile/Profile/components/Members/components/Member.tsx @@ -0,0 +1,43 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { RootState } from "@/redux/store"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import { UserBaseInfo, UserType } from "@/types/user"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import { profilePlaceholderImage, temp1 } from "@/utils/images"; +import Image from "next/image"; +import { useRouter } from "next/router"; +import { useSelector } from "react-redux"; +type Props = { + member: UserBaseInfo; +}; + +export const Member = ({ member }: Props) => { + const user = useSelector((state: RootState) => state.user); + const router = useRouter(); + + return ( +
{ + router.push(redirectTouserProfile(member.userId, user?.userId)); + }} + > +
+
+ +
+
+

{member.userName}

+ {member.userType === UserType.VERIFIED ? ( +
+ +
+ ) : null} +
+
+
+ ); +}; diff --git a/components/profile/Profile/components/Members/index.tsx b/components/profile/Profile/components/Members/index.tsx new file mode 100644 index 0000000..64f280c --- /dev/null +++ b/components/profile/Profile/components/Members/index.tsx @@ -0,0 +1,166 @@ +import { useEffect, useState } from "react"; +import { Member } from "./components/Member"; +import { UserBaseInfo } from "@/types/user"; +import { getFollowers } from "@/api/user/getFollowers"; +import { getFollowings } from "@/api/user/getFollowings"; +import { CircularProgress } from "@mui/material"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { useAuthContext } from "@/context/AuthContext"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { blockUserIllustrator } from "@/utils/images"; +import { useProfileContext } from "../../context/ProfileContext"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; + +type MemberTab = { + name: string; + type: "CIRCLE" | "CIRCLING"; +}; + +const memberTabs: MemberTab[] = [ + { + name: "Circle Members", + type: "CIRCLE", + }, + { + name: "Circling", + type: "CIRCLING", + }, +]; + +type GetMemberProps = { + memberType: "CIRCLE" | "CIRCLING"; + lastDoc?: { lastDocId: string; searchScore: number }; +}; + +export const Members = () => { + const { sendNotification } = useAuthContext(); + const { currentUser } = useProfileContext(); + + const [memberType, setMemberType] = useState<"CIRCLE" | "CIRCLING">("CIRCLE"); + const [members, setMembers] = useState([]); + const [hasMoreMember, setHasMoreMember] = useState(true); + + const getUserMembers = async ({ memberType, lastDoc }: GetMemberProps) => { + if (!currentUser) return; + + if (memberType === "CIRCLE") { + const membersData = await getFollowers({ + user_id: currentUser.userId, + limit: 20, + ...(lastDoc && { ...lastDoc }), + }); + + if (membersData.status === 200) { + const currentMembers = membersData.data.followers; + if (currentMembers.length < 20) { + setHasMoreMember(false); + } + if (currentMembers.length > 0) { + if (lastDoc) { + setMembers([...members, ...currentMembers]); + } else { + setMembers(currentMembers); + } + } + } else { + sendNotification({ type: "ERROR", message: membersData.error }); + } + } else { + const membersData = await getFollowings({ + user_id: currentUser.userId, + limit: 20, + ...(lastDoc && { ...lastDoc }), + }); + + if (membersData.status === 200) { + const currentMembers = membersData.data.followings; + if (currentMembers.length < 20) { + setHasMoreMember(false); + } + if (currentMembers.length > 0) { + if (lastDoc) { + setMembers([...members, ...currentMembers]); + } else { + setMembers(currentMembers); + } + } + } else { + sendNotification({ type: "ERROR", message: membersData.error }); + } + } + }; + + useEffect(() => { + setMembers([]); + setHasMoreMember(true); + getUserMembers({ memberType }); + }, [memberType, currentUser]); + + const fetchMoreMember = async () => { + const lastDocId = members[members.length - 1]?.userId; + const searchScore = members[members.length - 1]?.searchScore ?? 100; + + if (lastDocId && searchScore) { + getUserMembers({ + memberType, + lastDoc: { + lastDocId, + searchScore, + }, + }); + } + }; + + return ( +
+
+ {memberTabs.map((memberTab, index) => ( +

setMemberType(memberTab.type)} + > + {memberTab.name} +

+ ))} +
+ + {members.length === 0 && !hasMoreMember ? ( +
+ + +
+ } + /> +
+ ) : ( +
+ + +
+ } + scrollableTarget="memberScrollableDiv" + > +
+ {members.map((member, index) => { + return ; + })} +
+ + + )} + + ); +}; diff --git a/components/profile/Profile/components/Offering/components/CreateOfferDialog.tsx b/components/profile/Profile/components/Offering/components/CreateOfferDialog.tsx new file mode 100644 index 0000000..37e0755 --- /dev/null +++ b/components/profile/Profile/components/Offering/components/CreateOfferDialog.tsx @@ -0,0 +1,714 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { ImageInfo } from "@/types"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import CustomButton from "@/components/shared/CustomButton"; +import React, { useEffect, useState } from "react"; +import { + CircularProgress, + Divider, + FormHelperText, + IconButton, + Slider, + styled, +} from "@mui/material"; +import { theme } from "@/theme"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; +import EditIcon from "@/utils/icons/shared/EditIcon"; +import DeleteIcon from "@/utils/icons/shared/DeleteIcon"; +import LikeIcon from "@/utils/icons/shared/LikeIcon"; +import temp1 from "@/utils/images/temp1.jpg"; +import Image from "next/image"; +import CasualCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import { CustomSlider } from "@/components/shared/CustomSlider"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import InputCropSingleImage from "@/components/shared/cropImage/singleCropImage/InputCropSingleImage"; +import Lottie from "lottie-react"; +import ImagePlaceholderLottie from "@/utils/lottie/ImagePlaceholderLottie.json"; +import { DeleteOfferImage } from "@/utils/images/offering"; +import { Controller, useForm } from "react-hook-form"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { ImageState } from "@/types/post"; +import { CreateOffering, OfferingData } from "@/types/offering"; +import createOffering from "@/api/offering/createOffering"; +import { getImageObject } from "@/service/shared/getImageObject"; +import deleteOffering from "@/api/offering/deleteOffering"; +import { updateOffering } from "@/api/offering/updateOffering"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { useRouter } from "next/router"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; + +type Props = { + dialogType: + | "VIEWOFFER" + | "EDITOFFERING" + | "CREATEOFFER" + | "CREATEOFFERDETAILS" + | null; + setDialogType: React.Dispatch< + React.SetStateAction< + "VIEWOFFER" | "EDITOFFERING" | "CREATEOFFER" | "CREATEOFFERDETAILS" | null + > + >; + openOfferData: OfferingData | null; + setOpenOfferData: React.Dispatch>; + setOfferingData: React.Dispatch>; + handleUpdateLikeStatus: ({ + offeringId, + isLike, + }: { + offeringId: string; + isLike: boolean; + }) => void; +}; + +const CreateOfferDialog = ({ + dialogType, + setDialogType, + openOfferData, + setOpenOfferData, + setOfferingData, + handleUpdateLikeStatus, +}: Props) => { + const router = useRouter(); + const { user } = router.query; + + const [sliderValue, setsliderValue] = React.useState([20, 37]); + const [deleteOfferingId, setDeleteOfferingId] = useState(null); + const [finalOfferImage, setFinalOfferImage] = useState( + null + ); + const [isOfferImageLoading, setIsOfferImageLoading] = useState(false); + const { firebaseUser, sendNotification, amountPerCredit } = useAuthContext(); + const [isDataUploading, setIsDataUploading] = useState(false); + + const { + handleSubmit, + control, + setValue, + reset, + setError, + clearErrors, + getValues, + watch, + formState: { errors, isSubmitting, isDirty, dirtyFields }, + } = useForm({ + defaultValues: { + name: "", + image: [], + offeringDescription: "", + creditRange: { + min: 0, + max: 0, + }, + }, + mode: "onSubmit", + }); + + const setDefaultValue = async () => { + if (!openOfferData) return; + setIsOfferImageLoading(true); + reset({ + name: openOfferData.name, + image: openOfferData.image, + offeringDescription: openOfferData.offeringDescription, + creditRange: { + min: openOfferData.creditRange.min, + max: openOfferData.creditRange.max, + }, + }); + const { file } = await getImageObject(openOfferData.image[0]); + setFinalOfferImage({ imagePreview: openOfferData.image[0], file }); + setValue("image", openOfferData.image); + setIsOfferImageLoading(false); + }; + useEffect(() => { + if (dialogType === "EDITOFFERING" && openOfferData) { + setDefaultValue(); + } + }, [dialogType, openOfferData]); + + const handleNextClick = () => { + setDialogType("CREATEOFFERDETAILS"); + }; + + const handleBackClick = () => { + if (dialogType === "CREATEOFFERDETAILS") { + if (openOfferData) { + setDialogType("EDITOFFERING"); + } else { + setDialogType("CREATEOFFER"); + } + } + if (dialogType === "EDITOFFERING") { + setDialogType("VIEWOFFER"); + } + }; + const handleCloseDialog = () => { + if (dialogType === "EDITOFFERING") { + setDialogType("VIEWOFFER"); + } else if ( + dialogType === "CREATEOFFER" || + dialogType === "VIEWOFFER" || + dialogType === "CREATEOFFERDETAILS" + ) { + setDialogType(null); + setOpenOfferData(null); + } + setFinalOfferImage(null); + reset({ + name: "", + image: [], + offeringDescription: "", + creditRange: { + min: 0, + max: 0, + }, + }); + }; + + const handleMakeOfferClick = async () => { + if (!finalOfferImage) return; + // sendNotification({ type: "LOADING" }); + if (openOfferData) { + setIsDataUploading(true); + let imageUrl = ""; + if (finalOfferImage.imagePreview.includes("data:image/")) { + imageUrl = await uploadImageToStorage({ + folderName: "offering_images", + file: finalOfferImage.file, + metadata: { + userId: firebaseUser?.uid, + }, + }); + } + + if (imageUrl !== "" || Object.keys(dirtyFields).length !== 0) { + const UpdateOfferingData = { + offeringId: openOfferData.offeringId, + ...(Object.hasOwn(dirtyFields, "name") && { + name: getValues("name"), + }), + ...(imageUrl !== "" && { + image: [imageUrl], + }), + ...(Object.hasOwn(dirtyFields, "offeringDescription") && { + offeringDescription: getValues("offeringDescription"), + }), + ...(Object.hasOwn(dirtyFields, "creditRange") && { + creditRange: getValues("creditRange"), + }), + }; + const response = await updateOffering({ + user_id: firebaseUser?.uid!, + UpdateOfferingData, + }); + if (response.status === 200) { + setOfferingData((prevOfferings) => { + return prevOfferings.map((offering) => { + if (offering.offeringId === openOfferData.offeringId) { + return { + ...offering, + ...(Object.hasOwn(dirtyFields, "name") && { + name: getValues("name"), + }), + ...(imageUrl !== "" && { + image: [imageUrl], + }), + ...(Object.hasOwn(dirtyFields, "offeringDescription") && { + offeringDescription: getValues("offeringDescription"), + }), + ...(Object.hasOwn(dirtyFields, "creditRange") && { + creditRange: { + min: getValues("creditRange.min"), + max: getValues("creditRange.max"), + avg: + (Number(getValues("creditRange.max")) + + Number(getValues("creditRange.min"))) / + 2, + }, + }), + }; + } else { + return offering; + } + }); + }); + sendNotification({ type: "SUCCESS", message: "Offer Data updated" }); + setDialogType(null); + setOpenOfferData(null); + } else { + sendNotification({ type: "ERROR", message: response.error }); + } + } + } else { + setIsDataUploading(true); + const imageUrl = await uploadImageToStorage({ + folderName: "offering_images", + file: finalOfferImage.file, + metadata: { + userId: firebaseUser?.uid, + }, + }); + + setValue("image", [imageUrl]); + if (imageUrl) { + const response = await createOffering({ + offeringDetails: watch(), + user_id: firebaseUser?.uid, + }); + if (response.status === 200) { + sendNotification({ type: "SUCCESS", message: "Offer created" }); + setDialogType(null); + setOfferingData((preValue) => [...preValue, response.data!]); + } else { + sendNotification({ type: "ERROR", message: response.error }); + } + } + } + setIsDataUploading(false); + }; + + const handleDeleteClick = async () => { + if (!firebaseUser) return; + sendNotification({ type: "LOADING" }); + const response = await deleteOffering({ + user_id: firebaseUser.uid, + offeringId: deleteOfferingId!, + }); + if (response.status === 200) { + sendNotification({ type: "SUCCESS", message: "Offer Deleted" }); + setDialogType(null); + setOfferingData((preValue) => + preValue.filter((offer) => offer.offeringId !== deleteOfferingId) + ); + setDeleteOfferingId(null); + } else { + sendNotification({ type: "ERROR", message: response.error }); + } + }; + + return ( +
+ { + // setDialogType(null), setFinalOfferImage(null); + // setCroppingImage({ ...defaultImageConstant, isShowGrid: false }); + // }} + isOpen={dialogType !== null} + > + {dialogType === "VIEWOFFER" ? ( +
+
+
+
+

+ {openOfferData?.name} +

+
+
{ + setDialogType("EDITOFFERING"); + }} + > + +
+
{ + setDeleteOfferingId(openOfferData?.offeringId!); + }} + > + +
+
+
+
+
+
+ handleUpdateLikeStatus({ + offeringId: openOfferData?.offeringId!, + isLike: !openOfferData?.isUserLike, + }) + } + > + +
+

{openOfferData?.counts.like}

+
+
+
+ +
+

{openOfferData?.completeOffers}

+
+
+
+ +
+
+
+ +
+ +
+
+

Min. Credit:

+

+ {openOfferData?.creditRange.min} +

+
+
+

Avg. Credit:

+

+ {openOfferData?.creditRange.avg} +

+
+
+

Max. Credit:

+

+ {openOfferData?.creditRange.max} +

+
+
+ +
+

Description:

+
    +
  • {openOfferData?.offeringDescription}
  • +
+
+
+
+ ) : ( +
+
+
+ {dialogType === "CREATEOFFER" ? ( +
+ +
+ ) : ( +
+ +
+ )} + +
+ {openOfferData ? "Edit An Offering" : "Create An Offering"} +
+
+ + + +
+ + {dialogType === "CREATEOFFER" || dialogType === "EDITOFFERING" ? ( +
+
+
+ {isOfferImageLoading ? ( +
+ +
+ ) : ( + + +
+ ), + placeholderTitle: ( + <> +

+ Drag profile pic here, +

+

+ or{" "} + + browse + +

+ + ), + }} + /> + )} +
+
+
+ { + return ( + filedValue.length > 2 || + "Offering name should be at least 3 characters." + ); + }, + }, + }} + render={({ field }) => ( + + )} + /> +
+

Set Your Offering Credit Range

+

+ Set Your Offering Credit Range With Minimum and Maximum + credit Values. so that candidate can offer in that valued + credit range. +

+
+
+
+ { + return ( + filedValue < getValues("creditRange.max") || + "Minimum credit should be smaller than the maximum credit." + ); + }, + }, + }} + render={({ field }) => ( + + )} + /> +

+ $ + {( + watch("creditRange.min") * amountPerCredit.withdraw + ).toFixed(2)} +

+
+
+ { + return ( + filedValue > watch("creditRange.min") || + "Maximum credit should be greater than the maximum credit." + ); + }, + }, + }} + render={({ field }) => ( + + )} + /> +

+ $ + {( + watch("creditRange.max") * amountPerCredit.withdraw + ).toFixed(2)} +

+
+
+ {(errors?.creditRange?.max?.message || + errors?.creditRange?.min?.message) && ( + + Maximum credit should be greater than the maximum credit. + + )} +
+ + +
+ } + /> +
+
+
+ ) : dialogType === "CREATEOFFERDETAILS" ? ( +
+ { + return ( + filedValue.length > 2 || + "Offering description should be at least 3 characters." + ); + }, + }, + }} + render={({ field }) => ( + + )} + /> + +
+ ) : ( + <> + )} + + )} + + {deleteOfferingId !== null ? ( + { + setDeleteOfferingId(null); + }} + onConform={handleDeleteClick} + image={DeleteOfferImage} + title={{ + titleMain: "Delete Offer?", + title1: "Sure You Want to Delete This Offer From Your Account?", + title2: " You will not be able to recover them again.", + }} + /> + ) : // { + // setDeleteOfferingId(null); + // }} + // > + //
+ // { + // setDeleteOfferingId(null); + // }} + // > + // + // + //
+ // + //

Delete Offer

+ // + //

+ // Sure You Want to Delete This Offer From Your Account? + //

+ //

+ // You will not be able to recover them again. + //

+ //
+ // + //
+ //
+ + null} + + ); +}; + +export default CreateOfferDialog; diff --git a/components/profile/Profile/components/Offering/components/OfferingItem.tsx b/components/profile/Profile/components/Offering/components/OfferingItem.tsx new file mode 100644 index 0000000..ac3b1aa --- /dev/null +++ b/components/profile/Profile/components/Offering/components/OfferingItem.tsx @@ -0,0 +1,85 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { OfferingData } from "@/types/offering"; +import CasualCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon"; +import LikeIcon from "@/utils/icons/shared/LikeIcon"; +import React from "react"; + +interface OfferingItemProps { + // Define the props for the OfferingItem component here + setDialogType: React.Dispatch< + React.SetStateAction< + "VIEWOFFER" | "CREATEOFFER" | "CREATEOFFERDETAILS" | "EDITOFFERING" | null + > + >; + setOpenOfferData: React.Dispatch>; + offer: OfferingData; + handleUpdateLikeStatus: (data: { + offeringId: string; + isLike: boolean; + }) => void; +} + +export const OfferingItem: React.FC = ({ + setDialogType, + setOpenOfferData, + offer, + handleUpdateLikeStatus, +}) => { + // Implement the logic for the OfferingItem component here + + return ( +
{ + setDialogType("VIEWOFFER"); + setOpenOfferData(offer); + }} + > +
+
{}} + className={`bg-gradient-to-b from-[#121315] via-[#17181b00] to-[#17181b00] w-full h-full + flex absolute z-20 top-0 right-0 justify-end p-3 rounded-md group-hover:opacity-100 opacity-0 transition-all duration-300`} + > +
+
+
{ + e.stopPropagation(); + handleUpdateLikeStatus({ + offeringId: offer.offeringId, + isLike: !offer.isUserLike, + }); + }} + > + +
+

{offer.counts.like}

+
+
+
+ +
+

{offer.completeOffers}

+
+
+
+
+ +
+
+ +
+

{offer.name}

+

+ {offer.creditRange.avg} Credits +

+
+
+ ); +}; + +export default OfferingItem; diff --git a/components/profile/Profile/components/Offering/index.tsx b/components/profile/Profile/components/Offering/index.tsx new file mode 100644 index 0000000..a52e003 --- /dev/null +++ b/components/profile/Profile/components/Offering/index.tsx @@ -0,0 +1,229 @@ +import React, { useEffect, useState } from "react"; +import { CircularProgress, Grid } from "@mui/material"; +import Image from "next/image"; +import temp1 from "@/utils/images/temp1.jpg"; +import CreateOfferIcon from "@/utils/icons/profile/CreateOfferIcon"; +import LikeIcon from "@/utils/icons/shared/LikeIcon"; +import CasualCategoryIcon from "@/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import CreateOfferDialog from "./components/CreateOfferDialog"; +import { ComingSoon } from "@/components/shared/ComingSoon"; +import { defaultImageConstant } from "@/utils/constants/withoutHtml/appConstant"; +import { getOfferings } from "@/api/offering/getOfferings"; +import { OfferingData } from "@/types/offering"; +import InfiniteScroll from "react-infinite-scroll-component"; +import changeOfferingLikeStatus from "@/api/offering/changeOfferingLikeStatus"; +import { useRouter } from "next/router"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { questionNotFound } from "@/utils/images/question"; +import OfferingItem from "./components/OfferingItem"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; + +const styles = { + responsiveGrid: { + xxl: 3, + xl: 4, + lg: 6, + md: 12, + sm: 12, + xs: 12, + }, +}; + +type GetData = { + lastDocId?: string; + lastPendingOffers?: number; +}; +const Offering = () => { + const router = useRouter(); + const { user } = router.query; + + const { + setCustomDialogType, + setCroppingImage, + firebaseUser, + sendNotification, + } = useAuthContext(); + + const [isOfferHoverd, setisOfferHoverd] = useState({ + isHover: false, + index: 0, + }); + const [dialogType, setDialogType] = useState< + "VIEWOFFER" | "CREATEOFFER" | "CREATEOFFERDETAILS" | "EDITOFFERING" | null + >(null); + const [offeringData, setOfferingData] = useState([]); + const [hasMoreOffering, setHasMoreOffering] = useState(true); + const [openOfferData, setOpenOfferData] = useState(null); + + const getData = async ({ lastDocId, lastPendingOffers }: GetData) => { + if (!firebaseUser) return; + const limit = 10; + const respons = await getOfferings({ + limit, + user_id: firebaseUser?.uid, + lastDocId, + lastPendingOffers, + otherUserId: user as string, + }); + if (respons.status === 200) { + if (respons.data.length < 10) { + setHasMoreOffering(false); + } + setOfferingData(respons.data); + } + }; + useEffect(() => { + setOfferingData([]); + getData({}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [router]); + + const fetchMorePost = async () => { + if (offeringData.length > 0) { + const lastDocId = offeringData[offeringData.length - 1].offeringId; + const lastPendingOffers = + offeringData[offeringData.length - 1].pendingOffers; + getData({ lastDocId, lastPendingOffers }); + } + }; + + const handleUpdateLikeStatus = async ({ + offeringId, + isLike, + }: { + offeringId: string; + isLike: boolean; + }) => { + if (!firebaseUser) return; + const offeringUpdateLikeData = { + offeringId, + isLike: isLike, + }; + const respons = await changeOfferingLikeStatus({ + offeringUpdateLikeData, + user_id: firebaseUser.uid, + }); + if (respons.status === 200) { + setOfferingData((prevOfferings) => { + return prevOfferings.map((offering) => { + if (offering.offeringId === offeringId) { + return { + ...offering, + counts: { + ...offering.counts, + like: isLike + ? offering.counts.like + 1 + : offering.counts.like - 1, + }, + isUserLike: isLike, + }; + } else { + return offering; + } + }); + }); + setOpenOfferData((prevOffer) => { + if (!prevOffer) return null; + if (prevOffer.offeringId === offeringId) { + return { + ...prevOffer, + counts: { + ...prevOffer.counts, + like: isLike + ? prevOffer.counts.like + 1 + : prevOffer.counts.like - 1, + }, + isUserLike: isLike, + }; + } else { + return prevOffer; + } + }); + } else { + sendNotification({ type: "ERROR", message: respons.error }); + } + }; + + return ( +
+ +
+ ); + + if (offeringData.length === 0 && !hasMoreOffering) { + return ( +
+ + +
+ } + // description=" It looks like nobody has asked a question yet. Lets wait for the first one!" + /> + + ); + } + + return ( +
+ +
+ + +
+ } + scrollableTarget="offeringScrollableDiv" + className="w-full" + style={{ width: "100%", overflow: hasMoreOffering ? "" : "hidden" }} + > + + {offeringData.map((offer, index) => { + return ( + + + + ); + })} + + +
+
{ + setDialogType("CREATEOFFER"); + }} + className="group bg-primary-main absolute p-3 rounded-full bottom-8 right-8 shadow-md flex items-center gap-3 cursor-pointer" + > + +

+ Create Offering +

+
+ + ); +}; + +export default Offering; diff --git a/components/profile/Profile/components/ProfileInfo.tsx b/components/profile/Profile/components/ProfileInfo.tsx new file mode 100644 index 0000000..cfcb0a9 --- /dev/null +++ b/components/profile/Profile/components/ProfileInfo.tsx @@ -0,0 +1,189 @@ +import { joinOrLeaveCircle } from "@/api/cricle/joinOrLeaveCircle"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { getFormatedSocialLinks } from "@/service/profile/getFormatedSocialLinks"; +import { ReduxUser, UserType } from "@/types/user"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import OfferingIcon from "@/utils/icons/profile/OfferingIcon"; +import InstagramIcon from "@/utils/icons/setting/socialMedia/InstagramIcon"; +import TiktokIcon from "@/utils/icons/setting/socialMedia/TiktokIcon"; +import TwitchIcon from "@/utils/icons/setting/socialMedia/TwitchIcon"; +import TwitterIcon from "@/utils/icons/setting/socialMedia/TwitterIcon"; +import YouTubeIcon from "@/utils/icons/setting/socialMedia/YouTubeIcon"; +import { profilePlaceholderImage } from "@/utils/images"; +import { join } from "path"; +import { useEffect } from "react"; +import { useSelector } from "react-redux"; +import { useProfileContext } from "../context/ProfileContext"; + +type Props = { + contentType: "MEMBERS" | "OFFERING"; + setContentType: React.Dispatch>; +}; + +export const ProfileInfo = ({ setContentType, contentType }: Props) => { + const { sendNotification } = useAuthContext(); + const { currentUser, setCurrentUser } = useProfileContext(); + + const user = useSelector((state: RootState) => state.user); + + if (!currentUser) return <>; + if (!user) return <>; + + const socialLinks = getFormatedSocialLinks(currentUser?.linkedAccounts); + + const handleJoinOrLeaveCircle = async () => { + const res = await joinOrLeaveCircle({ + user_id: user?.userId, + isJoiningCircle: currentUser.isMyFollowing ? false : true, + friendId: currentUser.userId, + }); + + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: currentUser.isMyFollowing + ? "You have successfully leave circle" + : "You have successfully joined circle", + }); + + setCurrentUser((prev) => { + if (prev) { + return { + ...prev, + isMyFollowing: !prev.isMyFollowing, + }; + } else { + return null; + } + }); + + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + return ( + <> +
+
+ +
+ {/*
+
+ +
+
*/} +
+

+ {currentUser?.userName} + {currentUser?.userType === UserType.VERIFIED ? ( + + + + ) : null} +

+ {currentUser?.generalInfo.bio ? ( +
+

+ {currentUser?.generalInfo.bio} +

+ {/* + View More + */} +
+ ) : null} +
+ {socialLinks.map((link, index) => { + return ( + // +
+ {link.name === "Youtube" ? ( + + + + ) : link.name === "Twitch" ? ( + + + + ) : link.name === "Instagram" ? ( + + + + ) : link.name === "Twitter" ? ( + + + + ) : ( + + + + )} +
+ //
+ ); + })} +
+
+
{ + setContentType("OFFERING"); + }} + > + +
+
{ + setContentType("MEMBERS"); + }} + > + + {currentUser.counts.followerCount} + + Members +
{" "} + {user?.userId !== currentUser.userId && ( +
{ + handleJoinOrLeaveCircle(); + }} + > + {currentUser.isMyFollowing ? "Leave Circle" : "Join Circle"} +
+ )} + {user?.userId !== currentUser.userId && ( +
+
+ +
+
+ )} +
+ + ); +}; diff --git a/components/profile/Profile/components/ProfileLeftSection/index.tsx b/components/profile/Profile/components/ProfileLeftSection/index.tsx new file mode 100644 index 0000000..0f2d9dd --- /dev/null +++ b/components/profile/Profile/components/ProfileLeftSection/index.tsx @@ -0,0 +1,215 @@ +import React, { useEffect, useState } from "react"; +import { useAuthContext } from "@/context/AuthContext"; +import LinkCopyIcon from "@/utils/icons/shared/LinkCopyIcon"; +import BlockIcon from "@/utils/icons/shared/BlockIcon"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; +import { IconDropDown } from "@/components/shared/dropDown/IconDropDown"; +import { Box } from "@mui/material"; +import LogoutIcon from "@/utils/icons/shared/LogoutIcon"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; +import { DropDownItem } from "@/types"; +import { blockOrUnblockUser } from "@/api/user/blockOrUnblockUser"; +import { ProfileInfo } from "../ProfileInfo"; +import { Members } from "../Members"; +import Offering from "../Offering"; +import { useProfileContext } from "../../context/ProfileContext"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import ReportDialog from "@/components/shared/ReportDialog"; +import { reportUser } from "@/api/user/reportUser"; + +type Props = { + handleUser: () => void; +}; + +const ProfileLeftSection = ({ handleUser }: Props) => { + const { currentUser, setCurrentUser } = useProfileContext(); + + const user = useSelector((state: RootState) => state.user); + const { setToLogout, sendNotification } = useAuthContext(); + + const [contentType, setContentType] = useState<"MEMBERS" | "OFFERING">( + "MEMBERS" + ); + const [menuList, setmenuList] = useState([]); + const [isBlockDialogOpen, setIsBlockDialogOpen] = useState(false); + const [isReportDialogOpen, setIsReportDialogOpen] = useState(false); + + const handleItemSelect = (type: string) => { + if (type === "LOG_OUT") { + setToLogout(); + } + if (type === "COPY_PROFILE") { + handleCopyProfile(); + } + if (type === "BLOCK") { + setIsBlockDialogOpen(true); + } + if (type === "REPORT") { + setIsReportDialogOpen(true); + } + }; + + const blockUser = async () => { + if (!user) return; + if (!currentUser) return; + + const res = await blockOrUnblockUser({ + user_id: user?.userId, + data: { + isBlock: true, + blockedUserId: currentUser.userId, + }, + }); + setIsBlockDialogOpen(false); + + // setCurrentUser(null); + if (res.status === 200) { + handleUser(); + // setCurrentUser(null); + // getUserData(userId); + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + + const handleCopyProfile = () => { + // Copy profile link + navigator.clipboard.writeText( + "https://witit.com/profile/" + currentUser?.userId + ); + + sendNotification({ type: "SUCCESS", message: "Profile Link Coppied!!" }); + }; + + const submitReport = async (inputText: string) => { + if (!user) return; + if (!currentUser) return; + + const res = await reportUser({ + user_id: user.userId, + data: { reportFor: inputText, reportedUserId: currentUser.userId }, + }); + + if (res.status === 200) { + setIsReportDialogOpen(false); + + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + useEffect(() => { + const baseMenu = []; + + if (currentUser?.userId === user?.userId) { + baseMenu.push({ + startIcon: ( +
+ +
+ ), + title: "Logout", + actionType: "LOG_OUT", + }); + } else { + baseMenu.push({ + startIcon: , + title: "Report", + actionType: "REPORT", + }); + if (!currentUser?.blockedBy) { + baseMenu.push({ + startIcon: ( +
+ +
+ ), + title: "Block", + actionType: "BLOCK", + isMyProfileOption: false, + }); + } + } + baseMenu.push({ + startIcon: ( +
+ +
+ ), + actionType: "COPY_PROFILE", + title: "Copy Profile Link", + isMyProfileOption: false, + }); + setmenuList(baseMenu); + }, [currentUser]); + + return ( + <> + +
+ +
+
+ +
+
+ {contentType === "MEMBERS" ? : } +
+
+ + {isReportDialogOpen ? ( + submitReport(inputText)} + onCancel={() => { + setIsReportDialogOpen(false); + }} + /> + ) : null} + + {isBlockDialogOpen ? ( + { + setIsBlockDialogOpen(false); + }} + onConform={() => { + setCurrentUser(null); + blockUser(); + }} + title={{ + titleMain: "Block " + currentUser?.userName + "?", + title2: + currentUser?.userName + + " won't be able to send you messages, see your posts, connect with members, or join your circle. They won't receive a notification that you've blocked them.", + confirmButton: "Block", + }} + /> + ) : null} + + ); +}; + +export default ProfileLeftSection; diff --git a/components/profile/Profile/context/ProfileContext.tsx b/components/profile/Profile/context/ProfileContext.tsx new file mode 100644 index 0000000..6cfb28b --- /dev/null +++ b/components/profile/Profile/context/ProfileContext.tsx @@ -0,0 +1,33 @@ +import { createContext, useContext, useEffect, useState } from "react"; + +import { ReduxUser } from "@/types/user"; + +type ContextType = { + currentUser: ReduxUser | null; + setCurrentUser: React.Dispatch>; +}; + +const defaultContext: ContextType = { + currentUser: null, + setCurrentUser: () => {}, +}; + +const Context = createContext(defaultContext); + +function ProfileContext({ children }: { children: React.ReactNode }) { + const [currentUser, setCurrentUser] = useState(null); + + return ( + + {children} + + ); +} + +export default ProfileContext; +export const useProfileContext = () => useContext(Context); diff --git a/components/profile/Profile/index.tsx b/components/profile/Profile/index.tsx new file mode 100644 index 0000000..5e95de1 --- /dev/null +++ b/components/profile/Profile/index.tsx @@ -0,0 +1,247 @@ +import React, { useEffect, useState } from "react"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomButton from "@/components/shared/CustomButton"; +import { Box, CircularProgress, Divider } from "@mui/material"; +import { RootState } from "@/redux/store"; +import { useRouter } from "next/router"; +import { useDispatch, useSelector } from "react-redux"; +import { blockOrUnblockUser } from "@/api/user/blockOrUnblockUser"; +import { theme } from "@/theme"; +import Moments from "../Moments"; +import { Questionnaries } from "../Questionnaires"; +import ProfileLeftSection from "./components/ProfileLeftSection"; +import { getOtherUser } from "@/api/user/getOtherUser"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { addUserPost } from "@/redux/slices/userPostSlice"; +import FeedIcon from "@/utils/icons/profile/FeedIcon"; +import MomentsIcon from "@/utils/icons/profile/MomentsIcon"; +import { QuestionnariesIcon } from "@/utils/icons/profile/QuestionnariesIcon"; +import { blockUserIllustrator } from "@/utils/images"; +import { useProfileContext } from "./context/ProfileContext"; +import Feed from "../Feed"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import OfferingIcon from "@/utils/icons/profile/OfferingIcon"; +import Offering from "./components/Offering"; + +type ContentType = "FEED" | "QUESTIONNAIRES" | "MOMENTS" | "OFFERING"; + +type ProfileTab = { + name: string; + type: ContentType; + startIcon: JSX.Element; +}; + +const profileTabs: ProfileTab[] = [ + { + name: "Feed", + type: "FEED", + startIcon: , + }, + { + name: "Offering", + type: "OFFERING", + startIcon: , + }, + { + name: "Questionnaires", + type: "QUESTIONNAIRES", + startIcon: , + }, + { + name: "Moments", + type: "MOMENTS", + startIcon: , + }, +]; +const Profile = () => { + const router = useRouter(); + const dispatch = useDispatch(); + const { asPath } = useRouter(); + + const { sendNotification } = useAuthContext(); + const { currentUser, setCurrentUser } = useProfileContext(); + const [contentType, setcontentType] = useState("FEED"); + const [selectedPostId, setSelectedPostId] = useState(null); + + let user = useSelector((state: RootState) => state.user); + + const [userId, setUserId] = useState(null); + + const getUserData = async (userId: string) => { + if (!user) return; + const res = await getOtherUser({ + user_id: user.userId, + profilerId: userId, + }); + if (res.status === 200) { + setCurrentUser(res.data); + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + + const handleUserData = () => { + if (!userId) return; + + getUserData(userId); + }; + + const unblockUser = async () => { + if (!user) return; + if (!userId) return; + + const res = await blockOrUnblockUser({ + user_id: user.userId, + data: { + isBlock: false, + blockedUserId: userId, + }, + }); + + setCurrentUser(null); + if (res.status === 200) { + setCurrentUser(null); + getUserData(userId); + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + // This runs after the component has mounted + if (router.isReady) { + const userIdFromRouter = router.query.user as string; + setUserId(userIdFromRouter); + } + }, [router.isReady, asPath]); + + // useEffect(() => { + // setUserId(router.query.user as string); + // setCurrentUser(null); + // if (userId && userId !== user?.userId) { + // getUserData(userId); + // } else { + // setCurrentUser(user); + // } + // }, [asPath]); + + // const handleUserRequest = async () => { + // const userName = router.asPath.slice(1, router.asPath.length); + + // if (userName.length > 0) { + // const dynamicLinkData = await getUserByUserName(userName); + + // if (dynamicLinkData.status === 200) { + // const link = dynamicLinkData.data.dynamicProfileLink; + + // if (link) { + // window.location.href = link; + // console.log("redirecterd to:- ", link); + // return; + // } + // } + // } + // }; + + useEffect(() => { + setCurrentUser(null); + dispatch(addUserPost([])); + + if (userId !== null) { + if (userId && userId !== user?.userId) { + getUserData(userId); + } else { + setCurrentUser(user); + } + } + }, [userId]); + + if (currentUser === null) { + return ( +
+ +
+ ); + } + + if (currentUser.userId !== user?.userId && currentUser.blockedBy) { + if (currentUser.blockedBy === user?.userId) { + return ( + + + + } + title="You have blocked the user" + description="it looks like you are unable to view a profile of this user because you blocked this user." + buttonName="Unblock" + handleEvent={unblockUser} + /> + ); + } + + if (currentUser.blockedBy !== user?.userId) { + return ( + + + + } + title="User has blocked you" + description="it looks like you are unable to view a profile of this user because they blocked you." + /> + ); + } + } + return ( +
+
+ +
+
+
+
+ {profileTabs.map((tab, index) => { + return ( + { + setcontentType(tab.type); + setSelectedPostId(null); + }} + className={`w-fit rounded-3xl px-4 py-2 font-light text-sm tracking-wider ${ + contentType.includes(tab.type) + ? "" + : "bg-secondary-main text-grey-100 hover:bg-primary-main hover:bg-opacity-25" + }`} + name={tab.name} + startIcon={tab.startIcon} + /> + ); + })} +
+ + +
+ + {contentType === "FEED" ? ( + + ) : contentType === "QUESTIONNAIRES" ? ( + + ) : contentType === "MOMENTS" ? ( + + ) : contentType === "OFFERING" ? ( + + ) : null} +
+
+ ); +}; + +export default Profile; diff --git a/components/profile/Questionnaires/components/OtherUserQuestions.tsx b/components/profile/Questionnaires/components/OtherUserQuestions.tsx new file mode 100644 index 0000000..11d1623 --- /dev/null +++ b/components/profile/Questionnaires/components/OtherUserQuestions.tsx @@ -0,0 +1,125 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { RootState } from "@/redux/store"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import { theme } from "@/theme"; +import { QuestionType } from "@/types/question"; +import { profilePlaceholderImage } from "@/utils/images"; +import { Favorite, FavoriteBorder } from "@mui/icons-material"; +import { Checkbox, Divider, IconButton } from "@mui/material"; +import dayjs from "dayjs"; +import { useRouter } from "next/router"; + +import { useSelector } from "react-redux"; + +type Props = { + questionData: QuestionType; + + handleLikeCount: ({ + questionId, + isLike, + }: { + questionId: string; + isLike: boolean; + }) => void; + + questionId: string; +}; + +const OtherUserQuestions = ({ + questionData, + + handleLikeCount, +}: Props) => { + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + if (!user) { + return <>; + } + + return ( +
+
+ +
+ +
+
+
+

{questionData.question}

+
+

+ Asked By{" "} + { + e.stopPropagation(); + router.push( + redirectTouserProfile( + questionData.questioner.id, + user?.userId + ) + ); + }} + > + {questionData.questioner.userName} + +

+
+

+ {" "} + {Math.abs( + dayjs(questionData.createdAt).diff(dayjs(), "day") + ) === 0 + ? 1 + : Math.abs( + dayjs(questionData.createdAt).diff(dayjs(), "day") + )}{" "} + Days Ago +

+
+
+
+
+
+ { + handleLikeCount({ + questionId: questionData.questionId, + isLike: e.target.checked, + }); + }} + checked={questionData.isUserLike ? true : false} + icon={} + checkedIcon={} + /> +
+

+ {questionData.counts.like} +

+
+
+
+ + {questionData.reply ? ( + <> + {" "} + +

hello world

+ + ) : null} +
+
+ ); +}; +export default OtherUserQuestions; diff --git a/components/profile/Questionnaires/components/Question.tsx b/components/profile/Questionnaires/components/Question.tsx new file mode 100644 index 0000000..55c9f3a --- /dev/null +++ b/components/profile/Questionnaires/components/Question.tsx @@ -0,0 +1,238 @@ +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { RootState } from "@/redux/store"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import { theme } from "@/theme"; +import { QuestionType } from "@/types/question"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import { profilePlaceholderImage } from "@/utils/images"; +import { Favorite, FavoriteBorder } from "@mui/icons-material"; +import { Checkbox, Divider, IconButton } from "@mui/material"; +import dayjs from "dayjs"; +import { useRouter } from "next/router"; + +import { useSelector } from "react-redux"; + +type Props = { + questionData: QuestionType; + replyQuestion: (questionData: QuestionType) => void; + setCommentReplyText: React.Dispatch>; + handleAnswer: (questionData: QuestionType) => void; + commentReplyText: string | null; + setQuestionId: React.Dispatch>; + handleLikeCount: ({ + questionId, + isLike, + }: { + questionId: string; + isLike: boolean; + }) => void; + handleDeleteQuestion: (questionData: string) => void; + questionId: string; +}; + +export const Question = ({ + questionData, + replyQuestion, + setCommentReplyText, + handleAnswer, + handleLikeCount, + handleDeleteQuestion, + commentReplyText, + questionId, + setQuestionId, +}: Props) => { + const router = useRouter(); + + const handleClose = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + questionId !== "" && setQuestionId(""); + } + }; + const user = useSelector((state: RootState) => state.user); + if (!user) { + return <>; + } + + return ( +
+
+ +
+ +
+
+
+

{questionData.question}

+
+

+ Asked By{" "} + { + e.stopPropagation(); + router.push( + redirectTouserProfile( + questionData.questioner.id, + user?.userId + ) + ); + }} + > + {questionData.questioner.userName} + +

+
+

+ {" "} + {Math.abs( + dayjs(questionData.createdAt).diff(dayjs(), "day") + ) === 0 + ? 1 + : Math.abs( + dayjs(questionData.createdAt).diff(dayjs(), "day") + )}{" "} + Days Ago +

+
+
+
+
+
+ { + handleLikeCount({ + questionId: questionData.questionId, + isLike: e.target.checked, + }); + }} + checked={questionData.isUserLike ? true : false} + icon={} + checkedIcon={} + /> +
+

+ {questionData.counts.like} +

+
+
+
+ + {questionData.reply && + questionData.reply.length !== null && + questionData.questionId !== questionId && ( + <> + +

{questionData.reply}

+
+

{ + replyQuestion(questionData); + }} + > + Edit +

+

{ + handleDeleteQuestion(questionData.questionId); + }} + > + Delete +

+
+ + )} + {questionData.reply === null && + questionData.questionId !== questionId && ( + <> +
+

{ + replyQuestion(questionData); + }} + > + Reply +

+

{ + handleDeleteQuestion(questionData.questionId); + }} + > + Delete +

+
+ + )} + {questionData.questionId === questionId && ( + ) => { + setCommentReplyText(event.target.value); + }} + value={commentReplyText ?? ""} + placeholder="What do you want to reply?" + EndIcon={ + { + if (commentReplyText && commentReplyText.length > 5) { + handleAnswer(questionData); + } + }} + className={ + commentReplyText && commentReplyText.length > 5 + ? "text-primary-main cursor-pointer" + : "text-grey-300 cursor-default" + } + > + + + } + /> + )} + + {/* +
+
+
+ +
+
+

Gerdes

+
+ +
+
+
+

+ My favorite color is every color and none of the colors all at once + but also it not even a moment. Does that definitely make sense? +

+
*/} +
+
+ ); +}; diff --git a/components/profile/Questionnaires/index.tsx b/components/profile/Questionnaires/index.tsx new file mode 100644 index 0000000..1354142 --- /dev/null +++ b/components/profile/Questionnaires/index.tsx @@ -0,0 +1,307 @@ +import { Question } from "./components/Question"; +import { QuestionType } from "@/types/question"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; +import { use, useEffect, useRef, useState } from "react"; +import getQuestions from "@/api/question/getQuestions"; +import { CircularProgress, IconButton } from "@mui/material"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { useAuthContext } from "@/context/AuthContext"; +import updateReply from "@/api/question/updateReply"; +import changeQuestionLikeStatus from "@/api/question/changeQuestionLikeStatus"; +import deleteQuestion from "@/api/question/deleteQuestion"; +import OtherUserQuestions from "./components/OtherUserQuestions"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { questionNotFound } from "@/utils/images/question"; +import askQuestion from "@/api/question/askQuestion"; +import ProfileContext, { + useProfileContext, +} from "../Profile/context/ProfileContext"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import SendIcon from "@/utils/icons/circle/SendIcon"; + +type Parems = { + lastDocId?: string | undefined; + isLastReplyGiven?: boolean | undefined; +}; + +export const Questionnaries = () => { + const [questionList, setQusetionList] = useState([]); + const [hasMoreQuestion, sethasMoreQuestion] = useState(true); + const [commentReplyText, setCommentReplyText] = useState(null); + const [questionId, setQuestionId] = useState(""); + const [isOtherUserQuestions, setIsOtherUserQuestions] = useState(false); + const [askQuestionText, setAskQuestionText] = useState(""); + + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + const { currentUser, setCurrentUser } = useProfileContext(); + + useEffect(() => { + fetchQuestionList(); + + if (currentUser?.userId !== user?.userId) { + setIsOtherUserQuestions(true); + } else { + setIsOtherUserQuestions(false); + } + }, [currentUser]); + + if (!user) { + return <>; + } + + const fetchQuestionList = async ( + lastDocId?: string | undefined, + isLastReplyGiven?: boolean | undefined + ) => { + const response = await getQuestions({ + user_id: user.userId, + lastDocId, + isLastReplyGiven, + ...(currentUser?.userId !== user.userId && { + otherUserId: currentUser?.userId, + }), + }); + + if (response.status === 200 && response.data) { + if (response.data.length < 10) { + sethasMoreQuestion(false); + } else { + sethasMoreQuestion(true); + } + if (response.data.length >= 0) { + if (lastDocId) { + setQusetionList([...questionList, ...response.data]); + return; + } + } + + setQusetionList(response.data); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + if (!questionList) { + return <>; + } + const fetchMoreQuestions = () => { + const lastDocId = questionList[questionList.length - 1].questionId; + const lastReplyGiven = questionList[questionList.length - 1].reply; + if (lastDocId && lastReplyGiven !== null) { + fetchQuestionList(lastDocId, true); + } else { + fetchQuestionList(lastDocId, false); + } + }; + + const replyQuestion = (questionData: QuestionType) => { + setCommentReplyText(questionData.reply); + + questionList.map((value) => { + if (value.questionId === questionData.questionId) { + setQuestionId(questionData.questionId); + } + return value; + }); + }; + + const handleDeleteQuestion = async (questionId: string) => { + const dropQustionList = questionList.filter((value) => { + return value.questionId !== questionId; + }); + + setQusetionList(dropQustionList); + + const response = await deleteQuestion({ + user_id: user.userId, + questionId: questionId, + }); + + if (response.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Question Deleted successfully", + }); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + + const handleAnswer = async (questionData: QuestionType) => { + const updateQuestionList = questionList.map((value) => { + if (value.questionId === questionData.questionId) { + value.reply = commentReplyText; + } + return value; + }); + + setQusetionList(updateQuestionList); + setQuestionId(""); + const response = await updateReply({ + questionId: questionData.questionId, + user_id: user.userId, + reply: commentReplyText, + }); + if (response.status === 200) { + console.log(response); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + const handleLikeCount = async ({ + questionId, + isLike, + }: { + questionId: string; + isLike: boolean; + }) => { + const handleLikeRender = questionList.map((value) => { + if (value.questionId === questionId) { + if (isLike) { + value.counts.like += 1; + value.isUserLike = true; + } else { + value.counts.like -= 1; + value.isUserLike = false; + } + } + + return value; + }); + + setQusetionList(handleLikeRender); + + const response = await changeQuestionLikeStatus({ + user_id: user.userId, + questionId, + isLike, + }); + if (response.status === 200) { + return; + } + }; + + const handleAskQuestion = async () => { + if (currentUser?.userId === user.userId) return; + + const response = await askQuestion({ + user_id: user.userId, + creatorId: currentUser?.userId, + question: askQuestionText, + }); + if (response.status === 200 && response.data) { + setQusetionList((preQuestions) => { + if (response.data) { + return [response.data, ...preQuestions]; + } else { + return preQuestions; + } + }); + setAskQuestionText(""); + return; + } + + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( +
+
+ {questionList.length === 0 && !hasMoreQuestion ? ( + + +
+ } + description=" It looks like nobody has asked a question yet. Lets wait for the first one!" + /> + ) : ( + + +
+ } + className=" gap-3 w-full flex flex-col" + scrollableTarget="questionScrollableDiv" + > + {questionList.map((question, index) => { + return ( + <> + {isOtherUserQuestions ? ( + + ) : ( + <> + + + )} + + ); + })} + + )} +
+ + {isOtherUserQuestions && ( +
+ ) => { + setAskQuestionText(event.target.value); + }} + placeholder="What do you want to ask about?" + EndIcon={ + { + if (askQuestionText.length > 2) handleAskQuestion(); + }} + className={ + askQuestionText.length > 2 + ? "text-primary-main cursor-pointer" + : "text-grey-300 cursor-default" + } + > + + + } + /> +
+ )} +
+ ); +}; diff --git a/components/setting/components/Account/components/CreditSettings.tsx b/components/setting/components/Account/components/CreditSettings.tsx new file mode 100644 index 0000000..417594d --- /dev/null +++ b/components/setting/components/Account/components/CreditSettings.tsx @@ -0,0 +1,265 @@ +import { theme } from "@/theme"; +import CreaditIcon from "@/utils/icons/setting/CreaditIcon"; +import { Button, Divider } from "@mui/material"; +import React, { Dispatch, SetStateAction, useState } from "react"; +import { ReduxUser } from "@/types/user"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; + +import { + Control, + ControllerProps, + FieldErrors, + FieldPath, + FieldValues, + UseFormSetValue, +} from "react-hook-form"; +import CustomToggleSwitch from "@/components/shared/CustomToggleSwitch"; +import NotCreditShowCrown from "@/utils/icons/setting/NotCreditShowCrown"; +import CustomButton from "@/components/shared/CustomButton"; +import GradientCrown from "@/utils/icons/levelUp/GradientCrown"; +import { useAuthContext } from "@/context/AuthContext"; + +type Props = { + setValue: UseFormSetValue>; + setCurrentTab: Dispatch>; + Controller: < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath + >( + props: ControllerProps + ) => React.ReactElement; + control: Control, any>; + errors: FieldErrors>; +}; +const CreditSettings = ({ + setValue, + Controller, + control, + setCurrentTab, + errors, +}: Props) => { + const user = useSelector((state: RootState) => state.user); + const [isAllowedOthers, setIsAllowedOthers] = useState( + user?.generationSettings?.allowGenerationOnPost + ); + const { setCustomDialogType } = useAuthContext(); + + return ( + <> +
+
+
+ +

Credit Settings

+
+ +
+ +
+ {" "} +
+
+

+ Earn with Witit +

+

+ With Witit, you can allow others to generate images and By doing + so you can charge credits per transaction and withdrawal those + credits into cash at the rate of $1 for every 150 credits +

+
+
+
+

+ Allow others to use your post on their AI +

+
+ ( + { + setIsAllowedOthers(e.target.checked); + field.onChange(e.target.checked); + if (!e.target.checked) { + setValue( + "generationSettings.creditPerDerivative", + 0 + ); + return; + } + }} + /> + )} + /> +
+
+ {isAllowedOthers && ( + <> + +
+
+

+ Cost per derivative +

+

+ If someone uses your image when generating their image, + you will get this credit. +

+

+ { + errors.generationSettings?.creditPerDerivative + ?.message + } +

+
+ { + return ( + fieldValue! >= 1 || + "Credit PerDerivative must be greater than 0" + ); + }, + }), + }} + render={({ field }) => ( + { + field.onChange(+e.target.value); + }} + className=" w-[80px] p-2 h-fit text-center border rounded-lg focus:outline-none border-grey-600 bg-grey-800 " + /> + )} + /> +
+ + )} +
+
+
+
+

Cost per Message

+

+ You will get this credit when unverified senders sends a + message to you. +

+

+ {errors.generationSettings?.creditPerMessage?.message} +

+
+ { + return ( + fieldValue! >= 1 || + "Cost per Message must be greater than 0" + ); + }, + }), + }} + render={({ field }) => ( + { + field.onChange(+e.target.value); + }} + className=" w-[80px] p-2 h-fit text-center border rounded-lg focus:outline-none border-grey-600 bg-grey-800 " + /> + )} + /> +
+
+
+

+ You can set the price for your AI models so when someone uses + your AI model to generate an image, you get credits. +

+ +
+

{ + setCurrentTab("AI_MODELS"); + }} + > + SET PRICE FOR EACH MODEL +

+
+
+ {/*
+ { + handleSubmit(); + }} + /> +
*/} +
+
+ {!user?.generationSettings && ( +
+ +

+ Earn cash{" "} + from your AI, posts, prompts or through messaging +

+
+ + + +
+
+ )} +
+ + ); +}; + +export default CreditSettings; diff --git a/components/setting/components/Account/index.tsx b/components/setting/components/Account/index.tsx new file mode 100644 index 0000000..170721e --- /dev/null +++ b/components/setting/components/Account/index.tsx @@ -0,0 +1,591 @@ +import React, { + ChangeEvent, + Dispatch, + SetStateAction, + useEffect, + useState, +} from "react"; +import { theme } from "@/theme"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import InstagramIcon from "@/utils/icons/setting/socialMedia/InstagramIcon"; +import TwitterIcon from "@/utils/icons/setting/socialMedia/TwitterIcon"; +import TiktokIcon from "@/utils/icons/setting/socialMedia/TiktokIcon"; +import TwitchIcon from "@/utils/icons/setting/socialMedia/TwitchIcon"; +import YouTubeIcon from "@/utils/icons/setting/socialMedia/YouTubeIcon"; +import WebsiteIcon from "@/utils/icons/setting/socialMedia/WebsiteIcon"; +import EditProfileIcon from "@/utils/icons/setting/EditProfileIcon"; +import LinkIcon from "@/utils/icons/setting/LinkIcon"; +import CustomToggleSwitch from "@/components/shared/CustomToggleSwitch"; +import { CircularProgress, Divider } from "@mui/material"; +import { Controller, useForm } from "react-hook-form"; +import { ReduxUser } from "@/types/user"; +import ImagePlaceHolderGalleryIcon from "@/utils/icons/createPost/ImagePlaceHolderGalleryIcon"; +import { getImageObject } from "@/service/shared/getImageObject"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { convertEmptyToNull } from "@/service/shared/convertEmptyFieldToNull"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { updateUser } from "@/api/user/updateUser"; +import { useAuthContext } from "@/context/AuthContext"; +import { useDispatch } from "react-redux"; +import InputCropSingleImage from "@/components/shared/cropImage/singleCropImage/InputCropSingleImage"; +import CreditSettings from "./components/CreditSettings"; +import SettingBottomBar from "../Shared/SettingBottomBar"; + +type Props = { + user: ReduxUser; + setCurrentTab: Dispatch>; +}; + +const Account = ({ user, setCurrentTab }: Props) => { + const dispatch = useDispatch(); + + const [profileImage, setProfileImage] = useState<{ + imagePreview: string; + file: File; + } | null>(null); + const [isProfileSubmitting, setIsProfileSubmitting] = useState(false); + + const { sendNotification } = useAuthContext(); + + const defaultValues: Partial = { + generalInfo: { + firstName: user.generalInfo.firstName, + lastName: user.generalInfo.lastName, + profileImage: user.generalInfo.profileImage, + bio: user.generalInfo.bio ?? "", + }, + shouldShowRepost: user.shouldShowRepost, + userName: user.userName, + linkedAccounts: { + instagram: user.linkedAccounts.instagram ?? "", + twitter: user.linkedAccounts.twitter ?? "", + youtube: user.linkedAccounts.youtube ?? "", + twitch: user.linkedAccounts.twitch ?? "", + tiktok: user.linkedAccounts.tiktok ?? "", + onlyfans: user.linkedAccounts.onlyfans ?? "", + }, + generationSettings: { + allowGenerationOnPost: user.generationSettings?.allowGenerationOnPost, + creditPerDerivative: user.generationSettings?.creditPerDerivative ?? 0, + creditPerMessage: user.generationSettings?.creditPerMessage ?? 0, + }, + }; + + const { + control, + setValue, + handleSubmit, + formState: { errors, isSubmitting, isDirty, isValid }, + } = useForm>({ + defaultValues, + mode: "onSubmit", + }); + + const handleSetProfileImage = async () => { + if (!user.generalInfo.profileImage) return; + + const { file } = await getImageObject(user.generalInfo.profileImage); + + setProfileImage({ imagePreview: user.generalInfo.profileImage, file }); + setValue("generalInfo.profileImage", user.generalInfo.profileImage); + }; + + useEffect(() => { + handleSetProfileImage(); + () => { + handleSetProfileImage(); + }; + }, [user]); + + const onSubmit = async (data: Partial) => { + setIsProfileSubmitting(true); + if (user.userType === "GENERAL") { + delete data.generationSettings; + } + data = convertEmptyToNull(data); + + // profileImage && data.generalInfo?.profileImage; + + if ( + profileImage && + data.generalInfo && + profileImage?.imagePreview.includes("data:") + ) { + const image = await uploadImageToStorage({ + folderName: "profile_picture_images", + file: profileImage.file, + metadata: { + userId: user.userId, + }, + }); + data.generalInfo.profileImage = image; + } + + const result = await updateUser({ + user_id: user.userId, + data, + }); + + if (result.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Data Update Successfuly ", + }); + + setProfileImage(null); + setIsProfileSubmitting(false); + return; + } + + setIsProfileSubmitting(false); + sendNotification({ type: "ERROR", message: result.error }); + }; + + return ( + <> +
e.preventDefault()}> + {/* left side */} +
+
+
+
+
+ +

Edit Profile

+
+ +
+
+
+ {profileImage || !user.generalInfo.profileImage ? ( + + +
+ ), + placeholderTitle: ( + <> +

+ Drag & Drop Profile Photo +

+ or +

+ Browse +

+ + ), + }} + /> + ) : ( +
+
+ +
+
+ )} +
+
+
+
+

User name

+ ( + <> + ) => { + const value = e.target.value.replace( + /[^A-Za-z0-9._]/gi, + "" + ); + field.onChange(value); + }} + placeholder="Enter Your Username" + className="text-grey-100 border-0 h-full [&>.MuiInputBase-root]:font-light" + /> +

+ {errors.userName?.message} +

+ + )} + /> +
+
+

Your First name

+ ( + <> + +

+ {errors.generalInfo?.firstName?.message} +

+ + )} + /> +
+
+

Your Last name

+ ( + <> + +

+ {errors.generalInfo?.lastName?.message} +

+ + )} + /> +
+
+

Bio

+ ( + <> + +

+ {errors.generalInfo?.bio?.message} +

+ + )} + /> +
+
+
+

Show repost on your profile

+

+ Turning this on means other people will able to see + your reposted post in your profile. +

+
+
+ ( + field.onChange(!field.value)} + /> + )} + /> +
+
+
+
+
+
+ {/* right side */} +
+ +
+
+ {/*Links*/} +
+
+
+
+ +
+

Linked Accounts

+
+ +
+
+ ( +
+ .MuiInputBase-root]:font-light`} + StartIcon={ +
+ +
+ } + /> +
+ )} + /> + ( +
+ + +
+ } + /> +
+ )} + /> + ( +
+ + +
+ } + /> +
+ )} + /> + ( +
+ + +
+ } + /> + + )} + /> + ( +
+ + +
+ } + /> + + )} + /> + ( +
+ + +
+ } + /> + + )} + /> + + + +
+ { + if (isDirty || profileImage?.imagePreview.includes("data:")) { + handleSubmit(onSubmit)(); + } + }} + loading={isProfileSubmitting} + /> +
+ + + + ); +}; + +export default Account; diff --git a/components/setting/components/AiModels/components/ApplicationItem.tsx b/components/setting/components/AiModels/components/ApplicationItem.tsx new file mode 100644 index 0000000..6210758 --- /dev/null +++ b/components/setting/components/AiModels/components/ApplicationItem.tsx @@ -0,0 +1,51 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { theme } from "@/theme"; +import { AiApplication } from "@/types/ai"; +import { Divider } from "@mui/material"; +import dayjs from "dayjs"; +import React from "react"; + +type Props = { + application: AiApplication; +}; +const ApplicationItem = ({ application }: Props) => { + return ( +
+
+
+

{application.modelName}

+

+ Created On {dayjs(application.createdAt).format("DD MMM, YYYY")} +

+
+ +
+ {application.applicationStatus === "REJECTED" ? ( +
+ +

+ {application.message} +

+
+ ) : null} +
+ ); +}; + +export default ApplicationItem; diff --git a/components/setting/components/AiModels/components/ModelItem/components/EditModelDialog.tsx b/components/setting/components/AiModels/components/ModelItem/components/EditModelDialog.tsx new file mode 100644 index 0000000..54059fc --- /dev/null +++ b/components/setting/components/AiModels/components/ModelItem/components/EditModelDialog.tsx @@ -0,0 +1,258 @@ +import { updateAiModelDetails } from "@/api/ai/updateAiModelDetails"; +import CustomButton from "@/components/shared/CustomButton"; +import CustomInputTag from "@/components/shared/CustomInputTag"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import CustomToggleSwitch from "@/components/shared/CustomToggleSwitch"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import CustomDialogCommonTopBar from "@/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +import { useAuthContext } from "@/context/AuthContext"; +import { updateModels } from "@/redux/slices/modelSlice"; +import { RootState } from "@/redux/store"; +import { theme } from "@/theme"; +import { UserModel } from "@/types/ai"; +import EditIcon from "@/utils/icons/shared/EditIcon"; +import { Divider } from "@mui/material"; +import React, { ChangeEvent, useContext, useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { useDispatch, useSelector } from "react-redux"; +type Props = { + model: UserModel; + setIsModelDialogOpen: React.Dispatch>; +}; + +export const EditModelDialog = ({ model, setIsModelDialogOpen }: Props) => { + const dispatch = useDispatch(); + + const user = useSelector((state: RootState) => state.user); + const models = useSelector((state: RootState) => state.models); + + const { sendNotification } = useAuthContext(); + + const [isModelSubmitting, setIsModelSubmitting] = useState(false); + const [generationCostToggle, setGenerationCostToggle] = useState(false); + + const defaultValues: Partial = { + modelId: model.modelId, + modelName: model.modelName, + generationSettings: model.generationSettings, + }; + + useEffect(() => { + if (!user) return; + + setGenerationCostToggle(model.generationSettings.allowGenerationOnModel); + }, [model]); + + const { + control, + setValue, + handleSubmit, + watch, + getValues, + reset, + formState: { errors, isSubmitting }, + } = useForm>({ + defaultValues, + mode: "onSubmit", + }); + + const onSubmit = async (data: Partial) => { + if (!user) return; + + setIsModelSubmitting(true); + + if ( + data?.generationSettings && + data.generationSettings.allowGenerationOnModel === false + ) { + data.generationSettings.creditPerPhoto = 0; + } + + const result = await updateAiModelDetails({ + user_id: user.userId, + data, + }); + + if (result.status === 200) { + setIsModelSubmitting(false); + sendNotification({ + type: "SUCCESS", + message: "Data Updated Successfully", + }); + setIsModelDialogOpen(false); + + const updatedUserModel = models.userModelList.map((model) => { + if (model.modelId === data.modelId) { + return { + ...model, + ...data, + }; + } + return model; + }); + dispatch(updateModels({ userModelList: updatedUserModel })); + return; + } + + setIsModelSubmitting(false); + sendNotification({ type: "ERROR", message: result.error }); + }; + + return ( + { + setIsModelDialogOpen(false); + }} + className=" max-w-[700px] h-full max-h-[90%]" + > +
+
+ } + title="Edit Model" + onCancel={() => { + setIsModelDialogOpen(false); + }} + /> +

+ Please note that the training image and model class cannot be + edited. If you wish to retrain the model, kindly delete this one and + train a new model. +

+
+
+
+

Banned Words

+

+ Any words entered into this field will be prohibited to use, + preventing the generation of images containing those words. By not + including banned words, your verification badge will be red, + indicating that nothing is off limits. +

+
+
+ ( + { + field.onChange(negativePrompt); + }} + /> + )} + /> +
+
+
+
+

Model Name

+
+ ( + ) => { + field.onChange(e.target.value); + }} + /> + )} + /> +
+
+
+

Earn with Witit

+

+ With Witit, you can allow others to generate images and By doing + so you can charge credits per transaction and withdrawal those + credits into cash at the rate of $1 for every 150 credits +

+
+
+
+

Allow others to generate on your AI

+ ( + { + field.onChange(!field.value); + setGenerationCostToggle(!field.value); + }} + /> + )} + /> +
+ {generationCostToggle && ( + <> + +
+
+

Cost per derivative

+

+ If someone uses your image when generating their image, + you will get this credit. +

+
+
+ ( + ) => { + console.log(e.target.value, "555"); + field.onChange(e.target.value); + }} + className={`[&>.MuiInputBase-root>.MuiInputBase-input]:text-center py-2 ${ + errors.generationSettings?.creditPerPhoto + ? "border-error-main" + : "" + } `} + /> + )} + /> +
+
+ {errors.generationSettings?.creditPerPhoto && ( +

+ {errors.generationSettings?.creditPerPhoto.message} +

+ )} + + )} +
+
+
+ +
+
+
+ ); +}; diff --git a/components/setting/components/AiModels/components/ModelItem/index.tsx b/components/setting/components/AiModels/components/ModelItem/index.tsx new file mode 100644 index 0000000..4fa2f98 --- /dev/null +++ b/components/setting/components/AiModels/components/ModelItem/index.tsx @@ -0,0 +1,167 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { theme } from "@/theme"; +import DeleteIcon from "@/utils/icons/shared/DeleteIcon"; +import { AvatarGroup, Avatar, IconButton } from "@mui/material"; +import React, { useState } from "react"; +import { UserModel } from "@/types/ai"; +import dayjs from "dayjs"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { EditModelDialog } from "./components/EditModelDialog"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import deleteAiModel from "@/api/ai/deleteAiModel"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import { getBaseAndSelfModels } from "@/api/ai/getBaseAndSelfModels"; +import { updateModels } from "@/redux/slices/modelSlice"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import { deleteModelBin } from "@/utils/images"; + +type Props = { + model: UserModel; +}; + +const ModelItem = ({ model }: Props) => { + const [isModelDialogOpen, setIsModelDialogOpen] = useState(false); + const [isDeleteModel, setisDeleteModel] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const user = useSelector((state: RootState) => state.user); + const models = useSelector((state: RootState) => state.models); + const { sendNotification } = useAuthContext(); + + const dispatch = useDispatch(); + const { userModelList } = models; + + const handleDeleteModel = async () => { + setIsLoading(true); + const response = await deleteAiModel({ + user_id: user?.userId, + modelId: model.modelId, + }); + if (response.status === 200 && response.data) { + sendNotification({ type: "SUCCESS", message: response.data }); + const updatedList = userModelList.filter((item) => { + return item.modelId !== model.modelId; + }); + dispatch( + updateModels({ + userModelList: updatedList, + }) + ); + setIsLoading(false); + setisDeleteModel(false); + + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( + <> +
{ + if (model.isActive) { + e.stopPropagation(); + setIsModelDialogOpen(true); + } + }} + > +
+ + {model.selectedPhotos.map((image, index) => { + return ( + + + + ); + })} + +
+
+ {model.generationSettings.allowGenerationOnModel + ? "Public Model" + : "Private Model"} +
+ { + e.stopPropagation(); + setisDeleteModel(true); + }} + className="bg-grey-700 text-grey-200 rounded-lg border border-solid border-grey-600 hover:border-error-main hover:text-error-main" + > + + +
+
+
+

{model.modelName}

+

+ Created On {dayjs(model.createdAt).format("DD MMM, YYYY")} |{" "} + {model.counts.generatedImages} Photos Generated +

+
+
+ {isModelDialogOpen ? ( + + ) : null} + {isDeleteModel && ( + // { + // setisDeleteModel(false); + // }} + // className="h-[300px] w-[300px] flex items-center justify-center" + // > + // { + // handleDeleteModel(); + // }} + // /> + // + + { + setisDeleteModel(false); + }} + onConform={() => { + handleDeleteModel(); + }} + title={{ + titleMain: "Delete Model?", + title1: "Sure you want to delete this Model from your account?", + title2: "You will not be able to recover them again.", + confirmButton: "Delete", + }} + /> + )} + + ); +}; + +export default ModelItem; diff --git a/components/setting/components/AiModels/index.tsx b/components/setting/components/AiModels/index.tsx new file mode 100644 index 0000000..45b26b1 --- /dev/null +++ b/components/setting/components/AiModels/index.tsx @@ -0,0 +1,203 @@ +import React, { useEffect, useState } from "react"; +import { CircularProgress, Divider } from "@mui/material"; +import NotificationIcon from "@/utils/icons/setting/NotificationIcon"; + +import { theme } from "@/theme"; +import ApplicationItem from "./components/ApplicationItem"; +import ModelItem from "./components/ModelItem"; +import AiModelIcon from "@/utils/icons/setting/AiModelIcon"; +import AiApplicationIcon from "@/utils/icons/setting/AiApplicationIcon"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import AIModelTraining from "@/components/aiModelTraining"; +import { getAiModelApplications } from "@/api/ai/getAiModelApplications"; +import { AiApplication } from "@/types/ai"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { noModelFound } from "@/utils/images/setting"; +import CustomButton from "@/components/shared/CustomButton"; +import { useAuthContext } from "@/context/AuthContext"; +import SettingBottomBar from "../Shared/SettingBottomBar"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; + +type GetAiModelProps = { + lastDocId?: string; +}; + +const docLimit = 10; + +const AiModels = () => { + const models = useSelector((state: RootState) => state.models); + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + + const [isTrainModelDialogOpen, setIsTrainModelDialogOpen] = useState(false); + const [aiApplications, setAiApplications] = useState([]); + const [hasMoreAiApplication, setHasMoreAiApplication] = useState(true); + + const handleGetAiModelApplications = async ({ + lastDocId, + }: GetAiModelProps) => { + if (!user) return; + + const res = await getAiModelApplications({ + user_id: user.userId, + limit: docLimit, + ...(lastDocId && { lastDocId }), + }); + + if (res.status === 200) { + if (res.data.length < docLimit) { + setHasMoreAiApplication(false); + } + + if (res.data.length > 0) { + if (lastDocId) { + setAiApplications((preApplications) => { + return [...preApplications, ...res.data]; + }); + return; + } + setAiApplications(res.data); + } + return; + } + + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + handleGetAiModelApplications({}); + }, []); + + const fetchMoreAiApplications = async () => { + const lastDocId = aiApplications[aiApplications.length - 1].applicationId; + if (lastDocId) { + handleGetAiModelApplications({ + lastDocId, + }); + } + }; + + if (!user) <>; + + return ( +
+
+ {/* left side */} +
+
+
+
+ +
+

AI Models

+
+ +
+
+ {models.userModelList.map((data, index) => { + return ( +
+ +
+ ); + })} +
+ {models.userModelList.length < 1 && ( +
+ + +
+ } + title="No Models Found" + description="Start train models & enjoy an open and accessible experience!" + /> +
+ )} +
+ + {/* right side */} +
+
+
+
+
+ +
+

Applications

+
+ +
+
+ + +
+ } + scrollableTarget="aiApplicationsScrollableDiv" + className="overflow-auto flex flex-col gap-2 px-6 justify-around" + > + {aiApplications.map((application, index) => ( + + ))} + +
+ {aiApplications.length < 1 && !hasMoreAiApplication && ( +
+ + +
+ } + title="No Applications Found" + description="There are no applications pending. Start train models." + /> +
+ )} +
+
+ {user ? ( +

+ {user.allowedModels - models.userModelList.length} Models + remaining Out Of {user.allowedModels} Free Models +

+ ) : null} + setIsTrainModelDialogOpen(true)} + /> +
+ + {isTrainModelDialogOpen ? ( + + ) : null} + +
+ +
+ + ); +}; + +export default AiModels; diff --git a/components/setting/components/BlockProfiles/components/BlockItem.tsx b/components/setting/components/BlockProfiles/components/BlockItem.tsx new file mode 100644 index 0000000..cbb6ee4 --- /dev/null +++ b/components/setting/components/BlockProfiles/components/BlockItem.tsx @@ -0,0 +1,44 @@ +import CustomButton from "@/components/shared/CustomButton"; +import React from "react"; +import { BlockedUser } from "@/types/user"; +import dayjs from "dayjs"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { profilePlaceholderImage } from "@/utils/images"; + +type Props = { + blockedUser: BlockedUser; + unblockUser: (data: { blockedUserId: string }) => Promise; +}; +const BlockItem = ({ blockedUser, unblockUser }: Props) => { + return ( +
+
+
+ +
+
+

karlshakur

+

+ Blocked On {dayjs(blockedUser.createdAt).format("DD MMM, YYYY")} +

+
+
+ + unblockUser({ + blockedUserId: blockedUser.blockedUserInfo.userId, + }) + } + /> +
+ ); +}; + +export default BlockItem; diff --git a/components/setting/components/BlockProfiles/index.tsx b/components/setting/components/BlockProfiles/index.tsx new file mode 100644 index 0000000..6d9f446 --- /dev/null +++ b/components/setting/components/BlockProfiles/index.tsx @@ -0,0 +1,175 @@ +import React, { useEffect, useState } from "react"; +import { CircularProgress, Divider } from "@mui/material"; +import { theme } from "@/theme"; +import BlockItem from "./components/BlockItem"; +import BlocklistIcon from "@/utils/icons/setting/BlocklistIcon"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { BlockedUser } from "@/types/user"; +import { getBlocklist } from "@/api/user/getBlocklist"; +import { useAuthContext } from "@/context/AuthContext"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { blockOrUnblockUser } from "@/api/user/blockOrUnblockUser"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { blockUSerNotFound } from "@/utils/images/setting"; +import SettingBottomBar from "../Shared/SettingBottomBar"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; + +type GetBlocklistProps = { + lastDocId?: string; +}; + +type UnblockUserProps = { + blockedUserId: string; +}; + +let docLimit = 20; + +const BlockProfiles = () => { + const user = useSelector((state: RootState) => state.user); + + const { sendNotification } = useAuthContext(); + + const [blocklist, setBlocklist] = useState([]); + const [hasMoreBlockUsers, setHasMoreBlockUsers] = useState(true); + + const handleGetAiModelApplications = async ({ + lastDocId, + }: GetBlocklistProps) => { + if (!user) return; + + const res = await getBlocklist({ + user_id: user.userId, + limit: docLimit, + ...(lastDocId && { lastDocId }), + }); + + if (res.status === 200) { + const currentAiApplications = res.data; + if (currentAiApplications.length < docLimit) { + setHasMoreBlockUsers(false); + } + + if (currentAiApplications.length > 0) { + if (lastDocId) { + setBlocklist((preApplications) => { + return [...preApplications, ...currentAiApplications]; + }); + + return; + } + setBlocklist((preApplications) => { + return currentAiApplications; + }); + } + return; + } + + sendNotification({ type: "ERROR", message: res.error }); + }; + + const unblockUser = async ({ blockedUserId }: UnblockUserProps) => { + if (!user) return; + + const res = await blockOrUnblockUser({ + user_id: user?.userId, + data: { + isBlock: false, + blockedUserId, + }, + }); + + if (res.status === 200) { + setBlocklist((preApplications) => { + const newList = preApplications.filter( + (item) => item.blockedUserInfo.userId !== blockedUserId + ); + return newList; + }); + + return; + } + + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + handleGetAiModelApplications({}); + + return () => { + handleGetAiModelApplications({}); + }; + }, []); + + const fetchMoreBlockUsers = async () => { + const lastDocId = blocklist[blocklist.length - 1].blockListId; + + handleGetAiModelApplications({ + lastDocId, + }); + }; + + return ( +
+
+
+
+
+ +
+

Block Profiles

+
+ +
+
+ + +
+ } + scrollableTarget="blocklistScrollableDiv" + className="overflow-auto flex flex-col gap-4 px-6 pt-3 pb-6" + > + {blocklist.map((item, index) => ( +
+ +
+ +
+
+ ))} + +
+ {blocklist.length < 1 && !hasMoreBlockUsers && ( +
+ + +
+ } + title="No Blocked Profiles" + /> +
+ )} + +
+ +
+ + ); +}; + +export default BlockProfiles; diff --git a/components/setting/components/LinkBankAccount/components/DetailsPendingStatus.tsx b/components/setting/components/LinkBankAccount/components/DetailsPendingStatus.tsx new file mode 100644 index 0000000..d94b190 --- /dev/null +++ b/components/setting/components/LinkBankAccount/components/DetailsPendingStatus.tsx @@ -0,0 +1,65 @@ +import CustomButton from "@/components/shared/CustomButton"; +import { theme } from "@/theme"; +import DollerIcon from "@/utils/icons/setting/DollerIcon"; +import DocumentPending from "@/utils/icons/setting/DocumentPending"; +import { Divider } from "@mui/material"; +import React, { useState } from "react"; +import { getBankSetupUrl } from "@/api/stripe/getBankSetupUrl"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { useRouter } from "next/router"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; + +const DetailsPendingStatus = () => { + const [isLoding, setIsLoading] = useState(false); + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + + if (!user) { + return <>; + } + const handleSubmit = async () => { + setIsLoading(true); + const url = window.location.protocol + "//" + window.location.host; + + const response = await getBankSetupUrl({ + returnUrl: url, + refreshUrl: url, + user_id: user.userId, + }); + if (response.status === 200) { + window.open(response.data.url, "_blank"); + setIsLoading(false); + return; + } + setIsLoading(false); + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( +
+
+
+ {" "} + +
+

Document Pending

+

+ To verify your account, we require additional information. Please + provide them to proceed with the verification process. +

+
+ { + handleSubmit(); + }} + /> +
+ ); +}; + +export default DetailsPendingStatus; diff --git a/components/setting/components/LinkBankAccount/components/FailedStatus.tsx b/components/setting/components/LinkBankAccount/components/FailedStatus.tsx new file mode 100644 index 0000000..58cc3ef --- /dev/null +++ b/components/setting/components/LinkBankAccount/components/FailedStatus.tsx @@ -0,0 +1,64 @@ +import { getBankSetupUrl } from "@/api/stripe/getBankSetupUrl"; +import CustomButton from "@/components/shared/CustomButton"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { theme } from "@/theme"; +import DollerIcon from "@/utils/icons/setting/DollerIcon"; +import CancelIcon from "@/utils/icons/setting/statusDialog/CancelIcon"; +import { Divider } from "@mui/material"; +import { useState } from "react"; +import { useSelector } from "react-redux"; + +const FailedStatus = () => { + const [isLoding, setIsLoading] = useState(false); + + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + + const handleSubmit = async () => { + setIsLoading(true); + const url = window.location.protocol + "//" + window.location.host; + if (!user) { + return <>; + } + const response = await getBankSetupUrl({ + returnUrl: url, + refreshUrl: url, + user_id: user.userId, + }); + if (response.status === 200) { + window.open(response.data.url, "_blank"); + setIsLoading(false); + return; + } + setIsLoading(false); + sendNotification({ type: "ERROR", message: response.error }); + }; + return ( +
+
+
+ {" "} + +
+

+ Verification Pending +

+

+ Sorry, we were unable to verify your bank account. please Try Again. +

+
+ { + handleSubmit(); + }} + /> +
+ ); +}; + +export default FailedStatus; diff --git a/components/setting/components/LinkBankAccount/components/LinkedStatus.tsx b/components/setting/components/LinkBankAccount/components/LinkedStatus.tsx new file mode 100644 index 0000000..4d05370 --- /dev/null +++ b/components/setting/components/LinkBankAccount/components/LinkedStatus.tsx @@ -0,0 +1,59 @@ +import { getBankDashboardUrl } from "@/api/stripe/getBankDashboardUrl"; +import CustomButton from "@/components/shared/CustomButton"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import CheckCircleOverflowIcon from "@/utils/icons/setting/statusDialog/CheckCircleOverflowIcon"; +import React, { useState } from "react"; +import { useSelector } from "react-redux"; + +const LinkedStatus = () => { + const [isLoding, setIsLoading] = useState(false); + + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + + const handleSubmit = async () => { + setIsLoading(true); + const response = await getBankDashboardUrl({ user_id: user?.userId }); + if (response.status === 200) { + window.open(response.data.url, "_blank"); + setIsLoading(false); + return; + } + setIsLoading(false); + sendNotification({ type: "ERROR", message: response.error }); + }; + return ( +
+
+
+ {" "} + +
+

+ Bank account linked +

+

+ Your bank account has been linked successfully. You can withdraw your + credit from your linked bank account now. +

+
+ { + handleSubmit(); + }} + /> + {}} + /> +
+ ); +}; + +export default LinkedStatus; diff --git a/components/setting/components/LinkBankAccount/components/NotLinkedStatus.tsx b/components/setting/components/LinkBankAccount/components/NotLinkedStatus.tsx new file mode 100644 index 0000000..7a35d29 --- /dev/null +++ b/components/setting/components/LinkBankAccount/components/NotLinkedStatus.tsx @@ -0,0 +1,59 @@ +import CustomButton from "@/components/shared/CustomButton"; +import BankIcon from "@/utils/icons/setting/BankIcon"; +import React from "react"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { useAuthContext } from "@/context/AuthContext"; +import { getBankSetupUrl } from "@/api/stripe/getBankSetupUrl"; + +const NotLinkedStatus = () => { + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + + + if (!user) { + return <>; + } + const handleSubmit = async () => { + const url = window.location.protocol + "//" + window.location.host; + + const response = await getBankSetupUrl({ + returnUrl: url, + refreshUrl: url, + user_id: user.userId, + }); + if (response.status === 200) { + window.open(response.data.url, '_blank'); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( + + +
+
+
+ {" "} + +
+

+ Bank account not linked +

+

+ Connect bank account to receive payments from witit. +

+
+ { + handleSubmit(); + }} + /> +
+ ); +}; + +export default NotLinkedStatus; diff --git a/components/setting/components/LinkBankAccount/components/PendingStatus.tsx b/components/setting/components/LinkBankAccount/components/PendingStatus.tsx new file mode 100644 index 0000000..d89510d --- /dev/null +++ b/components/setting/components/LinkBankAccount/components/PendingStatus.tsx @@ -0,0 +1,28 @@ +import CustomButton from "@/components/shared/CustomButton"; +import ClockIcon from "@/utils/icons/setting/statusDialog/ClockIcon"; +import React from "react"; + +const PendingStatus = () => { + return ( + +
+
+
+ {" "} + +
+

+ Verification Pending +

+

+ Your bank linking process has not yet been completed, please + complete it. +

+
+ {}} /> +
+ + ); +}; + +export default PendingStatus; diff --git a/components/setting/components/LinkBankAccount/index.tsx b/components/setting/components/LinkBankAccount/index.tsx new file mode 100644 index 0000000..043bac5 --- /dev/null +++ b/components/setting/components/LinkBankAccount/index.tsx @@ -0,0 +1,70 @@ +import React, { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { useAuthContext } from "@/context/AuthContext"; +import { getBankStatus } from "@/api/stripe/getBankStatus"; +import NotLinkedStatus from "./components/NotLinkedStatus"; +import LinkedStatus from "./components/LinkedStatus"; +import DetailsPendingStatus from "./components/DetailsPendingStatus"; +import PendingStatus from "./components/PendingStatus"; +import { CircularProgress, Divider } from "@mui/material"; +import DollerIcon from "@/utils/icons/setting/DollerIcon"; +import { theme } from "@/theme"; +import SettingBottomBar from "../Shared/SettingBottomBar"; + +const LinkBankAccount = () => { + const [bankStatus, setBankStatus] = useState(""); + + const { sendNotification } = useAuthContext(); + const user = useSelector((state: RootState) => state.user); + + const fetchBankStatus = async () => { + const response = await getBankStatus({ user_id: user?.userId }); + if (response.status === 200) { + setBankStatus(response.data.status); + + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + useEffect(() => { + fetchBankStatus(); + }, []); + + return ( + <> +
+
+
+
+ +

Bank Account

+
+ +
+ {bankStatus === "ACCOUNT_NOT_LINKED" && } + {bankStatus === "ACCOUNT_LINKED" && } + {bankStatus === "ACCOUNT_DETAILS_PENDING" && } + {bankStatus === "ACCOUNT_VERIFICATION_PENDING" && } + {!bankStatus && ( +
+
+ +
+
+ )} +
+
+ +
+
+ + ); +}; + +export default LinkBankAccount; diff --git a/components/setting/components/NotificationAndNSFW/index.tsx b/components/setting/components/NotificationAndNSFW/index.tsx new file mode 100644 index 0000000..979ad9e --- /dev/null +++ b/components/setting/components/NotificationAndNSFW/index.tsx @@ -0,0 +1,313 @@ +import { theme } from "@/theme"; +import NotificationIcon from "@/utils/icons/setting/NotificationIcon"; +import { Divider } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import CustomToggleSwitch from "../../../shared/CustomToggleSwitch"; +import NSFWIcon from "@/utils/icons/setting/NSFWIcon"; +import { Interaction } from "@/types/setting"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { ReduxUser } from "@/types/user"; +import { updateUser } from "@/api/user/updateUser"; +import { useAuthContext } from "@/context/AuthContext"; +import SettingBottomBar from "../Shared/SettingBottomBar"; + +const NotificationAndNSFW = () => { + const user = useSelector((state: RootState) => state.user); + const { sendNotification } = useAuthContext(); + const dispatch = useDispatch(); + + const interactions: Interaction[] = [ + { + type: "Like", + description: "When Someone Likes Your Uploaded Post.", + isCheck: user?.pushNotifications?.likes, + objectType: "likes", + }, + { + type: "Comment", + description: "When Someone Comments Your Uploaded Post.", + isCheck: user?.pushNotifications?.comments, + objectType: "comments", + }, + { + type: "Direct Message", + description: "When Someone Messages You Directly.", + isCheck: user?.pushNotifications?.directMessages, + objectType: "directMessages", + }, + { + type: "Circle Add", + description: "When Someone Joins Your Circle.", + isCheck: user?.pushNotifications?.circleAdds, + objectType: "circleAdds", + }, + { + type: "From Witit", + description: "When Witit Sends You Updates.", + isCheck: user?.pushNotifications?.fromWitit, + objectType: "fromWitit", + }, + ]; + const [updatedList, setUpdatedList] = useState(interactions); + const [isNotification, setIsNotification] = useState( + user?.pushNotifications?.pauseAllNotification + ); + const [userObject, setUserObject] = useState(user); + + const fetchData = (item?: Interaction) => { + const notificationObj: any = user?.pushNotifications; + const keys: string[] = Object.keys(notificationObj); + if (!item) { + return; + } + const getKey: string | undefined = keys.find((value) => { + return value === item.objectType; + }); + if (userObject && getKey && userObject.pushNotifications) { + setUserObject({ + ...userObject, + pushNotifications: { + ...userObject.pushNotifications, + [getKey]: item.isCheck, + pauseAllNotification: false, + }, + }); + } + }; + + const handleSwitch = (id: number) => { + const list = updatedList.map((item, index) => { + if (index === id) { + item.isCheck = !item.isCheck; + } + return item; + }); + + setUpdatedList(list); + }; + + const handleAllNotification = (checked: boolean) => { + const obj = { + pauseAllNotification: checked, + likes: false, + comments: false, + directMessages: false, + circleAdds: false, + fromWitit: false, + }; + + if (userObject) { + setUserObject({ + ...userObject, + pushNotifications: obj, + }); + } + }; + + const handleNsfw = (event: boolean) => { + if (userObject) { + setUserObject({ + ...userObject, + NSFW: event, + }); + } + }; + + useEffect(() => { + if (!userObject) { + return; + } + handleSubmit(); + }, [userObject, isNotification]); + + const handleSubmit = async () => { + const response = await updateUser({ + data: { + pushNotifications: userObject?.pushNotifications, + NSFW: userObject?.NSFW, + }, + user_id: user?.userId, + }); + + if (response.status === 200) { + console.log(response.data); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( +
+
+ {/* left side */} +
+
+
+
+ +
+

Notification Settings

+
+ +
+ +
+
+
+

Pause All Notifications

+
+
+ { + setIsNotification(e.target.checked); + handleAllNotification(e.target.checked); + if (e.target.checked === true) { + setUpdatedList( + interactions.map((val) => { + val.isCheck = false; + return val; + }) + ); + } + }} + /> +
+
+ + {updatedList.map((item, id) => { + return ( + <> +
+
+

{item.type}

+

+ {item.description} +

+
+
+ { + handleSwitch(id); + if ( + updatedList.find((item) => item.isCheck === true) + ) { + setIsNotification(false); + } + fetchData(item); + }} + /> +
+
+ + ); + })} +
+
+ {/* right side */} +
+
+
+ +

NSFW

+
+ +
+
+ {" "} +
+
+

+ Allow others to watch NSFW Content In Your Account +

+
+
+ { + handleNsfw(e.target.checked); + }} + /> +
+
+ +
+

+ What is NSFW Content? +

+

+ NSFW is an abbreviation for the phrases such as: “Not Safe For + Wife”, “Not Suitable For Work”, but mostly used as “Not Safe For + Work” +

+

+ It is an internet slang that is often used to describe internet + posts and content that is mainly involves nudity, sexual + activity, heavy profanity and more... +

+

+ With Witit, we want to provide a safe place for people to freely + express art or interests that they couldn’t otherwise share on + other platforms. However doing so comes with some requirements, + such as needing to turn on the ability to see and post NSFW + content. +

+

+ NSFW is also not a free pass to post anything you want, we at + Witit just allow you fewer restricts than our social media + companions. We still do not tolerate obscene violence or illegal + activity of any sort. +

+

+ Accounts that post NSFW content have been marked with a red + verification badge. +

+
+ +
+

+ How can I view or post NSFW content? +

+

+ To turn on, off, or manage your NSFW preferences, you must do so + from the desktop version of Witit. This is part of the app + stores terms of service and not a creative decision. You also + must be 18 years of age or older. Please visit and login to your + Witit account at http://Witit.com to get started.{" "} +

+
+
+
+
+
+ +
+
+ ); +}; + +export default NotificationAndNSFW; diff --git a/components/setting/components/Shared/SettingBottomBar.tsx b/components/setting/components/Shared/SettingBottomBar.tsx new file mode 100644 index 0000000..2ec7907 --- /dev/null +++ b/components/setting/components/Shared/SettingBottomBar.tsx @@ -0,0 +1,91 @@ +import ContactUs from "@/components/footerDialogs/ContactUs"; +import ContentPolicy from "@/components/footerDialogs/ContentPolicy"; +import PrivacyPolicy from "@/components/footerDialogs/PrivacyPolicy"; +import TermsOfServices from "@/components/footerDialogs/TermsOfServices"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import { useAuthContext } from "@/context/AuthContext"; +import React, { useState } from "react"; + +const SettingBottomBar = () => { + const [isOpenDialogString, setIsOpenDialogString] = useState( + null + ); + return ( + <> +
+

{ + setIsOpenDialogString("TERMS_OF_SERVICE"); + }} + > + Terms Of Services +

+

|

+

{ + setIsOpenDialogString("PRIVACY_POLICY"); + }} + > + Privacy Policy +

+

|

{" "} +

{ + setIsOpenDialogString("CONTENT_POLICY"); + }} + > + Content Policy +

+

|

{" "} +

{ + setIsOpenDialogString("CONTACT_US"); + }} + > + Contact Us +

+
+ {isOpenDialogString && ( + { + setIsOpenDialogString(null); + }} + > + {isOpenDialogString === "TERMS_OF_SERVICE" ? ( + { + setIsOpenDialogString(null); + }} + /> + ) : isOpenDialogString === "PRIVACY_POLICY" ? ( + { + setIsOpenDialogString(null); + }} + /> + ) : isOpenDialogString === "CONTENT_POLICY" ? ( + { + setIsOpenDialogString(null); + }} + /> + ) : isOpenDialogString === "CONTACT_US" ? ( + { + setIsOpenDialogString(null); + }} + /> + ) : null} + + )} + + ); +}; + +export default SettingBottomBar; diff --git a/components/setting/index.tsx b/components/setting/index.tsx new file mode 100644 index 0000000..2bb8f8b --- /dev/null +++ b/components/setting/index.tsx @@ -0,0 +1,159 @@ +import { useEffect, useState } from "react"; +import Account from "./components/Account"; +import AiModels from "./components/AiModels"; +import BlockProfiles from "./components/BlockProfiles"; +import LinkBankAccount from "./components/LinkBankAccount"; +import NotificationAndNSFW from "./components/NotificationAndNSFW"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import { NoDataFound } from "../shared/NoDataFound"; +import Lottie from "lottie-react"; +import { failureLottie, verificationSuccessLottie } from "@/utils/lottie"; +import CustomDialog from "../shared/dialog/CustomDialog"; +import { useRouter } from "next/router"; +import paymentStatusSlice, { + PaymentMethodStatus, + setPaymentStatus, +} from "@/redux/slices/paymentStatusSlice"; + +const tabs = [ + { + name: "Account", + type: "ACCOUNT", + }, + { + name: "AI Models", + type: "AI_MODELS", + }, + { + name: "Block Profiles", + type: "BLOCK_PROFILES", + }, + { + name: "Bank Account", + type: "BANK_ACCOUNT", + }, + { + name: "Notification & NSFW", + type: "NOTIFICATION_AND_NSFW", + }, +]; + +const Settings = () => { + const [currentTab, setCurrentTab] = useState("ACCOUNT"); + const dispatch = useDispatch(); + const status = useSelector((state: RootState) => state.payments); + let user = useSelector((state: RootState) => state.user); + const router = useRouter(); + const url = window.location.protocol + "//" + window.location.host; + const { success } = router.query; + useEffect(() => { + if (success === "true" || success === "false") { + dispatch(setPaymentStatus(success)); + router.push(url + "/setting"); + } + }, [success]); + console.log(status); + if (!user) return <>; + + return ( + <> +
+
+ {tabs.map((tab, index) => { + return ( +
{ + setCurrentTab(tab.type); + }} + > +
+

+ {tab.name} +

+
+ ); + })} +
+
+
+ {currentTab === "ACCOUNT" ? ( + + ) : currentTab === "AI_MODELS" ? ( + + ) : currentTab === "BLOCK_PROFILES" ? ( + + ) : currentTab === "BANK_ACCOUNT" ? ( + + ) : ( + + )} +
+
+ + {status?.paymentStatus && ( + + {" "} + {status?.paymentStatus === "true" && ( +
+ + +
+ } + buttonName="Done" + title="Payment Successful" + description="Your transaction has successfully been completed. Credit has been added to your account." + descriptionStyle="text-xs w-full" + buttonStyle="bg-primary-main mt-3" + titleStyle=" text-primary-main mb-2" + handleEvent={() => { + dispatch(setPaymentStatus("")); + }} + /> +
+ )} + {status?.paymentStatus === "false" && ( +
+ + +
+ } + buttonName="Try Again" + title="Ohh No !!" + description="We aren’t able to process your payment. + Please try again !!" + buttonStyle="bg-error-main mt-3" + titleStyle=" text-error-main mb-2" + handleEvent={() => { + dispatch(setPaymentStatus("")); + }} + /> +
+ )} + + )} + + + ); +}; + +export default Settings; diff --git a/components/shared/CategorySelection.tsx b/components/shared/CategorySelection.tsx new file mode 100644 index 0000000..8c90779 --- /dev/null +++ b/components/shared/CategorySelection.tsx @@ -0,0 +1,93 @@ +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { theme } from "@/theme"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import { Tooltip } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; + +type Props = { + sendSelectedCategoryList: (list: string[]) => void; + setEmpty?: boolean; +}; + +const CategorySelection = ({ sendSelectedCategoryList, setEmpty }: Props) => { + const { setDiscoverSearch } = useAuthContext(); + const [selectedCategoryList, setSelectedCategoryList] = useState( + [] + ); + const user = useSelector((state: RootState) => state.user); + + useEffect(() => { + sendSelectedCategoryList(selectedCategoryList); + }, [selectedCategoryList]); + + useEffect(() => { + if (setEmpty) { + setSelectedCategoryList([]); + } + }, [setEmpty]); + + return ( +
+
+ {CategoryList.map((item, index) => { + return ( + <> + {index + 1 === CategoryList.length && !user?.NSFW ? null : ( +
+ { + setDiscoverSearch({ search: null }); + setSelectedCategoryList((prev) => { + if (prev.includes(item.name)) { + return prev.filter( + (category) => category !== item.name + ); + } else { + return [...prev, item.name]; + } + }); + }} + componentsProps={{ + tooltip: { + sx: { + paddingX: 1.5, + paddingY: 0.8, + bgcolor: theme.palette.primary.main, + "& .MuiTooltip-arrow": { + color: theme.palette.primary.main, + }, + }, + }, + }} + > +
+
+ {item.startIcon} +
+
+
+
+ )} + + ); + })} +
+
+ ); +}; + +export default CategorySelection; diff --git a/components/shared/ComingSoon.tsx b/components/shared/ComingSoon.tsx new file mode 100644 index 0000000..4dbd5db --- /dev/null +++ b/components/shared/ComingSoon.tsx @@ -0,0 +1,11 @@ +import { comingSoon } from "@/utils/images"; +import Image from "next/image"; +import { CustomImagePreview } from "./CustomImagePreview"; + +export const ComingSoon = () => { + return ( +
+ +
+ ); +}; diff --git a/components/shared/ConfirmationDialog.tsx b/components/shared/ConfirmationDialog.tsx new file mode 100644 index 0000000..0bddfad --- /dev/null +++ b/components/shared/ConfirmationDialog.tsx @@ -0,0 +1,94 @@ +import { theme } from "@/theme"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { IconButton, Divider } from "@mui/material"; +import React from "react"; +import CustomButton from "./CustomButton"; +import CustomDialog from "./dialog/CustomDialog"; +import { CustomImagePreview } from "./CustomImagePreview"; +import deleteImage from "@/utils/images/deleteOffer.svg"; +import Image from "next/image"; +import crossStripsBg from "@/utils/images/crossStripsBg.svg"; + +type Props = { + isOpen?: boolean; + onCancel?: () => void; + onConform?: () => void; + image?: string; + title?: { + titleMain?: string; + title1?: string; + title2?: string; + confirmButton?: string; + }; +}; +const ConfirmationDialog = ({ + isOpen, + onCancel, + onConform, + title, + image, +}: Props) => { + return ( + <> + {" "} + +
+
+ + +

+ {title && title.titleMain} +

+
+ {/* + + */} +
+ {image && ( +
+ +
+ )} + {title && ( +

+ {title.title1} +

+ )} + {title && ( +

+ {title.title2} +

+ )} +
+
+ + +
+
+
+ + ); +}; + +export default ConfirmationDialog; diff --git a/components/shared/CropImage/ImageCropZone.tsx b/components/shared/CropImage/ImageCropZone.tsx new file mode 100644 index 0000000..3832073 --- /dev/null +++ b/components/shared/CropImage/ImageCropZone.tsx @@ -0,0 +1,111 @@ +import { useAuthContext } from "@/context/AuthContext"; +import { theme } from "@/theme"; +import { ImageInfo } from "@/types"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import React, { useCallback, useEffect } from "react"; +import Cropper from "react-easy-crop"; +import { Point, Area } from "react-easy-crop/types"; + +type Props = { + imagePreview?: ImageInfo; + setAreaPixels?: React.Dispatch>; + setZoom?: (zoom: number) => void; + setCrop?: (crop: Point) => void; +}; + +const ImageCropZone = (props: Props) => { + const { croppingImage, setCroppingImage } = useAuthContext(); + + const handleCropComplete = useCallback( + (croppedArea: Area, croppedAreaPixels: Point) => { + setCroppingImage((prev) => { + return { + ...prev, + image: { ...prev.image, croppedPixels: croppedAreaPixels }, + }; + }); + }, + [] + ); + const handleCrop = useCallback((crop: Point) => { + setCroppingImage((prev) => { + return { + ...prev, + image: { ...prev.image, crop: crop }, + }; + }); + }, []); + + const handleZoom = useCallback((zoom: number) => { + setCroppingImage((prev) => { + return { + ...prev, + image: { ...prev.image, zoom: zoom }, + }; + }); + }, []); + + return ( +
+ {croppingImage?.image?.src && ( +
+ +
+ )} +
+ ); +}; + +export default ImageCropZone; +// style={{ +// // mediaStyle: { overflow: "initial" }, +// containerStyle: { +// // position: "absolute", +// // top: "0", +// width: "50px", +// // height: window.innerWidth, +// // overflow: "hidden", +// // border: "1px solid black", +// }, +// mediaStyle: { width: "51px" }, +// cropAreaStyle: { +// width: "52px", +// }, +// }}// diff --git a/components/shared/CropImage/multipleCropImage/InputCropMultiImages.tsx b/components/shared/CropImage/multipleCropImage/InputCropMultiImages.tsx new file mode 100644 index 0000000..a295b7c --- /dev/null +++ b/components/shared/CropImage/multipleCropImage/InputCropMultiImages.tsx @@ -0,0 +1,146 @@ +/* eslint-disable @next/next/no-img-element */ +"use client"; +import React, { useState, useRef, useEffect, forwardRef } from "react"; +import { ImageInfo } from "@/types"; +import ImagePlaceHolderGalleryIcon from "@/utils/icons/createPost/ImagePlaceHolderGalleryIcon"; +import Lottie from "lottie-react"; +import ImagePlaceholderLottie from "@/utils/lottie/ImagePlaceholderLottie.json"; +import DisplayMultipleImages from "@/service/imageCropper/DisplayMultipleImages"; + +type Props = { + setSelectdImgs: React.Dispatch< + React.SetStateAction< + { + image: ImageInfo; + index: number; + }[] + > + >; + isSmall: boolean; + isEnabled: boolean; +}; + +const InputCropMultiImages = forwardRef( + ({ setSelectdImgs, isSmall, isEnabled }: Props, ref) => { + const [multiImages, setMultiImages] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + + const imageInputRef = useRef(null); + + useEffect(() => { + if (multiImages.length !== 0) setSelectdImgs(multiImages); + }, [multiImages]); + + const handleImageSelection = ( + event: React.ChangeEvent + ) => { + const files = event.target.files; + if (files) { + // setMultiImages([]); + DisplayMultipleImages(Array.from(files), setMultiImages); + } + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + }; + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + const files = event.dataTransfer.files; + if (files) { + // setMultiImages([]); + DisplayMultipleImages(Array.from(files), setMultiImages); + } + }; + + const handleResetInputValue = (event: any) => { + event.target.value = null; + }; + + const handleImageContainerClick = () => { + if (imageInputRef.current) { + imageInputRef.current.click(); + } + // setTempObjectfit(undefined); + }; + + return ( +
+ + {/* */} + + {isSmall ? ( +
+ +
+ ) : ( +
+
+
+ +
+
+ Drag profile pic here,or + browse +
+
+ + {/*
+
+ {isSmall ? ( + + ) : ( +
+ +
+ )} +
+
+ Drag profile pic here,or + browse +
+
*/} +
+ )} + {/*
*/} +
+ ); + } +); + +InputCropMultiImages.displayName = "images"; + +export default InputCropMultiImages; diff --git a/components/shared/CropImage/multipleCropImage/ModifyImages.tsx b/components/shared/CropImage/multipleCropImage/ModifyImages.tsx new file mode 100644 index 0000000..0774313 --- /dev/null +++ b/components/shared/CropImage/multipleCropImage/ModifyImages.tsx @@ -0,0 +1,560 @@ +/* eslint-disable @next/next/no-img-element */ +/* eslint-disable jsx-a11y/alt-text */ +import React, { useCallback, useEffect, useState } from "react"; +import { ImageInfo } from "@/types"; +import InputImages from "../../dialog/GlobalDialogs/components/CreatePostDialog/components/InputImages"; +import { Grid, IconButton, Slider } from "@mui/material"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import CropLinerIcon from "@/utils/icons/createPost/CropLinerIcon"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import CustomButton from "../../CustomButton"; +import CheckIcon from "@/utils/icons/shared/CheckIcon"; +import { theme } from "@/theme"; +import { useAuthContext } from "@/context/AuthContext"; +import getCroppedImg from "@/service/imageCropper/cropImage"; +import DisplayMultipleImages from "@/service/imageCropper/DisplayMultipleImages"; +import ImageCropZone from "../ImageCropZone"; +import InputCropMultiImages from "@/components/shared/cropImage/multipleCropImage/InputCropMultiImages"; + +type Props = { + isNextVisible?: boolean; + isCrop: boolean; + limit: number; + images: { + image: ImageInfo; + index: number; + }[]; + setStep: React.Dispatch>; + setImages: React.Dispatch< + React.SetStateAction< + { + image: ImageInfo; + index: number; + }[] + > + >; +}; + +const styles = { + responsiveGrid: { + xxl: 12, + xl: 12, + lg: 12, + md: 15, + sm: 20, + xs: 20, + }, +}; +const ModifyImages = (props: Props) => { + let { images, setStep, setImages, isNextVisible, isCrop, limit } = props; + const { setCroppingImage, croppingImage } = useAuthContext(); + + const [recentlyAddedPostImageList, setRecentlyAddedPostImageList] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + images = images.slice(0, limit); + const [iszooming, setiszooming] = useState(false); + const [deletedIndex, setdeletedIndex] = useState(null); + const [isDraggingNewImage, setisDraggingNewImage] = useState(false); + + // change images order + const [draggingChangeIndex, setdraggingChangeIndex] = useState( + 0 + ); + const [dropChangeIndex, setDropChangeIndex] = useState(0); + const [isChangingInsideIndex, setIsChangingInsideIndex] = useState(false); + + // show cancelIcon on hover & delete + const [isCloseVisible, setisCloseVisible] = useState({ + isHover: false, + index: 0, + }); + + useEffect(() => { + setCroppingImage(defaultImageConstant); + }, []); + + useEffect(() => { + setTimeout(() => { + if (recentlyAddedPostImageList.length > 0) { + setImages([...images, ...recentlyAddedPostImageList]); + setRecentlyAddedPostImageList([]); + } + }, 2000); + }, [recentlyAddedPostImageList]); + + useEffect(() => { + if (deletedIndex !== null) { + if (deletedIndex + 1 <= images.length) { + setCroppingImage(() => { + return { + image: images[deletedIndex].image, + index: deletedIndex, + }; + }); + } + } + if (images.length === 0 && deletedIndex !== null) { + setdeletedIndex(null); + setStep(1); + } else { + setdeletedIndex(null); + } + }, [deletedIndex]); + + useEffect(() => { + if (dropChangeIndex !== null) { + setCroppingImage({ + image: images[dropChangeIndex].image, + index: dropChangeIndex, + }); + } + setdraggingChangeIndex(null); + setDropChangeIndex(null); + if (croppingImage.index > images.length - 1) { + setCroppingImage({ + image: images[images.length - 1]?.image, + index: images.length - 1, + }); + } + }, [images]); + useEffect(() => { + setImages(images.slice(0, limit)); + }, [recentlyAddedPostImageList]); + const changeIndexDragStart = (e: any, position: number) => { + setisCloseVisible({ isHover: false, index: 0 }); + setIsChangingInsideIndex(true); + if (position !== undefined) { + setdraggingChangeIndex(position); + } + }; + + const changeIndexDragEnter = (e: any, position: number) => { + setIsChangingInsideIndex(true); + setDropChangeIndex(position); + }; + + const changeIndexDrop = () => { + if (draggingChangeIndex !== null && dropChangeIndex != null) { + const copyListItems = [...images]; + const dragItemContent = copyListItems[draggingChangeIndex]; + copyListItems.splice(draggingChangeIndex, 1); + copyListItems.splice(dropChangeIndex, 0, dragItemContent); + + // dragItem.current = null; + // dragOverItem.current = null; + + setImages(copyListItems); + + // if (dropChangeIndex === croppingImage.index) { + // setCroppingImage({ + // image: images[draggingChangeIndex], + // index: draggingChangeIndex, + // }); + // } + } + + setIsChangingInsideIndex(false); + }; + + const showCroppedImage = useCallback( + async (posingImages: { image: ImageInfo; index: number }[]) => { + try { + const croppedImage = await getCroppedImg( + croppingImage.image.src!, + croppingImage.image.croppedPixels!, + 0 + ); + + if (croppedImage !== null) { + setImages(() => { + const newArray = posingImages; + newArray[croppingImage.index].image.croppedImageSrc = croppedImage; + return newArray; + }); + + // add Promise All Heare + const updatedImages: { image: ImageInfo; index: number }[] = + posingImages.map((postImage, index) => { + if (index === croppingImage.index) { + return { + ...postImage, + croppedImageSrc: croppedImage, + zoom: croppingImage.image.zoom, + crop: croppingImage.image.crop, + croppedPixels: croppingImage.image.croppedPixels, + aspectRatio: croppingImage.image.aspectRatio, + }; + } else { + return postImage; + } + }); + setImages(updatedImages); + } + } catch (e) { + console.error(e); + } + }, + [croppingImage.image?.croppedPixels] + ); + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + if (!isChangingInsideIndex) { + setisDraggingNewImage(true); + } + }; + const handleLeave = (event: React.DragEvent) => { + event.preventDefault(); + setisDraggingNewImage(false); + // } + // if (!isChangingInsideIndex) { + // setisDraggingNewImage(true); + // } + }; + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + + setisDraggingNewImage(false); + const files = event.dataTransfer.files; + + if (files) { + setRecentlyAddedPostImageList([]); + // displayImages(Array.from(files)); + DisplayMultipleImages(Array.from(files), setRecentlyAddedPostImageList); + } + }; + + return ( +
+ {/* Dragging Images top layer */} + {isDraggingNewImage && isCrop ? ( +
+ +
+ ) : null} + + {images.length !== 0 && isCrop ? ( +
+
+ {/* zoom Images */} +
+ {iszooming ? ( +
+
+
{ + setiszooming(!iszooming); // setiscrop(false); + setCroppingImage((prev) => { + return { ...prev, isShowGrid: false }; + }); + }} + > + +
+ { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + zoom: newValue as number, + }; + + return { + ...prevState, + image: updatedImage, + }; + }); + }} + aria-label="Small" + valueLabelDisplay="off" + /> +
{ + showCroppedImage(images); + setCroppingImage((prev) => { + return { ...prev, isShowGrid: false }; + }); + setiszooming(false); + }} + > + +
+
+
+ ) : ( +
+ { + setiszooming(!iszooming); // setiscrop(false); + setCroppingImage((prev) => { + return { ...prev, isShowGrid: true }; + }); + }} + > + + +
+ )} +
+ { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + croppedPixels: cropPixel, + }; + return { + ...prevState, + image: updatedImage, + }; + }); + }} + setZoom={(zoom) => { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + zoom: zoom, + }; + + return { + ...prevState, + image: updatedImage, + }; + }); + }} + setCrop={(crop) => { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + crop: crop, + }; + + return { + ...prevState, + image: updatedImage, + }; + }); + }} + /> +
+
+ ) : null} +
+ {isCrop && ( + <> +
+
+

Select Ratio

+

+ All images keep the same ratio. +

+
+
+ <> + {appConstant.aspectRatioList.map((ratio, index) => { + return ( +
{ + const updateRatio = images.map((image, index) => { + return { + ...image, + image: { ...image.image, aspectRatio: ratio }, + }; + }); + setImages(updateRatio); + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + aspectRatio: ratio, + }; + return { + image: updatedImage, + index: prevState.index, + }; + }); + }} + > + {ratio.split("/")[0]}:{ratio.split("/")[1]} +
+ ); + })} + +
+
+
+ + )} +
+ + {images.map((file, index) => { + return ( + + {file && ( +
+ setisCloseVisible({ isHover: true, index: index }) + } + onMouseLeave={() => + setisCloseVisible({ isHover: false, index: index }) + } + draggable + onDragStart={(e) => changeIndexDragStart(e, index)} + onDragEnter={(e) => changeIndexDragEnter(e, index)} + onDragEnd={changeIndexDrop} + className={`flex flex-row w-full aspect-[4/5] overflow-clip justify-center items-center relative border-2 ${ + index === croppingImage.index && " border-primary-main" + } rounded-md border-grey-200`} + > + {isCloseVisible.isHover && + isCloseVisible.index === index ? ( +
{ + setdeletedIndex(index); + setImages( + images.filter( + (image, deleteIndex) => index !== deleteIndex + ) + ); + }} + className={`bg-grey-800 + flex absolute z-10 top-0 right-0 w-5 h-5 justify-center items-center rounded-full m-1 opacity-100 + }`} + > + +
+ ) : null} + + { + showCroppedImage(images); + setCroppingImage({ + image: images[index].image, + index: index, + }); + }} + /> +
+ )} +
+ ); + })} + {recentlyAddedPostImageList.map((images, index) => { + return ( + +
+
+ ); + })} + {images.length < limit && ( + +
+ +
+
+ )} +
+
+ {isNextVisible !== false ? ( +
+ + +
+ } + handleEvent={() => { + setStep(3); + }} + /> +
+ ) : null} +
+ + ); +}; + +export default ModifyImages; diff --git a/components/shared/CropImage/singleCropImage/CropSingleImageDialog.tsx b/components/shared/CropImage/singleCropImage/CropSingleImageDialog.tsx new file mode 100644 index 0000000..a4d31fb --- /dev/null +++ b/components/shared/CropImage/singleCropImage/CropSingleImageDialog.tsx @@ -0,0 +1,196 @@ +import React, { useEffect, useState } from "react"; +import CustomDialog from "../../dialog/CustomDialog"; +import { useAuthContext } from "@/context/AuthContext"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import { theme } from "@/theme"; +import CropLinerIcon from "@/utils/icons/createPost/CropLinerIcon"; +import CheckIcon from "@/utils/icons/shared/CheckIcon"; +import { IconButton, Slider } from "@mui/material"; +import ImageCropZone from "../ImageCropZone"; + +type Props = { + handleEvent?: () => void; + type: string; + cropperAspectRatio?: string; +}; +const CropSingleImageDialog = ({ handleEvent, type }: Props) => { + const { + setCustomDialogType, + + croppingImage, + setCroppingImage, + } = useAuthContext(); + const [iszooming, setiszooming] = useState(false); + const [isCanceled, setisCanceled] = useState(type); + + return ( + <> + +
+ {/* titlebar */} +
+
Crop Image
+ +
{ + setisCanceled(""); + setCroppingImage(defaultImageConstant); + setCustomDialogType(null); + }} + className=" text-common-white p-2 scale-90 rounded-full " + > + +
+
+
+
+
+ {iszooming ? ( +
+
+
{ + setiszooming(!iszooming); // setiscrop(false); + setCroppingImage((prev) => { + return { ...prev, isShowGrid: false }; + }); + }} + > + +
+ { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + zoom: newValue as number, + }; + + return { + ...prevState, + image: updatedImage, + }; + }); + }} + aria-label="Small" + valueLabelDisplay="off" + /> +
{ + setCroppingImage((prev) => { + return { ...prev, isShowGrid: false }; + }); + setiszooming(false); + }} + > + +
+
+
+ ) : ( +
+ { + setiszooming(!iszooming); // setiscrop(false); + setCroppingImage((prev) => { + return { ...prev, isShowGrid: true }; + }); + }} + > + + +
+ )} +
{" "} + { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + croppedPixels: cropPixel, + }; + return { + ...prevState, + image: updatedImage, + }; + }); + }} + setZoom={(zoom) => { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + zoom: zoom, + }; + + return { + ...prevState, + image: updatedImage, + }; + }); + }} + setCrop={(crop) => { + setCroppingImage((prevState) => { + const updatedImage = { + ...prevState.image, + crop: crop, + }; + + return { + ...prevState, + image: updatedImage, + }; + }); + }} + /> +
+
+
+
+ SAVE +
+
+
+
+ + ); +}; + +export default CropSingleImageDialog; diff --git a/components/shared/CropImage/singleCropImage/InputCropSingleImage.tsx b/components/shared/CropImage/singleCropImage/InputCropSingleImage.tsx new file mode 100644 index 0000000..eb09cae --- /dev/null +++ b/components/shared/CropImage/singleCropImage/InputCropSingleImage.tsx @@ -0,0 +1,294 @@ +"use client"; +import React, { + useCallback, + useRef, + useEffect, + forwardRef, + useState, + ChangeEvent, +} from "react"; + +import { ImageInfo, SingleImagePlaceholder } from "@/types"; +import { useAuthContext } from "@/context/AuthContext"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { Box, IconButton } from "@mui/material"; +import ImagePlaceHolderGalleryIcon from "@/utils/icons/createPost/ImagePlaceHolderGalleryIcon"; +import displaySingleImage from "@/service/imageCropper/DisplaySingleImage"; +import getCroppedImg from "@/service/imageCropper/cropImage"; +import CropSingleImageDialog from "./CropSingleImageDialog"; +import Image from "next/image"; +import { CustomImagePreview } from "../../CustomImagePreview"; + +type Props = { + type?: string; + placeholder?: SingleImagePlaceholder; + aspect?: string; + finalImage: { imagePreview: string; file: File } | null; + setFinalImage: React.Dispatch< + React.SetStateAction<{ imagePreview: string; file: File } | null> + >; + // clearError: UseFormClearErrors; +} & Record; + +let filename: string = ""; + +const InputCropSingleImage = forwardRef( + ( + { + aspect, + type, + placeholder, + finalImage, + setFinalImage, + ...restProps + }: Props, + ref + ) => { + const imageInputRef = useRef(null); + const { croppingImage, setCroppingImage, setCustomDialogType } = + useAuthContext(); + const [isDragging, setisDragging] = useState(false); + const [cropDialog, setCropDialog] = useState(false); + + const handleImageSelection = ( + event: React.ChangeEvent + ) => { + // clearError("image"); + + const file = event.target.files?.[0]; + if (file) { + displaySingleImage(file, setCroppingImage); + // setCroppingImage((prev) => { + // return { + // ...prev, + // image: { + // ...prev.image, + // aspectRatio: + // aspect === undefined ? appConstant.defaultaspectRatio : aspect, + // }, + // }; + // }); + + // cropdialog disable until solve the issue how to put dialog + if (type === "MESSAGE" || type === "CREATE") { + setCropDialog(false); + // setCustomDialogType(null); + } else { + // setCustomDialogType("SINGLCROPPINGIMAGE"); + setCropDialog(true); + } + } + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + setisDragging(true); + }; + const handleLeave = (event: React.DragEvent) => { + event.preventDefault(); + setisDragging(false); + }; + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + setisDragging(false); + + const file = event.dataTransfer.files[0]; + displaySingleImage(file, setCroppingImage); + setCroppingImage((prev) => { + return { + ...prev, + image: { + ...prev.image, + aspectRatio: + aspect === undefined ? appConstant.defaultaspectRatio : aspect, + }, + }; + }); + + // cropdialog disable until solve the issue how to put dialog + if (type === "MESSAGE" || type === "CREATE") { + setCropDialog(false); + // setCustomDialogType(null); + } else { + // setCustomDialogType("SINGLCROPPINGIMAGE"); + + setCropDialog(true); + } + }; + + // const handleResetInputValue = (event: React.MouseEvent) => { + // event.target.value = null; + // }; + + const handleImageContainerClick = (e: React.MouseEvent) => { + e.stopPropagation(); + if (imageInputRef.current) { + imageInputRef.current.click(); + } + }; + + const showCroppedImage = useCallback(async () => { + try { + const croppedImage = await getCroppedImg( + croppingImage?.image?.src!, + croppingImage?.image?.croppedPixels, + 0 + ); + + if (croppedImage !== null) { + setCroppingImage((prev) => { + return { + ...prev, + croppedImageSrc: croppedImage, + name: filename, + }; + }); + + if (setFinalImage !== undefined) { + // setFinalImage((prev) => { + // return { + // ...prev, + // image: { + // ...prev.image, + // src: croppingImage.image?.src, + // objectFit: croppingImage.image?.objectFit, + // aspectRatio: croppingImage.image?.aspectRatio, + // zoom: croppingImage.image?.zoom, + // crop: croppingImage.image?.crop, + // croppedPixels: croppingImage.image?.croppedPixels, + // size: croppingImage.image?.size, + // croppedImageSrc: croppedImage, + // name: filename, + // }, + // }; + // }); + } + } + // setCustomDialogType(null); + + setCropDialog(false); + } catch (e) { + console.error(e); + } + }, [croppingImage?.image?.croppedPixels]); + + useEffect(() => { + setCroppingImage((prev) => { + return { + ...prev, + aspectRatio: + aspect === undefined ? appConstant.defaultaspectRatio : aspect, + }; + }); + }, []); + + const onImageChange = (event: ChangeEvent) => { + if (event.target.files && event.target.files[0]) { + let reader = new FileReader(); + let file = event.target.files[0]; + reader.onloadend = () => { + setFinalImage({ + // ...mydata, + imagePreview: reader.result as string, + file: file, + }); + }; + reader.readAsDataURL(file); + } + }; + + return ( + + + {finalImage?.imagePreview ? ( +
{ + // setCroppingImage(finalImage); + // setCropDialog(true); + // setCustomDialogType("SINGLCROPPINGIMAGE"); + }} + > + {/* {isDragging ? ( +
+
+ {placeholder?.placeholderImg} + {placeholder?.placeholderTitle} +
+
+ ) : null} */} +
+ +
+ {!isDragging ? ( + + + + ) : null} +
+ ) : ( + <> + {type === "PROFILEIMG" || + type === "CREATEOFFER" || + type === "UPLOADID" || + type === "MESSAGE" || + type === "AIVERIFICATION" || + type === "CREATE" ? ( +
+
+ {placeholder?.placeholderImg} + {placeholder?.placeholderTitle} +
+
+ ) : null} + + )} + {cropDialog === true ? ( + { + showCroppedImage(); + }} + /> + ) : null} +
+ ); + } +); + +InputCropSingleImage.displayName = "image"; + +export default InputCropSingleImage; diff --git a/components/shared/CustomAccordion.tsx b/components/shared/CustomAccordion.tsx new file mode 100644 index 0000000..425dc59 --- /dev/null +++ b/components/shared/CustomAccordion.tsx @@ -0,0 +1,49 @@ +import React, { useState } from "react"; +import AccordionSummary from "@mui/material/AccordionSummary"; +import AccordionDetails from "@mui/material/AccordionDetails"; +import Typography from "@mui/material/Typography"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import Fade from "@mui/material/Fade"; +import Accordion from "@mui/material/Accordion"; +import { theme } from "@/theme"; + +type Props = { + name: string; + element?: React.ReactElement; +}; +const CustomAccordion = ({ name, element }: Props) => { + const [expanded, setExpanded] = useState(false); + + return ( +
+ + } + > + {name} + + + + +
{element}
+
+
+
+
+ ); +}; + +export default CustomAccordion; diff --git a/components/shared/CustomButton.tsx b/components/shared/CustomButton.tsx new file mode 100644 index 0000000..7988ba3 --- /dev/null +++ b/components/shared/CustomButton.tsx @@ -0,0 +1,52 @@ +import { theme } from "@/theme"; +import { Button, IconButton, SvgIconTypeMap } from "@mui/material"; +import { OverridableComponent } from "@mui/material/OverridableComponent"; + +type Props = { + type?: "button" | "reset" | "submit"; + name?: string; + handleEvent?: () => void; + startIcon?: React.ReactElement | null; + endIcon?: React.ReactElement; +} & Record; + +const CustomButton = (props: Props) => { + const { type, name, handleEvent, startIcon, endIcon, ...restProps } = props; + return ( + + ); +}; + +export default CustomButton; diff --git a/components/shared/CustomCheckbox.tsx b/components/shared/CustomCheckbox.tsx new file mode 100644 index 0000000..006c6a1 --- /dev/null +++ b/components/shared/CustomCheckbox.tsx @@ -0,0 +1,41 @@ +import { Checkbox } from "@mui/material"; +import CheckBoxFillCheckedIcon from "@/utils/icons/shared/CheckBoxFillCheckedIcon"; +import CheckBoxEmptyIcon from "@/utils/icons/shared/CheckBoxEmptyIcon"; + +type Props = { + labelText?: string; + uncheckedColor?: string; + checkedColor?: string; + checkedIcon?: JSX.Element; + icon?: JSX.Element; +} & Record; + +const CustomCheckbox = ({ + labelText, + uncheckedColor, + checkedColor, + checkedIcon, + icon, + ...rest +}: Props) => { + return ( + <> + + {icon ? icon : } + + } + checkedIcon={ + + {checkedIcon ? checkedIcon : } + + } + {...rest} + /> + + ); +}; + +export default CustomCheckbox; diff --git a/components/shared/CustomEditPostDialog/index.tsx b/components/shared/CustomEditPostDialog/index.tsx new file mode 100644 index 0000000..c572fa0 --- /dev/null +++ b/components/shared/CustomEditPostDialog/index.tsx @@ -0,0 +1,193 @@ +import React, { useEffect, useState } from "react"; + +import { useAuthContext } from "@/context/AuthContext"; +import { Post } from "@/types/post"; +import { Controller, DefaultValues } from "react-hook-form"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; + +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import { Grid } from "@mui/material"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; + +import { updatePost } from "@/api/post/updatePost"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import CustomDialogCommonTopBar from "@/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +import { useRouter } from "next/router"; +import { updateUserPost } from "@/redux/slices/userPostSlice"; +import { updateDiscoverPost } from "@/redux/slices/discoverFeedSlice"; +import { updateSimilarDiscoverPost } from "@/redux/slices/discoverSimilarFeedSlice"; +import { updateCirclePost } from "@/redux/slices/circleFeedSlice"; + +type Props = { + editedValue?: Post | null; + isOpenEditPost: boolean; + setIsOpenEditPost: React.Dispatch>; + +}; + +const EditPostDialog = ({ + editedValue, + isOpenEditPost, + setIsOpenEditPost, +}: Props) => { + const [isLoading, setIsloading] = useState(false); + const [getCategory, setGetCategory] = useState([]); + const [caption, setCaption] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + const { setCustomDialogType, sendNotification } = useAuthContext(); + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + const styles = { + responsiveGrid: { + xxl: 4, + xl: 4, + // lg: 5, + md: 4, + sm: 8, + xs: 12, + }, + }; + useEffect(() => { + if ( + editedValue && + editedValue.category && + editedValue.category.length >= 1 + ) { + setGetCategory(editedValue.category); + + return; + } + }, []); + useEffect(() => { + if (editedValue?.caption) { + setCaption(editedValue.caption); + } + }, []); + const handleCategory = (item: string) => { + if (!getCategory.includes(item)) { + setGetCategory([...getCategory, item]); + } else { + setGetCategory((preValue) => { + return preValue.filter((value) => value !== item); + }); + } + }; + + const fetchData = async () => { + if (!editedValue) { + return; + } + setIsloading(true); + const data = { + postId: editedValue.postId, + category: getCategory, + caption:caption?? null, + }; + const response = await updatePost({ user_id: user?.userId, data }); + if (response.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Post updated Successfuly", + }); + setIsloading(false); + dispatch(updateSimilarDiscoverPost(data)); + dispatch(updateCirclePost(data)); + dispatch(updateUserPost(data)); + setIsOpenEditPost(false); + return; + } + setIsloading(false); + sendNotification({ type: "ERROR", message: response.error }); + }; + + return ( + { + setIsOpenEditPost(false); + }} + > + { + setIsOpenEditPost(false); + }} + title="Edit Post" + /> +
+
+ ) => { + setCaption(event.target.value); + }} + /> +
+
+
+ Category +
+ +
+ + {CategoryList.map((category, index) => { + return ( + +
item === category.name) + ? "bg-primary-main text-common-white" + : "text-grey-200 bg-grey-800" + } + `} + onClick={() => { + setErrorMessage(""); + handleCategory(category.name); + }} + > +

+ {category.startIcon} +

+

+ {category.name} +

+
+
+ ); + })} +
+
+
+
+

{errorMessage}

+ { + if (getCategory.length < 1) { + setErrorMessage("Please Select Category"); + return; + } + fetchData(); + setCustomDialogType(null); + }} + /> +
+
+
+ ); +}; + +export default EditPostDialog; diff --git a/components/shared/CustomEditPostFromGenetation/GenerationPostCategory.tsx b/components/shared/CustomEditPostFromGenetation/GenerationPostCategory.tsx new file mode 100644 index 0000000..552da0c --- /dev/null +++ b/components/shared/CustomEditPostFromGenetation/GenerationPostCategory.tsx @@ -0,0 +1,131 @@ +import { Grid } from "@mui/material"; +import React, { ChangeEvent, useEffect, useState } from "react"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { OwnerPost } from "@/types/post"; + +type Props = { + setStep: React.Dispatch>; + + handleSave: (data: Partial) => Promise; + defaultValues: Partial | undefined; + isLoading: boolean; + + setDefaultValues: React.Dispatch< + React.SetStateAction | undefined> + >; +}; +const styles = { + responsiveGrid: { + xxl: 4, + xl: 4, + // lg: 5, + md: 4, + sm: 8, + xs: 12, + }, +}; +const GenerationPostCategory = ({ + setDefaultValues, + isLoading, + defaultValues, + handleSave, +}: Props) => { + const [getCategory, setGetCategory] = useState([]); + const [errorMessage, setErrorMessage] = useState(""); + const handleCategory = (item: string, id: number) => { + if (!getCategory.includes(item)) { + setGetCategory([...getCategory, item]); + } else { + setGetCategory((preValue) => { + return preValue.filter((value) => value !== item); + }); + } + }; + + useEffect(() => { + if ( + defaultValues && + defaultValues.category && + defaultValues.category.length >= 1 + ) { + setGetCategory(defaultValues.category); + + return; + } + }, []); + useEffect(() => { + setDefaultValues({ ...defaultValues, category: getCategory as string[] }); + setErrorMessage(""); + }, [getCategory]); + + return ( +
+
+ ) => { + setDefaultValues({ + ...defaultValues, + caption: e.target.value, + }); + }} + placeholder="Write Caption" + tag="Caption" + multiline + rows={3} + /> +
+
+ Category +
+ + {CategoryList.map((category, index) => { + return ( + +
item === category.name) + ? "bg-primary-main text-common-white" + : "text-grey-200 bg-grey-800" + } + `} + onClick={() => { + handleCategory(category.name, index); + }} + > +

{category.startIcon}

+

+ {category.name} +

+
+
+ ); + })} +
+
+

{errorMessage}

+ { + if (defaultValues?.category && defaultValues.category!.length < 1) { + setErrorMessage("Please Select Category"); + return; + } + if (defaultValues) { + handleSave(defaultValues); + return; + } + }} + /> +
+
+ ); +}; + +export default GenerationPostCategory; diff --git a/components/shared/CustomEditPostFromGenetation/index.tsx b/components/shared/CustomEditPostFromGenetation/index.tsx new file mode 100644 index 0000000..6ede6ab --- /dev/null +++ b/components/shared/CustomEditPostFromGenetation/index.tsx @@ -0,0 +1,272 @@ +import React, { ChangeEvent, useEffect, useState } from "react"; +import { useAuthContext } from "@/context/AuthContext"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import GenerationPostCategory from "./GenerationPostCategory"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import CustomDialogCommonTopBar from "@/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +import CustomToggleSwitch from "@/components/shared/CustomToggleSwitch"; +import CustomButton from "@/components/shared/CustomButton"; +import { OwnerPost, Post } from "@/types/post"; +import { getOwnerPost } from "@/api/post/getOwnerPost"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import { updatePost } from "@/api/post/updatePost"; +import EditIcon from "@/utils/icons/shared/EditIcon"; +import RightThikArrowButton from "@/utils/icons/shared/RightThikArrowButton"; +import { updateSimilarDiscoverPost } from "@/redux/slices/discoverSimilarFeedSlice"; +import { updateCirclePost } from "@/redux/slices/circleFeedSlice"; +import { updateUserPost } from "@/redux/slices/userPostSlice"; + +type Props = { + editedValue: Post; + isOpenEditPost: boolean; + setIsOpenEditPost: React.Dispatch>; +}; + +const EditGenerationPostPrompt = ({ + editedValue, + isOpenEditPost, + setIsOpenEditPost, +}: Props) => { + const [isAllow, setIsAllow] = useState(false); + const [step, setStep] = useState(0); + const [isLoading, setIsLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + const [generationPostData, setGenerationPostData] = + useState(null); + const [defaultValues, setDefaultValues] = useState>(); + + const { sendNotification, setCustomDialogType, customDialogType } = + useAuthContext(); + const user = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + const fetchData = async () => { + if (!user) { + return; + } + const response = await getOwnerPost({ + user_id: user.userId, + postId: editedValue.postId, + }); + if (response.status === 200 && response.data) { + setGenerationPostData(response.data); + setIsAllow(response.data?.promptDetails.allowPromptView); + setDefaultValues({ + caption: response.data.caption ?? null, + category: editedValue.category ?? [], + prompt: response.data?.promptDetails.prompt ?? null, + image: response.data?.image, + generatedFrom: { + postId: null, + modelId: response.data?.generatedFrom?.modelId!, + }, + promptDetails: { + creditPerPromptView: response.data?.promptDetails.creditPerPromptView, + allowPromptView: + response.data?.promptDetails.allowPromptView ?? false, + }, + }); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + useEffect(() => { + fetchData(); + }, []); + + useEffect(() => { + if (!isAllow) { + setDefaultValues({ + ...defaultValues, + promptDetails: { + ...defaultValues?.promptDetails, + creditPerPromptView: 0, + }, + }); + return; + } + }, [isAllow]); + + const handleSave = async (values: Partial) => { + const data = { + caption: values.caption as string | null, + category: values.category as string[], + postId: editedValue.postId, + promptDetails: values.promptDetails, + }; + setIsLoading(true); + const response = await updatePost({ + data, + user_id: user?.userId, + }); + if (response.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Data Updated Successfully", + }); + dispatch(updateSimilarDiscoverPost(data)); + dispatch(updateCirclePost(data)); + dispatch(updateUserPost(data)); + setIsLoading(false); + setIsOpenEditPost(false); + setCustomDialogType(null); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + setIsLoading(false); + }; + + if (!generationPostData) { + return <>; + } + return ( + { + setIsOpenEditPost(false); + setStep(0); + }} + className="w-full max-h-[610px] flex flex-col justify-start items-center" + > + { + setIsOpenEditPost(false); + setStep(0); + }} + startIcon={ + step === 0 ? ( +
+ +
+ ) : ( +
{ + if (step > 0) { + setStep(0); + } + }} + > + +
+ ) + } + title="Edit Generation Post" + /> +
+ {step === 0 && ( +
+
+
+ {generationPostData?.image && ( + + )} +
+
+ +
+
+

Prompts for the generation

+
+

+ {defaultValues?.prompt} +

+
+ +
+
+ Allow Others to see your prompt +
+ + ) => { + setIsAllow(e.target.checked); + setDefaultValues({ + ...defaultValues, + promptDetails: { + ...defaultValues?.promptDetails, + allowPromptView: e.target.checked, + }, + }); + }} + /> +
+ {defaultValues?.promptDetails?.allowPromptView && ( +
+
+
+ Cost to Revel Prompt +
+

+ You will receive this credit when you create a post in + witit and someone wants to view the prompt of that post. +

+

+ {errorMessage} +

+
+ + = 1 + ? defaultValues?.promptDetails?.creditPerPromptView + : "" + } + type="number" + onChange={(e) => { + setDefaultValues({ + ...defaultValues, + promptDetails: { + ...defaultValues?.promptDetails, + creditPerPromptView: +e.target.value, + }, + }); + }} + placeholder="0" + className="w-[70px] p-2 text-center border rounded-lg focus:outline-none border-grey-600 bg-grey-800 py-2" + /> +
+ )} +
+ +
+ } + className="w-fit text-base font-semibold px-20 py-3" + handleEvent={() => { + if ( + defaultValues?.promptDetails?.allowPromptView && + defaultValues?.promptDetails?.creditPerPromptView! <= 0 + ) { + setErrorMessage( + "Cost per View Prompt must be greater than 0" + ); + return; + } + setErrorMessage(""); + setStep(1); + }} + /> +
+
+
+ )} + {step === 1 && ( + + )} + +
+ ); +}; + +export default EditGenerationPostPrompt; diff --git a/components/shared/CustomImagePreview.tsx b/components/shared/CustomImagePreview.tsx new file mode 100644 index 0000000..d199418 --- /dev/null +++ b/components/shared/CustomImagePreview.tsx @@ -0,0 +1,41 @@ +import Image, { StaticImageData } from "next/image"; +import { useEffect, useState } from "react"; +import { Blurhash } from "react-blurhash"; + +type Props = { + image: string | StaticImageData; + className?: string; + blurhash?: string; +}; + +export const CustomImagePreview = ({ image, blurhash, className }: Props) => { + const [isImgLoad, setIsImgLoad] = useState(false); + + useEffect(() => { + if (isImgLoad) { + setIsImgLoad(false); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [image]); + + return ( + <> + {blurhash && ( +
+ +
+ )} + setIsImgLoad(true)} + fill + priority={true} + src={image} + alt="" + className={`${ + isImgLoad ? "opacity-1" : "opacity-0" + } transition-all duration-500 pointer-events-none z-1 ${className}`} + quality={20} + /> + + ); +}; diff --git a/components/shared/CustomInputTag.tsx b/components/shared/CustomInputTag.tsx new file mode 100644 index 0000000..0568041 --- /dev/null +++ b/components/shared/CustomInputTag.tsx @@ -0,0 +1,72 @@ +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import EnterIcon from "@/utils/icons/shared/EnterIcon"; +import { IconButton } from "@mui/material"; +import { useState, ChangeEvent, KeyboardEvent, useRef, useEffect } from "react"; + +type Props = { + words: string[]; + setWords: (words: string[]) => void; +}; + +const CustomInputTag = ({ words, setWords }: Props) => { + const inputRef = useRef(null); + const [inputValue, setInputValue] = useState(""); + + const removeTag = (i: number) => { + const newTags = [...words]; + newTags.splice(i, 1); + setWords(newTags); + }; + + const handleInputChange = (event: ChangeEvent) => { + const value = event.target.value; + setInputValue(value); + }; + + const handleInputKeyDown = (event: KeyboardEvent) => { + const newVal = inputValue.trim(); + if (event.key === "Enter" && newVal) { + setWords([...words.filter((txt) => txt !== newVal), newVal]); + setInputValue(""); + } + }; + + return ( +
+
    + {words.map((tag, index) => ( +
  • +

    {tag}

    + { + removeTag(index); + }} + > + + +
  • + ))} +
  • + +
    + +
    +
  • +
+
+ ); +}; + +export default CustomInputTag; diff --git a/components/shared/CustomInputTextField.tsx b/components/shared/CustomInputTextField.tsx new file mode 100644 index 0000000..1f27763 --- /dev/null +++ b/components/shared/CustomInputTextField.tsx @@ -0,0 +1,134 @@ +import { theme } from "@/theme"; +import { + Box, + FormHelperText, + Icon, + InputBase, + InputBaseProps, + Stack, +} from "@mui/material"; +import { forwardRef } from "react"; +type Props = { + type?: "button" | "reset" | "submit"; + name?: string; + tag?: string; + tagStyle?: string; + startIcon?: React.ReactElement; + StartIconHandleEvent?: () => void; + StartIconStyle: string; + endIcon?: React.ReactElement; + EndIconHandleEvent?: () => void; + EndIconStyle: string; + error: string; + className?: string; + inputFieldClass?: string; +} & Record; + +const CustomInputTextField = forwardRef((props: Props, ref) => { + const { + name, + type, + StartIcon, + StartIconStyle, + StartIconHandleEvent, + EndIcon, + EndIconStyle, + EndIconHandleEvent, + tag, + tagStyle, + error, + className, + inputFieldClass, + ...restProps + } = props; + + return ( +
+ {tag && ( + +
{tag}
+
+ )} + + {StartIcon && ( + + {StartIcon} + + )} + + {EndIcon && ( + + {EndIcon} + + )} + + {error && ( + + {error} + + )} +
+ ); +}); + +CustomInputTextField.displayName = "CustomInputTextField"; + +export default CustomInputTextField; diff --git a/components/shared/CustomInsufficientCredit.tsx b/components/shared/CustomInsufficientCredit.tsx new file mode 100644 index 0000000..1672051 --- /dev/null +++ b/components/shared/CustomInsufficientCredit.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import CustomButton from "./CustomButton"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; + +type Props = { + onCancel: () => void; + handleEvent: () => void; +}; +const CustomInsufficientCredit = ({ onCancel, handleEvent }: Props) => { + return ( + <> +
+
+

+ Insufficient Credit Balance +

+

+ Oops!! You have insufficient credit balance. You can continue this + step by adding credits.{" "} +

+
+
+ +
+ +
+
+
+ + ); +}; + +export default CustomInsufficientCredit; diff --git a/components/shared/CustomLink.tsx b/components/shared/CustomLink.tsx new file mode 100644 index 0000000..d3e6511 --- /dev/null +++ b/components/shared/CustomLink.tsx @@ -0,0 +1,21 @@ +import Link from "next/link"; + +type Props = { + name: string; + redirectTo: string; + style?: string; +} & Record; + +const CustomLink = ({ name, redirectTo, style, ...restProps }: Props) => { + return ( + + {name} + + ); +}; + +export default CustomLink; diff --git a/components/shared/CustomLoadingButton.tsx b/components/shared/CustomLoadingButton.tsx new file mode 100644 index 0000000..0ec6de1 --- /dev/null +++ b/components/shared/CustomLoadingButton.tsx @@ -0,0 +1,56 @@ +import { theme } from "@/theme"; +import { LoadingButton } from "@mui/lab"; +import { Button, IconButton, SvgIconTypeMap } from "@mui/material"; +import { OverridableComponent } from "@mui/material/OverridableComponent"; + +type Props = { + type?: "button" | "reset" | "submit"; + name?: string; + handleEvent?: () => void; + startIcon?: React.ReactElement; + endIcon?: React.ReactElement; +} & Record; + +const CustomLoadingButton = (props: Props) => { + const { type, name, handleEvent, startIcon, endIcon, ...restProps } = props; + return ( + + {name} + + ); +}; + +export default CustomLoadingButton; diff --git a/components/shared/CustomSlider.tsx b/components/shared/CustomSlider.tsx new file mode 100644 index 0000000..e039de1 --- /dev/null +++ b/components/shared/CustomSlider.tsx @@ -0,0 +1,59 @@ +import { theme } from "@/theme"; +import styled from "@emotion/styled"; +import { Slider } from "@mui/material"; + +export const CustomSlider = styled(Slider)({ + color: theme.palette.primary.main, + height: 10, + "& .MuiSlider-track": { + border: "none", + }, + "& .MuiSlider-rail": { + background: theme.palette.grey[700], + opacity: 1, + }, + "& .MuiSlider-thumb": { + height: 20, + width: 10, + backgroundColor: theme.palette.common.white, + borderRadius: 2, + "&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": { + boxShadow: "inherit", + }, + "&:before": { + display: "none", + }, + }, + "& .MuiSlider-valueLabel": { + borderRadius: 6, + backgroundColor: theme.palette.primary.main, + minWidth: 50, + }, +}); +// const PrettoSlider = styled(Slider)({ +// color: theme.palette.primary.main, +// height: 10, +// "& .MuiSlider-track": { +// border: "none", +// }, +// "& .MuiSlider-rail": { +// background: theme.palette.grey[700], +// opacity: 1, +// }, +// "& .MuiSlider-thumb": { +// height: 16, +// width: 20, +// backgroundColor: theme.palette.common.white, +// borderRadius: 4, +// "&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": { +// boxShadow: "inherit", +// }, +// "&:before": { +// display: "none", +// }, +// }, +// "& .MuiSlider-valueLabel": { +// borderRadius: "25% 25% 25% 25%", +// backgroundColor: theme.palette.primary.main, +// }, +// }); diff --git a/components/shared/CustomToggleSwitch.tsx b/components/shared/CustomToggleSwitch.tsx new file mode 100644 index 0000000..af4d193 --- /dev/null +++ b/components/shared/CustomToggleSwitch.tsx @@ -0,0 +1,196 @@ +import { styled } from "@mui/material/styles"; +import Switch, { SwitchProps } from "@mui/material/Switch"; +import { forwardRef } from "react"; + +type Props = { + handleToggle?: any; + isChecked: boolean; + startIcon?: JSX.Element; + endIcon?: JSX.Element; + startNumber?: number; + endNumber?: number; +} & Record; + +const ToggleSwitchStyle = styled((props: SwitchProps) => ( + +))(({ theme }) => ({ + width: 50, + height: 28, + padding: 0, + display: "flex", + "&:active": { + "& .MuiSwitch-thumb": { + width: 18, + }, + "& .MuiSwitch-switchBase.Mui-checked": { + transform: "translateX(20px)", + }, + }, + "& .MuiSwitch-switchBase": { + color: theme.palette.grey[100], + + padding: "4px", + "&.Mui-checked": { + transform: "translateX(22px)", + color: theme.palette.common.white, + "& + .MuiSwitch-track": { + opacity: 1, + backgroundColor: theme.palette.primary.main, + }, + }, + }, + "& .MuiSwitch-thumb": { + boxShadow: "0 2px 4px 0 rgb(0 35 11 / 20%)", + width: 20, + height: 20, + borderRadius: 12, + transition: { + duration: 200, + }, + }, + "& .MuiSwitch-track": { + borderRadius: 14, + opacity: 1, + backgroundColor: theme.palette.grey[500], + boxSizing: "border-box", + }, +})); + +const IconSwitch = styled(Switch)(({ theme }) => ({ + width: 56, + height: 34, + padding: 0, + alignItems: "center", + "& .MuiSwitch-switchBase": { + margin: 1, + padding: 0, + transform: "translateX(2px)", + "&.Mui-checked": { + color: theme.palette.common.white, + transform: "translateX(24px)", + "& + .MuiSwitch-track": { + opacity: 1, + backgroundColor: theme.palette.primary.main, + }, + }, + }, + "& .MuiSwitch-thumb": { + backgroundColor: theme.palette.mode === "dark" ? "#003892" : "#001e3c", + width: 26, + height: 26, + }, + "& .MuiSwitch-track": { + opacity: 1, + backgroundColor: "#3C3D3F", + borderRadius: 40 / 2, + }, +})); + +const TextSwitch = styled(Switch)(({ theme }) => ({ + width: 72, + height: 34, + padding: 0, + alignItems: "center", + "& .MuiSwitch-switchBase": { + margin: 1, + padding: 0, + transform: "translateX(0px)", + "&.Mui-checked": { + color: theme.palette.common.white, + transform: "translateX(34px)", + "& + .MuiSwitch-track": { + opacity: 1, + backgroundColor: theme.palette.grey[700], + }, + }, + }, + "& .MuiSwitch-thumb": { + backgroundColor: theme.palette.primary.main, + width: 26, + height: 26, + }, + "& .MuiSwitch-track": { + opacity: 1, + backgroundColor: theme.palette.grey[700], + borderRadius: 40 / 2, + "&:after, &:before": { + color: "white", + fontSize: "12px", + position: "absolute", + top: "8px", + }, + "&:after": { + content: "'4'", + left: "14px", + }, + "&:before": { + content: "'8'", + right: "14px", + }, + }, +})); + +const CustomToggleSwitch = forwardRef((props: Props, ref) => { + const { + isChecked, + handleToggle, + startIcon, + endIcon, + startNumber, + endNumber, + ...restProps + } = props; + + if (startIcon) { + return ( + + {startIcon} + + } + checkedIcon={ +
+ {endIcon ?? startIcon} +
+ } + {...restProps} + /> + ); + } + + if (startNumber) { + return ( + + 4 + + } + checkedIcon={ +
+ {endNumber ?? startNumber} +
+ } + {...restProps} + /> + ); + } + + return ( + + ); +}); + +CustomToggleSwitch.displayName = "CustomToggleSwitch"; + +export default CustomToggleSwitch; diff --git a/components/shared/CustomTooltip.tsx b/components/shared/CustomTooltip.tsx new file mode 100644 index 0000000..7551921 --- /dev/null +++ b/components/shared/CustomTooltip.tsx @@ -0,0 +1,48 @@ +import { theme } from "@/theme"; +import { Tooltip } from "@mui/material"; +import { ReactElement, ReactNode } from "react"; + +type Props = { + children: ReactElement; + title: string; + placement?: + | "bottom-end" + | "bottom-start" + | "bottom" + | "left-end" + | "left-start" + | "left" + | "right-end" + | "right-start" + | "right" + | "top-end" + | "top-start" + | "top"; +}; + +export const CustomTooltip = ({ children, title, placement }: Props) => { + return ( + + {children} + + ); +}; diff --git a/components/shared/Loader.tsx b/components/shared/Loader.tsx new file mode 100644 index 0000000..739f7bc --- /dev/null +++ b/components/shared/Loader.tsx @@ -0,0 +1,39 @@ +import { Typography } from "@mui/material"; +import Backdrop from "@mui/material/Backdrop"; +import CircularProgress from "@mui/material/CircularProgress"; + +type Props = { + loading: boolean; +}; + +const Loader = ({ loading }: Props) => { + return ( + +
+
+ + +
+ + {/* + Redirecting... + */} +
+
+ ); +}; + +export default Loader; diff --git a/components/shared/LoginTag.tsx b/components/shared/LoginTag.tsx new file mode 100644 index 0000000..e479df3 --- /dev/null +++ b/components/shared/LoginTag.tsx @@ -0,0 +1,32 @@ +import { Box, Button, IconButton, SvgIconTypeMap } from "@mui/material"; +import { OverridableComponent } from "@mui/material/OverridableComponent"; + +type Props = { + title?: string; + desc?: string; + progress?: any; + desWidth?: any; + isLineRequired?: boolean; +} & Record; + +const LoginTag = (props: Props) => { + const { title, desc, progress, desWidth, isLineRequired, ...restProps } = + props; + return ( + <> +
+ {isLineRequired &&
} +

+ {title} +

+

+ {desc} +

+
+ + ); +}; + +export default LoginTag; diff --git a/components/shared/Loginterms.tsx b/components/shared/Loginterms.tsx new file mode 100644 index 0000000..af5a9c1 --- /dev/null +++ b/components/shared/Loginterms.tsx @@ -0,0 +1,59 @@ +import { useAuthContext } from "@/context/AuthContext"; +import { useRouter } from "next/router"; + +interface Props { + style?: any; + page?: any; +} +const Loginterms = ({ style, page }: any) => { + const { setCustomDialogType } = useAuthContext(); + return page === "LOGIN" ? ( +
+
+ © 2023 Witit Media Inc. All rights reserved. +
+
+
setCustomDialogType("PRIVACYPOLICY")} + > + Privacy Policy +
+

|

+
setCustomDialogType("TERMSOFSERVICE")} + > + Terms and condition +
+
+
+ ) : ( +
+
+ © 2023 Witit Media Inc. All rights reserved. +
+
+
setCustomDialogType("PRIVACYPOLICY")} + > + Privacy Policy +
+

|

+
setCustomDialogType("TERMSOFSERVICE")} + > + Terms and condition +
+
+
+ ); +}; + +export default Loginterms; diff --git a/components/shared/MainLogo.tsx b/components/shared/MainLogo.tsx new file mode 100644 index 0000000..4eeb8bd --- /dev/null +++ b/components/shared/MainLogo.tsx @@ -0,0 +1,27 @@ +import Image from "next/image"; +import companyLogo from "@/utils/images/witit.svg"; +import { CustomImagePreview } from "./CustomImagePreview"; +import { wititImage } from "@/utils/images"; + +interface Props { + withBottomText?: boolean; + style?: any; + onClick: () => void; +} + +const MainLogo = ({ withBottomText, style, onClick }: Props) => { + return ( +
+
+ +
+ {withBottomText && ( +

+ go get it +

+ )} +
+ ); +}; + +export default MainLogo; diff --git a/components/shared/MobileScreen.tsx b/components/shared/MobileScreen.tsx new file mode 100644 index 0000000..0462b9f --- /dev/null +++ b/components/shared/MobileScreen.tsx @@ -0,0 +1,30 @@ +import TriangleAlertIcon from "@/utils/icons/shared/TriangleAlertIcon"; +import React from "react"; + +const MobileScreen = () => { + return ( +
+
+
+
+ +
+
+

Go to the App

+

+ This link is supported only for large screen. you can operate it on + large screen or use the
+ + witit app + +

+
+
+ ); +}; + +export default MobileScreen; diff --git a/components/shared/Navbar/components/NavLink.tsx b/components/shared/Navbar/components/NavLink.tsx new file mode 100644 index 0000000..e132a35 --- /dev/null +++ b/components/shared/Navbar/components/NavLink.tsx @@ -0,0 +1,205 @@ +import { ListItemText, Stack } from "@mui/material"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { useAuthContext } from "@/context/AuthContext"; +import { theme } from "@/theme"; +import { useEffect, useState } from "react"; + +type Props = { + name: string; + link: string | null; + startIcon: React.ReactElement; + isSmallScreen: boolean; +} & Record; + +type GetListStyleProps = { isSmallScreen: boolean; isActive: boolean }; + +const getListStyle = ({ isSmallScreen, isActive }: GetListStyleProps) => { + return { + p: 1.25, + gap: 1.25, + alignItems: "center", + ...(isSmallScreen && { justifyContent: "center" }), + borderRadius: 2, + "&>*:nth-of-type(1)": { + "&>*": { + color: isActive ? theme.palette.common.white : theme.palette.grey[200], + }, + }, + ...(isActive && { background: theme.palette.grey[700] }), + ":hover": { + backgroundColor: isActive + ? theme.palette.grey[700] + : theme.palette.grey[700], + }, + }; +}; +const getListStyleNoPage = ({ isSmallScreen, isActive }: GetListStyleProps) => { + return { + p: 1.25, + gap: 1.25, + alignItems: "center", + ...(isSmallScreen && { justifyContent: "center" }), + borderRadius: 2, + "&>*:nth-of-type(1)": { + "&>*": { + color: isActive ? theme.palette.common.white : theme.palette.grey[200], + }, + }, + ...(isActive && { background: theme.palette.grey[700] }), + ":hover": { + backgroundColor: isActive + ? theme.palette.grey[700] + : theme.palette.grey[700], + }, + }; +}; + +export const NavLink = ({ + name, + link, + startIcon, + isSmallScreen, + ...restProps +}: Props) => { + const router = useRouter(); + const { asPath } = useRouter(); + const { + customDrawerType, + setCustomDrawerType, + setCustomDialogType, + customDialogType, + setGenerationPost, + } = useAuthContext(); + + // useEffect(() => { + // // This runs after the component has mounted + // if (router.isReady) { + // const userIdFromRouter = router.query.user as string; + // setUserId(userIdFromRouter); + // } + // }, [router.isReady, asPath]); + return ( +
+ {/* {name === + customDrawerType + ?.toLowerCase() + .replace(/\b\w/g, (s) => s.toUpperCase()) || + name === + customDialogType + ?.toLowerCase() + .replace(/\b\w/g, (s) => s.toUpperCase()) ? ( + ) : router.pathname.split("/")[1].toUpperCase() === activeTab && + (name !== + customDrawerType + ?.toLowerCase() + .replace(/\b\w/g, (s) => s.toUpperCase()) || + name !== + customDialogType + ?.toLowerCase() + .replace(/\b\w/g, (s) => s.toUpperCase())) ? ( +
+ ) : null} */} + {/* {name.toUpperCase() != customDrawerType && customDrawerType !== null ? ( */} + {(name.toLowerCase() === customDrawerType?.toLowerCase() || + name.toLowerCase() === customDialogType?.toLowerCase()) && + link === null ? ( +
+ ) : null} + + {} + {(router.query.user as string) ? ( + false + ) : customDrawerType === null && + customDialogType === null && + link && + router.pathname.includes(link) ? ( +
+ ) : null} + + <> + {link ? ( + { + // setCustomDialogType(null); + // setCustomDrawerType(null); + }} + > + + {startIcon} + {isSmallScreen ? null : ( + + )} + + + ) : ( + { + setGenerationPost(null); + if (name.toUpperCase() === "POST") { + setCustomDialogType((prev) => { + if (prev === null || prev === name.toUpperCase()) { + if (prev === null) { + return name.toUpperCase(); + } else { + return null; + } + } + return name.toUpperCase(); + }); + setCustomDrawerType(null); + } else { + setCustomDialogType(null); + setCustomDrawerType((prev) => { + if (prev === null || prev === name.toUpperCase()) { + if (prev === null) { + return name.toUpperCase(); + } else { + return null; + } + } + return name.toUpperCase(); + }); + } + }} + > + s.toUpperCase()) || + name === + customDialogType + ?.toLowerCase() + .replace(/\b\w/g, (s) => s.toUpperCase()), + })} + > + {startIcon} + {isSmallScreen ? null : ( + + )} + + + )} + + {/* ) : null} */} +
+ ); +}; diff --git a/components/shared/Navbar/index.tsx b/components/shared/Navbar/index.tsx new file mode 100644 index 0000000..fb3ad08 --- /dev/null +++ b/components/shared/Navbar/index.tsx @@ -0,0 +1,208 @@ +import { Box, Drawer, useMediaQuery } from "@mui/material"; +import VerifyAccountBg from "@/utils/images/verifyAccountBg.png"; +import VerificationIcon from "@/utils/icons/circle/VerifiedIcon"; +import { NavLink } from "./components/NavLink"; +import { theme } from "../../../theme"; +import Image from "next/image"; +import CreateIcon from "@/utils/icons/navbar/CreateIcon"; +import PostIcon from "@/utils/icons/navbar/PostIcon"; +import CircleIcon from "@/utils/icons/navbar/CircleIcon"; +import DiscoverIcon from "@/utils/icons/navbar/DiscoverIcon"; +import SettingIcon from "@/utils/icons/navbar/SettingIcon"; +import MyProfileIcon from "@/utils/icons/navbar/MyProfileIcon"; +import CreatorIcon from "@/utils/icons/navbar/CreatorIcon"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import MessageIcon from "@/utils/icons/navbar/MessageIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import MainLogo from "@/utils/images/wititLogo.svg"; +import SmallLogo from "@/utils/images/wititSmall.svg"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import { UserType } from "@/types/user"; +import { useRouter } from "next/router"; +import { CustomImagePreview } from "../CustomImagePreview"; + +const { small, medium } = appConstant.drawerWidth; + +const navbarItems = [ + { + name: "Create", + link: appConstant.pageRoute.create, + startIcon: , + }, + { + name: "Post", + link: null, + startIcon: , + }, + { + name: "Message", + link: appConstant.pageRoute.message, + startIcon: , + }, + { + name: "Circle", + link: appConstant.pageRoute.circle, + startIcon: , + }, + { + name: "Creator", + link: null, + startIcon: , + }, + { + name: "Discover", + link: appConstant.pageRoute.discover, + startIcon: , + }, + { + name: "Setting", + link: appConstant.pageRoute.setting, + startIcon: , + }, + { + name: "My Profile", + link: appConstant.pageRoute.profile, + startIcon: , + }, +]; + +const Navbar = () => { + const router = useRouter(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down("xl")); // shift to useAuthContext + + const { setCustomDialogType } = useAuthContext(); + + const user = useSelector((state: RootState) => state.user); + + const handleProfileRedirect = () => { + router.push(appConstant.pageRoute.profile); + }; + + if (!user) return <>; + + const drawer = ( + <> +
+
+
+
+ +
+
+
+ {navbarItems.map((item, index) => { + return ( + + ); + })} +
+
+
+ {!isSmallScreen ? ( +
{ + setCustomDialogType("LEVELUP"); + }} + > + +
+
+ +
+
Verify your account
+
+
+ ) : ( +
{ + setCustomDialogType("LEVELUP"); + }} + > + +
+
+ +
+
+
+ )} + +
+
+
+
+
+ profile-image +
+ {!isSmallScreen ? ( +
+

+ {user?.userName} + {user?.userType === UserType.VERIFIED ? ( + + + + ) : null} +

+

+ {user?.counts.followerCount} Members +

+
+ ) : null} +
+
+
+ + ); + + return ( + + + {drawer} + + + ); +}; + +export default Navbar; diff --git a/components/shared/NoDataFound.tsx b/components/shared/NoDataFound.tsx new file mode 100644 index 0000000..dac9eb1 --- /dev/null +++ b/components/shared/NoDataFound.tsx @@ -0,0 +1,60 @@ +import CustomButton from "./CustomButton"; +import { CustomImagePreview } from "./CustomImagePreview"; + +type Props = { + title?: string; + description?: string; + image?: React.ReactElement; + children?: React.ReactNode; + buttonStyle?: string; + buttonName?: string; + handleEvent?: () => void; + titleStyle?: string; + descriptionStyle?: string; +}; + +export const NoDataFound = ({ + title, + description, + image, + children, + buttonName, + titleStyle, + buttonStyle, + handleEvent, + descriptionStyle, +}: Props) => { + return ( +
+
+ {image ?
{image}
: null} +
+ {title ? ( +
+

+ {title} +

+
+ ) : null} + {description ? ( +
+ {description} +
+ ) : null} +
+ {buttonName ? ( + + ) : null} + {children} +
+
+ ); +}; diff --git a/components/shared/NoInternet.tsx b/components/shared/NoInternet.tsx new file mode 100644 index 0000000..fb82a31 --- /dev/null +++ b/components/shared/NoInternet.tsx @@ -0,0 +1,55 @@ +import React, { useState, useEffect } from "react"; +import Loader from "./Loader"; +import { NoDataFound } from "./NoDataFound"; +import { CustomImagePreview } from "./CustomImagePreview"; +import NetworkIcon from "@/utils/icons/shared/NetworkIcon"; +import { useRouter } from "next/router"; + +const NoInternetConnection = (props: any) => { + // state variable holds the state of the internet connection + const [internetStatus, setInternetStatus] = useState(null); + const router = useRouter(); + // On initization set the isOnline state. + useEffect(() => { + setInternetStatus(navigator.onLine ? "ONLINE" : "OFFLINE"); + }); + + // event listeners to update the state + window.addEventListener("online", () => { + setInternetStatus("ONLINE"); + }); + + window.addEventListener("offline", () => { + setInternetStatus("OFFLINE"); + }); + + if (!internetStatus) return ; + if (internetStatus === "ONLINE") { + return props.children; + } else { + return ( +
+ { + router.reload(); + }} + image={ +
+ {" "} + +
+ } + buttonName="Try Again" + buttonStyle="bg-error-main mt-2" + title="Oops!!" + descriptionStyle="mt-2" + titleStyle="mt-2" + description="No Internet connection found. + Check your connection or Try again !" + /> +
+ ); + } +}; + +export default NoInternetConnection; diff --git a/components/shared/ReportDialog.tsx b/components/shared/ReportDialog.tsx new file mode 100644 index 0000000..9cf0618 --- /dev/null +++ b/components/shared/ReportDialog.tsx @@ -0,0 +1,110 @@ +import React, { useEffect, useState } from "react"; +import CustomDialog from "./dialog/CustomDialog"; +import CustomButton from "./CustomButton"; +import CustomDialogCommonTopBar from "./dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; +import CustomInputTextField from "./CustomInputTextField"; +import { Controller, useForm } from "react-hook-form"; + +type Props = { + isOpen?: boolean; + onCancel: () => void; + onConform: (inputText: string) => void; + image?: string; + title?: string; + buttonName?: string; + inputField?: { + limit: number; + tag: string; + placeholder: string; + }; +}; +const ReportDialog = ({ + isOpen, + onConform, + onCancel, + title, + inputField, + buttonName, +}: Props) => { + const { + handleSubmit, + control, + getValues, + formState: { errors, isSubmitted }, + } = useForm({ + defaultValues: { + reportText: "", + }, + mode: "onChange", + }); + + return ( + <> + +
{ + inputField && + getValues().reportText.length >= inputField.limit && + onConform(getValues().reportText); + })} + method="POST" + > + {title && ( + } + title={title} + onCancel={onCancel} + /> + )} + +
+ {inputField && ( +
+ ( + + )} + /> +
+ )} +
+ {inputField && ( + { + // getValues().reportText.length >= inputField.limit && + // onConform(getValues().reportText); + // }} + type="submit" + className={`border-[#E15F60] text-[#E15F60] bg-[#e15f5f1d] border border-solid rounded-lg text-sm py-2.5 hover:bg-opacity-80 `} + /> + )} +
+
+ +
+ + ); +}; + +export default ReportDialog; diff --git a/components/shared/Stepper.tsx b/components/shared/Stepper.tsx new file mode 100644 index 0000000..d137e67 --- /dev/null +++ b/components/shared/Stepper.tsx @@ -0,0 +1,102 @@ +import { theme } from "@/theme"; +import styled from "@emotion/styled"; +import { + Box, + Step, + StepConnector, + StepIconProps, + StepLabel, + Stepper, + stepConnectorClasses, +} from "@mui/material"; +import React from "react"; + +type Props = { + activeStep: number; + completeStep: number; +}; + +const steps = [ + { step: 0, isComplete: true }, + { step: 1, isComplete: false }, + { step: 2, isComplete: false }, +]; + +const QontoConnector = styled(StepConnector)(({}) => ({ + [`&.${stepConnectorClasses.alternativeLabel}`]: { + top: "50%", + left: "calc(-50% + 16px)", + right: "calc(50% + 16px)", + }, + [`&.${stepConnectorClasses.active}`]: { + [`& .${stepConnectorClasses.line}`]: { + borderColor: theme.palette.primary.main, + }, + }, + [`&.${stepConnectorClasses.completed}`]: { + [`& .${stepConnectorClasses.line}`]: { + borderColor: theme.palette.primary.main, + }, + }, + [`& .${stepConnectorClasses.line}`]: { + borderColor: theme.palette.grey[800], + borderTopWidth: 1, + borderRadius: 1, + }, +})); + +const ColorlibStepIconRoot = styled("div")<{ + ownerState: { completed?: boolean; active?: boolean }; +}>(({ ownerState }) => ({ + pr: 0, + backgroundColor: theme.palette.grey[400], + zIndex: 1, + color: theme.palette.common.white, + width: 16, + height: 16, + display: "flex", + borderRadius: "50%", + justifyContent: "center", + alignItems: "center", + ...(ownerState.active && { + background: theme.palette.primary.main, + boxShadow: "0 4px 10px 0 rgba(0,0,0,.25)", + }), + ...(ownerState.completed && { + background: theme.palette.primary.main, + }), +})); + +function ColorlibStepIcon(props: StepIconProps) { + const { active, completed, className } = props; + + return ( + + ); +} + +const StepperArea = ({ activeStep, completeStep }: Props) => { + return ( + } + > + {steps.map((stepData, index) => ( + + + + ))} + + ); +}; + +export default StepperArea; diff --git a/components/shared/ToastMessage.tsx b/components/shared/ToastMessage.tsx new file mode 100644 index 0000000..cb4602e --- /dev/null +++ b/components/shared/ToastMessage.tsx @@ -0,0 +1,68 @@ +import toast, { Toaster } from "react-hot-toast"; +import { useDispatch, useSelector } from "react-redux"; +import { useEffect } from "react"; +import { generate } from "@/redux/slices/messageSlice"; +import { theme } from "@/theme"; + +const style = { + positiveToast: { + borderRadius: "10px", + background: theme.palette.success.main, //"#198754" + color: theme.palette.common.white, + }, + negativeToast: { + borderRadius: "10px", + background: theme.palette.error.main, //"#ff4444", + color: theme.palette.common.white, + }, +}; + +let toastId: string; +const notify = (type: string, message: string) => { + toast.remove(); + switch (type) { + case "LOADING": + toastId = toast.loading(message ?? "Loading..."); + break; + case "SUCCESS": + toast.success(message, { + id: toastId ?? "", + style: style.positiveToast, + iconTheme: { + primary: theme.palette.common.white, + secondary: theme.palette.success.light, + }, + duration: 4000, + }); + break; + case "ERROR": + toast.error(message, { + id: toastId ?? "", + style: style.negativeToast, + iconTheme: { + primary: theme.palette.common.white, + secondary: theme.palette.error.main, + }, + duration: 4000, + }); + break; + default: + break; + } +}; + +const ToastMessage = () => { + const dispatch = useDispatch(); + const messageData = useSelector((state: any) => state.message); + + useEffect(() => { + if (messageData) { + dispatch(generate(null)); + notify(messageData?.type, messageData?.message); + } + }, [messageData]); + + return ; +}; + +export default ToastMessage; diff --git a/components/shared/Topbar/components/CreditDialogbox.tsx b/components/shared/Topbar/components/CreditDialogbox.tsx new file mode 100644 index 0000000..701c909 --- /dev/null +++ b/components/shared/Topbar/components/CreditDialogbox.tsx @@ -0,0 +1,365 @@ +import { useAuthContext } from "@/context/AuthContext"; +import { theme } from "@/theme"; +import { Divider, IconButton } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import CreditTopBg from "@/utils/images/CreditTopBg.png"; +import Image from "next/image"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import Slider from "react-slick"; +import CustomButton from "@/components/shared/CustomButton"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { getAmountFromCredit } from "@/api/stripe/getAmountFromCredit"; +import createCheckoutSession from "@/api/stripe/createCheckoutSession"; +import { useRouter } from "next/router"; +import withdrawCredit from "@/api/stripe/withdrawCredit"; +import { generateArray } from "@/service/manageCredit/createCreditArray"; +import CustomDialog from "../../dialog/CustomDialog"; +import CustomLoadingButton from "../../CustomLoadingButton"; +import TermsOfServices from "@/components/footerDialogs/TermsOfServices"; +import PrivacyPolicy from "@/components/footerDialogs/PrivacyPolicy"; +import CustomInsufficientCredit from "../../CustomInsufficientCredit"; + +var sliderSettings = { + centerMode: true, + centerPadding: "60px", + slidesToShow: 3, + speed: 500, + swipeToSlide: true, + focusOnSelect: true, +}; + +const CreditDialogbox = () => { + const { customDialogType, setCustomDialogType, amountPerCredit } = + useAuthContext(); + const { sendNotification } = useAuthContext(); + const user = useSelector((state: RootState) => state.user); + const [currentSlide, setCurrentSlide] = useState(500); + const [ListArray, setListArray] = useState([]); + const [isButtonLoading, setIsButtonLoading] = useState(false); + const [policy, setPolicy] = useState(null); + const [isnotEnoughCredit, setIsnotEnoughCredit] = useState(false); + + const router = useRouter(); + const getCreditListArray = generateArray(500, 10000); + const withdrawCreditListArray = generateArray(1000, 10000); + + const settings = { + afterChange: (index: number) => { + ListArray?.map((val, id) => { + if (index === id) { + setCurrentSlide(val); + } + }); + }, + }; + + useEffect(() => { + customDialogType === "CREDITS-GETCREDITS" + ? setListArray(getCreditListArray) + : (setListArray(withdrawCreditListArray), setCurrentSlide(1000)); + }, []); + + const getCredit = async () => { + const url = + window.location.protocol + "//" + window.location.host + "/setting"; + setIsButtonLoading(true); + const response = await createCheckoutSession({ + credit: currentSlide, + url: url, + userid: user?.userId, + }); + if (response.status === 200) { + router.push(response.data?.sessionUrl); + + setIsButtonLoading(false); + return; + } + sendNotification({ + type: "ERROR", + message: response.error, + }); + }; + + const getwithdraw = async () => { + setIsButtonLoading(true); + const response = await withdrawCredit({ + credit: currentSlide, + user_id: user?.userId, + }); + if (response.status === 200) { + setIsButtonLoading(false); + sendNotification({ + type: "SUCCESS", + message: "Credit Successfuly Withdrawal", + }); + return; + } + if (response.status === 403) { + setIsnotEnoughCredit(true); + setIsButtonLoading(false); + return; + } + + setIsButtonLoading(false); + sendNotification({ + type: "ERROR", + message: response.error, + }); + }; + const taxAmount = currentSlide * amountPerCredit.add * 0.029; + const FinalAmount = currentSlide * amountPerCredit.add + taxAmount; + if (!user || !user.credit) return <>; + const { tempCredit, nonTransferableCredit, transferableCredit } = user.credit; + + const openGetCreditDialog = () => { + setCustomDialogType("CREDITS-GETCREDITS"); + }; + + const closeDialoag = () => { + setIsnotEnoughCredit(false); + }; + return ( + <> + + {/* top common layout */} +
+
+ { + setCustomDialogType(null); + }} + > + + + + +
+
+

+ {customDialogType === "CREDITS-GETCREDITS" + ? "Total" + : "Availabe"}{" "} + Credit Balance +

+
+

+ {customDialogType === "CREDITS-GETCREDITS" + ? tempCredit + nonTransferableCredit + transferableCredit + : transferableCredit} +

+
+ +
+
+
+
+
+
+ + {customDialogType === "CREDITS-GETCREDITS" || + customDialogType === "CREDITS-WITHDRAW" ? ( +
+
+ + +
+
+
+ (slider = slider)} + {...sliderSettings} + className="slick-slider_center-mode w-full flex flex-row " + > + {ListArray?.map((val, index) => { + return ( +
+

{val}

+
+ ); + })} +
+
+
+ ) : null} + +
+ {/* topbar-> gretCredits */} + {customDialogType === "CREDITS-GETCREDITS" ? ( +
+
+

Credit Amount

+

+ ${(currentSlide * amountPerCredit.add).toFixed(2)} +

+
+
+

Tax @ 2.9%

+

+ ${(currentSlide * amountPerCredit.add * 0.029).toFixed(2)} +

+
+ +
+
+ +
+
+
+

Total Payable Amount

+

+ ${FinalAmount.toFixed(2)} +

+
+
+ ) : null} + + {/* topbar-> withdrawal amount */} + {customDialogType === "CREDITS-WITHDRAW" ? ( +
+

+ The balance must be over 1000 credits to be withdrawn. +

+ +
+

Credit Amount

+

+ ${(currentSlide * amountPerCredit.withdraw).toFixed(2)} +

+
+ +
+ ) : null} + +
+ { + if (customDialogType === "CREDITS-GETCREDITS") { + getCredit(); + return; + } + getwithdraw(); + }} + /> +

+ By submitting this request you agree to witit’s +

+

+ { + setPolicy("PRIVACY_POLICYS"); + }} + > + Privacy Policy + {" "} + and + { + setPolicy("TERMS_OF_SERVICES"); + }} + > + Terms of Use + +

+
+
+ {isnotEnoughCredit && ( +
+ { + openGetCreditDialog(); + }} + onCancel={() => { + closeDialoag(); + }} + /> +
+ )} + + {policy && ( + + {policy === "TERMS_OF_SERVICES" ? ( + { + setPolicy(null); + }} + /> + ) : policy === "PRIVACY_POLICYS" ? ( + { + setPolicy(null); + }} + /> + ) : null} + + )} + + ); +}; + +export default CreditDialogbox; diff --git a/components/shared/Topbar/components/CreditOverlay.tsx b/components/shared/Topbar/components/CreditOverlay.tsx new file mode 100644 index 0000000..f9dfa0a --- /dev/null +++ b/components/shared/Topbar/components/CreditOverlay.tsx @@ -0,0 +1,147 @@ +import RighCrossArrowIcon from "@/utils/icons/shared/RighCrossArrowIcon"; +import CustomButton from "../../CustomButton"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import { Divider } from "@mui/material"; +import Image from "next/image"; +import HypeTriangleIcon from "@/utils/icons/shapes/HypeTriangleIcon"; +import { theme } from "@/theme"; +import { crossLineBg } from "@/utils/images"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { CreditItem } from "@/types/user"; +import { useAuthContext } from "@/context/AuthContext"; +import DollerIcon from "@/utils/icons/levelUp/DollerIcon"; +import { CustomImagePreview } from "../../CustomImagePreview"; +import { dollerImage } from "@/utils/images/topbar"; +import GradientCrown from "@/utils/icons/levelUp/GradientCrown"; +import { setPaymentStatus } from "@/redux/slices/paymentStatusSlice"; + +type Props = { + creditList: CreditItem[]; + handleButtonClick: ({ type }: { type: string }) => void; +}; + +export const CreditOverlay = ({ handleButtonClick, creditList }: Props) => { + const user = useSelector((state: RootState) => state.user); + const payment = useSelector((state: RootState) => state.payments); + + const dispatch = useDispatch(); + + const { amountPerCredit } = useAuthContext(); + + return ( +
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+

Credits

+
+
+
+ {creditList.map((data, index) => { + if ( + user?.userType !== "VERIFIED" && + data.name !== "Non Transferable Credit" + ) + return; + return ( +
+
+
+

{data.name}

+

+ {data.description} +

+
+
+
+
+ +
+

+ {data.credit} +

+
+

+ ${(amountPerCredit.withdraw * data.credit).toFixed(2)} +

+
+
+ {index < 2 && user?.userType === "VERIFIED" ? ( + + ) : null} +
+ ); + })} +
+ + +
+ } + handleEvent={() => { + handleButtonClick({ type: "ADD" }); + dispatch(setPaymentStatus("")); + }} + name="Deposit" + className="shadow-none py-2 text-sm" + /> + {user?.userType === "VERIFIED" && ( + + +
+ } + handleEvent={() => { + handleButtonClick({ type: "WITHDRAW" }); + dispatch(setPaymentStatus("")); + }} + name="Withdraw" + className="bg-grey-700 shadow-none py-2 text-sm" + /> + )} +
+ {user?.userType !== "VERIFIED" && ( +
+
+ +
+
+

+ Start Withdrawing +

+

+ Start withdrawing dollars by{" "} + + Go Pro Premium + {" "} + Feature. +

+
+
+ +
+
+ )} +
+
+
+ ); +}; diff --git a/components/shared/Topbar/index.tsx b/components/shared/Topbar/index.tsx new file mode 100644 index 0000000..04b3e3f --- /dev/null +++ b/components/shared/Topbar/index.tsx @@ -0,0 +1,279 @@ +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import HypeIcon from "@/utils/icons/topbar/HypeIcon"; +import React, { useEffect, useRef, useState } from "react"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomInputTextField from "../CustomInputTextField"; +import SearchIcon from "@/utils/icons/topbar/SearchIcon"; +import { CreditOverlay } from "./components/CreditOverlay"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { CreditItem } from "@/types/user"; +import { useRouter } from "next/router"; +import { CircularProgress } from "@mui/material"; +import { useDebounceEffect } from "@/hooks/useDebounceEffect"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import { IconDropDown } from "../dropDown/IconDropDown"; +import { DropDownItem } from "@/types"; +import { io } from "socket.io-client"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { setPaymentStatus } from "@/redux/slices/paymentStatusSlice"; + +type CreditVisible = { + isClicked: boolean; + isHover: boolean; +}; + +const initialCreditDialog: CreditVisible = { + isClicked: false, + isHover: false, +}; + +const hypeInitialList: DropDownItem[] = [ + { + title: "Notifications", + actionType: "NOTIFICATIONS", + }, + { + title: "Offer Created", + actionType: "OFFER_CREATED", + }, + { + title: "Offer Received", + actionType: "OFFER_RECEIVED", + }, +]; + +const Topbar = () => { + const router = useRouter(); + const { asPath } = useRouter(); + const currentPath = useRef(asPath); + const user = useSelector((state: RootState) => state.user); + + const { + setCustomDrawerType, + setCustomDialogType, + setDiscoverSearch, + discoverSearch, + amountPerCredit, + activityCounts, + } = useAuthContext(); + + const [search, setSearch] = useState(null); + const debouncedSearch = useDebounceEffect(search, 2000); + const [isSearching, setIsSearching] = useState(false); + const [hypes, setHypes] = useState(hypeInitialList); + + useEffect(() => { + if (!activityCounts) return; + + setHypes((prevHypes) => { + return prevHypes.map((item) => { + return { + ...item, + ...(item.actionType === "NOTIFICATIONS" + ? activityCounts.notification > 0 + ? { + endIcon: ( +
+ {activityCounts.notification} +
+ ), + } + : {} + : item.actionType === "OFFER_CREATED" + ? activityCounts.offerCreated > 0 + ? { + endIcon: ( +
+ {activityCounts.offerCreated} +
+ ), + } + : {} + : activityCounts.offerReceived > 0 + ? { + endIcon: ( +
+ {activityCounts.offerReceived} +
+ ), + } + : {}), + }; + }); + }); + }, [activityCounts]); + + const initialList: CreditItem[] = [ + { + name: "Transferable Credit", + description: + "Can be transferred to your bank account, and you can also use it throughout the app.", + credit: user?.credit?.transferableCredit ?? 0, + amount: 0, + color: "text-success-main", + }, + { + name: "Non Transferable Credit", + description: + "Can’t be transferred to your bank account, but you can use it throughout the app.", + credit: user?.credit?.nonTransferableCredit ?? 0, + amount: 0, + color: "text-error-main", + }, + { + name: "Temp Credit", + description: + "You will get free 100 temp credits everyday and they can be used throughout the app.", + credit: user?.credit?.tempCredit ?? 0, + amount: 0, + color: "text-primary-light", + }, + ]; + + const [creditVisible, setCreditVisible] = + useState(initialCreditDialog); + const [creditList, setCreditList] = useState(initialList); + + const dispatch = useDispatch(); + useEffect(() => { + setCreditList(initialList); + }, [user]); + + const handleButtonClick = ({ type }: { type: string }) => { + setCustomDrawerType(null); + setCreditVisible(initialCreditDialog); + if (type === "ADD") { + setCustomDialogType("CREDITS-GETCREDITS"); + } else { + setCustomDialogType("CREDITS-WITHDRAW"); + } + }; + + const handleHover = (isHover: boolean) => { + setCreditVisible((preCon) => { + return { + ...preCon, + isHover, + }; + }); + }; + + const handleClick = (isClicked: boolean) => { + setCreditVisible((preCon) => { + return { + ...preCon, + isClicked, + }; + }); + }; + + useEffect(() => { + if (creditVisible.isClicked) { + setTimeout(() => { + handleClick(false); + }, 3000); + } + }, [creditVisible.isClicked]); + + useEffect(() => { + if (search === debouncedSearch) { + setIsSearching(false); + } else if (search && search.length > 2) { + setIsSearching(true); + } + }, [search, debouncedSearch]); + + useEffect(() => { + if (debouncedSearch && debouncedSearch.length > 0) { + setDiscoverSearch({ search: debouncedSearch, isSearched: false }); + } + if (currentPath.current === "/discover" && debouncedSearch?.length === 0) { + setDiscoverSearch({ search: debouncedSearch, isSearched: false }); + } + }, [debouncedSearch]); + + useEffect(() => { + if (discoverSearch.search === null) { + setSearch(null); + } + }, [discoverSearch]); + + if (!user) return <>; + + return ( +
+
+ ) => { + setSearch(e.target.value); + }} + StartIcon={} + EndIcon={ + isSearching && ( +
+ +
+ ) + } + placeholder="Search Here" + className="text-sm rounded-lg overflow-hidden text-common-white focus-visible:outline-none max-w-[550px] min-w-[360px] py-2 h-12" + /> +
+
+
+
{ + handleHover(true); + }} + onMouseLeave={() => { + handleHover(false); + }} + > +
{ + handleClick(true); + }} + > + +
+ {creditVisible.isClicked || creditVisible.isHover ? ( + + ) : null} +
+ { + console.log("HYPE_" + type); + setCustomDrawerType("HYPE_" + type); + }} + Icon={ +
+
+ 0 || + activityCounts.offerCreated > 0 || + activityCounts.offerReceived > 0 + } + /> +

Hype

+
+
+ +
+
+ } + /> +
+
+
+ ); +}; +export default Topbar; diff --git a/components/shared/credit/CreditViewPrompt.tsx b/components/shared/credit/CreditViewPrompt.tsx new file mode 100644 index 0000000..662eb26 --- /dev/null +++ b/components/shared/credit/CreditViewPrompt.tsx @@ -0,0 +1,161 @@ +import { theme } from "@/theme"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import { CircularProgress, Divider } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import { CustomImagePreview } from "../CustomImagePreview"; +import { UserBaseInfo } from "@/types/user"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import { PromptDetail } from "@/types/post"; +import { getPromptChargeOfPost } from "@/api/post/getPromptChargeOfPost"; +import { useAuthContext } from "@/context/AuthContext"; +import { getAccessToViewPromptOfPost } from "@/api/post/getAccessToViewPromptOfPost"; +import CustomLoadingButton from "../CustomLoadingButton"; +import { getCreditObjectToUpdateCreditModel } from "@/service/manageCredit/getCreditObjectToUpdateCreditModel"; +import { updateSimilarDiscoverPostViewPrompt } from "@/redux/slices/discoverSimilarFeedSlice"; +import CustomInsufficientCredit from "../CustomInsufficientCredit"; + +type Props = { + postedBy: { + userInfo: UserBaseInfo; + postId: string; + } | null; + setPromptDetails: React.Dispatch>; + promptDetails: PromptDetail | null; +}; + +const CreditViewPrompt = ({ + postedBy, + promptDetails, + setPromptDetails, +}: Props) => { + const user = useSelector((state: RootState) => state.user); + const { sendNotification, setCustomDialogType } = useAuthContext(); + const dispatch = useDispatch(); + const [creditPerPrompt, setCreditPerPrompt] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [isnotEnoughCredit, setIsnotEnoughCredit] = useState(false); + + const getPromptCharge = async () => { + if (!user) return; + if (!postedBy) return; + const res = await getPromptChargeOfPost({ + user_id: user.userId, + postId: postedBy?.postId, + }); + + if (res.status === 200) { + setCreditPerPrompt(res.data); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const getAccessToView = async () => { + setIsLoading(true); + if (!user) return; + if (!postedBy) return; + const res = await getAccessToViewPromptOfPost({ + user_id: user.userId, + postId: postedBy?.postId, + }); + + if (res.status === 200 && user.credit && creditPerPrompt) { + const temp = +creditPerPrompt ?? 0; + const tempData = getCreditObjectToUpdateCreditModel({ + creditObj: user.credit, + credit: temp, + }); + + dispatch( + updateSimilarDiscoverPostViewPrompt({ postId: postedBy?.postId }) + ); + + setPromptDetails(res.data); + return; + } + if (res.status === 403) { + setIsnotEnoughCredit(true); + setIsLoading(false); + return; + } + setIsLoading(false); + sendNotification({ type: "ERROR", message: res.error }); + }; + + useEffect(() => { + getPromptCharge(); + }, []); + + useEffect(() => { + if (promptDetails) { + setIsLoading(false); + } + }, [promptDetails]); + const openGetCreditDialog = () => { + setCustomDialogType("CREDITS-GETCREDITS"); + }; + + const closeDialoag = () => { + setIsnotEnoughCredit(false); + }; + return ( +
+
+
+

Total Prompt Amount

+ {creditPerPrompt === null ? ( +
+ +
+ ) : ( +
+

+ {creditPerPrompt} +

+
+ +
+
+ )} +
+ +
+ + + {isnotEnoughCredit && ( +
+ +
+ )} +
+ ); +}; + +export default CreditViewPrompt; diff --git a/components/shared/credit/Index.tsx b/components/shared/credit/Index.tsx new file mode 100644 index 0000000..4e16c5c --- /dev/null +++ b/components/shared/credit/Index.tsx @@ -0,0 +1,109 @@ +import { theme } from "@/theme"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import { IconButton, Divider } from "@mui/material"; +import React, { useState } from "react"; +import Slider from "react-slick"; +import CustomButton from "../CustomButton"; +import CustomToggleSwitch from "../CustomToggleSwitch"; +import CustomDialog from "../dialog/CustomDialog"; +import { CustomImagePreview } from "../CustomImagePreview"; +import CreditTopBg from "@/utils/images/CreditTopBg.png"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { UserBaseInfo } from "@/types/user"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; + +type Props = { + creditDialogInfo: { + userInfo: UserBaseInfo; + postId: string; + } | null; + setCreditDialogInfo: React.Dispatch< + React.SetStateAction<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null> + >; + children?: React.ReactNode; +}; +const Creadit = ({ + children, + creditDialogInfo, + setCreditDialogInfo, +}: Props) => { + const user = useSelector((state: RootState) => state.user); + + return ( + +
+
+
+ { + setCreditDialogInfo(null); + }} + > + + + +
+ +
+ +
+
+

Total Credit Balance

+
+

+ {user?.credit && + user.credit.nonTransferableCredit + + user.credit.transferableCredit + + user.credit.tempCredit} +

+
+ +
+
+
+
+
+
+ {children} + +
+

+ By submitting this request you agree to witit’s +

+

+ { + e.stopPropagation(); + }} + > + Privacy Policy + {" "} + and + { + e.stopPropagation(); + }} + > + Terms of Use + +

+
+
+
+ ); +}; + +export default Creadit; diff --git a/components/shared/dialog/CustomDialog.tsx b/components/shared/dialog/CustomDialog.tsx new file mode 100644 index 0000000..da86844 --- /dev/null +++ b/components/shared/dialog/CustomDialog.tsx @@ -0,0 +1,58 @@ +import { Box, useMediaQuery } from "@mui/material"; +import React, { ReactNode, useEffect, useState } from "react"; + +import { theme } from "@/theme"; +import { useAuthContext } from "@/context/AuthContext"; + +type Props = { + children: ReactNode; + isOpen?: boolean; + onCancel?: () => void; +} & Record; + +const CustomDialog = ({ children, isOpen, onCancel, ...restProps }: Props) => { + const isSmallScreen = useMediaQuery(theme.breakpoints.down("xl")); // shift to useAuthContext + const { setCustomDialogType, customDialogType } = useAuthContext(); + + return ( + <> + {customDialogType || isOpen ? ( +
{ + if (onCancel) { + onCancel(); + } + }} + > + { + e.stopPropagation(); + }} + {...restProps} + > + {children} + +
+ ) : null} + + ); +}; + +export default CustomDialog; diff --git a/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/CategoryListInfo.tsx b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/CategoryListInfo.tsx new file mode 100644 index 0000000..807e1e3 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/CategoryListInfo.tsx @@ -0,0 +1,72 @@ +import { Grid } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import { ControllerRenderProps, UseFormSetValue } from "react-hook-form"; +import { Post } from "@/types/post"; +import { DefaultValues } from "@/types/createPostType"; + +type Props = { + setValue: UseFormSetValue>; + setErrorMessage: React.Dispatch>; +}; +const styles = { + responsiveGrid: { + xxl: 4, + xl: 4, + // lg: 5, + md: 4, + sm: 8, + xs: 12, + }, +}; +const CategoryListInfo = ({ setValue, setErrorMessage }: Props) => { + const [getCategory, setGetCategory] = useState([]); + + const handleCategory = (item: string, id: number) => { + if (!getCategory.includes(item)) { + setGetCategory([...getCategory, item]); + } else { + setGetCategory((preValue) => { + return preValue.filter((value) => value !== item); + }); + } + }; + + useEffect(() => { + setValue("category", getCategory as string[]); + }, [getCategory]); + + return ( +
+ + {CategoryList.map((category, index) => { + return ( + +
item === category.name) + ? "bg-primary-main text-common-white" + : "text-grey-200 bg-grey-800" + } + `} + onClick={() => { + setErrorMessage(""); + handleCategory(category.name, index); + }} + > +

{category.startIcon}

+

+ {category.name} +

+
+
+ ); + })} +
+
+ ); +}; + +export default CategoryListInfo; diff --git a/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/CategorySelection.tsx b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/CategorySelection.tsx new file mode 100644 index 0000000..931d831 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/CategorySelection.tsx @@ -0,0 +1,88 @@ +import React, { useState } from "react"; +import CustomInputTextField from "../../../../../CustomInputTextField"; +import { + Control, + Controller, + UseFormGetValues, + UseFormHandleSubmit, + UseFormSetValue, +} from "react-hook-form"; +import CategoryListInfo from "./CategoryListInfo"; +import { DefaultValues } from "@/types/createPostType"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; + +type Props = { + control: Control, any>; + handleSubmit: UseFormHandleSubmit>; + handleSave: (data: Partial) => Promise; + setValue: UseFormSetValue>; + isLoading: Boolean; + getValues: UseFormGetValues>; +}; +const CategorySelection = ({ + getValues, + control, + handleSubmit, + handleSave, + setValue, + isLoading, +}: Props) => { + const [errorMessage, setErrorMessage] = useState(""); + return ( +
+
+ { + return ( + + ); + }} + /> +
+
+
+ Category +
+ { + return ( + <> + + + ); + }} + /> +
+
+

{errorMessage}

+ { + if (getValues("category") && getValues("category")!.length < 1) { + setErrorMessage("Please Select Category"); + return; + } + handleSubmit(handleSave)(); + }} + /> +
+
+ ); +}; + +export default CategorySelection; diff --git a/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/InputImages.tsx b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/InputImages.tsx new file mode 100644 index 0000000..99387b1 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/InputImages.tsx @@ -0,0 +1,72 @@ +import React, { useEffect, useState } from "react"; +import InputCropMultiImages from "@/components/shared/cropImage/multipleCropImage/InputCropMultiImages"; +import { ImageInfo } from "@/types"; + + + + +type Props = { + setImages: React.Dispatch< + React.SetStateAction< + { + image: ImageInfo; + index: number; + }[] + > + >; + isSmall: boolean; + isEnabled: boolean; +}; +const InputImages = (props: Props) => { + const { setImages, isSmall, isEnabled } = props; + const [editedImages, seteditedImages] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + + useEffect(() => { + if (editedImages.length > 0) { + setImages(editedImages); + } + }, [editedImages]); + + return ( +
+
+ +
+ {isSmall ? ( + <> + ) : ( +
+

+ Upload Upto 10 Images +

+

+ Upload JPG, PNG With In 20MB To 50 MB{" "} +

+
+ )} +
+ ); +}; + +export default InputImages; diff --git a/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/PostFromGenetation/GenerationPostCategory.tsx b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/PostFromGenetation/GenerationPostCategory.tsx new file mode 100644 index 0000000..484233a --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/PostFromGenetation/GenerationPostCategory.tsx @@ -0,0 +1,139 @@ +import { Grid } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import { + Control, + ControllerProps, + FieldPath, + FieldValues, + UseFormGetValues, + UseFormHandleSubmit, + UseFormSetValue, +} from "react-hook-form"; +import { DefaultValues } from "@/types/createPostType"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; + +type Props = { + setValue: UseFormSetValue>; + setStep: React.Dispatch>; + getValues: UseFormGetValues>; + handleSubmit: UseFormHandleSubmit>; + handleSave: (data: Partial) => Promise; + isLoading: boolean; + control: Control, any>; + Controller: < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath + >( + props: ControllerProps + ) => import("react").ReactElement< + any, + string | import("react").JSXElementConstructor + >; +}; +const styles = { + responsiveGrid: { + xxl: 4, + xl: 4, + // lg: 5, + md: 4, + sm: 8, + xs: 12, + }, +}; +const GenerationPostCategory = ({ + getValues, + setValue, + Controller, + control, + isLoading, + handleSubmit, + handleSave, +}: Props) => { + const [getCategory, setGetCategory] = useState([]); + const [errorMessage, setErrorMessage] = useState(""); + + const handleCategory = (item: string, id: number) => { + if (!getCategory.includes(item)) { + setGetCategory([...getCategory, item]); + } else { + setGetCategory((preValue) => { + return preValue.filter((value) => value !== item); + }); + } + }; + + useEffect(() => { + setValue("category", getCategory as string[]); + setErrorMessage(""); + }, [getCategory]); + + return ( +
+
+ { + return ( + + ); + }} + /> +
+
+ Category +
+ + {CategoryList.map((category, index) => { + return ( + +
item === category.name) + ? "bg-primary-main text-common-white" + : "text-grey-200 bg-grey-800" + } + `} + onClick={() => { + handleCategory(category.name, index); + }} + > +

{category.startIcon}

+

+ {category.name} +

+
+
+ ); + })} +
+
+

{errorMessage}

+ { + if (getValues("category") && getValues("category")!.length < 1) { + setErrorMessage("Please Select Category"); + return; + } + handleSubmit(handleSave)(); + }} + /> +
+
+ ); +}; + +export default GenerationPostCategory; diff --git a/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/PostFromGenetation/SetPostPrompt.tsx b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/PostFromGenetation/SetPostPrompt.tsx new file mode 100644 index 0000000..2cf75b6 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/components/PostFromGenetation/SetPostPrompt.tsx @@ -0,0 +1,206 @@ +import React, { ChangeEvent, useEffect, useState } from "react"; +import CustomButton from "../../../../../../CustomButton"; +import { useAuthContext } from "@/context/AuthContext"; +import CustomToggleSwitch from "../../../../../../CustomToggleSwitch"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { DefaultValues } from "@/types/createPostType"; +import { Controller, useForm } from "react-hook-form"; +import GenerationPostCategory from "./GenerationPostCategory"; +import createPost from "@/api/post/createPost"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import CustomDialogCommonTopBar from "../../../shared/CustomDialogCommonTopBar"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import RightThikArrowButton from "@/utils/icons/shared/RightThikArrowButton"; + +const SetPostPrompt = () => { + const [isAllow, setIsAllow] = useState(false); + const [step, setStep] = useState(0); + const [isLoading, setIsLoading] = useState(false); + + const { generationPost, sendNotification, setCustomDialogType } = + useAuthContext(); + const user = useSelector((state: RootState) => state.user); + + const defaultValues: Partial = { + category: [], + caption: "", + image: [generationPost!.generationImages[0]], + generatedFrom: { postId: null, modelId: generationPost!.modelDetails.id }, + promptDetails: { + creditPerPromptView: 0, + allowPromptView: false, + generationId: generationPost!.Id, + }, + }; + + const { control, setValue, handleSubmit, getValues } = useForm< + Partial + >({ + defaultValues, + mode: "onSubmit", + }); + + useEffect(() => { + if (isAllow) { + setValue("promptDetails.allowPromptView", isAllow); + setValue("promptDetails.creditPerPromptView", 1); + } else { + setValue("promptDetails.creditPerPromptView", 0); + } + }, [isAllow]); + + const handleSave = async (data: Partial) => { + setIsLoading(true); + const response = await createPost({ + postObject: data, + user_id: user?.userId, + }); + if (response.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Data Updated Successfully", + }); + setIsLoading(false); + setCustomDialogType(null); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + setIsLoading(false); + }; + + if (!generationPost) { + return <>; + } + + return ( + <> + { + setCustomDialogType(null); + }} + startIcon={ + step === 0 ? ( +
+ +
+ ) : ( +
{ + if (step > 0) { + setStep(0); + } + }} + > + +
+ ) + } + title="Create Post" + /> +
+ {step === 0 && ( +
+
+
+ +
+
+ +
+
+

Prompts for the generation

+
+

+ {generationPost?.prompt} +

+
+ +
+
+ Allow Others to see your prompt +
+ { + return ( + <> + + ) => { + setIsAllow(e.target.checked); + }} + /> + + ); + }} + /> +
+ {isAllow && ( +
+
+
+ Cost to Revel Prompt +
+

+ You will receive this credit when you create a post in + witit and someone wants to view the prompt of that post. +

+
+ { + return ( + <> + + + ); + }} + /> +
+ )} +
+ +
+ } + name="Next" + className="w-fit text-base font-semibold px-20 py-3" + handleEvent={() => { + setStep(1); + }} + /> +
+
+
+ )} + {step === 1 && ( + + )} + + + ); +}; + +export default SetPostPrompt; diff --git a/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/index.tsx b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/index.tsx new file mode 100644 index 0000000..2fbc026 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/CreatePostDialog/index.tsx @@ -0,0 +1,202 @@ +import React, { useEffect, useState } from "react"; +import InputImages from "./components/InputImages"; +import { ImageInfo } from "@/types"; +import CustomDialog from "../../../CustomDialog"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import CategorySelection from "./components/CategorySelection"; +import SetPostPrompt from "./components/PostFromGenetation/SetPostPrompt"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import CustomDialogCommonTopBar from "../shared/CustomDialogCommonTopBar"; +import { useForm } from "react-hook-form"; +import { Image, Post } from "@/types/post"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { DefaultValues } from "@/types/createPostType"; +import { createImage } from "@/service/imageCropper/cropImage"; +import createPost from "@/api/post/createPost"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import ModifyImages from "@/components/shared/CropImage/multipleCropImage/ModifyImages"; + +const CreatePostDialog = () => { + const [createPostImages, setCreatePostImages] = useState< + { + image: ImageInfo; + index: number; + }[] + >([]); + const [isLoading, setLoading] = useState(false); + const [isBack, setisBack] = useState(false); + const [step, setStep] = useState(1); + + const { + firebaseUser, + setCustomDialogType, + sendNotification, + generationPost, + } = useAuthContext(); + + const user = useSelector((state: RootState) => state.user); + + const defaultValues: Partial = { + category: [], + caption: null, + image: [], + generatedFrom: null, + }; + + useEffect(() => { + if (createPostImages.length > 0) { + setStep(2); + } + }, [createPostImages]); + + useEffect(() => { + setCreatePostImages([]); + }, [isBack]); + + const { handleSubmit, control, setValue, getValues } = useForm({ + defaultValues, + }); + + const handleSave = async (data: Partial) => { + data.caption === "" && (data.caption = null); + + setLoading(true); + const getFirebaseImages: Blob[] = []; + + for (const val of createPostImages.slice(0, 10)) { + const imageInfo = val.image.croppedImageSrc; + const response = await fetch(imageInfo); + const file = await response.blob(); + getFirebaseImages.push(file); + } + + const selectedPhotosList = await Promise.all( + getFirebaseImages.map((file) => { + const folderName = "add_post"; + return file + ? uploadImageToStorage({ + folderName, + file, + metadata: { + userId: firebaseUser?.uid, + }, + }) + : null; + }) + ); + + const imageObject = await Promise.all( + selectedPhotosList.map(async (item) => { + if (!item) { + return; + } + const image = await createImage(item); + return { + url: image.currentSrc, + width: image.width, + height: image.height, + }; + }) + ); + + data.image = imageObject as Partial[]; + + const response = await createPost({ + postObject: data, + user_id: user?.userId, + }); + if (response.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Data Updated Successfully", + }); + setLoading(false); + setCustomDialogType(null); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + setLoading(false); + }; + console.log(createPostImages, "post"); + return ( + <> + {step >= 1 ? ( + +
+ {!generationPost && ( + <> + { + setCustomDialogType(null); + }} + startIcon={ + createPostImages.length === 0 || step === 1 ? ( +
+ +
+ ) : ( +
{ + if (step > 0) { + setStep(step - 1); + } + }} + > + +
+ ) + } + title="Create Post" + /> + +
+ {step === 1 ? ( +
+ +
+ ) : null} + + {step == 2 ? ( + <> + + + ) : null} + {step == 3 ? ( + + ) : null} +
+ + )} + {generationPost ? : null} + +
+ ) : null} + + ); +}; +{ + /* SetPostPrompt */ +} + +export default CreatePostDialog; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/LeftUserInfo.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/LeftUserInfo.tsx new file mode 100644 index 0000000..75c4eb2 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/LeftUserInfo.tsx @@ -0,0 +1,35 @@ +import Image from "next/image"; +import React from "react"; +import tempboy from "@/utils/images/tempboy.jpg"; +import slothImage from "@/utils/images/sloth_image.jpg"; +const LeftUserInfo = () => { + return ( +
+ + +
+
+ +
+

Alex goot

+

+ alexgoot@gmail.com +

+
+
{" "} +
Level up your AI
+

+ Generate stunning AI-generated images of Yourself within seconds, + using the premium access features. +

+
+
+ ); +}; + +export default LeftUserInfo; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/LevelStartCreating.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/LevelStartCreating.tsx new file mode 100644 index 0000000..dc10bdb --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/LevelStartCreating.tsx @@ -0,0 +1,172 @@ +import Image from "next/image"; +import React, { useState } from "react"; +import startCreatingBg from "@/utils/images/startCreatingBg.jpg"; +import { Button, Divider, IconButton } from "@mui/material"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import { theme } from "@/theme"; +import OpenLockIcon from "@/utils/icons/shared/OpenLockIcon"; +import CustomButton from "../../../../CustomButton"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import GetStartedMirroeIcon from "@/utils/icons/levelUp/GetStartedMirroeIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import GradientCrown from "@/utils/icons/levelUp/GradientCrown"; +import CustomDialog from "../../../CustomDialog"; +import TermsOfServices from "@/components/footerDialogs/TermsOfServices"; +import PrivacyPolicy from "@/components/footerDialogs/PrivacyPolicy"; +import ContentPolicy from "@/components/footerDialogs/ContentPolicy"; + +type Props = { + setcurrentStep: React.Dispatch>; +}; + +const LevelStartCreating = ({ setcurrentStep }: Props) => { + const { setCustomDialogType, customDialogType } = useAuthContext(); + const [policy, setPolicy] = useState(null); + return ( + <> +
+
{ + setCustomDialogType(null); + }} + > + +
+
+ +
+ +
+
+

Start Creating

+

+ Generate stunning AI-generated images of Yourself within seconds, + using the premium access features. +

+
+
+
+
+ +
+ +
+
+

+ Create{" "} + custom photos of yourself +

+
+
+ +
+ +
+
+

+ + Unlock 40 more + {" "} + photos of yourself +

+
+
+ +
+ +
+
+

+ Get + + {" "} + 195 credits + {" "} + to get started creating +

+
+
+ + + +
+

+ By tapping $4.99 you agree to be bound by Witit’s{" "} + { + setPolicy("TERMS_OF_SERVICES"); + }} + > + Terms of Service + + ,{" "} + { + setPolicy("CONTENT_POLICYS"); + }} + > + Content Policy + + , and{" "} + { + setPolicy("PRIVACY_POLICYS"); + }} + > + Privacy Policy. + +

+
+
+ + {policy && ( + + {policy === "TERMS_OF_SERVICES" ? ( + { + setPolicy(null); + }} + /> + ) : policy === "PRIVACY_POLICYS" ? ( + { + setPolicy(null); + }} + /> + ) : policy === "CONTENT_POLICYS" ? ( + { + setPolicy(null); + }} + /> + ) : null} + + )} + + ); +}; + +export default LevelStartCreating; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/VerifyUserDialog.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/VerifyUserDialog.tsx new file mode 100644 index 0000000..86bd2f6 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/VerifyUserDialog.tsx @@ -0,0 +1,55 @@ +import React, { useEffect, useState } from "react"; +import CustomDialog from "../../../CustomDialog"; +import { useAuthContext } from "@/context/AuthContext"; +import WhatYouGet from "./levelUpDialogRightSection/WhatYouGet"; +import CustomButton from "../../../../CustomButton"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import LeftUserInfo from "./LeftUserInfo"; + +const VerifyUserDialog = () => { + const { setCustomDialogType, customDialogType } = useAuthContext(); + const [currentStep, setcurrentStep] = useState(0); + + return ( + +
+
+ +
+
+
+
+
+

+ Here’s what you get with Level Up AI +

+
{ + setCustomDialogType(null); + }} + > + +
+
+
+
+ {currentStep === 0 ? ( + + ) : null} + + { + setcurrentStep(currentStep + 1); + }} + /> +
+
+
+ + ); +}; + +export default VerifyUserDialog; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/index.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/index.tsx new file mode 100644 index 0000000..d7388b3 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/index.tsx @@ -0,0 +1,189 @@ +import Image from "next/image"; +import React, { useEffect, useState } from "react"; +import CustomDialog from "../../../CustomDialog"; +import CustomButton from "../../../../CustomButton"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import LevelStartCreating from "./LevelStartCreating"; +import WhatYouGet from "./levelUpDialogRightSection/WhatYouGet"; +import LeftUserInfo from "./LeftUserInfo"; +import ChooseYourIdentity from "./levelUpDialogRightSection/ChooseYourIdentity"; +import UploadYourID from "./levelUpDialogRightSection/UploadYourID"; +import ApplicationSubmitted from "./levelUpDialogRightSection/ApplicationSubmitted"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; + +import { useSelector } from "react-redux"; +import Crown from "@/utils/icons/levelUp/Crown"; +import { ImageState } from "@/types/post"; +import { RootState } from "@/redux/store"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import createCheckoutSession from "@/api/stripe/createCheckoutSession"; +import { useForm } from "react-hook-form"; +import { Store } from "@/types/user"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import createVerificationApplication from "@/api/user/CreateVerificationApplication"; + +const LevelUp = () => { + const { firebaseUser, sendNotification } = useAuthContext(); + const { setCustomDialogType } = useAuthContext(); + const user = useSelector((state: RootState) => state.user); + const [currentStep, setcurrentStep] = useState(0); + const [isButtonLoading, setisButtonLoading] = useState(false); + const [frontOfLicense, setfrontOfLicense] = useState(null); + const [backOfLicense, setbackOfLicense] = useState(null); + const [isDisabled, setisDisabled] = useState(false); + + const devaultvalue: Store = { + documentName: "", + documentImages: [], + }; + const { setValue, getValues, handleSubmit } = useForm({ + defaultValues: devaultvalue, + }); + console.log(backOfLicense); + useEffect(() => { + if (currentStep === 3) { + frontOfLicense?.imagePreview && backOfLicense?.imagePreview + ? setisDisabled(false) + : setisDisabled(true); + } + }, [currentStep, backOfLicense, frontOfLicense]); + const FillData = async (data: Store) => { + if (data.documentImages.length > 1) { + return; + } + setisButtonLoading(true); + const DocumentImagesList = [frontOfLicense?.file, backOfLicense?.file]; + const folderName = "generation_images"; + const PromiseDataList = await Promise.all( + DocumentImagesList.map((file) => { + return file + ? uploadImageToStorage({ + folderName, + file, + metadata: { + userId: firebaseUser?.uid, + }, + }) + : null; + }) + ); + data.documentImages = PromiseDataList; + const res = await createVerificationApplication({ + data, + user_id: user?.userId, + }); + if (res.status === 200) { + setcurrentStep(currentStep + 1); + return; + } + setisButtonLoading(false); + sendNotification({ type: "ERROR", message: res.error }); + }; + + return ( + +
+
e.preventDefault()}> + {currentStep === 0 ? ( + + ) : ( +
+
+ +
+ +
+ {currentStep < 2 ? ( +
+
{ + if (currentStep > 0) { + setcurrentStep(currentStep - 1); + setisDisabled(false); + } + }} + > + +
+
+ {" "} +
+

+ Here’s what you get with Level Up AI +

+
{ + setCustomDialogType(null); + }} + > + +
+
+
+
+
+ ) : null} + +
+ {currentStep === 1 ? ( + + ) : currentStep === 2 ? ( + + ) : currentStep === 3 ? ( + + ) : currentStep === 4 ? ( + + ) : null} +
+ {currentStep === 3 && ( + { + handleSubmit(FillData)(); + }} + /> + )} +
+
+ )} + +
+ + ); +}; + +export default LevelUp; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/ApplicationSubmitted.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/ApplicationSubmitted.tsx new file mode 100644 index 0000000..cdfeeba --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/ApplicationSubmitted.tsx @@ -0,0 +1,40 @@ +import Lottie from "lottie-react"; +import React from "react"; +import verificationSuccessLottie from "@/utils/lottie/successLottie.json"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { useAuthContext } from "@/context/AuthContext"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; + +const ApplicationSubmitted = () => { + const { setCustomDialogType } = useAuthContext(); + return ( +
+ {" "} +
+
{ + setCustomDialogType(null); + }} + > + +
+
+
+
+ +
+ +

+ Application has been submitted +

+

+ Thank you for submitting your verification application. You can expect + to hear back from us regarding the status within the next 48 hours. +

+
+
+ ); +}; + +export default ApplicationSubmitted; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/ChooseYourIdentity.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/ChooseYourIdentity.tsx new file mode 100644 index 0000000..a522d09 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/ChooseYourIdentity.tsx @@ -0,0 +1,157 @@ +import CustomCheckbox from "@/components/shared/CustomCheckbox"; +import React, { useEffect, useState } from "react"; +import { UseFormGetValues, UseFormSetValue } from "react-hook-form"; +import { Store } from "@/types/user"; +import CustomButton from "@/components/shared/CustomButton"; +import Crown from "@/utils/icons/levelUp/Crown"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +type document = { + name: string; + value: boolean; +}; + +type Props = { + setValue: UseFormSetValue; + setcurrentStep: React.Dispatch>; + setCustomDialogType: React.Dispatch>; + currentStep: number; + getValues: UseFormGetValues; +}; + +const ChooseYourIdentity = ({ + setValue, + setcurrentStep, + getValues, + currentStep, + setCustomDialogType, +}: Props) => { + const [DocumentList, setDocumentList] = useState([ + { name: "Driver’s License", value: false }, + { name: "Passport", value: false }, + { name: "National Id Card", value: false }, + { name: "State ID", value: false }, + ]); + const [isDisabled, setisDisabled] = useState(false); + const [getId, setgetId] = useState(null); + const handleCheked = (index: number) => { + const DocumentDeatailsList = DocumentList.map((val, id) => { + if (id === index) { + val.value = true; + setValue("documentName", val.name); + setgetId(val.name); + } else if (id !== index) { + val.value = false; + } + return val; + }); + setDocumentList(DocumentDeatailsList); + }; + + useEffect(() => { + let selectedName = getValues("documentName"); + if (!getId) { + const DocumentDeatailsList = DocumentList.map((val, id) => { + if (val.name === selectedName) { + val.value = true; + setValue("documentName", val.name); + setgetId(val.name); + } else if (val.name !== selectedName) { + val.value = false; + } + return val; + }); + setDocumentList(DocumentDeatailsList); + } + + getId ? setisDisabled(false) : setisDisabled(true); + }, [getId]); + + return ( + <> +
+
{ + if (currentStep > 0) { + setcurrentStep(currentStep - 1); + setisDisabled(false); + } + }} + > + +
+
+ {" "} +
+

+ + 1 + {" "} + Confirm Your Identity +

+ + 2 + +
{ + setCustomDialogType(null); + }} + > + +
+
+
+
+
+
+
+

Select Your ID

+

+ The ID you choose must include your name, photo & birthdate. It + won’t be shared on your profile. +

+ +
+ {DocumentList.map((val, id) => { + return ( + <> + {" "} + + {val.name} + { + handleCheked(id); + }} + checked={val.value} + /> + + + ); + })} +
+

+ *Your ID will be stored securely and deleted within 30 days after we + finish confirming your identity. We might use trusted service + providers to help review your information. +

+
+ { + setcurrentStep((prev) => prev + 1); + }} + /> +
+ + ); +}; + +export default ChooseYourIdentity; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/UploadYourID.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/UploadYourID.tsx new file mode 100644 index 0000000..a461803 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/UploadYourID.tsx @@ -0,0 +1,174 @@ +import CustomButton from "@/components/shared/CustomButton"; +import driverLicenseFront from "@/utils/images/driverLicenseFront.svg"; +import driverLicenseBack from "@/utils/images/driverLicenseBack.svg"; +import Image from "next/image"; +import React, { useEffect, useState } from "react"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { useAuthContext } from "@/context/AuthContext"; +import InputCropSingleImage from "@/components/shared/cropImage/singleCropImage/InputCropSingleImage"; +import { ImageState } from "@/types/post"; +import { DriverLicense } from "@/types/user"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +type stroelink = { + frontSide: null | string; + backSide: null | string; +}; +type User = { + selectedPhotos: string[]; + verificationImages: string[]; + audioURL: string | null; + generationSettings: { + bannedWords: string[]; + allowGenerationOnModel: boolean; + creditPerPhoto: number; + }; + classType: string; +}; +type Props = { + setfrontOfLicense: void | any; + setbackOfLicense: void | any; + frontOfLicense: null | ImageState; + backOfLicense: null | ImageState; + setCustomDialogType: React.Dispatch>; + setcurrentStep: React.Dispatch>; + currentStep: number; + setisDisabled: React.Dispatch>; +}; + +const UploadYourID = ({ + setfrontOfLicense, + setbackOfLicense, + frontOfLicense, + backOfLicense, + setCustomDialogType, + setcurrentStep, + currentStep, + setisDisabled, +}: Props) => { + return ( + <> +
+
{ + if (currentStep > 0) { + setcurrentStep(currentStep - 1); + setisDisabled(false); + } + }} + > + +
+
+ {" "} +
+

+ + 1 + {" "} + + 2 + {" "} + Confirm Your Identity +

+
{ + setCustomDialogType(null); + }} + > + +
+
+
+
+
+
+
+
+
+ + ), + placeholderTitle: ( + <> +
+

+ Upload front of Driver’s License +

+

+ Upload photo with a well light area, flat surface and + contrasting background. +

+
+ + + ), + }} + /> +
+
+ + ), + placeholderTitle: ( + <> +
+

+ Upload Back of Driver’s License +

+

+ Upload photo with a well light area, flat surface and + contrasting background. +

+
+ + + ), + }} + /> +
+
+
+
+ + ); +}; + +export default UploadYourID; diff --git a/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/WhatYouGet.tsx b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/WhatYouGet.tsx new file mode 100644 index 0000000..82ba3b0 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/levelUp/levelUpDialogRightSection/WhatYouGet.tsx @@ -0,0 +1,106 @@ +import React from "react"; +import SettingIcon from "@/utils/icons/levelUp/SettingIcon"; +import DollerIcon from "@/utils/icons/levelUp/DollerIcon"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import AlertIcon from "@/utils/icons/levelUp/AlertIcon"; +import FormIcon from "@/utils/icons/levelUp/FormIcon"; +import CustomButton from "@/components/shared/CustomButton"; +import Crown from "@/utils/icons/levelUp/Crown"; + +type Props = { + setcurrentStep: React.Dispatch>; +}; +const WhatYouGet = ({ setcurrentStep }: Props) => { + return ( +
+ {" "} +
+
+
+ +
+

+ Advanced{" "} + + creation tools + +

+
+
+
+ +
+

+ Earn cash{" "} + from your AI, posts, prompts or through messaging +

+
+
+
+ +
+

+ AI{" "} + yourself{" "} + into posts{" "} + on Witit +

+
+
+
+ +
+

+ Get{" "} + + 20 photo creations a day + {" "} + included with your subscription +

+
+
+
+ +
+

Get verified

+
+
+
+ +
+

+ + Create & View + {" "} + Content with less restriction +

+
{" "} +
+
+ +
+

+ Create AI photos of your{" "} + pet, brand{" "} + or in your{" "} + + art/photography style. + {" "} +

+
+
+ } + type="submit" + name={"Go Pro With 20% OFF"} + handleEvent={() => { + setcurrentStep((prev) => prev + 1); + }} + /> +
+ ); +}; + +export default WhatYouGet; diff --git a/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar.tsx b/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar.tsx new file mode 100644 index 0000000..e9f59d8 --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar.tsx @@ -0,0 +1,45 @@ +import { useAuthContext } from "@/context/AuthContext"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; +import { IconButton } from "@mui/material"; +import React from "react"; + +type Props = { + startIcon?: React.ReactElement; + title?: string; + isCloseIcon?: boolean; + onCancel?: () => void; +}; +const CustomDialogCommonTopBar = ({ + startIcon, + title, + isCloseIcon = true, + onCancel, +}: Props) => { + const { customDialogType, setCustomDialogType } = useAuthContext(); + + return ( +
+
+ {startIcon ? ( +
{startIcon}
+ ) : null} + +
{title}
+
+ { + if (onCancel) { + onCancel(); + } + }} + > + {isCloseIcon ? : null} + +
+ ); +}; + +export default CustomDialogCommonTopBar; diff --git a/components/shared/dialog/GlobalDialogs/index.tsx b/components/shared/dialog/GlobalDialogs/index.tsx new file mode 100644 index 0000000..b6cacce --- /dev/null +++ b/components/shared/dialog/GlobalDialogs/index.tsx @@ -0,0 +1,24 @@ +import LevelUp from "@/components/shared/dialog/GlobalDialogs/components/levelUp"; +import CreatePostDialog from "@/components/shared/dialog/GlobalDialogs/components/CreatePostDialog"; +import { useAuthContext } from "@/context/AuthContext"; +import React from "react"; +import CreditViewPromptDialog from "@/components/circle/CreditViewPromptDialog"; +import CreditDialogbox from "../../Topbar/components/CreditDialogbox"; + +const GlobalDialogs = () => { + const { customDialogType } = useAuthContext(); + + return ( +
+ {customDialogType === "LEVELUP" ? : null} + {customDialogType === "POST" ? : null} + {customDialogType === "CREDITS-VIEWPROMPT" ? ( + + ) : null} + {customDialogType === "CREDITS-GETCREDITS" ? : null} + {customDialogType === "CREDITS-WITHDRAW" ? : null} +
+ ); +}; + +export default GlobalDialogs; diff --git a/components/shared/drawer/CustomDrawer.tsx b/components/shared/drawer/CustomDrawer.tsx new file mode 100644 index 0000000..0c5c305 --- /dev/null +++ b/components/shared/drawer/CustomDrawer.tsx @@ -0,0 +1,97 @@ +import { useAuthContext } from "@/context/AuthContext"; +import React, { ReactNode, useEffect, useState } from "react"; +import ReportDialog from "../ReportDialog"; +import DrawerContext, { + useDrawerContext, +} from "./GlobalDrawers/context/DrawerContext"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { reportOffer } from "@/api/offering/reportOffer"; + +type Props = { + position: "LEFT" | "RIGHT"; + children: ReactNode; + isOpen?: boolean; + onCancel?: () => void; +} & Record; + +const CustomDrawer = ({ children, position, isOpen, onCancel }: Props) => { + const user = useSelector((state: RootState) => state.user); + + const { customDrawerType, sendNotification } = useAuthContext(); + const { reportOfferId, setReportOfferId } = useDrawerContext(); + + const [anchor, setAnchor] = useState<"LEFT" | "RIGHT">(position); + + useEffect(() => { + if (customDrawerType === "HYPE") { + setAnchor("RIGHT"); + } else if (customDrawerType === "CREATOR") { + setAnchor("LEFT"); + } + }, [customDrawerType]); + + const submitReport = async (inputText: string) => { + if (!user || !reportOfferId) return; + + const res = await reportOffer({ + user_id: user.userId, + body: { reportFor: inputText, offerId: reportOfferId }, + }); + + if (res.status === 200) { + setReportOfferId(null); + + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + return; + } + sendNotification({ type: "ERROR", message: res.error }); + }; + + return ( +
+ {customDrawerType !== null || isOpen ? ( +
+ ) : null} +
+ {children} +
+ {reportOfferId ? ( +
+ submitReport(inputText)} + onCancel={() => { + setReportOfferId(null); + }} + /> +
+ ) : null} +
+ ); +}; + +export default CustomDrawer; diff --git a/components/shared/drawer/GlobalDrawers/components/creator/components/CreatorItem.tsx b/components/shared/drawer/GlobalDrawers/components/creator/components/CreatorItem.tsx new file mode 100644 index 0000000..1d7e971 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/creator/components/CreatorItem.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import Image from "next/image"; +import temp1 from "@/utils/images/tempboy.jpg"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import { SearchCreator } from "@/types/user"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import { useRouter } from "next/router"; +import { redirectTouserProfile } from "@/service/shared/redirectTouserProfile"; +import { RootState } from "@/redux/store"; +import { useSelector } from "react-redux"; + +type Props = { + creator: SearchCreator; +}; +const CreatorItem = ({ creator }: Props) => { + const router = useRouter(); + const user = useSelector((state: RootState) => state.user); + + return ( +
{ + router.push(redirectTouserProfile(creator.userId, user?.userId)); + }} + > +
+
+ {/*
+ +
*/} + +
+ +
+
+

{creator.userName}

+ {creator.userType === "VERIFIED" ? ( +
+ +
+ ) : null} +
+

+ {creator.counts.followerCount} Members{" "} +

+
+
+ {/*
+

1

+
*/} +
+ ); +}; + +export default CreatorItem; diff --git a/components/shared/drawer/GlobalDrawers/components/creator/index.tsx b/components/shared/drawer/GlobalDrawers/components/creator/index.tsx new file mode 100644 index 0000000..eacd69d --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/creator/index.tsx @@ -0,0 +1,186 @@ +import React, { useEffect, useState } from "react"; +import CustomInputTextField from "../../../../CustomInputTextField"; +import SearchIcon from "@/utils/icons/topbar/SearchIcon"; +import CreatorIcon from "@/utils/icons/navbar/CreatorIcon"; +import { CircularProgress, Divider } from "@mui/material"; +import { theme } from "@/theme"; +import CreatorItem from "./components/CreatorItem"; +import { SearchCreator } from "@/types/user"; +import { useDebounceEffect } from "@/hooks/useDebounceEffect"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { useAuthContext } from "@/context/AuthContext"; +import { searchCreatorUser } from "@/api/user/searchCreatorUser"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { concatCreator } from "@/redux/slices/creatorListSlice"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { searchUserNotFound } from "@/utils/images/message"; + +type Res = { status: number; data: SearchCreator[]; error: any }; + +type GetCreatorsProps = { + search?: string | ""; + paginationInfo?: { + lastDocId: string; + searchScore: number; + followerCount: number; + }; + res?: Res; +}; +const Creator = () => { + const { sendNotification } = useAuthContext(); + + const creatorList = useSelector((state: RootState) => state.creators); + const user = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + const [search, setSearch] = useState(null); + const [hasMoreCreator, setHasMoreCreator] = useState(true); + + const debouncedSearch = useDebounceEffect(search, 2000); + const getCreatorUserList = async ({ paginationInfo }: GetCreatorsProps) => { + if (!user) return; + const res = await searchCreatorUser({ + user_id: user.userId, + limit: 20, + ...(paginationInfo && { paginationInfo }), + search: search && search.length > 1 ? search : "", + }); + + if (res.status === 200) { + console.log(res.data); + if (res.data.length < 20) { + setHasMoreCreator(false); + } + if (res.data.length > 0) { + if (paginationInfo?.lastDocId) { + dispatch(concatCreator([...creatorList, ...res.data])); + } else { + dispatch(concatCreator(res.data)); + } + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const fetchMoreUser = async () => { + const lastUser = creatorList[creatorList.length - 1]; + const lastDocId = lastUser?.userId; + const searchScore = lastUser?.searchScore; + const followerCount = lastUser?.counts.followerCount; + if (searchScore) + getCreatorUserList({ + paginationInfo: { lastDocId, searchScore, followerCount }, + }); + }; + + useEffect(() => { + if (search && search.length > 2) { + dispatch(concatCreator([])); + return; + } + }, [search, debouncedSearch]); + + useEffect(() => { + creatorList.length == 0 && getCreatorUserList({}); + }, []); + + useEffect(() => { + debouncedSearch !== null && getCreatorUserList({}); + setHasMoreCreator(true); + }, [debouncedSearch]); + + useEffect(() => { + if (search === "") { + getCreatorUserList({}); + return; + } + }, [search]); + return ( +
+
+
+
+
+ +
+

Creator

+
+ + ) => { + setSearch(e.target.value); + }} + StartIcon={ +
+ +
+ } + placeholder="Search Creator" + className="text-sm py-2 " + /> +
+ + +
+ + +
+ } + scrollableTarget="creatorScrollableDiv" + style={hasMoreCreator ? {} : { overflow: "hidden" }} + > + {creatorList.map((creator, index) => { + return ( +
+ + + {/* {index != creatorsList.length - 1 ? ( + + ) : null} */} +
+ ); + })} + +
+
+ {creatorList.length <= 0 && !hasMoreCreator && ( +
+ + +
+ } + title="No Creator Found" + description="Start Chatting with your witit friends!" + /> +
+ )} +
+ ); +}; + +export default Creator; diff --git a/components/shared/drawer/GlobalDrawers/components/hypes/components/Notifications/components/HypesItem.tsx b/components/shared/drawer/GlobalDrawers/components/hypes/components/Notifications/components/HypesItem.tsx new file mode 100644 index 0000000..5c16a42 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/hypes/components/Notifications/components/HypesItem.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { Activity } from "@/types/activity"; +import { profilePlaceholderImage } from "@/utils/images"; +import { getRecentTimeFromTimeStamp } from "@/service/shared/getRecentTimeFromTimeStamp"; + +type Props = { + notification: Activity; + isNew: boolean; +}; + +const HypesItem = ({ notification, isNew }: Props) => { + const { activity, createdAt } = notification; + + return ( +
+
+
+
+ +
+
+

+ {activity.title}{" "} + {activity.message ? ( + + {activity.message} + + ) : null} +

+

+ {getRecentTimeFromTimeStamp(createdAt)} +

+
+
+
+ ); +}; + +export default HypesItem; diff --git a/components/shared/drawer/GlobalDrawers/components/hypes/components/Notifications/index.tsx b/components/shared/drawer/GlobalDrawers/components/hypes/components/Notifications/index.tsx new file mode 100644 index 0000000..c554430 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/hypes/components/Notifications/index.tsx @@ -0,0 +1,151 @@ +import { getActivity } from "@/api/activity/getActivity"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { RootState } from "@/redux/store"; +import { Activity } from "@/types/activity"; +import { blockUserIllustrator } from "@/utils/images"; +import { CircularProgress } from "@mui/material"; +import router from "next/router"; +import { useEffect, useState } from "react"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { useSelector } from "react-redux"; +import HypesItem from "./components/HypesItem"; +import { useAuthContext } from "@/context/AuthContext"; +import { readActivity } from "@/api/activity/readActivity"; + +export const Notifications = () => { + const user = useSelector((state: RootState) => state.user); + + const { sendNotification, activityCounts } = useAuthContext(); + + const [hasMoreActivity, setHasMoreActivity] = useState(true); + const [activities, setActivities] = useState([]); + const [count, setCount] = useState(0); + + const getUserActivity = async ({ lastDocId }: { lastDocId?: string }) => { + if (!user) return; + const hypeAct = await getActivity({ + user_id: user.userId, + ...(lastDocId && { lastDocId }), + limit: 20, + }); + + if (hypeAct.status === 200) { + if (hypeAct?.data.length < 20) { + setHasMoreActivity(false); + } + if (hypeAct.data.length > 0) { + if (lastDocId) { + setActivities([...activities, ...hypeAct.data]); + } else { + setActivities(hypeAct.data); + + // read activity if unread count is greater than 0 + if (count > 0) { + const result = await readActivity({ user_id: user.userId }); + if (result.status !== 200) { + sendNotification({ type: "ERROR", message: result.error }); + } + } + } + } + } else { + sendNotification({ type: "ERROR", message: hypeAct.error }); + } + }; + + useEffect(() => { + setActivities([]); + getUserActivity({}); + }, []); + + useEffect(() => { + if (!activityCounts) return; + setCount(activityCounts.notification); + }, [activityCounts]); + + const fetchMoreActivity = async () => { + const lastDocId = activities[activities.length - 1].activityId; + getUserActivity({ lastDocId }); + }; + + const handleParems = (hype: Activity) => { + if ( + [ + "USER_GENERATION_NOTIFICATION", + "GENERATION_NOTIFICATION", + "CREATOR_GENERATION_NOTIFICATION", + ].includes(hype.activityType) + ) { + router.push("/create"); + } else if ( + hype.activityType === "POST_NOTIFICATION" && + hype.action.postId + ) { + router.push(`/discover/post?postId=${hype.action.postId}`); + } else if (hype.activityType === "CREATOR_NOTIFICATION") { + router.push("/setting"); + } else if ( + [ + "CREDIT_NOTIFICATION", + "QUESTION_NOTIFICATION", + "USER_NOTIFICATION", + ].includes(hype.activityType) + ) { + router.push("/profile"); + } + }; + + if (activities.length === 0 && !hasMoreActivity) + return ( +
+ + +
+ } + /> +
+ ); + + return ( +
+ + +
+ } + scrollableTarget="hypeScrollableDiv" + > +
+ {activities.map((notification, index) => { + return ( + <> +
{ + handleParems(notification); + }} + > + index} + /> +
+ {count === index + 1 ? ( +
+ ) : null} + + ); + })} +
+ +
+ ); +}; diff --git a/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferCreated/components/Offer.tsx b/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferCreated/components/Offer.tsx new file mode 100644 index 0000000..26e6472 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferCreated/components/Offer.tsx @@ -0,0 +1,290 @@ +import React, { SetStateAction, useState } from "react"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { Activity } from "@/types/activity"; +import { profilePlaceholderImage } from "@/utils/images"; +import { getRecentTimeFromTimeStamp } from "@/service/shared/getRecentTimeFromTimeStamp"; +import { Offer } from "@/types/offering"; +import CreditIcon from "@/utils/icons/topbar/CreditIcon"; +import dayjs from "dayjs"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { useAuthContext } from "@/context/AuthContext"; +import { getOfferNotifications } from "@/api/offering/getOfferNotifications"; +import { readOfferNotifications } from "@/api/offering/readOfferNotifications"; +import { CircularProgress } from "@mui/material"; +import { CalenderIcon } from "@/utils/icons/topbar/CalenderIcon"; +import CustomButton from "@/components/shared/CustomButton"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; + +const bottomDivContent = [ + { + status: "COMPLETED", + text: "Your offer has been Completed. If not you can report on this user.", + hasButton: true, + }, + { + status: "ACCEPTED", + text: "Your offer has been Accepted. Enjoy your offer!!", + hasButton: false, + }, +]; + +type HandleOfferActionsProps = { + type: "CANCEL" | "REPORT"; + offerId: string; +}; + +type Props = { + offer: Offer; + isNew: boolean; + isOpen: boolean; + handleSetCuuerntOfferId: (offerId: string | null) => void; + setOffers: React.Dispatch>; + handleOfferAction: ({ type, offerId }: HandleOfferActionsProps) => void; +}; + +type CurrentActivity = { + isFetched: boolean; + activities: Activity[]; +}; + +const OfferItem = ({ + offer, + isNew, + setOffers, + isOpen, + handleSetCuuerntOfferId, + handleOfferAction, +}: Props) => { + const user = useSelector((state: RootState) => state.user); + + const { sendNotification } = useAuthContext(); + + const { status, createdAt, offering } = offer; + const item = { + text: + status !== "CANCELLED_BY_USER" + ? status[0] + status.slice(1).toLowerCase() + : "Cancelled", + textColor: + status === "ACCEPTED" + ? "text-green-main" + : status === "COMPLETED" + ? "text-primary-main" + : status === "REPORTED" + ? "text-common-white" + : status === "REFUNDED" + ? "text-blue-light" + : status === "PENDING" + ? "text-orange-main" + : status === "REJECTED" || status === "CANCELLED_BY_USER" + ? "text-error-main" + : "", + bgColor: + status === "ACCEPTED" + ? "bg-green-main" + : status === "COMPLETED" + ? "bg-primary-main" + : status === "REPORTED" + ? "bg-common-white" + : status === "REFUNDED" + ? "bg-blue-light" + : status === "PENDING" + ? "bg-orange-main" + : status === "REJECTED" || status === "CANCELLED_BY_USER" + ? "bg-error-main" + : "", + }; + + const [currentActivity, setCurrentActivity] = useState({ + isFetched: false, + activities: [], + }); + + const getUserOfferNotification = async () => { + if (!user || currentActivity.isFetched) return; + + const result = await getOfferNotifications({ + user_id: user.userId, + offerId: offer.offerId, + limit: 20, + }); + + if (result.status === 200) { + setCurrentActivity({ isFetched: true, activities: result.data }); + + if (isNew) { + const result = await readOfferNotifications({ + user_id: user.userId, + offerId: offer.offerId, + }); + if (result.status !== 200) { + sendNotification({ type: "ERROR", message: result.error }); + } + setOffers((offers) => + offers.map((data) => { + if (data.offerId === offer.offerId) { + return { + ...data, + isActiveNotification: false, + }; + } + return data; + }) + ); + } + } else { + sendNotification({ type: "ERROR", message: result.error }); + } + }; + + const handleOpenOffer = () => { + if (!isOpen) { + getUserOfferNotification(); + handleSetCuuerntOfferId(offer.offerId); + } else { + handleSetCuuerntOfferId(null); + } + }; + + return ( + <> +
+
+
{ + handleOpenOffer(); + }} + > +
+
+ +
+
+
+

{offering.name}

+ {offering.completeOffers > 0 ? ( + + {offering.completeOffers + " Joiners"} + + ) : null} +
+
+ {item.text} +
+
+
+ {isOpen ? ( +
+
+
+
+ +
+

{offer.credit} Credits

+
+
+
+
+ +
+

+ {dayjs(offer.offerDate * 1000).format("DD MMM, YYYY")} +

+
+
+
+ {!currentActivity.isFetched ? ( +
+ +
+ ) : currentActivity.activities.length > 0 ? ( + currentActivity.activities.map((item, index) => { + const { activity } = item; + return ( +
+
+ +
+
+

+ {activity.title}{" "} + {activity.message ? ( + + {activity.message} + + ) : null} +

+

+ {getRecentTimeFromTimeStamp(createdAt)} +

+
+
+ ); + }) + ) : null} +
+
+ ) : null} +
+
+ {bottomDivContent.find((d) => d.status === offer.status) && isOpen ? ( +
+

+ {bottomDivContent.find((d) => d.status === offer.status)?.text} +

+ {bottomDivContent.find((d) => d.status === offer.status) + ?.hasButton ? ( + + +
+ } + className="py-1 px-6 text-sm bg-error-light w-max" + handleEvent={() => + handleOfferAction({ type: "REPORT", offerId: offer.offerId }) + } + /> + ) : null} +
+ ) : null} + {offer.status === "ACCEPTED" && offer.isReschedule ? ( +
+
+

+ Rescheduled on{" "} + {dayjs(offer.offerDate * 1000).format("DD MMM, YYYY")} +

+ + handleOfferAction({ type: "CANCEL", offerId: offer.offerId }) + } + /> +
+
+ ) : null} + + ); +}; + +export default OfferItem; diff --git a/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferCreated/index.tsx b/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferCreated/index.tsx new file mode 100644 index 0000000..08164e9 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferCreated/index.tsx @@ -0,0 +1,225 @@ +import { getActivity } from "@/api/activity/getActivity"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { RootState } from "@/redux/store"; +import { Activity } from "@/types/activity"; +import { blockUserIllustrator } from "@/utils/images"; +import { CircularProgress } from "@mui/material"; +import router from "next/router"; +import { useEffect, useState } from "react"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { useSelector } from "react-redux"; +import { useAuthContext } from "@/context/AuthContext"; +import { readActivity } from "@/api/activity/readActivity"; +import OfferItem from "./components/Offer"; +import { getCreatedOffers } from "@/api/offering/getCreatedOffers"; +import { Offer } from "@/types/offering"; +import CustomButton from "@/components/shared/CustomButton"; +import OutLinedAlertIcon from "@/utils/icons/shared/OutLinedAlertIcon"; +import dayjs from "dayjs"; +import ReportDialog from "@/components/shared/ReportDialog"; +import { reportOffer } from "@/api/offering/reportOffer"; +import { updateOfferAsUser } from "@/api/offering/updateOffer"; +import { useDrawerContext } from "../../../../context/DrawerContext"; + +type GetUserCreatedOffersProps = { + lastDocId?: string; + status?: "ACCEPTED" | "ALL"; +}; + +type StatusItem = { + status: "ALL" | "ACCEPTED"; + name: string; +}; + +const docLimit = 20; +const statusList: StatusItem[] = [ + { + status: "ALL", + name: "All Offers", + }, + { + status: "ACCEPTED", + name: "Active Offers", + }, +]; + +type HandleOfferActionsProps = { + type: "CANCEL" | "REPORT"; + offerId: string; +}; + +export const OfferCreated = () => { + const user = useSelector((state: RootState) => state.user); + + const { sendNotification, activityCounts } = useAuthContext(); + const { reportOfferId, setReportOfferId } = useDrawerContext(); + + const [hasMoreOffers, setHasMoreOffers] = useState(true); + const [offers, setOffers] = useState([]); + const [currentOpenOfferId, setCurrentOpenOfferId] = useState( + null + ); + const [activeTabStatus, setActiveTabStatus] = useState<"ALL" | "ACCEPTED">( + "ALL" + ); + + const getUserCreatedOffers = async ({ + lastDocId, + status, + }: GetUserCreatedOffersProps) => { + if (!user) return; + + const currentOffers = await getCreatedOffers({ + user_id: user.userId, + ...(lastDocId && { lastDocId }), + ...(status && { status }), + limit: docLimit, + }); + + if (currentOffers.status === 200) { + if (currentOffers?.data.length < docLimit) { + setHasMoreOffers(false); + } + if (currentOffers.data.length > 0) { + if (lastDocId) { + setOffers([...offers, ...currentOffers.data]); + } else { + setOffers(currentOffers.data); + } + } + } else { + sendNotification({ type: "ERROR", message: currentOffers.error }); + } + }; + + + const handleCancelOffer = async ({ offerId }: { offerId: string }) => { + if (!user) return; + + const res = await updateOfferAsUser({ + user_id: user.userId, + body: { status: "CANCELLED_BY_USER", offerId }, + }); + + if (res.status === 200) { + setOffers((prevOffers) => { + return prevOffers.map((offer) => { + if (offer.offerId === offerId) { + return { ...offer, status: "CANCELLED_BY_USER" }; + } + return offer; + }); + }); + + sendNotification({ + type: "SUCCESS", + message: "Offer Cancelled Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const fetchMoreActivity = async () => { + if (offers.length > 0) { + const lastDocId = offers[offers.length - 1].offerId; + getUserCreatedOffers({ lastDocId }); + } + }; + + const handleOfferAction = ({ type, offerId }: HandleOfferActionsProps) => { + switch (type) { + case "CANCEL": + handleCancelOffer({ offerId }); + break; + case "REPORT": + setReportOfferId(offerId); + break; + + default: + break; + } + type; + }; + + useEffect(() => { + setOffers([]); + setCurrentOpenOfferId(null); + setHasMoreOffers(true); + getUserCreatedOffers({ status: activeTabStatus }); + }, [activeTabStatus]); + + return ( +
+
+ {statusList.map((item, index) => ( +
setActiveTabStatus(item.status)} + > +
+ {item.name} +
+ {item.status === activeTabStatus ? ( +
+ ) : null} +
+ ))} +
+ {offers.length === 0 && !hasMoreOffers ? ( +
+ + +
+ } + /> +
+ ) : ( +
+ + +
+ } + scrollableTarget="offerCreatedScrollableDiv" + > +
+ {offers.map((offer, index) => { + return ( +
+ + setCurrentOpenOfferId(offerId) + } + handleOfferAction={handleOfferAction} + /> +
+ ); + })} +
+ +
+ )} +
+ ); +}; diff --git a/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferReceived/index.tsx b/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferReceived/index.tsx new file mode 100644 index 0000000..6293fd1 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/hypes/components/OfferReceived/index.tsx @@ -0,0 +1,3 @@ +export const OfferReceived = () => { + return
received
; +}; diff --git a/components/shared/drawer/GlobalDrawers/components/hypes/index.tsx b/components/shared/drawer/GlobalDrawers/components/hypes/index.tsx new file mode 100644 index 0000000..4fd48a0 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/components/hypes/index.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { useAuthContext } from "@/context/AuthContext"; +import CloseIcon from "@/utils/icons/shared/CloseIcon"; +import { Notifications } from "./components/Notifications"; +import { OfferCreated } from "./components/OfferCreated"; +import { OfferReceived } from "./components/OfferReceived"; + +const Hypes = () => { + const { setCustomDrawerType, customDrawerType } = + useAuthContext(); + + return ( +
+
+

+ {customDrawerType === "HYPE_NOTIFICATIONS" + ? "Notifications" + : customDrawerType === "HYPE_OFFER_CREATED" + ? "Offer Created" + : "Offer Received"} +

+
setCustomDrawerType(null)} + > + +
+
+ + {customDrawerType === "HYPE_NOTIFICATIONS" ? ( + + ) : customDrawerType === "HYPE_OFFER_CREATED" ? ( + + ) : ( + + )} +
+ ); +}; + +export default Hypes; diff --git a/components/shared/drawer/GlobalDrawers/context/DrawerContext.tsx b/components/shared/drawer/GlobalDrawers/context/DrawerContext.tsx new file mode 100644 index 0000000..a7fb4f0 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/context/DrawerContext.tsx @@ -0,0 +1,31 @@ +import { createContext, useContext, useState } from "react"; + +type ContextType = { + reportOfferId: string | null; + setReportOfferId: React.Dispatch>; +}; + +const defaultContext: ContextType = { + reportOfferId: null, + setReportOfferId: () => {}, +}; + +const Context = createContext(defaultContext); + +function DrawerContext({ children }: { children: React.ReactNode }) { + const [reportOfferId, setReportOfferId] = useState(null); + + return ( + + {children} + + ); +} + +export default DrawerContext; +export const useDrawerContext = () => useContext(Context); diff --git a/components/shared/drawer/GlobalDrawers/index.tsx b/components/shared/drawer/GlobalDrawers/index.tsx new file mode 100644 index 0000000..16d3365 --- /dev/null +++ b/components/shared/drawer/GlobalDrawers/index.tsx @@ -0,0 +1,41 @@ +import { useAuthContext } from "@/context/AuthContext"; +import React, { useEffect } from "react"; +import Hypes from "./components/hypes"; +import Creator from "./components/creator"; +import CustomDrawer from "../CustomDrawer"; +import DrawerContext from "./context/DrawerContext"; + +const GlobalDrawers = () => { + const { customDrawerType, setCustomDrawerType, discoverSearch } = + useAuthContext(); + + useEffect(() => { + if (discoverSearch?.search && discoverSearch.search.length > 0) { + setCustomDrawerType(null); + } + }, [discoverSearch]); + return ( + + {customDrawerType?.includes("HYPE") ? ( + setCustomDrawerType(null)} + > + + + ) : null} + {customDrawerType?.includes("CREATOR") ? ( + setCustomDrawerType(null)} + > + + + ) : null} + + ); +}; + +export default GlobalDrawers; diff --git a/components/shared/dropDown/IconDropDown.tsx b/components/shared/dropDown/IconDropDown.tsx new file mode 100644 index 0000000..1b1810c --- /dev/null +++ b/components/shared/dropDown/IconDropDown.tsx @@ -0,0 +1,77 @@ +import { theme } from "@/theme"; +import { DropDownItem } from "@/types"; +import ThreeVerticalDots from "@/utils/icons/circle/ThreeVerticalDots"; +import { IconButton } from "@mui/material"; +import { useState } from "react"; +import CustomDropDown from "./components/CustomDropDown"; + +type Position = { + vertical: "top" | "center" | "bottom"; + horizontal: "left" | "center" | "right"; +}; + +type Props = { + Icon?: JSX.Element; + position: Position; + handleItemSelect?: (type: string) => void; + listItems: DropDownItem[]; +} & Record; + +export const IconDropDown = ({ + Icon, + handleItemSelect, + listItems, + position, +}: Props) => { + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + + const handleClick = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + setAnchorEl(event.currentTarget); + return; + }; + + const handleCloseMenu = (event: React.MouseEvent) => { + event.stopPropagation(); + setAnchorEl(null); + }; + + return ( + <> + + {Icon ?? ( +
+ +
+ )} +
+ { + if (handleItemSelect) { + handleItemSelect(type); + setAnchorEl(null); + } + }} + anchorEl={anchorEl} + position={position} + /> + + ); +}; diff --git a/components/shared/dropDown/SelectDropDown.tsx b/components/shared/dropDown/SelectDropDown.tsx new file mode 100644 index 0000000..66b750a --- /dev/null +++ b/components/shared/dropDown/SelectDropDown.tsx @@ -0,0 +1,81 @@ +import { theme } from "@/theme"; +import ArrowDownIcon from "@/utils/icons/shared/ArrowDownIcon"; +import { Box, IconButton } from "@mui/material"; +import { useState } from "react"; +import CustomSelectDropDown from "./components/CustomSelectDropDown"; + +type Props = { + listItems: string[]; + Icon?: JSX.Element; + inputAreaStyle: string; + handleItemSelect?: (type: string) => void; +} & Record; + +export const SelectDropDown = ({ + getValues, + listItems, + inputAreaStyle, + handleItemSelect, +}: Props) => { + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + + const handleClick = (event: React.MouseEvent) => { + event.stopPropagation(); + setAnchorEl(event.currentTarget); + }; + + const handleClose = (event: React.MouseEvent) => { + event.stopPropagation(); + setAnchorEl(null); + }; + + return ( +
+ +

{getValues("subject")}

+ + + +
+ + { + setAnchorEl(null); + if (handleItemSelect) { + handleItemSelect(type); + } + }} + /> +
+ ); +}; diff --git a/components/shared/dropDown/components/CustomDropDown.tsx b/components/shared/dropDown/components/CustomDropDown.tsx new file mode 100644 index 0000000..6032661 --- /dev/null +++ b/components/shared/dropDown/components/CustomDropDown.tsx @@ -0,0 +1,159 @@ +import { Menu, MenuItem, PopoverVirtualElement } from "@mui/material"; +import { theme } from "@/theme"; +import { DropDownItem } from "@/types"; + +type Position = { + vertical: "top" | "center" | "bottom"; + horizontal: "left" | "center" | "right"; +}; + +type Props = { + listItems: DropDownItem[]; + isParentWidth?: boolean; + handleClose: (event: React.MouseEvent) => void; + handleItemSelect: (type: string) => void; + anchorEl: null | HTMLElement; + position?: Position; +} & Record; + +const CustomDropDown = (props: Props) => { + const { + listItems, + isParentWidth, + handleClose, + handleItemSelect, + anchorEl, + position, + ...restProps + } = props; + + const pos = position ? position.vertical[0] + position?.horizontal[0] : "tl"; + + return ( + .MuiPaper-root]:rounded-tr-none" + : pos === "bl" + ? "[&>.MuiPaper-root]:rounded-bl-none" + : pos === "br" + ? "[&>.MuiPaper-root]:rounded-br-none" + : "[&>.MuiPaper-root]:rounded-tl-none" + : "" + } + {...restProps} + > + {listItems.map((option, index) => ( +
+ { + e.stopPropagation(); + if (option.actionType) handleItemSelect(option.actionType); + }} + sx={{ + "&.Mui-selected": { + borderRadius: "4px", + backgroundColor: theme.palette.grey[700], + }, + "&.Mui-selected:hover": { + borderRadius: "4px", + backgroundColor: theme.palette.grey[700], + }, + "&:hover": { + backgroundColor: theme.palette.grey[700], + "& p": { + color: + option.actionType === "DELETE" + ? theme.palette.error.main + " !important" + : theme.palette.common.white + " !important", + }, + }, + }} + > +
+ {option.startIcon && ( +
+ {option.startIcon} +
+ )} +

+ {option.title} +

+ {option.endIcon && ( +
+ {option.endIcon} +
+ )} +
+
+ {index < listItems.length - 1 ? ( +
+ ) : null} +
+ ))} +
+ ); +}; + +export default CustomDropDown; + +{ + /*
+ +
*/ +} +{ + /* {list.length - 1 !== index ? ( + + ) : null} */ +} diff --git a/components/shared/dropDown/components/CustomSelectDropDown.tsx b/components/shared/dropDown/components/CustomSelectDropDown.tsx new file mode 100644 index 0000000..a916ded --- /dev/null +++ b/components/shared/dropDown/components/CustomSelectDropDown.tsx @@ -0,0 +1,105 @@ +import { Menu, MenuItem } from "@mui/material"; +import { theme } from "@/theme"; + +type Position = { + vertical: "top" | "center" | "bottom"; + horizontal: "left" | "center" | "right"; +}; + +type Props = { + listItems: string[]; + isParentWidth?: boolean; + handleClose: (event: React.MouseEvent) => void; + handleItemSelect: (type: string) => void; + anchorEl: null | HTMLElement; + position?: Position; +} & Record; + +const CustomSelectDropDown = (props: Props) => { + const { + listItems, + isParentWidth, + handleClose, + handleItemSelect, + anchorEl, + position, + ...restProps + } = props; + + return ( + + {listItems.map((option, index) => ( +
+ { + e.stopPropagation(); + if (option) handleItemSelect(option); + }} + > +
+ {option && ( +
+ {option} +
+ )} +
+
+ {index < listItems.length - 1 ? ( +
+ ) : null} +
+ ))} +
+ ); +}; + +export default CustomSelectDropDown; + +{ + /*
+ +
*/ +} +{ + /* {list.length - 1 !== index ? ( + + ) : null} */ +} diff --git a/context/AuthContext.tsx b/context/AuthContext.tsx new file mode 100644 index 0000000..327e3ab --- /dev/null +++ b/context/AuthContext.tsx @@ -0,0 +1,293 @@ +import { + Dispatch, + SetStateAction, + createContext, + useContext, + useEffect, + useRef, + useState, +} from "react"; +import { User, onAuthStateChanged } from "firebase/auth"; +import auth from "../utils/firebase/firebaseConfig"; +import { useDispatch, useSelector } from "react-redux"; +import { AmountPerCredit, ImageInfo } from "@/types"; +import { generate } from "@/redux/slices/messageSlice"; +import { useRouter } from "next/router"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import { getUser } from "@/api/user/getUser"; +import { RootState, clearAll } from "@/redux/store"; +import { firebaseLogout } from "@/service/firebase/auth"; +import { SendNotification } from "@/types/common"; +import { setReduxUser, updateReduxUser } from "@/redux/slices/userSlice"; +import { GetAiGeneration, PostAiGeneration } from "@/types/ai"; +import { getAmountFromCredit } from "@/api/stripe/getAmountFromCredit"; +import { io } from "socket.io-client"; +import { ReduxUser } from "@/types/user"; +import { ActivityCounts } from "@/types/activity"; + +type MyContextType = { + setToLogout: () => void; + setGenerationPost: React.Dispatch< + React.SetStateAction + >; + firebaseUser: User | null; + generationPost: GetAiGeneration | null; + setFirebaseUser: React.Dispatch>; + sendNotification: ({ type, message }: SendNotification) => void; + customDrawerType: string | null; + setCustomDrawerType: React.Dispatch>; + customDialogType: string | null; + setCustomDialogType: React.Dispatch>; + lastVisitedPage: string | null; + setLastVisitedPage: React.Dispatch>; + discoverSearch: { search: string | null; isSearched?: boolean }; + setDiscoverSearch: React.Dispatch< + React.SetStateAction<{ search: string | null; isSearched?: boolean }> + >; + croppingImage: { + image: ImageInfo; + index: number; + isShowGrid?: boolean; + }; + setCroppingImage: React.Dispatch< + React.SetStateAction<{ + image: ImageInfo; + index: number; + isShowGrid?: boolean; + }> + >; + amountPerCredit: AmountPerCredit; + setAmountPerCredit: Dispatch>; + activityCounts: ActivityCounts; +}; + +const defaultContext: MyContextType = { + setToLogout: () => {}, + firebaseUser: null, + setFirebaseUser: () => {}, + sendNotification: () => {}, + customDrawerType: null, + setCustomDrawerType: () => {}, + customDialogType: null, + setCustomDialogType: () => {}, + lastVisitedPage: null, + setLastVisitedPage: () => {}, + discoverSearch: { search: null, isSearched: false }, + setDiscoverSearch: () => {}, + croppingImage: { ...defaultImageConstant, isShowGrid: false }, + setCroppingImage: () => {}, + setGenerationPost: () => {}, + generationPost: null, + amountPerCredit: { + add: 0, + withdraw: 0, + }, + setAmountPerCredit: () => {}, + activityCounts: { + notification: 0, + offerCreated: 0, + offerReceived: 0, + }, +}; + +const Context = createContext(defaultContext); + +function AuthContext({ children }: { children: React.ReactNode }) { + const dispatch = useDispatch(); + const { asPath, push, pathname } = useRouter(); + const currentPath = useRef(asPath); + const router = useRouter(); + + const reduxUser = useSelector((state: RootState) => state.user); + + const [firebaseUser, setFirebaseUser] = useState(null); + const [customDrawerType, setCustomDrawerType] = useState(null); + const [customDialogType, setCustomDialogType] = useState(null); + const [lastVisitedPage, setLastVisitedPage] = useState(null); + const [activityCounts, setActivityCounts] = useState({ + notification: 0, + offerCreated: 0, + offerReceived: 0, + }); + const [generationPost, setGenerationPost] = useState( + null + ); + const [discoverSearch, setDiscoverSearch] = useState<{ + search: string | null; + isSearched?: boolean; + }>({ search: null, isSearched: false }); + const [croppingImage, setCroppingImage] = useState<{ + image: ImageInfo; + index: number; + isShowGrid?: boolean; + }>({ ...defaultImageConstant, isShowGrid: false }); + const [amountPerCredit, setAmountPerCredit] = useState({ + add: 0, + withdraw: 0, + }); + + const sendNotification = ({ type, message }: SendNotification) => { + dispatch( + generate({ + type, + message: message ?? null, + }) + ); + }; + + const getUserData = async ({ userId }: { userId: string }) => { + const user = await getUser(userId); + + if (user.status === 200) { + dispatch(setReduxUser(user.data)); + return; + } + sendNotification({ type: "ERROR", message: user.error }); + }; + + useEffect(() => { + setLastVisitedPage(currentPath.current); + currentPath.current = asPath; + }, [asPath]); + + useEffect(() => { + if (!firebaseUser && !reduxUser) { + router.push(appConstant.pageRoute.login); + } + + if (firebaseUser && reduxUser) { + getUserData({ userId: firebaseUser.uid }); + } + }, [firebaseUser]); + + useEffect(() => { + const unsubscribe = onAuthStateChanged(auth, (currentuser) => { + if (currentuser) { + setFirebaseUser(currentuser); + } + }); + return () => { + unsubscribe(); + }; + }, []); + + useEffect(() => { + if ( + currentPath.current !== "/discover" && + discoverSearch && + discoverSearch?.search && + discoverSearch?.search.length > 0 && + discoverSearch.isSearched === false + ) { + router.push(appConstant.pageRoute.discover); + } + }, [currentPath, discoverSearch]); + + useEffect(() => { + if (discoverSearch.isSearched && currentPath.current !== "/discover") { + setDiscoverSearch({ search: null, isSearched: false }); + } + }, [currentPath.current]); + + const setToLogout = async () => { + sendNotification({ type: "LOADING" }); + const res = await firebaseLogout(); + if (res.status === 200) { + dispatch(clearAll()); + setFirebaseUser(null); + sendNotification({ type: "REMOVE" }); + + console.log("first"); + + router.push(appConstant.pageRoute.login); + } else { + console.log(res.error); + sendNotification({ type: "ERROR", message: res.error }); + } + }; + useEffect(() => { + window.addEventListener("online", () => console.log("Became online")); + window.addEventListener("offline", () => console.log("Became offline")); + }, []); + useEffect(() => { + if (!firebaseUser) return; + const getCreditAmount = async () => { + const withdrawalRes = await getAmountFromCredit({ + credit: 1, + actionType: "WITHDRAWAL", + user_id: firebaseUser.uid, + }); + const addRes = await getAmountFromCredit({ + credit: 1, + actionType: "ADD", + user_id: firebaseUser.uid, + }); + if (withdrawalRes.status === 200 || addRes.status === 200) { + const data = { + add: addRes.data.amount || 0, + withdraw: withdrawalRes.data.amount || 0, + }; + setAmountPerCredit(data); + } + }; + getCreditAmount(); + }, [firebaseUser]); + + useEffect(() => { + if (!reduxUser) return; + + const socket = io(appConstant.backendUrl, { + path: "/socket.io", + query: { + userId: reduxUser.userId, + }, + transports: ["websocket"], + }); + + socket.on("User", (user: Partial) => { + dispatch(updateReduxUser(user)); + }); + + socket.on("ActivityCounts", (counts: ActivityCounts) => { + setActivityCounts(counts); + }); + + return () => { + socket.disconnect(); + }; + }, []); + + return ( + + {children} + + ); +} + +export default AuthContext; + +export const useAuthContext = () => useContext(Context); diff --git a/context/Wrapper.tsx b/context/Wrapper.tsx new file mode 100644 index 0000000..e84c2e1 --- /dev/null +++ b/context/Wrapper.tsx @@ -0,0 +1,98 @@ +import { theme } from "@/theme"; +import { + StyledEngineProvider, + ThemeProvider, + useMediaQuery, +} from "@mui/material"; +import { useSelector } from "react-redux"; +import { RootState } from "../redux/store"; +import localFont from "@next/font/local"; +import Navbar from "@/components/shared/Navbar"; +import { useRouter } from "next/router"; +import Topbar from "@/components/shared/Topbar"; +import { useEffect } from "react"; +import { useAuthContext } from "./AuthContext"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; +import GlobalDialogs from "@/components/shared/dialog/GlobalDialogs"; +import GlobalDrawers from "@/components/shared/drawer/GlobalDrawers"; +import { isMobile } from "react-device-detect"; +import MobileScreen from "@/components/shared/MobileScreen"; +import Loader from "@/components/shared/Loader"; + +// const poppins = Poppins({ +// weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"], +// subsets: ["latin"], +// preload: true, +// }); +const poppins = localFont({ + src: "../public/fonts/Poppins-Regular.ttf", +}); + +const { small, medium } = appConstant.drawerWidth; + +const withoutNavPaths = ["/", "/account-setup", "/app/subscription", "/test"]; // put `/` before every pathname + +const Wrapper = ({ children }: any) => { + const router = useRouter(); + const reduxUser = useSelector((state: RootState) => state.user); + + const { setCustomDrawerType, setCustomDialogType, firebaseUser } = + useAuthContext(); + + useEffect(() => { + setCustomDrawerType(null); + setCustomDialogType(null); + }, [children]); + + return ( + + + +
+ {withoutNavPaths.includes(router.pathname) ? ( +
+ {children} +
+ ) : ( + <> + {!reduxUser ? ( + + ) : ( + <> + {isMobile ? ( +
+ +
+ ) : ( +
+
+ {/* don't remove this div */} +
+ +
+
+ +
+ {children} + + +
+
+
+
+ )} + + )} + + )} +
+
+
+ ); +}; + +export default Wrapper; diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..f93a9ff --- /dev/null +++ b/firebase.json @@ -0,0 +1,12 @@ +{ + "hosting": { + "source": ".", + "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/hooks/useDebounceEffect.ts b/hooks/useDebounceEffect.ts new file mode 100644 index 0000000..0a70f3e --- /dev/null +++ b/hooks/useDebounceEffect.ts @@ -0,0 +1,23 @@ +import { useEffect, useState } from "react"; + +export function useDebounceEffect( + // fn: () => void, + value: T, + waitTime?: 2000 + // deps?: DependencyList +) { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timeOut = setTimeout(() => { + // fn.apply(undefined); + setDebouncedValue(value); + }, waitTime); + + return () => { + clearTimeout(timeOut); + }; + }, [value, waitTime]); + + return debouncedValue; +} diff --git a/hooks/useIsVisible.ts b/hooks/useIsVisible.ts new file mode 100644 index 0000000..6929ffa --- /dev/null +++ b/hooks/useIsVisible.ts @@ -0,0 +1,20 @@ +import { MutableRefObject, useEffect, useState } from "react"; + +export function useIsVisible(ref: MutableRefObject) { + const [isIntersecting, setIntersecting] = useState(false); + + useEffect(() => { + if (!ref.current) return; + + const observer = new IntersectionObserver(([entry]) => + setIntersecting(entry.isIntersecting) + ); + + observer.observe(ref.current); + return () => { + observer.disconnect(); + }; + }, [ref]); + + return isIntersecting; +} diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..47a373e --- /dev/null +++ b/next.config.js @@ -0,0 +1,19 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + webpack(config) { + config.experiments = { ...config.experiments, topLevelAwait: true }; + return config; + }, + reactStrictMode: true, + images: { + unoptimized: true, + remotePatterns: [ + { + protocol: "https", + hostname: "**", + }, + ], + }, +}; + +module.exports = nextConfig; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3a21b00 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8404 @@ +{ + "name": "witit-web", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "witit-web", + "version": "0.1.0", + "dependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@firebase/storage-types": "^0.8.0", + "@hookform/resolvers": "^3.1.0", + "@mui/icons-material": "^5.11.16", + "@mui/lab": "^5.0.0-alpha.142", + "@mui/material": "^5.14.10", + "@mui/x-date-pickers": "^6.2.1", + "@next/font": "^14.1.0", + "@reduxjs/toolkit": "^1.9.5", + "@types/node": "18.15.11", + "@types/react": "18.0.35", + "@types/react-dom": "18.0.11", + "autoprefixer": "10.4.14", + "axios": "^1.3.6", + "bson": "^6.2.0", + "dayjs": "^1.11.7", + "eslint": "8.38.0", + "eslint-config-next": "13.3.0", + "firebase": "^9.20.0", + "firebase-admin": "^11.7.0", + "lottie-react": "^2.4.0", + "next": "13.3.0", + "postcss": "8.4.22", + "react": "18.2.0", + "react-blurhash": "^0.3.0", + "react-device-detect": "^2.2.3", + "react-dom": "18.2.0", + "react-dropzone": "^14.2.3", + "react-easy-crop": "^4.7.5", + "react-hook-form": "^7.43.9", + "react-hot-toast": "^2.4.0", + "react-infinite-scroll-component": "^6.1.0", + "react-outside-click-handler": "^1.3.0", + "react-redux": "^8.0.5", + "react-slick": "^0.29.0", + "redux-persist": "^6.0.0", + "sharp": "^0.32.1", + "slick-carousel": "^1.8.1", + "socket.io-client": "^4.7.2", + "tailwindcss": "3.3.1", + "typescript": "5.0.4" + }, + "devDependencies": { + "@types/react-datepicker": "^4.10.0", + "@types/react-outside-click-handler": "^1.3.3", + "@types/react-slick": "^0.23.10" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "optional": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.10.8", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.8.tgz", + "integrity": "sha512-gxNky50AJL3AlkbjvTARiwAqei6/tNUxDZPSKd+3jqWVM3AmdVTTdpjHorR/an/M0VJqdsuq5oGcFH+rjtyujQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.1.4" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.10.8", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.8.tgz", + "integrity": "sha512-ZfGfiABtJ1P1OXqOBsW08EgCDp5fK6C5I8hUJauc/VcJBGSzqAirMnFslhFWnZJ/w5HxPI36XbvMV0l4KZHl+w==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.8", + "@emotion/cache": "^11.10.8", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.10.8", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.8.tgz", + "integrity": "sha512-gow0lF4Uw/QEdX2REMhI8v6wLOabPKJ+4HKNF0xdJ2DJdznN6fxaXpQOx6sNkyBhSUL558Rmcu1Lq/MYlVo4vw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.8", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz", + "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", + "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", + "dependencies": { + "text-decoding": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.0.tgz", + "integrity": "sha512-Locv8gAqx0e+GX/0SI3dzmBY5e9kjVDtD+3zCFLJ0tH2hJwuCAiL+5WkHuxKj92rqQj/rvkBUCfA1ewlX2hehg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.6.tgz", + "integrity": "sha512-4MqpVLFkGK7NJf/5wPEEP7ePBJatwYpyjgJ+wQHQGHfzaCDgntOnl9rL2vbVGGKCnRqWtZDIWhctB86UWXaX2Q==", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-types": "0.8.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.0.tgz", + "integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==" + }, + "node_modules/@firebase/app": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.9.tgz", + "integrity": "sha512-8jzuHtQ/t9XqK+0IAQ/lpylVYzXGKIUKm6U3v7LWor+MGIm+9Ucn+hbrd2iBjH8qfmNrjnQnmf7sWBbdSa54oA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.7.0.tgz", + "integrity": "sha512-y0raLJpEtiL+wonfInFMaSfBV/EDvr356ZHMWbpr5F7fR0/I3cC0h7U6SKpKhrbSHJ0fOYIe0xbih20KTlpcnA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.6.tgz", + "integrity": "sha512-azHAeHi9igoaIo04E6Yfuc7aIbWoWuBXuqjyYyWbeCc8Zz/NfJvIAgmXugN4LdxsHJ7XGlZTvwJ6YaYROdSa7A==", + "dependencies": { + "@firebase/app-check": "0.7.0", + "@firebase/app-check-types": "0.5.0", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.2.0.tgz", + "integrity": "sha512-+3PQIeX6/eiVK+x/yg8r6xTNR97fN7MahFDm+jiQmDjcyvSefoGuTTNQuuMScGyx3vYUBeZn+Cp9kC0yY/9uxQ==" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.0.tgz", + "integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==" + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.9.tgz", + "integrity": "sha512-XdnkHNK3XdPrwChmuSJHDA6eYmo2KLAtaAG1SJLGMQ+n+S5/UcufmDkw9GvPh93H1xhPRAwd/vKdjHmE7xp3Zw==", + "dependencies": { + "@firebase/app": "0.9.9", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", + "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + }, + "node_modules/@firebase/auth": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.23.1.tgz", + "integrity": "sha512-QubckPA5Ad92HiY20szjdH7EnFxL8gsZzRLyNCmO2oqebVAVuh9pJp6Zb8EA+P/AuMQYMBo6rQ3oIHi9gUCstg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.4.1.tgz", + "integrity": "sha512-wCw+6Jz7zCWzMA2bN8vphqEUmxuIFxHfBJiF3rKFTCEFPPXG4ulIcmMT98uuZVVq4xDPk/hxm105xwHBFAwBng==", + "dependencies": { + "@firebase/auth": "0.23.1", + "@firebase/auth-types": "0.12.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", + "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.0.tgz", + "integrity": "sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", + "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "dependencies": { + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", + "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", + "dependencies": { + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", + "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/database": "0.14.4", + "@firebase/database-types": "0.10.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", + "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "dependencies": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.3" + } + }, + "node_modules/@firebase/firestore": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-3.11.0.tgz", + "integrity": "sha512-r9qUbjuIKOXAVYwqZaamgXuUJBuV8I2X0Kao5PUxQAPueV2mRapdIlby6awYgjknE8kq1Tlys5Nf5/TV6WtnAg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "@firebase/webchannel-wrapper": "0.10.0", + "@grpc/grpc-js": "~1.7.0", + "@grpc/proto-loader": "^0.6.13", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.8.tgz", + "integrity": "sha512-VrTckDEVBqFWFsHGVdQgCb0Tht/Rrg/nKFp2aat0FaIjr8A9t4Pfcuu32Py25SbiCnr98pyh3RmVYs0kbF/lCA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/firestore": "3.11.0", + "@firebase/firestore-types": "2.5.1", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-2.5.1.tgz", + "integrity": "sha512-xG0CA6EMfYo8YeUxC8FeDzf6W3FX1cLlcAGBYV6Cku12sZRI81oWcu61RSKM66K6kUENP+78Qm8mvroBcm1whw==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.9.4.tgz", + "integrity": "sha512-3H2qh6U+q+nepO5Hds+Ddl6J0pS+zisuBLqqQMRBHv9XpWfu0PnDHklNmE8rZ+ccTEXvBj6zjkPfdxt6NisvlQ==", + "dependencies": { + "@firebase/app-check-interop-types": "0.2.0", + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.4.tgz", + "integrity": "sha512-kxVxTGyLV1MBR3sp3mI+eQ6JBqz0G5bk310F8eX4HzDFk4xjk5xY0KdHktMH+edM2xs1BOg0vwvvsAHczIjB+w==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/functions": "0.9.4", + "@firebase/functions-types": "0.6.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.0.tgz", + "integrity": "sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==" + }, + "node_modules/@firebase/installations": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.4.tgz", + "integrity": "sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.4.tgz", + "integrity": "sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/installations-types": "0.5.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.0.tgz", + "integrity": "sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/installations/node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, + "node_modules/@firebase/logger": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", + "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.4.tgz", + "integrity": "sha512-6JLZct6zUaex4g7HI3QbzeUrg9xcnmDAPTWpkoMpd/GoSVWH98zDoWXMGrcvHeCAIsLpFMe4MPoZkJbrPhaASw==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.3", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.4.tgz", + "integrity": "sha512-lyFjeUhIsPRYDPNIkYX1LcZMpoVbBWXX4rPl7c/rqc7G+EUea7IEtSt4MxTvh6fDfPuzLn7+FZADfscC+tNMfg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/messaging": "0.12.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz", + "integrity": "sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==" + }, + "node_modules/@firebase/messaging/node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, + "node_modules/@firebase/performance": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.4.tgz", + "integrity": "sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.4.tgz", + "integrity": "sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/performance": "0.6.4", + "@firebase/performance-types": "0.2.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.0.tgz", + "integrity": "sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==" + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.4.tgz", + "integrity": "sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.4.tgz", + "integrity": "sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-types": "0.3.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz", + "integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==" + }, + "node_modules/@firebase/storage": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.11.2.tgz", + "integrity": "sha512-CtvoFaBI4hGXlXbaCHf8humajkbXhs39Nbh6MbNxtwJiCqxPy9iH3D3CCfXAvP0QvAAwmJUTK3+z9a++Kc4nkA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.2.tgz", + "integrity": "sha512-wvsXlLa9DVOMQJckbDNhXKKxRNNewyUhhbXev3t8kSgoCotd1v3MmqhKKz93ePhDnhHnDs7bYHy+Qa8dRY6BXw==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/storage": "0.11.2", + "@firebase/storage-types": "0.8.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.0.tgz", + "integrity": "sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", + "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.0.tgz", + "integrity": "sha512-2I8y+vJVrPfPFJrnRGpao1Qc2Gu7wmYoo5ed2s5zK/DUGgcyY1Yr/xC0YdnKM4pi7rG3HqwW9ehAKUXoTMLdoA==" + }, + "node_modules/@floating-ui/core": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.4.1.tgz", + "integrity": "sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==", + "dependencies": { + "@floating-ui/utils": "^0.1.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.1.tgz", + "integrity": "sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==", + "dependencies": { + "@floating-ui/core": "^1.4.1", + "@floating-ui/utils": "^0.1.1" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.2.tgz", + "integrity": "sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==", + "dependencies": { + "@floating-ui/dom": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz", + "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==" + }, + "node_modules/@google-cloud/firestore": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.5.0.tgz", + "integrity": "sha512-U0QwG6pEQxO5c0v0eUylswozmuvlvz7iXSW+I18jzqR2hAFrUq2Weu1wm3NaH8wGD4ZL7W9Be4cMHG5CYU8LuQ==", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "functional-red-black-tree": "^1.0.1", + "google-gax": "^3.5.7", + "protobufjs": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@google-cloud/firestore/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "optional": true + }, + "node_modules/@google-cloud/firestore/node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@google-cloud/paginator": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "optional": true, + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", + "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", + "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@google-cloud/storage": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.9.5.tgz", + "integrity": "sha512-fcLsDA8YKcGuqvhk0XTjJGVpG9dzs5Em8IcUjSjspYvERuHYqMy9CMChWapSjv3Lyw//exa3mv4nUxPlV93BnA==", + "optional": true, + "dependencies": { + "@google-cloud/paginator": "^3.0.7", + "@google-cloud/projectify": "^3.0.0", + "@google-cloud/promisify": "^3.0.0", + "abort-controller": "^3.0.0", + "async-retry": "^1.3.3", + "compressible": "^2.0.12", + "duplexify": "^4.0.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "gaxios": "^5.0.0", + "google-auth-library": "^8.0.1", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "retry-request": "^5.0.0", + "teeny-request": "^8.0.0", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@google-cloud/storage/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.7.3.tgz", + "integrity": "sha512-H9l79u4kJ2PVSxUNA08HMYAnUBLj9v6KjYQ7SQ71hOZcEXhShE/y5iQCesP8+6/Ik/7i2O0a10bPquIcYfufog==", + "dependencies": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.6.tgz", + "integrity": "sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw==", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/grpc-js/node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/protobufjs/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/@grpc/proto-loader": { + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.13.tgz", + "integrity": "sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.11.3", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@hookform/resolvers": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.1.0.tgz", + "integrity": "sha512-z0A8K+Nxq+f83Whm/ajlwE6VtQlp/yPHZnXw7XWVPIGm1Vx0QV8KThU3BpbBRfAZ7/dYqCKKBNnQh85BkmBKkA==", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", + "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "optional": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.13", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.13.tgz", + "integrity": "sha512-uC0l97pBspfDAp+iz2cJq8YZ8Sd9i73V77+WzUiOAckIVEyCm5dyVDZCCO2/phmzckVEeZCGcytybkjMQuhPQw==", + "dependencies": { + "@babel/runtime": "^7.22.10", + "@emotion/is-prop-valid": "^1.2.1", + "@floating-ui/react-dom": "^2.0.1", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.7", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.14.10", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.10.tgz", + "integrity": "sha512-kPHu/NhZq1k+vSZR5wq3AyUfD4bnfWAeuKpps0+8PS7ZHQ2Lyv1cXJh+PlFdCIOa0PK98rk3JPwMzS8BMhdHwQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.11.16", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.16.tgz", + "integrity": "sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/lab": { + "version": "5.0.0-alpha.142", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.142.tgz", + "integrity": "sha512-JDrT5G3QBZ0nzkKMFWzJY5KN8WcyDx4p7qOjg6hs7yKLq90VSdsqIOmyhvWDxJR7zPNQjo0WRYBAaRaQ5FlGxg==", + "dependencies": { + "@babel/runtime": "^7.22.10", + "@mui/base": "5.0.0-beta.13", + "@mui/system": "^5.14.7", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.7", + "clsx": "^2.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/lab/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/material": { + "version": "5.14.10", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.10.tgz", + "integrity": "sha512-ejFMppnO+lzBXpzju+N4SSz0Mhmi5sihXUGcr5FxpgB6bfUP0Lpe32O0Sw/3s8xlmLEvG1fqVT0rRyAVMlCA+A==", + "dependencies": { + "@babel/runtime": "^7.22.15", + "@mui/base": "5.0.0-beta.16", + "@mui/core-downloads-tracker": "^5.14.10", + "@mui/system": "^5.14.10", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.10", + "@types/react-transition-group": "^4.4.6", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/@mui/base": { + "version": "5.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.16.tgz", + "integrity": "sha512-OYxhC81c9bO0wobGcM8rrY5bRwpCXAI21BL0P2wz/2vTv4ek7ALz9+U5M8wgdmtRNUhmCmAB4L2WRwFRf5Cd8Q==", + "dependencies": { + "@babel/runtime": "^7.22.15", + "@floating-ui/react-dom": "^2.0.2", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.10", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/private-theming": { + "version": "5.14.10", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.10.tgz", + "integrity": "sha512-f67xOj3H06wWDT9xBg7hVL/HSKNF+HG1Kx0Pm23skkbEqD2Ef2Lif64e5nPdmWVv+7cISCYtSuE2aeuzrZe78w==", + "dependencies": { + "@babel/runtime": "^7.22.15", + "@mui/utils": "^5.14.10", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.14.10", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.10.tgz", + "integrity": "sha512-EJckxmQHrsBvDbFu1trJkvjNw/1R7jfNarnqPSnL+jEQawCkQIqVELWLrlOa611TFtxSJGkdUfCFXeJC203HVg==", + "dependencies": { + "@babel/runtime": "^7.22.15", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.14.10", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.10.tgz", + "integrity": "sha512-QQmtTG/R4gjmLiL5ECQ7kRxLKDm8aKKD7seGZfbINtRVJDyFhKChA1a+K2bfqIAaBo1EMDv+6FWNT1Q5cRKjFA==", + "dependencies": { + "@babel/runtime": "^7.22.15", + "@mui/private-theming": "^5.14.10", + "@mui/styled-engine": "^5.14.10", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.10", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/system/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/types": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", + "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.14.10", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.10.tgz", + "integrity": "sha512-Rn+vYQX7FxkcW0riDX/clNUwKuOJFH45HiULxwmpgnzQoQr3A0lb+QYwaZ+FAkZrR7qLoHKmLQlcItu6LT0y/Q==", + "dependencies": { + "@babel/runtime": "^7.22.15", + "@types/prop-types": "^15.7.5", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.3.0.tgz", + "integrity": "sha512-Qux/nRGb0HueZU4L0h1QEqmORCrpgLukWWhG1Im6cFCmLtZbBey/0JuAFRa+OgvIXgGktDt8SY/FYsRkfGt2TQ==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.12.0", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/base": "^5.0.0-alpha.87", + "@mui/material": "^5.8.6", + "@mui/system": "^5.8.0", + "date-fns": "^2.25.0", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.2 || ^18.0.0", + "react-dom": "^17.0.2 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@next/env": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.3.0.tgz", + "integrity": "sha512-AjppRV4uG3No7L1plinoTQETH+j2F10TEnrMfzbTUYwze5sBUPveeeBAPZPm8OkJZ1epq9OyYKhZrvbD6/9HCQ==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.3.0.tgz", + "integrity": "sha512-wuGN5qSEjSgcq9fVkH0Y/qIPFjnZtW3ZPwfjJOn7l/rrf6y8J24h/lo61kwqunTyzZJm/ETGfGVU9PUs8cnzEA==", + "dependencies": { + "glob": "7.1.7" + } + }, + "node_modules/@next/font": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/font/-/font-14.1.0.tgz", + "integrity": "sha512-9hJ7bEYDI7UGQ1a++5zRD3F2VUu9NIaK5Hro/uL9bvFFs6b0Cy1OdLtLQHCIQE7sSMt8Rbu4VtcbnlubsseelA==", + "peerDependencies": { + "next": "*" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.0.tgz", + "integrity": "sha512-DmIQCNq6JtccLPPBzf0dgh2vzMWt5wjxbP71pCi5EWpWYE3MsP6FcRXi4MlAmFNDQOfcFXR2r7kBeG1LpZUh1w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.0.tgz", + "integrity": "sha512-oQoqFa88OGgwnYlnAGHVct618FRI/749se0N3S8t9Bzdv5CRbscnO0RcX901+YnNK4Q6yeiizfgO3b7kogtsZg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.0.tgz", + "integrity": "sha512-Wzz2p/WqAJUqTVoLo6H18WMeAXo3i+9DkPDae4oQG8LMloJ3if4NEZTnOnTUlro6cq+S/W4pTGa97nWTrOjbGw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.0.tgz", + "integrity": "sha512-xPVrIQOQo9WXJYgmoTlMnAD/HlR/1e1ZIWGbwIzEirXBVBqMARUulBEIKdC19zuvoJ477qZJgBDCKtKEykCpyQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.0.tgz", + "integrity": "sha512-jOFlpGuPD7W2tuXVJP4wt9a3cpNxWAPcloq5EfMJRiXsBBOjLVFZA7boXYxEBzSVgUiVVr1V9T0HFM7pULJ1qA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.0.tgz", + "integrity": "sha512-2OwKlzaBgmuet9XYHc3KwsEilzb04F540rlRXkAcjMHL7eCxB7uZIGtsVvKOnQLvC/elrUegwSw1+5f7WmfyOw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.0.tgz", + "integrity": "sha512-OeHiA6YEvndxT46g+rzFK/MQTfftKxJmzslERMu9LDdC6Kez0bdrgEYed5eXFK2Z1viKZJCGRlhd06rBusyztA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.0.tgz", + "integrity": "sha512-4aB7K9mcVK1lYEzpOpqWrXHEZympU3oK65fnNcY1Qc4HLJFLJj8AViuqQd4jjjPNuV4sl8jAwTz3gN5VNGWB7w==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.0.tgz", + "integrity": "sha512-Reer6rkLLcoOvB0dd66+Y7WrWVFH7sEEkF/4bJCIfsSKnTStTYaHtwIJAwbqnt9I392Tqvku0KkoqZOryWV9LQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", + "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", + "dependencies": { + "cross-spawn": "^7.0.3", + "is-glob": "^4.0.3", + "open": "^8.4.0", + "picocolors": "^1.0.0", + "tiny-glob": "^0.2.9", + "tslib": "^2.4.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", + "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", + "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.34", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", + "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "optional": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "optional": true + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "optional": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "optional": true + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "optional": true + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/react": { + "version": "18.0.35", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.35.tgz", + "integrity": "sha512-6Laome31HpetaIUGFWl1VQ3mdSImwxtFZ39rh059a1MNnKGqBpC88J6NJ8n/Is3Qx7CefDGLgf/KhN/sYCf7ag==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-datepicker": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.11.0.tgz", + "integrity": "sha512-naH5k8Uu5NG9+1esiCIIl9HU2hq6W6ck/3xA5XpX3kc6WUBP+ndklciQ5avGbjiYE3BvdqlHtAeHd5jcZatdTw==", + "dev": true, + "dependencies": { + "@popperjs/core": "^2.9.2", + "@types/react": "*", + "date-fns": "^2.0.1", + "react-popper": "^2.2.5" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-outside-click-handler": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/react-outside-click-handler/-/react-outside-click-handler-1.3.3.tgz", + "integrity": "sha512-fF7x4dHf/IPIne8kkt3rlCGuWFrWkFJmzQm4JkxSBzXJIM9WDLob++VnmGpE3ToVWrW3Xw9D5TxcUWrwqe04Gg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-slick": { + "version": "0.23.10", + "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.10.tgz", + "integrity": "sha512-ZiqdencANDZy6sWOWJ54LDvebuXFEhDlHtXU9FFipQR2BcYU2QJxZhvJPW6YK7cocibUiNn+YvDTbt1HtCIBVA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", + "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "optional": true, + "dependencies": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz", + "integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz", + "integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==", + "dependencies": { + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz", + "integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz", + "integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==", + "dependencies": { + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz", + "integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==", + "dependencies": { + "@typescript-eslint/types": "5.59.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "optional": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.find": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.2.tgz", + "integrity": "sha512-DRumkfW97iZGOfn+lIXbkVrXL04sfYKX+EfOodo8XboR5sxPDVvOjZTF/rysusa9lmhmSOeD6Vp6RKQP+eP4Tg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "optional": true, + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", + "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true + }, + "node_modules/blurhash": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz", + "integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==", + "peer": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bson": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", + "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "optional": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "optional": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/consolidated-events": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/consolidated-events/-/consolidated-events-2.0.2.tgz", + "integrity": "sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ==" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "devOptional": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-equal": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.0", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/document.contains": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/document.contains/-/document.contains-1.0.2.tgz", + "integrity": "sha512-YcvYFs15mX8m3AO1QNQy3BlIpSMfNRj3Ujk2BEJxsZG+HZf7/hZ6jr7mDpXrF8q+ff95Vef5yjhiZxm8CGJr6Q==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.609", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.609.tgz", + "integrity": "sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquire.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz", + "integrity": "sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw==" + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "optional": true + }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "optional": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "optional": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "optional": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "optional": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "optional": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "optional": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", + "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.38.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.3.0.tgz", + "integrity": "sha512-6YEwmFBX0VjBd3ODGW9df0Is0FLaRFdMN8eAahQG9CN6LjQ28J8AFr19ngxqMSg7Qv6Uca/3VeeBosJh1bzu0w==", + "dependencies": { + "@next/eslint-plugin-next": "13.3.0", + "@rushstack/eslint-patch": "^1.1.3", + "@typescript-eslint/parser": "^5.42.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.31.7", + "eslint-plugin-react-hooks": "^4.5.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", + "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "get-tsconfig": "^4.5.0", + "globby": "^13.1.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/globby": { + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", + "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "optional": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fast-text-encoding": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", + "optional": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/firebase": { + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-9.21.0.tgz", + "integrity": "sha512-kQpT+YjusVhqj8feSmb+9Fpmyfy7ayGSd6GVk2k0qJjt+AwYgHZ9tuHuIgFdEHGsvqxYRZJpu067ck9ZQwbqQw==", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-compat": "0.2.6", + "@firebase/app": "0.9.9", + "@firebase/app-check": "0.7.0", + "@firebase/app-check-compat": "0.3.6", + "@firebase/app-compat": "0.2.9", + "@firebase/app-types": "0.9.0", + "@firebase/auth": "0.23.1", + "@firebase/auth-compat": "0.4.1", + "@firebase/database": "0.14.4", + "@firebase/database-compat": "0.3.4", + "@firebase/firestore": "3.11.0", + "@firebase/firestore-compat": "0.3.8", + "@firebase/functions": "0.9.4", + "@firebase/functions-compat": "0.3.4", + "@firebase/installations": "0.6.4", + "@firebase/installations-compat": "0.2.4", + "@firebase/messaging": "0.12.4", + "@firebase/messaging-compat": "0.2.4", + "@firebase/performance": "0.6.4", + "@firebase/performance-compat": "0.2.4", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-compat": "0.2.4", + "@firebase/storage": "0.11.2", + "@firebase/storage-compat": "0.3.2", + "@firebase/util": "1.9.3" + } + }, + "node_modules/firebase-admin": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.7.0.tgz", + "integrity": "sha512-58y9dor/nrK4Dc/hwpmm7uGCy+oqld+k189mclWwhKu8IZJcZbXxPFHsNzW/yG7aVTH5sTD4rHnRXj8+t5AhPQ==", + "dependencies": { + "@fastify/busboy": "^1.2.1", + "@firebase/database-compat": "^0.3.4", + "@firebase/database-types": "^0.10.4", + "@types/node": ">=12.12.47", + "jsonwebtoken": "^9.0.0", + "jwks-rsa": "^3.0.1", + "node-forge": "^1.3.1", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "@google-cloud/firestore": "^6.5.0", + "@google-cloud/storage": "^6.9.5" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "node_modules/follow-redirects": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "optional": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.0.tgz", + "integrity": "sha512-aezGIjb+/VfsJtIcHGcBSerNEDdfdHeMros+RbYbGpmonKWQCOVOes0LVZhn1lDtIgq55qq0HaxymIoae3Fl/A==", + "optional": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gcp-metadata": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.2.0.tgz", + "integrity": "sha512-aFhhvvNycky2QyhG+dcfEdHBF0FRbYcf39s6WNHUDysKSrbJ5vuFbjydxBcmewtXeV248GP8dWT3ByPNxsyHCw==", + "optional": true, + "dependencies": { + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.5.0.tgz", + "integrity": "sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==", + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==" + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" + }, + "node_modules/goober": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.13.tgz", + "integrity": "sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/google-auth-library": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.7.0.tgz", + "integrity": "sha512-1M0NG5VDIvJZEnstHbRdckLZESoJwguinwN8Dhae0j2ZKIQFIV63zxm6Fo6nM4xkgqUr2bbMtV5Dgo+Hy6oo0Q==", + "optional": true, + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^5.0.0", + "gcp-metadata": "^5.0.0", + "gtoken": "^6.1.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/google-gax": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.1.tgz", + "integrity": "sha512-g/lcUjGcB6DSw2HxgEmCDOrI/CByOwqRvsuUvNalHUK2iPPPlmAIpbMbl62u0YufGMr8zgE3JL7th6dCb1Ry+w==", + "optional": true, + "dependencies": { + "@grpc/grpc-js": "~1.8.0", + "@grpc/proto-loader": "^0.7.0", + "@types/long": "^4.0.0", + "@types/rimraf": "^3.0.2", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "fast-text-encoding": "^1.0.3", + "google-auth-library": "^8.0.2", + "is-stream-ended": "^0.1.4", + "node-fetch": "^2.6.1", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^1.0.0", + "protobufjs": "7.2.4", + "protobufjs-cli": "1.1.1", + "retry-request": "^5.0.0" + }, + "bin": { + "compileProtos": "build/tools/compileProtos.js", + "minifyProtoJson": "build/tools/minify.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/google-gax/node_modules/@grpc/grpc-js": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz", + "integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==", + "optional": true, + "dependencies": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/google-gax/node_modules/@grpc/proto-loader": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.6.tgz", + "integrity": "sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw==", + "optional": true, + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/google-gax/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/google-gax/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/google-gax/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "optional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-gax/node_modules/protobufjs": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", + "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/google-gax/node_modules/protobufjs-cli": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", + "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", + "optional": true, + "dependencies": { + "chalk": "^4.0.0", + "escodegen": "^1.13.0", + "espree": "^9.0.0", + "estraverse": "^5.1.0", + "glob": "^8.0.0", + "jsdoc": "^4.0.0", + "minimist": "^1.2.0", + "semver": "^7.1.2", + "tmp": "^0.2.1", + "uglify-js": "^3.7.7" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "protobufjs": "^7.0.0" + } + }, + "node_modules/google-gax/node_modules/protobufjs/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "optional": true + }, + "node_modules/google-p12-pem": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", + "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", + "optional": true, + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "node_modules/gtoken": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", + "optional": true, + "dependencies": { + "gaxios": "^5.0.1", + "google-p12-pem": "^4.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "optional": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "optional": true + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jiti": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", + "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jose": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.3.tgz", + "integrity": "sha512-YPM9Q+dmsna4CGWNn5+oHFsuXJdxvKAOVoNjpe2nje3odSoX5Xz4s71rP50vM8uUKJyQtMnEGPmbVCVR+G4W5g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "peer": true + }, + "node_modules/js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "optional": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "optional": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "optional": true, + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "dependencies": { + "string-convert": "^0.2.0" + } + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "optional": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwks-rsa": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", + "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "dependencies": { + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^9.0.0", + "debug": "^4.3.4", + "jose": "^4.10.4", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "optional": true, + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "optional": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lottie-react": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.0.tgz", + "integrity": "sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-memoizer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", + "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "optional": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "optional": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "optional": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "optional": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/next": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/next/-/next-13.3.0.tgz", + "integrity": "sha512-OVTw8MpIPa12+DCUkPqRGPS3thlJPcwae2ZL4xti3iBff27goH024xy4q2lhlsdoYiKOi8Kz6uJoLW/GXwgfOA==", + "dependencies": { + "@next/env": "13.3.0", + "@swc/helpers": "0.4.14", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=14.6.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "13.3.0", + "@next/swc-darwin-x64": "13.3.0", + "@next/swc-linux-arm64-gnu": "13.3.0", + "@next/swc-linux-arm64-musl": "13.3.0", + "@next/swc-linux-x64-gnu": "13.3.0", + "@next/swc-linux-x64-musl": "13.3.0", + "@next/swc-win32-arm64-msvc": "13.3.0", + "@next/swc-win32-ia32-msvc": "13.3.0", + "@next/swc-win32-x64-msvc": "13.3.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-abi": { + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.40.0.tgz", + "integrity": "sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.22.tgz", + "integrity": "sha512-XseknLAfRHzVWjCEtdviapiBtfLdgyzExD50Rg2ePaucEesyh8Wv4VPdW0nbyDa1ydbrAxV19jvMT4+LFmcNUA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-exact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.0.tgz", + "integrity": "sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==", + "dependencies": { + "has": "^1.0.3", + "object.assign": "^4.1.0", + "reflect.ownkeys": "^0.2.0" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/proto3-json-serializer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", + "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "optional": true, + "dependencies": { + "protobufjs": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proto3-json-serializer/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "optional": true + }, + "node_modules/proto3-json-serializer/node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-blurhash": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/react-blurhash/-/react-blurhash-0.3.0.tgz", + "integrity": "sha512-XlKr4Ns1iYFRnk6DkAblNbAwN/bTJvxTVoxMvmTcURdc5oLoXZwqAF9N3LZUh/HT+QFlq5n6IS6VsDGsviYAiQ==", + "peerDependencies": { + "blurhash": "^2.0.3", + "react": ">=15" + } + }, + "node_modules/react-device-detect": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz", + "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==", + "dependencies": { + "ua-parser-js": "^1.0.33" + }, + "peerDependencies": { + "react": ">= 0.14.0", + "react-dom": ">= 0.14.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-dropzone": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", + "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, + "node_modules/react-easy-crop": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-4.7.5.tgz", + "integrity": "sha512-qKfI4PuhaH1jOLC3DQfQB0cE0z+3N7bfyPkPejQmylXNb8nstfPMH+oHj3gKgpBHLFUiQp/C1rY7sVCVgtjn3Q==", + "dependencies": { + "normalize-wheel": "^1.0.1", + "tslib": "2.0.1" + }, + "peerDependencies": { + "react": ">=16.4.0", + "react-dom": ">=16.4.0" + } + }, + "node_modules/react-easy-crop/node_modules/tslib": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==" + }, + "node_modules/react-fast-compare": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", + "integrity": "sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg==", + "dev": true + }, + "node_modules/react-hook-form": { + "version": "7.43.9", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.43.9.tgz", + "integrity": "sha512-AUDN3Pz2NSeoxQ7Hs6OhQhDr6gtF9YRuutGDwPQqhSUAHJSgGl2VeY3qN19MG0SucpjgDiuMJ4iC5T5uB+eaNQ==", + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-hot-toast": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.0.tgz", + "integrity": "sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-outside-click-handler": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz", + "integrity": "sha512-Te/7zFU0oHpAnctl//pP3hEAeobfeHMyygHB8MnjP6sX5OR8KHT1G3jmLsV3U9RnIYo+Yn+peJYWu+D5tUS8qQ==", + "dependencies": { + "airbnb-prop-types": "^2.15.0", + "consolidated-events": "^1.1.1 || ^2.0.0", + "document.contains": "^1.0.1", + "object.values": "^1.1.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^0.14 || >=15", + "react-dom": "^0.14 || >=15" + } + }, + "node_modules/react-outside-click-handler/node_modules/airbnb-prop-types": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz", + "integrity": "sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==", + "dependencies": { + "array.prototype.find": "^2.1.1", + "function.prototype.name": "^1.1.2", + "is-regex": "^1.1.0", + "object-is": "^1.1.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2", + "prop-types": "^15.7.2", + "prop-types-exact": "^1.2.0", + "react-is": "^16.13.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "peerDependencies": { + "react": "^0.14 || ^15.0.0 || ^16.0.0-alpha" + } + }, + "node_modules/react-outside-click-handler/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dev": true, + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-slick": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.29.0.tgz", + "integrity": "sha512-TGdOKE+ZkJHHeC4aaoH85m8RnFyWqdqRfAGkhd6dirmATXMZWAxOpTLmw2Ll/jPTQ3eEG7ercFr/sbzdeYCJXA==", + "dependencies": { + "classnames": "^2.2.5", + "enquire.js": "^2.1.6", + "json2mq": "^0.2.0", + "lodash.debounce": "^4.0.8", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "peerDependencies": { + "redux": ">4.0.0" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, + "node_modules/reflect.ownkeys": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", + "integrity": "sha512-qOLsBKHCpSOFKK1NUOCGC5VyeufB6lEsFe92AL2bhIJsacZS1qdoOZSbPk3MYKuT2cFlRDnulKXuuElIrMjGUg==" + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "optional": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-request": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", + "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/sharp/node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/slick-carousel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/slick-carousel/-/slick-carousel-1.8.1.tgz", + "integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==", + "peerDependencies": { + "jquery": ">=1.8.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "optional": true, + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "optional": true + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/streamx": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", + "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "optional": true + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.4.tgz", + "integrity": "sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ==" + }, + "node_modules/sucrase": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", + "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tailwindcss": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz", + "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==", + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1", + "sucrase": "^3.29.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/teeny-request": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", + "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "optional": true, + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/text-decoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", + "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", + "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "optional": true + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "optional": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "optional": true + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9964001 --- /dev/null +++ b/package.json @@ -0,0 +1,60 @@ +{ + "name": "witit-web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@firebase/storage-types": "^0.8.0", + "@hookform/resolvers": "^3.1.0", + "@mui/icons-material": "^5.11.16", + "@mui/lab": "^5.0.0-alpha.142", + "@mui/material": "^5.14.10", + "@mui/x-date-pickers": "^6.2.1", + "@next/font": "^14.1.0", + "@reduxjs/toolkit": "^1.9.5", + "@types/node": "18.15.11", + "@types/react": "18.0.35", + "@types/react-dom": "18.0.11", + "autoprefixer": "10.4.14", + "axios": "^1.3.6", + "bson": "^6.2.0", + "dayjs": "^1.11.7", + "eslint": "8.38.0", + "eslint-config-next": "13.3.0", + "firebase": "^9.20.0", + "firebase-admin": "^11.7.0", + "lottie-react": "^2.4.0", + "next": "13.3.0", + "postcss": "8.4.22", + "react": "18.2.0", + "react-blurhash": "^0.3.0", + "react-device-detect": "^2.2.3", + "react-dom": "18.2.0", + "react-dropzone": "^14.2.3", + "react-easy-crop": "^4.7.5", + "react-hook-form": "^7.43.9", + "react-hot-toast": "^2.4.0", + "react-infinite-scroll-component": "^6.1.0", + "react-outside-click-handler": "^1.3.0", + "react-redux": "^8.0.5", + "react-slick": "^0.29.0", + "redux-persist": "^6.0.0", + "sharp": "^0.32.1", + "slick-carousel": "^1.8.1", + "socket.io-client": "^4.7.2", + "tailwindcss": "3.3.1", + "typescript": "5.0.4" + }, + "devDependencies": { + "@types/react-datepicker": "^4.10.0", + "@types/react-outside-click-handler": "^1.3.3", + "@types/react-slick": "^0.23.10" + } +} diff --git a/pages/_app.tsx b/pages/_app.tsx new file mode 100644 index 0000000..f84140d --- /dev/null +++ b/pages/_app.tsx @@ -0,0 +1,37 @@ +import ToastMessage from "@/components/shared/ToastMessage"; +import AuthContext from "@/context/AuthContext"; +import Wrapper from "@/context/Wrapper"; +import { persistor, store } from "@/redux/store"; +import "@/styles/globals.css"; +import { theme } from "@/theme"; +import { StyledEngineProvider, ThemeProvider } from "@mui/material"; +import type { AppProps } from "next/app"; +import dynamic from "next/dynamic"; +import { Provider } from "react-redux"; +import { PersistGate } from "redux-persist/integration/react"; + +const NoInternet = dynamic(() => import("@/components/shared/NoInternet"), { + ssr: false, +}); +export default function App({ Component, pageProps }: AppProps) { + return ( +
+ + + + + + + + + + + + + + + + +
+ ); +} diff --git a/pages/_document.tsx b/pages/_document.tsx new file mode 100644 index 0000000..c0150a9 --- /dev/null +++ b/pages/_document.tsx @@ -0,0 +1,14 @@ +import { Html, Head, Main, NextScript } from "next/document"; + + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/pages/account-setup.tsx b/pages/account-setup.tsx new file mode 100644 index 0000000..8bb38c1 --- /dev/null +++ b/pages/account-setup.tsx @@ -0,0 +1,439 @@ +import { + AppBar, + FormHelperText, + Stack, + Toolbar, + Typography, +} from "@mui/material"; +import { Controller, useForm } from "react-hook-form"; +import { CalendarMonthOutlined } from "@mui/icons-material"; +import { LocalizationProvider, MobileDatePicker } from "@mui/x-date-pickers"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs from "dayjs"; +import CustomButton from "@/components/shared/CustomButton"; +import React, { useEffect, useState } from "react"; +import { createUser } from "@/api/user/createUser"; +import { useDispatch } from "react-redux"; +import { useRouter } from "next/router"; +import { checkUsernameExist } from "@/api/public/checkUsernameExist"; +import { uploadImageToStorage } from "@/service/firebase/uploadImage"; +import { useAuthContext } from "@/context/AuthContext"; +import ConfirmPasswordDialog from "@/components/accountSetup/ConfirmPasswordDialog"; +import Loader from "@/components/shared/Loader"; +import MainLogo from "@/components/shared/MainLogo"; +import LoginTag from "@/components/shared/LoginTag"; +import Loginterms from "@/components/shared/Loginterms"; +import StepperArea from "@/components/shared/Stepper"; +import { ChevronRightRounded } from "@mui/icons-material"; +import CongratulationsDialog from "@/components/accountSetup/CongratulationsBox"; +import Head from "next/head"; +import { ImageInfo } from "@/types"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import { setReduxUser } from "@/redux/slices/userSlice"; +import appConstant, { + defaultImageConstant, +} from "@/utils/constants/withoutHtml/appConstant"; +import { theme } from "@/theme"; +import profilePlaceHolder from "@/utils/images/profilePlaceHolder.svg"; +import Image from "next/image"; +import InputCropSingleImage from "@/components/shared/cropImage/singleCropImage/InputCropSingleImage"; + +type SelectedImage = { + imagePreview: string; + file: File; +}; + +const AccountSetup = () => { + let dispatch = useDispatch(); + const router = useRouter(); + + const [isLoginSuccess, setIsLoginSuccess] = useState(false); + const [email, setEmail] = useState(""); + const [isLoginRequired, setIsLoginRequired] = useState(false); + const [isLoading, setIsLoding] = useState(true); + const [finalProfileImage, setFinalProfileImage] = useState<{ + image: ImageInfo; + index: number; + }>(defaultImageConstant); + const [selectedImage, setSelectedImage] = useState( + null + ); + const { firebaseUser, sendNotification, croppingImage, customDialogType } = + useAuthContext(); + + const { + handleSubmit, + control, + setValue, + setError, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + image: "", + email: "", + userName: "", + firstName: "", + lastName: "", + DOB: "", + }, + mode: "onSubmit", + }); + + useEffect(() => { + setTimeout(() => { + setIsLoding(false); + }, 1000); + }, []); + + useEffect(() => { + if (firebaseUser && firebaseUser.email) { + console.log(firebaseUser.email); + setValue("email", firebaseUser.email); + setIsLoginRequired(false); + } else { + const queryParameters = new URLSearchParams(window.location.search); + const email = queryParameters.get("email"); + if (email) { + console.log(email); + setValue("email", email); + setEmail(email); + setIsLoginRequired(true); + } else { + router.replace("/"); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [firebaseUser]); + useEffect(() => { + setFinalProfileImage(defaultImageConstant); + }, []); + + const onSubmit = async (data: Record) => { + if (!firebaseUser) return; + + if (isLoginRequired) { + sendNotification({ type: "ERROR", message: "Please Login First!" }); + return; + } + sendNotification({ type: "LOADING" }); + console.log("submitData", data); + + // check if username already exist + const username = await checkUsernameExist(data?.userName); + if (!username?.data?.isAvailable) { + sendNotification({ type: "REMOVE" }); + setError("userName", { + type: "custom", + message: "username already exist", + }); + return; + } + + //modify birthdate + if (data?.DOB !== "") { + const birthDate = dayjs(data?.DOB).format("YYYY-MM-DD"); + data.DOB = birthDate; + setValue("DOB", birthDate); + } else { + data.DOB = null; + } + + // // upload image to firebase and get image url + if (selectedImage) { + const imageUrl = await uploadImageToStorage({ + folderName: "profile_picture_images", + file: selectedImage.file, + metadata: { + userId: firebaseUser.uid, + }, + }); + data.image = imageUrl; + setValue("image", imageUrl); + } else { + setValue("image", ""); + } + + const addUser = await createUser({ data, user_id: firebaseUser?.uid }); + if (addUser.status === 200) { + dispatch(setReduxUser(addUser.data)); + sendNotification({ + type: "SUCCESS", + message: "You have Successfully SignUp", + }); + setIsLoginSuccess(true); + router.push(appConstant.pageRoute.create); + } else { + sendNotification({ type: "ERROR", message: addUser?.error }); + console.log(addUser); + } + }; + + const sendToHome = () => { + router.replace("/"); + }; + + return ( + <> + + Witit - Account Setup + + {isLoading ? ( + + ) : ( +
+ {isLoginRequired ? ( + + ) : null} + + + sendToHome()} /> + + +
+
+
+ + + +
+ ( + + +
+ ), + placeholderTitle: ( + <> +

+ Drag profile pic here, +

+

+ or{" "} + + browse + +

+ + ), + }} + /> + )} + /> +
+
+ +
+
+
+
+
+
+ + User name + + ( + } + /> + )} + /> +
+
+ + Let’s get to know you + + +
+ ( + } + /> + )} + /> +
+
+ ( + } + /> + )} + /> +
+
+
+
+ + Birthdate + + ( + <> + + + + {" "} + + + {errors.DOB && ( + + {errors.DOB.message} + + )} + + )} + /> +
+
+
+ } + /> +
+
+
+
+
+ +
+ {isLoginSuccess ? : null} +
+ )} + + ); +}; + +export default AccountSetup; diff --git a/pages/app/subscription.tsx b/pages/app/subscription.tsx new file mode 100644 index 0000000..b7dd5b7 --- /dev/null +++ b/pages/app/subscription.tsx @@ -0,0 +1,154 @@ +import { ImageSliderAnimationShowBox } from "@/components/home/ImageSliderAnimationShowBox"; +import CustomButton from "@/components/shared/CustomButton"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import VerifiedIcon from "@/utils/icons/circle/VerifiedIcon"; +import AlertIcon from "@/utils/icons/levelUp/AlertIcon"; +import DollerIcon from "@/utils/icons/levelUp/DollerIcon"; +import FormIcon from "@/utils/icons/levelUp/FormIcon"; +import SettingIcon from "@/utils/icons/levelUp/SettingIcon"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import Image from "next/image"; +import React, { useEffect } from "react"; +import companyLogo from "@/utils/images/witit.svg"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import slothImage from "@/utils/images/sloth_image.jpg"; +import { useRouter } from "next/router"; + +const AppSubscription = () => { + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + + const handleSubmit = () => { + if (!user) return; + router.push("https://witit.com/" + user.userName); + }; + + return ( +
+
+
+
+ Company Logo +
+
+
+ +
+
+
+ Level up your AI +
+

+ Generate stunning AI-powered photos of yourself + unlock + numerous additional benefits. +

+

+ Here’s what you get with Level Up AI +

+
+
+
{" "} +
+
+
+ +
+

+ Advanced{" "} + + creation tools + +

+
+
+
+ +
+

+ + Earn cash + {" "} + from your AI, posts, prompts or through messaging +

+
+
+
+ +
+

+ AI{" "} + yourself{" "} + + into posts + {" "} + on Witit +

+
+
+
+ +
+

+ Get{" "} + + 20 photo creations a day + {" "} + included with your subscription +

+
+
+
+ +
+

Get verified

+
+
+
+ +
+

+ + Create & View + {" "} + Content with less restriction +

+
{" "} +
+
+ +
+

+ Create AI photos of your{" "} + + pet, brand + {" "} + or in your{" "} + + art/photography style. + {" "} +

+
+
{" "} +
+ +
+
+ +
+
+ ); +}; + +export default AppSubscription; diff --git a/pages/circle.tsx b/pages/circle.tsx new file mode 100644 index 0000000..d2bac7a --- /dev/null +++ b/pages/circle.tsx @@ -0,0 +1,528 @@ +import CirclePost from "@/components/circle/CirclePost"; +import CirclePostInfoDialog from "@/components/circle/CirclePostInfoDialog"; +import { useAuthContext } from "@/context/AuthContext"; +import Head from "next/head"; +import CategorySelection from "@/components/shared/CategorySelection"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { Post, PromptDetail } from "@/types/post"; +import { getCircleFeed } from "@/api/circle/getCircleFeed"; +import { + addCirclePost, + deleteCirclePost, + updateCircleCommentCount, + updateCircleLikeStatus, + updateCirclePostView, + updateCirclePostViewPrompt, + updateCircleRepostStatus, +} from "@/redux/slices/circleFeedSlice"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { CircularProgress } from "@mui/material"; +import { likePost } from "@/api/post/likePost"; +import { deletePost } from "@/api/post/deletePost"; +import { doRepost } from "@/api/post/doRepost"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import { UserBaseInfo } from "@/types/user"; +import Creadit from "@/components/shared/credit/Index"; +import CreditViewPrompt from "@/components/shared/credit/CreditViewPrompt"; +import ViewPromptDrawer from "@/components/discover/ViewPromptDrawer"; +import { getPromptOfPost } from "@/api/post/getPromptOfPost"; +import { viewPost } from "@/api/post/viewPost"; +import ReportDialog from "@/components/shared/ReportDialog"; +import { reportUser } from "@/api/user/reportUser"; +import { reportPost } from "@/api/post/reportPost"; +import EditPostDialog from "@/components/shared/CustomEditPostDialog/index"; +import EditGenerationPostPrompt from "@/components/shared/CustomEditPostFromGenetation/index"; + +type Res = { + status: number; + data: Post[]; + error: any; +}; + +type GetCircleProps = { + rank?: number; + lastDocId?: string; + res?: Res; +}; + +type LikePostProps = { postId: string; isLiked: boolean; res?: Res }; + +const Circle = () => { + const { sendNotification } = useAuthContext(); + const dispatch = useDispatch(); + const circleScrollableDivRef = useRef(null); + + const user = useSelector((state: RootState) => state.user); + const circlePosts = useSelector((state: RootState) => state.circlePosts); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + const [isOpenEditPost, setIsOpenEditPost] = useState(false); + const [hasMoreFeed, setHasMoreFeed] = useState(true); + const [category, setCategory] = useState(); + const [selectedImageIndex, setSelectedImageIndex] = useState(0); + const [editedValue, setEditedValue] = useState(null); + const [deletingPostIndex, setDeletingPostIndex] = useState( + null + ); + const [selectedPost, setSelectedPost] = useState(null); + const [isFetched, setIsFetched] = useState(false); + const [creditDialogInfo, setCreditDialogInfo] = useState<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null>(null); + const [promptDetails, setPromptDetails] = useState(null); + const [reportingPostIndex, setReportingPostIndex] = useState( + null + ); + + const handleLikePost = async ({ postId, isLiked }: LikePostProps) => { + if (!user) return; + const res = await likePost({ + user_id: user.userId, + postId, + isLiked, + }); + + if (!res) return; + if (res.status === 200) { + dispatch(updateCircleLikeStatus({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleRepost = async ( + event: React.MouseEvent, + postId: string, + isReposted: boolean + ) => { + event.stopPropagation(); + if (!user) return; + sendNotification({ type: "LOADING" }); + let res; + if (isReposted) { + res = await deletePost({ + user_id: user.userId, + postId, + }); + } else { + res = await doRepost({ + user_id: user.userId, + postId, + }); + } + if (!res) return; + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: isReposted + ? "Post Deleted Successfully" + : "Reposted Successfully", + }); + dispatch(updateCircleRepostStatus({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleChange = ( + event: React.ChangeEvent, + postId: string + ) => { + handleLikePost({ + postId: postId, + isLiked: event.target.checked, + }); + }; + + const getFeed = async ({ lastDocId, rank }: GetCircleProps) => { + if (!user) return; + const res = await getCircleFeed({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + ...(category && { category }), + ...(rank && { rank }), + }); + setIsFetched(true); + setFeed({ res, lastDocId }); + }; + + const viewPostCount = async (postId: string) => { + if (!user) return; + const res = await viewPost({ + user_id: user.userId, + postId, + }); + if (res.status === 200) { + dispatch(updateCirclePostView({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const setFeed = ({ lastDocId, res }: GetCircleProps) => { + if (!res) return; + + if (res.status === 200) { + if (res?.data.length < 20) { + setHasMoreFeed(false); + } else { + setHasMoreFeed(true); + } + if (res.data.length > 0) { + if (lastDocId) { + dispatch(addCirclePost([...circlePosts, ...res.data])); + } else { + dispatch(addCirclePost(res.data)); + } + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleCommentCount = (postId: string) => { + dispatch(updateCircleCommentCount({ postId })); + }; + + const fetchMorePost = async () => { + const lastPost = circlePosts[circlePosts.length - 1]; + const lastDocId = lastPost?.postId; + const rank = lastPost?.rank; + + getFeed({ lastDocId, rank }); + setIsFetched(false); + }; + + const handleCategoryFilter = (list: string[]) => { + setIsFetched(false); + if (list.length > 0) setCategory(list); + else setCategory(undefined); + }; + + const handleDeletePostFromMenu = async (postId: string) => { + if (!user) return; + const selectedPost = circlePosts.find((post) => post.postId === postId); + if (!selectedPost) return; + + sendNotification({ type: "LOADING" }); + const res = await deletePost({ + user_id: user.userId, + postId, + }); + + if (!res) return; + if (res.status === 200) { + dispatch(deleteCirclePost({ postId: selectedPost?.postId })); + + sendNotification({ + type: "SUCCESS", + message: "Post Deleted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + setHasMoreFeed(false); + }; + + const getPromptDetails = async () => { + if (!user) return; + if (!creditDialogInfo) return; + const res = await getPromptOfPost({ + user_id: user.userId, + postId: creditDialogInfo.postId, + }); + + if (res.status === 200) { + setPromptDetails(res.data); + dispatch( + updateCirclePostViewPrompt({ postId: selectedPost?.postId || "" }) + ); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handlePostClicked = ( + event: React.MouseEvent, + postId: string + ) => { + event.stopPropagation(); + + const clickedPost = circlePosts.find((post) => post.postId === postId); + if (clickedPost) { + const isViewdPost = viewedNsfwList.includes(clickedPost.postId); + if (!clickedPost.category.includes("NSFW")) { + setSelectedPost(clickedPost); + } else if (isViewdPost && clickedPost.category.includes("NSFW")) { + setSelectedPost(clickedPost); + } + } + }; + const submitReport = async (inputText: string) => { + if (!user) return; + if (!reportingPostIndex) return; + + const res = await reportPost({ + user_id: user.userId, + data: { reportFor: inputText, postId: reportingPostIndex }, + }); + + if (res.status === 200) { + setReportingPostIndex(null); + + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + useEffect(() => { + dispatch(addCirclePost([])); + getFeed({}); + }, [category]); + + useEffect(() => { + if (circlePosts) + setSelectedPost((prev) => { + const matchedPost = circlePosts.find( + (post) => post.postId === prev?.postId + ); + return matchedPost ? matchedPost : null; + }); + }, [circlePosts]); + + useEffect(() => { + if (creditDialogInfo?.isPostAccessed) { + getPromptDetails(); + } + }, [creditDialogInfo]); + + useEffect(() => { + if (promptDetails) { + setCreditDialogInfo(null); + } + }, [promptDetails]); + + // get visible post on screen + useEffect(() => { + if (!circlePosts) { + return; + } + + const options = { + root: null, + rootMargin: "0px", + threshold: 1, + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + // dispatch(removetempAll()); + + if (entry.isIntersecting) { + if ( + !circlePosts.filter((post) => post.postId === entry.target.id)[0] + .userActivity.isViewed + ) { + viewPostCount(entry.target.id); + } + } + }); + }, options); + + document.querySelectorAll(".post-item").forEach((postElement) => { + observer.observe(postElement); + }); + + return () => { + observer.disconnect(); + }; + }, [circlePosts]); + + const handleEdit = (selectedPost: Post) => { + setEditedValue(selectedPost); + setIsOpenEditPost(true); + }; + return ( + <> + + Witit - Circle + + +
+ + {circlePosts.length === 0 && isFetched ? ( +
+ no post found Here +
+ ) : ( +
+ + +
+ } + scrollableTarget="circleScrollableDiv" + style={hasMoreFeed ? {} : { overflow: "hidden" }} + > +
+ {circlePosts.map((post, index) => { + return ( +
+ + ) => { + handleChange(event, post.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + post.postId, + post.userActivity.isReposted + ); + }} + selectedPost={post} + handleEdit={handleEdit} + setSelectedImageIndex={setSelectedImageIndex} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + handlePostClicked={handlePostClicked} + promptDetails={promptDetails} + creditDialogInfo={creditDialogInfo} + setReportingPostIndex={setReportingPostIndex} + /> +
+ ); + })} +
+ +
+ )} + + {selectedPost ? ( + ) => { + handleChange(event, selectedPost.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + selectedPost.postId, + selectedPost.userActivity.isReposted + ); + }} + selectedPost={selectedPost} + selectedImageIndex={selectedImageIndex} + setSelectedPost={setSelectedPost} + handleEdit={handleEdit} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + creditDialogInfo={creditDialogInfo} + promptDetails={promptDetails} + setReportingPostIndex={setReportingPostIndex} + /> + ) : null} + + {reportingPostIndex ? ( + submitReport(inputText)} + onCancel={() => { + setReportingPostIndex(null); + }} + /> + ) : null} + + {deletingPostIndex ? ( + { + setDeletingPostIndex(null); + }} + onConform={() => { + handleDeletePostFromMenu(deletingPostIndex); + setDeletingPostIndex(null); + }} + title={{ + titleMain: "Delete Post?", + title1: "Sure You Want to Delete This Offer From Your Account?", + title2: " You will not be able to recover them again.", + confirmButton: "Delete", + }} + /> + ) : null} + + {creditDialogInfo && !creditDialogInfo.isPostAccessed ? ( + + + + ) : null} + + {promptDetails ? ( + + ) : null} + {isOpenEditPost && !editedValue?.generatedFrom && ( + + )} + {editedValue?.generatedFrom && isOpenEditPost && ( + + )} +
+ + ); +}; + +export default Circle; diff --git a/pages/create.tsx b/pages/create.tsx new file mode 100644 index 0000000..7ac233b --- /dev/null +++ b/pages/create.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import Head from "next/head"; +import GenerationContext from "@/components/create/context/GenerationContext"; +import { Create } from "@/components/create"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; + +export type CreateDrawerType = "MODEL_SELECTION" | "FILTER"; + +const CreatePage = () => { + const user = useSelector((state: RootState) => state.user); + + return ( + <> + + Witit - Create + + {user ? ( + + + + ) : null} + + ); +}; + +export default CreatePage; + +{ + /* {isDragging ? ( +
+
+ + +
+ ), + placeholderTitle: ( + <> +

+ Drag profile pic here, +

+

+ or browse +

+ + ), + }} + /> +
+
+ ) : null} */ +} diff --git a/pages/discover/EditPostFromGenetation/GenerationPostCategory.tsx b/pages/discover/EditPostFromGenetation/GenerationPostCategory.tsx new file mode 100644 index 0000000..2202976 --- /dev/null +++ b/pages/discover/EditPostFromGenetation/GenerationPostCategory.tsx @@ -0,0 +1,131 @@ +import { Grid } from "@mui/material"; +import React, { ChangeEvent, useEffect, useState } from "react"; +import { CategoryList } from "@/utils/constants/withHtml/CategoryList"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import CustomLoadingButton from "@/components/shared/CustomLoadingButton"; +import { OwnerPost } from "@/types/post"; + +type Props = { + setStep: React.Dispatch>; + + handleSave: (data: Partial) => Promise; + defaultValues: Partial | undefined; + isLoading: boolean; + + setDefaultValues: React.Dispatch< + React.SetStateAction | undefined> + >; +}; +const styles = { + responsiveGrid: { + xxl: 4, + xl: 4, + // lg: 5, + md: 4, + sm: 8, + xs: 12, + }, +}; +const GenerationPostCategory = ({ + setDefaultValues, + isLoading, + defaultValues, + handleSave, +}: Props) => { + const [getCategory, setGetCategory] = useState([]); + const [errorMessage, setErrorMessage] = useState(""); + const handleCategory = (item: string, id: number) => { + if (!getCategory.includes(item)) { + setGetCategory([...getCategory, item]); + } else { + setGetCategory((preValue) => { + return preValue.filter((value) => value !== item); + }); + } + }; + + useEffect(() => { + if ( + defaultValues && + defaultValues.category && + defaultValues.category.length >= 1 + ) { + setGetCategory(defaultValues.category); + + return; + } + }, []); + useEffect(() => { + setDefaultValues({ ...defaultValues, category: getCategory as string[] }); + setErrorMessage(""); + }, [getCategory]); + + return ( +
+
+ ) => { + setDefaultValues({ + ...defaultValues, + caption: e.target.value, + }); + }} + placeholder="Write Caption" + tag="Caption" + multiline + rows={3} + /> +
+
+ Category +
+ + {CategoryList.map((category, index) => { + return ( + +
item === category.name) + ? "bg-primary-main text-common-white" + : "text-grey-200 bg-grey-800" + } + `} + onClick={() => { + handleCategory(category.name, index); + }} + > +

{category.startIcon}

+

+ {category.name} +

+
+
+ ); + })} +
+
+

{errorMessage}

+ { + if (defaultValues?.category && defaultValues.category!.length < 1) { + setErrorMessage("Please Select Category"); + return; + } + if (defaultValues) { + handleSave(defaultValues); + return; + } + }} + /> +
+
+ ); +}; + +export default GenerationPostCategory; diff --git a/pages/discover/EditPostFromGenetation/index.tsx b/pages/discover/EditPostFromGenetation/index.tsx new file mode 100644 index 0000000..193398d --- /dev/null +++ b/pages/discover/EditPostFromGenetation/index.tsx @@ -0,0 +1,267 @@ +import React, { ChangeEvent, useEffect, useState } from "react"; +import { useAuthContext } from "@/context/AuthContext"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import GenerationPostCategory from "./GenerationPostCategory"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import CustomDialogCommonTopBar from "@/components/shared/dialog/GlobalDialogs/components/shared/CustomDialogCommonTopBar"; +import CustomToggleSwitch from "@/components/shared/CustomToggleSwitch"; +import CustomButton from "@/components/shared/CustomButton"; +import { OwnerPost, Post } from "@/types/post"; +import { getOwnerPost } from "@/api/post/getOwnerPost"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import { updatePost } from "@/api/post/updatePost"; +import EditIcon from "@/utils/icons/shared/EditIcon"; +import RightThikArrowButton from "@/utils/icons/shared/RightThikArrowButton"; +import { updateSimilarDiscoverPost } from "@/redux/slices/discoverSimilarFeedSlice"; + +type Props = { + editedValue: Post; + isOpenEditPost: boolean; + setIsOpenEditPost: React.Dispatch>; +}; + +const EditGenerationPostPrompt = ({ + editedValue, + isOpenEditPost, + setIsOpenEditPost, +}: Props) => { + const [isAllow, setIsAllow] = useState(false); + const [step, setStep] = useState(0); + const [isLoading, setIsLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + const [generationPostData, setGenerationPostData] = + useState(null); + const [defaultValues, setDefaultValues] = useState>(); + + const { sendNotification, setCustomDialogType, customDialogType } = + useAuthContext(); + const user = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + const fetchData = async () => { + if (!user) { + return; + } + const response = await getOwnerPost({ + user_id: user.userId, + postId: editedValue.postId, + }); + if (response.status === 200 && response.data) { + setGenerationPostData(response.data); + setIsAllow(response.data?.promptDetails.allowPromptView); + setDefaultValues({ + caption: response.data.caption ?? null, + category: editedValue.category ?? [], + prompt: response.data?.promptDetails.prompt ?? null, + image: response.data?.image, + generatedFrom: { + postId: null, + modelId: response.data?.generatedFrom?.modelId!, + }, + promptDetails: { + creditPerPromptView: response.data?.promptDetails.creditPerPromptView, + allowPromptView: + response.data?.promptDetails.allowPromptView ?? false, + }, + }); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + }; + + useEffect(() => { + fetchData(); + }, []); + + useEffect(() => { + if (!isAllow) { + setDefaultValues({ + ...defaultValues, + promptDetails: { + ...defaultValues?.promptDetails, + creditPerPromptView: 0, + }, + }); + return; + } + }, [isAllow]); + + const handleSave = async (values: Partial) => { + const data = { + caption: values.caption as string | null, + category: values.category as string[], + postId: editedValue.postId, + promptDetails: values.promptDetails, + }; + setIsLoading(true); + const response = await updatePost({ + data, + user_id: user?.userId, + }); + if (response.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Data Updated Successfully", + }); + dispatch(updateSimilarDiscoverPost(data)); + setIsLoading(false); + setIsOpenEditPost(false); + setCustomDialogType(null); + return; + } + sendNotification({ type: "ERROR", message: response.error }); + setIsLoading(false); + }; + + if (!generationPostData) { + return <>; + } + return ( + { + setIsOpenEditPost(false); + setStep(0); + }} + className="w-full max-h-[610px] flex flex-col gap-2 justify-start items-center" + > + { + setIsOpenEditPost(false); + setStep(0); + }} + startIcon={ + step === 0 ? ( +
+ +
+ ) : ( +
{ + if (step > 0) { + setStep(0); + } + }} + > + +
+ ) + } + title="Edit Generation Post" + /> +
+ {step === 0 && ( + <> +
+
+ {generationPostData?.image && ( + + )} +
+
+ +
+
+
+

+ {defaultValues?.prompt} +

+
+ +
+
+ Allow Others to see your prompt +
+ + ) => { + setIsAllow(e.target.checked); + setDefaultValues({ + ...defaultValues, + promptDetails: { + ...defaultValues?.promptDetails, + allowPromptView: e.target.checked, + }, + }); + }} + /> +
+ {defaultValues?.promptDetails?.allowPromptView && ( +
+
+
+ Cost to Revel Prompt +
+

+ You will receive this credit when you create a post in + witit and someone wants to view the prompt of that post. +

+

+ {errorMessage} +

+
+ + = 1 + ? defaultValues?.promptDetails?.creditPerPromptView + : "" + } + type="number" + onChange={(e) => { + setDefaultValues({ + ...defaultValues, + promptDetails: { + ...defaultValues?.promptDetails, + creditPerPromptView: +e.target.value, + }, + }); + }} + placeholder="0" + className=" w-[80px] p-2 text-center border rounded-md focus:outline-none border-grey-600 bg-grey-800 py-2" + /> +
+ )} +
+ +
+ } + className="w-fit text-base font-semibold px-20 py-3" + handleEvent={() => { + if ( + defaultValues?.promptDetails?.allowPromptView && + defaultValues?.promptDetails?.creditPerPromptView! <= 0 + ) { + setErrorMessage( + "Cost per View Prompt must be greater than 0" + ); + return; + } + setErrorMessage(""); + setStep(1); + }} + /> +
+
+ + )} + {step === 1 && ( + + )} + +
+ ); +}; + +export default EditGenerationPostPrompt; diff --git a/pages/discover/index.tsx b/pages/discover/index.tsx new file mode 100644 index 0000000..387a884 --- /dev/null +++ b/pages/discover/index.tsx @@ -0,0 +1,264 @@ +import { Masonry } from "@mui/lab"; +import Head from "next/head"; +import React, { useEffect, useRef, useState } from "react"; +import { getDiscoverFeed } from "@/api/discover/getDiscoverFeed"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import { useAuthContext } from "@/context/AuthContext"; +import { addDiscoverPost } from "@/redux/slices/discoverFeedSlice"; +import FeedItem from "@/components/discover/FeedItem"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { CircularProgress, Grid, IconButton } from "@mui/material"; +import CategorySelection from "@/components/shared/CategorySelection"; +import { DiscoverPost } from "@/types/post"; +import { getDiscoverSearchPostByContent } from "@/api/discover/getDiscoverSearchPostByContent"; +import NormalLeftArrowIcon from "@/utils/icons/shared/NormalLeftArrowIcon"; +import { useRouter } from "next/router"; +import { addSimilarDiscoverPost } from "@/redux/slices/discoverSimilarFeedSlice"; +import { NoDataFound } from "@/components/shared/NoDataFound"; +import { CustomImagePreview } from "@/components/shared/CustomImagePreview"; +import { postNotFoundSloth } from "@/utils/images"; + +type Res = { + status: number; + data: DiscoverPost[]; + error: any; +}; + +type GetDiscoverProps = { + lastDocId?: string; + search?: string | null; + res?: Res; + referencePostDetail?: { postId: string; description: string }; +}; + +const responsiveGrid = { + xl: 3, + lg: 4, + md: 6, + sm: 12, + xs: 12, +}; + +const Discover = () => { + const dispatch = useDispatch(); + const parentRef = useRef(null); + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + const discoverPosts = useSelector((state: RootState) => state.discoverPosts); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + + const { sendNotification, discoverSearch, setDiscoverSearch } = + useAuthContext(); + + const [hasMoreFeed, setHasMoreFeed] = useState(true); + const [category, setCategory] = useState(); + const [isFetched, setIsFetched] = useState(false); + // + + const [clickedDiscovePost, setClickedDiscovePost] = + useState(null); + + const getFeed = async ({ lastDocId }: GetDiscoverProps) => { + if (!user) return; + const res = await getDiscoverFeed({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + ...(category && { category }), + }); + + setFeed({ res, lastDocId }); + }; + + const getSearchFeed = async ({ search, lastDocId }: GetDiscoverProps) => { + if (!user) return; + const res = await getDiscoverSearchPostByContent({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + ...(search && { search }), + }); + + setFeed({ res, lastDocId }); + }; + + const setFeed = ({ lastDocId, res }: GetDiscoverProps) => { + if (!res) return; + + if (res.status === 200) { + if (res?.data.length < 20) { + setHasMoreFeed(false); + } + if (res.data.length > 0) { + if (lastDocId) { + dispatch(addDiscoverPost([...discoverPosts, ...res.data])); + } else { + dispatch(addDiscoverPost(res.data)); + } + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const fetchMorePost = async () => { + const lastDocId = discoverPosts[discoverPosts.length - 1]?.postId; + getFeed({ lastDocId }); + setIsFetched(false); + }; + + const handleCategoryFilter = (list: string[]) => { + setIsFetched(false); + if (list.length > 0) setCategory(list); + else setCategory(undefined); + }; + + useEffect(() => { + if (!discoverSearch) { + dispatch(addDiscoverPost([])); + getFeed({}); + } + }, []); + + useEffect(() => { + if (!discoverSearch.search) { + dispatch(addDiscoverPost([])); + getFeed({}); + } + }, [category]); + + useEffect(() => { + setHasMoreFeed(true); + if ( + discoverSearch && + discoverSearch?.search && + discoverSearch?.search?.length > 2 && + discoverSearch?.isSearched === false + ) { + setClickedDiscovePost(null); + + dispatch(addDiscoverPost([])); + getSearchFeed({ search: discoverSearch.search }); + setDiscoverSearch((prev) => ({ + ...prev, + isSearched: true, + })); + } + }, [discoverSearch]); + + useEffect(() => { + if (discoverSearch?.search?.length === 0 && category === undefined) { + dispatch(addDiscoverPost([])); + getFeed({}); + } + }, [discoverSearch, category]); + + useEffect(() => { + if (clickedDiscovePost) { + dispatch(addSimilarDiscoverPost([])); + + let url = window.location.protocol + "//" + window.location.host; + url = url + "/discover/similarFeed?postId=" + clickedDiscovePost.postId; + router.push(url); + } + }, [clickedDiscovePost]); + + return ( + <> + + Witit - Discover + + + {!clickedDiscovePost && ( +
+ 0 + ? true + : false + } + /> + {discoverPosts.length === 0 && !hasMoreFeed ? ( +
+ + +
+ } + description="No results found for your search. Feel free to explore other topics!" + /> +
+ ) : ( +
+
+ + +
+ } + scrollableTarget="discoverScrollableDiv" + style={hasMoreFeed ? {} : { overflow: "hidden" }} + > + {/* */} + + {discoverPosts.map((post, index) => ( + { + const isViewdPost = viewedNsfwList.includes( + post.postId + ); + if (!post.category.includes("NSFW")) { + setClickedDiscovePost(post); + } else if ( + isViewdPost && + post.category.includes("NSFW") + ) { + setClickedDiscovePost(post); + } + }} + > + + + ))} + + {/* */} + +
+
+ )} +
+ )} + + ); +}; + +export default Discover; diff --git a/pages/discover/post.tsx b/pages/discover/post.tsx new file mode 100644 index 0000000..439144c --- /dev/null +++ b/pages/discover/post.tsx @@ -0,0 +1,451 @@ +import { deletePost } from "@/api/post/deletePost"; +import { doRepost } from "@/api/post/doRepost"; +import { getPromptOfPost } from "@/api/post/getPromptOfPost"; +import { getSinglePostById } from "@/api/post/getSinglePostById"; +import { likePost } from "@/api/post/likePost"; +import { reportPost } from "@/api/post/reportPost"; +import { viewPost } from "@/api/post/viewPost"; +import CirclePost from "@/components/circle/CirclePost"; + +import CirclePostInfoDialog from "@/components/circle/CirclePostInfoDialog"; +import ViewPromptDrawer from "@/components/discover/ViewPromptDrawer"; +import ConfirmationDialog from "@/components/shared/ConfirmationDialog"; +import ReportDialog from "@/components/shared/ReportDialog"; +import CreditViewPrompt from "@/components/shared/credit/CreditViewPrompt"; +import Creadit from "@/components/shared/credit/Index"; +import { useAuthContext } from "@/context/AuthContext"; +import { RootState } from "@/redux/store"; +import { Post, PromptDetail } from "@/types/post"; +import { UserBaseInfo } from "@/types/user"; +import { CircularProgress } from "@mui/material"; +import { useRouter } from "next/router"; +import React, { useEffect, useRef, useState } from "react"; +import { useSelector } from "react-redux"; + +type Res = { + status: number; + data: null; + error: any; +}; +type LikePostProps = { postId: string; isLiked: boolean; res?: Res }; + +const PostPage = () => { + const { asPath } = useRouter(); + const currentPath = useRef(asPath); + const { sendNotification } = useAuthContext(); + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + + const [post, setPost] = useState(null); + const [selectedImageIndex, setSelectedImageIndex] = useState(0); + const [deletingPostIndex, setDeletingPostIndex] = useState( + null + ); + const [selectedPost, setSelectedPost] = useState(null); + const [creditDialogInfo, setCreditDialogInfo] = useState<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null>(null); + const [promptDetails, setPromptDetails] = useState(null); + const [isFetched, setIsFetched] = useState(false); + const [reportingPostIndex, setReportingPostIndex] = useState( + null + ); + + const getPost = async (postId: string) => { + if (!user) return; + const res = await getSinglePostById({ + user_id: user.userId, + postId, + }); + setIsFetched(true); + if (res.status === 200 && res.data) { + setPost(res.data); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleLikePost = async ({ postId, isLiked }: LikePostProps) => { + if (!user) return; + const res = await likePost({ + user_id: user.userId, + postId, + isLiked, + }); + + if (!res) return; + if (res.status === 200) { + setPost((prev) => { + if (!prev) return null; + + return { + ...prev, + counts: { + ...prev.counts, + like: prev.userActivity.isLiked + ? prev.counts.like - 1 + : prev.counts.like + 1, + }, + userActivity: { + ...prev.userActivity, + isLiked: !prev.userActivity.isLiked, + }, + }; + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleDeletePostFromMenu = async (postId: string) => { + if (!user) return; + + sendNotification({ type: "LOADING" }); + const res = await deletePost({ + user_id: user.userId, + postId, + }); + + if (!res) return; + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: "Post Deleted Successfully", + }); + + router.push("/discover"); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleRepost = async ( + event: React.MouseEvent, + postId: string, + isReposted: boolean + ) => { + event.stopPropagation(); + if (!user) return; + sendNotification({ type: "LOADING" }); + let res; + if (isReposted) { + res = await deletePost({ + user_id: user.userId, + postId, + }); + } else { + res = await doRepost({ + user_id: user.userId, + postId, + }); + } + if (!res) return; + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: isReposted + ? "Post Deleted Successfully" + : "Reposted Successfully", + }); + + setPost((prev) => { + if (!prev) return null; + + return { + ...prev, + counts: { + ...prev.counts, + repost: prev.userActivity.isReposted + ? prev.counts.repost - 1 + : prev.counts.repost + 1, + }, + repostedBy: prev.userActivity.isReposted ? null : prev.repostedBy, + userActivity: { + ...prev.userActivity, + isReposted: !prev.userActivity.isReposted, + }, + }; + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleCommentCount = () => { + setPost((prev) => { + if (!prev) return null; + + return { + ...prev, + counts: { + ...prev.counts, + comment: prev.counts.comment + 1, + }, + userActivity: { + ...prev.userActivity, + isCommented: true, + }, + }; + }); + }; + + const getPromptDetails = async () => { + if (!user) return; + if (!creditDialogInfo) return; + const res = await getPromptOfPost({ + user_id: user.userId, + postId: creditDialogInfo.postId, + }); + + if (res.status === 200) { + setPromptDetails(res.data); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleChange = ( + event: React.ChangeEvent, + postId: string + ) => { + handleLikePost({ + postId: postId, + isLiked: event.target.checked, + }); + }; + const viewPostCount = async (postId: string) => { + if (!user) return; + const res = await viewPost({ + user_id: user.userId, + postId, + }); + if (res.status === 200) { + setPost((prev) => { + if (!prev) return null; + + return { + ...prev, + userActivity: { + ...prev.userActivity, + isViewed: true, + }, + }; + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handlePostClicked = ( + event: React.MouseEvent, + postId: string + ) => { + event.stopPropagation(); + + if (post) { + const isViewdPost = viewedNsfwList.includes(post.postId); + if (!post.category.includes("NSFW")) { + setSelectedPost(post); + } else if (isViewdPost && post.category.includes("NSFW")) { + setSelectedPost(post); + } + } + }; + + const submitReport = async (inputText: string) => { + if (!user) return; + if (!reportingPostIndex) return; + + const res = await reportPost({ + user_id: user.userId, + data: { reportFor: inputText, postId: reportingPostIndex }, + }); + + if (res.status === 200) { + setReportingPostIndex(null); + + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + useEffect(() => { + const postId = router.query.postId; + + if (postId) { + getPost(postId as string); + } else { + router.push("/discover"); + } + }, [currentPath.current]); + + useEffect(() => { + if (creditDialogInfo?.isPostAccessed) { + getPromptDetails(); + } + }, [creditDialogInfo]); + + useEffect(() => { + if (promptDetails) { + setCreditDialogInfo(null); + + setPost((prev) => { + if (!prev) return null; + return { + ...prev, + isPromptAvailable: true, + userActivity: { + ...prev.userActivity, + isAccessToViewPrompt: true, + }, + }; + }); + } + }, [promptDetails]); + + useEffect(() => { + if (post && !post.userActivity.isViewed) { + viewPostCount(post.postId); + } + if (selectedPost) setSelectedPost(post); + }, [post]); + + return ( +
+ {post ? ( +
{ + e.stopPropagation(); + setSelectedPost(post); + }} + > + ) => { + handleChange(event, post.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost(event, post.postId, post.userActivity.isReposted); + }} + selectedPost={post} + setSelectedImageIndex={setSelectedImageIndex} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + promptDetails={promptDetails} + creditDialogInfo={creditDialogInfo} + handlePostClicked={handlePostClicked} + setReportingPostIndex={setReportingPostIndex} + /> +
+ ) : ( + <> + {isFetched ? ( +
+
Post Not Found
+
+ ) : ( +
+ +
+ )} + + )} + {selectedPost ? ( + ) => { + handleChange(event, selectedPost.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + selectedPost.postId, + selectedPost.userActivity.isReposted + ); + }} + selectedPost={selectedPost} + selectedImageIndex={selectedImageIndex} + setSelectedPost={setSelectedPost} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + creditDialogInfo={creditDialogInfo} + promptDetails={promptDetails} + setReportingPostIndex={setReportingPostIndex} + /> + ) : null} + + {deletingPostIndex ? ( + { + setDeletingPostIndex(null); + }} + onConform={() => { + handleDeletePostFromMenu(deletingPostIndex); + setDeletingPostIndex(null); + }} + title={{ + titleMain: "Delete Post?", + title1: "Sure You Want to Delete This Offer From Your Account?", + title2: " You will not be able to recover them again.", + confirmButton: "Delete", + }} + /> + ) : null} + + {reportingPostIndex ? ( + submitReport(inputText)} + onCancel={() => { + setReportingPostIndex(null); + }} + /> + ) : null} + + {creditDialogInfo && !creditDialogInfo.isPostAccessed ? ( + + + + ) : null} + + {promptDetails ? ( + + ) : null} +
+ ); +}; + +export default PostPage; diff --git a/pages/discover/similarFeed.tsx b/pages/discover/similarFeed.tsx new file mode 100644 index 0000000..aca303b --- /dev/null +++ b/pages/discover/similarFeed.tsx @@ -0,0 +1,559 @@ +import React, { useEffect, useRef, useState } from "react"; +import CirclePost from "../../components/circle/CirclePost"; +import { DiscoverPost, Post, PromptDetail } from "@/types/post"; +import { getSimilerFeed } from "@/api/discover/getSimilerFeed"; +import { + addDiscoverPost, + deleteDiscoverPost, +} from "@/redux/slices/discoverFeedSlice"; +import { RootState } from "@/redux/store"; +import { useDispatch, useSelector } from "react-redux"; +import { useAuthContext } from "@/context/AuthContext"; +import { + addSimilarDiscoverPost, + deleteSimilarDiscoverPost, + updateSimilarDiscoverCommentCount, + updateSimilarDiscoverLikeStatus, + updateSimilarDiscoverPostView, + updateSimilarDiscoverPostViewPrompt, + updateSimilarDiscoverRepostStatus, +} from "@/redux/slices/discoverSimilarFeedSlice"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { CircularProgress } from "@mui/material"; +import CirclePostInfoDialog from "../../components/circle/CirclePostInfoDialog"; +import ConfirmationDialog from "../../components/shared/ConfirmationDialog"; +import { deletePost } from "@/api/post/deletePost"; +import { likePost } from "@/api/post/likePost"; +import { doRepost } from "@/api/post/doRepost"; +import Creadit from "../../components/shared/credit/Index"; +import CreditViewPrompt from "../../components/shared/credit/CreditViewPrompt"; +import { UserBaseInfo } from "@/types/user"; +import ViewPromptDrawer from "../../components/discover/ViewPromptDrawer"; +import { getPromptOfPost } from "@/api/post/getPromptOfPost"; +import { viewPost } from "@/api/post/viewPost"; +import { useRouter } from "next/router"; +import ReportDialog from "@/components/shared/ReportDialog"; +import { reportPost } from "@/api/post/reportPost"; +import EditPostDialog from "@/components/shared/CustomEditPostDialog/index"; +import EditGenerationPostPrompt from "@/components/shared/CustomEditPostFromGenetation/index"; + +type LikePostProps = { postId: string; isLiked: boolean; res?: Res }; + +type Res = { + status: number; + data: DiscoverPost[]; + error: any; +}; +type GetDiscoverProps = { + lastDocId?: string; + search?: string | null; + res?: Res; + postId: string; + description?: string | null; + searchScore?: number; +}; +const SimilarFeed = () => { + const dispatch = useDispatch(); + const { asPath, push, pathname } = useRouter(); + const similarFeedScrollableDivRef = useRef(null); + const currentPath = useRef(asPath); + const router = useRouter(); + + const user = useSelector((state: RootState) => state.user); + const viewedNsfwList = useSelector((state: RootState) => state.viewedNSFW); + const similarPosts = useSelector( + (state: RootState) => state.discoverSimilarPosts + ); + const discoverPosts = useSelector((state: RootState) => state.discoverPosts); + + const { sendNotification, setCustomDialogType, customDialogType } = + useAuthContext(); + const [hasMoreFeed, setHasMoreFeed] = useState(true); + const [clickedPost, setClickedPost] = useState(null); + const [selectedImageIndex, setSelectedImageIndex] = useState(0); + const [deletingPostIndex, setDeletingPostIndex] = useState( + null + ); + const [isOpenEditPost, setIsOpenEditPost] = useState(false); + const [selectedPost, setSelectedPost] = useState(null); + const [isFetched, setIsFetched] = useState(false); + const [editedValue, setEditedValue] = useState(null); + const [creditDialogInfo, setCreditDialogInfo] = useState<{ + userInfo: UserBaseInfo; + postId: string; + isPostAccessed: boolean; + } | null>(null); + const [promptDetails, setPromptDetails] = useState(null); + const [reportingPostIndex, setReportingPostIndex] = useState( + null + ); + + const handleLikePost = async ({ postId, isLiked }: LikePostProps) => { + if (!user) return; + const res = await likePost({ + user_id: user.userId, + postId, + isLiked, + }); + + if (!res) return; + if (res.status === 200) { + dispatch(updateSimilarDiscoverLikeStatus({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleRepost = async ( + event: React.MouseEvent, + postId: string, + isReposted: boolean + ) => { + event.stopPropagation(); + if (!user) return; + sendNotification({ type: "LOADING" }); + let res; + if (isReposted) { + res = await deletePost({ + user_id: user.userId, + postId, + }); + } else { + res = await doRepost({ + user_id: user.userId, + postId, + }); + } + if (!res) return; + if (res.status === 200) { + sendNotification({ + type: "SUCCESS", + message: isReposted + ? "Post Deleted Successfully" + : "Reposted Successfully", + }); + dispatch(updateSimilarDiscoverRepostStatus({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleChange = ( + event: React.ChangeEvent, + postId: string + ) => { + handleLikePost({ + postId: postId, + isLiked: event.target.checked, + }); + }; + + const getSimilarPosts = async ({ + searchScore, + description, + postId, + lastDocId, + }: GetDiscoverProps) => { + if (!user) return; + + const res = await getSimilerFeed({ + user_id: user.userId, + limit: 20, + ...(lastDocId && { lastDocId }), + ...(searchScore && { searchScore }), + ...(description && { description }), + postId, + }); + + setIsFetched(true); + setSimilarFeed({ res, lastDocId, postId }); + }; + + const setSimilarFeed = ({ lastDocId, res }: GetDiscoverProps) => { + if (!res) return; + + if (res.status === 200) { + if (res?.data.length < 20) { + setHasMoreFeed(false); + } else { + setHasMoreFeed(true); + } + if (res.data.length > 0) { + if (lastDocId) { + dispatch(addSimilarDiscoverPost([...similarPosts, ...res.data])); + } else { + dispatch(addSimilarDiscoverPost(res.data)); + } + } + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handleCommentCount = (postId: string) => { + dispatch(updateSimilarDiscoverCommentCount({ postId })); + }; + + const fetchMorePost = async () => { + const lastDocId = similarPosts[similarPosts.length - 1]?.postId; + const searchScore = similarPosts[similarPosts.length - 1]?.searchScore; + if (clickedPost) + getSimilarPosts({ + lastDocId, + searchScore, + postId: clickedPost.postId, + description: clickedPost.image[0].description, + }); + setIsFetched(false); + }; + + const handleDeletePostFromMenu = async (postId: string) => { + if (!user) return; + const selectedPost = similarPosts.find((post) => post.postId === postId); + if (!selectedPost) return; + + sendNotification({ type: "LOADING" }); + const res = await deletePost({ + user_id: user.userId, + postId, + }); + + if (res.status === 200) { + dispatch(deleteSimilarDiscoverPost({ postId: selectedPost?.postId })); + if (clickedPost) + dispatch(deleteDiscoverPost({ postId: clickedPost.postId })); + + sendNotification({ + type: "SUCCESS", + message: "Post Deleted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + setHasMoreFeed(false); + }; + + const getPromptDetails = async () => { + if (!user) return; + if (!creditDialogInfo) return; + const res = await getPromptOfPost({ + user_id: user.userId, + postId: creditDialogInfo.postId, + }); + + if (res.status === 200) { + setPromptDetails(res.data); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const viewPostCount = async (postId: string) => { + if (!user) return; + const res = await viewPost({ + user_id: user.userId, + postId, + }); + if (res.status === 200) { + dispatch(updateSimilarDiscoverPostView({ postId })); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + const handlePostClicked = ( + event: React.MouseEvent, + postId: string + ) => { + event.stopPropagation(); + + const clickedPost = similarPosts.find((post) => post.postId === postId); + if (clickedPost) { + const isViewdPost = viewedNsfwList.includes(clickedPost.postId); + if (!clickedPost.category.includes("NSFW")) { + setSelectedPost(clickedPost); + } else if (isViewdPost && clickedPost.category.includes("NSFW")) { + setSelectedPost(clickedPost); + } + } + }; + + const submitReport = async (inputText: string) => { + if (!user) return; + if (!reportingPostIndex) return; + + const res = await reportPost({ + user_id: user.userId, + data: { reportFor: inputText, postId: reportingPostIndex }, + }); + + if (res.status === 200) { + setReportingPostIndex(null); + + sendNotification({ + type: "SUCCESS", + message: "Report Submitted Successfully", + }); + } else { + sendNotification({ type: "ERROR", message: res.error }); + } + }; + + useEffect(() => { + const postId = router.query.postId; + + if (postId) { + const post = discoverPosts.find((p) => p.postId === (postId as string)); + + if (post) { + setClickedPost(post); + } else { + setClickedPost(null); + } + } else { + router.push("/discover"); + } + // discoverPosts.filter; + }, []); + + useEffect(() => { + if (similarPosts) + setSelectedPost((prev) => { + const matchedPost = similarPosts.find( + (post) => post.postId === prev?.postId + ); + return matchedPost ? matchedPost : null; + }); + }, [similarPosts]); + + useEffect(() => { + dispatch(addSimilarDiscoverPost([])); + if (clickedPost) + getSimilarPosts({ + postId: clickedPost.postId, + description: clickedPost.image[0].description, + }); + }, [clickedPost]); + + useEffect(() => { + if (creditDialogInfo?.isPostAccessed) { + getPromptDetails(); + } + }, [creditDialogInfo]); + + useEffect(() => { + if (promptDetails) { + setCreditDialogInfo(null); + dispatch( + updateSimilarDiscoverPostViewPrompt({ + postId: selectedPost?.postId || "", + }) + ); + } + }, [promptDetails]); + + // get visible post on screen + useEffect(() => { + if (!similarPosts) { + return; + } + + const options = { + root: null, + rootMargin: "0px", + threshold: 1, + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if ( + !similarPosts.filter((post) => post.postId === entry.target.id)[0] + .userActivity.isViewed + ) { + viewPostCount(entry.target.id); + } + } + }); + }, options); + + document.querySelectorAll(".post-item").forEach((postElement) => { + observer.observe(postElement); + }); + + return () => { + observer.disconnect(); + }; + }, [similarPosts]); + + const handleEdit = (selectedPost: Post) => { + setEditedValue(selectedPost); + setIsOpenEditPost(true); + }; + + return ( +
+ {similarPosts.length === 0 && isFetched ? ( +
+ No Similar Post found +
+ ) : ( +
+ + +
+ } + scrollableTarget="similarFeedScrollableDiv" + style={hasMoreFeed ? {} : { overflow: "hidden" }} + > +
+ {similarPosts.map((post, index) => { + return ( +
+ + ) => { + handleChange(event, post.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + post.postId, + post.userActivity.isReposted + ); + }} + similarPostId={clickedPost && clickedPost.postId} + selectedPost={post} + setSelectedImageIndex={setSelectedImageIndex} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + handleEdit={handleEdit} + handlePostClicked={handlePostClicked} + promptDetails={promptDetails} + creditDialogInfo={creditDialogInfo} + setReportingPostIndex={setReportingPostIndex} + /> +
+ ); + })} +
+ +
+ )} + + {selectedPost ? ( + ) => { + handleChange(event, selectedPost.postId); + }} + handleRepost={( + event: React.MouseEvent + ) => { + handleRepost( + event, + selectedPost.postId, + selectedPost.userActivity.isReposted + ); + }} + selectedPost={selectedPost} + selectedImageIndex={selectedImageIndex} + setSelectedPost={setSelectedPost} + setDeletingPostIndex={setDeletingPostIndex} + setCreditDialogInfo={setCreditDialogInfo} + promptDetails={promptDetails} + handleEdit={handleEdit} + creditDialogInfo={creditDialogInfo} + setReportingPostIndex={setReportingPostIndex} + /> + ) : null} + {deletingPostIndex ? ( + { + setDeletingPostIndex(null); + }} + onConform={() => { + handleDeletePostFromMenu(deletingPostIndex); + setDeletingPostIndex(null); + }} + title={{ + titleMain: "Delete Post?", + title1: "Sure You Want to Delete This Offer From Your Account?", + title2: " You will not be able to recover them again.", + confirmButton: "Delete", + }} + /> + ) : null} + + {reportingPostIndex ? ( + submitReport(inputText)} + onCancel={() => { + setReportingPostIndex(null); + }} + /> + ) : null} + + {creditDialogInfo && !creditDialogInfo.isPostAccessed ? ( + + + + ) : null} + + {promptDetails ? ( + + ) : null} + {isOpenEditPost && !editedValue?.generatedFrom && ( + + )} + {editedValue?.generatedFrom && isOpenEditPost && ( + + )} +
+ ); +}; + +export default SimilarFeed; diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 0000000..7aef427 --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,202 @@ +/* eslint-disable @next/next/no-img-element */ +/* eslint-disable react-hooks/exhaustive-deps */ +import { getProfileDynamicLink } from "@/api/public/getProfileDynamicLink"; +import ContactUs from "@/components/footerDialogs/ContactUs"; +import ContentPolicy from "@/components/footerDialogs/ContentPolicy"; +import PrivacyPolicy from "@/components/footerDialogs/PrivacyPolicy"; +import TermsOfServices from "@/components/footerDialogs/TermsOfServices"; +import ForgetPasswordBox from "@/components/home/ForgetPassword"; +import { ImageSliderAnimationShowBox } from "@/components/home/ImageSliderAnimationShowBox"; +import LoginBox from "@/components/home/LoginBox"; +import SignUpBox from "@/components/home/SignUp"; +import VerifyEmail from "@/components/home/VerifyEmail"; +import CustomDialog from "@/components/shared/dialog/CustomDialog"; +import Loader from "@/components/shared/Loader"; +import Loginterms from "@/components/shared/Loginterms"; +import MainLogo from "@/components/shared/MainLogo"; +import StepperArea from "@/components/shared/Stepper"; +import { useAuthContext } from "@/context/AuthContext"; +import { setReduxUser } from "@/redux/slices/userSlice"; +import { RootState } from "@/redux/store"; +import { AppBar, Toolbar } from "@mui/material"; +import Head from "next/head"; +import { useRouter } from "next/router"; +import { useEffect, useRef, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { isMobile } from "react-device-detect"; +import { getUser } from "@/api/user/getUser"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; + +export default function LoginBg() { + const router = useRouter(); + const dispatch = useDispatch(); + const { customDialogType, setCustomDialogType } = useAuthContext(); + const reduxUser = useSelector((state: RootState) => state.user); + + const { firebaseUser, sendNotification } = useAuthContext(); + + const [activeStep, setActiveStep] = useState(-1); + const [isLoading, setIsLoading] = useState(true); + + const sendToHome = () => { + router.reload(); + }; + + useEffect(() => { + if (reduxUser) { + router.push(appConstant.pageRoute.create); + } + }, []); + + const redirectUserToDestinetion = async () => { + console.log(firebaseUser); + // send to verification screen if email not verified + if (!firebaseUser?.emailVerified) { + setActiveStep(1); + return; + } + + const userId = firebaseUser?.uid; + + const userData = await getUser(userId); + // if account not found then redirect to account-setup screen + if (userData?.status === 404) { + router.push(appConstant.pageRoute.accountSetup); + return; + } + + // if user found redirect to setting screen + if (userData.status === 200 && userData.data) { + dispatch(setReduxUser(userData.data)); + router.push(appConstant.pageRoute.create); + return; + } + + sendNotification({ type: "ERROR", message: userData?.error }); + setIsLoading(false); + }; + + useEffect(() => { + handleUserRequest(); + }, []); + + const handleUserRequest = async () => { + if (isMobile) { + const userName = router.asPath.slice(1, router.asPath.length); + + if (userName.length > 0) { + const dynamicLinkData = await getProfileDynamicLink(userName); + + if (dynamicLinkData.status === 200) { + const link = dynamicLinkData.data.dynamicProfileLink; + + if (link) { + router.push(link); + console.log("redirecterd to:- ", link); + return; + } + } + } + } + + if (firebaseUser) { + redirectUserToDestinetion(); + } else { + setTimeout(() => { + setIsLoading(false); + }, 1000); + } + }; + + const [height, setHeight] = useState(0); + const carousel = useRef(); + useEffect(() => { + if (carousel?.current) { + setHeight(carousel.current.clientHeight); + // setWidth(carousel.current.scrollWidth - carousel.current.offsetWeidth); + } + }, []); + //animation + + document.documentElement.style.setProperty("--height", `${height}`); + + if (isLoading) { + return ; + } + + return ( + <> + + Witit + +
+
+ + + sendToHome()} /> + + +
+ {activeStep === 0 ? ( + <> + +
+ +
+ + ) : activeStep === 1 ? ( + <> + +
+ +
+ + ) : activeStep === -2 ? ( + + ) : ( + + )} +
+ +
+ + + {customDialogType === "TERMSOFSERVICE" ? ( + { + setCustomDialogType(null); + }} + /> + ) : customDialogType === "PRIVACYPOLICY" ? ( + { + setCustomDialogType(null); + }} + /> + ) : customDialogType === "CONTENTPOLICY" ? ( + { + setCustomDialogType(null); + }} + /> + ) : customDialogType === "CONTACTUS" ? ( + { + setCustomDialogType(null); + }} + /> + ) : null} + +
+ + ); +} diff --git a/pages/message.tsx b/pages/message.tsx new file mode 100644 index 0000000..a5fcf5c --- /dev/null +++ b/pages/message.tsx @@ -0,0 +1,69 @@ +import Image from "next/image"; +import React, { useEffect, useState } from "react"; +import CustomInputTextField from "@/components/shared/CustomInputTextField"; +import SearchIcon from "@/utils/icons/topbar/SearchIcon"; +import SendIcon from "@/utils/icons/circle/SendIcon"; +import { Divider, useMediaQuery } from "@mui/material"; +import CustomDrawer from "@/components/shared/drawer/CustomDrawer"; +import { useAuthContext } from "@/context/AuthContext"; +import PlusIcon from "@/utils/icons/shared/PlusIcon"; +import ThreeVerticalDots from "@/utils/icons/circle/ThreeVerticalDots"; +import { theme } from "@/theme"; +import PersonalChat from "@/components/message/PersonalChat"; +// import { MessageInfo } from "@/types"; +import twoMessageBox from "@/utils/images/twoMessageBox.svg"; +import RecentMessageListDrawer from "@/components/message/RecentMessageListDrawer"; +import Head from "next/head"; +import { useSelector } from "react-redux"; +import { RootState } from "@/redux/store"; +import MessageContext from "@/components/message/context/MessageContext"; +import Lottie from "lottie-react"; +import { startChatingLottie } from "@/utils/lottie"; + +const Message = () => { + const [isMessageListOpen, setisMessageListOpen] = useState(true); + const [isMessageBoxOpen, setIsMessageBoxOpen] = useState(false); + + const isSmallScreen = useMediaQuery(theme.breakpoints.down("xl")); // shift to useAuthContext + + useEffect(() => { + if (isSmallScreen) { + setisMessageListOpen(false); + } else { + setisMessageListOpen(true); + } + }, [isSmallScreen]); + + return ( + <> + + Witit - Message + + +
+
+ +
+ + {isMessageBoxOpen ? ( + + ) : ( +
+ {" "} + +

Start Chatting

+

By click on the User Name

+
+ )} +
+
+ + ); +}; + +export default Message; diff --git a/pages/profile.tsx b/pages/profile.tsx new file mode 100644 index 0000000..64ab367 --- /dev/null +++ b/pages/profile.tsx @@ -0,0 +1,48 @@ +import FeedIcon from "@/utils/icons/profile/FeedIcon"; +import MomentsIcon from "@/utils/icons/profile/MomentsIcon"; +import Head from "next/head"; +import Profile from "@/components/profile/Profile"; +import { QuestionnariesIcon } from "@/utils/icons/profile/QuestionnariesIcon"; +import ProfileContext from "@/components/profile/Profile/context/ProfileContext"; + +type ContentType = "FEED" | "QUESTIONNAIRES" | "MOMENTS"; + +type ProfileTab = { + name: string; + type: ContentType; + startIcon: JSX.Element; +}; + +const profileTabs: ProfileTab[] = [ + { + name: "Feed", + type: "FEED", + startIcon: , + }, + { + name: "Questionnaires", + type: "QUESTIONNAIRES", + startIcon: , + }, + { + name: "Moments", + type: "MOMENTS", + startIcon: , + }, +]; + +const ProfilePage = () => { + return ( + <> + + Witit - Profile + + + + + + + ); +}; + +export default ProfilePage; diff --git a/pages/setting.tsx b/pages/setting.tsx new file mode 100644 index 0000000..be642b6 --- /dev/null +++ b/pages/setting.tsx @@ -0,0 +1,22 @@ +import { useSelector } from "react-redux"; +import Head from "next/head"; +import { RootState } from "@/redux/store"; +import Settings from "@/components/setting"; + + +const SettingPage = () => { + + const user = useSelector((state: RootState) => state.user); + + if (!user) return <>; + + return ( + <> + + Witit - Setting + + + + ); +}; +export default SettingPage; diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..829eda8 --- /dev/null +++ b/public/404.html @@ -0,0 +1,33 @@ + + + + + + Page Not Found + + + + +
+

404

+

Page Not Found

+

The specified file was not found on this website. Please check the URL for mistakes and try again.

+

Why am I seeing this?

+

This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.

+
+ + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..5ce251d Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/fonts/Poppins-Regular.ttf b/public/fonts/Poppins-Regular.ttf new file mode 100644 index 0000000..9f0c71b Binary files /dev/null and b/public/fonts/Poppins-Regular.ttf differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..6a73af0 --- /dev/null +++ b/public/index.html @@ -0,0 +1,183 @@ + + + + + + Welcome to Firebase Hosting + + + + + + + + + + + + + + + + + + + + + + + +
+

Welcome

+

Firebase Hosting Setup Complete

+

+ You're seeing this because you've successfully setup Firebase Hosting. + Now it's time to go build something extraordinary! +

+ Open Hosting Documentation +
+

Firebase SDK Loading…

+ + + + + diff --git a/public/next.svg b/public/next.svg new file mode 100644 index 0000000..b27221c --- /dev/null +++ b/public/next.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/vercel.svg b/public/vercel.svg new file mode 100644 index 0000000..d2f8422 --- /dev/null +++ b/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/redux/slices/circleFeedSlice.ts b/redux/slices/circleFeedSlice.ts new file mode 100644 index 0000000..6be4a32 --- /dev/null +++ b/redux/slices/circleFeedSlice.ts @@ -0,0 +1,140 @@ +import { Post } from "@/types/post"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +type InitialPostList = Post[]; + +const circleFeedSlice = createSlice({ + name: "circleFeedPost", + initialState: [] as InitialPostList, + reducers: { + addCirclePost(state, action) { + return action.payload.length > 0 ? action.payload : []; + }, + updateCirclePost(state, action) { + const { postId, caption, category } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + caption: caption, + category: category, + } + : post + ); + return updatedState; + }, + updateCircleCommentCount(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + comment: post.counts.comment + 1, + }, + userActivity: { + ...post.userActivity, + isCommented: true, + }, + } + : post + ); + return updatedState; + }, + updateCircleLikeStatus(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + like: post.userActivity.isLiked + ? post.counts.like - 1 + : post.counts.like + 1, + }, + userActivity: { + ...post.userActivity, + isLiked: !post.userActivity.isLiked, + }, + } + : post + ); + return updatedState; + }, + updateCircleRepostStatus(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + repost: post.userActivity.isReposted + ? post.counts.repost - 1 + : post.counts.repost + 1, + }, + repostedBy: post.userActivity.isReposted ? null : post.repostedBy, + userActivity: { + ...post.userActivity, + isReposted: !post.userActivity.isReposted, + }, + } + : post + ); + return updatedState; + }, + deleteCirclePost(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.filter((post) => post.postId !== postId); + return updatedState; + }, + updateCirclePostView(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + userActivity: { + ...post.userActivity, + isViewed: true, + }, + } + : post + ); + return updatedState; + }, + updateCirclePostViewPrompt( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + isPromptAvailable: true, + userActivity: { + ...post.userActivity, + isAccessToViewPrompt: true, + }, + } + : post + ); + return updatedState; + }, + }, +}); + +export const { + addCirclePost, + updateCirclePost, + updateCircleLikeStatus, + updateCircleCommentCount, + updateCircleRepostStatus, + deleteCirclePost, + updateCirclePostView, + updateCirclePostViewPrompt, +} = circleFeedSlice.actions; +export default circleFeedSlice.reducer; diff --git a/redux/slices/creatorListSlice.ts b/redux/slices/creatorListSlice.ts new file mode 100644 index 0000000..0a55305 --- /dev/null +++ b/redux/slices/creatorListSlice.ts @@ -0,0 +1,17 @@ +import { SearchCreator } from "@/types/user"; +import { createSlice } from "@reduxjs/toolkit"; + +type InitialCreator = SearchCreator[]; + +const creatorListSlice = createSlice({ + name: "creators", + initialState: [] as InitialCreator, + reducers: { + concatCreator(state, action) { + return action.payload; + }, + }, +}); + +export const { concatCreator } = creatorListSlice.actions; +export default creatorListSlice.reducer; diff --git a/redux/slices/discoverFeedSlice.ts b/redux/slices/discoverFeedSlice.ts new file mode 100644 index 0000000..cb66fbf --- /dev/null +++ b/redux/slices/discoverFeedSlice.ts @@ -0,0 +1,28 @@ +import { DiscoverPost } from "@/types/post"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +type InitialPostList = DiscoverPost[]; + +const discoverFeedSlice = createSlice({ + name: "discoverPost", + initialState: [] as InitialPostList, + reducers: { + addDiscoverPost(state, action) { + return action.payload.length > 0 ? action.payload : []; + }, + updateDiscoverPost(state, action) { + console.log(action.payload); + }, + + deleteDiscoverPost(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.filter((post) => post.postId !== postId); + return updatedState; + }, + }, + +}); + +export const { addDiscoverPost, updateDiscoverPost, deleteDiscoverPost } = + discoverFeedSlice.actions; +export default discoverFeedSlice.reducer; diff --git a/redux/slices/discoverSimilarFeedSlice.ts b/redux/slices/discoverSimilarFeedSlice.ts new file mode 100644 index 0000000..bf38262 --- /dev/null +++ b/redux/slices/discoverSimilarFeedSlice.ts @@ -0,0 +1,156 @@ +import { Post } from "@/types/post"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +type InitialPostList = Post[]; + +const discoverSimilarFeedSlice = createSlice({ + name: "discoverSimilarPost", + initialState: [] as InitialPostList, + reducers: { + addSimilarDiscoverPost(state, action) { + return action.payload.length > 0 ? action.payload : []; + }, + + updateSimilarDiscoverPost(state, action) { + const { postId, caption, category } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + caption: caption, + category: category, + } + : post + ); + return updatedState; + }, + updateSimilarDiscoverCommentCount( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + comment: post.counts.comment + 1, + }, + userActivity: { + ...post.userActivity, + isCommented: true, + }, + } + : post + ); + return updatedState; + }, + updateSimilarDiscoverLikeStatus( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + like: post.userActivity.isLiked + ? post.counts.like - 1 + : post.counts.like + 1, + }, + userActivity: { + ...post.userActivity, + isLiked: !post.userActivity.isLiked, + }, + } + : post + ); + return updatedState; + }, + updateSimilarDiscoverRepostStatus( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + repost: post.userActivity.isReposted + ? post.counts.repost - 1 + : post.counts.repost + 1, + }, + repostedBy: post.userActivity.isReposted ? null : post.repostedBy, + userActivity: { + ...post.userActivity, + isReposted: !post.userActivity.isReposted, + }, + } + : post + ); + return updatedState; + }, + deleteSimilarDiscoverPost( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.filter((post) => post.postId !== postId); + return updatedState; + }, + updateSimilarDiscoverPostView( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + userActivity: { + ...post.userActivity, + isViewed: true, + }, + } + : post + ); + return updatedState; + }, + updateSimilarDiscoverPostViewPrompt( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + isPromptAvailable: true, + userActivity: { + ...post.userActivity, + isAccessToViewPrompt: true, + }, + } + : post + ); + return updatedState; + }, + }, +}); + +export const { + addSimilarDiscoverPost, + updateSimilarDiscoverPost, + updateSimilarDiscoverLikeStatus, + updateSimilarDiscoverCommentCount, + updateSimilarDiscoverRepostStatus, + deleteSimilarDiscoverPost, + updateSimilarDiscoverPostView, + updateSimilarDiscoverPostViewPrompt, +} = discoverSimilarFeedSlice.actions; +export default discoverSimilarFeedSlice.reducer; diff --git a/redux/slices/messageSlice.ts b/redux/slices/messageSlice.ts new file mode 100644 index 0000000..d236e1c --- /dev/null +++ b/redux/slices/messageSlice.ts @@ -0,0 +1,14 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const messageSlice = createSlice({ + name: "message", + initialState: null, + reducers: { + generate(state, action) { + return action.payload ? { ...action.payload } : null; + }, + }, +}); + +export const { generate } = messageSlice.actions; +export default messageSlice.reducer; diff --git a/redux/slices/modelSlice.ts b/redux/slices/modelSlice.ts new file mode 100644 index 0000000..44b69a1 --- /dev/null +++ b/redux/slices/modelSlice.ts @@ -0,0 +1,24 @@ +import { BaseModel, FriendModel, ModelContainer, UserModel } from "@/types/ai"; +import { createSlice } from "@reduxjs/toolkit"; + +const initialModelContainer: ModelContainer = { + baseModelList: [], + userModelList: [], + friendModelList: [], +}; + +const modelSlice = createSlice({ + name: "models", + initialState: initialModelContainer, + reducers: { + setModels(state, action) { + return action.payload ? { ...action.payload } : null; + }, + updateModels(state, action) { + return { ...state, ...action.payload }; + }, + }, +}); + +export const { setModels, updateModels } = modelSlice.actions; +export default modelSlice.reducer; diff --git a/redux/slices/paymentStatusSlice.ts b/redux/slices/paymentStatusSlice.ts new file mode 100644 index 0000000..8d82a8f --- /dev/null +++ b/redux/slices/paymentStatusSlice.ts @@ -0,0 +1,32 @@ +import { createSlice } from "@reduxjs/toolkit"; + +export type PaymentMethodStatus = { + paymentStatus: string | null; +}; +const paymentMethodStatus: PaymentMethodStatus = { + paymentStatus: "", +}; + +const paymentSlice = createSlice({ + name: "payments", + initialState: paymentMethodStatus, + reducers: { + setPaymentStatus(state, action) { + let value: PaymentMethodStatus = { + paymentStatus: "", + }; + if (action.payload === "true") { + value.paymentStatus = "true"; + } else if (action.payload === "false") { + value.paymentStatus = "false"; + } else { + value.paymentStatus = null; + } + + return value; + }, + }, +}); + +export const { setPaymentStatus } = paymentSlice.actions; +export default paymentSlice.reducer; diff --git a/redux/slices/userPostSlice.ts b/redux/slices/userPostSlice.ts new file mode 100644 index 0000000..85f50d3 --- /dev/null +++ b/redux/slices/userPostSlice.ts @@ -0,0 +1,143 @@ +import { Post } from "@/types/post"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +type InitialPostList = Post[]; + +const userPostSlice = createSlice({ + name: "userPost", + initialState: [] as InitialPostList, + reducers: { + addUserPost(state, action) { + return action.payload.length > 0 ? action.payload : []; + }, + updateUserPost(state, action) { + const { postId, category, caption } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + caption: caption, + category: category, + } + : post + ); + return updatedState; + }, + updateUserPostCommentCount( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + comment: post.counts.comment + 1, + }, + userActivity: { + ...post.userActivity, + isCommented: true, + }, + } + : post + ); + return updatedState; + }, + updateUserPostLikeStatus(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + like: post.userActivity.isLiked + ? post.counts.like - 1 + : post.counts.like + 1, + }, + userActivity: { + ...post.userActivity, + isLiked: !post.userActivity.isLiked, + }, + } + : post + ); + return updatedState; + }, + updateUserPostRepostStatus( + state, + action: PayloadAction<{ postId: string }> + ) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + counts: { + ...post.counts, + repost: post.userActivity.isReposted + ? post.counts.repost - 1 + : post.counts.repost + 1, + }, + repostedBy: post.userActivity.isReposted ? null : post.repostedBy, + userActivity: { + ...post.userActivity, + isReposted: !post.userActivity.isReposted, + }, + } + : post + ); + return updatedState; + }, + deleteUserPost(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.filter((post) => post.postId !== postId); + return updatedState; + }, + updateUserPostView(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + userActivity: { + ...post.userActivity, + isViewed: true, + }, + } + : post + ); + return updatedState; + }, + updateUserPostViewPrompt(state, action: PayloadAction<{ postId: string }>) { + const { postId } = action.payload; + const updatedState = state.map((post) => + post.postId === postId + ? { + ...post, + isPromptAvailable: true, + userActivity: { + ...post.userActivity, + isAccessToViewPrompt: true, + }, + } + : post + ); + return updatedState; + }, + }, +}); + +export const { + addUserPost, + updateUserPost, + deleteUserPost, + updateUserPostCommentCount, + updateUserPostLikeStatus, + updateUserPostRepostStatus, + updateUserPostView, + updateUserPostViewPrompt, +} = userPostSlice.actions; +export default userPostSlice.reducer; diff --git a/redux/slices/userSlice.ts b/redux/slices/userSlice.ts new file mode 100644 index 0000000..b7ca422 --- /dev/null +++ b/redux/slices/userSlice.ts @@ -0,0 +1,20 @@ +import { ReduxUser } from "@/types/user"; +import { createSlice } from "@reduxjs/toolkit"; + +type InitialUser = ReduxUser | null; + +const userSlice = createSlice({ + name: "user", + initialState: null as InitialUser, + reducers: { + setReduxUser(state, action: { payload: ReduxUser | null }) { + return action.payload ? { ...action.payload } : null; + }, + updateReduxUser(state, action: { payload: Partial }) { + if (state) return { ...state, ...action?.payload }; + }, + }, +}); + +export const { setReduxUser, updateReduxUser } = userSlice.actions; +export default userSlice.reducer; diff --git a/redux/slices/viewedNSFWSlice.ts b/redux/slices/viewedNSFWSlice.ts new file mode 100644 index 0000000..07b475c --- /dev/null +++ b/redux/slices/viewedNSFWSlice.ts @@ -0,0 +1,20 @@ +import { createSlice } from "@reduxjs/toolkit"; + +type InitialPostIdList = string[]; + +const viewedNSFWSlice = createSlice({ + name: "viewedNSFWSlice", + initialState: [] as InitialPostIdList, + reducers: { + addViewedNSFWPost(state, action) { + const postIdToAdd = action.payload.postId; + if (postIdToAdd && !state.includes(postIdToAdd)) { + return [...state, postIdToAdd]; + } + return state; + }, + }, +}); + +export const { addViewedNSFWPost } = viewedNSFWSlice.actions; +export default viewedNSFWSlice.reducer; diff --git a/redux/store.ts b/redux/store.ts new file mode 100644 index 0000000..20ccf5d --- /dev/null +++ b/redux/store.ts @@ -0,0 +1,89 @@ +import { SendNotification } from "./../types/common"; +import { configureStore, createAction } from "@reduxjs/toolkit"; +import messageReducer from "./slices/messageSlice"; +import userSlice from "./slices/userSlice"; +import storage from "redux-persist/lib/storage"; +import { combineReducers } from "redux"; +import { + persistStore, + persistReducer, + FLUSH, + REHYDRATE, + PAUSE, + PERSIST, + PURGE, + REGISTER, +} from "redux-persist"; +import userPostSlice from "./slices/userPostSlice"; +import modelSlice from "./slices/modelSlice"; +import { ReduxUser, SearchCreator } from "@/types/user"; +import { DiscoverPost, Post } from "@/types/post"; +import { ModelContainer } from "@/types/ai"; +import discoverFeedSlice from "./slices/discoverFeedSlice"; +import discoverSimilarFeedSlice from "./slices/discoverSimilarFeedSlice"; +import viewedNSFWSlice from "./slices/viewedNSFWSlice"; +import circleFeedSlice from "./slices/circleFeedSlice"; +import creatorListSlice from "./slices/creatorListSlice"; +import paymentStatusSlice, { + PaymentMethodStatus, +} from "./slices/paymentStatusSlice"; + +interface InitState { + message: null; + user: ReduxUser | null; + userPosts: Post[]; + discoverPosts: DiscoverPost[]; + discoverSimilarPosts: Post[]; + models: ModelContainer; + viewedNSFW: string[]; + circlePosts: Post[]; + creators: SearchCreator[]; + payments: PaymentMethodStatus; +} + +type RootAction = any; + +const persistConfig = { + key: "root", + storage, +}; + +const appReducer = combineReducers({ + message: messageReducer, + user: userSlice, + userPosts: userPostSlice, + discoverPosts: discoverFeedSlice, + discoverSimilarPosts: discoverSimilarFeedSlice, + models: modelSlice, + viewedNSFW: viewedNSFWSlice, + circlePosts: circleFeedSlice, + creators: creatorListSlice, + payments: paymentStatusSlice, +}); + +export const clearAll = createAction("USER_LOGOUT"); + +const rootReducer = (state: InitState | undefined, action: RootAction) => { + if (action.type === "USER_LOGOUT") { + storage.removeItem("persist:root"); + return appReducer(undefined, action); + } + + return appReducer(state, action); +}; + +export type RootState = ReturnType; + +const persistedReducer = persistReducer(persistConfig, rootReducer); + +export const store = configureStore({ + reducer: persistedReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], + }, + }), +}); + +export const persistor = persistStore(store); diff --git a/service/firebase/auth.ts b/service/firebase/auth.ts new file mode 100644 index 0000000..3e53663 --- /dev/null +++ b/service/firebase/auth.ts @@ -0,0 +1,127 @@ +import auth from "@/utils/firebase/firebaseConfig"; +import { + signOut, + onAuthStateChanged, + signInWithEmailAndPassword, + sendPasswordResetEmail, + createUserWithEmailAndPassword, + sendEmailVerification, + User, +} from "firebase/auth"; + +interface res { + status: number; + data: any; + msg: string; + error: any; +} + +export const getCurrentUser = async () => { + return new Promise((resolve, reject) => { + onAuthStateChanged( + auth, + async (user) => { + if (user) { + resolve(user); + } else { + resolve(null); + } + }, + reject + ); + }); +}; + +export function onAuth(callback: any) { + auth.onAuthStateChanged(callback); +} + +export const LoginToAccount = async (email: string, password: string) => { + let res: res = { status: 0, data: "", msg: "", error: "" }; + + try { + const userCredential = await signInWithEmailAndPassword( + auth, + email, + password + ); + res.status = 200; + res.data = userCredential?.user; + } catch (error: any) { + res.status = 0; + res.error = error.code; + } + return res; +}; + +export const ResetAccountPassword = async (email: string) => { + let res: res = { status: 0, data: "", msg: "", error: "" }; + + try { + const result = await sendPasswordResetEmail(auth, email); + res.status = 200; + res.msg = "Email Sent Successfully!"; + } catch (error: any) { + res.status = 0; + res.error = error.code; + } + return res; +}; + +export const signUpToFirebase = async (email: string, password: string) => { + let res: any = { status: 0, data: "", msg: "", error: "" }; + + await createUserWithEmailAndPassword(auth, email, password) + .then(async (userCredential) => { + // Signed in + const user = userCredential.user; + await sendEmail(user); + res.status = 200; + // ... + }) + .catch((error) => { + res.error = error.code; + res.msg = error.message; + // .. + }); + return res; +}; + +export const sendEmail = async (user: User) => { + let res: any = { status: 0, data: "", msg: "", error: "" }; + + var actionCodeSettings = { + url: + window.location.protocol + + "//" + + window.location.host + + "/account-setup?email=" + + user?.email, + handleCodeInApp: true, + }; + + try { + await sendEmailVerification(user, actionCodeSettings); + res.status = 200; + } catch (error: any) { + console.log(error); + res.error = error.code; + } + console.log(res); + return res; +}; + +export const firebaseLogout = async () => { + let res = { status: 0, data: "", error: "" }; + + try { + const data = await signOut(auth); + console.log("d:-----", data); + res.status = 200; + } catch (error: any) { + res.status = 0; + res.error = error.code; + } + + return res; +}; diff --git a/service/firebase/errorCode.ts b/service/firebase/errorCode.ts new file mode 100644 index 0000000..f3898a5 --- /dev/null +++ b/service/firebase/errorCode.ts @@ -0,0 +1,22 @@ +interface ErrorCodes { + [key: string]: string; +} + +const errorCodes: ErrorCodes = { + "auth/email-already-exists": "Email Already Registered!", + "auth/email-already-in-use": "Email Already Registered!", + "auth/invalid-continue-uri": "Invalid Success URL", + "auth/invalid-email": "Invalid Email", + "auth/invalid-password": "Invalid Password", + "auth/wrong-password": "Incorrect Password", + "auth/invalid-uid": "Invalid User Id", + "auth/user-not-found": "User Not Found", + "auth/too-many-requests":"Try After Sometime" +}; + +const getFirebaseErrorMessage = async (code: string) => { + if (errorCodes[code]) return errorCodes[code]; + return code; +}; + +export default getFirebaseErrorMessage; diff --git a/service/firebase/uploadImage.ts b/service/firebase/uploadImage.ts new file mode 100644 index 0000000..e09ffc3 --- /dev/null +++ b/service/firebase/uploadImage.ts @@ -0,0 +1,43 @@ +import "firebase/storage"; +import { getDownloadURL, ref, uploadBytes } from "firebase/storage"; +import { firebaseStorage } from "@/utils/firebase/firebaseConfig"; + +type Keys = { + folderName: + | "profile_picture_images" + | "generation_images" + | "update_ai_images" + | "creator_verification_image" + | "chat_images" + | "add_post" + | "offering_images"; + + file: Blob | Uint8Array | ArrayBuffer; + metadata: Record; +}; + +export async function uploadImageToStorage({ + folderName, + file, + metadata, +}: Keys) { + try { + const randomNumber = Math.floor(Math.random() * 90000) + 10000; + + const timestamp = Date.now(); + const extension = "jpeg"; + const storagePath = `${folderName}/${randomNumber}_${timestamp}.${extension}`; + + const storageRef = ref(firebaseStorage, storagePath); + + // 'file' comes from the Blob or File API + await uploadBytes(storageRef, file, metadata); + + const imageUrl = await getDownloadURL(storageRef); + + return imageUrl; + } catch (error) { + console.error("Error while uploading image to Firebase Storage:", error); + throw error; + } +} diff --git a/service/imageCropper/DisplayMultipleImages.ts b/service/imageCropper/DisplayMultipleImages.ts new file mode 100644 index 0000000..64d017b --- /dev/null +++ b/service/imageCropper/DisplayMultipleImages.ts @@ -0,0 +1,58 @@ +import { getObjectFit } from "@/service/shared/getObjectFit"; +import { ImageInfo } from "@/types"; +import appConstant from "@/utils/constants/withoutHtml/appConstant"; + +const DisplayMultipleImages = async ( + files: File[], + setImages: React.Dispatch< + React.SetStateAction< + { + image: ImageInfo; + index: number; + }[] + > + > +) => { + const newLoadedMultiImages: { + image: ImageInfo; + index: number; + }[] = await Promise.all<{ image: ImageInfo; index: number }>( + files.map((file, index) => { + return new Promise<{ image: ImageInfo; index: number }>( + (resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + let img = new Image(); + img.src = reader.result as string; + img.onload = () => { + resolve({ + image: { + src: reader.result as string, + croppedImageSrc: reader.result as string, + objectFit: getObjectFit({ + w: img.naturalWidth, + h: img.naturalHeight, + }), + aspectRatio: appConstant.defaultaspectRatio, + crop: { x: 0, y: 0 }, + zoom: 1, + croppedPixels: { x: 0, y: 0 }, + name: file?.name, + size: { width: 200, height: 200 }, + }, + index, + }); + }; + img.onerror = (error) => reject(`Error loading image: ${error}`); + }; + reader.onerror = (error) => reject(`Error reading file: ${error}`); + reader.readAsDataURL(file); + } + ); + }) + ); + + setImages(newLoadedMultiImages); +}; + +export default DisplayMultipleImages; diff --git a/service/imageCropper/DisplaySingleImage.ts b/service/imageCropper/DisplaySingleImage.ts new file mode 100644 index 0000000..c70bac5 --- /dev/null +++ b/service/imageCropper/DisplaySingleImage.ts @@ -0,0 +1,51 @@ +import { getObjectFit } from "@/service/shared/getObjectFit"; +import { ImageInfo } from "@/types"; + +const displaySingleImage = ( + file: File, + setImage: React.Dispatch< + React.SetStateAction<{ image: ImageInfo; index: number }> + > +) => { + // const { setCustomDialogType } = useAuthContext(); + + let filename = file?.name; + const reader = new FileReader(); + + reader.onload = () => { + // setTempImagePreview(reader.result as string); + // setCustomDialogType("CROPSINGLEIMG"); + + let img = new Image(); + img.src = reader.result as string; + img.onload = () => { + setImage((prev) => { + return { + ...prev, + image: { + ...prev.image, + src: reader.result as string, + croppedImageSrc: reader.result as string, + objectFit: getObjectFit({ + w: img.naturalWidth, + h: img.naturalHeight, + }), + crop: { x: 0, y: 0 }, + zoom: 1, + croppedPixels: { + x: 0, + y: 0, + width: img.naturalWidth, + height: img.naturalHeight, + }, + name: file?.name, + size: { width: img.naturalWidth, height: img.naturalHeight }, + }, + }; + }); + }; + }; + reader?.readAsDataURL(file); +}; + +export default displaySingleImage; diff --git a/service/imageCropper/cropImage.ts b/service/imageCropper/cropImage.ts new file mode 100644 index 0000000..df7b56b --- /dev/null +++ b/service/imageCropper/cropImage.ts @@ -0,0 +1,92 @@ +export const createImage = (url: string): Promise => + new Promise((resolve, reject) => { + const image = new Image(); + image.addEventListener("load", () => resolve(image)); + image.addEventListener("error", (error) => reject(error)); + image.setAttribute("crossOrigin", "anonymous"); // needed to avoid cross-origin issues on CodeSandbox + image.src = url; + }); + +export function getRadianAngle(degreeValue: number): number { + return (degreeValue * Math.PI) / 180; +} + +/** + * Returns the new bounding area of a rotated rectangle. + */ +export function rotateSize(width: number, height: number, rotation: number) { + const rotRad = getRadianAngle(rotation); + + return { + width: + Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height), + height: + Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height), + }; +} + +/** + * This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop + */ +export default async function getCroppedImg( + imageSrc: string, + pixelCrop: { x: number; y: number; width: number; height: number }, + rotation = 0, + flip = { horizontal: false, vertical: false } +): Promise { + const image = await createImage(imageSrc); + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + + if (!ctx) { + return null; + } + + const rotRad = getRadianAngle(rotation); + + // calculate bounding box of the rotated image + const { width: bBoxWidth, height: bBoxHeight } = rotateSize( + image.width, + image.height, + rotation + ); + + // set canvas size to match the bounding box + canvas.width = bBoxWidth; + canvas.height = bBoxHeight; + + // translate canvas context to a central location to allow rotating and flipping around the center + ctx.translate(bBoxWidth / 2, bBoxHeight / 2); + ctx.rotate(rotRad); + ctx.scale(flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1); + ctx.translate(-image.width / 2, -image.height / 2); + + // draw rotated image + ctx.drawImage(image, 0, 0); + + // croppedAreaPixels values are bounding box relative + // extract the cropped image using these values + const data = ctx.getImageData( + pixelCrop.x, + pixelCrop.y, + pixelCrop.width, + pixelCrop.height + ); + + // set canvas width to final desired crop size - this will clear existing context + canvas.width = pixelCrop.width; + canvas.height = pixelCrop.height; + + // paste generated rotate image at the top left corner + ctx.putImageData(data, 0, 0); + + // As Base64 string + // return canvas.toDataURL('image/jpeg'); + + // As a blob + return new Promise((resolve, reject) => { + canvas.toBlob((file) => { + if (file) resolve(URL.createObjectURL(file)); + }, "image/jpeg"); + }); +} diff --git a/service/manageCredit/createCreditArray.ts b/service/manageCredit/createCreditArray.ts new file mode 100644 index 0000000..ac4e91d --- /dev/null +++ b/service/manageCredit/createCreditArray.ts @@ -0,0 +1,29 @@ +export function generateArray(start: number, end: number) { + const resultArray: number[] = []; + + // Define the ranges and corresponding increments + const ranges = [ + { start: 10, end: 100, increment: 10 }, + { start: 100, end: 1000, increment: 50 }, + { start: 1000, end: 2000, increment: 100 }, + { start: 2000, end: 5000, increment: 500 }, + { start: 5000, end: 10000, increment: 1000 }, + ]; + + // Generate the array based on user-specified start and end values + ranges.forEach((range) => { + if (start < range.end && end > range.start) { + const min = Math.max(start, range.start); + const max = Math.min(end, range.end); + + for (let i = min; i <= max; i += range.increment) { + // Check if the value is not already in the resultArray + if (!resultArray.includes(i)) { + resultArray.push(i); + } + } + } + }); + + return resultArray; +} diff --git a/service/manageCredit/getCreditObjectToUpdateCreditModel.ts b/service/manageCredit/getCreditObjectToUpdateCreditModel.ts new file mode 100644 index 0000000..0458fdd --- /dev/null +++ b/service/manageCredit/getCreditObjectToUpdateCreditModel.ts @@ -0,0 +1,47 @@ +type GetCreditObjProps = { + creditObj: { + tempCredit: number; + nonTransferableCredit: number; + transferableCredit: number; + }; + credit: number; +}; + +export const getCreditObjectToUpdateCreditModel = ({ + creditObj, + credit, +}: GetCreditObjProps) => { + let remainingCredit = credit; + + const cutFromTransferableCredit = Math.min( + remainingCredit, + creditObj.transferableCredit + ); + remainingCredit -= cutFromTransferableCredit; + + const cutFromNonTransferableCredit = Math.min( + remainingCredit, + creditObj.nonTransferableCredit + ); + remainingCredit -= cutFromNonTransferableCredit; + + const newTransferableCredit = Math.max( + 0, + creditObj.transferableCredit - cutFromTransferableCredit + ); + + const newNonTransferableCredit = Math.max( + 0, + creditObj.nonTransferableCredit - cutFromNonTransferableCredit + ); + + const newTempCredit = Math.max(0, creditObj.tempCredit - remainingCredit); + + return { + credit: { + transferableCredit: newTransferableCredit, + nonTransferableCredit: newNonTransferableCredit, + tempCredit: newTempCredit, + }, + }; +}; diff --git a/service/profile/getFormatedSocialLinks.ts b/service/profile/getFormatedSocialLinks.ts new file mode 100644 index 0000000..3e46957 --- /dev/null +++ b/service/profile/getFormatedSocialLinks.ts @@ -0,0 +1,21 @@ +import { LinkedAccounts } from "@/types/user"; + +type SocialAccount = { + name: string; + value: string; +}; + +export const getFormatedSocialLinks = (linkedAccounts: LinkedAccounts) => { + const socialAccounts: SocialAccount[] = []; + + Object.entries(linkedAccounts).forEach(([key, value]) => { + if (value) { + socialAccounts.push({ + name: key[0].toUpperCase() + key.slice(1), + value, + }); + } + }); + + return socialAccounts; +}; diff --git a/service/shared/convertEmptyFieldToNull.ts b/service/shared/convertEmptyFieldToNull.ts new file mode 100644 index 0000000..dbb5fb7 --- /dev/null +++ b/service/shared/convertEmptyFieldToNull.ts @@ -0,0 +1,18 @@ +type Obj = { + [key: string]: any; +}; + +export const convertEmptyToNull = (obj: Obj): Obj => { + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key] === "object" && obj[key] !== null) { + // Recursively process nested objects + obj[key] = convertEmptyToNull(obj[key]); + } else if (obj[key] === "") { + // Convert empty string to null + obj[key] = null; + } + } + } + return obj; +}; diff --git a/service/shared/formatLargeNumber.ts b/service/shared/formatLargeNumber.ts new file mode 100644 index 0000000..23ed0dd --- /dev/null +++ b/service/shared/formatLargeNumber.ts @@ -0,0 +1,21 @@ +type Props = { + value: number; +}; + +export const formatLargeNumber = (value: number) => { + if (value >= 1000000000) { + let result = value / 1000000000; + return result.toFixed(result % 1 === 0 ? 0 : 1) + "B+"; + } else if (value >= 1000000) { + let result = value / 1000000; + return result.toFixed(result % 1 === 0 ? 0 : 1) + "M+"; + } else if (value >= 1000) { + let result = value / 1000; + return result.toFixed(result % 1 === 0 ? 0 : 1) + "k+"; + } else if (value >= 100) { + return value.toString(); + } else if (value >= 10) { + return value.toString(); + } + return value.toString(); +}; diff --git a/service/shared/getDayFromTimeStamp.ts b/service/shared/getDayFromTimeStamp.ts new file mode 100644 index 0000000..642e272 --- /dev/null +++ b/service/shared/getDayFromTimeStamp.ts @@ -0,0 +1,18 @@ +import dayjs from "dayjs"; +type Props = { + time: string; +}; + +export const getDayFromTimeStamp = ({ time }: Props) => { + let day = ""; + + if (dayjs(time).unix() > dayjs().subtract(1, "day").unix()) { + day = "Today"; + } else if (dayjs(time).unix() > dayjs().subtract(2, "day").unix()) { + day = "Yesterday"; + } else { + day = dayjs(time).format("DD MMM, YYYY"); + } + + return day; +}; diff --git a/service/shared/getImageObject.ts b/service/shared/getImageObject.ts new file mode 100644 index 0000000..f01364e --- /dev/null +++ b/service/shared/getImageObject.ts @@ -0,0 +1,7 @@ +export const getImageObject = async (url: string) => { + const response = await fetch(url); + const blob = await response.blob(); + const file = new File([blob], "image.jpg", { type: blob.type }); + + return { blob: URL.createObjectURL(blob), file }; +}; diff --git a/service/shared/getObjectFit.ts b/service/shared/getObjectFit.ts new file mode 100644 index 0000000..484572d --- /dev/null +++ b/service/shared/getObjectFit.ts @@ -0,0 +1,18 @@ +import { ObjectFit } from "@/types"; + +type Props = { + w: number; + h: number; +}; + +export const getObjectFit = ({ w, h }: Props) => { + let data: ObjectFit = "horizontal-cover"; + + if (h - w < 80) { + data = "vertical-cover"; + } else { + data = "horizontal-cover"; + } + + return data; +}; diff --git a/service/shared/getRecentTimeFromTimeStamp.ts b/service/shared/getRecentTimeFromTimeStamp.ts new file mode 100644 index 0000000..47b967f --- /dev/null +++ b/service/shared/getRecentTimeFromTimeStamp.ts @@ -0,0 +1,29 @@ +export const getRecentTimeFromTimeStamp = (time: string) => { + let timeAgo = ""; + + const currentTime = new Date().getTime() as number; + const targetTime = new Date(time).getTime() as number; + const timeDifference = currentTime - targetTime; + + const seconds = Math.floor(timeDifference / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + const months = Math.floor(days / 30); + const years = Math.floor(months / 12); + + if (seconds < 60) { + timeAgo = `${seconds} sec ago`; + } else if (minutes < 60) { + timeAgo = `${minutes} min ago`; + } else if (hours < 24) { + timeAgo = `${hours} hr ago`; + } else if (days < 30) { + timeAgo = `${days} day ago`; + } else if (months < 12) { + timeAgo = `${months} month ago`; + } else { + timeAgo = `${years} year ago`; + } + return timeAgo; +}; diff --git a/service/shared/localStorageOperations.ts b/service/shared/localStorageOperations.ts new file mode 100644 index 0000000..b5ff2fc --- /dev/null +++ b/service/shared/localStorageOperations.ts @@ -0,0 +1,23 @@ +export const saveDataLocal = (key: string, value: any, document: any) => { + document.cookie = `${key}=${JSON.stringify(value)}`; +}; + +export const getDataLocal = async (cname: string, document: any) => { + let name = cname + "="; + let decodedCookie = decodeURIComponent(document.cookie); + let ca = decodedCookie.split(";"); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) == " ") { + c = c.substring(1); + } + if (c.indexOf(name) == 0) { + return c.substring(name.length + 1, c.length - 1); + } + } + return ""; +}; + +export const deleteDataLocal = (name: string, document: any) => { + document.cookie = name + "=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"; +}; diff --git a/service/shared/redirectTouserProfile.ts b/service/shared/redirectTouserProfile.ts new file mode 100644 index 0000000..9b7c714 --- /dev/null +++ b/service/shared/redirectTouserProfile.ts @@ -0,0 +1,12 @@ +export function redirectTouserProfile( + redirectUser: string, + userId: string | undefined +) { + let url = window.location.protocol + "//" + window.location.host; + if (userId === redirectUser) { + url = url + "/profile"; + } else { + url = url + "/profile?user=" + redirectUser; + } + return url; +} diff --git a/styles/globals.css b/styles/globals.css new file mode 100644 index 0000000..c35a211 --- /dev/null +++ b/styles/globals.css @@ -0,0 +1,384 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; +@import "./slick/slick-theme.css"; +@import "./slick/slick.css"; + +@font-face { + font-family: "Poppins"; + src: url("../public/fonts/Poppins-Regular.ttf"); + + font-weight: normal; + font-style: normal; +} + +/* width */ +::-webkit-scrollbar { + width: 4px; + height: 4px; +} +/* Track */ +::-webkit-scrollbar-track { + border-radius: 10px; + background-color: #ffffff10; +} +/* Handle */ +::-webkit-scrollbar-thumb { + border-radius: 10px; + background-color: #8d9091b2; +} + +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "Poppins" !important; +} + +input:-webkit-autofill, +input:-webkit-autofill:focus { + transition: background-color 600000s 0s, color 600000s 0s; +} +input[data-autocompleted] { + background-color: transparent !important; +} +@layer components { + body { + color: rgb(var(--foreground-rgb)); + background: #17181b; + @apply m-0; + } +} +/* ........login animation....... */ +.wrapper { + width: 50%; + overflow: hidden; +} +.contenr { + position: absolute; + width: 147%; + min-width: 150vh; + transform: matrix(0.95, 0.32, -0.71, 0.71, 0, 0); +} +.slider_img { + display: block; + position: relative; + width: auto; + height: 42.5vh; + margin: 18px; + aspect-ratio: 4/5; + border-radius: 8px; + user-select: none; + -moz-user-select: none; + overflow: hidden; + object-fit: cover; + object-position: center; + background-repeat: no-repeat; + background: #282828; +} +.slide_b-t div { + position: relative; + top: 75vh; + animation: track 100s linear infinite; + justify-content: space-around; +} +.slide_t-b div { + position: relative; + top: -75vh; + animation: track-r 100s linear infinite; + justify-content: space-around; +} +p { + letter-spacing: 0.05em !important; + font-size: 0.875rem; +} +div { + color: white; +} + +@keyframes track { + 0% { + transform: translateY(0%); + } + 100% { + transform: translateY(-89.78%); + } +} +@keyframes track-r { + 0% { + transform: translateY(0%); + } + 100% { + transform: translateY(89.78%); + } +} +/* ........terms & policy........ */ +.heading { + font-size: 1.8rem; +} +.title { + font-size: 1.2rem; +} +.description { + padding-top: 5px; + font-size: 0.875rem; + gap: 10px; +} +.list { + gap: 5; + list-style-type: disc; + list-style-position: outside; +} +/* ---------- blink notification circle ----------------*/ +.circle { + position: absolute; + margin: 0 auto; + width: 6.5px; + height: 6.5px; + border-radius: 50%; + transition: all 0.3s; + background-color: #0b7bff; + animation: pulse 1s infinite; + top: 1.7px; + right: 1.7px; +} +@keyframes pulse { + 0% { + transform: scale(1); + opacity: 1; + } + 60% { + transform: scale(1.5); + opacity: 1; + } + 80% { + transform: scale(1.5); + opacity: 0; + } + 100% { + transform: scale(1); + opacity: 1; + } +} +.overlay_shadow::before { + content: ""; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.6), 0 2px 2px rgba(0, 0, 0, 0.6), + 0 4px 4px rgba(0, 0, 0, 0.6), 0 8px 8px rgba(0, 0, 0, 0.6), + 0 16px 16px rgba(0, 0, 0, 0.6); + mix-blend-mode: soft-light; +} + +.slide-in { + animation: slide-in 1s forwards; + -webkit-animation: slide-in 1s forwards; +} + +.slide-out { + animation: slide-out 1s forwards; + -webkit-animation: slide-out 1s forwards; +} + +@keyframes slide-in { + 0% { + transform: translateX(100%); + } + 100% { + transform: translateX(0); + } +} + +@keyframes slide-out { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(100%); + } +} + +#india { + transition: fill 0.5s; + fill: #000000; +} + +#india:hover { + stroke: hotpink; +} + +.slick_slider_arrow .slick-prev { + position: absolute; + z-index: 20; + display: flex !important; + align-items: center; + justify-content: center; + margin-left: 10px; + margin-right: 10px; +} +.slick_slider_arrow .slick-next { + position: absolute; + z-index: 20; + display: flex !important; + align-items: center; + justify-content: center; + margin-left: 10px; + margin-right: 10px; +} +.slick_slider_arrow .slick-dots { + bottom: 5px; +} +.slick_slider_arrow .slick-dots li button:before { + font-size: 20px; +} + +.slick-slider_center-mode .slick-slide { + transform: scale(0.8); + transition: all 0.1s ease-in-out; +} + +.slick-slider_center-mode .slick-slide.slick-active.slick-center.slick-current { + color: #000000; +} + +.slick-slider_center-mode .slick-center { + position: relative; + transform: scale(1.1); + /* background-color: #26272c; */ + border-radius: 10px; +} + +.slick-slider_center-mode .div { + max-width: 100%; + transition: all 0.4s ease-in-out; +} + +.slick_slider_arrow .slick-list, +.slick_slider_arrow .slick-track { + height: 100%; +} +.slick_slider_arrow .slick-list .slick-slide { + height: 100%; + background-color: #000000; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; +} + +div.corner-border { + position: relative; + height: 100%; + width: 100%; +} + +/* div.corner-border:before, +div.corner-border:after { + content: ""; + z-index: 50; + position: absolute; +} + +div.corner-border:before { + border-left: 3px solid white; + border-top: 3px solid white; + width: 20px; + height: 20px; + left: 0px; + top: 0px; +} + +div.corner-border:after { + border-right: 3px solid white; + border-bottom: 3px solid white; + width: 20px; + height: 20px; + right: 0px; + bottom: 0px; +} */ +.div:before, +.div:after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + border: 3px solid white; +} + +.div:before { + left: -1px; + top: -1px; + border-bottom: none; + border-right: none; +} + +.div:after { + right: -1px; + bottom: -1px; + border-top: none; + border-left: none; +} +/* cropper Border */ +.reactEasyCrop_CropArea { + background: linear-gradient(to right, white 2px, #00000000 2px) 0 0, + linear-gradient(to right, white 2px, #00000000 2px) 0 50%, + linear-gradient(to right, white 2px, #00000000 2px) 0 100%, + linear-gradient(to left, white 2px, #00000000 2px) 100% 0, + linear-gradient(to left, white 2px, #00000000 2px) 100% 50%, + linear-gradient(to left, white 2px, #00000000 2px) 100% 100%, + linear-gradient(to bottom, white 2px, #00000000 2px) 0 0, + linear-gradient(to bottom, white 2px, #00000000 2px) 50% 0, + linear-gradient(to bottom, white 2px, #00000000 2px) 100% 0, + linear-gradient(to top, white 2px, #00000000 2px) 0 100%, + linear-gradient(to top, white 2px, #00000000 2px) 50% 100%, + linear-gradient(to top, white 2px, #00000000 2px) 100% 100%; + background-repeat: no-repeat !important; + background-size: 30px 30px; + border: none; +} + +.crop_bottom_line { + background: linear-gradient(to right, white 2px, #00000000 2px) 0 100%, + linear-gradient(to left, white 2px, #00000000 2px) 100% 100%, + linear-gradient(to top, white 2px, #00000000 2px) 0 100%, + linear-gradient(to top, white 2px, #00000000 2px) 50% 100%, + linear-gradient(to top, white 2px, #00000000 2px) 100% 100%; + background-repeat: no-repeat !important; + background-size: 30px 30px; + border: none; + z-index: 18; +} + +/* inputtext type:number remove up-down arrows */ +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type="number"] { + -moz-appearance: textfield; +} + +img { + pointer-events: "none"; +} + +.slick_slider_arrow { +} diff --git a/styles/slick/slick-theme.css b/styles/slick/slick-theme.css new file mode 100644 index 0000000..18910fd --- /dev/null +++ b/styles/slick/slick-theme.css @@ -0,0 +1,176 @@ +/* Arrows */ +.slick-prev, +.slick-next { + font-size: 0; + line-height: 0; + + /* position: absolute; */ + top: 50%; + + display: block; + width: 36px; + height: 36px; + /* min-height: 15px; + min-width: 15px; */ + padding: 0; + + /* -webkit-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); */ + + cursor: pointer; + + color: transparent; + border: none; + outline: none; + background: transparent; +} +.slick-prev:hover, +.slick-prev:focus, +.slick-next:hover, +.slick-next:focus { + color: transparent; + outline: none; + background: transparent; +} +.slick-prev:hover:before, +.slick-prev:focus:before, +.slick-next:hover:before, +.slick-next:focus:before { + opacity: 1; +} +.slick-prev.slick-disabled:before, +.slick-next.slick-disabled:before { + opacity: 0.25; +} + +.slick-prev:before, +.slick-next:before { + font-family: "slick"; + font-size: 20px; + line-height: 1; + + opacity: 0.75; + color: white; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.slick-prev { + margin-left: 16px; + margin-right: 16px; + left: 0; +} +[dir="rtl"] .slick-prev { + right: 0; + left: auto; + margin-left: 16px; + margin-right: 16px; +} +.slick-prev:before { + content: ""; +} +[dir="rtl"] .slick-prev:before { + content: ""; +} + +.slick-next { + right: 0; + margin-left: 16px; + margin-right: 16px; +} +[dir="rtl"] .slick-next { + right: auto; + left: 0; + margin-left: 16px; + margin-right: 16px; +} +.slick-next:before { + content: ""; +} +[dir="rtl"] .slick-next:before { + content: ""; +} + +/* Dots */ +.slick-dotted.slick-slider { + margin-bottom: 30px; +} + +.slick-dots { + position: absolute; + bottom: -50px; + + display: block; + + width: 100%; + padding: 0; + margin: 0; + + list-style: none; + + text-align: center; +} +.slick-dots li { + position: relative; + + display: inline-block; + + width: 20px; + height: 20px; + margin: 0 5px; + padding: 0; + + cursor: pointer; +} +.slick-dots li button { + font-size: 0; + line-height: 0; + + display: block; + + width: 20px; + height: 20px; + padding: 5px; + + cursor: pointer; + + color: transparent; + border: 0; + outline: none; + background: transparent; +} +.slick-dots li button:hover, +.slick-dots li button:focus { + outline: none; +} +.slick-dots li button:hover:before, +.slick-dots li button:focus:before { + opacity: 1; +} +.slick-dots li button:before { + font-family: "slick"; + font-size: 6px; + line-height: 20px; + + position: absolute; + top: 0; + left: 0; + + width: 20px; + height: 20px; + + content: "•"; + text-align: center; + + opacity: 0.25; + color: white; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.slick-dots li.slick-active button:before { + opacity: 0.75; + color: white; +} diff --git a/styles/slick/slick.css b/styles/slick/slick.css new file mode 100644 index 0000000..26977c0 --- /dev/null +++ b/styles/slick/slick.css @@ -0,0 +1,101 @@ +/* Slider */ +.slick-slider { + position: relative; + + display: block; + box-sizing: border-box; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + -webkit-touch-callout: none; + -khtml-user-select: none; + -ms-touch-action: pan-y; + touch-action: pan-y; + -webkit-tap-highlight-color: transparent; +} + +.slick-list { + position: relative; + + display: block; + overflow: hidden; + + margin: 0; + padding: 0; +} +.slick-list:focus { + outline: none; +} +.slick-list.dragging { + cursor: pointer; + cursor: hand; +} + +.slick-slider .slick-track, +.slick-slider .slick-list { + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.slick-track { + position: relative; + top: 0; + left: 0; + + display: block; + margin-left: auto; + margin-right: auto; +} +.slick-track:before, +.slick-track:after { + display: table; + + content: ""; +} +.slick-track:after { + clear: both; +} +.slick-loading .slick-track { + visibility: hidden; +} + +.slick-slide { + display: none; + float: left; + height: 100%; + min-height: 1px; +} +[dir="rtl"] .slick-slide { + float: right; +} +.slick-slide img { + display: block; +} +.slick-slide.slick-loading img { + display: none; +} +.slick-slide.dragging img { + pointer-events: none; +} +.slick-initialized .slick-slide { + display: block; +} +.slick-loading .slick-slide { + visibility: hidden; +} +.slick-vertical .slick-slide { + display: block; + + height: auto; + + border: 1px solid transparent; +} +.slick-arrow.slick-hidden { + display: none; +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..3c61755 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,72 @@ +/** @type {import('tailwindcss').Config} */ + +export const colorPalette = { + grey: { + // 50: "#0", + 100: "#CCCCCC", + 200: "#999999", + 300: "#808080", + 400: "#666666", + 500: "#3C3D3F", + 600: "#333436", + 700: "#2A2A2D", + 800: "#202124", + 900: "#1C1D20", + A100: "#3E424D", + A200: "#2C2F36", + A400: "#2A2C32", + A700: "#26272C", + }, + common: { + white: "#fff", + black: "#000", + }, + transparent: { main: "#00000000" }, + primary: { main: "#0677E8", light: "#3097FF", dark: "#171F29" }, + secondary: { main: "#17181B", light: "#17181bcd" }, + success: { main: "#40C34D", dark: "#1FDC1B", light: "#0EA32E" }, + error: { main: "#DD5757", dark: "#642728", light: "#A04041" }, + orange: { main: "#FFA000" }, + blue: { light: "#50D5FF", main: "#1448FF", dark: "#6597BE" }, + green: { main: "#1FA682" }, +}; + +module.exports = { + content: [ + "./pages/**/*.{js,ts,jsx,tsx}", + "./components/**/*.{js,ts,jsx,tsx}", + "./app/**/*.{js,ts,jsx,tsx}", + "./context/**/*.{js,ts,jsx,tsx}", + ], + theme: { + colors: { + ...colorPalette, + }, + screens: { + xs: "0px", + sm: "640px", + md: "768px", + lg: "1024px", + xl: "1280px", + xxl: "1536px", + }, + + extend: { + fontSize: { + "2sm": "0.8125rem", + "2xs": "0.7rem", + }, + backgroundImage: { + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + }, + fontFamily: { + sans: ["Poppins"], + }, + }, + }, + plugins: [], + corePlugins: { preflight: true }, + important: true, +}; diff --git a/theme/index.ts b/theme/index.ts new file mode 100644 index 0000000..a5030c4 --- /dev/null +++ b/theme/index.ts @@ -0,0 +1,82 @@ +import { Color, createTheme } from "@mui/material"; + +export const colorPalette = { + grey: { + // 50: "#0", + 100: "#CCCCCC", + 200: "#999999", + 300: "#808080", + 400: "#666666", + 500: "#3C3D3F", + 600: "#333436", + 700: "#2A2A2D", + 800: "#202124", + 900: "#1C1D20", + A100: "#3E424D", + A200: "#2C2F36", + A400: "#2A2C32", + A700: "#26272C", + }, + common: { + white: "#fff", + black: "#000", + }, + primary: { main: "#0677E8", light: "#3097FF", dark: "#171F29" }, + secondary: { main: "#17181B", light: "#17181bcd" }, + success: { main: "#40C34D", dark: "#1FDC1B", light: "#0EA32E" }, + error: { main: "#DD5757", dark: "#642728", light: "#A04041" }, + orange: { main: "#FFA000" }, + blue: { light: "#50D5FF", main: "#1448FF", dark: "#6597BE" }, + green: { main: "#1FA682" }, +}; + +export const theme = createTheme({ + palette: { ...colorPalette }, + typography: { + fontFamily: [ + "Poppins", + "Roboto", + "Helvetica Neue", + "Arial", + "sans-serif", + ].join(","), + button: { + fontSize: 16, + fontWeight: 500, + textTransform: "none", + }, + }, + breakpoints: { + values: { + xs: 0, + sm: 640, + md: 768, + lg: 1024, + xl: 1280, + xxl: 1536, + }, + }, +}); +// Typescript module augmentation +import "@mui/material"; +declare module "@mui/material/styles" { + interface Palette { + orange: Palette["primary"]; + blue: Palette["primary"]; + green: Palette["primary"]; + } + interface PaletteOptions { + orange?: PaletteOptions["primary"]; + blue?: PaletteOptions["primary"]; + green?: PaletteOptions["primary"]; + } + interface BreakpointOverrides { + // xxs: true; + xs: true; + sm: true; + md: true; + lg: true; + xl: true; + xxl: true; + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8b8e581 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/types/activity.ts b/types/activity.ts new file mode 100644 index 0000000..0a7fb9c --- /dev/null +++ b/types/activity.ts @@ -0,0 +1,45 @@ +export type ActivityInfo = { + title: string; + message: string | null; + frontImage: string; + otherInfo: string | null; + backImage: string | null; +}; + +type Action = { + actionTakerId: string; + postId: string | null; +}; + +type GenerationDetails = { + id: string; + creatorId: string; + postId: string | null; +}; + +export type ActivityType = + | "USER_NOTIFICATION" + | "CREATOR_NOTIFICATION" + | "CREDIT_NOTIFICATION" + | "POST_NOTIFICATION" + | "GENERATION_NOTIFICATION" + | "USER_GENERATION_NOTIFICATION" + | "CREATOR_GENERATION_NOTIFICATION" + | "QUESTION_NOTIFICATION"; + +export type Activity = { + activityId: string; + userId: string; + activity: ActivityInfo; + action: Action; + generationDetails: GenerationDetails | null; + activityType: ActivityType; + createdAt: string; + updatedAt: string; +}; + +export type ActivityCounts = { + notification: number; + offerCreated: number; + offerReceived: number; +}; diff --git a/types/ai.ts b/types/ai.ts new file mode 100644 index 0000000..1cf4710 --- /dev/null +++ b/types/ai.ts @@ -0,0 +1,182 @@ +import exp from "constants"; +import { Image } from "./post"; +import { UserType } from "./user"; + +export type AiApplication = { + applicationId: string; + userId: string; + applicationStatus: "APPROVED" | "REJECTED" | "PENDING" | "TRAINING"; + modelName: string; + message: string | null; + createdAt: string; +}; + +type Creator = { + id: string; + userName: string; +}; + +type GeneratedFrom = { + id: string | null; + image: string | null; +}; + +type ModelDetails = { + id: string; + type: string; + name: string; +}; + +export type FaceDetails = { + definition: number; + preservationStrength: number; +}; + +export type HandDetails = { + definition: number; + preservationStrength: number; +}; + +export type ImageSize = "sm" | "md" | "lg"; + +export type AspectRatio = "2:3" | "5:4" | "1:1" | "3:2" | "4:5"; + +export type Resolution = 1 | 1.5 | 2; + +export type CreationSettings = { + imageSize: ImageSize; + aspectRatio: AspectRatio; + promptStrength: number; + definition: number; + restoreFace: boolean; + preserveFaceDetails: FaceDetails | null; + preserveHandDetails: HandDetails | null; +}; + +export type RecreationSettings = { + recreationType: string | null; + recreationTypeStrength: number | null; + recreationStrength: number; +}; + +export type GenerationSetting = { + negativePrompt: string[]; + creationSettings: CreationSettings; + recreationSettings: RecreationSettings | null; + inPaintingSettings: InPaintingSettings | null; + hiResSettings: HiResSettings | null; +}; + +export type HiResSettings = { + definition: number; + similarityStrength: number; + increaseResolution: Resolution; +}; +export type InPaintingSettings = { recreateMaskOnly: boolean }; + +export type GetAiGeneration = { + Id: string; + userId: string; + prompt: string; + negativePrompt: string[]; + generationId: string[]; + status: "SUCCESS" | "PENDING" | "FAILURE"; + message: string; + creator: Creator | null; + generatedFrom: GeneratedFrom | null; + modelDetails: ModelDetails; + remainingGeneration: number; + superShoot: boolean; + isAccessible: boolean; + creationSettings: CreationSettings; + recreationSettings: RecreationSettings | null; + inPaintingSettings: InPaintingSettings | null; + hiResSettings: HiResSettings | null; + generationImages: Image[]; + createdAt: string; + updatedAt: string; +}; + +export type PostAiGeneration = { + prompt: string; + modelId: number | string; + negativePrompt: string[]; + postId: string | null; + numberOfGenerations: number; + superShoot: boolean; + image: string | null; + creationSettings: CreationSettings; + recreationSettings: RecreationSettings | null; + inPaintingSettings: InPaintingSettings | null; + hiResSettings: HiResSettings | null; +}; + +type WithOutSuperShoot = { + creditPerGeneration: number; +}; + +type WithSuperShoot = { + creditPerGeneration: number; +}; + +export type AiCharges = { + numberOfGeneration: number; + withOutSuperShoot: WithOutSuperShoot; + withSuperShoot: WithSuperShoot; +}; + +export type SuperShoot = { + multiplierConstant: number; + discountConstant: number; +}; + +export type BaseModel = { + modelName: string; + modelId: number | string; + isActive: boolean; +}; + +type Counts = { + generatedImages: number; + creditEarn: number; +}; + +export type ClassType = "Man" | "Woman" | "Style" | "Base"; + +type GenerationSettings = { + bannedWords: string[]; + allowGenerationOnModel: boolean; + creditPerPhoto: number; +}; + +export type UserModel = { + modelName: string; + classType: ClassType; + generationSettings: GenerationSettings; + counts: Counts; + isActive: boolean; + createdAt: string; + modelId: number | string; + selectedPhotos: string[]; +}; + +export type Model = { + modelName: string; + classType: ClassType; + modelId: number | string; +}; + +export type FriendModel = { + userName: string; + userType: UserType; + userId: string; + profileImage: string | null; + models: Model[]; + searchScore: number; +}; + +export type ModelContainer = { + baseModelList: BaseModel[]; + userModelList: UserModel[]; + friendModelList: FriendModel[]; +}; diff --git a/types/circle.ts b/types/circle.ts new file mode 100644 index 0000000..1043ebb --- /dev/null +++ b/types/circle.ts @@ -0,0 +1,7 @@ +export type FriendsList = { + userName: string; + userType: string; + userId: string; + profileImage: string; + searchScore: number; + }; \ No newline at end of file diff --git a/types/common.ts b/types/common.ts new file mode 100644 index 0000000..21f8802 --- /dev/null +++ b/types/common.ts @@ -0,0 +1,9 @@ +export type SendNotification = { + type: "SUCCESS" | "ERROR" | "LOADING" | "REMOVE"; + message?: string; +}; + +export type Category = { + startIcon: JSX.Element; + name: string; +}; diff --git a/types/createPostType.ts b/types/createPostType.ts new file mode 100644 index 0000000..1b0fc98 --- /dev/null +++ b/types/createPostType.ts @@ -0,0 +1,16 @@ +import { GetAiGeneration } from "./ai"; +import { GeneratedFrom, Image, PromptDetail } from "./post"; + + +type generationCreatePost = PromptDetail & { + generationId:string +} + +export type DefaultValues = { + category: string[]; + caption: string | null; + image: Partial[]; + generatedFrom: GeneratedFrom | null; + promptDetails: Partial ; + prompt:string | null +}; diff --git a/types/feature.ts b/types/feature.ts new file mode 100644 index 0000000..90b21f3 --- /dev/null +++ b/types/feature.ts @@ -0,0 +1,8 @@ +export type Feature = { + featureId: string; + title: string; + description: string; + tag: string[]; + vote: number; + isVoted: boolean; +}; diff --git a/types/index.ts b/types/index.ts new file mode 100644 index 0000000..b07158f --- /dev/null +++ b/types/index.ts @@ -0,0 +1,59 @@ +import { type } from "os"; +import { Point } from "react-easy-crop"; + +export type ObjectFit = + | "horizontal-cover" + | "vertical-cover" + | "auto-cover" + | "contain"; + +export type ImageInfo = { + name: string; + src: string; + croppedImageSrc: string; + objectFit: ObjectFit; + aspectRatio: string; + zoom: number; + crop: Point; + croppedPixels: any; + size: { width: number; height: number }; +}; + +export type DropDownItem = { + startIcon?: JSX.Element; + endIcon?: JSX.Element; + title: string; + actionType?: string; + isMyProfile?: boolean; +}; +export type SingleImagePlaceholder = { + placeholderTitle: React.ReactElement; + placeholderImg: React.ReactElement; +}; + +export type DialogBoxType = + | null + | "CREDITS-VIEWPROMPT" + | "CREDITS-MESSAGE" + | "CREDITS-WITHDRAW" + | "CREDITS-VIEWPROMPT" + | "CREDITS-VIEWPROMPT" + | "CREATEMOMENT" + | "DOUNBLOCK" + | "CREATEOFFERDETAILS" + | "CREATEOFFER" + | "EDITMODEL" + | "PRIVACYPOLICY" + | "TERMSOFSERVICE" + | "CONTENTPOLICY" + | "CONTACTUS" + | "AIMODELTRAINING" + | "LEVELUP" + | "CIRCLEPOST" + | "FILTER" + | "VIEWOFFER-${number}"; + +export type AmountPerCredit = { + add: number; + withdraw: number; +}; diff --git a/types/message.ts b/types/message.ts new file mode 100644 index 0000000..8002371 --- /dev/null +++ b/types/message.ts @@ -0,0 +1,31 @@ +import { Image } from "./post"; + + +export type UserInfo = { + id: string; + userName: string; + profileImage: string | null; + userType: string; +}; + +export type RecentMessage = { + messageId: string; + lastMessage: string; + messageStatus: string; + receiver: UserInfo; + sender: UserInfo; + createdAt: string; + updatedAt: string; +}; + +export type Message = { + messageId: string; + senderId: string; + receiverId: string; + type: string; + message: string | null; + image: Image[]; + credit: number | null; + createdAt: string; + updatedAt: string; +}; diff --git a/types/offering.ts b/types/offering.ts new file mode 100644 index 0000000..98c53c8 --- /dev/null +++ b/types/offering.ts @@ -0,0 +1,58 @@ +type CreditRange = { + min: number; + max: number; + avg?: number; +}; + +export type CreateOffering = { + name: string; + image: string[]; + offeringDescription: string; + creditRange: CreditRange; +}; +export type UpateOffering = { + offeringId: string; +} & Partial; + +type User = { + id: string; + userName: string; + userType: string; + profileImage: string; +}; + +type counts = { + like: number; +}; +export type OfferingData = { + owner: User; + name: string; + image: string[]; + offeringDescription: string; + creditRange: CreditRange; + completeOffers: number; + isActive: boolean; + createdAt: string; + updatedAt: string; + offeringId: string; + pendingOffers?: number; + offerStatus?: null | string; + counts?: counts; + isUserLike?: boolean; +}; + +export type Offer = { + offeringId: string; + offerId: string; + user: User; + credit: number; + isReschedule: boolean; + offerDate: number; + offerDescription: string | null; + status: string; + message: string | null; + isActiveNotification: boolean; + createdAt: string; + updatedAt: string; + offering: OfferingData; +}; diff --git a/types/post.ts b/types/post.ts new file mode 100644 index 0000000..02b2b11 --- /dev/null +++ b/types/post.ts @@ -0,0 +1,107 @@ +import { CreationSettings, GenerationSetting, RecreationSettings } from "./ai"; +import { UserBaseInfo } from "./user"; + +export type Image = { + url: string; + width: number; + height: number; + blurhash: string; + description?: string | null; +}; + +type RepostedBy = { + userId: string; + userName: string; +}; + +export type GeneratedFrom = { + postId: string | null; + modelId: string | null; +}; + +type Counts = { + like: number; + comment: number; + repost: number; + recreation: number; + view: number; +}; + +type UserActivity = { + isLiked: boolean; + isCommented: boolean; + isReposted: boolean; + isViewed: boolean; + isAccessToViewPrompt: boolean; +}; + +export type Post = { + rank?: number; + postId: string; + postedBy: UserBaseInfo; + caption: string | null; + category: string[]; + image: Image[]; + repostedBy: RepostedBy | null; + generatedFrom: GeneratedFrom | null; + allowGenerations: boolean; + counts: Counts; + createdAt: string; + updatedAt: string; + isPromptAvailable: boolean; + userActivity: UserActivity; + searchScore?: number; +}; + +export type OtherUserPost = { + blockedBy: string | null; + postData: Post[]; +}; + +export type DiscoverPost = { + postId: string; + category: string[]; + image: Image[]; + searchScore?: number; +}; + +export type Tag = { + userId: string; + userName: string; +}; + +export type PostComment = { + commentId: string; + postId: string; + comment: string; + tag: Tag[]; + commenter: UserBaseInfo; + createdAt: string; + updatedAt: string; +}; + +export type PostPrompt = { + prompt: string; + creationSettings: null; + recreationSettings: null; + modelName: string; +}; + +export type PromptDetail = { + prompt: string; + modelName: string; + creditPerPromptView: number; + allowPromptView: boolean; + generationId: string; +} & GenerationSetting; + +export type ImageState = { + imagePreview: string; + file: File; +}; + +export type OwnerPost = Post & { + parentId: string | null; + promptDetails: Partial; + prompt: string | null; +}; diff --git a/types/question.ts b/types/question.ts new file mode 100644 index 0000000..a3b714a --- /dev/null +++ b/types/question.ts @@ -0,0 +1,18 @@ +export type QuestionType = { + questionId: string; + userId: string; + questioner: { + id: string; + userName: string; + userType: string; + profileImage: string; + }; + question: string; + reply: string | null ; + createdAt: string; + updatedAt: string; + counts: { + like: number; + }; + isUserLike: boolean; +}; diff --git a/types/setting.ts b/types/setting.ts new file mode 100644 index 0000000..043a4a9 --- /dev/null +++ b/types/setting.ts @@ -0,0 +1,9 @@ +import { Image } from "./post"; + +export type Interaction = { + type: string; + description: string; + isCheck: boolean | undefined; + objectType: string; +}; + diff --git a/types/stripe.ts b/types/stripe.ts new file mode 100644 index 0000000..0026699 --- /dev/null +++ b/types/stripe.ts @@ -0,0 +1,11 @@ +export type Session = { + sessionUrl: string; + sessionId: string ; +}; + +export enum BankAccountStatus { + "ACCOUNT_NOT_LINKED", + "ACCOUNT_LINKED", + "ACCOUNT_VERIFICATION_PENDING", + "ACCOUNT_DETAILS_PENDING", +} diff --git a/types/user.ts b/types/user.ts new file mode 100644 index 0000000..b541ba8 --- /dev/null +++ b/types/user.ts @@ -0,0 +1,190 @@ +export type GeneralInfo = { + firstName: string; + lastName: string; + profileImage: string | null; + DOB?: Date | null; + describedWord?: string | null; + bio: string | null; +}; + +export type LinkedAccounts = { + instagram: string | null; + tiktok: string | null; + twitter: string | null; + youtube: string | null; + twitch: string | null; + onlyfans: string | null; +}; + +type Credit = { + nonTransferableCredit: number; + tempCredit: number; + transferableCredit: number; +}; + +type Counts = { + followingCount: number; + followerCount: number; +}; + +type PushNotifications = { + pauseAllNotification: boolean; + likes: boolean; + comments: boolean; + directMessages: boolean; + circleAdds: boolean; + fromWitit: boolean; +}; + +export type GenerationSettings = { + creditPerDerivative: number | undefined; + creditPerMessage: number | undefined; + allowGenerationOnPost: boolean | undefined; +}; + +type UserPlan = { + id: string | null; + name: string; + status: string; + startAt: Date; + endAt: Date; +}; + +type Notification = { + dialog: string; + priorityType: "STICKY" | "NON_STICKY"; + notificationId: string; +}; + +export enum UserType { + "GENERAL" = "GENERAL", + "VERIFIED" = "VERIFIED", +} + +export type ReduxUser = { + userId: string; + userName: string; + email?: string; + phone?: string | null; + userType: UserType; + NSFW?: boolean; + shouldShowRepost?: boolean; + generalInfo: GeneralInfo; + linkedAccounts: LinkedAccounts; + credit?: Credit; + counts: Counts; + isModelTrained: boolean; + dynamicProfileLink: string | null; + allowedModels: number; + pushNotifications?: PushNotifications; + generationSettings: GenerationSettings | null; + userPlan: UserPlan | null; + notifications?: Notification[]; + isMyFollower?: boolean; + isMyFollowing?: boolean; + blockedBy?: string | null; + modelCount?: number; +}; + +export type UserBaseInfo = { + userId: string; + userName: string; + profileImage: string | null; + userType: UserType; + searchScore?: number; +}; + +// export type OtherUser = { +// userId: string; +// userName: string; +// userType: UserType; +// generalInfo: GeneralInfo; +// linkedAccounts: LinkedAccounts; +// counts: Counts; +// isModelTrained: boolean; +// dynamicProfileLink: string | null; +// allowedModels: number; +// generationSettings: GenerationSettings | null; +// userPlan: UserPlan | null; +// isMyFollower: boolean; +// isMyFollowing: boolean; +// blockedBy: string | null; +// modelCount: number; +// }; + +export type SearchCreator = { + userName: string; + generalInfo: GeneralInfo; + userType: UserType; + counts: { + followerCount: 17; + }; + userId: string; + searchScore?: number; +}; + +export type BlockedUser = { + blockListId: string; + userId: string; + blockedUserInfo: UserBaseInfo; + createdAt: string; + updatedAt: string; +}; + +export type CreditItem = { + name: string; + description: string; + credit: number; + amount: number; + color: string; +}; + +export type DriverLicense = { + frontOfLicense: { + imagePreview: string; + file: File | null; + }; + backOfLicense: { + imagePreview: string; + file: File | null; + }; +}; + +export type Aimodel = { + selectedPhotos: (string | null)[]; + verificationImages: (string | null)[]; + audioURL: string | null; + generationSettings: { + bannedWords: string[]; + allowGenerationOnModel: boolean; + creditPerPhoto: number; + }; + classType: string; +}; + +export type AimodelRes = { + status: number; + data: { + selectedPhotos: string[]; + audioURL: null | string; + generationSettings: { + bannedWords: string[]; + allowGenerationOnModel: boolean; + creditPerPhoto: number; + }; + }; + error: any; +}; + +export type Store = { + documentName: string; + documentImages: (string | null)[]; +}; + +export type generationSettingsUnit = { + generationSettings: { + creditPerDerivative: number; + creditPerMessage: number; + allowGenerationOnPost: boolean; + } | null; +}; diff --git a/utils/constants/withHtml/CategoryList.tsx b/utils/constants/withHtml/CategoryList.tsx new file mode 100644 index 0000000..c3c5880 --- /dev/null +++ b/utils/constants/withHtml/CategoryList.tsx @@ -0,0 +1,85 @@ +import { Category } from "@/types/common"; +import ActionCategoryIcon from "../../icons/createPost/selectCategoryIcons/ActionCategoryIcon"; +import ArtCategoryIcon from "../../icons/createPost/selectCategoryIcons/ArtCategoryIcon"; +import BusinessCategoryIcon from "../../icons/createPost/selectCategoryIcons/BusinessCategoryIcon"; +import CasualCategoryIcon from "../../icons/createPost/selectCategoryIcons/CasualCategoryIcon"; +import ComedyCategoryIcon from "../../icons/createPost/selectCategoryIcons/ComedyCategoryIcon"; +import CosplayCategoryIcon from "../../icons/createPost/selectCategoryIcons/CosplayCategoryIcon"; +import DIYCategoryIcon from "../../icons/createPost/selectCategoryIcons/DIYCategoryIcon"; +import FantasyCategoryIcon from "../../icons/createPost/selectCategoryIcons/FantasyCategoryIcon"; +import FashionCategoryIcon from "../../icons/createPost/selectCategoryIcons/FashionCategoryIcon"; +import FitnessCategoryIcon from "../../icons/createPost/selectCategoryIcons/FitnessCategoryIcon"; +import HistoricalCategoryIcon from "../../icons/createPost/selectCategoryIcons/HistoricalCategoryIcon"; +import HorrorCategoryIcon from "../../icons/createPost/selectCategoryIcons/HorrorCategoryIcon"; +import MusicCategoryIcon from "../../icons/createPost/selectCategoryIcons/MusicCategoryIcon"; +import NSFWCategoryIcon from "../../icons/createPost/selectCategoryIcons/NSFWCategoryIcon"; +import TravelCategoryIcon from "../../icons/createPost/selectCategoryIcons/TravelCategoryIcon"; +import WellnessCategoryIcon from "../../icons/createPost/selectCategoryIcons/WellnessCategoryIcon"; + +export const CategoryList: Category[] = [ + { + startIcon: , + name: "Art", + }, + { + startIcon: , + name: "Casual", + }, + { + startIcon: , + name: "Cosplay", + }, + { + startIcon: , + name: "Fantasy", + }, + { + startIcon: , + name: "Comedy", + }, + { + startIcon: , + name: "Wellness", + }, + { + startIcon: , + name: "Fitness", + }, + { + startIcon: , + name: "Horror", + }, + { + startIcon: , + name: "Travel", + }, + { + startIcon: , + name: "Historical", + }, + { + startIcon: , + name: "Fashion", + }, + { + startIcon: , + name: "Action", + }, + { + startIcon: , + name: "Music", + }, + { + startIcon: , + name: "Business", + }, + { + startIcon: , + name: "DIY", + }, + { + //NSFW in is dependent on index + startIcon: , + name: "NSFW", + }, +]; diff --git a/utils/constants/withHtml/ai.tsx b/utils/constants/withHtml/ai.tsx new file mode 100644 index 0000000..8d2ebdb --- /dev/null +++ b/utils/constants/withHtml/ai.tsx @@ -0,0 +1,54 @@ +import { DropDownItem } from "@/types"; +import PostIcon from "@/utils/icons/navbar/PostIcon"; +import DownloadIcon from "@/utils/icons/setting/DownloadIcon"; +import AutomodeBlackIcon from "@/utils/icons/shared/AutomodeBlackIcon"; +import ShareIcon from "@/utils/icons/shared/ShareIcon"; +import UpscaleIcon from "@/utils/icons/shared/UpscaleIcon"; + +export const GenerationActionList: DropDownItem[] = [ + { + title: "Download", + startIcon: ( +
+ +
+ ), + actionType: "DOWNLOAD", + }, + { + title: "Recreate", + startIcon: ( +
+ +
+ ), + actionType: "RECREATE", + }, + { + startIcon: ( +
+ +
+ ), + title: "Post", + actionType: "POST", + }, + { + startIcon: ( +
+ +
+ ), + title: "Share", + actionType: "SHARE", + }, + { + startIcon: ( +
+ +
+ ), + title: "Upscale", + actionType: "UP_SCALE", + }, +]; diff --git a/utils/constants/withoutHtml/ai.ts b/utils/constants/withoutHtml/ai.ts new file mode 100644 index 0000000..feeafaa --- /dev/null +++ b/utils/constants/withoutHtml/ai.ts @@ -0,0 +1,44 @@ +import { GenerationSetting, ImageSize } from "@/types/ai"; +import PostIcon from "../../icons/navbar/PostIcon"; + +type ImageSizeItem = { + name: string; + tag: ImageSize; +}; + +export const initialGenerationSetting: GenerationSetting = { + negativePrompt: [], + creationSettings: { + imageSize: "md", + aspectRatio: "4:5", + promptStrength: 7, + definition: 50, + restoreFace: false, + preserveFaceDetails: null, + preserveHandDetails: null, + }, + recreationSettings: { + recreationType: null, + recreationTypeStrength: 0.6, + recreationStrength: 0.6, + }, + inPaintingSettings: { + recreateMaskOnly: false, + }, + hiResSettings: null, +}; + +export const imageSizes: ImageSizeItem[] = [ + { + name: "Small", + tag: "sm", + }, + { + name: "Medium", + tag: "md", + }, + { + name: "Large", + tag: "lg", + }, +]; diff --git a/utils/constants/withoutHtml/appConstant.ts b/utils/constants/withoutHtml/appConstant.ts new file mode 100644 index 0000000..60328d4 --- /dev/null +++ b/utils/constants/withoutHtml/appConstant.ts @@ -0,0 +1,42 @@ +import {ImageInfo} from "@/types"; + +const path = { + login: "/", + discover: "/discover", + profile: "/profile", + create: "/create", + setting: "/setting", + circle: "/circle", + message: "/message", + accountSetup: "/account-setup", +}; + +const appConstant = { + backendUrl: process.env.NEXT_PUBLIC_API_URL, + drawerWidth: { + small: 80, + medium: 200, + }, + defaultaspectRatio: "4/5", + aspectRatioList: ["1/1", "2/3", "3/2", "4/5", "5/4"], + pageRoute: path, + defaultProfileImage: + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/witit_images%2Fprofile_placeholder_image.png?alt=media&token=89758d76-12d6-4c4d-9d31-14ba03cee4c0", +}; + +export default appConstant; + +export const defaultImageConstant: {image: ImageInfo; index: number} = { + image: { + name: "", + src: "", + croppedImageSrc: "", + objectFit: "contain", + aspectRatio: "4/5", + zoom: 1, + crop: {x: 0, y: 0}, + croppedPixels: {x: 0, y: 0}, + size: {width: 0, height: 0}, + }, + index: 0, +}; diff --git a/utils/constants/withoutHtml/common.ts b/utils/constants/withoutHtml/common.ts new file mode 100644 index 0000000..739b680 --- /dev/null +++ b/utils/constants/withoutHtml/common.ts @@ -0,0 +1,46 @@ +import { AspectRatio, Resolution } from "@/types/ai"; + +type AspectRatioItem = { + displayName: string; + applicable: string; + tag: AspectRatio; +}; + +export const aspectRatioList: AspectRatioItem[] = [ + { + displayName: "3:2", + applicable: "3/2", + tag: "3:2", + }, + { + displayName: "5:4", + applicable: "5/4", + tag: "5:4", + }, + { + displayName: "1:1", + applicable: "1/1", + tag: "1:1", + }, + { + displayName: "4:5", + applicable: "4/5", + tag: "4:5", + }, + { + displayName: "2:3", + applicable: "2/3", + tag: "2:3", + }, +]; + +type ResolutionItem = { + displayName: string; + applicable: string; + tag: Resolution; +}; +export const ResolutionList: ResolutionItem[] = [ + { displayName: "1x", applicable: "1", tag: 1 }, + { displayName: "1.5x", applicable: "1.5", tag: 1.5 }, + { displayName: "2x", applicable: "2", tag: 2 }, +]; diff --git a/utils/constants/withoutHtml/loginImages.ts b/utils/constants/withoutHtml/loginImages.ts new file mode 100644 index 0000000..d895290 --- /dev/null +++ b/utils/constants/withoutHtml/loginImages.ts @@ -0,0 +1,32 @@ +export const image1 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_beautiful_attractive_woman_model_laying_in_be_89de5e84-6b10-4792-b17d-aa257d9d1a71-min.png?alt=media&token=ede8853d-25c7-4622-a92e-8620c44bca56"; +export const image2 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_beautiful_man_close_up_panoramic_shot_romanti_828a9fce-cc21-4a14-87df-97b6873f395e-min.png?alt=media&token=db19231b-1ce0-4b6c-8dbb-ac2a5f698cb6"; +export const image3 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_beautiful_woman_Light_painting_adding_a_dynam_e0cf2c57-a659-4b8c-ac3a-8f6050f53795-min.png?alt=media&token=b8e57d73-a976-4cfa-a96d-400617eb6773"; +export const image4 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_man_dressed_as_a_CEO_crossing_his_arms_with_a_6663fab0-7228-4764-b6b2-d01db404b172-min.png?alt=media&token=3567efbe-5d3c-4002-b8cc-90bdc1f829b7"; +export const image5 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_man_dressed_as_a_knight_heroic_pose_during_th_0ccea4a4-1672-4032-9f80-f11fd2e5779b-min.png?alt=media&token=f3bee07d-1415-4acf-93aa-2f7231a3cdcf"; +export const image6 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_woman_depth_of_field_desaturated_colors_Long__c7d16bd8-b5ff-4677-aab4-c8aba6699874-min.png?alt=media&token=ff034f1d-5491-46f1-bffa-ac275da5f7eb"; +export const image7 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_woman_half_body_close_up_dramatically_lit_Hig_de2f7ea9-076a-4b49-9947-9d805d13cb55-min.png?alt=media&token=9060bbd4-ff32-45a7-a8eb-d94b42d7d712"; +export const image8 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_woman_model_in_a_photography_studio_making_a__f5595ffd-323a-45b1-8284-bb04b44bedb8-min.png?alt=media&token=ac8a0e72-a26b-4e0b-8664-fe1615e31f1c"; +export const image9 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_a_woman_vibrant_gel_lighting_Symbolism_style_Hi_e4a22434-2339-4e87-80a7-590f9fa35163-min.png?alt=media&token=2b609dc5-06a2-402a-b89d-d83ab2b2760e"; +export const image10 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_an_asian_woman_dressed_as_daenerys_targaryen_st_b4dc0fe4-5119-463a-9d62-c3b5722e8f9f-min.png?alt=media&token=dc40f544-7dee-4540-8431-0323857b2712"; +export const image11 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_an_attractive_man_in_his_mid_20s_portrait_photo_6bdf3dfb-c67a-45f2-9f95-3f97f222ade2-min.png?alt=media&token=9d87f215-3374-4858-aa4c-b9cdf4c4f2cb"; +export const image12 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_an_attractive_man_model_dressed_as_a_Sith_Lord__44688ded-ab49-4cdb-aa58-d42a4060f9be-min.png?alt=media&token=acb55bd6-1b0c-4718-a70e-68b6642be06a"; +export const image13 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_an_attractive_man_selfie_Wearing_a_traditional__fc78d52d-0861-45a0-b5c2-23182bb0a773-min.png?alt=media&token=91b475bb-5e0e-41a0-a21f-882ad232815a"; +export const image14 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_an_attractive_woman_in_her_mid_20s_At_a_glamoro_62001f3f-2bfa-48f6-a64b-6f8f906f5271-min.png?alt=media&token=df19ba08-3962-4b44-8ddc-0859d3cef15d"; +export const image15 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_an_attractive_woman_with_a_grizzly_bear_smiling_fd4dfc61-9ad7-430f-8405-d37eefd9247c-min.png?alt=media&token=011c40da-52ce-4500-961e-20c0b24c6ca1"; +export const image16 = + "https://firebasestorage.googleapis.com/v0/b/witit-dcc9d.appspot.com/o/sample_generated_images%2Fnathanielgerdes_n_attractive_women_model_coming_out_of_the_ocea_9f1b7b8e-bbb8-4e84-b1fd-42c3c79b79c6-min.png?alt=media&token=6f3dcff8-5b9a-41ab-af10-64096baf5a3f"; diff --git a/utils/firebase/firebaseConfig.ts b/utils/firebase/firebaseConfig.ts new file mode 100644 index 0000000..e1872cd --- /dev/null +++ b/utils/firebase/firebaseConfig.ts @@ -0,0 +1,25 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from "firebase/app"; +import { getAnalytics } from "firebase/analytics"; +import { getStorage } from "firebase/storage"; +import { getAuth } from "firebase/auth"; + +const firebaseConfig = { + apiKey: process.env.NEXT_PUBLIC_FIREBASE_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MSG_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, +}; + +const app = initializeApp(firebaseConfig); +export const analytics = + typeof window !== "undefined" ? getAnalytics(app) : null; + +export const firebaseStorage = getStorage(app); + +const auth = getAuth(); +export default auth; diff --git a/utils/icons/circle/SendIcon.tsx b/utils/icons/circle/SendIcon.tsx new file mode 100644 index 0000000..7b07fab --- /dev/null +++ b/utils/icons/circle/SendIcon.tsx @@ -0,0 +1,16 @@ +export default function SendIcon() { + return ( + + + + ); +} diff --git a/utils/icons/circle/SynchronizeIcon.tsx b/utils/icons/circle/SynchronizeIcon.tsx new file mode 100644 index 0000000..041035c --- /dev/null +++ b/utils/icons/circle/SynchronizeIcon.tsx @@ -0,0 +1,61 @@ +export default function SynchronizeIcon({ size = 24 }) { + return ( + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/circle/SyncronizeIcon2.svg b/utils/icons/circle/SyncronizeIcon2.svg new file mode 100644 index 0000000..3ce3bf0 --- /dev/null +++ b/utils/icons/circle/SyncronizeIcon2.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/utils/icons/circle/ThreeVerticalDots.tsx b/utils/icons/circle/ThreeVerticalDots.tsx new file mode 100644 index 0000000..6c27982 --- /dev/null +++ b/utils/icons/circle/ThreeVerticalDots.tsx @@ -0,0 +1,16 @@ +export default function ThreeVerticalDots() { + return ( + + + + ); +} diff --git a/utils/icons/circle/VerifiedIcon.tsx b/utils/icons/circle/VerifiedIcon.tsx new file mode 100644 index 0000000..152659d --- /dev/null +++ b/utils/icons/circle/VerifiedIcon.tsx @@ -0,0 +1,16 @@ +export default function VerifiedIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/CropLinerIcon.tsx b/utils/icons/createPost/CropLinerIcon.tsx new file mode 100644 index 0000000..633fb26 --- /dev/null +++ b/utils/icons/createPost/CropLinerIcon.tsx @@ -0,0 +1,20 @@ +export default function CropLinerIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/createPost/ImagePlaceHolderGalleryIcon.tsx b/utils/icons/createPost/ImagePlaceHolderGalleryIcon.tsx new file mode 100644 index 0000000..59ab20d --- /dev/null +++ b/utils/icons/createPost/ImagePlaceHolderGalleryIcon.tsx @@ -0,0 +1,16 @@ +export default function ImagePlaceHolderGalleryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/ActionCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/ActionCategoryIcon.tsx new file mode 100644 index 0000000..956c384 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/ActionCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function ActionCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/ArtCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/ArtCategoryIcon.tsx new file mode 100644 index 0000000..d36f5e7 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/ArtCategoryIcon.tsx @@ -0,0 +1,24 @@ +export default function ArtCategoryIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/BusinessCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/BusinessCategoryIcon.tsx new file mode 100644 index 0000000..c2541c3 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/BusinessCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function BusinessCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon.tsx new file mode 100644 index 0000000..15ca6c4 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/CasualCategoryIcon.tsx @@ -0,0 +1,20 @@ +export default function CasualCategoryIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/ComedyCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/ComedyCategoryIcon.tsx new file mode 100644 index 0000000..082a1a4 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/ComedyCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function ComedyCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/CosplayCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/CosplayCategoryIcon.tsx new file mode 100644 index 0000000..5efa4dc --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/CosplayCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function CosplayCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/DIYCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/DIYCategoryIcon.tsx new file mode 100644 index 0000000..0be2d39 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/DIYCategoryIcon.tsx @@ -0,0 +1,63 @@ +export default function DIYCategoryIcon() { + return ( + + + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/FantasyCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/FantasyCategoryIcon.tsx new file mode 100644 index 0000000..1177884 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/FantasyCategoryIcon.tsx @@ -0,0 +1,48 @@ +export default function FantasyCategoryIcon() { + return ( + + + + + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/FashionCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/FashionCategoryIcon.tsx new file mode 100644 index 0000000..e13fc5f --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/FashionCategoryIcon.tsx @@ -0,0 +1,18 @@ +export default function FashionCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/FitnessCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/FitnessCategoryIcon.tsx new file mode 100644 index 0000000..2d549a8 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/FitnessCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function FitnessCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/HistoricalCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/HistoricalCategoryIcon.tsx new file mode 100644 index 0000000..813cac0 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/HistoricalCategoryIcon.tsx @@ -0,0 +1,27 @@ +export default function HistoricalCategoryIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/HorrorCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/HorrorCategoryIcon.tsx new file mode 100644 index 0000000..ff62cca --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/HorrorCategoryIcon.tsx @@ -0,0 +1,23 @@ +export default function HorrorCategoryIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/MusicCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/MusicCategoryIcon.tsx new file mode 100644 index 0000000..b0e9731 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/MusicCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function MusicCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/NSFWCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/NSFWCategoryIcon.tsx new file mode 100644 index 0000000..c675c12 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/NSFWCategoryIcon.tsx @@ -0,0 +1,28 @@ +export default function NSFWCategoryIcon() { + return ( + + + + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/TravelCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/TravelCategoryIcon.tsx new file mode 100644 index 0000000..cb5fc84 --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/TravelCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function TravelCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/createPost/selectCategoryIcons/WellnessCategoryIcon.tsx b/utils/icons/createPost/selectCategoryIcons/WellnessCategoryIcon.tsx new file mode 100644 index 0000000..a4e955a --- /dev/null +++ b/utils/icons/createPost/selectCategoryIcons/WellnessCategoryIcon.tsx @@ -0,0 +1,16 @@ +export default function WellnessCategoryIcon() { + return ( + + + + ); +} diff --git a/utils/icons/levelUp/AlertIcon.tsx b/utils/icons/levelUp/AlertIcon.tsx new file mode 100644 index 0000000..ef7659e --- /dev/null +++ b/utils/icons/levelUp/AlertIcon.tsx @@ -0,0 +1,16 @@ +export default function AlertIcon() { + return ( + + + + ); +} diff --git a/utils/icons/levelUp/Crown.tsx b/utils/icons/levelUp/Crown.tsx new file mode 100644 index 0000000..57653af --- /dev/null +++ b/utils/icons/levelUp/Crown.tsx @@ -0,0 +1,33 @@ +import React from "react"; + +const Crown = () => { + return ( + <> + + + + + + + + + + + + + ); +}; + +export default Crown; diff --git a/utils/icons/levelUp/DollerIcon.tsx b/utils/icons/levelUp/DollerIcon.tsx new file mode 100644 index 0000000..2fbaa12 --- /dev/null +++ b/utils/icons/levelUp/DollerIcon.tsx @@ -0,0 +1,28 @@ +export default function DollerIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/levelUp/FormIcon.tsx b/utils/icons/levelUp/FormIcon.tsx new file mode 100644 index 0000000..d8d149a --- /dev/null +++ b/utils/icons/levelUp/FormIcon.tsx @@ -0,0 +1,30 @@ +export default function FormIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/levelUp/GetStartedMirroeIcon.tsx b/utils/icons/levelUp/GetStartedMirroeIcon.tsx new file mode 100644 index 0000000..342faec --- /dev/null +++ b/utils/icons/levelUp/GetStartedMirroeIcon.tsx @@ -0,0 +1,23 @@ +export default function GetStartedMirroeIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/levelUp/GradientCrown.tsx b/utils/icons/levelUp/GradientCrown.tsx new file mode 100644 index 0000000..264983c --- /dev/null +++ b/utils/icons/levelUp/GradientCrown.tsx @@ -0,0 +1,128 @@ +import React from "react"; + +const GradientCrown = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default GradientCrown; diff --git a/utils/icons/levelUp/SettingIcon.tsx b/utils/icons/levelUp/SettingIcon.tsx new file mode 100644 index 0000000..cae171b --- /dev/null +++ b/utils/icons/levelUp/SettingIcon.tsx @@ -0,0 +1,28 @@ +export default function SettingIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/message/LeftArrow.tsx b/utils/icons/message/LeftArrow.tsx new file mode 100644 index 0000000..fd3ccf4 --- /dev/null +++ b/utils/icons/message/LeftArrow.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +const LeftArrow = () => { + return ( + + + + + ); +}; + +export default LeftArrow; diff --git a/utils/icons/message/TwoUserIcon.tsx b/utils/icons/message/TwoUserIcon.tsx new file mode 100644 index 0000000..8820cb4 --- /dev/null +++ b/utils/icons/message/TwoUserIcon.tsx @@ -0,0 +1,27 @@ +import React from "react"; + +const TwoUserIcon = () => { + return ( + + + + + + + + + + + ); +}; + +export default TwoUserIcon; diff --git a/utils/icons/navbar/CircleIcon.tsx b/utils/icons/navbar/CircleIcon.tsx new file mode 100644 index 0000000..f7d4fef --- /dev/null +++ b/utils/icons/navbar/CircleIcon.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +const CircleIcon = () => { + return ( + + + + ); +}; + +export default CircleIcon; diff --git a/utils/icons/navbar/CreateIcon.tsx b/utils/icons/navbar/CreateIcon.tsx new file mode 100644 index 0000000..61b8224 --- /dev/null +++ b/utils/icons/navbar/CreateIcon.tsx @@ -0,0 +1,23 @@ +import React from "react"; +type Props = { + size?: string; +}; + +const CreateIcon = ({ size = "24" }: Props) => { + return ( + + + + ); +}; + +export default CreateIcon; diff --git a/utils/icons/navbar/CreatorIcon.tsx b/utils/icons/navbar/CreatorIcon.tsx new file mode 100644 index 0000000..8db812b --- /dev/null +++ b/utils/icons/navbar/CreatorIcon.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +const CreatorIcon = () => { + return ( + + + + ); +}; + +export default CreatorIcon; diff --git a/utils/icons/navbar/DiscoverIcon.tsx b/utils/icons/navbar/DiscoverIcon.tsx new file mode 100644 index 0000000..409c49a --- /dev/null +++ b/utils/icons/navbar/DiscoverIcon.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +const DiscoverIcon = () => { + return ( + + + + + ); +}; + +export default DiscoverIcon; diff --git a/utils/icons/navbar/MessageIcon.tsx b/utils/icons/navbar/MessageIcon.tsx new file mode 100644 index 0000000..56d50a8 --- /dev/null +++ b/utils/icons/navbar/MessageIcon.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +type Props = { + isWithBlue?: boolean; +}; + +const MessageIcon = ({ isWithBlue }: Props) => { + return ( + + + + ); +}; + +export default MessageIcon; diff --git a/utils/icons/navbar/MyProfileIcon.tsx b/utils/icons/navbar/MyProfileIcon.tsx new file mode 100644 index 0000000..74f0ae5 --- /dev/null +++ b/utils/icons/navbar/MyProfileIcon.tsx @@ -0,0 +1,32 @@ +import React from "react"; + +const MyProfileIcon = () => { + return ( + + + + + ); +}; + +export default MyProfileIcon; diff --git a/utils/icons/navbar/PostIcon.tsx b/utils/icons/navbar/PostIcon.tsx new file mode 100644 index 0000000..65e90e3 --- /dev/null +++ b/utils/icons/navbar/PostIcon.tsx @@ -0,0 +1,39 @@ +import React from "react"; + +const PostIcon = () => { + return ( + + + + + + ); +}; + +export default PostIcon; diff --git a/utils/icons/navbar/SettingIcon.tsx b/utils/icons/navbar/SettingIcon.tsx new file mode 100644 index 0000000..4686e01 --- /dev/null +++ b/utils/icons/navbar/SettingIcon.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +const SettingIcon = () => { + return ( + + + + + ); +}; + +export default SettingIcon; diff --git a/utils/icons/profile/CreateMomentIcon.tsx b/utils/icons/profile/CreateMomentIcon.tsx new file mode 100644 index 0000000..c8615ec --- /dev/null +++ b/utils/icons/profile/CreateMomentIcon.tsx @@ -0,0 +1,39 @@ +import React from "react"; + +export default function CreateMomentIcon() { + return ( + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/profile/CreateOfferIcon.tsx b/utils/icons/profile/CreateOfferIcon.tsx new file mode 100644 index 0000000..2180f83 --- /dev/null +++ b/utils/icons/profile/CreateOfferIcon.tsx @@ -0,0 +1,39 @@ +import React from "react"; + +export default function CreateOfferIcon() { + return ( + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/profile/FeedIcon.tsx b/utils/icons/profile/FeedIcon.tsx new file mode 100644 index 0000000..e36ae60 --- /dev/null +++ b/utils/icons/profile/FeedIcon.tsx @@ -0,0 +1,16 @@ +export default function FeedIcon() { + return ( + + + + ); +} diff --git a/utils/icons/profile/MomentsIcon.tsx b/utils/icons/profile/MomentsIcon.tsx new file mode 100644 index 0000000..82aabe0 --- /dev/null +++ b/utils/icons/profile/MomentsIcon.tsx @@ -0,0 +1,16 @@ +export default function MomentsIcon() { + return ( + + + + ); +} diff --git a/utils/icons/profile/OfferingIcon.tsx b/utils/icons/profile/OfferingIcon.tsx new file mode 100644 index 0000000..b09b22e --- /dev/null +++ b/utils/icons/profile/OfferingIcon.tsx @@ -0,0 +1,24 @@ +export default function OfferingIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/profile/QuestionnariesIcon.tsx b/utils/icons/profile/QuestionnariesIcon.tsx new file mode 100644 index 0000000..601effe --- /dev/null +++ b/utils/icons/profile/QuestionnariesIcon.tsx @@ -0,0 +1,36 @@ +export const QuestionnariesIcon = () => { + return ( + + + + + + + + + + + + + ); +}; diff --git a/utils/icons/setting/AiApplicationIcon.tsx b/utils/icons/setting/AiApplicationIcon.tsx new file mode 100644 index 0000000..a1b6984 --- /dev/null +++ b/utils/icons/setting/AiApplicationIcon.tsx @@ -0,0 +1,35 @@ +export default function AiApplicationIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/AiModelIcon.tsx b/utils/icons/setting/AiModelIcon.tsx new file mode 100644 index 0000000..63af548 --- /dev/null +++ b/utils/icons/setting/AiModelIcon.tsx @@ -0,0 +1,122 @@ +export default function AiModelIcon() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/setting/BankIcon.tsx b/utils/icons/setting/BankIcon.tsx new file mode 100644 index 0000000..d3f3665 --- /dev/null +++ b/utils/icons/setting/BankIcon.tsx @@ -0,0 +1,17 @@ +export default function BankIcon() { + return ( + + + + ); +} diff --git a/utils/icons/setting/BlocklistIcon.tsx b/utils/icons/setting/BlocklistIcon.tsx new file mode 100644 index 0000000..40c7882 --- /dev/null +++ b/utils/icons/setting/BlocklistIcon.tsx @@ -0,0 +1,35 @@ +export default function BlocklistIcon() { + return ( + + + + + + + ); +} diff --git a/utils/icons/setting/CreaditIcon.tsx b/utils/icons/setting/CreaditIcon.tsx new file mode 100644 index 0000000..920ccbc --- /dev/null +++ b/utils/icons/setting/CreaditIcon.tsx @@ -0,0 +1,35 @@ +export default function CreaditIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/DocumentPending.tsx b/utils/icons/setting/DocumentPending.tsx new file mode 100644 index 0000000..0ace6cf --- /dev/null +++ b/utils/icons/setting/DocumentPending.tsx @@ -0,0 +1,33 @@ +import React from "react"; + +const DocumentPending = () => { + return ( + + + + + + + + + + + + ); +}; + +export default DocumentPending; diff --git a/utils/icons/setting/DollerIcon.tsx b/utils/icons/setting/DollerIcon.tsx new file mode 100644 index 0000000..ca15645 --- /dev/null +++ b/utils/icons/setting/DollerIcon.tsx @@ -0,0 +1,33 @@ +export default function BankAccountIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/DownloadIcon.tsx b/utils/icons/setting/DownloadIcon.tsx new file mode 100644 index 0000000..149e63b --- /dev/null +++ b/utils/icons/setting/DownloadIcon.tsx @@ -0,0 +1,16 @@ +export default function DownloadIcon() { + return ( + + + + ); +} diff --git a/utils/icons/setting/EditProfileIcon.tsx b/utils/icons/setting/EditProfileIcon.tsx new file mode 100644 index 0000000..09e0836 --- /dev/null +++ b/utils/icons/setting/EditProfileIcon.tsx @@ -0,0 +1,33 @@ +export default function EditProfileIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/LinkIcon.tsx b/utils/icons/setting/LinkIcon.tsx new file mode 100644 index 0000000..0d7e159 --- /dev/null +++ b/utils/icons/setting/LinkIcon.tsx @@ -0,0 +1,37 @@ +export default function LinkIcon() { + return ( + + + + + + + ); +} diff --git a/utils/icons/setting/NSFWIcon.tsx b/utils/icons/setting/NSFWIcon.tsx new file mode 100644 index 0000000..9f91589 --- /dev/null +++ b/utils/icons/setting/NSFWIcon.tsx @@ -0,0 +1,45 @@ +export default function NSFWIcon() { + return ( + + + + + + + + + + + + + ); +} diff --git a/utils/icons/setting/NotCreditShowCrown.tsx b/utils/icons/setting/NotCreditShowCrown.tsx new file mode 100644 index 0000000..3673651 --- /dev/null +++ b/utils/icons/setting/NotCreditShowCrown.tsx @@ -0,0 +1,66 @@ +import React from "react"; + +const NotCreditShowCrown = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default NotCreditShowCrown; diff --git a/utils/icons/setting/NotificationIcon.tsx b/utils/icons/setting/NotificationIcon.tsx new file mode 100644 index 0000000..d6061b7 --- /dev/null +++ b/utils/icons/setting/NotificationIcon.tsx @@ -0,0 +1,33 @@ +export default function NotificationIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/aiModelTranning/RangeTrueIcon.tsx b/utils/icons/setting/aiModelTranning/RangeTrueIcon.tsx new file mode 100644 index 0000000..0df19b6 --- /dev/null +++ b/utils/icons/setting/aiModelTranning/RangeTrueIcon.tsx @@ -0,0 +1,36 @@ +import { theme } from "@/theme"; +import React from "react"; +type Props = { + photosLength: number; +}; +const RangeTrueIcon = ({ photosLength }: Props) => { + return ( + + + + + ); +}; + +export default RangeTrueIcon; diff --git a/utils/icons/setting/socialMedia/InstagramIcon.tsx b/utils/icons/setting/socialMedia/InstagramIcon.tsx new file mode 100644 index 0000000..aa93151 --- /dev/null +++ b/utils/icons/setting/socialMedia/InstagramIcon.tsx @@ -0,0 +1,16 @@ +export default function InstagramIcon() { + return ( + + + + ); +} diff --git a/utils/icons/setting/socialMedia/TiktokIcon.tsx b/utils/icons/setting/socialMedia/TiktokIcon.tsx new file mode 100644 index 0000000..7e6f82b --- /dev/null +++ b/utils/icons/setting/socialMedia/TiktokIcon.tsx @@ -0,0 +1,30 @@ +export default function TiktokIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/socialMedia/TwitchIcon.tsx b/utils/icons/setting/socialMedia/TwitchIcon.tsx new file mode 100644 index 0000000..923a83b --- /dev/null +++ b/utils/icons/setting/socialMedia/TwitchIcon.tsx @@ -0,0 +1,24 @@ +export default function TwitchIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/socialMedia/TwitterIcon.tsx b/utils/icons/setting/socialMedia/TwitterIcon.tsx new file mode 100644 index 0000000..0d8138b --- /dev/null +++ b/utils/icons/setting/socialMedia/TwitterIcon.tsx @@ -0,0 +1,16 @@ +export default function TwitterIcon() { + return ( + + + + ); +} diff --git a/utils/icons/setting/socialMedia/WebsiteIcon.tsx b/utils/icons/setting/socialMedia/WebsiteIcon.tsx new file mode 100644 index 0000000..bc6f4b7 --- /dev/null +++ b/utils/icons/setting/socialMedia/WebsiteIcon.tsx @@ -0,0 +1,28 @@ +export default function WebsiteIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/setting/socialMedia/YouTubeIcon.tsx b/utils/icons/setting/socialMedia/YouTubeIcon.tsx new file mode 100644 index 0000000..fbe05e4 --- /dev/null +++ b/utils/icons/setting/socialMedia/YouTubeIcon.tsx @@ -0,0 +1,20 @@ +export default function YouTubeIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/setting/statusDialog/CancelIcon.tsx b/utils/icons/setting/statusDialog/CancelIcon.tsx new file mode 100644 index 0000000..9f11f5f --- /dev/null +++ b/utils/icons/setting/statusDialog/CancelIcon.tsx @@ -0,0 +1,25 @@ +export default function CancelIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/setting/statusDialog/CheckCircleOverflowIcon.tsx b/utils/icons/setting/statusDialog/CheckCircleOverflowIcon.tsx new file mode 100644 index 0000000..0d05430 --- /dev/null +++ b/utils/icons/setting/statusDialog/CheckCircleOverflowIcon.tsx @@ -0,0 +1,28 @@ +export default function CheckCircleOverflowIcon() { + return ( + + + + + + + + ); +} diff --git a/utils/icons/setting/statusDialog/ClockIcon.tsx b/utils/icons/setting/statusDialog/ClockIcon.tsx new file mode 100644 index 0000000..86bccad --- /dev/null +++ b/utils/icons/setting/statusDialog/ClockIcon.tsx @@ -0,0 +1,19 @@ +export default function ClockIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shapes/CrossStipsBg.tsx b/utils/icons/shapes/CrossStipsBg.tsx new file mode 100644 index 0000000..79f6a7b --- /dev/null +++ b/utils/icons/shapes/CrossStipsBg.tsx @@ -0,0 +1,57 @@ +export default function CrossStipsBg() { + return ( + + + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shapes/HypeTriangleIcon.tsx b/utils/icons/shapes/HypeTriangleIcon.tsx new file mode 100644 index 0000000..dbf0651 --- /dev/null +++ b/utils/icons/shapes/HypeTriangleIcon.tsx @@ -0,0 +1,35 @@ +export default function HypeTriangleIcon() { + return ( + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/ArrowDownIcon.tsx b/utils/icons/shared/ArrowDownIcon.tsx new file mode 100644 index 0000000..306a033 --- /dev/null +++ b/utils/icons/shared/ArrowDownIcon.tsx @@ -0,0 +1,19 @@ +export default function ArrowDownIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/AutomodeBlackIcon.tsx b/utils/icons/shared/AutomodeBlackIcon.tsx new file mode 100644 index 0000000..45a13c0 --- /dev/null +++ b/utils/icons/shared/AutomodeBlackIcon.tsx @@ -0,0 +1,43 @@ +export default function AutomodeBlackIcon() { + return ( + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/BlockIcon.tsx b/utils/icons/shared/BlockIcon.tsx new file mode 100644 index 0000000..d9dfff8 --- /dev/null +++ b/utils/icons/shared/BlockIcon.tsx @@ -0,0 +1,25 @@ +export default function BlockIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/CheckBoxEmptyIcon.tsx b/utils/icons/shared/CheckBoxEmptyIcon.tsx new file mode 100644 index 0000000..53c1674 --- /dev/null +++ b/utils/icons/shared/CheckBoxEmptyIcon.tsx @@ -0,0 +1,21 @@ +export default function CheckBoxEmptyIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/CheckBoxFillCheckedIcon.tsx b/utils/icons/shared/CheckBoxFillCheckedIcon.tsx new file mode 100644 index 0000000..df8b5db --- /dev/null +++ b/utils/icons/shared/CheckBoxFillCheckedIcon.tsx @@ -0,0 +1,22 @@ +export default function CheckBoxFillCheckedIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/CheckBoxTickCheckedIcon.tsx b/utils/icons/shared/CheckBoxTickCheckedIcon.tsx new file mode 100644 index 0000000..fc473fe --- /dev/null +++ b/utils/icons/shared/CheckBoxTickCheckedIcon.tsx @@ -0,0 +1,73 @@ +export default function CheckBoxTickCheckedIcon() { + return ( + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/CheckIcon.tsx b/utils/icons/shared/CheckIcon.tsx new file mode 100644 index 0000000..3e158a9 --- /dev/null +++ b/utils/icons/shared/CheckIcon.tsx @@ -0,0 +1,19 @@ +export default function CheckIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/CloseIcon.tsx b/utils/icons/shared/CloseIcon.tsx new file mode 100644 index 0000000..d845387 --- /dev/null +++ b/utils/icons/shared/CloseIcon.tsx @@ -0,0 +1,37 @@ +import { Box } from "@mui/material"; + +type Props = { + isBorderRounded?: boolean; +}; +export default function CloseIcon({ isBorderRounded }: Props) { + return ( + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/CommentMessageIcon.tsx b/utils/icons/shared/CommentMessageIcon.tsx new file mode 100644 index 0000000..6b95a86 --- /dev/null +++ b/utils/icons/shared/CommentMessageIcon.tsx @@ -0,0 +1,19 @@ +export default function CommentMessageIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/CommentQuestionIcon.tsx b/utils/icons/shared/CommentQuestionIcon.tsx new file mode 100644 index 0000000..0c98217 --- /dev/null +++ b/utils/icons/shared/CommentQuestionIcon.tsx @@ -0,0 +1,33 @@ +export default function CommentQuestionIcon() { + return ( + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/CopyIcon.tsx b/utils/icons/shared/CopyIcon.tsx new file mode 100644 index 0000000..d8ebaac --- /dev/null +++ b/utils/icons/shared/CopyIcon.tsx @@ -0,0 +1,23 @@ +export default function CopyIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/DashIcon.tsx b/utils/icons/shared/DashIcon.tsx new file mode 100644 index 0000000..40c2d0c --- /dev/null +++ b/utils/icons/shared/DashIcon.tsx @@ -0,0 +1,34 @@ +export default function DashIcon() { + return ( + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/DeleteIcon.tsx b/utils/icons/shared/DeleteIcon.tsx new file mode 100644 index 0000000..37bef44 --- /dev/null +++ b/utils/icons/shared/DeleteIcon.tsx @@ -0,0 +1,24 @@ +export default function DeleteIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/shared/EditIcon.tsx b/utils/icons/shared/EditIcon.tsx new file mode 100644 index 0000000..754bbe0 --- /dev/null +++ b/utils/icons/shared/EditIcon.tsx @@ -0,0 +1,32 @@ +export default function EditIcon() { + return ( + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/EmailIcon.tsx b/utils/icons/shared/EmailIcon.tsx new file mode 100644 index 0000000..1ac7738 --- /dev/null +++ b/utils/icons/shared/EmailIcon.tsx @@ -0,0 +1,40 @@ +export default function EmailIcon() { + return ( + + + + + + + ); +} diff --git a/utils/icons/shared/EnterIcon.tsx b/utils/icons/shared/EnterIcon.tsx new file mode 100644 index 0000000..85a3abc --- /dev/null +++ b/utils/icons/shared/EnterIcon.tsx @@ -0,0 +1,15 @@ +export default function EnterIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/ExternalLinkIcon.tsx b/utils/icons/shared/ExternalLinkIcon.tsx new file mode 100644 index 0000000..e56c78e --- /dev/null +++ b/utils/icons/shared/ExternalLinkIcon.tsx @@ -0,0 +1,19 @@ +export default function ExternalLinkIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/FilterIcon.tsx b/utils/icons/shared/FilterIcon.tsx new file mode 100644 index 0000000..d9b6bf3 --- /dev/null +++ b/utils/icons/shared/FilterIcon.tsx @@ -0,0 +1,36 @@ +export default function FilterIcon() { + return ( + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/GlobleHypeIcon.tsx b/utils/icons/shared/GlobleHypeIcon.tsx new file mode 100644 index 0000000..ce5697e --- /dev/null +++ b/utils/icons/shared/GlobleHypeIcon.tsx @@ -0,0 +1,26 @@ +export default function GlobleHypeIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/LampIcon.tsx b/utils/icons/shared/LampIcon.tsx new file mode 100644 index 0000000..3a65e0a --- /dev/null +++ b/utils/icons/shared/LampIcon.tsx @@ -0,0 +1,19 @@ +export default function LampIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/LikeIcon.tsx b/utils/icons/shared/LikeIcon.tsx new file mode 100644 index 0000000..abdef92 --- /dev/null +++ b/utils/icons/shared/LikeIcon.tsx @@ -0,0 +1,22 @@ +type Props = { + isFilled?: boolean; +}; + +export default function LikeIcon({ isFilled }: Props) { + return ( + + + + ); +} diff --git a/utils/icons/shared/LinkCopyIcon.tsx b/utils/icons/shared/LinkCopyIcon.tsx new file mode 100644 index 0000000..8d3d0cb --- /dev/null +++ b/utils/icons/shared/LinkCopyIcon.tsx @@ -0,0 +1,24 @@ +export default function LinkCopyIcon() { + return ( + + + + + + ); +} diff --git a/utils/icons/shared/LockIcon.tsx b/utils/icons/shared/LockIcon.tsx new file mode 100644 index 0000000..1d28604 --- /dev/null +++ b/utils/icons/shared/LockIcon.tsx @@ -0,0 +1,40 @@ +export default function LockIcon() { + return ( + + + + + + + ); +} diff --git a/utils/icons/shared/LogoutIcon.tsx b/utils/icons/shared/LogoutIcon.tsx new file mode 100644 index 0000000..1e71478 --- /dev/null +++ b/utils/icons/shared/LogoutIcon.tsx @@ -0,0 +1,20 @@ +export default function LogoutIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/MicrophoneIcon.tsx b/utils/icons/shared/MicrophoneIcon.tsx new file mode 100644 index 0000000..4dd0f69 --- /dev/null +++ b/utils/icons/shared/MicrophoneIcon.tsx @@ -0,0 +1,16 @@ +export default function MicrophoneIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/NetworkIcon.tsx b/utils/icons/shared/NetworkIcon.tsx new file mode 100644 index 0000000..427f97b --- /dev/null +++ b/utils/icons/shared/NetworkIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react' + +const NetworkIcon = () => { + return ( + + + + + + + + + + + + + + + + + ) +} + +export default NetworkIcon \ No newline at end of file diff --git a/utils/icons/shared/NormalLeftArrowIcon.tsx b/utils/icons/shared/NormalLeftArrowIcon.tsx new file mode 100644 index 0000000..8426570 --- /dev/null +++ b/utils/icons/shared/NormalLeftArrowIcon.tsx @@ -0,0 +1,26 @@ +export default function NormalLeftArrowIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/OpenLockIcon.tsx b/utils/icons/shared/OpenLockIcon.tsx new file mode 100644 index 0000000..930fd81 --- /dev/null +++ b/utils/icons/shared/OpenLockIcon.tsx @@ -0,0 +1,16 @@ +export default function OpenLockIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/OutLinedAlertIcon.tsx b/utils/icons/shared/OutLinedAlertIcon.tsx new file mode 100644 index 0000000..5455b43 --- /dev/null +++ b/utils/icons/shared/OutLinedAlertIcon.tsx @@ -0,0 +1,36 @@ +export default function OutLinedAlertIcon() { + return ( + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/PlusIcon.tsx b/utils/icons/shared/PlusIcon.tsx new file mode 100644 index 0000000..f5a6511 --- /dev/null +++ b/utils/icons/shared/PlusIcon.tsx @@ -0,0 +1,26 @@ +export default function PlusIcon() { + return ( + + + + + ); +} diff --git a/utils/icons/shared/QuestionMarkIcon.tsx b/utils/icons/shared/QuestionMarkIcon.tsx new file mode 100644 index 0000000..f73f1d0 --- /dev/null +++ b/utils/icons/shared/QuestionMarkIcon.tsx @@ -0,0 +1,28 @@ +export default function QuestionMarkIcon() { + return ( + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/RefreshIcon.tsx b/utils/icons/shared/RefreshIcon.tsx new file mode 100644 index 0000000..a7c62f3 --- /dev/null +++ b/utils/icons/shared/RefreshIcon.tsx @@ -0,0 +1,32 @@ +export default function RefreshIcon() { + return ( + + + + + + + ); +} diff --git a/utils/icons/shared/ReverseIcon.tsx b/utils/icons/shared/ReverseIcon.tsx new file mode 100644 index 0000000..8f077fc --- /dev/null +++ b/utils/icons/shared/ReverseIcon.tsx @@ -0,0 +1,27 @@ +import React from "react"; + +const ReverseIcon = () => { + return ( + + + + + + + + + + + ); +}; + +export default ReverseIcon; diff --git a/utils/icons/shared/RighCrossArrowIcon.tsx b/utils/icons/shared/RighCrossArrowIcon.tsx new file mode 100644 index 0000000..e2d0b2c --- /dev/null +++ b/utils/icons/shared/RighCrossArrowIcon.tsx @@ -0,0 +1,19 @@ +export default function RighCrossArrowIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/RightThikArrowButton.tsx b/utils/icons/shared/RightThikArrowButton.tsx new file mode 100644 index 0000000..005cccf --- /dev/null +++ b/utils/icons/shared/RightThikArrowButton.tsx @@ -0,0 +1,22 @@ +import React from "react"; + +const RightThikArrowButton = () => { + return ( + + + + ); +}; + +export default RightThikArrowButton; diff --git a/utils/icons/shared/RocketIcon.tsx b/utils/icons/shared/RocketIcon.tsx new file mode 100644 index 0000000..b8f238b --- /dev/null +++ b/utils/icons/shared/RocketIcon.tsx @@ -0,0 +1,24 @@ +export default function RocketIcon() { + return ( + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/RotateIcon.tsx b/utils/icons/shared/RotateIcon.tsx new file mode 100644 index 0000000..f0f7b66 --- /dev/null +++ b/utils/icons/shared/RotateIcon.tsx @@ -0,0 +1,18 @@ +export default function RotatetIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/ShareIcon.tsx b/utils/icons/shared/ShareIcon.tsx new file mode 100644 index 0000000..0acd759 --- /dev/null +++ b/utils/icons/shared/ShareIcon.tsx @@ -0,0 +1,47 @@ +export default function ShareIcon() { + return ( + + + + + + + + ); +} diff --git a/utils/icons/shared/TriangleAlertIcon.tsx b/utils/icons/shared/TriangleAlertIcon.tsx new file mode 100644 index 0000000..01b0915 --- /dev/null +++ b/utils/icons/shared/TriangleAlertIcon.tsx @@ -0,0 +1,36 @@ +export default function TriangleAlertIcon() { + return ( + + + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/UpscaleIcon.tsx b/utils/icons/shared/UpscaleIcon.tsx new file mode 100644 index 0000000..133c0af --- /dev/null +++ b/utils/icons/shared/UpscaleIcon.tsx @@ -0,0 +1,18 @@ +export default function UpscaleIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/VisibilityOffIcon.tsx b/utils/icons/shared/VisibilityOffIcon.tsx new file mode 100644 index 0000000..1305a8d --- /dev/null +++ b/utils/icons/shared/VisibilityOffIcon.tsx @@ -0,0 +1,16 @@ +export default function VisibilityOffIcon() { + return ( + + + + ); +} diff --git a/utils/icons/shared/WititLogoIcon.tsx b/utils/icons/shared/WititLogoIcon.tsx new file mode 100644 index 0000000..1c6e184 --- /dev/null +++ b/utils/icons/shared/WititLogoIcon.tsx @@ -0,0 +1,67 @@ +export default function WititLogoIcon() { + return ( + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/utils/icons/shared/index.ts b/utils/icons/shared/index.ts new file mode 100644 index 0000000..9185780 --- /dev/null +++ b/utils/icons/shared/index.ts @@ -0,0 +1,4 @@ +export { default as EmailIcon } from "./EmailIcon"; +export { default as LockIcon } from "./LockIcon"; +export { default as RefreshIcon } from "./RefreshIcon"; +export { default as ExternalLinkIcon } from "./ExternalLinkIcon"; diff --git a/utils/icons/topbar/CalenderIcon.tsx b/utils/icons/topbar/CalenderIcon.tsx new file mode 100644 index 0000000..54b1780 --- /dev/null +++ b/utils/icons/topbar/CalenderIcon.tsx @@ -0,0 +1,40 @@ +export const CalenderIcon = () => { + return ( + + + + + + + + + + + + + + ); +}; diff --git a/utils/icons/topbar/CreditIcon.tsx b/utils/icons/topbar/CreditIcon.tsx new file mode 100644 index 0000000..2ce1a13 --- /dev/null +++ b/utils/icons/topbar/CreditIcon.tsx @@ -0,0 +1,22 @@ +import React from "react"; + +const CreditIcon = () => { + return ( + + + + ); +}; + +export default CreditIcon; diff --git a/utils/icons/topbar/HypeIcon.tsx b/utils/icons/topbar/HypeIcon.tsx new file mode 100644 index 0000000..3e9bbc5 --- /dev/null +++ b/utils/icons/topbar/HypeIcon.tsx @@ -0,0 +1,47 @@ +import React from "react"; + +type Props = { + isWithBlue?: boolean; +}; + +const HypeIcon = ({ isWithBlue }: Props) => { + return ( +
+ + + + {/* */} + + {isWithBlue ?
: null} +
+ ); +}; + +export default HypeIcon; diff --git a/utils/icons/topbar/SearchIcon.tsx b/utils/icons/topbar/SearchIcon.tsx new file mode 100644 index 0000000..50fb37a --- /dev/null +++ b/utils/icons/topbar/SearchIcon.tsx @@ -0,0 +1,21 @@ +import React from "react"; + +const SearchIcon = () => { + return ( + + + + ); +}; + +export default SearchIcon; diff --git a/utils/images/CreditTopBg.png b/utils/images/CreditTopBg.png new file mode 100644 index 0000000..4ad1e9c Binary files /dev/null and b/utils/images/CreditTopBg.png differ diff --git a/utils/images/CrossLineBg.png b/utils/images/CrossLineBg.png new file mode 100644 index 0000000..bc2905a Binary files /dev/null and b/utils/images/CrossLineBg.png differ diff --git a/utils/images/aiModelTraining/CoveringFace.jpg b/utils/images/aiModelTraining/CoveringFace.jpg new file mode 100644 index 0000000..278be1b Binary files /dev/null and b/utils/images/aiModelTraining/CoveringFace.jpg differ diff --git a/utils/images/aiModelTraining/blurry.jpg b/utils/images/aiModelTraining/blurry.jpg new file mode 100644 index 0000000..e1a90fe Binary files /dev/null and b/utils/images/aiModelTraining/blurry.jpg differ diff --git a/utils/images/aiModelTraining/farAway.jpg b/utils/images/aiModelTraining/farAway.jpg new file mode 100644 index 0000000..6df95ba Binary files /dev/null and b/utils/images/aiModelTraining/farAway.jpg differ diff --git a/utils/images/aiModelTraining/highQulity.jpg b/utils/images/aiModelTraining/highQulity.jpg new file mode 100644 index 0000000..d8f38a8 Binary files /dev/null and b/utils/images/aiModelTraining/highQulity.jpg differ diff --git a/utils/images/aiModelTraining/landscapeOriantation.jpg b/utils/images/aiModelTraining/landscapeOriantation.jpg new file mode 100644 index 0000000..70054e1 Binary files /dev/null and b/utils/images/aiModelTraining/landscapeOriantation.jpg differ diff --git a/utils/images/aiModelTraining/manVector.svg b/utils/images/aiModelTraining/manVector.svg new file mode 100644 index 0000000..3c10762 --- /dev/null +++ b/utils/images/aiModelTraining/manVector.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/aiModelTraining/multiplePeople.jpg b/utils/images/aiModelTraining/multiplePeople.jpg new file mode 100644 index 0000000..ac9727c Binary files /dev/null and b/utils/images/aiModelTraining/multiplePeople.jpg differ diff --git a/utils/images/aiModelTraining/selfies.jpg b/utils/images/aiModelTraining/selfies.jpg new file mode 100644 index 0000000..95e755a Binary files /dev/null and b/utils/images/aiModelTraining/selfies.jpg differ diff --git a/utils/images/aiModelTraining/sitting.jpg b/utils/images/aiModelTraining/sitting.jpg new file mode 100644 index 0000000..7e0a72f Binary files /dev/null and b/utils/images/aiModelTraining/sitting.jpg differ diff --git a/utils/images/aiModelTraining/varietyOfAngles.jpg b/utils/images/aiModelTraining/varietyOfAngles.jpg new file mode 100644 index 0000000..fb24eb6 Binary files /dev/null and b/utils/images/aiModelTraining/varietyOfAngles.jpg differ diff --git a/utils/images/aiModelTraining/varietyOfLighting.jpg b/utils/images/aiModelTraining/varietyOfLighting.jpg new file mode 100644 index 0000000..bee9cb8 Binary files /dev/null and b/utils/images/aiModelTraining/varietyOfLighting.jpg differ diff --git a/utils/images/aiModelTraining/varietyOfLocations.jpg b/utils/images/aiModelTraining/varietyOfLocations.jpg new file mode 100644 index 0000000..57e387d Binary files /dev/null and b/utils/images/aiModelTraining/varietyOfLocations.jpg differ diff --git a/utils/images/aiModelTraining/womanVector.svg b/utils/images/aiModelTraining/womanVector.svg new file mode 100644 index 0000000..a494a62 --- /dev/null +++ b/utils/images/aiModelTraining/womanVector.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/blockUserIllustrator.svg b/utils/images/blockUserIllustrator.svg new file mode 100644 index 0000000..3fd3e12 --- /dev/null +++ b/utils/images/blockUserIllustrator.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/utils/images/comingSoon.svg b/utils/images/comingSoon.svg new file mode 100644 index 0000000..f93a49e --- /dev/null +++ b/utils/images/comingSoon.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/congratulations.png b/utils/images/congratulations.png new file mode 100644 index 0000000..0d58448 Binary files /dev/null and b/utils/images/congratulations.png differ diff --git a/utils/images/crossStripsBg.svg b/utils/images/crossStripsBg.svg new file mode 100644 index 0000000..137e9f1 --- /dev/null +++ b/utils/images/crossStripsBg.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/deleteOffer.svg b/utils/images/deleteOffer.svg new file mode 100644 index 0000000..081cef0 --- /dev/null +++ b/utils/images/deleteOffer.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/utils/images/driverLicenseBack.svg b/utils/images/driverLicenseBack.svg new file mode 100644 index 0000000..41fdaa8 --- /dev/null +++ b/utils/images/driverLicenseBack.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/driverLicenseFront.svg b/utils/images/driverLicenseFront.svg new file mode 100644 index 0000000..46d54b6 --- /dev/null +++ b/utils/images/driverLicenseFront.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/externalLink.svg b/utils/images/externalLink.svg new file mode 100644 index 0000000..f476193 --- /dev/null +++ b/utils/images/externalLink.svg @@ -0,0 +1,3 @@ + + + diff --git a/utils/images/filter.svg b/utils/images/filter.svg new file mode 100644 index 0000000..d14fc6f --- /dev/null +++ b/utils/images/filter.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/utils/images/index.ts b/utils/images/index.ts new file mode 100644 index 0000000..bee743e --- /dev/null +++ b/utils/images/index.ts @@ -0,0 +1,11 @@ +export { default as temp1 } from "./temp1.jpg"; +export { default as profilePlaceholderImage } from "./profilePlaceholderImage.png"; +export { default as crossLineBg } from "./CrossLineBg.png"; +export { default as comingSoon } from "./comingSoon.svg"; +export { default as filterImage } from "./filter.svg"; +export { default as creditDialogBg } from "./CreditTopBg.png"; +export { default as wititImage } from "./witit.svg"; +export { default as blockUserIllustrator } from "./blockUserIllustrator.svg"; +export { default as postNotFoundSloth } from "./postNotFoundSloth.svg"; +export { default as noCommentFound } from "./noCommentFound.svg"; +export {default as deleteModelBin} from "./deleteOffer.svg" \ No newline at end of file diff --git a/utils/images/loginImage.png b/utils/images/loginImage.png new file mode 100644 index 0000000..e235254 Binary files /dev/null and b/utils/images/loginImage.png differ diff --git a/utils/images/message/index.ts b/utils/images/message/index.ts new file mode 100644 index 0000000..0dd5fa0 --- /dev/null +++ b/utils/images/message/index.ts @@ -0,0 +1,2 @@ +export { default as messageNotFound } from "./noMessageFound.svg"; +export { default as searchUserNotFound } from "./notSearchUserFound.svg"; diff --git a/utils/images/message/noMessageFound.svg b/utils/images/message/noMessageFound.svg new file mode 100644 index 0000000..003fbf4 --- /dev/null +++ b/utils/images/message/noMessageFound.svg @@ -0,0 +1,3 @@ + + + diff --git a/utils/images/message/notSearchUserFound.svg b/utils/images/message/notSearchUserFound.svg new file mode 100644 index 0000000..44bcf3b --- /dev/null +++ b/utils/images/message/notSearchUserFound.svg @@ -0,0 +1,3 @@ + + + diff --git a/utils/images/noCommentFound.svg b/utils/images/noCommentFound.svg new file mode 100644 index 0000000..f91e081 --- /dev/null +++ b/utils/images/noCommentFound.svg @@ -0,0 +1,4 @@ + + + + diff --git a/utils/images/offering/deleteOffer.svg b/utils/images/offering/deleteOffer.svg new file mode 100644 index 0000000..081cef0 --- /dev/null +++ b/utils/images/offering/deleteOffer.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/utils/images/offering/index.tsx b/utils/images/offering/index.tsx new file mode 100644 index 0000000..1803475 --- /dev/null +++ b/utils/images/offering/index.tsx @@ -0,0 +1 @@ +export { default as DeleteOfferImage } from "./deleteOffer.svg"; diff --git a/utils/images/postNotFoundSloth.svg b/utils/images/postNotFoundSloth.svg new file mode 100644 index 0000000..5ddb16a --- /dev/null +++ b/utils/images/postNotFoundSloth.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/utils/images/profilePlaceHolder.svg b/utils/images/profilePlaceHolder.svg new file mode 100644 index 0000000..d2faafe --- /dev/null +++ b/utils/images/profilePlaceHolder.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/utils/images/profilePlaceholderImage.png b/utils/images/profilePlaceholderImage.png new file mode 100644 index 0000000..04fcceb Binary files /dev/null and b/utils/images/profilePlaceholderImage.png differ diff --git a/utils/images/question/index.ts b/utils/images/question/index.ts new file mode 100644 index 0000000..11a0d7f --- /dev/null +++ b/utils/images/question/index.ts @@ -0,0 +1 @@ +export { default as questionNotFound } from "./notFound.svg"; \ No newline at end of file diff --git a/utils/images/question/notFound.svg b/utils/images/question/notFound.svg new file mode 100644 index 0000000..2272147 --- /dev/null +++ b/utils/images/question/notFound.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/utils/images/setting/blockuUserNotFound.svg b/utils/images/setting/blockuUserNotFound.svg new file mode 100644 index 0000000..6ddea5e --- /dev/null +++ b/utils/images/setting/blockuUserNotFound.svg @@ -0,0 +1,4 @@ + + + + diff --git a/utils/images/setting/documentPending.svg b/utils/images/setting/documentPending.svg new file mode 100644 index 0000000..22bf599 --- /dev/null +++ b/utils/images/setting/documentPending.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/utils/images/setting/index.ts b/utils/images/setting/index.ts new file mode 100644 index 0000000..79518c4 --- /dev/null +++ b/utils/images/setting/index.ts @@ -0,0 +1,2 @@ +export { default as blockUSerNotFound } from "./blockuUserNotFound.svg"; +export { default as noModelFound } from "./noModelFound.svg"; diff --git a/utils/images/setting/noApplicationFound.svg b/utils/images/setting/noApplicationFound.svg new file mode 100644 index 0000000..79b0a0d --- /dev/null +++ b/utils/images/setting/noApplicationFound.svg @@ -0,0 +1,3 @@ + + + diff --git a/utils/images/setting/noModelFound.svg b/utils/images/setting/noModelFound.svg new file mode 100644 index 0000000..f9b05e9 --- /dev/null +++ b/utils/images/setting/noModelFound.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/sloth_image.jpg b/utils/images/sloth_image.jpg new file mode 100644 index 0000000..6f7a904 Binary files /dev/null and b/utils/images/sloth_image.jpg differ diff --git a/utils/images/startCreatingBg.jpg b/utils/images/startCreatingBg.jpg new file mode 100644 index 0000000..1c1e9fc Binary files /dev/null and b/utils/images/startCreatingBg.jpg differ diff --git a/utils/images/temp1.jpg b/utils/images/temp1.jpg new file mode 100644 index 0000000..7a66caa Binary files /dev/null and b/utils/images/temp1.jpg differ diff --git a/utils/images/temp2.jpg b/utils/images/temp2.jpg new file mode 100644 index 0000000..e23b800 Binary files /dev/null and b/utils/images/temp2.jpg differ diff --git a/utils/images/temp3.jpg b/utils/images/temp3.jpg new file mode 100644 index 0000000..663ac9c Binary files /dev/null and b/utils/images/temp3.jpg differ diff --git a/utils/images/temp4.jpg b/utils/images/temp4.jpg new file mode 100644 index 0000000..d0a38e6 Binary files /dev/null and b/utils/images/temp4.jpg differ diff --git a/utils/images/temp5.jpg b/utils/images/temp5.jpg new file mode 100644 index 0000000..fb9182f Binary files /dev/null and b/utils/images/temp5.jpg differ diff --git a/utils/images/tempIdentificationCard.jpg b/utils/images/tempIdentificationCard.jpg new file mode 100644 index 0000000..81a5ccc Binary files /dev/null and b/utils/images/tempIdentificationCard.jpg differ diff --git a/utils/images/tempPickachu.jpg b/utils/images/tempPickachu.jpg new file mode 100644 index 0000000..4e08629 Binary files /dev/null and b/utils/images/tempPickachu.jpg differ diff --git a/utils/images/tempboy.jpg b/utils/images/tempboy.jpg new file mode 100644 index 0000000..f9fa028 Binary files /dev/null and b/utils/images/tempboy.jpg differ diff --git a/utils/images/tempuser.jpg b/utils/images/tempuser.jpg new file mode 100644 index 0000000..7dee6a8 Binary files /dev/null and b/utils/images/tempuser.jpg differ diff --git a/utils/images/topbar/dollerImage.svg b/utils/images/topbar/dollerImage.svg new file mode 100644 index 0000000..999cbd0 --- /dev/null +++ b/utils/images/topbar/dollerImage.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/utils/images/topbar/index.ts b/utils/images/topbar/index.ts new file mode 100644 index 0000000..c2bd262 --- /dev/null +++ b/utils/images/topbar/index.ts @@ -0,0 +1 @@ +export {default as dollerImage} from "./dollerImage.svg" \ No newline at end of file diff --git a/utils/images/twoMessageBox.svg b/utils/images/twoMessageBox.svg new file mode 100644 index 0000000..61145f4 --- /dev/null +++ b/utils/images/twoMessageBox.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/utils/images/verifyAccountBg.png b/utils/images/verifyAccountBg.png new file mode 100644 index 0000000..8d256b8 Binary files /dev/null and b/utils/images/verifyAccountBg.png differ diff --git a/utils/images/witit.svg b/utils/images/witit.svg new file mode 100644 index 0000000..5128ec5 --- /dev/null +++ b/utils/images/witit.svg @@ -0,0 +1,3 @@ + + + diff --git a/utils/images/wititLogo.svg b/utils/images/wititLogo.svg new file mode 100644 index 0000000..ead960c --- /dev/null +++ b/utils/images/wititLogo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/utils/images/wititSmall.svg b/utils/images/wititSmall.svg new file mode 100644 index 0000000..794b9da --- /dev/null +++ b/utils/images/wititSmall.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/images/world.svg b/utils/images/world.svg new file mode 100644 index 0000000..a3fb3e1 --- /dev/null +++ b/utils/images/world.svg @@ -0,0 +1,977 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/utils/lottie/failurelottle.json b/utils/lottie/failurelottle.json new file mode 100644 index 0000000..72f873b --- /dev/null +++ b/utils/lottie/failurelottle.json @@ -0,0 +1 @@ +{"nm":"Cross","ddd":0,"h":500,"w":500,"meta":{"g":"LottieFiles AE 1.0.0"},"layers":[{"ty":2,"nm":"cross","sr":1,"st":0,"op":68,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[188,188,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.559,"y":0},"i":{"x":0.667,"y":1},"s":[0,0,100],"t":35},{"s":[46,46,100],"t":45}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"refId":"image_0","ind":1},{"ty":4,"nm":"circle-3-white","sr":1,"st":0,"op":68,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[12,0,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[96,96,100],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[96,96,100],"t":7},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[96,96,100],"t":22},{"s":[0,0,100],"t":34}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[248.391,252.391,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[375.219,375.219],"ix":2}},{"ty":"st","bm":0,"hd":true,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":18,"ix":5},"c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[1,1,1],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[13.609,-2.391],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"circle-2-red","sr":1,"st":0,"op":68,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[12,0,0],"ix":1},"s":{"a":0,"k":[96,96,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[248.391,252.391,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":19},{"s":[100],"t":22}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[375.219,375.219],"ix":2}},{"ty":"st","bm":0,"hd":true,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":18,"ix":5},"c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[13.609,-2.391],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"circle-1-line","sr":1,"st":0,"op":68,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[12,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[248.391,252.391,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[375.219,375.219],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":18,"ix":5},"c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":3}},{"ty":"fl","bm":0,"hd":true,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[13.609,-2.391],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":-62,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.699,"y":0},"i":{"x":0.786,"y":1},"s":[0],"t":0},{"s":[100],"t":22}],"ix":1},"m":1}],"ind":4},{"ty":4,"nm":"Shadows","sr":1,"st":0,"op":68,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[12,0,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[96,96,100],"t":40},{"s":[118,118,100],"t":50}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[248.391,252.391,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":40},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[100],"t":50},{"s":[0],"t":64}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[375.219,375.219],"ix":2}},{"ty":"st","bm":0,"hd":true,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":18,"ix":5},"c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.8667,0.3412,0.3412],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[13.609,-2.391],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5}],"v":"4.8.0","fr":30,"op":60,"ip":0,"assets":[{"id":"image_0","u":"","e":1,"w":376,"h":376,"p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXgAAAF4CAYAAABeneKmAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAU9UlEQVR4nO3d63Uc17GA0WolIGVgZiA5AiODqwwMRWA5A94MmIHhCExHYCoDMoJLZUBFcO6PAWWQwmOm5pzu89h7LS394WoMu6s+NhvDQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwOq2o1/AY0opryLiJiJ+ePDft4/80t8i4n1EfLz//7tt297v8iKBqZRSvotTd27i1JxXEfGnJ375r3Hqzrv4b3s+NX6J4yqlvCqlvCmlfCzX+VRKuSul/HD07wnoWynlu1LKbSnl/ZXdKaWUt/fH+u7o31c3Sik3pZR3FU7uY96XUm6P/j0CfSmnG8q7crohrO1TKeV1WTn09ye4Vdi/9rGUcnP07xk4Vjndsb/eqTufSimvj/49727HE/y1t2XlP1VhYeX0tODaR8AZH8sKj4zL6U/PGs+6nGzgbOX0/b2j/Xz0eWimlPJDafO8K+NT8WwepldON5VvD+7NQ3dHn5PqSl9xf+j26HMDtFH6eGLwmN0eFTd/H3w5PQ55F4+/j70HP23bdnf0iwDquQ/ou4j4/uCX8pR/b9v2Y+sv0jTw5fQPlt5Hv3H/TORhEgPE/bN/btt22/ILfNPqwPcn+W30H/eIiH8Uj2tgeAPFPSLir6XxN16b3cGXUt5ExN9aHb8Rd/IwqMHi/tCfW33ESpPAl9M/KvpPi2PvQORhMAPHPSLiw7ZtTd663eoRzV2j4+7B4xoYyOBxj4j4vlVzqgf+/oU+9QlsoxB5GMAEcf/sTYu3Tra4g3/d4JhHEHno2ERxjzi9GeW29kGrBn6Su/eHRB46NFncP6v+jprad/DN37h/AJGHjkwa94iIP5VSqja0WuDvT/r/1DpeZ0QeOjBx3D/rM/Ax5937QyIPB1og7hEdB/6m4rF6JfJwgEXiHhHxban4ceY1A7/KZ6yLPOxoobh/1mXgVzn5ESIPu1gw7hERr2odqErga/6VYiAiDw0tGveIio+7a93Br/pzTkUeGlg47lU1+7jghYg8VCTunT2iQeShBnGPiIqfBiDw9Yg8XEHc6xP4ukQeEsT9Cx9qHUjg6xN5uIC4/8GnWgeqFfiPlY4zC5GHM4j7o/oK/LZtH2scZzIiD88Q9ydV+/msNR/R/FLxWLMQeXiEuD+ry8A3+angExB5eEDcX9Rl4N9VPNZsRB5C3M/woeYj72qB37btbUT8Vut4ExJ5libuZ3lX82C13yb5tvLxZiPyLEncz/am5sFqB77qi5uUyLMUcT/bL7XfkVg18Nu2vQ/vpjmHyLMEcb9I9RvkrfYBSyk3EfGf2sed1E/btt0d/SKgBXG/yIdt26r/XI3qH1Wwbdu7cBd/LnfyTEncL/Zzi4O2+iya2/COmnOJPFMR94v9+/7GuLomgb//RsHrFseelMgzBXG/2K9xuiFuovoz+IdKKXcR8deWX2MynskzLHFP+fP9m1OaaP1xwT9Hxc82XoA7eYYk7ik/tYx7ROM7+AgXPsmdPMOw4ym77HjzwEcYgCSRp3t2O2W33d4l8BEGIUnk6ZadTtl1p3cLfISBSBJ5umOXU3bf5V0DH2EwkkSebtjhlEN2ePfARxiQJJHncHY35bDdPSTwEQYlSeQ5jJ1NOXRnDwt8hIFJEnl2Z1dTDt/VQwMfYXCSDh8c1mFHU7rY0cMDH2GAkroYIOZmN1O62c0uAh9hkJK6GSTmYydTutrJbgIfYaCSuhoo5mAXU7rbxa4CH2GwkrobLMZlB1O63MHuAh9hwJK6HDDGYvdSut29LgMfYdCSuh00+mfnUrreuW4DH2HgkroeOPpk11K637WuAx9h8JK6Hzz6YcdShtix7gMfYQCThhhAjmW3UobZrSECH2EQk4YZRPZnp1KG2qlhAh9hIJOGGkj2YZdShtuloQIfYTCThhtM2rFDKUPu0HCBjzCgSUMOKHXZnZRhd2fIwEcY1KRhB5Xr2ZmUoXdm2MBHGNikoQeWHLuSMvyuDB34CIObNPzgcj47kjLFjgwf+AgDnDTFAPM8u5EyzW5MEfgIg5w0zSDzR3YiZaqdmCbwEQY6aaqB5sQupEy3C1MFPsJgJ0032CuzAylT7sB0gY8w4ElTDvhqzH7KtLM/ZeAjDHrStIO+AjOfMvXMTxv4CAOfNPXAz8qsp0w/61MHPsLgJ00/+DMx4ylLzPj0gY+wAElLLMDozHbKMrO9ROAjLELSMoswIjOdstRMLxP4CAuRtNRCjMIspyw3y0sFPsJiJC23GD0zwylLzvBygY+wIElLLkhvzG7KsrO7ZOAjLErSsovSAzObsvTMLhv4CAuTtPTCHMWspiw/q0sHPsLiJC2/OHsyoylmNAQ+IixQkgXagdlMMZv3BP6eRUqxSA2ZyRQz+YDAP2ChUixUA2YxxSx+ReC/YrFSLFZFZjDFDD5C4B9hwVIsWAVmL8XsPUHgn2DRUizaFcxcipl7hsA/w8KlWLgEs5Zi1l4g8C+weCkW7wJmLMWMnUHgz2ABUyzgGcxWitk6k8CfySKmWMRnmKkUM3UBgb+AhUyxkI8wSylm6UICfyGLmWIxHzBDKWYoQeATLGiKBQ2zk2R2kgQ+yaKmLL2oZiZl6Zm5lsBfwcKmLLmwZiVlyVmpSeCvZHFTllpcM5Ky1Iy0IvAVWOCUJRbYbKQsMRt7EPhKLHLK1ItsJlKmnom9CXxFFjplyoU2CylTzsKRBL4yi50y1WKbgZSpZqAXAt+ABU+ZYsFd+5Qprn2PBL4Ri54y9KK75ilDX/PeCXxDFj5lyIV3rVOGvNYjEfjGLH7KUIvvGqcMdY1HJfA7EICUIQLg2qYMcW1nIPA7EYKUrkPgmqZ0fU1nI/A7EoSULoPgWqZ0eS1nJvA7E4aUrsLgGqZ0dQ1XIfAHEIiULgLh2qV0ce1WJPAHEYqUQ0PhmqWI+4EE/kCCkXJIMFyrFHE/mMAfTDhSdg2Ha5Qi7h0Q+A4ISMouAXFtUsS9EwLfCSFJaRoS1yRF3Dsi8B0RlJQmQXEtUsS9MwLfGWFJqRoW1yBF3Dsk8B0SmJQqgXHuU8S9UwLfKaFJuSo0znmKuHdM4DsmOCmp4DjXKeLeOYHvnPCkXBQe5zhF3Acg8AMQoJSzAuTcpoj7IAR+EEKU8myInNMUcR+IwA9EkFIeDZJzmSLugxH4wQhTyhdhcg5TxH1AAj8ggUr5adu2O+cuRdwHJfCDEqqUv0fEbThnlxD3gQn8wESexsR9cAI/OJGnEXGfgMBPQOSpTNwnIfCTEHkqEfeJCPxERJ4riftkBH4yIk+SuE9I4Cck8lxI3Ccl8JMSec4k7hMT+ImJPC8Q98kJ/OREnieI+wIEfgEiz1fEfRECvwiR5564L0TgFyLyyxP3xQj8YkR+WeK+IIFfkMgvR9wXJfCLEvlliPvCBH5hIj89cV+cwC9O5Kcl7gg8Ij8hcSciBJ57Ij8Nced3As/vRH544s4XBJ4viPywxJ0/EHj+QOSHI+48SuB5lMgPQ9x5ksDzJJHvnrjzLIHnWSLfLXHnRQLPi0S+O+LOWQSes4h8N8Sdswk8ZxP5w4k7FxF4LiLyhxF3LibwXEzkdyfupAg8KSK/G3EnTeBJE/nmxJ2rCDxXEflmxJ2rCTxXE/nqxJ0qBJ4qRL4acacagacakb+auFOVwFOVyKeJO9V9c/QLAKANd/BU4+79au7iqUrgqULcqxF5qhF4ribu1Yk8VQg8VxH3ZkSeqwk8aeLenMhzFYEnRdx3I/KkCTwXE/fdiTwpAs9FxP0wIs/FBJ6zifvhRJ6LCDxnEfduiDxnE3heJO7dEXnOIvA8S9y7JfK8SOB5krh3T+R5lsDzKHEfhsjzJIHnD8R9OCLPowSeL4j7sESePxB4fifuwxN5viDwRIS4T0Tk+Z3AI+7zEXkiQuCXJ+7TEnkEfmXiPj2RX5zAL0rclyHyCxP4BYn7ckR+UQK/GHFflsgvSOAXIu7LE/nFCPwixJ17Ir8QgV+AuPMVkV+EwE9O3HmCyC9A4Ccm7rxA5Ccn8JMSd84k8hMT+AmJOxcS+UkJ/GTEnSSRn5DAT0TcuZLIT0bgJyHuVCLyExH4CYg7lYn8JAR+cOJOIyI/AYEfmLjTmMgP7pujXwA54p7y94j4cPSLGMg/Sim3R78I8gR+QOKe8tO2bW8i4iZE/hIiPzCPaAYj7ilfPGpwDlM8rhmQwA9EmFIeDZNzmSLygxH4QQhSyrNBck5TRH4gAj8AIUo5K0TObYrID0LgOydAKRcFyDlOEfkBCHzHhCclFR7nOkXkOyfwnRKclKuC45yniHzHBL5DQpNSJTTOfYrId0rgOyMwKVUD4xqkiHyHBL4jwpLSJCyuRYrId0bgOyEoKU2D4pqkiHxHBL4DQpKyS0hcmxSR74TAH0xAUnYNiGuUIvIdEPgDCUfKIeFwrVJE/mACfxDBSDk0GK5ZisgfSOAPIBQpXYTCtUvp4tqtSOB3JhApXQXCNUzp6hquQuB3JAwpXYbBtUzp8lrOTOB3IggpXQfBNU3p+prORuB3IAQpQ4TAtU0Z4trOQOAbE4CUoQLgGqcMdY1HJfANWfyUIRfftU4Z8lqPROAbsfApQy+8a54y9DXvncA3YNFTplh01z5limvfI4GvzIKnTLXgZiBlqhnohcBXZLFTplxss5Ay5SwcSeArsdApUy+0mUiZeib2JvAVWOSUJRbZbKQsMRt7EPgrWeCUpRbYjKQsNSOtCPwVLG7KkotrVlKWnJWaBD7JwqYsvbBmJmXpmbmWwCdY1BSLGmYnyewkCfyFLGiKBX3ADKWYoQSBv4DFTLGYjzBLKWbpQgJ/JguZYiGfYaZSzNQFBP4MFjHFIp7BbKWYrTMJ/AssYIoFvIAZSzFjZxD4Z1i8FIuXYNZSzNoLBP4JFi7Fwl3BzKWYuWcI/CMsWopFq8DspZi9Jwj8VyxYigWryAymmMFHCPwDFivFYjVgFlPM4lcE/p6FSrFQDZnJFDP5gMCHRUqySDswmylm897ygbdAKRZoR2Y0xYzG4oG3OCkW5wBmNWX5WV028BYmZfmFOZKZTVl6ZpcMvEVJWXpRemF2U5ad3eUCb0FSll2QHpnhlCVneKnAW4yUJRejd2Y5ZblZXibwFiJluYUYiZlOWWqmlwi8RUhZahFGZbZTlpnt6QNvAVKWWYAZmPGUJWZ86sAb/JQlBn82Zj1l+lmfNvAGPmX6gZ+ZmU+ZeuanDLxBT5l60Fdh9lOmnf3pAm/AU6Yd8BXZgZQpd2CqwBvslCkHe3V2IWW6XZgm8AY6ZbqB5r/sRMpUOzFF4A1yylSDzOPsRso0uzF84A1wyjQDzMvsSMoUOzJ04A1uyhSDy2XsSsrwuzJs4A1syvADS56dSRl6Z4YMvEFNGXpQqcPupAy7O8MF3oCmDDug1GeHUobcoaECbzBThhxM2rJLKcPt0jCBN5Apww0k+7FTKUPt1BCBN4gpQw0ix7BbKcPsVveBN4Apwwwgx7NjKUPsWNeBN3gpQwwefbFrKd3vWreBN3Ap3Q8c/bJzKV3vXJeBN2gpXQ8aY7B7Kd3uXneBN2Ap3Q4Y47GDKV3uYFeBN1gpXQ4WY7OLKd3tYjeBN1Ap3Q0U87CTKV3tZBeBN0gpXQ0Sc7KbKd3s5uGBN0Ap3QwQ87OjKV3s6KGBNzgpXQwOa7GrKYfv6mGBNzAphw8M67KzKYfu7CGBNygp4s7h7G7KYbu7e+ANSIq40w07nHLIDu8aeIORIu50xy6n7L7LuwXeQKSIO92y0ym77vQugTcIKeJO9+x2ym673TzwBiBF3BmGHU/ZZce/af0FIuJtuPCXEHeGsm3bp4i4iYgPB7+UkfyjlHLb+os0vYMvpdxFxF9bfo3JiDvDcid/sd8i4mbbtvetvkCzwJdSfoyIf7U6/oTEneGJ/MU+xCnyn1ocvMkjmvuLfNfi2JMSd6bgcc3Fvo+I160O3uoZ/JuI+LbRsWcj7kxF5C/2t1LKTYsDV39Ec/9C/1P7uJMSd6blcc1Fftm27ab2QVvcwb9ucMwZiTtTcyd/kb+0uIuvegdfSnkVEf9X85iTEneW4U7+bNXv4mvfwb+ufLwZiTtLcSd/tr/c3yRXUzvwP1Y+3mzEnSWJ/NmqNrRa4O+fH3nnzNPEnaWJ/Fluax6s5h28u/eniTuEyJ/h+/vvWVRRM/A/VDzWTMQdHhD5F93UOlDNwP+l4rFmIe7wCJF/VrWb5SqBr/2d30mIOzxD5J/UV+Aj4lWl48xC3OEMIv+oLp/BcyLucAGRb0fg6xJ3SBD5L1T7fqbA1yPucAWRr0/g6xB3qEDkIyLi11oHEvjriTtUJPLxsdaBagW+yY+bGoC4QwMiX0eVwLf8obEdE3doaOHIV+tpzUc01Z4bDUDcYQeLRv5jrQPVDPy7isfqmbjDjhaM/LtaBxL4y4g7HGChyP9W85G3wJ9P3OFAi0T+bc2DVQv8tm0fI+KXWsfrjLhDBxaIfJ+Bv3dX+Xg9EHfoyMSR/3Xbtn4Dfx/Cmd5NI+7QoUkjf1f7gC3+Jetdg2MeQdyhY5NF/reIeFP7oNUDv23b6xj/Ll7cYQATRf7N/e+lqq32ASMiSik/RsS/Whx7B+IOg7n/QdXvIuL7g19Kxq/btr1qceAmHzZ2/42Cf7c4dmPiDgMa/E7+x1YHbvlpkrcx1qMacYeBDRr5/235WV5NHtF8Vkr5IU5/bfq25depQNxhEgM9rvnntm23Lb9A08BHDPE8XtxhMgNE/kNE3LT4xuruSim3pU+3R58boI1SynellPdHR+YR78vpD6B5lFJuSimfDj6xD90efU6Atkp/kX9bZov7Z6WUH8rxJ/tTKeXm6HMB7KeUcndwd0oppfo/ZOpOOf2J+uagE/yulPLq6HMA7K+U8mM55inCp3L6XuQ6yumRzV538x+LRzKwvHK6wdzzbv5NmfWRzDnK6RuwHxud3I+llNdLn2DgD0opr0rb0N8VTwv+q5zu6O9Knb9CvS3u2IEXlFPoX5c6N5nvSyk/l45uKJu/Dz6jnL4J+vm/VxHxp2d++W9x+ink7z7/f4r3lgK7Kqc77h8j4of7/156D/0vcfoB2e/i1J2P7V5dTpeBf0r58t0v74UcaK2c/kX+57vyjz2GHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKjg/wFDOUBw8eL9OwAAAABJRU5ErkJggg=="}]} \ No newline at end of file diff --git a/utils/lottie/imagePlaceholderLottie.json b/utils/lottie/imagePlaceholderLottie.json new file mode 100644 index 0000000..7ab0b06 --- /dev/null +++ b/utils/lottie/imagePlaceholderLottie.json @@ -0,0 +1,1365 @@ +{ + "nm": "Comp 1", + "ddd": 0, + "h": 1000, + "w": 1000, + "meta": { "g": "@lottiefiles/toolkit-js 0.26.1" }, + "layers": [ + { + "ty": 0, + "nm": "upload", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [500, 500, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 }, + "sk": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [500, 500, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100, "ix": 11 } + }, + "ef": [], + "w": 1000, + "h": 1000, + "refId": "comp_0", + "ind": 1 + } + ], + "v": "5.5.4", + "fr": 31, + "op": 184, + "ip": 4, + "assets": [ + { + "nm": "", + "id": "comp_0", + "layers": [ + { + "ty": 4, + "nm": "Shape Layer 4", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 505, 0], + "t": 0, + "ti": [0, 5, 0], + "to": [0, 5, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 535, 0], + "t": 27.528, + "ti": [0, 5.667, 0], + "to": [0, -5, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 475, 0], + "t": 30.83, + "ti": [0, -3.667, 0], + "to": [0, -5.667, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 501, 0], + "t": 36.336, + "ti": [0, -0.167, 0], + "to": [0, 3.667, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 497, 0], + "t": 45.145, + "ti": [0, -1.333, 0], + "to": [0, 0.167, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 502, 0], + "t": 50.65, + "ti": [0, -5.5, 0], + "to": [0, 1.333, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 505, 0], + "t": 72.672, + "ti": [0, 5, 0], + "to": [0, 5.5, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 535, 0], + "t": 100.199, + "ti": [0, 5.667, 0], + "to": [0, -5, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 475, 0], + "t": 103.503, + "ti": [0, -3.667, 0], + "to": [0, -5.667, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 501, 0], + "t": 109.009, + "ti": [0, -0.167, 0], + "to": [0, 3.667, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 497, 0], + "t": 117.817, + "ti": [0, -1.333, 0], + "to": [0, 0.167, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 502, 0], + "t": 123.323, + "ti": [0, -5.5, 0], + "to": [0, 1.333, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 505, 0], + "t": 150.85, + "ti": [0, 5, 0], + "to": [0, 5.5, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 535, 0], + "t": 178.377, + "ti": [0, 5.667, 0], + "to": [0, -5, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 475, 0], + "t": 181.68, + "ti": [0, -3.667, 0], + "to": [0, -5.667, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 501, 0], + "t": 187.186, + "ti": [0, -0.167, 0], + "to": [0, 3.667, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [500, 497, 0], + "t": 195.994, + "ti": [0, -0.833, 0], + "to": [0, 0.167, 0] + }, + { "s": [500, 502, 0], "t": 201.5 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [6.75, 31], + [-106.75, 141.25], + [-64.75, 182.5], + [-19.5, 131], + [-21, 306.25], + [35.25, 306.25], + [32.25, 132.25], + [80, 183], + [119.5, 143.75] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.0431, 0.4824, 1], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 1 + }, + { + "ty": 4, + "nm": "Shape Layer 3", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { "a": 0, "k": [-52.423, 53.888, 100], "ix": 6 }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [228, 328, 0], + "t": 0, + "ti": [0, 0, 0], + "to": [4.667, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [256, 328, 0], + "t": 48.519, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [228, 328, 0], + "t": 82.02, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [256, 328, 0], + "t": 123.607, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [228, 328, 0], + "t": 149.023, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [256, 328, 0], + "t": 199.852, + "ti": [4.667, 0, 0], + "to": [0, 0, 0] + }, + { "s": [228, 328, 0], "t": 225.266666666667 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [103, -10], + [6, -11], + [0, 0], + [41, -121], + [-28, -2], + [0, 0], + [46, 138], + [0, 0] + ], + "o": [ + [-103, 10], + [-6, 11], + [0, 0], + [-16, 92], + [27, 0], + [0, 0], + [-20, -59], + [0, 0] + ], + "v": [ + [40, -76], + [-94, 6], + [-107, 27], + [-262, 99], + [-171, 242], + [176, 242], + [263, 80], + [182, 17] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.2314, 0.2392, 0.2588], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 2 + }, + { + "ty": 4, + "nm": "Shape Layer 5", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { "a": 0, "k": [-52.423, 53.888, 100], "ix": 6 }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [228, 368, 0], + "t": 0, + "ti": [0, 0, 0], + "to": [4.667, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [256, 368, 0], + "t": 48.519, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [228, 368, 0], + "t": 82.02, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [256, 368, 0], + "t": 123.607, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [228, 368, 0], + "t": 149.023, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [256, 368, 0], + "t": 199.852, + "ti": [4.667, 0, 0], + "to": [0, 0, 0] + }, + { "s": [228, 368, 0], "t": 225.266666666667 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 3, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [103, -10], + [6, -11], + [0, 0], + [41, -121], + [-28, -2], + [0, 0], + [46, 138], + [0, 0] + ], + "o": [ + [-103, 10], + [-6, 11], + [0, 0], + [-16, 92], + [27, 0], + [0, 0], + [-20, -59], + [0, 0] + ], + "v": [ + [40, -76], + [-94, 6], + [-107, 27], + [-262, 99], + [-171, 242], + [176, 242], + [263, 80], + [182, 17] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0, 0, 0], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 3 + }, + { + "ty": 4, + "nm": "Shape Layer 1", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 0 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 27.9 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [89, 89, 100], + "t": 31 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 36.167 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 100.233 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [89, 89, 100], + "t": 103.333 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 108.5 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 178.767 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [89, 89, 100], + "t": 181.867 + }, + { "s": [100, 100, 100], "t": 187.033333333333 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [500, 500, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [103, -10], + [6, -11], + [0, 0], + [41, -121], + [-28, -2], + [0, 0], + [46, 138], + [0, 0] + ], + "o": [ + [-103, 10], + [-6, 11], + [0, 0], + [-16, 92], + [27, 0], + [0, 0], + [-20, -59], + [0, 0] + ], + "v": [ + [40, -76], + [-94, 6], + [-107, 27], + [-262, 99], + [-171, 242], + [176, 242], + [263, 80], + [182, 17] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.2314, 0.2392, 0.2588], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 4 + }, + { + "ty": 4, + "nm": "Shape Layer 6", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 0 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 27.9 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [89, 89, 100], + "t": 31 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 36.167 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 100.233 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [89, 89, 100], + "t": 103.333 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 108.5 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [100, 100, 100], + "t": 178.767 + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [89, 89, 100], + "t": 181.867 + }, + { "s": [100, 100, 100], "t": 187.033333333333 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [500, 544, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 3, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [103, -10], + [6, -11], + [0, 0], + [41, -121], + [-28, -2], + [0, 0], + [46, 138], + [0, 0] + ], + "o": [ + [-103, 10], + [-6, 11], + [0, 0], + [-16, 92], + [27, 0], + [0, 0], + [-20, -59], + [0, 0] + ], + "v": [ + [40, -76], + [-94, 6], + [-107, 27], + [-262, 99], + [-171, 242], + [176, 242], + [263, 80], + [182, 17] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0, 0, 0], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 5 + }, + { + "ty": 4, + "nm": "Shape Layer 2", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [530, 494, 0], + "t": 0, + "ti": [0, 0, 0], + "to": [-5.333, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [498, 494, 0], + "t": 48.519, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [530, 494, 0], + "t": 82.02, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [498, 494, 0], + "t": 123.607, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [530, 494, 0], + "t": 149.023, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [498, 494, 0], + "t": 199.852, + "ti": [-5.333, 0, 0], + "to": [0, 0, 0] + }, + { "s": [530, 494, 0], "t": 225.266666666667 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 100, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 2", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": false, + "i": [[0, 0]], + "o": [[0, 0]], + "v": [[588, 97]] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.5686, 0.5882, 0.6549], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 2, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [146, -1], + [33, -77], + [9.492, -75.94], + [-58, -16], + [0, 0], + [0, 0], + [-13, 78], + [141, 6], + [0, 0] + ], + "o": [ + [-90, -2], + [-33, -2], + [-9, 72], + [1, 0], + [0, 0], + [0, 0], + [13, -78], + [-15, 2], + [0, 0] + ], + "v": [ + [39, -245], + [-155, -122], + [-261, -10], + [-172, 139], + [129, 139], + [280, 139], + [410, 36], + [241, -138], + [209, -130] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.5686, 0.5882, 0.6549], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 6 + }, + { + "ty": 4, + "nm": "Shape Layer 7", + "sr": 1, + "st": 0, + "op": 713, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [0, 0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [530, 554, 0], + "t": 0, + "ti": [0, 0, 0], + "to": [-5.333, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [498, 554, 0], + "t": 48.519, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [530, 554, 0], + "t": 82.02, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [498, 554, 0], + "t": 123.607, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [530, 554, 0], + "t": 149.023, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.167, "y": 0.167 }, + "i": { "x": 0.833, "y": 0.833 }, + "s": [498, 554, 0], + "t": 199.852, + "ti": [-5.333, 0, 0], + "to": [0, 0, 0] + }, + { "s": [530, 554, 0], "t": 225.266666666667 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { "a": 0, "k": 3, "ix": 11 } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 2", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": false, + "i": [[0, 0]], + "o": [[0, 0]], + "v": [[588, 97]] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0, 0, 0], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Shape 1", + "ix": 2, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [146, -1], + [33, -77], + [9.492, -75.94], + [-58, -16], + [0, 0], + [0, 0], + [-13, 78], + [141, 6], + [0, 0] + ], + "o": [ + [-90, -2], + [-33, -2], + [-9, 72], + [1, 0], + [0, 0], + [0, 0], + [13, -78], + [-15, 2], + [0, 0] + ], + "v": [ + [39, -245], + [-155, -122], + [-261, -10], + [-172, 139], + [129, 139], + [280, 139], + [410, 36], + [241, -138], + [209, -130] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0, 0, 0], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [0, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 7 + } + ] + } + ] +} diff --git a/utils/lottie/index.ts b/utils/lottie/index.ts new file mode 100644 index 0000000..f9d6626 --- /dev/null +++ b/utils/lottie/index.ts @@ -0,0 +1,3 @@ +export { default as startChatingLottie } from "./startChatingLottie.json"; +export { default as verificationSuccessLottie } from "./successLottie.json"; +export { default as failureLottie } from "./failurelottle.json"; diff --git a/utils/lottie/startChatingLottie.json b/utils/lottie/startChatingLottie.json new file mode 100644 index 0000000..cf5c77b --- /dev/null +++ b/utils/lottie/startChatingLottie.json @@ -0,0 +1,1981 @@ +{ + "nm": "loading-messages", + "ddd": 0, + "h": 500, + "w": 500, + "meta": { "g": "@lottiefiles/toolkit-js 0.26.1" }, + "layers": [ + { + "ty": 4, + "nm": "chat Outlines 5", + "sr": 1, + "st": 60, + "op": 84, + "ip": 60, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [161, 341, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0, 0, 100], + "t": 60 + }, + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.833, "y": 1 }, + "s": [-100, 100, 100], + "t": 65 + }, + { + "o": { "x": 0.167, "y": 0 }, + "i": { "x": 0.833, "y": 1 }, + "s": [-100, 100, 100], + "t": 80 + }, + { "s": [0, 0, 100], "t": 83 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { "a": 0, "k": [338.075, 340.9, 0], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [100], + "t": 80 + }, + { "s": [0], "t": 86 } + ], + "ix": 11 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 5", + "ix": 1, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.202, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.202, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [227.125, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 65 + }, + { "s": [100], "t": 70 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 6", + "ix": 2, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 70 + }, + { "s": [100], "t": 75 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 7", + "ix": 3, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [98.425, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [2], + "t": 75 + }, + { "s": [100], "t": 80 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 8", + "ix": 4, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [0, -13.475], + [0, 0], + [13.473, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 13.474], + [0, 0], + [-13.474, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 13.479], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [-13.474, 0], + [0, 0], + [0, -13.48], + [0, 0], + [13.478, 0] + ], + "v": [ + [118.8, -79.551], + [118.8, 25.096], + [94.402, 49.5], + [-9.9, 49.5], + [-59.4, 103.95], + [-59.4, 49.5], + [-94.402, 49.5], + [-118.8, 25.101], + [-118.8, -79.546], + [-94.402, -103.95], + [94.397, -103.95] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.2314, 0.2471, 0.2902], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 341.05], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 1 + }, + { + "ty": 4, + "nm": "chat Outlines 3", + "sr": 1, + "st": 40, + "op": 84, + "ip": 40, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [161, 341, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0, 0, 100], + "t": 40 + }, + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.833, "y": 1 }, + "s": [100, 100, 100], + "t": 45 + }, + { + "o": { "x": 0.167, "y": 0 }, + "i": { "x": 0.833, "y": 1 }, + "s": [100, 100, 100], + "t": 80 + }, + { "s": [0, 0, 100], "t": 83 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [161, 341, 0], + "t": 60, + "ti": [0, 31.5, 0], + "to": [0, -31.5, 0] + }, + { "s": [161, 152, 0], "t": 65 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [100], + "t": 80 + }, + { "s": [0], "t": 86 } + ], + "ix": 11 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 5", + "ix": 1, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.202, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.202, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [227.125, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 55 + }, + { "s": [100], "t": 60 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 6", + "ix": 2, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 50 + }, + { "s": [100], "t": 55 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 7", + "ix": 3, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [98.425, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [2], + "t": 45 + }, + { "s": [100], "t": 50 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 8", + "ix": 4, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [0, -13.475], + [0, 0], + [13.473, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 13.474], + [0, 0], + [-13.474, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 13.479], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [-13.474, 0], + [0, 0], + [0, -13.48], + [0, 0], + [13.478, 0] + ], + "v": [ + [118.8, -79.551], + [118.8, 25.096], + [94.402, 49.5], + [-9.9, 49.5], + [-59.4, 103.95], + [-59.4, 49.5], + [-94.402, 49.5], + [-118.8, 25.101], + [-118.8, -79.546], + [-94.402, -103.95], + [94.397, -103.95] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1686, 0.1843, 0.2157], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 341.05], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 2 + }, + { + "ty": 4, + "nm": "chat Outlines 4", + "sr": 1, + "st": 20, + "op": 84, + "ip": 20, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [161, 341, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0, 0, 100], + "t": 20 + }, + { "s": [-100, 100, 100], "t": 25 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [338.075, 340.9, 0], + "t": 40, + "ti": [0, 31.5, 0], + "to": [0, -31.5, 0] + }, + { + "o": { "x": 0.333, "y": 0.333 }, + "i": { "x": 0.667, "y": 0.667 }, + "s": [338.075, 151.9, 0], + "t": 45, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [338.075, 151.9, 0], + "t": 60, + "ti": [1, 42.333, 0], + "to": [-1, -42.333, 0] + }, + { "s": [332.075, -102.1, 0], "t": 65 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [100], + "t": 59 + }, + { "s": [0], "t": 62 } + ], + "ix": 11 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 5", + "ix": 1, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.202, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.202, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [227.125, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 25 + }, + { "s": [100], "t": 30 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 6", + "ix": 2, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 30 + }, + { "s": [100], "t": 35 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 7", + "ix": 3, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [98.425, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [2], + "t": 35 + }, + { "s": [100], "t": 40 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 8", + "ix": 4, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [0, -13.475], + [0, 0], + [13.473, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 13.474], + [0, 0], + [-13.474, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 13.479], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [-13.474, 0], + [0, 0], + [0, -13.48], + [0, 0], + [13.478, 0] + ], + "v": [ + [118.8, -79.551], + [118.8, 25.096], + [94.402, 49.5], + [-9.9, 49.5], + [-59.4, 103.95], + [-59.4, 49.5], + [-94.402, 49.5], + [-118.8, 25.101], + [-118.8, -79.546], + [-94.402, -103.95], + [94.397, -103.95] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.2314, 0.2471, 0.2902], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 341.05], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 3 + }, + { + "ty": 4, + "nm": "chat Outlines 2", + "sr": 1, + "st": 0, + "op": 84, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [161, 341, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0, 0, 100], + "t": 0 + }, + { "s": [-100, 100, 100], "t": 5 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [332.075, 151.9, 0], + "t": 20, + "ti": [0, 43.167, 0], + "to": [0, -43.167, 0] + }, + { "s": [332.075, -107.1, 0], "t": 25 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [100], + "t": 18 + }, + { "s": [0], "t": 21 } + ], + "ix": 11 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 5", + "ix": 1, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.202, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.202, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [227.125, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 5 + }, + { "s": [100], "t": 10 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 6", + "ix": 2, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 10 + }, + { "s": [100], "t": 15 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 7", + "ix": 3, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [98.425, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [2], + "t": 15 + }, + { "s": [100], "t": 20 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 8", + "ix": 4, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [0, -13.475], + [0, 0], + [13.473, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 13.474], + [0, 0], + [-13.474, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 13.479], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [-13.474, 0], + [0, 0], + [0, -13.48], + [0, 0], + [13.478, 0] + ], + "v": [ + [118.8, -79.551], + [118.8, 25.096], + [94.402, 49.5], + [-9.9, 49.5], + [-59.4, 103.95], + [-59.4, 49.5], + [-94.402, 49.5], + [-118.8, 25.101], + [-118.8, -79.546], + [-94.402, -103.95], + [94.397, -103.95] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.2314, 0.2471, 0.2902], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 341.05], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 4 + }, + { + "ty": 4, + "nm": "chat Outlines", + "sr": 1, + "st": 0, + "op": 84, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { "a": 0, "k": [161, 341, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0, 0, 100], + "t": 0 + }, + { "s": [100, 100, 100], "t": 5 } + ], + "ix": 6 + }, + "sk": { "a": 0, "k": 0 }, + "p": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [161, 341, 0], + "t": 20, + "ti": [0, 31.5, 0], + "to": [0, -31.5, 0] + }, + { + "o": { "x": 0.333, "y": 0.333 }, + "i": { "x": 0.667, "y": 0.667 }, + "s": [161, 152, 0], + "t": 25, + "ti": [0, 0, 0], + "to": [0, 0, 0] + }, + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [161, 152, 0], + "t": 40, + "ti": [0, 31.833, 0], + "to": [0, -31.833, 0] + }, + { "s": [161, -39, 0], "t": 45 } + ], + "ix": 2 + }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "sa": { "a": 0, "k": 0 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [100], + "t": 39 + }, + { "s": [0], "t": 42 } + ], + "ix": 11 + } + }, + "ef": [], + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 5", + "ix": 1, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.202, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.202, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [227.125, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 15 + }, + { "s": [100], "t": 20 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 6", + "ix": 2, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [0], + "t": 10 + }, + { "s": [100], "t": 15 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 7", + "ix": 3, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [-8.201, 0], + [0, -8.202], + [8.202, 0], + [0, 8.201] + ], + "o": [ + [8.202, 0], + [0, 8.201], + [-8.201, 0], + [0, -8.202] + ], + "v": [ + [0, -14.85], + [14.85, 0], + [0, 14.85], + [-14.85, 0] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1098, 0.1137, 0.1255], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [98.425, 316.3], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { + "a": 1, + "k": [ + { + "o": { "x": 0.333, "y": 0 }, + "i": { "x": 0.667, "y": 1 }, + "s": [2], + "t": 5 + }, + { "s": [100], "t": 10 } + ], + "ix": 7 + } + } + ] + }, + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Group 8", + "ix": 4, + "cix": 2, + "np": 2, + "it": [ + { + "ty": "sh", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Group", + "nm": "Path 1", + "ix": 1, + "d": 1, + "ks": { + "a": 0, + "k": { + "c": true, + "i": [ + [0, -13.475], + [0, 0], + [13.473, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 13.474], + [0, 0], + [-13.474, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 13.479], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [-13.474, 0], + [0, 0], + [0, -13.48], + [0, 0], + [13.478, 0] + ], + "v": [ + [118.8, -79.551], + [118.8, 25.096], + [94.402, 49.5], + [-9.9, 49.5], + [-59.4, 103.95], + [-59.4, 49.5], + [-94.402, 49.5], + [-118.8, 25.101], + [-118.8, -79.546], + [-94.402, -103.95], + [94.397, -103.95] + ] + }, + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { "a": 0, "k": [0.1686, 0.1843, 0.2157], "ix": 4 }, + "r": 1, + "o": { "a": 0, "k": 100, "ix": 5 } + }, + { + "ty": "tr", + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "p": { "a": 0, "k": [162.775, 341.05], "ix": 2 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "o": { "a": 0, "k": 100, "ix": 7 } + } + ] + } + ], + "ind": 5 + } + ], + "v": "5.5.5", + "fr": 25, + "op": 84, + "ip": 0, + "assets": [] +} diff --git a/utils/lottie/successLottie.json b/utils/lottie/successLottie.json new file mode 100644 index 0000000..5ee9da6 --- /dev/null +++ b/utils/lottie/successLottie.json @@ -0,0 +1 @@ +{"nm":"success","ddd":0,"h":600,"w":600,"meta":{"g":"@lottiefiles/toolkit-js 0.26.1"},"layers":[{"ty":4,"nm":"Shape Layer 2","sr":1,"st":25,"op":50,"ip":25,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[300,300,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[367.859,367.859],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.829,"y":0},"i":{"x":0.333,"y":1},"s":[0],"t":25},{"s":[100],"t":39}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":25},{"o":{"x":0.655,"y":0},"i":{"x":0.089,"y":1},"s":[0],"t":36},{"s":[100],"t":50}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1.93,-10.07],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":25,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[300,300,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[367.859,367.859],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.829,"y":0},"i":{"x":0.333,"y":1},"s":[0],"t":0},{"s":[100],"t":14}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":0},{"o":{"x":0.655,"y":0},"i":{"x":0.089,"y":1},"s":[0],"t":11},{"s":[100],"t":25}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1.93,-10.07],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":0,"nm":"Pre-comp 1","sr":1,"st":54,"op":354,"ip":54,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[300,300,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[86,86,100],"t":54},{"s":[94,94,100],"t":62}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[300,300,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":54},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":56},{"s":[100],"t":62}],"ix":11}},"ef":[],"w":600,"h":600,"refId":"comp_0","ind":3},{"ty":4,"nm":"Layer 2 Outlines","sr":1,"st":54,"op":354,"ip":54,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[137.378,109.309,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[300,300,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-84.878,0.669],[-28.738,56.809],[84.878,-56.809]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":21,"ix":5},"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[137.378,109.308],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.35,"y":1},"s":[0],"t":54},{"o":{"x":0.333,"y":0},"i":{"x":0.032,"y":1},"s":[100],"t":62},{"s":[94],"t":66}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.185,"y":1},"s":[0],"t":59},{"o":{"x":0.333,"y":0},"i":{"x":0.306,"y":1},"s":[6],"t":62},{"s":[0],"t":66}],"ix":1},"m":1}],"ind":4},{"ty":4,"nm":"Layer 1 Outlines","sr":1,"st":50,"op":350,"ip":50,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[190.878,189.014,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.046,"y":1},"s":[0,0,100],"t":50},{"o":{"x":0.333,"y":0.032},"i":{"x":0.019,"y":1},"s":[116,116,100],"t":61},{"s":[100,100,100],"t":67}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[299.988,299.91,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-4.067,-3.573],[0,0],[-2.665,-0.588],[0,0],[-1.937,-5.043],[0,0],[-2.087,-1.753],[0,0],[0.635,-5.357],[0,0],[-1.033,-2.517],[0,0],[3.063,-4.444],[0,0],[0.259,-2.704],[0,0],[4.789,-2.513],[0,0],[1.492,-2.273],[0,0],[5.418,-0.007],[0,0],[2.383,-1.32],[0,0],[4.806,2.501],[0,0],[2.727,-0.064],[0,0],[3.093,4.437],[0,0],[2.448,1.205],[0,0],[0.67,5.356],[0,0],[1.607,2.198],[0,0],[-1.904,5.047],[0,0],[0.399,2.689],[0,0],[-4.043,3.583],[0,0],[-0.901,2.564],[0,0],[-5.257,1.298],[0,0],[-1.995,1.85],[0,0],[-5.265,-1.284],[0,0],[-2.632,0.713],[0,0]],"o":[[0,0],[2.049,1.8],[0,0],[5.292,1.166],[0,0],[0.976,2.539],[0,0],[4.146,3.481],[0,0],[-0.32,2.698],[0,0],[2.05,4.998],[0,0],[-1.542,2.239],[0,0],[-0.514,5.372],[0,0],[-2.412,1.266],[0,0],[-2.961,4.512],[0,0],[-2.728,0.003],[0,0],[-4.73,2.62],[0,0],[-2.42,-1.26],[0,0],[-5.416,0.129],[0,0],[-1.557,-2.233],[0,0],[-4.861,-2.393],[0,0],[-0.338,-2.697],[0,0],[-3.192,-4.367],[0,0],[0.959,-2.542],[0,0],[-0.792,-5.339],[0,0],[2.036,-1.805],[0,0],[1.789,-5.09],[0,0],[2.647,-0.653],[0,0],[3.961,-3.674],[0,0],[2.651,0.646],[0,0],[5.226,-1.416]],"v":[[49.728,-183.893],[75.948,-160.861],[83.134,-157.221],[117.251,-149.704],[128.834,-139.758],[141.329,-107.249],[146,-100.704],[172.734,-78.264],[178.36,-64.104],[174.265,-29.568],[175.352,-21.617],[188.578,10.606],[186.957,25.734],[167.211,54.389],[164.465,61.924],[161.152,96.546],[152.657,109.178],[121.785,125.385],[115.833,130.78],[96.742,159.871],[83.317,167.112],[48.39,167.159],[40.598,169.176],[10.101,186.072],[-5.177,186.263],[-36.157,170.138],[-44.005,168.317],[-78.921,169.146],[-92.553,162.244],[-112.489,133.642],[-118.596,128.399],[-149.931,112.972],[-158.793,100.558],[-163.119,66.033],[-166.084,58.567],[-186.661,30.418],[-188.724,15.336],[-176.447,-17.206],[-175.593,-25.182],[-180.697,-59.604],[-175.488,-73.898],[-149.422,-97.001],[-144.943,-103.66],[-133.405,-136.47],[-122.117,-146.703],[-88.233,-155.074],[-81.156,-158.891],[-55.62,-182.572],[-40.839,-186.4],[-6.899,-178.12],[1.156,-178.22],[34.84,-187.349]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[190.878,189.015],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5}],"v":"5.1.7","fr":30,"op":69,"ip":25,"assets":[{"nm":"","id":"comp_0","layers":[{"ty":4,"nm":"Layer 4 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[26.859,26.86,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[115.68,468.673,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-20.859,20.86],[20.859,-20.86]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[26.859,26.86],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100],"t":4},{"s":[0],"t":22}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":1},{"ty":4,"nm":"Layer 5 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[26.86,26.859,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[467.82,115.827,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-20.86,20.859],[20.86,-20.859]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[26.86,26.859],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":4},{"s":[100],"t":22}],"ix":1},"m":1}],"ind":2},{"ty":4,"nm":"Layer 6 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[26.859,26.859,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[115.327,116.18,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-20.859,-20.86],[20.859,20.86]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[26.859,26.86],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100],"t":4},{"s":[0],"t":22}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":3},{"ty":4,"nm":"Layer 7 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[26.86,26.86,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[468.174,468.32,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-20.86,-20.86],[20.86,20.86]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[26.86,26.86],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":4},{"s":[100],"t":22}],"ix":1},"m":1}],"ind":4},{"ty":4,"nm":"Layer 8 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[35.5,6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[42.5,292.5,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6,6],[65,6]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100],"t":4},{"s":[0],"t":22}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":5},{"ty":4,"nm":"Layer 9 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[35.5,6,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[541,292,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6,6],[65,6]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":4},{"s":[100],"t":22}],"ix":1},"m":1}],"ind":6},{"ty":4,"nm":"Layer 10 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[6,35.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[292,541.5,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6,65],[6,6]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[100],"t":4},{"s":[0],"t":22}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":0,"k":0,"ix":1},"m":1}],"ind":7},{"ty":4,"nm":"Layer 11 Outlines","sr":1,"st":0,"op":28,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[6,35.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[291.5,43,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Group 1","ix":1,"cix":2,"np":2,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":false,"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[6,65],[6,6]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":10,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":12,"ix":5},"c":{"a":0,"k":[0.0235,0.4667,0.9098],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":4},{"s":[100],"t":22}],"ix":1},"m":1}],"ind":8}]}]} \ No newline at end of file