diff --git a/apps/web/package.json b/apps/web/package.json index 268f5db53..45376ab00 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -60,6 +60,9 @@ "@stripe/react-stripe-js": "^1.10.0", "@stripe/stripe-js": "^1.35.0", "@tanstack/react-query": "^4.3.9", + "@tiptap/extension-link": "^2.1.11", + "@tiptap/react": "^2.1.11", + "@tiptap/starter-kit": "^2.1.11", "@tremor/react": "^2.0.0", "@types/turndown": "^5.0.1", "@upstash/ratelimit": "^0.4.3", diff --git a/apps/web/pages/[user].tsx b/apps/web/pages/[user].tsx index 16750759c..797684352 100644 --- a/apps/web/pages/[user].tsx +++ b/apps/web/pages/[user].tsx @@ -1,833 +1,378 @@ -import { cva } from "class-variance-authority"; -// import { createCheckoutSession } from "lib/stripe"; -import { useAuthContext } from "context/authContext"; -import { getProfile } from "lib/firebase/utils"; -import { NextSeo } from "next-seo"; +import type { DehydratedState } from "@tanstack/react-query"; +import classNames from "classnames"; +import type { GetServerSideProps, InferGetServerSidePropsType } from "next"; import Link from "next/link"; -import { CalendarPlus } from "react-bootstrap-icons"; -import { titleCase } from "title-case"; - -import { Button, Tooltip } from "@calcom/ui"; +import { Toaster } from "react-hot-toast"; +import type { z } from "zod"; + +import { + sdkActionManager, + useEmbedNonStylesConfig, + useEmbedStyles, + useIsEmbed, +} from "@calcom/embed-core/embed-iframe"; +import OrganizationAvatar from "@calcom/features/ee/organizations/components/OrganizationAvatar"; +import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains"; +import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; +import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components"; +import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage"; +import { getUsernameList } from "@calcom/lib/defaultEvents"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; +import useTheme from "@calcom/lib/hooks/useTheme"; +import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML"; +import { stripMarkdown } from "@calcom/lib/stripMarkdown"; +import prisma from "@calcom/prisma"; +import type { EventType, User } from "@calcom/prisma/client"; +import { baseEventTypeSelect } from "@calcom/prisma/selects"; +import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; +import { HeadSeo, UnpublishedEntity } from "@calcom/ui"; +import { Verified, ArrowRight } from "@calcom/ui/components/icon"; + +import type { EmbedProps } from "@lib/withEmbedSsr"; import PageWrapper from "@components/PageWrapper"; -import insertNonBreakingSpaces from "./ui/utilities/insert-non-breaking-spaces"; -import BioLink from "./ui/valery/bio-link"; -import BookItem from "./ui/valery/book-item"; -import CirclesBackground from "./ui/valery/circles-background"; -import ExperienceItem from "./ui/valery/experience-item"; -import FactItem from "./ui/valery/fact-item"; -import PodcastItem from "./ui/valery/podcast-item"; -import ProjectItem from "./ui/valery/project-item"; -import Publication from "./ui/valery/publication-item"; -import VideoItem from "./ui/valery/video-item"; - -const Section = ({ title, tileLayout = false, children }) => { - const childrenLayoutClasses = cva([], { - variants: { - tileLayout: { - true: ["sm:columns-2", "gap-14"], - false: ["flex", "flex-col", "gap-7"], - }, - }, - }); - return ( -
-

{title}

-
{children}
-
- ); -}; - -// Two-part links section. -// Top: Links to social media, etc. (Icon-only.) -// Bottom: Generic links -const LinksSection = ({ links }) => { - const iconLinks = links?.filter( - ({ type, url }) => type !== "generic_link" && type !== "website" && url !== "" - ); - const genericLinks = links?.filter( - ({ type, url }) => type === "generic_link" || (type === "website" && url !== "") - ); - - // Two-part variant - // return ( - //
- // {/* Icon links */} - //
- // {iconLinks.map(({ key, url, name }, index) => ( - // - // ))} - //
- // {/* Generic links */} - //
- // {genericLinks.map(({ key, url, name }, index) => ( - // - // ))} - //
- //
- // ); +import { ssrInit } from "@server/lib/ssr"; + +export function UserPage(props: InferGetServerSidePropsType) { + const { users, profile, eventTypes, markdownStrippedBio, entity } = props; + + const [user] = users; //To be used when we only have a single user, not dynamic group + useTheme(profile.theme); + const { t } = useLocale(); + + const isBioEmpty = !user.bio || !user.bio.replace("


