From 20d2955e689cce90c1ff3eebef4fd7a6c4ac3370 Mon Sep 17 00:00:00 2001 From: Philipp Dormann <17651032+philippdormann@users.noreply.github.com> Date: Tue, 8 Feb 2022 23:12:28 +0100 Subject: [PATCH] Add Jitsi Meet Integration (#1674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * basic integration structure * jitsi logo * add jitsi meet description to event settings page * add JitsiVideoApiAdapter ref #1445 * add LocationType.Jitsi to BookingPage ref #1445 * add LocationType.Jitsi to event-types ref #1445 * add meet.jit.si/cal/uuid support to BookingPage ref #1445 * add basic "cal_provide_jitsi_meeting_url" translation strings ref #1445 * generate meeting id ref #1445 * implement direct jitsi link in /success page ref #1445 * cleanup location link duplicate ref #1445 * full JitsiVideoApiAdapter implementation ref #1445 * check integration availability in /pages/event-types/[type] ref #1445 * add video conferencing link as calendar event location ref #1445 * PR feedback * Update components/booking/pages/BookingPage.tsx don't know - wouldn't do this myself for future proofing but fine... Co-authored-by: Omar López * Update components/booking/pages/BookingPage.tsx 🤷‍♂️ Co-authored-by: Omar López * cleanup: props.type === "jitsi_video" ref #1445 Co-authored-by: zomars --- components/booking/pages/BookingPage.tsx | 11 +++ lib/events/EventManager.ts | 1 + lib/integrations.ts | 2 + .../Jitsi/JitsiVideoApiAdapter.ts | 34 ++++++++ lib/integrations/getIntegrations.ts | 20 +++-- lib/location.ts | 1 + lib/videoClient.ts | 4 + pages/event-types/[type].tsx | 80 +++++++++++++++++-- pages/integrations/index.tsx | 2 +- pages/success.tsx | 20 +++-- public/integrations/jitsi.svg | 1 + public/static/locales/cs/common.json | 1 + public/static/locales/de/common.json | 1 + public/static/locales/en/common.json | 1 + public/static/locales/es/common.json | 1 + public/static/locales/fr/common.json | 1 + public/static/locales/it/common.json | 1 + public/static/locales/ja/common.json | 1 + public/static/locales/ko/common.json | 1 + public/static/locales/nl/common.json | 1 + public/static/locales/pl/common.json | 1 + public/static/locales/pt-BR/common.json | 1 + public/static/locales/pt/common.json | 1 + public/static/locales/ro/common.json | 1 + public/static/locales/ru/common.json | 1 + public/static/locales/zh-CN/common.json | 1 + 26 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 lib/integrations/Jitsi/JitsiVideoApiAdapter.ts create mode 100644 public/integrations/jitsi.svg diff --git a/components/booking/pages/BookingPage.tsx b/components/booking/pages/BookingPage.tsx index 46d4ef85..4ffda4bd 100644 --- a/components/booking/pages/BookingPage.tsx +++ b/components/booking/pages/BookingPage.tsx @@ -16,6 +16,7 @@ import { Controller, useForm, useWatch } from "react-hook-form"; import { FormattedNumber, IntlProvider } from "react-intl"; import { ReactMultiEmail } from "react-multi-email"; import { useMutation } from "react-query"; +import { v4 as uuidv4 } from "uuid"; import { createPaymentLink } from "@ee/lib/stripe/client"; @@ -89,6 +90,9 @@ const BookingPage = (props: BookingPageProps) => { if (!location) { return; } + if (location === "integrations:jitsi") { + return "https://meet.jit.si/cal/" + uuidv4(); + } if (location.includes("integration")) { return t("web_conferencing_details_to_follow"); } @@ -143,6 +147,7 @@ const BookingPage = (props: BookingPageProps) => { [LocationType.Phone]: t("phone_call"), [LocationType.GoogleMeet]: "Google Meet", [LocationType.Zoom]: "Zoom Video", + [LocationType.Jitsi]: "Jitsi Meet", [LocationType.Daily]: "Daily.co Video", [LocationType.Huddle01]: "Huddle01 Video", [LocationType.Tandem]: "Tandem Video", @@ -330,6 +335,12 @@ const BookingPage = (props: BookingPageProps) => { {getLocationValue({ locationType: selectedLocation })}

)} + {selectedLocation === LocationType.Jitsi && ( +

+ + Jitsi Meet +

+ )}

