From 8fc0dfb7634f1b56db932907188370416fa47ff4 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Fri, 13 Jan 2023 13:10:02 +0100 Subject: [PATCH 1/4] booking page: only scroll to bottom on mobile (#6453) * move useMediaQuery into packages * revert logo.tsx --- apps/web/lib/hooks/useMediaQuery.ts | 1 + packages/features/calendars/DatePicker.tsx | 17 +++++++++++------ packages/lib/hooks/useMediaQuery.ts | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 packages/lib/hooks/useMediaQuery.ts diff --git a/apps/web/lib/hooks/useMediaQuery.ts b/apps/web/lib/hooks/useMediaQuery.ts index 9d06c75005..a5512ecb73 100644 --- a/apps/web/lib/hooks/useMediaQuery.ts +++ b/apps/web/lib/hooks/useMediaQuery.ts @@ -1,3 +1,4 @@ +// lets refactor and move this into packages/lib/hooks/ import { useState, useEffect } from "react"; const useMediaQuery = (query: string) => { diff --git a/packages/features/calendars/DatePicker.tsx b/packages/features/calendars/DatePicker.tsx index fd05a13421..58be50d715 100644 --- a/packages/features/calendars/DatePicker.tsx +++ b/packages/features/calendars/DatePicker.tsx @@ -5,6 +5,7 @@ import { useEmbedStyles } from "@calcom/embed-core/embed-iframe"; import classNames from "@calcom/lib/classNames"; import { daysInMonth, yyyymmdd } from "@calcom/lib/date-fns"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import useMediaQuery from "@calcom/lib/hooks/useMediaQuery"; import { weekdayNames } from "@calcom/lib/weekday"; import { Button, Icon, SkeletonText } from "@calcom/ui"; @@ -135,6 +136,9 @@ const Days = ({ const date = browsingDate.set("date", day); days.push(date); } + + const isMobile = useMediaQuery("(max-width: 768px)"); + return ( <> {days.map((day, idx) => ( @@ -153,12 +157,13 @@ const Days = ({ date={day} onClick={() => { props.onChange(day); - setTimeout(() => { - window.scrollTo({ - top: 360, - behavior: "smooth", - }); - }, 500); + isMobile && + setTimeout(() => { + window.scrollTo({ + top: 360, + behavior: "smooth", + }); + }, 500); }} disabled={ (includedDates && !includedDates.includes(yyyymmdd(day))) || diff --git a/packages/lib/hooks/useMediaQuery.ts b/packages/lib/hooks/useMediaQuery.ts new file mode 100644 index 0000000000..9d06c75005 --- /dev/null +++ b/packages/lib/hooks/useMediaQuery.ts @@ -0,0 +1,19 @@ +import { useState, useEffect } from "react"; + +const useMediaQuery = (query: string) => { + const [matches, setMatches] = useState(false); + + useEffect(() => { + const media = window.matchMedia(query); + if (media.matches !== matches) { + setMatches(media.matches); + } + const listener = () => setMatches(media.matches); + window.addEventListener("resize", listener); + return () => window.removeEventListener("resize", listener); + }, [matches, query]); + + return matches; +}; + +export default useMediaQuery; From ce9413e0dd8bcc2c1e7b2b70c41cb93b6949d1cc Mon Sep 17 00:00:00 2001 From: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Fri, 13 Jan 2023 19:42:43 +0530 Subject: [PATCH 2/4] fix: missing empty state in `/apps/installed/web3` (#6377) * refactor: turn enum into const assertion * feat: add web3 to icon list * fix: type * fix: type cast query params and add category list * fix: conditional rendering * feat: add i18n keys * fix: type errors Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../apps/layouts/InstalledAppsLayout.tsx | 6 ++- apps/web/pages/apps/installed/[category].tsx | 40 +++++++++---------- apps/web/public/static/locales/en/common.json | 3 ++ .../app-store/_utils/getInstalledAppPath.ts | 2 +- packages/app-store/utils.ts | 17 ++++---- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/apps/web/components/apps/layouts/InstalledAppsLayout.tsx b/apps/web/components/apps/layouts/InstalledAppsLayout.tsx index 648817f021..d238742831 100644 --- a/apps/web/components/apps/layouts/InstalledAppsLayout.tsx +++ b/apps/web/components/apps/layouts/InstalledAppsLayout.tsx @@ -44,13 +44,15 @@ export default function InstalledAppsLayout({ children, ...rest }: { children: React.ReactNode } & ComponentProps) { + const variant: typeof InstalledAppVariants[number] = "payment"; + const query = trpc.viewer.integrations.useQuery({ - variant: InstalledAppVariants.payment, + variant, onlyInstalled: true, }); let actualTabs = tabs; if (query.data?.items.length === 0) { - actualTabs = tabs.filter((tab) => tab.name !== InstalledAppVariants.payment); + actualTabs = tabs.filter((tab) => tab.name !== variant); } return ( diff --git a/apps/web/pages/apps/installed/[category].tsx b/apps/web/pages/apps/installed/[category].tsx index d0503d4a33..d7468cf327 100644 --- a/apps/web/pages/apps/installed/[category].tsx +++ b/apps/web/pages/apps/installed/[category].tsx @@ -92,8 +92,8 @@ function ConnectOrDisconnectIntegrationButton(props: { } interface IntegrationsContainerProps { - variant?: keyof typeof InstalledAppVariants; - exclude?: (keyof typeof InstalledAppVariants)[]; + variant?: typeof InstalledAppVariants[number]; + exclude?: typeof InstalledAppVariants[number][]; } interface IntegrationsListProps { @@ -143,8 +143,10 @@ const IntegrationsContainer = ({ variant, exclude }: IntegrationsContainerProps) automation: Icon.FiShare2, analytics: Icon.FiBarChart, payment: Icon.FiCreditCard, + web3: Icon.FiBarChart, other: Icon.FiGrid, }; + return ( ; + export default function InstalledApps() { const { t } = useLocale(); const router = useRouter(); - const category = router.query.category; + const category = router.query.category as querySchemaType["category"]; + const categoryList: querySchemaType["category"][] = [ + "payment", + "conferencing", + "automation", + "analytics", + "web3", + ]; + return ( - {(category === InstalledAppVariants.payment || category === InstalledAppVariants.conferencing) && ( - - )} - {(category === InstalledAppVariants.automation || category === InstalledAppVariants.analytics) && ( - - )} - {category === InstalledAppVariants.calendar && } - {category === InstalledAppVariants.other && ( - + {categoryList.includes(category) && } + {category === "calendar" && } + {category === "other" && ( + )} ); diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index c9ff08313e..b4ed9b7afd 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -799,12 +799,14 @@ "no_category_apps_description_analytics": "Add an analytics app for your booking pages", "no_category_apps_description_automation": "Add an automation app to use", "no_category_apps_description_other": "Add any other type of app to do all sorts of things", + "no_category_apps_description_web3": "Add a web3 app for your booking pages", "installed_app_calendar_description": "Set the calendars to check for conflicts to prevent double bookings.", "installed_app_conferencing_description": "Add your favourite video conferencing apps for your meetings", "installed_app_payment_description": "Configure which payment processing services to use when charging your clients.", "installed_app_analytics_description": "Configure which analytics apps to use for your booking pages", "installed_app_other_description": "All your installed apps from other categories.", "installed_app_automation_description": "Configure which automation apps to use", + "installed_app_web3_description": "Configure which web3 apps to use for your booking pages", "analytics": "Analytics", "empty_installed_apps_headline": "No apps installed", "empty_installed_apps_description": "Apps enable you to enhance your workflow and improve your scheduling life significantly.", @@ -1217,6 +1219,7 @@ "connect_automation_apps": "Connect automation apps", "connect_analytics_apps": "Connect analytics apps", "connect_other_apps": "Connect other apps", + "connect_web3_apps": "Connect web3 apps", "current_step_of_total": "Step {{currentStep}} of {{maxSteps}}", "add_variable": "Add variable", "custom_phone_number": "Custom phone number", diff --git a/packages/app-store/_utils/getInstalledAppPath.ts b/packages/app-store/_utils/getInstalledAppPath.ts index 3d2b70c74f..f6f8fd1511 100644 --- a/packages/app-store/_utils/getInstalledAppPath.ts +++ b/packages/app-store/_utils/getInstalledAppPath.ts @@ -2,7 +2,7 @@ import z from "zod"; import { InstalledAppVariants } from "../utils"; -const variantSchema = z.nativeEnum(InstalledAppVariants); +const variantSchema = z.enum(InstalledAppVariants); export default function getInstalledAppPath( { variant, slug }: { variant?: string; slug?: string }, diff --git a/packages/app-store/utils.ts b/packages/app-store/utils.ts index a5d6fbf5a9..cdef280d0d 100644 --- a/packages/app-store/utils.ts +++ b/packages/app-store/utils.ts @@ -31,14 +31,15 @@ const credentialData = Prisma.validator()({ export type CredentialData = Prisma.CredentialGetPayload; -export enum InstalledAppVariants { - "conferencing" = "conferencing", - "calendar" = "calendar", - "payment" = "payment", - "analytics" = "analytics", - "automation" = "automation", - "other" = "other", -} +export const InstalledAppVariants = [ + "conferencing", + "calendar", + "payment", + "analytics", + "automation", + "other", + "web3", +] as const; export const ALL_APPS = Object.values(ALL_APPS_MAP); From a4d6f7da6274935161f23c2069420372e28caa8d Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Fri, 13 Jan 2023 15:29:42 -0300 Subject: [PATCH 3/4] Fixing GCal emailing notif and sequential deleting (#6460) --- packages/app-store/googlecalendar/lib/CalendarService.ts | 2 +- packages/features/bookings/lib/handleCancelBooking.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/app-store/googlecalendar/lib/CalendarService.ts b/packages/app-store/googlecalendar/lib/CalendarService.ts index 9e516b05e3..42c6a7c916 100644 --- a/packages/app-store/googlecalendar/lib/CalendarService.ts +++ b/packages/app-store/googlecalendar/lib/CalendarService.ts @@ -273,7 +273,7 @@ export default class GoogleCalendarService implements Calendar { auth: myGoogleAuth, calendarId: calendarId ? calendarId : defaultCalendarId, eventId: uid, - sendNotifications: true, + sendNotifications: false, sendUpdates: "all", }, function (err: GoogleCalError | null, event) { diff --git a/packages/features/bookings/lib/handleCancelBooking.ts b/packages/features/bookings/lib/handleCancelBooking.ts index 99a41e8769..0f87754973 100644 --- a/packages/features/bookings/lib/handleCancelBooking.ts +++ b/packages/features/bookings/lib/handleCancelBooking.ts @@ -306,15 +306,16 @@ async function handler(req: NextApiRequest & { userId?: number }) { ) { bookingToDelete.user.credentials .filter((credential) => credential.type.endsWith("_calendar")) - .forEach((credential) => { + .forEach(async (credential) => { const calendar = getCalendar(credential); - updatedBookings.forEach((updBooking) => { + for (const updBooking of updatedBookings) { const bookingRef = updBooking.references.find((ref) => ref.type.includes("_calendar")); if (bookingRef) { const { uid, externalCalendarId } = bookingRef; - apiDeletes.push(calendar?.deleteEvent(uid, evt, externalCalendarId) as Promise); + const deletedEvent = await calendar?.deleteEvent(uid, evt, externalCalendarId); + apiDeletes.push(deletedEvent); } - }); + } }); } else { apiDeletes.push(calendar?.deleteEvent(uid, evt, externalCalendarId) as Promise); From f96e909dce93f3b7d933520001542031ce8f4412 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Fri, 13 Jan 2023 13:58:41 -0500 Subject: [PATCH 4/4] Team invites - transform email or username to lower case (#6470) * Fix string * Use current hashPassword * Transform email to lowercase Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/web/pages/api/auth/signup.ts | 2 +- packages/features/ee/teams/components/AddNewTeamMembers.tsx | 4 ++-- packages/trpc/server/routers/viewer/teams.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/pages/api/auth/signup.ts b/apps/web/pages/api/auth/signup.ts index cf8d0b674a..9442f1f707 100644 --- a/apps/web/pages/api/auth/signup.ts +++ b/apps/web/pages/api/auth/signup.ts @@ -1,10 +1,10 @@ import { IdentityProvider } from "@prisma/client"; import { NextApiRequest, NextApiResponse } from "next"; +import { hashPassword } from "@calcom/lib/auth"; import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager"; import prisma from "@calcom/prisma"; -import { hashPassword } from "@lib/auth"; import slugify from "@lib/slugify"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/packages/features/ee/teams/components/AddNewTeamMembers.tsx b/packages/features/ee/teams/components/AddNewTeamMembers.tsx index a5b051d0b5..284a171e11 100644 --- a/packages/features/ee/teams/components/AddNewTeamMembers.tsx +++ b/packages/features/ee/teams/components/AddNewTeamMembers.tsx @@ -5,7 +5,7 @@ import { z } from "zod"; import MemberInvitationModal from "@calcom/features/ee/teams/components/MemberInvitationModal"; import { classNames } from "@calcom/lib"; -import { WEBAPP_URL } from "@calcom/lib/constants"; +import { WEBAPP_URL, APP_NAME } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { RouterOutputs, trpc } from "@calcom/trpc/react"; import { Avatar, Badge, Button, Icon, showToast, SkeletonContainer, SkeletonText } from "@calcom/ui"; @@ -156,7 +156,7 @@ const PendingMemberItem = (props: { member: TeamMember; index: number; teamId: n {member.username ? (

{`${WEBAPP_URL}/${member.username}`}

) : ( -

{t("not_on_cal")}

+

{t("not_on_cal", { appName: APP_NAME })}

)} diff --git a/packages/trpc/server/routers/viewer/teams.tsx b/packages/trpc/server/routers/viewer/teams.tsx index a47200b045..30033a1f5f 100644 --- a/packages/trpc/server/routers/viewer/teams.tsx +++ b/packages/trpc/server/routers/viewer/teams.tsx @@ -251,7 +251,7 @@ export const viewerTeamsRouter = router({ .input( z.object({ teamId: z.number(), - usernameOrEmail: z.string(), + usernameOrEmail: z.string().transform((usernameOrEmail) => usernameOrEmail.toLowerCase()), role: z.nativeEnum(MembershipRole), language: z.string(), sendEmailInvitation: z.boolean(), @@ -321,7 +321,7 @@ export const viewerTeamsRouter = router({ from: ctx.user.name, to: input.usernameOrEmail, teamName: team.name, - joinLink: `${WEBAPP_URL}/signup?token=${token}&callbackUrl=/settings/teams`, + joinLink: `${WEBAPP_URL}/signup?token=${token}&callbackUrl=/teams`, }); } } else {