Merge branch 'main' into feat/organizations

This commit is contained in:
Leo Giovanetti 2023-06-02 17:01:31 -03:00
commit acda675519
12 changed files with 285 additions and 27 deletions

View File

@ -5,6 +5,8 @@ import Script from "next/script";
import "@calcom/embed-core/src/embed-iframe";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { buildCanonical } from "@calcom/lib/next-seo.config";
import type { AppProps } from "@lib/app-providers";
import AppProviders from "@lib/app-providers";
@ -49,9 +51,24 @@ function PageWrapper(props: AppProps) {
};
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page);
// Canonical: Check if the URL is from cal.com so that we set the canonical conditionally
const isCalcom =
WEBAPP_URL &&
(new URL(WEBAPP_URL).hostname.endsWith("cal.com") || new URL(WEBAPP_URL).hostname.endsWith("cal.dev"));
const path = router.asPath;
return (
<AppProviders {...providerProps}>
<DefaultSeo {...seoConfig.defaultNextSeo} />
<DefaultSeo
// Set canonical to https://cal.com or self-hosted URL
canonical={
isCalcom
? buildCanonical({ path, origin: "https://cal.com" }) // cal.com & .dev
: buildCanonical({ path, origin: WEBAPP_URL }) // self-hosted
}
{...seoConfig.defaultNextSeo}
/>
<I18nLanguageHandler />
<Script
nonce={nonce}

View File

@ -1340,6 +1340,7 @@
"exchange_version_2013_SP1": "2013 SP1",
"exchange_version_2015": "2015",
"exchange_version_2016": "2016",
"routing_forms_description": "أنشئ النماذج لتوجيه الحضور إلى الوجهات الصحيحة",
"routing_forms_send_email_owner": "إرسال رسالة إلكترونية إلى المالك",
"routing_forms_send_email_owner_description": "يرسل رسالة بريد إلكتروني إلى المالك عند إرسال النموذج",
"add_new_form": "إضافة استمارة جديدة",

View File

@ -26,6 +26,8 @@
"rejection_confirmation": "Buchung ablehnen",
"manage_this_event": "Diesen Termin verwalten",
"invite_team_member": "Teammitglied einladen",
"invite_team_individual_segment": "Person einladen",
"invite_team_bulk_segment": "Massenimport",
"invite_team_notifcation_badge": "Eing.",
"your_event_has_been_scheduled": "Ihr Termin wurde gebucht",
"your_event_has_been_scheduled_recurring": "Ihr wiederkehrender Termin wurde gebucht",
@ -239,6 +241,7 @@
"continue_without_calendar": "Ohne Kalender fortfahren",
"connect_your_calendar": "Kalender verbinden",
"connect_your_video_app": "Verbinden Sie Ihre Video-Apps",
"connect_your_video_app_instructions": "Verbinden Sie Ihre Video-Apps, um sie für Ihre Termintypen zu verwenden.",
"connect_your_calendar_instructions": "Verbinden Sie Ihren Kalender, um automatisch zu prüfen, ob Termine verfügbar sind.",
"set_up_later": "Später einrichten",
"current_time": "Aktuelle Zeit",
@ -368,6 +371,7 @@
"create_webhook": "Webhook erstellen",
"booking_cancelled": "Termin abgesagt",
"booking_rescheduled": "Termin verlegt",
"recording_ready": "Download-Link der Aufnahme bereit",
"booking_created": "Termin erstellt",
"meeting_ended": "Meeting beendet",
"form_submitted": "Formular gesendet",
@ -754,6 +758,10 @@
"new_event_type_to_book_description": "Erstellen Sie einen neuen Termintyp, mit dem Personen Zeiten buchen können.",
"length": "Länge",
"minimum_booking_notice": "Mindesvorlaufzeit für eine Buchung",
"offset_toggle": "Startzeiten versetzen",
"offset_toggle_description": "Um eine bestimmte Anzahl an Minuten versetzte Zeitfenster, die Buchern angezeigt werden",
"offset_start": "Versetzt um",
"offset_start_description": "z.B. wird dies Zeitfenster für Ihre Bucher um {{ adjustedTime }} statt {{ originalTime }} anzeigen",
"slot_interval": "Zeit-Slot-Intervalle",
"slot_interval_default": "Verwende Terminlänge (Standard)",
"delete_event_type": "Ereignistyp löschen?",
@ -906,6 +914,7 @@
"duplicate": "Duplizieren",
"offer_seats": "Plätze anbieten",
"offer_seats_description": "Bieten Sie Plätze für Buchungen an (dies deaktiviert Gäste & Opt-in-Buchungen)",
"seats_available_one": "Verfügbarer Platz",
"seats_available_other": "Verfügbare Plätze",
"number_of_seats": "Anzahl der Plätze pro Termin",
"enter_number_of_seats": "Anzahl der Plätze eingeben",
@ -1040,6 +1049,7 @@
"event_cancelled_trigger": "wenn das Ereignis abgesagt wird",
"new_event_trigger": "wenn ein neer Termin gebucht wird",
"email_host_action": "E-Mail an den Veranstalter senden",
"email_attendee_action": "E-Mail an Teilnehmende senden",
"sms_attendee_action": "SMS an Teilnehmende senden",
"sms_number_action": "SMS an eine bestimmte Nummer senden",
"workflows": "Workflows",
@ -1192,6 +1202,7 @@
"create_workflow": "Einen Workflow erstellen",
"do_this": "Mache dies",
"turn_off": "Abschalten",
"turn_on": "Einschalten",
"settings_updated_successfully": "Einstellungen erfolgreich aktualisiert",
"error_updating_settings": "Fehler beim Aktualisieren der Einstellungen",
"personal_cal_url": "Meine persönliche {{appName}}-URL",
@ -1248,6 +1259,7 @@
"calendars_description": "Konfigurieren Sie, wie Ihre Event-Typen mit Ihren Kalendern interagieren sollen",
"appearance_description": "Einstellungen für Ihre Buchungsdarstellung verwalten",
"conferencing_description": "Fügen Sie Ihre favorisierten Videokonferenz-Apps für Ihre Meetings hinzu",
"add_conferencing_app": "Konferenz-App hinzufügen",
"password_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
"2fa_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
"we_just_need_basic_info": "Wir benötigen nur ein paar grundlegende Informationen, um Ihr Profil einzurichten.",
@ -1622,6 +1634,7 @@
"email_user_cta": "Einladung anzeigen",
"email_no_user_invite_heading": "Sie wurden eingeladen, dem Team in {{appName}} beizutreten",
"email_no_user_invite_subheading": "{{invitedBy}} hat Sie eingeladen, dem Team in {{appName}} beizutreten. {{appName}} ist der Event-Planer, der es Ihnen und Ihrem Team ermöglicht, Meetings ohne ständiges hin und her zu planen.",
"email_user_invite_subheading": "{{invitedBy}} hat Sie eingeladen, dem Team „{{teamName}}“ beizutreten. {{appName}} ist der Event-Planer, der es Ihnen und Ihrem Team ermöglicht, Meetings ohne Hin und Her zu planen.",
"email_no_user_invite_steps_intro": "Wir begleiten Sie durch ein paar Schritte, danach können Sie stressfreie Planung mit Ihrem Team in kürzester Zeit genießen.",
"email_no_user_step_one": "Wählen Sie Ihren Benutzernamen",
"email_no_user_step_two": "Verbinden Sie Ihr Kalenderkonto",
@ -1697,7 +1710,15 @@
"spot_popular_event_types_description": "Sehen Sie, welche Ihrer Ereignistypen die meisten Klicks und Buchungen erhalten",
"no_responses_yet": "Noch keine Antworten",
"this_will_be_the_placeholder": "Dies wird der Platzhalter sein",
"error_booking_event": "Bei der Buchung dieses Termins ist ein Fehler aufgetreten, bitte aktualisieren Sie die Seite und versuchen Sie es erneut",
"timeslot_missing_title": "Kein Zeitfenster ausgewählt",
"timeslot_missing_description": "Bitte wählen Sie einen Zeitraum aus, um den Termin zu buchen.",
"timeslot_missing_cta": "Zeitfenster auswählen",
"switch_monthly": "Zur monatlichen Ansicht wechseln",
"switch_weekly": "Zur Wochenansicht wechseln",
"switch_multiday": "Zur Tagesansicht wechseln",
"num_locations": "{{num}} Standortoptionen",
"select_on_next_step": "Im nächsten Schritt auswählen",
"this_meeting_has_not_started_yet": "Dieses Meeting hat noch nicht begonnen",
"this_app_requires_connected_account": "{{appName}} benötigt ein verbundenes {{dependencyName}}-Konto",
"connect_app": "{{dependencyName}} verbinden",
@ -1727,6 +1748,7 @@
"locked_apps_description": "Mitglieder können die aktiven Apps sehen, können aber keine App-Einstellungen anpassen",
"locked_webhooks_description": "Mitglieder können die aktiven Webhooks sehen, können aber keine Webhook-Einstellungen anpassen",
"locked_workflows_description": "Mitglieder können die aktiven Workflows sehen, können aber keine Workflow-Einstellungen anpassen",
"locked_by_admin": "Vom Team-Admin gesperrt",
"app_not_connected": "Sie haben kein {{appName}}-Konto verbunden.",
"connect_now": "Jetzt verbinden",
"managed_event_dialog_confirm_button_one": "{{count}} Mitglied ersetzen & benachrichtigen",
@ -1784,5 +1806,34 @@
"seats_and_no_show_fee_error": "Aktuell können keine Plätze aktiviert oder eine Gebühr für das Nichterscheinen berechnet werden",
"complete_your_booking": "Schließen Sie Ihre Buchung ab",
"complete_your_booking_subject": "Schließen Sie Ihre Buchung ab: {{title}} am {{date}}",
"email_invite_team": "{{email}} wurde eingeladen"
"confirm_your_details": "Bestätigen Sie Ihre Daten",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Sie sind im Begriff, den Teilnehmer {{amount, currency}} in Rechnung zu stellen. Sind Sie sicher, dass Sie fortfahren möchten?",
"charge_attendee": "Teilnehmer {{amount, currency}} berechnen",
"payment_app_commission": "Zahlung erfordern ({{paymentFeePercentage}} % + {{fee, currency}} Provision pro Transaktion)",
"email_invite_team": "{{email}} wurde eingeladen",
"email_invite_team_bulk": "{{userCount}} Benutzer wurden eingeladen",
"error_collecting_card": "Fehler beim Erfassen der Karte",
"image_size_limit_exceed": "Das hochgeladene Bild sollte die maximale Größe von 5 MB nicht überschreiten",
"inline_embed": "Inline-Einbettung",
"load_inline_content": "Laden Sie Ihren Event-Typ direkt inline mit Ihren anderen Website-Inhalten.",
"floating_pop_up_button": "Schwebende Pop-Up-Schaltfläche",
"floating_button_trigger_modal": "Erstellt einen schwebenden Button auf Ihrer Website, der einen modalen Dialog mit Ihrem Termintypen erstellt.",
"pop_up_element_click": "Pop-Up über Element-Klick",
"open_dialog_with_element_click": "Öffnet Ihren Cal-Dialog, wenn jemand ein Element anklickt.",
"need_help_embedding": "Brauchen Sie Hilfe? Sehen Sie sich unsere Anleitungen zum Einbetten von Cal auf Wix, Squarespace, oder WordPress an, schauen Sie sich unsere häufig gestellten Fragen an oder erkunden Sie erweiterte Einbettungsoptionen.",
"book_my_cal": "Mein Cal buchen",
"invite_as": "Einladen als",
"form_updated_successfully": "Formular erfolgreich aktualisiert.",
"email_not_cal_member_cta": "Treten Sie Ihrem Team bei",
"disable_attendees_confirmation_emails": "Standardmäßige Bestätigungs-E-Mails für Teilnehmer deaktivieren",
"disable_attendees_confirmation_emails_description": "Mindestens ein Workflow ist für diesen Termintyp aktiv, welcher bei Buchung eine E-Mail an die Teilnehmer sendet.",
"disable_host_confirmation_emails": "Standardmäßige Bestätigungs-E-Mails für Veranstalter deaktivieren",
"disable_host_confirmation_emails_description": "Mindestens ein Workflow ist für diesen Termintyp aktiv, welcher bei Buchung eine E-Mail an den Veranstalter sendet.",
"add_an_override": "Eine Überschreibung hinzufügen",
"import_from_google_workspace": "Benutzer aus Google Workspace importieren",
"connect_google_workspace": "Google Workspace verbinden",
"google_workspace_admin_tooltip": "Sie müssen ein Workspace-Admin sein, um diese Funktion nutzen zu können",
"first_event_type_webhook_description": "Erstellen Sie Ihren ersten Webhook für diesen Termintypen",
"create_for": "Erstellen für"
}

