From da0bdfacae1cf86d9b36a101c4df98607317be71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 13 Dec 2022 05:43:37 -0700 Subject: [PATCH 01/31] Handle membership updates in Stripe (#5992) --- packages/features/ee/teams/lib/payments.ts | 50 +++++++++++++++---- packages/trpc/server/routers/viewer/teams.tsx | 18 ++----- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/packages/features/ee/teams/lib/payments.ts b/packages/features/ee/teams/lib/payments.ts index 2df29ff18e..ec09284257 100644 --- a/packages/features/ee/teams/lib/payments.ts +++ b/packages/features/ee/teams/lib/payments.ts @@ -1,9 +1,17 @@ +import { z } from "zod"; + import { getStripeCustomerIdFromUserId } from "@calcom/app-store/stripepayment/lib/customer"; import stripe from "@calcom/app-store/stripepayment/lib/server"; import { WEBAPP_URL } from "@calcom/lib/constants"; import prisma from "@calcom/prisma"; import { teamMetadataSchema } from "@calcom/prisma/zod-utils"; +const teamPaymentMetadataSchema = z.object({ + paymentId: z.string(), + subscriptionId: z.string(), + subscriptionItemId: z.string(), +}); + /** Used to prevent double charges for the same team */ export const checkIfTeamPaymentRequired = async ({ teamId = -1 }) => { const team = await prisma.team.findUniqueOrThrow({ @@ -56,21 +64,43 @@ export const purchaseTeamSubscription = async (input: { teamId: number; seats: n return { url: session.url }; }; +const getTeamWithPaymentMetadata = async (teamId: number) => { + const team = await prisma.team.findUniqueOrThrow({ + where: { id: teamId }, + select: { metadata: true, members: true }, + }); + const metadata = teamPaymentMetadataSchema.parse(team.metadata); + return { ...team, metadata }; +}; + export const cancelTeamSubscriptionFromStripe = async (teamId: number) => { try { - const team = await prisma.team.findUniqueOrThrow({ - where: { id: teamId }, - select: { metadata: true }, - }); - const metadata = teamMetadataSchema.parse(team.metadata); - if (!metadata?.subscriptionId) - throw Error( - `Couldn't cancelTeamSubscriptionFromStripe, Team id: ${teamId} didn't have a subscriptionId` - ); - return await stripe.subscriptions.cancel(metadata.subscriptionId); + const team = await getTeamWithPaymentMetadata(teamId); + const { subscriptionId } = team.metadata; + return await stripe.subscriptions.cancel(subscriptionId); } catch (error) { let message = "Unknown error on cancelTeamSubscriptionFromStripe"; if (error instanceof Error) message = error.message; console.error(message); } }; + +export const updateQuantitySubscriptionFromStripe = async (teamId: number) => { + try { + const { url } = await checkIfTeamPaymentRequired({ teamId }); + /** + * If there's no pending checkout URL it means that this team has not been paid. + * We cannot update the subscription yet, this will be handled on publish/checkout. + **/ + if (!url) return; + const team = await getTeamWithPaymentMetadata(teamId); + const { subscriptionId, subscriptionItemId } = team.metadata; + await stripe.subscriptions.update(subscriptionId, { + items: [{ quantity: team.members.length, id: subscriptionItemId }], + }); + } catch (error) { + let message = "Unknown error on updateQuantitySubscriptionFromStripe"; + if (error instanceof Error) message = error.message; + console.error(message); + } +}; diff --git a/packages/trpc/server/routers/viewer/teams.tsx b/packages/trpc/server/routers/viewer/teams.tsx index 2242798c68..81be573198 100644 --- a/packages/trpc/server/routers/viewer/teams.tsx +++ b/packages/trpc/server/routers/viewer/teams.tsx @@ -8,8 +8,9 @@ import { sendTeamInviteEmail } from "@calcom/emails"; import { cancelTeamSubscriptionFromStripe, purchaseTeamSubscription, + updateQuantitySubscriptionFromStripe, } from "@calcom/features/ee/teams/lib/payments"; -import { HOSTED_CAL_FEATURES, IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants"; +import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants"; import { getTranslation } from "@calcom/lib/server/i18n"; import { getTeamWithMembers, isTeamAdmin, isTeamMember, isTeamOwner } from "@calcom/lib/server/queries/teams"; import slugify from "@calcom/lib/slugify"; @@ -242,8 +243,7 @@ export const viewerTeamsRouter = router({ // Sync Services closeComDeleteTeamMembership(membership.user); - // @TODO: Update with new logic - // if (HOSTED_CAL_FEATURES) await removeSeat(ctx.user.id, input.teamId, input.memberId); + if (IS_TEAM_BILLING_ENABLED) await updateQuantitySubscriptionFromStripe(input.teamId); }), inviteMember: authedProcedure .input( @@ -354,13 +354,7 @@ export const viewerTeamsRouter = router({ }); } } - - // @TODO: Update with new logic - // try { - // if (HOSTED_CAL_FEATURES) await addSeat(ctx.user.id, team.id, inviteeUserId); - // } catch (e) { - // console.log(e); - // } + if (IS_TEAM_BILLING_ENABLED) await updateQuantitySubscriptionFromStripe(input.teamId); }), acceptOrLeave: authedProcedure .input( @@ -392,10 +386,6 @@ export const viewerTeamsRouter = router({ include: { team: true }, }); - // TODO: disable if not hosted by Cal - // @TODO: Update with new logic - // if (teamOwner) await removeSeat(teamOwner.userId, input.teamId, ctx.user.id); - const membership = await ctx.prisma.membership.delete({ where: { userId_teamId: { userId: ctx.user.id, teamId: input.teamId }, From 98a4684a2b8608d1db3f9289ef4d933a92a598a3 Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Tue, 13 Dec 2022 10:25:30 -0300 Subject: [PATCH 02/31] Impl (#5993) Co-authored-by: Peer Richelsen Co-authored-by: Bailey Pumfleet --- apps/web/pages/api/email.ts | 22 +- apps/web/public/emails/teamCircle@2x.png | Bin 0 -> 2468 bytes apps/web/public/static/locales/en/common.json | 5 +- .../emails/src/components/V2BaseEmailHtml.tsx | 191 ++++++++++++++++++ packages/emails/src/components/index.ts | 1 + .../emails/src/templates/TeamInviteEmail.tsx | 44 +++- 6 files changed, 234 insertions(+), 29 deletions(-) create mode 100644 apps/web/public/emails/teamCircle@2x.png create mode 100644 packages/emails/src/components/V2BaseEmailHtml.tsx diff --git a/apps/web/pages/api/email.ts b/apps/web/pages/api/email.ts index 04c25824a0..950cbbfb75 100644 --- a/apps/web/pages/api/email.ts +++ b/apps/web/pages/api/email.ts @@ -32,18 +32,6 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { timeZone: "America/Chihuahua", language, }, - { - email: "pro@example.com", - name: "pro@example.com", - timeZone: "America/Chihuahua", - language, - }, - { - email: "pro@example.com", - name: "pro@example.com", - timeZone: "America/Chihuahua", - language, - }, ], location: "Zoom video", destinationCalendar: null, @@ -60,10 +48,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { res.setHeader("Content-Type", "text/html"); res.setHeader("Cache-Control", "no-cache, no-store, private, must-revalidate"); res.write( - renderEmail("DisabledAppEmail", { - appName: "Stripe", - appType: ["payment"], - t, + renderEmail("TeamInviteEmail", { + language: t, + from: "From", + to: "To", + teamName: "Team name", + joinLink: "Join link", }) ); res.end(); diff --git a/apps/web/public/emails/teamCircle@2x.png b/apps/web/public/emails/teamCircle@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1e65560d2cc7087fb338acf068039070e8f767ee GIT binary patch literal 2468 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 ihWl;p@_t$b?&N19grwO|NM3>f0000 ( + <> + + {props.children} + +); + +export const V2BaseEmailHtml = (props: { + children: React.ReactNode; + callToAction?: React.ReactNode; + subject: string; + title?: string; + subtitle?: React.ReactNode; + headerType?: BodyHeadType; +}) => { + return ( + + + +
+ + + + {props.headerType && } + {props.title && } + {(props.headerType || props.title || props.subtitle) && } + +
`} + /> +
+ +
+
`} + /> +
`} + /> +
+ +
+ + + + + + + + {props.callToAction && } +
`} + /> +
+ +
+
+ {props.children} +
+
`} + /> + +
+ +
+ + + + + + + + + + + )} + + + + + + + + + + ); +}; diff --git a/packages/emails/src/components/index.ts b/packages/emails/src/components/index.ts index a01f573d69..32a5906b46 100644 --- a/packages/emails/src/components/index.ts +++ b/packages/emails/src/components/index.ts @@ -1,4 +1,5 @@ export { BaseEmailHtml } from "./BaseEmailHtml"; +export { V2BaseEmailHtml } from "./V2BaseEmailHtml"; export { CallToAction } from "./CallToAction"; export { CallToActionTable } from "./CallToActionTable"; export { CustomInputs } from "./CustomInputs"; diff --git a/packages/emails/src/templates/TeamInviteEmail.tsx b/packages/emails/src/templates/TeamInviteEmail.tsx index 3d4b6d6838..03332e173b 100644 --- a/packages/emails/src/templates/TeamInviteEmail.tsx +++ b/packages/emails/src/templates/TeamInviteEmail.tsx @@ -1,8 +1,8 @@ import type { TFunction } from "next-i18next"; -import { APP_NAME } from "@calcom/lib/constants"; +import { APP_NAME, BASE_URL, IS_PRODUCTION } from "@calcom/lib/constants"; -import { BaseEmailHtml, CallToAction } from "../components"; +import { V2BaseEmailHtml, CallToAction } from "../components"; type TeamInvite = { language: TFunction; @@ -12,15 +12,36 @@ type TeamInvite = { joinLink: string; }; -export const TeamInviteEmail = (props: TeamInvite & Partial>) => { +export const TeamInviteEmail = ( + props: TeamInvite & Partial> +) => { return ( - -

+ +

<> {props.language("user_invited_you", { user: props.from, @@ -30,21 +51,22 @@ export const TeamInviteEmail = (props: TeamInvite & Partial

-

+

<>{props.language("calcom_explained", { appName: APP_NAME })}

-
-

+

+

<> {props.language("have_any_questions")}{" "} - <>{props.language("contact_our_support_team")} - + <>{props.language("contact")} + {" "} + {props.language("our_support_team")}

- + ); }; From 8849d1148cd169d2f2546a94c002a07ffb89d901 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Tue, 13 Dec 2022 18:34:25 +0100 Subject: [PATCH 03/31] removed z-index from topbanner (#6008) --- packages/ui/components/top-banner/TopBanner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/components/top-banner/TopBanner.tsx b/packages/ui/components/top-banner/TopBanner.tsx index 0a62d141aa..9714ace906 100644 --- a/packages/ui/components/top-banner/TopBanner.tsx +++ b/packages/ui/components/top-banner/TopBanner.tsx @@ -23,7 +23,7 @@ export function TopBanner(props: TopBannerProps) {
From 8f48ecafec397cf0786c59a90f9e80516617c205 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Tue, 13 Dec 2022 12:44:53 -0500 Subject: [PATCH 04/31] Misc fixes (#5988) * Address reports * Clean up * remove activeOn in where Co-authored-by: Peer Richelsen Co-authored-by: CarinaWolli Co-authored-by: Bailey Pumfleet --- .../trpc/server/routers/viewer/eventTypes.tsx | 21 ++++++++++++--- .../trpc/server/routers/viewer/workflows.tsx | 26 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/trpc/server/routers/viewer/eventTypes.tsx b/packages/trpc/server/routers/viewer/eventTypes.tsx index 95838c762f..7068af435c 100644 --- a/packages/trpc/server/routers/viewer/eventTypes.tsx +++ b/packages/trpc/server/routers/viewer/eventTypes.tsx @@ -456,8 +456,14 @@ export const eventTypesRouter = router({ users, id, hashedLink, + // Extract this from the input so it doesn't get saved in the db + // eslint-disable-next-line + userId, + // eslint-disable-next-line + teamId, ...rest } = input; + const data: Prisma.EventTypeUpdateInput = { ...rest, metadata: rest.metadata === null ? Prisma.DbNull : rest.metadata, @@ -500,11 +506,20 @@ export const eventTypesRouter = router({ } if (schedule) { - data.schedule = { - connect: { + // Check that the schedule belongs to the user + const userScheduleQuery = await ctx.prisma.schedule.findFirst({ + where: { + userId: ctx.user.id, id: schedule, }, - }; + }); + if (userScheduleQuery) { + data.schedule = { + connect: { + id: schedule, + }, + }; + } } if (users) { diff --git a/packages/trpc/server/routers/viewer/workflows.tsx b/packages/trpc/server/routers/viewer/workflows.tsx index 47b87bd94c..295afe17ac 100644 --- a/packages/trpc/server/routers/viewer/workflows.tsx +++ b/packages/trpc/server/routers/viewer/workflows.tsx @@ -926,6 +926,32 @@ export const workflowsRouter = router({ .mutation(async ({ ctx, input }) => { const { eventTypeId, workflowId } = input; + // Check that workflow & event type belong to the user + const userEventType = await ctx.prisma.eventType.findFirst({ + where: { + id: eventTypeId, + users: { + some: { + id: ctx.user.id, + }, + }, + }, + }); + + if (!userEventType) + throw new TRPCError({ code: "UNAUTHORIZED", message: "This event type does not belong to the user" }); + + // Check that the workflow belongs to the user + const eventTypeWorkflow = await ctx.prisma.workflow.findFirst({ + where: { + id: workflowId, + userId: ctx.user.id, + }, + }); + + if (!eventTypeWorkflow) + throw new TRPCError({ code: "UNAUTHORIZED", message: "This event type does not belong to the user" }); + // NOTE: This was unused // const eventType = await ctx.prisma.eventType.findFirst({ // where: { From 2e6c3a6068bea37f1e6c90f1a0ac708f992f2d46 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Dec 2022 19:11:45 +0100 Subject: [PATCH 05/31] New Crowdin translations by Github Action (#6001) Co-authored-by: Crowdin Bot --- apps/web/public/static/locales/ar/common.json | 1 - apps/web/public/static/locales/cs/common.json | 1 - apps/web/public/static/locales/de/common.json | 1 - apps/web/public/static/locales/el/common.json | 1 + apps/web/public/static/locales/es/common.json | 1 - apps/web/public/static/locales/fr/common.json | 2 +- apps/web/public/static/locales/he/common.json | 1 - apps/web/public/static/locales/it/common.json | 37 ++++++++++++++++++- apps/web/public/static/locales/ja/common.json | 1 - apps/web/public/static/locales/ko/common.json | 1 - apps/web/public/static/locales/nl/common.json | 1 - apps/web/public/static/locales/no/common.json | 1 - apps/web/public/static/locales/pl/common.json | 1 - .../public/static/locales/pt-BR/common.json | 1 - apps/web/public/static/locales/pt/common.json | 1 - apps/web/public/static/locales/ro/common.json | 1 - apps/web/public/static/locales/ru/common.json | 1 - apps/web/public/static/locales/sr/common.json | 1 - apps/web/public/static/locales/sv/common.json | 1 - apps/web/public/static/locales/tr/common.json | 1 - apps/web/public/static/locales/uk/common.json | 2 +- apps/web/public/static/locales/vi/common.json | 1 - .../public/static/locales/zh-CN/common.json | 1 - .../public/static/locales/zh-TW/common.json | 1 - 24 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 apps/web/public/static/locales/el/common.json diff --git a/apps/web/public/static/locales/ar/common.json b/apps/web/public/static/locales/ar/common.json index 2352a58d0b..1fd5680539 100644 --- a/apps/web/public/static/locales/ar/common.json +++ b/apps/web/public/static/locales/ar/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "انتقل إلى بوابة الفوترة", "need_anything_else": "هل تحتاج إلى أي شيء آخر؟", "further_billing_help": "إذا كنت تحتاج إلى أي مساعدة إضافية بخصوص الفوترة، فإن فريق الدعم لدينا في انتظارك لتقديم المساعدة.", - "contact_our_support_team": "الاتصال بفريق الدعم لدينا", "uh_oh": "عذرًا!", "no_event_types_have_been_setup": "لم يقم هذا المستخدم بإعداد أي أنواع للحدث حتى الآن.", "edit_logo": "تعديل الشعار", diff --git a/apps/web/public/static/locales/cs/common.json b/apps/web/public/static/locales/cs/common.json index 2a0bf74781..9e184deaa5 100644 --- a/apps/web/public/static/locales/cs/common.json +++ b/apps/web/public/static/locales/cs/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Přejít na fakturační portál", "need_anything_else": "Potřebujete ještě něco?", "further_billing_help": "Pokud potřebujete další pomoc s fakturací, náš tým podpory je zde, aby vám pomohl.", - "contact_our_support_team": "Kontaktovat tým podpory", "uh_oh": "Ale ne!", "no_event_types_have_been_setup": "Tento uživatel zatím nezaložil žádné typy událostí.", "edit_logo": "Upravit logo", diff --git a/apps/web/public/static/locales/de/common.json b/apps/web/public/static/locales/de/common.json index a6f4efc470..48d41bbe3e 100644 --- a/apps/web/public/static/locales/de/common.json +++ b/apps/web/public/static/locales/de/common.json @@ -370,7 +370,6 @@ "go_to_billing_portal": "Zum Rechnungsportal gehen", "need_anything_else": "Brauchen Sie etwas anderes?", "further_billing_help": "Wenn Sie weitere Hilfe bei der Rechnungsstellung benötigen, hilft Ihnen unser Support-Team gerne weiter.", - "contact_our_support_team": "Kontaktieren Sie unser Support-Team", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Dieser Benutzer hat noch keine Termintypen eingerichtet.", "edit_logo": "Logo bearbeiten", diff --git a/apps/web/public/static/locales/el/common.json b/apps/web/public/static/locales/el/common.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/apps/web/public/static/locales/el/common.json @@ -0,0 +1 @@ +{} diff --git a/apps/web/public/static/locales/es/common.json b/apps/web/public/static/locales/es/common.json index 06091ec18c..30c3929cfe 100644 --- a/apps/web/public/static/locales/es/common.json +++ b/apps/web/public/static/locales/es/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Ir al portal de facturación", "need_anything_else": "¿Necesita algo más?", "further_billing_help": "Si necesita más ayuda con la facturación, nuestro equipo de soporte está aquí para ayudarlo.", - "contact_our_support_team": "Contacta con nuestro equipo de soporte", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Este usuario aún no ha configurado ningún tipo de evento.", "edit_logo": "Cambiar la marca", diff --git a/apps/web/public/static/locales/fr/common.json b/apps/web/public/static/locales/fr/common.json index 9c3de1ab0f..ab1960f5d4 100644 --- a/apps/web/public/static/locales/fr/common.json +++ b/apps/web/public/static/locales/fr/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Accéder au portail de facturation", "need_anything_else": "Besoin d'autre chose ?", "further_billing_help": "Si vous avez besoin d'aide pour la facturation, notre équipe d'assistance est là pour vous aider.", - "contact_our_support_team": "Contactez notre équipe d'assistance", "uh_oh": "Oups !", "no_event_types_have_been_setup": "Cet utilisateur n'a pas encore configuré de types d'événements.", "edit_logo": "Modifier le logo", @@ -562,6 +561,7 @@ "duration": "Durée", "available_durations": "Durées disponibles", "default_duration": "Durée par défaut", + "default_duration_no_options": "Veuillez d'abord choisir les durées disponibles", "minutes": "Minutes", "round_robin": "Round Robin", "round_robin_description": "Faites tourner les réunions entre plusieurs membres de l'équipe.", diff --git a/apps/web/public/static/locales/he/common.json b/apps/web/public/static/locales/he/common.json index d47b25f681..16c56e18ef 100644 --- a/apps/web/public/static/locales/he/common.json +++ b/apps/web/public/static/locales/he/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "מעבר אל פורטל החיובים", "need_anything_else": "צריך משהו נוסף?", "further_billing_help": "אם דרוש לך סיוע נוסף בענייני חיוב, צוות התמיכה שלנו כאן כדי לעזור.", - "contact_our_support_team": "יצירת קשר עם צוות התמיכה", "uh_oh": "אוי, לא!", "no_event_types_have_been_setup": "משתמש זה עדיין לא הגדיר סוג אירוע.", "edit_logo": "עריכת לוגו", diff --git a/apps/web/public/static/locales/it/common.json b/apps/web/public/static/locales/it/common.json index 93f7e5d8b6..ec0196bf45 100644 --- a/apps/web/public/static/locales/it/common.json +++ b/apps/web/public/static/locales/it/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Vai al portale di fatturazione", "need_anything_else": "Hai bisogno di altro?", "further_billing_help": "Se hai bisogno di ulteriore aiuto per la fatturazione, il nostro team di supporto è qui per aiutarti.", - "contact_our_support_team": "Contatta il nostro team di supporto", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Questo utente non ha ancora impostato alcun tipo di evento.", "edit_logo": "Modifica logo", @@ -1404,5 +1403,39 @@ "edit_event_type": "Modifica tipo di evento", "collective_scheduling": "Pianificazione collettiva", "make_it_easy_to_book": "Facilita la prenotazione del tuo team quando tutti sono disponibili.", - "find_the_best_person": "Trova la persona più adatta disponibile e passa tra i membri del team." + "find_the_best_person": "Trova la persona più adatta disponibile e passa tra i membri del team.", + "fixed_round_robin": "Round robin fisso", + "add_one_fixed_attendee": "Aggiungi un partecipante fisso e fai intervenire a turno altri partecipanti.", + "calcom_is_better_with_team": "Cal.com funziona meglio in team", + "add_your_team_members": "Aggiungi i membri del tuo team ai tuoi tipi di eventi. Usa la pianificazione collettiva per includere tutti o trova la persona più adatta con la pianificazione round robin.", + "booking_limit_reached": "È stato raggiunto il limite di prenotazione per questo tipo di evento", + "admin_has_disabled": "Un amministratore ha disabilitato {{appName}}", + "disabled_app_affects_event_type": "Un amministratore ha disabilitato {{appName}}, il che influenza il tuo tipo di evento {{eventType}}", + "disable_payment_app": "L'amministratore ha disabilitato {{appName}}, il che influenza il tuo tipo di evento {{title}}. I partecipanti sono ancora in grado di prenotare questo tipo di evento, ma non gli verrà richiesto di pagare. Per evitarlo, è possibile nascondere questo tipo di evento fino a che l'amministratore non riattivi il tuo metodo di pagamento.", + "payment_disabled_still_able_to_book": "I partecipanti sono ancora in grado di prenotare questo tipo di evento, ma non gli verrà richiesto di pagare. Per evitarlo, è possibile nascondere questo tipo di evento fino a che l'amministratore non riattivi il tuo metodo di pagamento.", + "app_disabled_with_event_type": "L'amministratore ha disabilitato {{appName}}, il che influenza il tuo tipo di evento {{title}}.", + "app_disabled_video": "L'amministratore ha disabilitato {{appName}}, il che potrebbe influenzare i tuoi tipi di eventi. Se hai dei tipi di eventi che utilizzano {{appName}} come luogo, allora verrà usato Cal Video come luogo predefinito.", + "app_disabled_subject": "{{appName}} è stato disabilitato", + "navigate_installed_apps": "Vai alle app installate", + "disabled_calendar": "Se si dispone di un altro calendario installato, le nuove prenotazioni saranno aggiunte a quel calendario. Se così non fosse, connettere un nuovo calendario in modo da non perdere nessuna nuova prenotazione.", + "enable_apps": "Abilita app", + "enable_apps_description": "Abilita le app che gli utenti possono integrare con Cal.com", + "app_is_enabled": "{{appName}} è abilitato", + "app_is_disabled": "{{appName}} è disabilitato", + "keys_have_been_saved": "Le chiavi sono state salvate", + "disable_app": "Disabilita app", + "disable_app_description": "La disattivazione di questa app potrebbe causare problemi con il modo in cui i tuoi utenti interagiscono con Cal", + "edit_keys": "Modifica chiavi", + "no_available_apps": "Nessuna app disponibile", + "no_available_apps_description": "Assicurarsi che ci siano delle applicazioni nella propria distribuzione in 'packages/app-store'", + "no_apps": "Non ci sono applicazioni abilitate in questa istanza di Cal", + "apps_settings": "Impostazioni delle app", + "fill_this_field": "Compilare il campo", + "options": "Opzioni", + "enter_option": "Immetti opzione {{index}}", + "add_an_option": "Aggiungi un'opzione", + "radio": "Radio", + "event_type_duplicate_copy_text": "{{slug}}-copia", + "set_as_default": "Imposta come predefinito", + "hide_eventtype_details": "Nascondi dettagli tipo di evento" } diff --git a/apps/web/public/static/locales/ja/common.json b/apps/web/public/static/locales/ja/common.json index e5ea9abeee..841690aea1 100644 --- a/apps/web/public/static/locales/ja/common.json +++ b/apps/web/public/static/locales/ja/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "請求ポータルに移動", "need_anything_else": "他に必要なものはありませんか?", "further_billing_help": "請求に関するサポートが必要な場合は、サポートチームがお手伝いします。", - "contact_our_support_team": "サポートチームに問い合わせる", "uh_oh": "おっと!", "no_event_types_have_been_setup": "このユーザーはまだイベントタイプを設定していません。", "edit_logo": "ロゴを編集", diff --git a/apps/web/public/static/locales/ko/common.json b/apps/web/public/static/locales/ko/common.json index 7686ae0e18..774fff6bce 100644 --- a/apps/web/public/static/locales/ko/common.json +++ b/apps/web/public/static/locales/ko/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "결제 포털로 이동", "need_anything_else": "다른 것이 필요하십니까?", "further_billing_help": "청구와 관련하여 추가 도움이 필요한 경우 지원 팀이 도와드리겠습니다.", - "contact_our_support_team": "지원팀에 문의하기", "uh_oh": "오!", "no_event_types_have_been_setup": "사용자가 이벤트 타입을 설정하지 않았습니다.", "edit_logo": "로고 수정하기", diff --git a/apps/web/public/static/locales/nl/common.json b/apps/web/public/static/locales/nl/common.json index 3e65b52200..ed3b2fa686 100644 --- a/apps/web/public/static/locales/nl/common.json +++ b/apps/web/public/static/locales/nl/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Ga naar het facturatiepaneel", "need_anything_else": "Nog iets nodig?", "further_billing_help": "Als u verdere hulp nodig heeft bij facturering, is ons ondersteuningsteam er om u te helpen.", - "contact_our_support_team": "Neem contact op met onze klantenservice", "uh_oh": "Oeps!", "no_event_types_have_been_setup": "Deze gebruiker heeft nog geen evenementen.", "edit_logo": "Bewerk logo", diff --git a/apps/web/public/static/locales/no/common.json b/apps/web/public/static/locales/no/common.json index d6965b7a45..d9dfeba533 100644 --- a/apps/web/public/static/locales/no/common.json +++ b/apps/web/public/static/locales/no/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Gå til betalingsportalen", "need_anything_else": "Trenger du noe annet?", "further_billing_help": "Hvis du trenger ytterligere hjelp med betaling, er supportteamet vårt her for å hjelpe.", - "contact_our_support_team": "Kontakt supportteamet vårt", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Denne brukeren har ikke konfigurert noen hendelsestyper ennå.", "edit_logo": "Rediger logo", diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index 968fc948df..a6fe5753f8 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Przejdź do portalu rozliczeniowego", "need_anything_else": "Potrzebujesz czegoś innego?", "further_billing_help": "Jeśli potrzebujesz dalszej pomocy przy rozliczaniu, nasz zespół wsparcia jest tutaj, aby pomóc.", - "contact_our_support_team": "Skontaktuj się z naszym zespołem wsparcia", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Ten użytkownik nie ustawił jeszcze żadnych typów wydarzeń.", "edit_logo": "Edytuj logo", diff --git a/apps/web/public/static/locales/pt-BR/common.json b/apps/web/public/static/locales/pt-BR/common.json index 658b7cce71..7a7cffd6a5 100644 --- a/apps/web/public/static/locales/pt-BR/common.json +++ b/apps/web/public/static/locales/pt-BR/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Ir para o portal de pagamento", "need_anything_else": "Precisa de algo mais?", "further_billing_help": "Se precisar de mais ajuda com o faturamento, o nosso time de suporte está aqui para ajudar.", - "contact_our_support_team": "Fale com a nossa equipe de suporte", "uh_oh": "Oh oh!", "no_event_types_have_been_setup": "Este usuário ainda não definiu nenhum tipo de evento.", "edit_logo": "Editar logotipo", diff --git a/apps/web/public/static/locales/pt/common.json b/apps/web/public/static/locales/pt/common.json index d918cef235..b55830c399 100644 --- a/apps/web/public/static/locales/pt/common.json +++ b/apps/web/public/static/locales/pt/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Ir para o portal de pagamento", "need_anything_else": "Precisa de algo mais?", "further_billing_help": "Se precisar de mais ajuda com a faturação, a nossa equipa de suporte está aqui para ajudar.", - "contact_our_support_team": "Contacte a nossa equipa de suporte", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Este utilizador ainda não configurou nenhum tipo de evento.", "edit_logo": "Editar logótipo", diff --git a/apps/web/public/static/locales/ro/common.json b/apps/web/public/static/locales/ro/common.json index d20abc5d44..2927ed042d 100644 --- a/apps/web/public/static/locales/ro/common.json +++ b/apps/web/public/static/locales/ro/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Accesați portalul de facturare", "need_anything_else": "Aveți nevoie de altceva?", "further_billing_help": "Dacă ai nevoie de ajutor suplimentar pentru facturare, echipa noastră de asistență este aici pentru a te ajuta.", - "contact_our_support_team": "Contactează echipa noastră de suport", "uh_oh": "Uh oh!", "no_event_types_have_been_setup": "Acest utilizator nu a configurat încă niciun tip de eveniment.", "edit_logo": "Editare logo", diff --git a/apps/web/public/static/locales/ru/common.json b/apps/web/public/static/locales/ru/common.json index 0cc77df145..99397bc2aa 100644 --- a/apps/web/public/static/locales/ru/common.json +++ b/apps/web/public/static/locales/ru/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "Перейти на платёжный портал", "need_anything_else": "Нужно что-нибудь еще?", "further_billing_help": "Если вам нужна дальнейшая помощь с оплатой счета, наша служба поддержки готова помочь.", - "contact_our_support_team": "Свяжитесь с нашей службой поддержки", "uh_oh": "О нет!", "no_event_types_have_been_setup": "Этот пользователь еще не создал ни одного события.", "edit_logo": "Изменить логотип", diff --git a/apps/web/public/static/locales/sr/common.json b/apps/web/public/static/locales/sr/common.json index 3d6bf6c116..4c0c11906f 100644 --- a/apps/web/public/static/locales/sr/common.json +++ b/apps/web/public/static/locales/sr/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Idite na portal naplate", "need_anything_else": "Treba li vam još nešto?", "further_billing_help": "Ako vam treba pomoć sa naplatom, naš tim podrške je tu da pomogne.", - "contact_our_support_team": "Kontaktirjate naš tim podrške", "uh_oh": "O ne!", "no_event_types_have_been_setup": "Ovaj korisnik još nije podesio tipove događaja.", "edit_logo": "Uredi logo", diff --git a/apps/web/public/static/locales/sv/common.json b/apps/web/public/static/locales/sv/common.json index d987c38648..626a131907 100644 --- a/apps/web/public/static/locales/sv/common.json +++ b/apps/web/public/static/locales/sv/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Gå till faktureringsportalen", "need_anything_else": "Behöver du något annat?", "further_billing_help": "Om du behöver ytterligare hjälp med fakturering finns vårt supportteam här för att hjälpa till.", - "contact_our_support_team": "Kontakta vårt kundsupportteam", "uh_oh": "Åh nej!", "no_event_types_have_been_setup": "Den här användaren har inte skapat några händelsetyper ännu.", "edit_logo": "Ändra logotyp", diff --git a/apps/web/public/static/locales/tr/common.json b/apps/web/public/static/locales/tr/common.json index 8b48044a70..cebbf05fb3 100644 --- a/apps/web/public/static/locales/tr/common.json +++ b/apps/web/public/static/locales/tr/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Fatura portalına git", "need_anything_else": "Başka bir şeye ihtiyacınız var mı?", "further_billing_help": "Faturalandırma konusunda daha fazla yardıma ihtiyacınız olursa destek ekibimiz size yardımcı olmaya hazır.", - "contact_our_support_team": "Destek ekibimizle iletişime geçin", "uh_oh": "Hay aksi!", "no_event_types_have_been_setup": "Bu kullanıcı henüz etkinlik türü ayarlamadı.", "edit_logo": "Logoyu düzenle", diff --git a/apps/web/public/static/locales/uk/common.json b/apps/web/public/static/locales/uk/common.json index 29c619ed57..166e98b717 100644 --- a/apps/web/public/static/locales/uk/common.json +++ b/apps/web/public/static/locales/uk/common.json @@ -52,6 +52,7 @@ "still_waiting_for_approval": "Захід досі чекає на схвалення", "event_is_still_waiting": "Запит на захід досі в очікуванні: {{attendeeName}} – {{date}} – {{eventType}}", "no_more_results": "Інших результатів немає", + "no_results": "Немає результатів", "load_more_results": "Завантажити інші результати", "integration_meeting_id": "Ідентифікатор наради «{{integrationName}}»: {{meetingId}}", "confirmed_event_type_subject": "Підтверджено: {{eventType}} «{{name}}», {{date}}", @@ -383,7 +384,6 @@ "go_to_billing_portal": "Перейти на портал виставлення рахунків", "need_anything_else": "Потрібно щось інше?", "further_billing_help": "Якщо вам потрібна додаткова допомога з виставленням рахунків, наша служба підтримки готова її надати.", - "contact_our_support_team": "Зв’язатися зі службою підтримки", "uh_oh": "Отакої!", "no_event_types_have_been_setup": "Цей користувач ще не налаштував жодних типів заходів.", "edit_logo": "Редагувати логотип", diff --git a/apps/web/public/static/locales/vi/common.json b/apps/web/public/static/locales/vi/common.json index 6c6ab74425..9c2b0ebbba 100644 --- a/apps/web/public/static/locales/vi/common.json +++ b/apps/web/public/static/locales/vi/common.json @@ -385,7 +385,6 @@ "go_to_billing_portal": "Đi tới cổng thanh toán", "need_anything_else": "Cần gì nữa không?", "further_billing_help": "Nếu bạn cần thêm bất kỳ trợ giúp nào về thanh toán, nhóm hỗ trợ của chúng tôi luôn sẵn sàng trợ giúp.", - "contact_our_support_team": "Liên hệ với nhóm hỗ trợ của chúng tôi", "uh_oh": "\bÔi không!", "no_event_types_have_been_setup": "Người dùng này chưa thiết lập bất kỳ loại sự kiện nào.", "edit_logo": "Chỉnh sửa logo", diff --git a/apps/web/public/static/locales/zh-CN/common.json b/apps/web/public/static/locales/zh-CN/common.json index 500c13441c..628edb2ece 100644 --- a/apps/web/public/static/locales/zh-CN/common.json +++ b/apps/web/public/static/locales/zh-CN/common.json @@ -384,7 +384,6 @@ "go_to_billing_portal": "转到账单门户网站", "need_anything_else": "还有其他需要?", "further_billing_help": "如果您在支付帐单时需要任何进一步的帮助,我们的支持团队会给您提供帮助。", - "contact_our_support_team": "联系我们的支持团队", "uh_oh": "糟糕!", "no_event_types_have_been_setup": "此用户尚未设置任何活动类型。", "edit_logo": "编辑标志", diff --git a/apps/web/public/static/locales/zh-TW/common.json b/apps/web/public/static/locales/zh-TW/common.json index b2c6e8fb5b..1e46df005d 100644 --- a/apps/web/public/static/locales/zh-TW/common.json +++ b/apps/web/public/static/locales/zh-TW/common.json @@ -383,7 +383,6 @@ "go_to_billing_portal": "前往付費入口", "need_anything_else": "還要什麼嗎?", "further_billing_help": "如果有關於付費的進一步需求,我們的支援團隊隨時上前幫忙。", - "contact_our_support_team": "聯繫支援團隊", "uh_oh": "哎呦喂呀!", "no_event_types_have_been_setup": "使用者尚未設定任何活動類型。", "edit_logo": "編輯標誌", From 61e6f76bc6d97e43865ebb23ad919a849b1df675 Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Tue, 13 Dec 2022 18:09:28 -0300 Subject: [PATCH 06/31] Direct links to accept/reject a booking (#5939) * Impl * Added reason * Secondary reject CTA * Update packages/emails/src/components/Info.tsx * Adjusting recurring info * Not showing reason for rejecting if none given * Feedback * Error handling + style fixes Co-authored-by: Peer Richelsen --- apps/web/pages/500.tsx | 42 +- apps/web/pages/api/email.ts | 17 +- apps/web/pages/booking/direct/[...link].tsx | 450 ++++++++++++++++++ apps/web/public/emails/linkIcon.svg | 5 + apps/web/public/static/locales/en/common.json | 3 + .../emails/src/components/CallToAction.tsx | 19 +- .../src/components/CallToActionTable.tsx | 2 - packages/emails/src/components/LinkIcon.tsx | 6 +- packages/emails/src/components/Separator.tsx | 3 + packages/emails/src/components/WhenInfo.tsx | 27 +- packages/emails/src/components/index.ts | 1 + .../src/templates/OrganizerRequestEmail.tsx | 65 ++- .../lib/{getWebhooks.tsx => getWebhooks.ts} | 0 .../lib/{sendPayload.tsx => sendPayload.ts} | 0 .../lib/server/queries/bookings/confirm.ts | 441 +++++++++++++++++ .../trpc/server/routers/viewer/bookings.tsx | 415 +--------------- 16 files changed, 1018 insertions(+), 478 deletions(-) create mode 100644 apps/web/pages/booking/direct/[...link].tsx create mode 100644 apps/web/public/emails/linkIcon.svg create mode 100644 packages/emails/src/components/Separator.tsx rename packages/features/webhooks/lib/{getWebhooks.tsx => getWebhooks.ts} (100%) rename packages/features/webhooks/lib/{sendPayload.tsx => sendPayload.ts} (100%) create mode 100644 packages/lib/server/queries/bookings/confirm.ts diff --git a/apps/web/pages/500.tsx b/apps/web/pages/500.tsx index 3fa4508a3b..47bb99684c 100644 --- a/apps/web/pages/500.tsx +++ b/apps/web/pages/500.tsx @@ -1,32 +1,48 @@ import Head from "next/head"; +import { useRouter } from "next/router"; import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Button } from "@calcom/ui"; +import { Button, Icon, showToast } from "@calcom/ui"; export default function Error500() { const { t } = useLocale(); + const router = useRouter(); return ( -
+
Something unexpected occurred | {APP_NAME} -
-

- 5 - { - // eslint-disable-next-line @next/next/no-img-element - 0 - } - 0 -

-

It's not you, it's us.

-

+

+

500

+

It's not you, it's us.

+

Something went wrong on our end. Get in touch with our support team, and we’ll get it fixed right away for you.

+ {router.query.error && ( +
+

+ Please provide the following text when contacting support to better help you: +

+
+              {router.query.error}
+              
+ +
+
+ )}
`} + /> + {props.callToAction && ( +
+ +
+ {props.callToAction} +
+
+