{parseDate(date)} diff --git a/lib/events/EventManager.ts b/lib/events/EventManager.ts index 14cf3238..199418b2 100644 --- a/lib/events/EventManager.ts +++ b/lib/events/EventManager.ts @@ -66,6 +66,7 @@ export const getLocationRequestFromIntegration = (location: string) => { location === LocationType.GoogleMeet.valueOf() || location === LocationType.Zoom.valueOf() || location === LocationType.Daily.valueOf() || + location === LocationType.Jitsi.valueOf() || location === LocationType.Huddle01.valueOf() || location === LocationType.Tandem.valueOf() ) { diff --git a/lib/integrations.ts b/lib/integrations.ts index 03bb519c..9556dc98 100644 --- a/lib/integrations.ts +++ b/lib/integrations.ts @@ -14,6 +14,8 @@ export function getIntegrationName(name: string) { return "Apple Calendar"; case "daily_video": return "Daily"; + case "jitsi_video": + return "Jitsi Meet"; case "huddle01_video": return "Huddle01"; case "tandem_video": diff --git a/lib/integrations/Jitsi/JitsiVideoApiAdapter.ts b/lib/integrations/Jitsi/JitsiVideoApiAdapter.ts new file mode 100644 index 00000000..92f7c2f9 --- /dev/null +++ b/lib/integrations/Jitsi/JitsiVideoApiAdapter.ts @@ -0,0 +1,34 @@ +import { v4 as uuidv4 } from "uuid"; + +import { PartialReference } from "@lib/events/EventManager"; +import { VideoApiAdapter, VideoCallData } from "@lib/videoClient"; + +const JitsiVideoApiAdapter = (): VideoApiAdapter => { + return { + getAvailability: () => { + return Promise.resolve([]); + }, + createMeeting: async (): Promise => { + const meetingID = uuidv4(); + return Promise.resolve({ + type: "jitsi_video", + id: meetingID, + password: "", + url: "https://meet.jit.si/cal/" + meetingID, + }); + }, + deleteMeeting: async (): Promise => { + Promise.resolve(); + }, + updateMeeting: (bookingRef: PartialReference): Promise => { + return Promise.resolve({ + type: "jitsi_video", + id: bookingRef.meetingId as string, + password: bookingRef.meetingPassword as string, + url: bookingRef.meetingUrl as string, + }); + }, + }; +}; + +export default JitsiVideoApiAdapter; diff --git a/lib/integrations/getIntegrations.ts b/lib/integrations/getIntegrations.ts index fce6deb4..62d2a520 100644 --- a/lib/integrations/getIntegrations.ts +++ b/lib/integrations/getIntegrations.ts @@ -1,11 +1,7 @@ import { Prisma } from "@prisma/client"; import _ from "lodash"; -/** - * We can't use aliases in playwright tests (yet) - * https://github.com/microsoft/playwright/issues/7121 - */ -import { validJson } from "../../lib/jsonUtils"; +import { validJson } from "@lib/jsonUtils"; const credentialData = Prisma.validator()({ select: { id: true, type: true }, @@ -24,6 +20,7 @@ export type Integration = { | "caldav_calendar" | "apple_calendar" | "stripe_payment" + | "jitsi_video" | "huddle01_video" | "metamask_web3"; title: string; @@ -65,6 +62,14 @@ export const ALL_INTEGRATIONS = [ description: "Video Conferencing", variant: "conferencing", }, + { + installed: true, + type: "jitsi_video", + title: "Jitsi Meet", + imageSrc: "integrations/jitsi.svg", + description: "Video Conferencing", + variant: "conferencing", + }, { installed: true, type: "huddle01_video", @@ -146,7 +151,10 @@ export function hasIntegration(integrations: IntegrationMeta, type: string): boo (i) => i.type === type && !!i.installed && - (type === "daily_video" || type === "huddle01_video" || i.credentials.length > 0) + (type === "daily_video" || + type === "jitsi_video" || + type === "huddle01_video" || + i.credentials.length > 0) ); } export function hasIntegrationInstalled(type: Integration["type"]): boolean { diff --git a/lib/location.ts b/lib/location.ts index c3070051..5401d888 100644 --- a/lib/location.ts +++ b/lib/location.ts @@ -4,6 +4,7 @@ export enum LocationType { GoogleMeet = "integrations:google:meet", Zoom = "integrations:zoom", Daily = "integrations:daily", + Jitsi = "integrations:jitsi", Huddle01 = "integrations:huddle01", Tandem = "integrations:tandem", } diff --git a/lib/videoClient.ts b/lib/videoClient.ts index dfcf642c..577eca4a 100644 --- a/lib/videoClient.ts +++ b/lib/videoClient.ts @@ -6,6 +6,7 @@ import { getUid } from "@lib/CalEventParser"; import { EventResult } from "@lib/events/EventManager"; import { PartialReference } from "@lib/events/EventManager"; import Huddle01VideoApiAdapter from "@lib/integrations/Huddle01/Huddle01VideoApiAdapter"; +import JitsiVideoApiAdapter from "@lib/integrations/Jitsi/JitsiVideoApiAdapter"; import logger from "@lib/logger"; import DailyVideoApiAdapter from "./integrations/Daily/DailyVideoApiAdapter"; @@ -46,6 +47,9 @@ const getVideoAdapters = (withCredentials: Credential[]): VideoApiAdapter[] => case "daily_video": acc.push(DailyVideoApiAdapter(cred)); break; + case "jitsi_video": + acc.push(JitsiVideoApiAdapter()); + break; case "huddle01_video": acc.push(Huddle01VideoApiAdapter()); break; diff --git a/pages/event-types/[type].tsx b/pages/event-types/[type].tsx index 5b819ef3..e85988c0 100644 --- a/pages/event-types/[type].tsx +++ b/pages/event-types/[type].tsx @@ -115,6 +115,7 @@ const EventTypePage = (props: inferSSRProps) => { const defaultLocations = [ { value: LocationType.InPerson, label: t("in_person_meeting") }, + { value: LocationType.Jitsi, label: "Jitsi Meet" }, { value: LocationType.Phone, label: t("phone_call") }, ]; @@ -125,7 +126,12 @@ const EventTypePage = (props: inferSSRProps) => { const updateMutation = trpc.useMutation("viewer.eventTypes.update", { onSuccess: async ({ eventType }) => { await router.push("/event-types"); - showToast(t("event_type_updated_successfully", { eventTypeTitle: eventType.title }), "success"); + showToast( + t("event_type_updated_successfully", { + eventTypeTitle: eventType.title, + }), + "success" + ); }, onError: (err) => { if (err instanceof HttpError) { @@ -261,6 +267,8 @@ const EventTypePage = (props: inferSSRProps) => { return

{t("cal_provide_zoom_meeting_url")}

; case LocationType.Daily: return

{t("cal_provide_video_meeting_url")}

; + case LocationType.Jitsi: + return

{t("cal_provide_jitsi_meeting_url")}

; case LocationType.Huddle01: return

{t("cal_provide_huddle01_meeting_url")}

; case LocationType.Tandem: @@ -276,7 +284,11 @@ const EventTypePage = (props: inferSSRProps) => { setCustomInputs([...customInputs]); }; - const schedulingTypeOptions: { value: SchedulingType; label: string; description: string }[] = [ + const schedulingTypeOptions: { + value: SchedulingType; + label: string; + description: string; + }[] = [ { value: SchedulingType.COLLECTIVE, label: t("collective"), @@ -328,7 +340,10 @@ const EventTypePage = (props: inferSSRProps) => { locations: { type: LocationType; address?: string }[]; customInputs: EventTypeCustomInput[]; users: string[]; - availability: { openingHours: AvailabilityInput[]; dateOverrides: AvailabilityInput[] }; + availability: { + openingHours: AvailabilityInput[]; + dateOverrides: AvailabilityInput[]; + }; timeZone: string; periodType: PeriodType; periodDays: number; @@ -548,6 +563,33 @@ const EventTypePage = (props: inferSSRProps) => { Tandem Video )} + {location.type === LocationType.Jitsi && ( +
+ + + + + + + Jitsi Meet +
+ )}
{!needsConfirmation && (
- + {t("add_to_calendar")}
@@ -162,7 +171,8 @@ export default function Success(props: inferSSRProps) .utc() .format("YYYYMMDDTHHmmss[Z]")}&text=${eventName}&details=${ props.eventType.description - }` + (typeof location === "string" ? encodeURIComponent(location) : "") + }` + + (typeof location === "string" ? "&location=" + encodeURIComponent(location) : "") }> \ No newline at end of file diff --git a/public/static/locales/cs/common.json b/public/static/locales/cs/common.json index 24c31007..902e6207 100644 --- a/public/static/locales/cs/common.json +++ b/public/static/locales/cs/common.json @@ -553,6 +553,7 @@ "cal_provide_zoom_meeting_url": "Cal poskytne URL Zoom meetingu.", "cal_provide_tandem_meeting_url": "Cal poskytne URL Tandem meetingu.", "cal_provide_video_meeting_url": "Cal poskytne URL Daily video meetingu.", + "cal_provide_jitsi_meeting_url": "Cal poskytne URL Jitsi Meet video meetingu.", "cal_provide_huddle01_meeting_url": "Cal poskytne URL Huddle01 web3 video meetingu.", "require_payment": "Vyžadovat platbu", "commission_per_transaction": "provize za transakci", diff --git a/public/static/locales/de/common.json b/public/static/locales/de/common.json index 471f1c98..e8af131e 100644 --- a/public/static/locales/de/common.json +++ b/public/static/locales/de/common.json @@ -557,6 +557,7 @@ "cal_provide_zoom_meeting_url": "Cal stellt eine Zoom Meeting-URL zur Verfügung.", "cal_provide_tandem_meeting_url": "Cal stellt eine Tandem Meeting-URL zur Verfügung.", "cal_provide_video_meeting_url": "Cal stellt eine tägliche Video-Meeting-URL zur Verfügung.", + "cal_provide_jitsi_meeting_url": "Cal stellt eine Jitsi Meet URL zur Verfügung.", "cal_provide_huddle01_meeting_url": "Cal stellt eine tägliche Huddle01-Web3-Meeting-URL zur Verfügung.", "require_payment": "Zahlung erforderlich", "commission_per_transaction": "Provision pro Transaktion", diff --git a/public/static/locales/en/common.json b/public/static/locales/en/common.json index 2ee157b6..4fec5d30 100644 --- a/public/static/locales/en/common.json +++ b/public/static/locales/en/common.json @@ -559,6 +559,7 @@ "cal_provide_zoom_meeting_url": "Cal will provide a Zoom meeting URL.", "cal_provide_tandem_meeting_url": "Cal will provide a Tandem meeting URL.", "cal_provide_video_meeting_url": "Cal will provide a Daily video meeting URL.", + "cal_provide_jitsi_meeting_url": "We will generate a Jitsi Meet URL for you.", "cal_provide_huddle01_meeting_url": "Cal will provide a Huddle01 web3 video meeting URL.", "require_payment": "Require Payment", "commission_per_transaction": "commission per transaction", diff --git a/public/static/locales/es/common.json b/public/static/locales/es/common.json index e286e08b..551ede22 100644 --- a/public/static/locales/es/common.json +++ b/public/static/locales/es/common.json @@ -525,6 +525,7 @@ "cal_provide_zoom_meeting_url": "Cal proporcionará una URL de reunión de Zoom.", "cal_provide_tandem_meeting_url": "Cal proporcionará una URL de reunión de Tandem.", "cal_provide_video_meeting_url": "Cal proporcionará una URL de reunión de Daily Video.", + "cal_provide_jitsi_meeting_url": "Cal proporcionará una URL de reunión de Jitsi Meet.", "cal_provide_huddle01_meeting_url": "Cal proporcionará una URL de reunión de Huddle01 Web3 Video.", "require_payment": "Requiere Pago", "commission_per_transaction": "Comisión por Transacción", diff --git a/public/static/locales/fr/common.json b/public/static/locales/fr/common.json index 4d1c423a..1c9949c9 100644 --- a/public/static/locales/fr/common.json +++ b/public/static/locales/fr/common.json @@ -491,6 +491,7 @@ "cal_provide_zoom_meeting_url": "Cal fournira une URL de réunion Zoom.", "cal_provide_tandem_meeting_url": "Cal fournira une URL de réunion Tandem.", "cal_provide_video_meeting_url": "Cal fournira une URL de réunion Daily video.", + "cal_provide_jitsi_meeting_url": "Cal fournira une URL de réunion Jitsi Meet.", "cal_provide_huddle01_meeting_url": "Cal fournira une URL de réunion Huddle01 web3 video.", "require_payment": "Exiger un paiement", "commission_per_transaction": "commission par transaction", diff --git a/public/static/locales/it/common.json b/public/static/locales/it/common.json index bda09eef..ad446e10 100644 --- a/public/static/locales/it/common.json +++ b/public/static/locales/it/common.json @@ -517,6 +517,7 @@ "cal_provide_zoom_meeting_url": "Cal fornirà un URL di riunione Zoom.", "cal_provide_tandem_meeting_url": "Cal fornirà un URL di riunione Tandem.", "cal_provide_video_meeting_url": "Cal fornirà un URL di riunione Daily video.", + "cal_provide_jitsi_meeting_url": "Cal fornirà un URL di riunione Jitsi Meet.", "cal_provide_huddle01_meeting_url": "Cal fornirà un URL di riunione Huddle01 web3 video.", "require_payment": "Richiedi Pagamento", "commission_per_transaction": "commissione per transazione", diff --git a/public/static/locales/ja/common.json b/public/static/locales/ja/common.json index 54f8b62f..1054065e 100644 --- a/public/static/locales/ja/common.json +++ b/public/static/locales/ja/common.json @@ -489,6 +489,7 @@ "cal_provide_zoom_meeting_url": "カルはZoomミーティングURLを提供します。", "cal_provide_tandem_meeting_url": "カルはTandemミーティングURLを提供します。", "cal_provide_video_meeting_url": "カルは毎日のビデオミーティングのURLを提供します。", + "cal_provide_jitsi_meeting_url": "カルはJitsi MeetミーティングURLを提供します。", "cal_provide_huddle01_meeting_url": "カルはHuddle01 Web3ミーティングURLを提供します。", "require_payment": "お支払いが必要です", "commission_per_transaction": "取引あたりの手数料", diff --git a/public/static/locales/ko/common.json b/public/static/locales/ko/common.json index 3c6500ec..e8eb6975 100644 --- a/public/static/locales/ko/common.json +++ b/public/static/locales/ko/common.json @@ -512,6 +512,7 @@ "cal_provide_zoom_meeting_url": "Cal은 Zoom 회의 URL을 제공합니다.", "cal_provide_tandem_meeting_url": "Cal은 Tandem 회의 URL을 제공합니다.", "cal_provide_video_meeting_url": "Cal은 일일 화상 회의 URL을 제공합니다.", + "cal_provide_jitsi_meeting_url": "Cal은 Jitsi Meet 회의 URL을 제공합니다.", "cal_provide_huddle01_meeting_url": "Cal은 Huddle01 Web3 회의 URL을 제공합니다.", "require_payment": "지불 요청", "commission_per_transaction": "거래당 수수료", diff --git a/public/static/locales/nl/common.json b/public/static/locales/nl/common.json index 2ef5231f..ee56c094 100644 --- a/public/static/locales/nl/common.json +++ b/public/static/locales/nl/common.json @@ -482,6 +482,7 @@ "cal_provide_zoom_meeting_url": "Cal zal een Zoom meeting-URL meegeven in de afspraak bevestiging.", "cal_provide_tandem_meeting_url": "Cal zal een Tandem meeting-URL meegeven in de afspraak bevestiging.", "cal_provide_video_meeting_url": "Cal zal een Daily meeting-URL meegeven in de afspraak bevestiging.", + "cal_provide_jitsi_meeting_url": "Cal zal een Jitsi Meet meeting-URL meegeven in de afspraak bevestiging.", "cal_provide_huddle01_meeting_url": "Cal zal een Huddle01 web3 meeting-URL meegeven in de afspraak bevestiging.", "require_payment": "Betaling vereisen", "commission_per_transaction": "commissie per transactie", diff --git a/public/static/locales/pl/common.json b/public/static/locales/pl/common.json index 57a0d831..791c4b67 100644 --- a/public/static/locales/pl/common.json +++ b/public/static/locales/pl/common.json @@ -527,6 +527,7 @@ "cal_provide_google_meet_location": "Cal zapewni lokalizację Google Meet.", "cal_provide_zoom_meeting_url": "Cal zapewni URL spotkania Zoom.", "cal_provide_video_meeting_url": "Kal poda adres URL spotkania wideo platformy Daily.", + "cal_provide_jitsi_meeting_url": "Cal zapewni URL spotkania Jitsi Meet.", "cal_provide_huddle01_meeting_url": "Cal zapewni URL spotkania Huddle01 Web3.", "require_payment": "Wymagaj płatności", "commission_per_transaction": "prowizja za transakcję", diff --git a/public/static/locales/pt-BR/common.json b/public/static/locales/pt-BR/common.json index ebf69ab1..7e688aa5 100644 --- a/public/static/locales/pt-BR/common.json +++ b/public/static/locales/pt-BR/common.json @@ -528,6 +528,7 @@ "cal_provide_zoom_meeting_url": "Cal fornecerá uma URL de reunião do Zoom.", "cal_provide_tandem_meeting_url": "Cal fornecerá uma URL de reunião do Tandem.", "cal_provide_video_meeting_url": "O Cal irá fornecer um URL de reunião do Daily video.", + "cal_provide_jitsi_meeting_url": "O Cal irá fornecer um URL de reunião do Jitsi Meet.", "cal_provide_huddle01_meeting_url": "O Cal irá fornecer um URL de reunião do Huddle01 Web3 video.", "require_payment": "Requerer Pagamento", "commission_per_transaction": "comissão por transação", diff --git a/public/static/locales/pt/common.json b/public/static/locales/pt/common.json index 2018c35f..d3b10f85 100644 --- a/public/static/locales/pt/common.json +++ b/public/static/locales/pt/common.json @@ -559,6 +559,7 @@ "cal_provide_zoom_meeting_url": "O Cal irá fornecer um URL de reunião do Zoom.", "cal_provide_tandem_meeting_url": "O Cal irá fornecer um URL de reunião do Tandem.", "cal_provide_video_meeting_url": "O Cal irá fornecer um URL de reunião do Daily video.", + "cal_provide_jitsi_meeting_url": "O Cal irá fornecer um URL de reunião vídeo do Jitsi Meet.", "cal_provide_huddle01_meeting_url": "O Cal irá fornecer um URL de reunião vídeo do Huddle01 Web3.", "require_payment": "Requer Pagamento", "commission_per_transaction": "comissão por transação", diff --git a/public/static/locales/ro/common.json b/public/static/locales/ro/common.json index b23bc891..5a67aa91 100644 --- a/public/static/locales/ro/common.json +++ b/public/static/locales/ro/common.json @@ -489,6 +489,7 @@ "cal_provide_zoom_meeting_url": "Cal va oferi un URL pentru ședința de Zoom.", "cal_provide_tandem_meeting_url": "Cal va oferi un URL pentru ședința de Tandem.", "cal_provide_video_meeting_url": "Cal va oferi un URL pentru ședința de Daily.", + "cal_provide_jitsi_meeting_url": "Cal va oferi un URL pentru ședința de Jitsi Meet.", "cal_provide_huddle01_meeting_url": "Cal va oferi un URL pentru ședința de Huddle01 Web3.", "require_payment": "Solicită plata", "commission_per_transaction": "comision per tranzacție", diff --git a/public/static/locales/ru/common.json b/public/static/locales/ru/common.json index 827a1a4b..023a14c9 100644 --- a/public/static/locales/ru/common.json +++ b/public/static/locales/ru/common.json @@ -529,6 +529,7 @@ "cal_provide_zoom_meeting_url": "Cal создаст ссылку на встречу в Zoom.", "cal_provide_tandem_meeting_url": "Cal создаст ссылку на встречу в Tandem.", "cal_provide_video_meeting_url": "Cal создаст ссылку на встречу в Daily.", + "cal_provide_jitsi_meeting_url": "Cal создаст ссылку на встречу в Jitsi Meet.", "cal_provide_huddle01_meeting_url": "Cal создаст ссылку на встречу в Huddle01 Web3.", "require_payment": "Требуется оплата", "commission_per_transaction": "комиссия за сделку", diff --git a/public/static/locales/zh-CN/common.json b/public/static/locales/zh-CN/common.json index b64af2f7..36b7b86e 100644 --- a/public/static/locales/zh-CN/common.json +++ b/public/static/locales/zh-CN/common.json @@ -534,6 +534,7 @@ "cal_provide_google_meet_location": "Cal 将提供 Google Meet 位置。", "cal_provide_zoom_meeting_url": "Cal 将提供Zoom会议 URL", "cal_provide_video_meeting_url": "Cal 将提供Daily视频会议 URL", + "cal_provide_jitsi_meeting_url": "Cal 将提供Jitsi Meet视频会议 URL", "cal_provide_huddle01_meeting_url": "Cal 将提供Huddle01 Web3视频会议 URL", "require_payment": "需要付款", "commission_per_transaction": "每笔交易的佣金",