View File

@ -26,6 +26,8 @@
"rejection_confirmation": "Refuser la réservation",
"manage_this_event": "Gérer cet événement",
"invite_team_member": "Inviter un membre d'équipe",
"invite_team_individual_segment": "Inviter une personne",
"invite_team_bulk_segment": "Importation multiple",
"invite_team_notifcation_badge": "Inv.",
"your_event_has_been_scheduled": "Votre événement a été planifié",
"your_event_has_been_scheduled_recurring": "Votre événement récurrent a été planifié",
@ -193,6 +195,7 @@
"page_doesnt_exist": "Cette page n'existe pas.",
"check_spelling_mistakes_or_go_back": "Vérifiez s'il y a des erreurs d'orthographe ou retournez à la page précédente.",
"404_page_not_found": "404 : Cette page est introuvable.",
"booker_event_not_found": "Nous n'avons pas pu trouver l'événement que vous essayez de réserver.",
"getting_started": "Commencer",
"15min_meeting": "Rendez-vous de 15 min",
"30min_meeting": "Rendez-vous de 30 min",
@ -222,6 +225,7 @@
"go_back_login": "Retour à la page de connexion",
"error_during_login": "Une erreur s'est produite lors de votre connexion. Retournez à l'écran de connexion et réessayez.",
"request_password_reset": "Envoyer l'email de réinitialisation",
"send_invite": "Envoyer l'invitation",
"forgot_password": "Mot de passe oublié ?",
"forgot": "Oublié ?",
"done": "Terminé",
@ -360,6 +364,7 @@
"user_dynamic_booking_disabled": "Certains utilisateurs du groupe ont actuellement désactivé les réservations de groupe dynamiques",
"allow_dynamic_booking_tooltip": "Les liens de réservation de groupe peuvent être créés dynamiquement en ajoutant plusieurs noms d'utilisateur séparés par un « + ». Exemple : « {{appName}}/bailey+peer ».",
"allow_dynamic_booking": "Autoriser les participants à prendre rendez-vous avec vous via des réservations de groupe dynamiques",
"dynamic_booking": "Liens de groupe dynamiques",
"email": "E-mail",
"email_placeholder": "jdoe@exemple.com",
"full_name": "Nom complet",
@ -370,6 +375,8 @@
"booking_rescheduled": "Réservation replanifiée",
"recording_ready": "Lien de téléchargement d'enregistrement prêt",
"booking_created": "Réservation créée",
"booking_rejected": "Réservation rejetée",
"booking_requested": "Réservation demandée",
"meeting_ended": "Rendez-vous terminé",
"form_submitted": "Formulaire envoyé",
"event_triggers": "Déclencheurs d'événement",
@ -503,7 +510,7 @@
"or": "OU",
"go_back": "Retour",
"email_or_username": "Adresse e-mail ou identifiant",
"send_invite_email": "Envoyer un e-mail d'invitation",
"send_invite_email": "Envoyer une invitation par e-mail",
"role": "Rôle",
"edit_role": "Modifier le rôle",
"edit_team": "Modifier l'équipe",
@ -755,6 +762,7 @@
"new_event_type_to_book_description": "Créez un nouveau type dévénement pour que les personnes puissent effectuer des réservations.",
"length": "Durée",
"minimum_booking_notice": "Préavis minimum",
"offset_start_description": "p. ex. cela affichera les créneaux à vos utilisateurs à {{ adjustedTime }} au lieu de {{ originalTime }}",
"slot_interval": "Fréquence de créneaux horaires",
"slot_interval_default": "Utiliser la durée de l'événement (par défaut)",
"delete_event_type": "Supprimer le type d'événement ?",
@ -789,7 +797,7 @@
"connect_your_favourite_apps": "Connectez vos applications favorites.",
"automation": "Automatisation",
"configure_how_your_event_types_interact": "Configurez la manière dont vos types d'événements doivent interagir avec vos calendriers.",
"toggle_calendars_conflict": "Activez/désactivez les calendriers pour lesquels vous souhaitez vérifier les conflits afin d'éviter les réservations en double.",
"toggle_calendars_conflict": "Activez/désactivez les calendriers pour lesquels vous souhaitez vérifier les conflits afin d'éviter les doubles réservations.",
"select_destination_calendar": "Créer des événements dans :",
"connect_additional_calendar": "Connecter un calendrier supplémentaire",
"calendar_updated_successfully": "Calendrier mis à jour avec succès",
@ -828,14 +836,14 @@
"installed_apps": "Apps installées",
"free_to_use_apps": "Gratuit",
"no_category_apps": "Aucune application {{category}}",
"no_category_apps_description_calendar": "Ajoutez une application de calendrier pour vérifier les conflits et éviter les réservations en double.",
"no_category_apps_description_calendar": "Ajoutez une application de calendrier pour vérifier les conflits et éviter les doubles réservations.",
"no_category_apps_description_conferencing": "Essayez d'ajouter une application de visioconférence pour intégrer les appels vidéo avec vos clients.",
"no_category_apps_description_payment": "Ajoutez une application de paiement pour faciliter les transactions entre vous et vos clients.",
"no_category_apps_description_analytics": "Ajoutez une application d'analyse pour vos pages de réservation.",
"no_category_apps_description_automation": "Ajoutez une application d'automatisation.",
"no_category_apps_description_other": "Ajoutez n'importe quel autre type d'application pour faire toutes sortes de choses.",
"no_category_apps_description_web3": "Ajoutez une application Web3 pour vos pages de réservation.",
"installed_app_calendar_description": "Définissez les calendriers pour vérifier les conflits afin d'éviter les réservations en double.",
"installed_app_calendar_description": "Définissez les calendriers pour vérifier les conflits afin d'éviter les doubles réservations.",
"installed_app_conferencing_description": "Ajoutez vos applications de visioconférence préférées pour vos rendez-vous.",
"installed_app_payment_description": "Configurez les services de traitement de paiement à utiliser lors de la facturation de vos clients.",
"installed_app_analytics_description": "Configurez les applications d'analyse à utiliser pour vos pages de réservation.",
@ -907,6 +915,7 @@
"duplicate": "Dupliquer",
"offer_seats": "Proposer des places",
"offer_seats_description": "Proposez des places de réservation. Cela désactive automatiquement les réservations d'invités et d'opt-in.",
"seats_available_one": "Place disponible",
"seats_available_other": "places disponibles",
"number_of_seats": "Nombre de places par réservation",
"enter_number_of_seats": "Saisir le nombre de sièges",
@ -1206,7 +1215,7 @@
"recordings_title": "Enregistrements",
"recording": "Enregistrement",
"happy_scheduling": "Bonne planification",
"select_calendars": "Sélectionnez les calendriers dont vous souhaitez vérifier les conflits afin d'éviter les réservations en double.",
"select_calendars": "Sélectionnez les calendriers dont vous souhaitez vérifier les conflits afin d'éviter les doubles réservations.",
"check_for_conflicts": "Vérifier les conflits",
"view_recordings": "Voir les enregistrements",
"adding_events_to": "Ajout d'événements",
@ -1804,15 +1813,26 @@
"charge_attendee": "Facturer {{amount, currency}} au participant",
"payment_app_commission": "Exiger un paiement ({{paymentFeePercentage}} % + {{fee, currency}} de commission par transaction)",
"email_invite_team": "{{email}} a été invité",
"email_invite_team_bulk": "{{userCount}} utilisateurs ont été invités",
"error_collecting_card": "Erreur lors de la collecte de la carte",
"image_size_limit_exceed": "L'image téléchargée ne doit pas dépasser 5 Mo",
"unauthorized_workflow_error_message": "{{errorCode}} : Vous n'êtes pas autorisé à activer ou désactiver ce workflow",
"inline_embed": "Intégration en ligne",
"load_inline_content": "Charge votre type d'événement directement en ligne avec le contenu de votre site web.",
"floating_pop_up_button": "Bouton pop-up flottant",
"need_help_embedding": "Besoin d'aide ? Consultez nos guides pour intégrer Cal sur Wix, Squarespace ou WordPress, consultez nos questions fréquentes ou explorez les options d'intégration avancées.",
"invite_as": "Inviter en tant que",
"form_updated_successfully": "Formulaire mis à jour avec succès.",
"email_not_cal_member_cta": "Rejoignez votre équipe",
"disable_attendees_confirmation_emails": "Désactiver les e-mails de confirmation par défaut pour les participants",
"disable_attendees_confirmation_emails_description": "Au moins un workflow est actif sur ce type d'événement qui envoie un e-mail aux participants lorsque l'événement est réservé.",
"disable_host_confirmation_emails": "Désactiver les e-mails de confirmation par défaut pour l'hôte",
"disable_host_confirmation_emails_description": "Au moins un workflow est actif sur ce type d'événement qui envoie un e-mail à l'hôte lorsque l'événement est réservé."
"disable_host_confirmation_emails_description": "Au moins un workflow est actif sur ce type d'événement qui envoie un e-mail à l'hôte lorsque l'événement est réservé.",
"add_an_override": "Ajouter une superposition",
"import_from_google_workspace": "Importer des utilisateurs depuis Google Workspace",
"connect_google_workspace": "Connecter Google Workspace",
"first_event_type_webhook_description": "Créez votre premier webhook pour ce type d'événement",
"create_for": "Créer pour",
"additional_url_parameters": "Paramètres d'URL supplémentaires",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Ajoutez vos nouvelles chaînes ci-dessus ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}