", "").length; + + const isEmbed = useIsEmbed(props.isEmbed); + const eventTypeListItemEmbedStyles = useEmbedStyles("eventTypeListItem"); + const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left"; + const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed; + const { + // So it doesn't display in the Link (and make tests fail) + user: _user, + orgSlug: _orgSlug, + ...query + } = useRouterQuery(); + + /* + const telemetry = useTelemetry(); + useEffect(() => { + if (top !== window) { + //page_view will be collected automatically by _middleware.ts + telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/[user]")); + } + }, [telemetry, router.asPath]); */ - // One-part variant - return ( -
-
- {iconLinks.map(({ type, url, name }, index) => ( - - ))} - {genericLinks.map(({ type, url, name }, index) => ( - - ))} + if (entity?.isUnpublished) { + return ( +
+
-
- ); -}; - -const ProfilePage = ({ profileData }) => { - const { user } = useAuthContext(); - console.log({ profileData }); - - const userPhoto = () => { - if (profileData.avatar_url) return profileData.avatar_url; - if (profileData.name) return `https://api.dicebear.com/6.x/initials/svg?seed=${profileData.name}`; - return `https://api.dicebear.com/7.x/shapes/svg?seed=${profileData.uid}`; - }; - - const userPlainTextBio = - profileData?.bio?.content?.length && profileData?.bio?.content[0]?.content - ? profileData.bio.content[0].content.map((item) => item?.text ?? "").join("") - : ""; - - const isLoggedInUser = profileData?.uid === user?.uid; + ); + } + const isEventListEmpty = eventTypes.length === 0; return ( -
- {/* Profile header */} - + - {/* {process.env.NODE_ENV === "production" ? "" :
} */} -
- {/* Top */} -
- {profileData?.name} -
-
- {profileData?.name} -
- {profileData?.role && ( -
- {titleCase(profileData?.role)} -
- )} - {profileData?.company && ( -
-
at
-
{insertNonBreakingSpaces(profileData?.company)}
-
+ +
+
+
+ +

+ {profile.name} + {user.verified && ( + + )} +

+ {!isBioEmpty && ( + <> +
+ )}
- {/* Button block */} +
- {user?.uid ? ( - // - + className={classNames("rounded-md ", !isEventListEmpty && "border-subtle border")} + data-testid="event-types"> + {user.away ? ( +
+
+

😴{" " + t("user_away")}

+

{t("user_away_description") as string}

+
+
) : ( - //
- + eventTypes.map((type) => ( +
+ + {/* Don't prefetch till the time we drop the amount of javascript in [user][type] page which is impacting score for [user] page */} +
+ { + sdkActionManager?.fire("eventTypeSelected", { + eventType: type, + }); + }} + data-testid="event-type-link"> +
+

{type.title}

+
+ + +
+
+ )) )} - -
${profileData?.call_charges}/hr
-
- {/* Links */} - {profileData.links?.length > 0 && } - -
- {isLoggedInUser ? ( - - ) : ( - "" - )} - {user?.email?.includes("hive.one") || user?.email?.includes("bord.id") ? ( -
- -
- ) : ( - "" - )} -
- {/* About */} - {/* {profileData?.bio ? ( - - ) : ( - "" - )} */} -
- {/* Gray section */} -
-
- {/* Facts */} - {profileData?.facts?.length > 0 && ( -
-
- {profileData?.facts.map(({ title, description, url }, index) => ( - - ))} -
-
- )} - {/* Advise on */} - {profileData?.advice_on?.length ? ( -
-
- {profileData?.advice_on?.map((title) => ( - 50} - text={
{title}
} - key={title}> -
- {title?.slice(0, 50)} - {title?.length > 50 ? "..." : ""} -
-
- ))} -
-
- ) : ( - "" - )} -
-
- -
+ {isEventListEmpty && } + +
- {/* Details */} -
- {profileData?.projects?.length ? ( -
- {profileData?.projects?.map((project, index) => ( - - ))} -
- ) : ( - "" - )} - {profileData?.books?.length ? ( -
-
- {profileData?.books?.map((book, index) => ( - - ))} -
-
- ) : ( - "" - )} - {profileData?.podcast?.episodes?.length && ( -
-
- -
-
- )} - {profileData?.appearances && profileData.appearances.length > 0 && ( -
-
- -
-
- )} - {profileData?.videos?.length ? ( -
-
- {profileData?.videos?.map((video, index) => ( - - ))} -
-
- ) : ( - "" - )} - {profileData?.experience?.length ? ( -
- {profileData?.experience?.map((experience, index) => ( - - ))} -
- ) : ( - "" - )} - {profileData?.publications?.length > 0 && ( -
- {profileData?.publications?.map((publication, index) => ( - - ))} -
- )} -
- {/*
*/} -
+ ); +} + +UserPage.isBookingPage = true; +UserPage.PageWrapper = PageWrapper; + +const getEventTypesWithHiddenFromDB = async (userId: number) => { + return ( + await prisma.eventType.findMany({ + where: { + AND: [ + { + teamId: null, + }, + { + OR: [ + { + userId, + }, + { + users: { + some: { + id: userId, + }, + }, + }, + ], + }, + ], + }, + orderBy: [ + { + position: "desc", + }, + { + id: "asc", + }, + ], + select: { + ...baseEventTypeSelect, + metadata: true, + }, + }) + ).map((eventType) => ({ + ...eventType, + metadata: EventTypeMetaDataSchema.parse(eventType.metadata), + })); }; -export async function getServerSideProps({ params, res }) { - res.setHeader("Cache-Control", "public, s-maxage=10, stale-while-revalidate=59"); - const profileID = params.user; - console.log("profileID", profileID); - let profileData; +export type UserPageProps = { + trpcState: DehydratedState; + profile: { + name: string; + image: string; + theme: string | null; + brandColor: string; + darkBrandColor: string; + organizationSlug: string | null; + allowSEOIndexing: boolean; + }; + users: Pick[]; + themeBasis: string | null; + markdownStrippedBio: string; + safeBio: string; + entity: { + isUnpublished?: boolean; + orgSlug?: string | null; + name?: string | null; + }; + eventTypes: ({ + descriptionAsSafeHTML: string; + metadata: z.infer; + } & Pick< + EventType, + | "id" + | "title" + | "slug" + | "length" + | "hidden" + | "requiresConfirmation" + | "requiresBookerEmailVerification" + | "price" + | "currency" + | "recurringEvent" + >)[]; +} & EmbedProps; + +export const getServerSideProps: GetServerSideProps = async (context) => { + const ssr = await ssrInit(context); + const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig( + context.req.headers.host ?? "", + context.params?.orgSlug + ); + const usernameList = getUsernameList(context.query.user as string); + const dataFetchStart = Date.now(); + const usersWithoutAvatar = await prisma.user.findMany({ + where: { + username: { + in: usernameList, + }, + organization: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null, + }, + select: { + id: true, + username: true, + email: true, + name: true, + bio: true, + brandColor: true, + darkBrandColor: true, + organizationId: true, + organization: { + select: { + slug: true, + name: true, + }, + }, + theme: true, + away: true, + verified: true, + allowDynamicBooking: true, + allowSEOIndexing: true, + }, + }); - try { - profileData = await getProfile(profileID); - console.log("profileData", profileData); - if (!profileData) { - throw new Error("User not found"); // Throw an error if profileData is empty - } - } catch (e) { - res.statusCode = 404; // Set the status code to 404 + const isDynamicGroup = usersWithoutAvatar.length > 1; + if (isDynamicGroup) { return { - props: { - profileID, - profileData: null, // Set profileData to null + redirect: { + permanent: false, + destination: `/${usernameList.join("+")}/dynamic`, }, + } as { + redirect: { + permanent: false; + destination: string; + }; }; } - return { - props: { - profileID, - profileData: JSON.parse(JSON.stringify(profileData)), - }, - }; -} - -ProfilePage.PageWrapper = PageWrapper; - -export default ProfilePage; - -// import type { DehydratedState } from "@tanstack/react-query"; -// import classNames from "classnames"; -// import type { GetServerSideProps, InferGetServerSidePropsType } from "next"; -// import Link from "next/link"; -// import { Toaster } from "react-hot-toast"; -// import type { z } from "zod"; - -// import { -// sdkActionManager, -// useEmbedNonStylesConfig, -// useEmbedStyles, -// useIsEmbed, -// } from "@calcom/embed-core/embed-iframe"; -// import OrganizationAvatar from "@calcom/features/ee/organizations/components/OrganizationAvatar"; -// import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains"; -// import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; -// import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components"; -// import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage"; -// import { getUsernameList } from "@calcom/lib/defaultEvents"; -// import { useLocale } from "@calcom/lib/hooks/useLocale"; -// import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery"; -// import useTheme from "@calcom/lib/hooks/useTheme"; -// import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML"; -// import { stripMarkdown } from "@calcom/lib/stripMarkdown"; -// import prisma from "@calcom/prisma"; -// import type { EventType, User } from "@calcom/prisma/client"; -// import { baseEventTypeSelect } from "@calcom/prisma/selects"; -// import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; -// import { HeadSeo, UnpublishedEntity } from "@calcom/ui"; -// import { Verified, ArrowRight } from "@calcom/ui/components/icon"; - -// import type { EmbedProps } from "@lib/withEmbedSsr"; - -// import { ssrInit } from "@server/lib/ssr"; - -// export function UserPage(props: InferGetServerSidePropsType) { -// const { users, profile, eventTypes, markdownStrippedBio, entity } = props; - -// const [user] = users; //To be used when we only have a single user, not dynamic group -// useTheme(profile.theme); -// const { t } = useLocale(); - -// const isBioEmpty = !user.bio || !user.bio.replace("


", "").length; - -// const isEmbed = useIsEmbed(props.isEmbed); -// const eventTypeListItemEmbedStyles = useEmbedStyles("eventTypeListItem"); -// const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left"; -// const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed; -// const { -// // So it doesn't display in the Link (and make tests fail) -// user: _user, -// orgSlug: _orgSlug, -// ...query -// } = useRouterQuery(); - -// /* -// const telemetry = useTelemetry(); -// useEffect(() => { -// if (top !== window) { -// //page_view will be collected automatically by _middleware.ts -// telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/[user]")); -// } -// }, [telemetry, router.asPath]); */ - -// if (entity?.isUnpublished) { -// return ( -//
-// -//
-// ); -// } + const users = usersWithoutAvatar.map((user) => ({ + ...user, + avatar: `/${user.username}/avatar.png`, + })); -// const isEventListEmpty = eventTypes.length === 0; -// return ( -// <> -// - -//
-//
-//
-// -//

-// {profile.name} -// {user.verified && ( -// -// )} -//

-// {!isBioEmpty && ( -// <> -//
-// -// )} -//
- -//
-// {user.away ? ( -//
-//
-//

😴{" " + t("user_away")}

-//

{t("user_away_description") as string}

-//
-//
-// ) : ( -// eventTypes.map((type) => ( -//
-// -// {/* Don't prefetch till the time we drop the amount of javascript in [user][type] page which is impacting score for [user] page */} -//
-// { -// sdkActionManager?.fire("eventTypeSelected", { -// eventType: type, -// }); -// }} -// data-testid="event-type-link"> -//
-//

{type.title}

-//
-// -// -//
-//
-// )) -// )} -//
- -// {isEventListEmpty && } -//
-// -//
-// -// ); -// } - -// UserPage.isBookingPage = true; -// UserPage.PageWrapper = PageWrapper; - -// const getEventTypesWithHiddenFromDB = async (userId: number) => { -// return ( -// await prisma.eventType.findMany({ -// where: { -// AND: [ -// { -// teamId: null, -// }, -// { -// OR: [ -// { -// userId, -// }, -// { -// users: { -// some: { -// id: userId, -// }, -// }, -// }, -// ], -// }, -// ], -// }, -// orderBy: [ -// { -// position: "desc", -// }, -// { -// id: "asc", -// }, -// ], -// select: { -// ...baseEventTypeSelect, -// metadata: true, -// }, -// }) -// ).map((eventType) => ({ -// ...eventType, -// metadata: EventTypeMetaDataSchema.parse(eventType.metadata), -// })); -// }; - -// export type UserPageProps = { -// trpcState: DehydratedState; -// profile: { -// name: string; -// image: string; -// theme: string | null; -// brandColor: string; -// darkBrandColor: string; -// organizationSlug: string | null; -// allowSEOIndexing: boolean; -// }; -// users: Pick[]; -// themeBasis: string | null; -// markdownStrippedBio: string; -// safeBio: string; -// entity: { -// isUnpublished?: boolean; -// orgSlug?: string | null; -// name?: string | null; -// }; -// eventTypes: ({ -// descriptionAsSafeHTML: string; -// metadata: z.infer; -// } & Pick< -// EventType, -// | "id" -// | "title" -// | "slug" -// | "length" -// | "hidden" -// | "requiresConfirmation" -// | "requiresBookerEmailVerification" -// | "price" -// | "currency" -// | "recurringEvent" -// >)[]; -// } & EmbedProps; - -// export const getServerSideProps: GetServerSideProps = async (context) => { -// const ssr = await ssrInit(context); -// const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig( -// context.req.headers.host ?? "", -// context.params?.orgSlug -// ); -// const usernameList = getUsernameList(context.query.user as string); -// const dataFetchStart = Date.now(); -// const usersWithoutAvatar = await prisma.user.findMany({ -// where: { -// username: { -// in: usernameList, -// }, -// organization: isValidOrgDomain && currentOrgDomain ? getSlugOrRequestedSlug(currentOrgDomain) : null, -// }, -// select: { -// id: true, -// username: true, -// email: true, -// name: true, -// bio: true, -// brandColor: true, -// darkBrandColor: true, -// organizationId: true, -// organization: { -// select: { -// slug: true, -// name: true, -// }, -// }, -// theme: true, -// away: true, -// verified: true, -// allowDynamicBooking: true, -// allowSEOIndexing: true, -// }, -// }); - -// const isDynamicGroup = usersWithoutAvatar.length > 1; -// if (isDynamicGroup) { -// return { -// redirect: { -// permanent: false, -// destination: `/${usernameList.join("+")}/dynamic`, -// }, -// } as { -// redirect: { -// permanent: false; -// destination: string; -// }; -// }; -// } - -// const users = usersWithoutAvatar.map((user) => ({ -// ...user, -// avatar: `/${user.username}/avatar.png`, -// })); - -// if (!users.length || (!isValidOrgDomain && !users.some((user) => user.organizationId === null))) { -// return { -// notFound: true, -// } as { -// notFound: true; -// }; -// } + if (!users.length || (!isValidOrgDomain && !users.some((user) => user.organizationId === null))) { + return { + notFound: true, + } as { + notFound: true; + }; + } -// const [user] = users; //to be used when dealing with single user, not dynamic group + const [user] = users; //to be used when dealing with single user, not dynamic group -// const profile = { -// name: user.name || user.username || "", -// image: user.avatar, -// theme: user.theme, -// brandColor: user.brandColor, -// darkBrandColor: user.darkBrandColor, -// organizationSlug: user.organization?.slug ?? null, -// allowSEOIndexing: user.allowSEOIndexing ?? true, -// }; + const profile = { + name: user.name || user.username || "", + image: user.avatar, + theme: user.theme, + brandColor: user.brandColor, + darkBrandColor: user.darkBrandColor, + organizationSlug: user.organization?.slug ?? null, + allowSEOIndexing: user.allowSEOIndexing ?? true, + }; -// const eventTypesWithHidden = await getEventTypesWithHiddenFromDB(user.id); -// const dataFetchEnd = Date.now(); -// if (context.query.log === "1") { -// context.res.setHeader("X-Data-Fetch-Time", `${dataFetchEnd - dataFetchStart}ms`); -// } -// const eventTypesRaw = eventTypesWithHidden.filter((evt) => !evt.hidden); + const eventTypesWithHidden = await getEventTypesWithHiddenFromDB(user.id); + const dataFetchEnd = Date.now(); + if (context.query.log === "1") { + context.res.setHeader("X-Data-Fetch-Time", `${dataFetchEnd - dataFetchStart}ms`); + } + const eventTypesRaw = eventTypesWithHidden.filter((evt) => !evt.hidden); -// const eventTypes = eventTypesRaw.map((eventType) => ({ -// ...eventType, -// metadata: EventTypeMetaDataSchema.parse(eventType.metadata || {}), -// descriptionAsSafeHTML: markdownToSafeHTML(eventType.description), -// })); + const eventTypes = eventTypesRaw.map((eventType) => ({ + ...eventType, + metadata: EventTypeMetaDataSchema.parse(eventType.metadata || {}), + descriptionAsSafeHTML: markdownToSafeHTML(eventType.description), + })); -// const safeBio = markdownToSafeHTML(user.bio) || ""; + const safeBio = markdownToSafeHTML(user.bio) || ""; -// const markdownStrippedBio = stripMarkdown(user?.bio || ""); -// const org = usersWithoutAvatar[0].organization; + const markdownStrippedBio = stripMarkdown(user?.bio || ""); + const org = usersWithoutAvatar[0].organization; -// return { -// props: { -// users: users.map((user) => ({ -// name: user.name, -// username: user.username, -// bio: user.bio, -// away: user.away, -// verified: user.verified, -// })), -// entity: { -// isUnpublished: org?.slug === null, -// orgSlug: currentOrgDomain, -// name: org?.name ?? null, -// }, -// eventTypes, -// safeBio, -// profile, -// // Dynamic group has no theme preference right now. It uses system theme. -// themeBasis: user.username, -// trpcState: ssr.dehydrate(), -// markdownStrippedBio, -// }, -// }; -// }; + return { + props: { + users: users.map((user) => ({ + name: user.name, + username: user.username, + bio: user.bio, + away: user.away, + verified: user.verified, + })), + entity: { + isUnpublished: org?.slug === null, + orgSlug: currentOrgDomain, + name: org?.name ?? null, + }, + eventTypes, + safeBio, + profile, + // Dynamic group has no theme preference right now. It uses system theme. + themeBasis: user.username, + trpcState: ssr.dehydrate(), + markdownStrippedBio, + }, + }; +}; -// export default UserPage; +export default UserPage; diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index b93ca8281..16c1cef90 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -1,4 +1,4 @@ -import { AuthContextProvider } from "context/AuthContext"; +import { AuthContextProvider } from "context/authContext"; import React from "react"; import { trpc } from "@calcom/trpc/react"; diff --git a/apps/web/pages/signup.tsx b/apps/web/pages/signup.tsx index e1ba2af3d..776c8ccdf 100644 --- a/apps/web/pages/signup.tsx +++ b/apps/web/pages/signup.tsx @@ -79,14 +79,14 @@ export default function Signup({ prepopulateFormValues, token, orgSlug, orgAutoA const signUp: SubmitHandler = async (data) => { console.info("signup data", data); - const { result, error } = firebaseSignUp(data?.email, data?.password); - if (error) { - if (error.code === "auth/email-already-in-use") alert("Email already in use πŸ˜•"); - if (error.code === "auth/weak-password") alert("Password should be at least 6 characters πŸ˜•"); - if (error.code === "auth/invalid-email") alert("Invalid email πŸ˜•"); + const res: any = firebaseSignUp(data?.email, data?.password); + if (res?.error) { + if (res?.error.code === "auth/email-already-in-use") alert("Email already in use πŸ˜•"); + if (res?.error.code === "auth/weak-password") alert("Password should be at least 6 characters πŸ˜•"); + if (res?.error.code === "auth/invalid-email") alert("Invalid email πŸ˜•"); return; } - console.info({ result, error }); + console.info({ res }); await fetch("/api/auth/signup", { body: JSON.stringify({ diff --git a/apps/web/pages/ui/button.js b/apps/web/pages/ui/button.js deleted file mode 100644 index 98f5a4f4e..000000000 --- a/apps/web/pages/ui/button.js +++ /dev/null @@ -1,92 +0,0 @@ -import clsx from "clsx"; -import Link from "next/link"; - -export default function Button(props) { - const { className, prefix, disabled, suffix, children, variant, onClick, as, href, active, target } = props; - - const makeButtonClass = ({ active, disabled } = {}) => { - switch (variant) { - case "link": - return clsx( - `text-gray-600 hover:text-black border-b border-transparent hover:border-gray-600 duration-100`, - disabled ? "" : "", - active ? "" : "" - ); - case "rishi-primary": - return clsx( - `bg-gradient-to-br border-black from-white to-gray-200 text-black flex items-center justify-center rounded-lg px-3 py-1 border border-transparent duration-100 text-sm`, - disabled ? "" : "", - active ? "" : "" - ); - case "primary": - return clsx( - `bg-primary text-[#9e802b] flex items-center justify-center rounded-lg px-3 py-1 border border-primary-dark/50 hover:border-primary-dark duration-100 text-sm`, - disabled ? "" : "", - active ? "" : "" - ); - case "secondary": - return clsx( - `bg-white text-gray-600 flex items-center justify-center rounded-lg px-3 py-1 border border-gray-200 hover:border-gray-400 duration-100 text-sm`, - disabled ? "" : "", - active ? "" : "" - ); - case "invisible": - return clsx( - `text-gray-600 flex items-center justify-center rounded-lg px-3 py-1 hover:text-primary-dark w-full duration-100 text-sm`, - disabled ? "" : "", - active ? "" : "" - ); - case "ternary": - return clsx( - "py-[2.4px] px-3 flex items-center relative rounded-[7px] cursor-pointer", - active - ? "text-black border-gray-300 bg-gray-200/80" - : "text-gray-600 border-transparent hover:text-gray-800 hover:bg-gray-200/50" - ); - default: - return ``; - } - }; - - if (as === "a") { - return ( - - {prefix && prefix} - {children} - {suffix && suffix} - - ); - } - - if (as === "div") { - return ( -
- {prefix && prefix} - {children} - {suffix && suffix} -
- ); - } - - return ( - - ); -} diff --git a/apps/web/pages/ui/container.js b/apps/web/pages/ui/container.js deleted file mode 100644 index 6ab7a0e09..000000000 --- a/apps/web/pages/ui/container.js +++ /dev/null @@ -1,11 +0,0 @@ -import clsx from "clsx"; - -const Container = ({ children, className, width }) => { - return ( -
- {children} -
- ); -}; - -export default Container; diff --git a/apps/web/pages/ui/dialog.js b/apps/web/pages/ui/dialog.js deleted file mode 100644 index a4074c29b..000000000 --- a/apps/web/pages/ui/dialog.js +++ /dev/null @@ -1,35 +0,0 @@ -import { X } from "@phosphor-icons/react"; -import * as RadixDialog from "@radix-ui/react-dialog"; - -const Dialog = ({ trigger, content, title, description, hideClose, ...props }) => ( - - {trigger ?? ""} - - - - {hideClose ? ( - "" - ) : ( - -
- -
-
- )} - {title ? ( - {title} - ) : ( - "" - )} - {description && ( - - {description} - - )} - {content ?? ""} -
-
-
-); - -export default Dialog; diff --git a/apps/web/pages/ui/dropdown.js b/apps/web/pages/ui/dropdown.js deleted file mode 100644 index 0792a6f2c..000000000 --- a/apps/web/pages/ui/dropdown.js +++ /dev/null @@ -1,94 +0,0 @@ -"use client"; - -import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; -import clsx from "clsx"; -import { motion } from "framer-motion"; -import Link from "next/link"; - -const ITEM_CLASS = - "focus:outline-none ring-1 ring-transparent focus:bg-white dark:focus:bg-gray-100 cursor-pointer flex items-center px-2 py-[5px] text-sm hover:bg-white hover:shadow-[0_1px_2px_rgba(0,0,0,0.15)] focus:shadow-[0_1px_3px_rgba(0,0,0,0.15)] dark:focus:shadow-[0_1px_2px_rgba(0,0,0,0.9)] dark:hover:shadow-[0_1px_2px_rgba(0,0,0,0.9)] dark:hover:bg-white dark:hover:text-gray-800 dark:text-gray-200 dark:focus:text-gray-800 rounded-lg mb-[2px]"; - -const RenderItem = ({ item }) => { - switch (item?.as) { - case "divider": - return
; - case "a": - return ( - - - {item?.icon ? {item?.icon} : ""} - {item?.title} - - - ); - default: - return ( - -
- {item?.icon ? {item?.icon} : ""} - {item?.title} -
-
- ); - } -}; - -const Dropdown = ({ trigger, side, align, items } = {}) => { - return ( - - -
{trigger}
-
- - - - - <> -
- - {items?.map((item, index) => - item?.hide ? "" : - )} - - - - - - ); -}; - -export default Dropdown; diff --git a/apps/web/pages/ui/fayaz/Button.js b/apps/web/pages/ui/fayaz/Button.js deleted file mode 100644 index b0cde839f..000000000 --- a/apps/web/pages/ui/fayaz/Button.js +++ /dev/null @@ -1,42 +0,0 @@ -import clsx from "clsx"; -import React from "react"; - -const Button = ({ label, icon, size, loading, color = "primary", className, ...props }) => { - return ( - - ); -}; - -export default Button; diff --git a/apps/web/pages/ui/fayaz/PhotoUpload.js b/apps/web/pages/ui/fayaz/PhotoUpload.js deleted file mode 100644 index 24fd17418..000000000 --- a/apps/web/pages/ui/fayaz/PhotoUpload.js +++ /dev/null @@ -1,57 +0,0 @@ -import { useState, useEffect } from "react"; -import { UserCircle } from "ui/icons/user"; - -const PhotoUpload = (props) => { - useEffect(() => { - if (props.avatarUrl) { - setImageUrl(props.avatarUrl); - } - }, [props.avatarUrl]); - - const [imageUrl, setImageUrl] = useState(null); - - async function handleFileChange(event) { - const file = event.target.files[0]; - const blobUrl = await generateBlobUrl(file); - setImageUrl(blobUrl); - props.onPhotoChange(file); - } - - function generateBlobUrl(file) { - return new Promise((resolve) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result); - reader.readAsDataURL(file); - }); - } - - return ( -
- -
- {imageUrl ? ( - uploaded - ) : ( - - - - )} - - -
-
- ); -}; - -export default PhotoUpload; diff --git a/apps/web/pages/ui/fayaz/RemoveButton.js b/apps/web/pages/ui/fayaz/RemoveButton.js deleted file mode 100644 index a2608acd6..000000000 --- a/apps/web/pages/ui/fayaz/RemoveButton.js +++ /dev/null @@ -1,18 +0,0 @@ -import clsx from "clsx"; -import React from "react"; - -const RemoveButton = ({ label, onClick, className }) => { - return ( - - ); -}; - -export default RemoveButton; diff --git a/apps/web/pages/ui/fayaz/RichContentParser.js b/apps/web/pages/ui/fayaz/RichContentParser.js deleted file mode 100644 index 4e595e20f..000000000 --- a/apps/web/pages/ui/fayaz/RichContentParser.js +++ /dev/null @@ -1,15 +0,0 @@ -import Link from "@tiptap/extension-link"; -import { EditorContent, useEditor } from "@tiptap/react"; -import StarterKit from "@tiptap/starter-kit"; -import React from "react"; - -const RichContentParser = ({ content = "" }) => { - const editor = useEditor({ - extensions: [StarterKit, Link.configure()], - editable: false, - content, - }); - return ; -}; - -export default RichContentParser; diff --git a/apps/web/pages/ui/fayaz/Select.js b/apps/web/pages/ui/fayaz/Select.js deleted file mode 100644 index 7cfc84b98..000000000 --- a/apps/web/pages/ui/fayaz/Select.js +++ /dev/null @@ -1,21 +0,0 @@ -export default function Select({ label, id, name, options, defaultValue, ...props }) { - return ( -
- - -
- ); -} diff --git a/apps/web/pages/ui/fayaz/Textarea.js b/apps/web/pages/ui/fayaz/Textarea.js deleted file mode 100644 index 9a18d6638..000000000 --- a/apps/web/pages/ui/fayaz/Textarea.js +++ /dev/null @@ -1,21 +0,0 @@ -const Textarea = ({ id, label, name, helperText, ...props }) => { - return ( - <> - -
-