View File

@ -26,6 +26,7 @@
"rejection_confirmation": "Odrzuć prośbę o rezerwację",
"manage_this_event": "Zarządzaj wydarzeniem",
"invite_team_member": "Zaproś członka zespołu",
"invite_team_individual_segment": "Zaproś pojedynczą osobę",
"invite_team_bulk_segment": "Import zbiorczy",
"invite_team_notifcation_badge": "Zap.",
"your_event_has_been_scheduled": "Zaplanowano wydarzenie",
@ -757,9 +758,10 @@
"new_event_type_to_book_description": "Utwórz nowy typ wydarzenia, z którym ludzie mogą rezerwować czasy.",
"length": "Długość",
"minimum_booking_notice": "Minimalne powiadomienie",
"offset_toggle": "Opóźnij czasy rozpoczęcia",
"offset_toggle": "Przesuń czasy rozpoczęcia",
"offset_toggle_description": "Przesuń przedziały czasowe wyświetlane rezerwującym o określoną liczbę minut",
"offset_start": "Przesuń o",
"offset_start_description": "np. przedziały czasowe do rezerwacji będą dostępne o godz. {{ adjustedTime }} zamiast o {{ originalTime }}.",
"slot_interval": "Przedziały czasowe",
"slot_interval_default": "Użyj długości zdarzenia (domyślnie)",
"delete_event_type": "Usunąć typ wydarzenia?",
@ -1632,6 +1634,7 @@
"email_user_cta": "Wyświetl zaproszenie",
"email_no_user_invite_heading": "Zaproszono Cię do dołączenia do zespołu w aplikacji {{appName}}",
"email_no_user_invite_subheading": "Użytkownik {{invitedBy}} zaprasza Cię do dołączenia do jego zespołu w aplikacji {{appName}}. Aplikacja {{appName}} to terminarz do planowania wydarzeń, który umożliwi Tobie i Twojemu zespołowi planowanie spotkań bez czasochłonnej wymiany wiadomości e-mail.",
"email_user_invite_subheading": "Użytkownik {{invitedBy}} zaprasza Cię do dołączenia do jego zespołu „{{teamName}}” w aplikacji {{appName}}. Aplikacja {{appName}} to terminarz do planowania wydarzeń, który umożliwi Tobie i Twojemu zespołowi planowanie spotkań bez czasochłonnej wymiany wiadomości e-mail.",
"email_no_user_invite_steps_intro": "Przeprowadzimy Cię przez kilka krótkich etapów i wkrótce zaczniesz z przyjemnością korzystać z bezstresowego narzędzia planowania.",
"email_no_user_step_one": "Wybierz nazwę użytkownika",
"email_no_user_step_two": "Połącz swoje konto kalendarza",
@ -1707,6 +1710,7 @@
"spot_popular_event_types_description": "Zobacz, które typy wydarzeń są najczęściej klikane i rezerwowane",
"no_responses_yet": "Nie ma jeszcze odpowiedzi",
"this_will_be_the_placeholder": "To będzie symbol zastępczy",
"error_booking_event": "Podczas rezerwacji wydarzenia wystąpił błąd, odśwież stronę i spróbuj ponownie.",
"timeslot_missing_title": "Nie wybrano przedziału czasowego",
"timeslot_missing_description": "Wybierz przedział czasowy, aby zarezerwować wydarzenie.",
"timeslot_missing_cta": "Wybierz przedział czasowy",
@ -1811,11 +1815,25 @@
"email_invite_team_bulk": "Zaproszono {{userCount}} użytkowników",
"error_collecting_card": "Błąd podczas pobierania karty",
"image_size_limit_exceed": "Przesłany obraz nie powinien być większy niż 5 MB.",
"inline_embed": "Osadź na stronie",
"load_inline_content": "Wczytuje typ wydarzenia bezpośrednio w treści Twojej strony internetowej.",
"floating_pop_up_button": "Pływający przycisk wyskakujący",
"floating_button_trigger_modal": "Wstawia na stronie przycisk pływający, który umożliwia wywołanie okna modalnego z typem wydarzenia.",
"pop_up_element_click": "Wyskakujące okienko po kliknięciu elementu",
"open_dialog_with_element_click": "Otwiera okno dialogowe Cal, gdy użytkownik kliknie odpowiedni element.",
"need_help_embedding": "Potrzebujesz pomocy? Zapoznaj się z naszymi instrukcjami osadzania narzędzi Cal na stronach stworzonych w usługach Wix, Squarespace lub WordPress, sprawdź często zadawane pytania lub poznaj zaawansowane opcje osadzania.",
"book_my_cal": "Zarezerwuj w moim kalendarzu",
"invite_as": "Zaproś jako",
"form_updated_successfully": "Formularz zaktualizowany pomyślnie.",
"email_not_cal_member_cta": "Dołącz do zespołu",
"disable_attendees_confirmation_emails": "Wyłącz domyślne wiadomości e-mail z potwierdzeniem dla uczestników",
"disable_attendees_confirmation_emails_description": "W tym typie wydarzenia aktywny jest co najmniej jeden przepływ pracy, który wysyła wiadomość e-mail do uczestników, gdy wydarzenie zostanie zarezerwowane.",
"disable_host_confirmation_emails": "Wyłącz domyślne wiadomości e-mail z potwierdzeniem dla gospodarza",
"disable_host_confirmation_emails_description": "W tym typie wydarzenia aktywny jest co najmniej jeden przepływ pracy, który wysyła wiadomość e-mail do gospodarza, gdy wydarzenie zostanie zarezerwowane.",
"add_an_override": "Dodaj zastąpienie",
"import_from_google_workspace": "Importuj użytkowników z usługi Google Workspace",
"connect_google_workspace": "Połącz usługę Google Workspace",
"google_workspace_admin_tooltip": "Aby skorzystać z tej funkcji, musisz być administratorem usługi Workspace.",
"first_event_type_webhook_description": "Utwórz swój pierwszy element webhook dla tego typu wydarzenia",
"create_for": "Utwórz dla"
}

View File

@ -26,6 +26,8 @@
"rejection_confirmation": "Отказаться от бронирования",
"manage_this_event": "Управление этой встречей",
"invite_team_member": "Пригласить участника команды",
"invite_team_individual_segment": "Пригласить пользователя",
"invite_team_bulk_segment": "Массовый импорт",
"invite_team_notifcation_badge": "Прг.",
"your_event_has_been_scheduled": "Запланирована новая встреча",
"your_event_has_been_scheduled_recurring": "Повторяющееся событие запланировано",
@ -222,6 +224,7 @@
"go_back_login": "Вернуться на страницу входа",
"error_during_login": "Произошла ошибка при входе в систему. Вернитесь на экран входа и повторите попытку.",
"request_password_reset": "Запросить сброс пароля",
"send_invite": "Отправить приглашение",
"forgot_password": "Восстановить пароль",
"forgot": "Забыли пароль?",
"done": "Готово",
@ -237,6 +240,8 @@
"set_availability": "Задайте время в которое вы доступны",
"continue_without_calendar": "Продолжить без подключения календаря",
"connect_your_calendar": "Подключите календарь",
"connect_your_video_app": "Подключите приложения для просмотра видео",
"connect_your_video_app_instructions": "Подключите приложения для просмотра видео и используйте их для разных типов событий.",
"connect_your_calendar_instructions": "Подключите календарь чтобы автоматически отслеживать вашу занятость при создании встреч.",
"set_up_later": "Настроить позже",
"current_time": "Текущее время",
@ -366,6 +371,7 @@
"create_webhook": "Создать веб-хук",
"booking_cancelled": "Бронирование отменено",
"booking_rescheduled": "Бронирование изменено",
"recording_ready": "Готова ссылка для загрузки записи",
"booking_created": "Бронирование создано",
"meeting_ended": "Встреча завершилась",
"form_submitted": "Форма отправлена",
@ -464,6 +470,7 @@
"friday": "Пятница",
"saturday": "Суббота",
"sunday": "Воскресенье",
"all_booked_today": "Всё забронировано.",
"slots_load_fail": "Не удалось загрузить доступные временные интервалы.",
"additional_guests": "Добавить гостей",
"your_name": "Ваше имя",
@ -751,6 +758,10 @@
"new_event_type_to_book_description": "Создайте новый тип мероприятия, с помощью которого люди смогут забронировать время.",
"length": "Продолжительность",
"minimum_booking_notice": "Минимальный срок уведомления о встрече",
"offset_toggle": "Скорректировать время начала",
"offset_toggle_description": "Откорректировать на указанное количество минут интервалы времени, которые видят пользователи, оформляющие бронирование",
"offset_start": "Скорректировать на",
"offset_start_description": "Например, в этом случае пользователи, оформляющие бронирование, будут видеть интервалы времени {{ adjustedTime }}, а не {{ originalTime }}",
"slot_interval": "Интервалы времени",
"slot_interval_default": "Использовать длину события (по умолчанию)",
"delete_event_type": "Удалить тип события?",
@ -903,6 +914,7 @@
"duplicate": "Создать копию",
"offer_seats": "Предложить места",
"offer_seats_description": "Предлагать места при бронировании (данная настройка автоматически отключает гостевой режим и бронирование с подтверждением).",
"seats_available_one": "Доступное место",
"seats_available_other": "Доступные места",
"number_of_seats": "Количество мест на одну бронь",
"enter_number_of_seats": "Укажите количество мест",
@ -1037,6 +1049,7 @@
"event_cancelled_trigger": "когда событие отменено",
"new_event_trigger": "когда будет забронировано новое событие",
"email_host_action": "отправить письмо организатору",
"email_attendee_action": "отправить письмо участникам",
"sms_attendee_action": "отправить SMS-сообщение участнику",
"sms_number_action": "отправка SMS-сообщение на указанный номер",
"workflows": "Рабочие процессы",
@ -1189,6 +1202,7 @@
"create_workflow": "Создать рабочий процесс",
"do_this": "Сделать",
"turn_off": "Выключить",
"turn_on": "Включить",
"settings_updated_successfully": "Настройки успешно обновлены",
"error_updating_settings": "Ошибка при обновлении настроек",
"personal_cal_url": "URL-адрес моего персонального {{appName}}",
@ -1245,6 +1259,7 @@
"calendars_description": "Настройка взаимодействия типов событий с календарями",
"appearance_description": "Настройка внешнего вида страниц бронирования",
"conferencing_description": "Настройка приложений для видеоконференций, используемых для проведения онлайн-встреч",
"add_conferencing_app": "Добавить приложение для видеоконференций",
"password_description": "Настройка паролей для аккаунта",
"2fa_description": "Настройка паролей для аккаунта",
"we_just_need_basic_info": "Для настройки вашего профиля необходимо указать основную информацию.",
@ -1619,6 +1634,7 @@
"email_user_cta": "Посмотреть приглашение",
"email_no_user_invite_heading": "Вас пригласили в команду {{appName}}",
"email_no_user_invite_subheading": "{{invitedBy}} пригласил(-а) вас в команду в {{appName}}. {{appName}} — это гибкий планировщик событий, с помощью которого пользователи и целые команды могут планировать встречи без утомительной переписки по электронной почте.",
"email_user_invite_subheading": "{{invitedBy}} пригласил(а) вас в команду в `{{teamName}}` в приложении {{appName}}. {{appName}} — это гибкий планировщик событий, с помощью которого пользователи и целые команды могут планировать встречи без утомительной переписки по электронной почте.",
"email_no_user_invite_steps_intro": "Всего несколько шагов — и вы сможете оперативно и без стресса планировать встречи с командой.",
"email_no_user_step_one": "Выберите имя пользователя",
"email_no_user_step_two": "Подключите аккаунт календаря",
@ -1694,6 +1710,15 @@
"spot_popular_event_types_description": "Узнайте, какие типы событий собирают больше всего кликов и бронирований",
"no_responses_yet": "Ответов пока нет",
"this_will_be_the_placeholder": "Это текст-заполнитель",
"error_booking_event": "При бронировании события произошла ошибка. Обновите страницу и повторите попытку",
"timeslot_missing_title": "Не выбран интервал времени",
"timeslot_missing_description": "Чтобы забронировать событие, выберите интервал времени.",
"timeslot_missing_cta": "Выбрать интервал времени",
"switch_monthly": "Перейти в режим «месяц»",
"switch_weekly": "Перейти в режим «неделя»",
"switch_multiday": "Перейти в режим «день»",
"num_locations": "Варианты местоположений: {{num}}",
"select_on_next_step": "Выбрать на следующем этапе",
"this_meeting_has_not_started_yet": "Эта встреча еще не началась",
"this_app_requires_connected_account": "Для {{appName}} требуется подключенный аккаунт {{dependencyName}}",
"connect_app": "Подключить {{dependencyName}}",
@ -1723,6 +1748,7 @@
"locked_apps_description": "Участники смогут видеть активные приложения, но не смогут редактировать их настройки",
"locked_webhooks_description": "Участники смогут видеть активные вебхуки, но не смогут редактировать их настройки",
"locked_workflows_description": "Участники смогут видеть активные рабочие процессы, но не смогут редактировать их настройки",
"locked_by_admin": "Заблокировано администратором команды",
"app_not_connected": "Вы не подключили аккаунт {{appName}}.",
"connect_now": "Подключить",
"managed_event_dialog_confirm_button_one": "Заменить и уведомить {{count}} участника",
@ -1780,5 +1806,34 @@
"seats_and_no_show_fee_error": "Списание платы за неявку при использовании выбора места в настоящее время не поддерживается",
"complete_your_booking": "Завершить бронирование",
"complete_your_booking_subject": "Завершите бронирование: {{title}}, {{date}}",
"email_invite_team": "Участник {{email}} приглашен(а)"
"confirm_your_details": "Подтвердите свои данные",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Вы собираетесь получить с участника {{amount, currency}}. Продолжить?",
"charge_attendee": "Получить с участника {{amount, currency}}",
"payment_app_commission": "Необходима оплата: ({{paymentFeePercentage}}% + комиссия за операцию {{fee, currency}})",
"email_invite_team": "Участник {{email}} приглашен(а)",
"email_invite_team_bulk": "Приглашено пользователей: {{userCount}}",
"error_collecting_card": "Карточка ошибок",
"image_size_limit_exceed": "Размер загружаемого изображения не должен превышать 5 Мб",
"inline_embed": "Встроить",
"load_inline_content": "Загрузите тип события на сайт вместе с другим контентом.",
"floating_pop_up_button": "Плавающая кнопка",
"floating_button_trigger_modal": "Размещает на сайте плавающую кнопку, которая открывает модальное окно с типом события.",
"pop_up_element_click": "Окно, всплывающее при нажатии на элемент",
"open_dialog_with_element_click": "Открыть диалог Cal при нажатии на элемент.",
"need_help_embedding": "Нужна помощь? Воспользуйтесь нашими руководствами, чтобы узнать, как встроить Cal в Wix, Squarespace или WordPress, изучите часто встречающиеся вопросы или расширенные возможности интеграции.",
"book_my_cal": "Забронировать в Cal",
"invite_as": "Пригласить как",
"form_updated_successfully": "Форма успешно обновлена.",
"email_not_cal_member_cta": "Присоединиться к команде",
"disable_attendees_confirmation_emails": "Отключить для участников подтверждение по электронной почте по умолчанию",
"disable_attendees_confirmation_emails_description": "В этом типе события активен по крайней мере один рабочий процесс, который при бронировании события отправляет участникам сообщение по электронной почте.",
"disable_host_confirmation_emails": "Отключить для организатора подтверждение по электронной почте по умолчанию",
"disable_host_confirmation_emails_description": "В этом типе события активен по крайней мере один рабочий процесс, который при бронировании события отправляет организатору сообщение по электронной почте.",
"add_an_override": "Добавить переопределение",
"import_from_google_workspace": "Импортировать пользователей из Google Workspace",
"connect_google_workspace": "Подключить Google Workspace",
"google_workspace_admin_tooltip": "Эту функцию может использовать только администратор Workspace",
"first_event_type_webhook_description": "Создайте первый вебхук для этого типа событий",
"create_for": "Создать для"
}

View File

@ -26,6 +26,8 @@
"rejection_confirmation": "拒絕預約",
"manage_this_event": "管理活動",
"invite_team_member": "邀請團隊成員",
"invite_team_individual_segment": "邀請個人",
"invite_team_bulk_segment": "大量匯入",
"invite_team_notifcation_badge": "邀請",
"your_event_has_been_scheduled": "活動已預定時間",
"your_event_has_been_scheduled_recurring": "您的定期活動已預定",
@ -222,6 +224,7 @@
"go_back_login": "回到登入頁面",
"error_during_login": "登入的時候發生錯誤。請回到登入畫面,再試一次。",
"request_password_reset": "要求重設密碼",
"send_invite": "傳送邀請",
"forgot_password": "忘記密碼",
"forgot": "忘記了?",
"done": "完成",
@ -237,6 +240,8 @@
"set_availability": "設定開放時間",
"continue_without_calendar": "在沒有行事曆的情況下繼續",
"connect_your_calendar": "連結行事曆",
"connect_your_video_app": "連結視訊應用程式",
"connect_your_video_app_instructions": "連結視訊應用程式,以便用於活動類型。",
"connect_your_calendar_instructions": "連結行事曆之後,就可以在預約時,自動檢查忙碌時段和新活動。",
"set_up_later": "稍後設定",
"current_time": "現在時間",
@ -366,6 +371,7 @@
"create_webhook": "建立 Webhook",
"booking_cancelled": "預約已取消",
"booking_rescheduled": "已重新安排預約",
"recording_ready": "錄製內容下載連結已準備就緒",
"booking_created": "已建立預約",
"meeting_ended": "會議已結束",
"form_submitted": "表單已提交",
@ -464,6 +470,7 @@
"friday": "星期五",
"saturday": "星期六",
"sunday": "星期日",
"all_booked_today": "全部已預約。",
"slots_load_fail": "無法讀取剩下的時間區間。",
"additional_guests": "新增賓客",
"your_name": "名字",
@ -751,6 +758,10 @@
"new_event_type_to_book_description": "新增大家可以用來預約時段的活動類型。",
"length": "長度",
"minimum_booking_notice": "最晚預約通知",
"offset_toggle": "偏移開始時間",
"offset_toggle_description": "針對向預約者顯示的時段偏移指定的分鐘數",
"offset_start": "偏移時間",
"offset_start_description": "例如,這麼做會向您的預約者顯示 {{ adjustedTime }},而非 {{ originalTime }}",
"slot_interval": "時間單位",
"slot_interval_default": "使用活動長度(預設)",
"delete_event_type": "要刪除活動類型嗎?",
@ -903,6 +914,7 @@
"duplicate": "複製",
"offer_seats": "提供座位",
"offer_seats_description": "為預約提供座位 (這將停用賓客和選擇加入的預約)",
"seats_available_one": "可用座位",
"seats_available_other": "尚有座位",
"number_of_seats": "每次預約的座位數",
"enter_number_of_seats": "輸入座位數",
@ -1037,6 +1049,7 @@
"event_cancelled_trigger": "活動取消時",
"new_event_trigger": "預約新活動時",
"email_host_action": "傳送電子郵件給主辦者",
"email_attendee_action": "傳送電子郵件給與會者",
"sms_attendee_action": "傳送簡訊給與會者",
"sms_number_action": "傳送簡訊至特定號碼",
"workflows": "工作流程",
@ -1189,6 +1202,7 @@
"create_workflow": "建立工作流程",
"do_this": "執行此操作",
"turn_off": "關閉",
"turn_on": "開啟",
"settings_updated_successfully": "成功更新設定",
"error_updating_settings": "更新設定時發生錯誤",
"personal_cal_url": "我的個人 {{appName}} 網址",
@ -1245,6 +1259,7 @@
"calendars_description": "設定活動類型跟行事曆互動的方式",
"appearance_description": "管理預約外觀設定",
"conferencing_description": "為您的會議加入最愛的視訊會議應用程式",
"add_conferencing_app": "新增會議應用程式",
"password_description": "管理帳號密碼設定",
"2fa_description": "管理帳號密碼設定",
"we_just_need_basic_info": "我們只需要一些基本資料,就能完成您的個人資料設定。",
@ -1619,6 +1634,7 @@
"email_user_cta": "檢視邀請",
"email_no_user_invite_heading": "您已獲邀加入 {{appName}} 上的團隊",
"email_no_user_invite_subheading": "{{invitedBy}} 已邀請您加入對方在 {{appName}} 上的團隊。{{appName}} 是活動多工排程工具,可讓您和您的團隊無須透過繁複的電子郵件往來就能輕鬆預定會議。",
"email_user_invite_subheading": "{{invitedBy}} 已邀請您加入對方在 {{appName}} 上的「{{teamName}}」團隊。{{appName}} 為一款活動多功能排程工具,可讓您和團隊無須透過繁複的電子郵件往來,就能輕鬆預定會議。",
"email_no_user_invite_steps_intro": "我們會逐步引導您完成幾個簡短的步驟,然後您就能馬上與團隊享受沒有壓力的排程預定功能。",
"email_no_user_step_one": "選擇使用者名稱",
"email_no_user_step_two": "連結行事曆帳號",
@ -1694,6 +1710,15 @@
"spot_popular_event_types_description": "查看哪種活動類型的點閱次數及預約次數最多",
"no_responses_yet": "還沒有回應",
"this_will_be_the_placeholder": "此處會是佔位符",
"error_booking_event": "預約活動時發生錯誤,請重新整理頁面然後再試一次",
"timeslot_missing_title": "未選擇任何時段",
"timeslot_missing_description": "請選擇要預約活動的時段。",
"timeslot_missing_cta": "選擇時段",
"switch_monthly": "切換至每月檢視",
"switch_weekly": "切換至每週檢視",
"switch_multiday": "切換至每日檢視",
"num_locations": "{{num}} 個地點選項",
"select_on_next_step": "於下一步選擇",
"this_meeting_has_not_started_yet": "此會議尚未開始",
"this_app_requires_connected_account": "{{appName}} 需要已連結的 {{dependencyName}} 帳號",
"connect_app": "連結 {{dependencyName}}",
@ -1723,6 +1748,7 @@
"locked_apps_description": "成員將能查看啟用的應用程式,但無法編輯任何應用程式設定",
"locked_webhooks_description": "成員將能查看啟用的 Webhook但無法編輯任何 Webhook 設定",
"locked_workflows_description": "成員將能查看啟用的工作流程,但無法編輯任何工作流程設定",
"locked_by_admin": "已由團隊管理員鎖定",
"app_not_connected": "您尚未連結 {{appName}} 帳號。",
"connect_now": "立即連結",
"managed_event_dialog_confirm_button_one": "取代並通知 {{count}} 位成員",
@ -1780,5 +1806,34 @@
"seats_and_no_show_fee_error": "目前無法啟用座位並收取缺席費",
"complete_your_booking": "完成您的預約",
"complete_your_booking_subject": "完成您的預約:{{date}} 的 {{title}}",
"email_invite_team": "已邀請 {{email}}"
"confirm_your_details": "確認詳細資料",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "您即將向與會者收取 {{amount, currency}}。確定要繼續嗎?",
"charge_attendee": "向與會者收取 {{amount, currency}}",
"payment_app_commission": "需付款 (每筆交易佣金為 {{paymentFeePercentage}}% + {{fee, currency}})",
"email_invite_team": "已邀請 {{email}}",
"email_invite_team_bulk": "已邀請 {{userCount}} 位使用者",
"error_collecting_card": "收集卡片時發生錯誤",
"image_size_limit_exceed": "上傳的圖片大小不得超過 5MB 限制",
"inline_embed": "內嵌式嵌入",
"load_inline_content": "直接與其他網站內容內嵌式載入您的活動類型。",
"floating_pop_up_button": "浮動式彈出按鈕",
"floating_button_trigger_modal": "在網站上放置浮動式按鈕,以根據活動類型觸發強制回應。",
"pop_up_element_click": "透過點閱元素彈出",
"open_dialog_with_element_click": "有人按一下元素即開啟 Cal 對話方塊。",
"need_help_embedding": "需要協助嗎?歡迎查看我們的指南了解如何在 Wix、Squarespace 或 WordPress 上嵌入 Cal也歡迎參閱我們的常見問題或探索進階嵌入方案。",
"book_my_cal": "預約我的 Cal",
"invite_as": "以下列身分邀請:",
"form_updated_successfully": "表單更新成功。",
"email_not_cal_member_cta": "加入您的團隊",
"disable_attendees_confirmation_emails": "為與會者停用預設確認電子郵件",
"disable_attendees_confirmation_emails_description": "預約活動時,此活動類型至少要啟用一個工作流程來傳送電子郵件給與會者。",
"disable_host_confirmation_emails": "為主辦人停用預設確認電子郵件",
"disable_host_confirmation_emails_description": "預約活動時,此活動類型至少要啟用一個工作流程來傳送電子郵件給主辦人。",
"add_an_override": "新增覆寫",
"import_from_google_workspace": "從 Google Workspace 匯入使用者",
"connect_google_workspace": "連結 Google Workspace",
"google_workspace_admin_tooltip": "您必須是 Workspace 管理員才能使用此功能",
"first_event_type_webhook_description": "為此活動類型建立第一個 Webhook",
"create_for": "適用目標"
}

View File

@ -468,6 +468,13 @@ function getBookingData({
if (val.responses) {
const unwantedProps: string[] = [];
legacyProps.forEach((legacyProp) => {
if (typeof val[legacyProp as keyof typeof val] !== "undefined") {
console.error(
`Deprecated: Unexpected falsy value for: ${unwantedProps.join(
","
)}. They can't be used with \`responses\`. This will become a 400 error in the future.`
);
}
if (val[legacyProp as keyof typeof val]) {
unwantedProps.push(legacyProp);
}
@ -489,7 +496,24 @@ function getBookingData({
}
}
});
const reqBody = bookingDataSchema.parse(req.body);
// Work with Typescript to require reqBody.end
type ReqBodyWithoutEnd = z.infer<typeof bookingDataSchema>;
type ReqBodyWithEnd = ReqBodyWithoutEnd & { end: string };
const reqBodyWithEnd = (reqBody: ReqBodyWithoutEnd): reqBody is ReqBodyWithEnd => {
// Use the event length to auto-set the event end time.
if (!Object.prototype.hasOwnProperty.call(reqBody, "end")) {
reqBody.end = dayjs.utc(reqBody.start).add(eventType.length, "minutes").format();
}
return true;
};
if (!reqBodyWithEnd(reqBody)) {
throw new Error("Internal Error.");
}
// reqBody.end is no longer an optional property.
if ("customInputs" in reqBody) {
if (reqBody.customInputs) {
// Check if required custom inputs exist
@ -667,7 +691,7 @@ async function handler(
metadata: true,
},
})
: !!eventType.hosts?.length
: eventType.hosts?.length
? eventType.hosts.map(({ user, isFixed }) => ({
...user,
isFixed,
@ -731,14 +755,17 @@ async function handler(
defaultLocationUrl = firstUsersMetadata?.defaultConferencingApp?.appLink;
}
if (eventType && eventType.hasOwnProperty("bookingLimits") && eventType?.bookingLimits) {
if (
Object.prototype.hasOwnProperty.call(eventType, "bookingLimits") ||
Object.prototype.hasOwnProperty.call(eventType, "durationLimits")
) {
const startAsDate = dayjs(reqBody.start).toDate();
await checkBookingLimits(eventType.bookingLimits, startAsDate, eventType.id);
}
if (eventType && eventType.hasOwnProperty("durationLimits") && eventType?.durationLimits) {
const startAsDate = dayjs(reqBody.start).toDate();
await checkDurationLimits(eventType.durationLimits, startAsDate, eventType.id);
if (eventType.bookingLimits) {
await checkBookingLimits(eventType.bookingLimits, startAsDate, eventType.id);
}
if (eventType.durationLimits) {
await checkDurationLimits(eventType.durationLimits, startAsDate, eventType.id);
}
}
if (!eventType.seatsPerTimeSlot) {
@ -911,7 +938,7 @@ async function handler(
requiresConfirmation: requiresConfirmation ?? false,
eventTypeId: eventType.id,
// if seats are not enabled we should default true
seatsShowAttendees: !!eventType.seatsPerTimeSlot ? eventType.seatsShowAttendees : true,
seatsShowAttendees: eventType.seatsPerTimeSlot ? eventType.seatsShowAttendees : true,
seatsPerTimeSlot: eventType.seatsPerTimeSlot,
};

View File

@ -4,6 +4,7 @@ type BrowserInfo = {
referrer: string;
title: string;
query: string;
origin: string;
};
export const getBrowserInfo = (): Partial<BrowserInfo> => {
@ -16,5 +17,6 @@ export const getBrowserInfo = (): Partial<BrowserInfo> => {
referrer: window.document?.referrer ?? undefined,
title: window.document.title ?? undefined,
query: window.document.location?.search,
origin: window.document.location?.origin,
};
};

View File

@ -1,4 +1,5 @@
import type { DefaultSeoProps, NextSeoProps } from "next-seo";
import type { Router } from "next/router";
import { APP_NAME, SEO_IMG_DEFAULT, SEO_IMG_OGIMG } from "@calcom/lib/constants";
@ -39,3 +40,13 @@ export const seoConfig: {
},
},
} as const;
/**
* This function builds a canonical URL from a given host and path omitting the query params. Note: on homepage it omits the trailing slash
* @param origin The protocol + host, e.g. `https://cal.com` or `https://cal.dev`
* @param path NextJS' useRouter().asPath
* @returns
*/
export const buildCanonical = ({ origin, path }: { origin: Location["origin"]; path: Router["asPath"] }) => {
return `${origin}${path === "/" ? "" : path}`.split("?")[0];
};

View File

@ -161,7 +161,7 @@ export const stringOrNumber = z.union([
export const stringToDayjs = z.string().transform((val) => dayjs(val));
export const bookingCreateBodySchema = z.object({
end: z.string(),
end: z.string().optional(),
eventTypeId: z.number(),
eventTypeSlug: z.string().optional(),
rescheduleUid: z.string().optional(),

View File

@ -6,8 +6,8 @@ import { useRouter } from "next/router";
import type { AppImageProps, MeetingImageProps } from "@calcom/lib/OgImages";
import { constructAppImage, constructGenericImage, constructMeetingImage } from "@calcom/lib/OgImages";
import { getBrowserInfo } from "@calcom/lib/browser/browser.utils";
import { APP_NAME } from "@calcom/lib/constants";
import { seoConfig, getSeoImage } from "@calcom/lib/next-seo.config";
import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
import { seoConfig, getSeoImage, buildCanonical } from "@calcom/lib/next-seo.config";
import { truncateOnWord } from "@calcom/lib/text";
export type HeadSeoProps = {
@ -73,16 +73,17 @@ export const HeadSeo = (props: HeadSeoProps): JSX.Element => {
// The below code sets the defaultUrl for our canonical tags
// Get the current URL from the window object
const url = getBrowserInfo()?.url;
const { url } = getBrowserInfo();
// Check if the URL is from cal.com
const isCalcom =
url && (new URL(url).hostname.endsWith("cal.com") || new URL(url).hostname.endsWith("cal.dev"));
// Get the router's path
const path = useRouter().asPath;
// Build the canonical URL using the router's path, without query parameters. Note: on homepage it omits the trailing slash
const calcomCanonical = `https://cal.com${path === "/" ? "" : path}`.split("?")[0];
const selfHostedOrigin = WEBSITE_URL || "https://cal.com";
// Set the default URL to either the current URL (if self-hosted) or https://cal.com canonical URL
const defaultUrl = isCalcom ? calcomCanonical : url;
const defaultUrl = isCalcom
? buildCanonical({ path, origin: "https://cal.com" })
: buildCanonical({ path, origin: selfHostedOrigin });
const {
title,