Merge branch 'main' into refactor-event-types-type-id-10419-cal-2264-cal-2296

This commit is contained in:
Peer Richelsen 2023-09-04 15:42:24 +02:00 committed by GitHub
commit b48934b126
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 141 additions and 89 deletions

View File

@ -1,6 +1,6 @@
# Contributing to Cal.com # Contributing to Cal.com
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. Contributions are what makes the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
- Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission. - Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission.
@ -37,7 +37,7 @@ Contributions are what make the open source community such an amazing place to l
</tr> </tr>
<tr> <tr>
<td> <td>
Core Features (Booking page, availabilty, timezone calculation) Core Features (Booking page, availability, timezone calculation)
</td> </td>
<td> <td>
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+sort:updated-desc+label:%22High+priority%22"> <a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+sort:updated-desc+label:%22High+priority%22">
@ -132,7 +132,6 @@ If you get errors, be sure to fix them before committing.
## Making a Pull Request ## Making a Pull Request
- Be sure to [check the "Allow edits from maintainers" option](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) while creating you PR. - Be sure to [check the "Allow edits from maintainers" option](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) while creating your PR.
- If your PR refers to or fixes an issue, be sure to add `refs #XXX` or `fixes #XXX` to the PR description. Replacing `XXX` with the respective issue number. See more about [Linking a pull request to an issue - If your PR refers to or fixes an issue, be sure to add `refs #XXX` or `fixes #XXX` to the PR description. Replacing `XXX` with the respective issue number. See more about [Linking a pull request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
- Be sure to fill the PR Template accordingly. - Be sure to fill the PR Template accordingly.

View File

@ -423,7 +423,7 @@ yarn seed-app-store
``` ```
You will need to complete a few more steps to activate Google Calendar App. You will need to complete a few more steps to activate Google Calendar App.
Make sure to complete section "Obtaining the Google API Credentials". After the do the Make sure to complete section "Obtaining the Google API Credentials". After that do the
following following
1. Add extra redirect URL `<Cal.com URL>/api/auth/callback/google` 1. Add extra redirect URL `<Cal.com URL>/api/auth/callback/google`
@ -449,8 +449,8 @@ following
7. Click "Create". 7. Click "Create".
8. Now copy the Client ID and Client Secret to your `.env` file into the `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET` fields. 8. Now copy the Client ID and Client Secret to your `.env` file into the `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET` fields.
9. Set the Redirect URL for OAuth `<Cal.com URL>/api/integrations/zoomvideo/callback` replacing Cal.com URL with the URI at which your application runs. 9. Set the Redirect URL for OAuth `<Cal.com URL>/api/integrations/zoomvideo/callback` replacing Cal.com URL with the URI at which your application runs.
10. Also add the redirect URL given above as a allow list URL and enable "Subdomain check". Make sure, it says "saved" below the form. 10. Also add the redirect URL given above as an allow list URL and enable "Subdomain check". Make sure, it says "saved" below the form.
11. You don't need to provide basic information about your app. Instead click at "Scopes" and then at "+ Add Scopes". On the left, click the category "Meeting" and check the scope `meeting:write`. 11. You don't need to provide basic information about your app. Instead click on "Scopes" and then on "+ Add Scopes". On the left, click the category "Meeting" and check the scope `meeting:write`.
12. Click "Done". 12. Click "Done".
13. You're good to go. Now you can easily add your Zoom integration in the Cal.com settings. 13. You're good to go. Now you can easily add your Zoom integration in the Cal.com settings.

View File

@ -13,7 +13,7 @@ import { Meta } from "@storybook/addon-docs";
<a href="https://www.figma.com/file/9MOufQNLtdkpnDucmNX10R/%E2%9D%96-Cal-DS" target="_blank"> <a href="https://www.figma.com/file/9MOufQNLtdkpnDucmNX10R/%E2%9D%96-Cal-DS" target="_blank">
Figma Figma
</a>{" "} </a>{" "}
library is avalible for anyone to view and use. If you have any questions or concerns, please reach out to library is available for anyone to view and use. If you have any questions or concerns, please reach out to
the design team. the design team.
</p> </p>
</div> </div>

View File

@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react";
import { z } from "zod"; import { z } from "zod";
import type { CredentialOwner } from "@calcom/app-store/types"; import type { CredentialOwner } from "@calcom/app-store/types";
import classNames from "@calcom/lib/classNames";
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage"; import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery"; import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
@ -80,7 +81,13 @@ export default function AppListCard(props: AppListCardProps) {
return ( return (
<div className={`${highlight ? "dark:bg-muted bg-yellow-100" : ""}`}> <div className={`${highlight ? "dark:bg-muted bg-yellow-100" : ""}`}>
<div className="flex items-center gap-x-3 px-5 py-4"> <div className="flex items-center gap-x-3 px-5 py-4">
{logo ? <img className="h-10 w-10" src={logo} alt={`${title} logo`} /> : null} {logo ? (
<img
className={classNames(logo.includes("-dark") && "dark:invert", "h-10 w-10")}
src={logo}
alt={`${title} logo`}
/>
) : null}
<div className="flex grow flex-col gap-y-1 truncate"> <div className="flex grow flex-col gap-y-1 truncate">
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
<h3 className="text-emphasis truncate text-sm font-semibold">{title}</h3> <h3 className="text-emphasis truncate text-sm font-semibold">{title}</h3>

View File

@ -306,7 +306,7 @@ export const EventSetupTab = (
"h-4 w-4", "h-4 w-4",
// invert all the icons except app icons // invert all the icons except app icons
eventLocationType.iconUrl && eventLocationType.iconUrl &&
!eventLocationType.iconUrl.startsWith("/app-store") && eventLocationType.iconUrl.includes("-dark") &&
"dark:invert" "dark:invert"
)} )}
alt={`${eventLocationType.label} logo`} alt={`${eventLocationType.label} logo`}

View File

@ -66,6 +66,7 @@ type Props = {
formMethods: UseFormReturn<FormValues>; formMethods: UseFormReturn<FormValues>;
isUpdateMutationLoading?: boolean; isUpdateMutationLoading?: boolean;
availability?: AvailabilityOption; availability?: AvailabilityOption;
isUserOrganizationAdmin: boolean;
}; };
function getNavigation(props: { function getNavigation(props: {
@ -133,6 +134,7 @@ function EventTypeSingleLayout({
isUpdateMutationLoading, isUpdateMutationLoading,
formMethods, formMethods,
availability, availability,
isUserOrganizationAdmin,
}: Props) { }: Props) {
const utils = trpc.useContext(); const utils = trpc.useContext();
const { t } = useLocale(); const { t } = useLocale();
@ -142,7 +144,8 @@ function EventTypeSingleLayout({
const hasPermsToDelete = const hasPermsToDelete =
currentUserMembership?.role !== "MEMBER" || currentUserMembership?.role !== "MEMBER" ||
!currentUserMembership || !currentUserMembership ||
eventType.schedulingType === SchedulingType.MANAGED; eventType.schedulingType === SchedulingType.MANAGED ||
isUserOrganizationAdmin;
const deleteMutation = trpc.viewer.eventTypes.delete.useMutation({ const deleteMutation = trpc.viewer.eventTypes.delete.useMutation({
onSuccess: async () => { onSuccess: async () => {

View File

@ -4,7 +4,6 @@ import { components } from "react-select";
import type { EventLocationType } from "@calcom/app-store/locations"; import type { EventLocationType } from "@calcom/app-store/locations";
import type { CredentialDataWithTeamName } from "@calcom/app-store/utils"; import type { CredentialDataWithTeamName } from "@calcom/app-store/utils";
import { classNames } from "@calcom/lib"; import { classNames } from "@calcom/lib";
import cx from "@calcom/lib/classNames";
import { Select } from "@calcom/ui"; import { Select } from "@calcom/ui";
export type LocationOption = { export type LocationOption = {
@ -28,7 +27,7 @@ const OptionWithIcon = ({ icon, label }: { icon?: string; label: string }) => {
src={icon} src={icon}
alt="cover" alt="cover"
// invert all the icons except app icons // invert all the icons except app icons
className={cx("h-3.5 w-3.5", icon && !icon.startsWith("/app-store") && "dark:invert")} className={classNames(icon.includes("-dark") && "dark:invert", "h-3.5 w-3.5")}
/> />
)} )}
<span className={classNames("text-sm font-medium")}>{label}</span> <span className={classNames("text-sm font-medium")}>{label}</span>
@ -57,7 +56,13 @@ export default function LocationSelect(props: Props<LocationOption, false, Group
}} }}
formatOptionLabel={(e) => ( formatOptionLabel={(e) => (
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{e.icon && <img src={e.icon} alt="app-icon" className="h-5 w-5" />} {e.icon && (
<img
src={e.icon}
alt="app-icon"
className={classNames(e.icon.includes("-dark") && "dark:invert", "h-5 w-5")}
/>
)}
<span>{e.label}</span> <span>{e.label}</span>
</div> </div>
)} )}

View File

@ -12,7 +12,14 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { AppCategories } from "@calcom/prisma/enums"; import type { AppCategories } from "@calcom/prisma/enums";
import type { inferSSRProps } from "@calcom/types/inferSSRProps"; import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import type { HorizontalTabItemProps } from "@calcom/ui"; import type { HorizontalTabItemProps } from "@calcom/ui";
import { AllApps, AppStoreCategories, HorizontalTabs, TextField, PopularAppsSlider } from "@calcom/ui"; import {
AllApps,
AppStoreCategories,
HorizontalTabs,
TextField,
PopularAppsSlider,
RecentAppsSlider,
} from "@calcom/ui";
import { Search } from "@calcom/ui/components/icon"; import { Search } from "@calcom/ui/components/icon";
import PageWrapper from "@components/PageWrapper"; import PageWrapper from "@components/PageWrapper";
@ -81,6 +88,7 @@ export default function Apps({
<> <>
<AppStoreCategories categories={categories} /> <AppStoreCategories categories={categories} />
<PopularAppsSlider items={appStore} /> <PopularAppsSlider items={appStore} />
<RecentAppsSlider items={appStore} />
</> </>
)} )}
<AllApps <AllApps

View File

@ -443,7 +443,8 @@ const EventTypePage = (props: EventTypeSetupProps) => {
isUpdateMutationLoading={updateMutation.isLoading} isUpdateMutationLoading={updateMutation.isLoading}
formMethods={formMethods} formMethods={formMethods}
disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"} disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"}
currentUserMembership={currentUserMembership}> currentUserMembership={currentUserMembership}
isUserOrganizationAdmin={props.isUserOrganizationAdmin}>
<Form <Form
form={formMethods} form={formMethods}
id="event-type-form" id="event-type-form"

View File

@ -674,6 +674,7 @@ export const EventTypeList = ({ data }: EventTypeListProps): JSX.Element => {
title={t(`delete${isManagedEventPrefix()}_event_type`)} title={t(`delete${isManagedEventPrefix()}_event_type`)}
confirmBtnText={t(`confirm_delete_event_type`)} confirmBtnText={t(`confirm_delete_event_type`)}
loadingText={t(`confirm_delete_event_type`)} loadingText={t(`confirm_delete_event_type`)}
isLoading={deleteMutation.isLoading}
onConfirm={(e) => { onConfirm={(e) => {
e.preventDefault(); e.preventDefault();
deleteEventTypeHandler(deleteDialogTypeId); deleteEventTypeHandler(deleteDialogTypeId);

View File

@ -1074,7 +1074,7 @@
"event_cancelled": "تم إلغاء هذا الحدث", "event_cancelled": "تم إلغاء هذا الحدث",
"emailed_information_about_cancelled_event": "لقد أرسلنا إليك وإلى الحاضرين الآخرين بريداً إلكترونياً لإعلامهم.", "emailed_information_about_cancelled_event": "لقد أرسلنا إليك وإلى الحاضرين الآخرين بريداً إلكترونياً لإعلامهم.",
"this_input_will_shown_booking_this_event": "سيُعرَض هذا المُدخَل عند حجز هذا الحدث", "this_input_will_shown_booking_this_event": "سيُعرَض هذا المُدخَل عند حجز هذا الحدث",
"meeting_url_in_conformation_email": "عنوان رابط الاجتماع موجود في رسالة التأكيد الإلكترونية", "meeting_url_in_confirmation_email": "عنوان رابط الاجتماع موجود في رسالة التأكيد الإلكترونية",
"url_start_with_https": "يجب أن يبدأ العنوان بـ http:// أو https://", "url_start_with_https": "يجب أن يبدأ العنوان بـ http:// أو https://",
"number_provided": "سيتم توفير رقم الهاتف", "number_provided": "سيتم توفير رقم الهاتف",
"before_event_trigger": "قبل بدء الحدث", "before_event_trigger": "قبل بدء الحدث",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Tato událost je zrušena", "event_cancelled": "Tato událost je zrušena",
"emailed_information_about_cancelled_event": "Poslali jsme vám a ostatním účastníkům informační e-mail.", "emailed_information_about_cancelled_event": "Poslali jsme vám a ostatním účastníkům informační e-mail.",
"this_input_will_shown_booking_this_event": "Toto pole se zobrazí při rezervaci této události", "this_input_will_shown_booking_this_event": "Toto pole se zobrazí při rezervaci této události",
"meeting_url_in_conformation_email": "Adresa URL schůzky je v potvrzovacím e-mailu", "meeting_url_in_confirmation_email": "Adresa URL schůzky je v potvrzovacím e-mailu",
"url_start_with_https": "Adresa URL musí začínat http:// nebo https://", "url_start_with_https": "Adresa URL musí začínat http:// nebo https://",
"number_provided": "Bude uvedeno telefonní číslo", "number_provided": "Bude uvedeno telefonní číslo",
"before_event_trigger": "před zahájením události", "before_event_trigger": "před zahájením události",

View File

@ -960,7 +960,7 @@
"reschedule_placeholder": "Lad andre vide, hvorfor du har brug for at omlægge", "reschedule_placeholder": "Lad andre vide, hvorfor du har brug for at omlægge",
"emailed_information_about_cancelled_event": "Vi har sendt en e-mail til dig og de andre deltagere for at give dem besked.", "emailed_information_about_cancelled_event": "Vi har sendt en e-mail til dig og de andre deltagere for at give dem besked.",
"this_input_will_shown_booking_this_event": "Dette input vil blive vist ved booking af denne begivenhed", "this_input_will_shown_booking_this_event": "Dette input vil blive vist ved booking af denne begivenhed",
"meeting_url_in_conformation_email": "Møde-url er i bekræftelses-mailen", "meeting_url_in_confirmation_email": "Møde-url er i bekræftelses-mailen",
"url_start_with_https": "URL'en skal starte med http:// eller https://", "url_start_with_https": "URL'en skal starte med http:// eller https://",
"number_provided": "Telefonnummer vil blive angivet", "number_provided": "Telefonnummer vil blive angivet",
"before_event_trigger": "før begivenheden starter", "before_event_trigger": "før begivenheden starter",

View File

@ -1095,7 +1095,7 @@
"event_cancelled": "Dieser Termin ist abgesagt", "event_cancelled": "Dieser Termin ist abgesagt",
"emailed_information_about_cancelled_event": "Wir haben Ihnen und den anderen Teilnehmern eine E-Mail gesendet, damit alle Bescheid wissen.", "emailed_information_about_cancelled_event": "Wir haben Ihnen und den anderen Teilnehmern eine E-Mail gesendet, damit alle Bescheid wissen.",
"this_input_will_shown_booking_this_event": "Diese Eingabe wird bei der Buchung dieses Termins angezeigt", "this_input_will_shown_booking_this_event": "Diese Eingabe wird bei der Buchung dieses Termins angezeigt",
"meeting_url_in_conformation_email": "Termin-URL ist in der Bestätigungsmail", "meeting_url_in_confirmation_email": "Termin-URL ist in der Bestätigungsmail",
"url_start_with_https": "URL muss mit http:// oder https:// beginnen", "url_start_with_https": "URL muss mit http:// oder https:// beginnen",
"number_provided": "Telefonnummer wird angegeben", "number_provided": "Telefonnummer wird angegeben",
"before_event_trigger": "vor Beginn des Termins", "before_event_trigger": "vor Beginn des Termins",

View File

@ -1098,7 +1098,7 @@
"event_cancelled": "This event is canceled", "event_cancelled": "This event is canceled",
"emailed_information_about_cancelled_event": "We emailed you and the other attendees to let them know.", "emailed_information_about_cancelled_event": "We emailed you and the other attendees to let them know.",
"this_input_will_shown_booking_this_event": "This input will be shown when booking this event", "this_input_will_shown_booking_this_event": "This input will be shown when booking this event",
"meeting_url_in_conformation_email": "Meeting url is in the confirmation email", "meeting_url_in_confirmation_email": "Meeting url is in the confirmation email",
"url_start_with_https": "URL needs to start with http:// or https://", "url_start_with_https": "URL needs to start with http:// or https://",
"number_provided": "Phone number will be provided", "number_provided": "Phone number will be provided",
"before_event_trigger": "before event starts", "before_event_trigger": "before event starts",
@ -2037,5 +2037,6 @@
"team_no_event_types": "This team has no event types", "team_no_event_types": "This team has no event types",
"seat_options_doesnt_multiple_durations": "Seat option doesn't support multiple durations", "seat_options_doesnt_multiple_durations": "Seat option doesn't support multiple durations",
"include_calendar_event": "Include calendar event", "include_calendar_event": "Include calendar event",
"recently_added":"Recently added",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
} }

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Este evento se canceló", "event_cancelled": "Este evento se canceló",
"emailed_information_about_cancelled_event": "Le enviamos un correo electrónico a usted y a los demás asistentes para informarles.", "emailed_information_about_cancelled_event": "Le enviamos un correo electrónico a usted y a los demás asistentes para informarles.",
"this_input_will_shown_booking_this_event": "Esta entrada se mostrará al reservar este evento.", "this_input_will_shown_booking_this_event": "Esta entrada se mostrará al reservar este evento.",
"meeting_url_in_conformation_email": "La URL de la reunión está en el correo de confirmación", "meeting_url_in_confirmation_email": "La URL de la reunión está en el correo de confirmación",
"url_start_with_https": "La URL debe empezar por http:// o https://", "url_start_with_https": "La URL debe empezar por http:// o https://",
"number_provided": "Se proporcionará el número de teléfono", "number_provided": "Se proporcionará el número de teléfono",
"before_event_trigger": "antes del inicio del evento", "before_event_trigger": "antes del inicio del evento",

View File

@ -1098,7 +1098,7 @@
"event_cancelled": "Cet événement est annulé", "event_cancelled": "Cet événement est annulé",
"emailed_information_about_cancelled_event": "Nous vous avons envoyé un e-mail à vous et aux autres participants pour les en informer.", "emailed_information_about_cancelled_event": "Nous vous avons envoyé un e-mail à vous et aux autres participants pour les en informer.",
"this_input_will_shown_booking_this_event": "Ce champ sera affiché lors de la réservation de cet événement.", "this_input_will_shown_booking_this_event": "Ce champ sera affiché lors de la réservation de cet événement.",
"meeting_url_in_conformation_email": "Le lien du rendez-vous est dans l'e-mail de confirmation", "meeting_url_in_confirmation_email": "Le lien du rendez-vous est dans l'e-mail de confirmation",
"url_start_with_https": "Le lien doit commencer par http:// ou https://", "url_start_with_https": "Le lien doit commencer par http:// ou https://",
"number_provided": "Un numéro de téléphone sera fourni", "number_provided": "Un numéro de téléphone sera fourni",
"before_event_trigger": "avant le début de l'événement", "before_event_trigger": "avant le début de l'événement",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "האירוע בוטל", "event_cancelled": "האירוע בוטל",
"emailed_information_about_cancelled_event": "שלחנו לך ולשאר המשתתפים הודעת דוא״ל כדי ליידע אותם על כך.", "emailed_information_about_cancelled_event": "שלחנו לך ולשאר המשתתפים הודעת דוא״ל כדי ליידע אותם על כך.",
"this_input_will_shown_booking_this_event": "הקלט יוצג בעת הזמנת אירוע זה", "this_input_will_shown_booking_this_event": "הקלט יוצג בעת הזמנת אירוע זה",
"meeting_url_in_conformation_email": "כתובת ה-URL של הפגישה נמצאת בהודעת הדוא״ל שנשלחה לאישור הפגישה", "meeting_url_in_confirmation_email": "כתובת ה-URL של הפגישה נמצאת בהודעת הדוא״ל שנשלחה לאישור הפגישה",
"url_start_with_https": "כתובת ה-URL צריכה להתחיל עם הקידומת http:// או https://", "url_start_with_https": "כתובת ה-URL צריכה להתחיל עם הקידומת http:// או https://",
"number_provided": "מספר הטלפון יסופק", "number_provided": "מספר הטלפון יסופק",
"before_event_trigger": "לפני שהאירוע מתחיל", "before_event_trigger": "לפני שהאירוע מתחיל",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Questo evento è stato cancellato", "event_cancelled": "Questo evento è stato cancellato",
"emailed_information_about_cancelled_event": "Abbiamo inviato un'e-mail di notifica a te e agli altri partecipanti.", "emailed_information_about_cancelled_event": "Abbiamo inviato un'e-mail di notifica a te e agli altri partecipanti.",
"this_input_will_shown_booking_this_event": "Questo input verrà mostrato durante la prenotazione di questo evento", "this_input_will_shown_booking_this_event": "Questo input verrà mostrato durante la prenotazione di questo evento",
"meeting_url_in_conformation_email": "L'URL della riunione è riportato nell'e-mail di conferma", "meeting_url_in_confirmation_email": "L'URL della riunione è riportato nell'e-mail di conferma",
"url_start_with_https": "L'URL deve iniziare con http:// o https://", "url_start_with_https": "L'URL deve iniziare con http:// o https://",
"number_provided": "Verrà fornito il numero di telefono", "number_provided": "Verrà fornito il numero di telefono",
"before_event_trigger": "prima dell'inizio dell'evento", "before_event_trigger": "prima dell'inizio dell'evento",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "このイベントはキャンセルされました", "event_cancelled": "このイベントはキャンセルされました",
"emailed_information_about_cancelled_event": "あなたと他の出席者に電子メールでお知らせしました。", "emailed_information_about_cancelled_event": "あなたと他の出席者に電子メールでお知らせしました。",
"this_input_will_shown_booking_this_event": "この入力は、このイベントを予約する際に表示されます", "this_input_will_shown_booking_this_event": "この入力は、このイベントを予約する際に表示されます",
"meeting_url_in_conformation_email": "ミーティングURLは確認メールに記載されています", "meeting_url_in_confirmation_email": "ミーティングURLは確認メールに記載されています",
"url_start_with_https": "URLは、http://またはhttps://で始まる必要があります", "url_start_with_https": "URLは、http://またはhttps://で始まる必要があります",
"number_provided": "電話番号が提供されます", "number_provided": "電話番号が提供されます",
"before_event_trigger": "イベント開始前に", "before_event_trigger": "イベント開始前に",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "이 이벤트는 취소되었습니다", "event_cancelled": "이 이벤트는 취소되었습니다",
"emailed_information_about_cancelled_event": "귀하와 다른 참석자들에게 이메일로 알려 드렸습니다.", "emailed_information_about_cancelled_event": "귀하와 다른 참석자들에게 이메일로 알려 드렸습니다.",
"this_input_will_shown_booking_this_event": "이 입력은 이 이벤트를 예약할 때 표시됩니다.", "this_input_will_shown_booking_this_event": "이 입력은 이 이벤트를 예약할 때 표시됩니다.",
"meeting_url_in_conformation_email": "회의 URL은 확인 이메일에 있습니다", "meeting_url_in_confirmation_email": "회의 URL은 확인 이메일에 있습니다",
"url_start_with_https": "URL은 http:// 또는 https://로 시작해야 합니다", "url_start_with_https": "URL은 http:// 또는 https://로 시작해야 합니다",
"number_provided": "전화 번호는 제공됩니다", "number_provided": "전화 번호는 제공됩니다",
"before_event_trigger": "이벤트 시작 전", "before_event_trigger": "이벤트 시작 전",

View File

@ -1079,7 +1079,7 @@
"event_cancelled": "Deze gebeurtenis is geannuleerd", "event_cancelled": "Deze gebeurtenis is geannuleerd",
"emailed_information_about_cancelled_event": "We hebben u en de andere deelnemers een e-mail gestuurd om hen te informeren.", "emailed_information_about_cancelled_event": "We hebben u en de andere deelnemers een e-mail gestuurd om hen te informeren.",
"this_input_will_shown_booking_this_event": "Deze invoer wordt getoond tijdens het boeken van dit evenement", "this_input_will_shown_booking_this_event": "Deze invoer wordt getoond tijdens het boeken van dit evenement",
"meeting_url_in_conformation_email": "De vergader-URL wordt vermeld in de bevestigings-e-mail", "meeting_url_in_confirmation_email": "De vergader-URL wordt vermeld in de bevestigings-e-mail",
"url_start_with_https": "URL moet beginnen met http:// of https://", "url_start_with_https": "URL moet beginnen met http:// of https://",
"number_provided": "Telefoonnummer wordt verstrekt", "number_provided": "Telefoonnummer wordt verstrekt",
"before_event_trigger": "voordat de gebeurtenis begint", "before_event_trigger": "voordat de gebeurtenis begint",

View File

@ -941,7 +941,7 @@
"reschedule_placeholder": "Fortell andre hvorfor du må endre tidspunktet", "reschedule_placeholder": "Fortell andre hvorfor du må endre tidspunktet",
"emailed_information_about_cancelled_event": "Vi sendte deg og de andre deltakerne en e-post for å informere.", "emailed_information_about_cancelled_event": "Vi sendte deg og de andre deltakerne en e-post for å informere.",
"this_input_will_shown_booking_this_event": "Dette inputfeltet vil vises når man booker denne hendelsen", "this_input_will_shown_booking_this_event": "Dette inputfeltet vil vises når man booker denne hendelsen",
"meeting_url_in_conformation_email": "Møte-url ligger i e-postbekreftelsen", "meeting_url_in_confirmation_email": "Møte-url ligger i e-postbekreftelsen",
"url_start_with_https": "URL må begynne med http:// eller https://", "url_start_with_https": "URL må begynne med http:// eller https://",
"number_provided": "Telefonnummer vil bli oppgitt", "number_provided": "Telefonnummer vil bli oppgitt",
"before_event_trigger": "før hendelsen starter", "before_event_trigger": "før hendelsen starter",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "To wydarzenie zostało anulowane", "event_cancelled": "To wydarzenie zostało anulowane",
"emailed_information_about_cancelled_event": "Wysłaliśmy wiadomość e-mail Tobie i innym uczestnikom, aby ich o tym poinformować.", "emailed_information_about_cancelled_event": "Wysłaliśmy wiadomość e-mail Tobie i innym uczestnikom, aby ich o tym poinformować.",
"this_input_will_shown_booking_this_event": "To wejście zostanie wyświetlone podczas rezerwacji tego wydarzenia", "this_input_will_shown_booking_this_event": "To wejście zostanie wyświetlone podczas rezerwacji tego wydarzenia",
"meeting_url_in_conformation_email": "Adres URL spotkania znajduje się w wiadomości e-mail z potwierdzeniem", "meeting_url_in_confirmation_email": "Adres URL spotkania znajduje się w wiadomości e-mail z potwierdzeniem",
"url_start_with_https": "Adres URL musi zaczynać się od http:// lub https://", "url_start_with_https": "Adres URL musi zaczynać się od http:// lub https://",
"number_provided": "Numer telefonu zostanie podany.", "number_provided": "Numer telefonu zostanie podany.",
"before_event_trigger": "przed rozpoczęciem wydarzenia", "before_event_trigger": "przed rozpoczęciem wydarzenia",

View File

@ -1091,7 +1091,7 @@
"event_cancelled": "Este evento foi cancelado", "event_cancelled": "Este evento foi cancelado",
"emailed_information_about_cancelled_event": "Avisamos por e-mail aos outros participantes e a você.", "emailed_information_about_cancelled_event": "Avisamos por e-mail aos outros participantes e a você.",
"this_input_will_shown_booking_this_event": "Este campo será mostrado na reserva deste evento", "this_input_will_shown_booking_this_event": "Este campo será mostrado na reserva deste evento",
"meeting_url_in_conformation_email": "O URL da reunião está no e-mail de confirmação", "meeting_url_in_confirmation_email": "O URL da reunião está no e-mail de confirmação",
"url_start_with_https": "O URL precisa começar com http:// ou https://", "url_start_with_https": "O URL precisa começar com http:// ou https://",
"number_provided": "O número de telefone será fornecido", "number_provided": "O número de telefone será fornecido",
"before_event_trigger": "antes do início do evento", "before_event_trigger": "antes do início do evento",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Este evento foi cancelado", "event_cancelled": "Este evento foi cancelado",
"emailed_information_about_cancelled_event": "Enviámos um email com o aviso para si e para os restantes participantes.", "emailed_information_about_cancelled_event": "Enviámos um email com o aviso para si e para os restantes participantes.",
"this_input_will_shown_booking_this_event": "Este campo será mostrado na reserva deste evento", "this_input_will_shown_booking_this_event": "Este campo será mostrado na reserva deste evento",
"meeting_url_in_conformation_email": "O URL da reunião está no email de confirmação", "meeting_url_in_confirmation_email": "O URL da reunião está no email de confirmação",
"url_start_with_https": "O URL tem de começar por http:// ou https://", "url_start_with_https": "O URL tem de começar por http:// ou https://",
"number_provided": "Será fornecido um número de telefone", "number_provided": "Será fornecido um número de telefone",
"before_event_trigger": "antes do evento iniciar", "before_event_trigger": "antes do evento iniciar",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Acest eveniment este anulat", "event_cancelled": "Acest eveniment este anulat",
"emailed_information_about_cancelled_event": "V-am trimis un e-mail de informare dvs. și celorlalți participanți.", "emailed_information_about_cancelled_event": "V-am trimis un e-mail de informare dvs. și celorlalți participanți.",
"this_input_will_shown_booking_this_event": "Datele introduse vor fi afișate la rezervarea acestui eveniment", "this_input_will_shown_booking_this_event": "Datele introduse vor fi afișate la rezervarea acestui eveniment",
"meeting_url_in_conformation_email": "Adresa URL a întâlnirii este în e-mailul de confirmare", "meeting_url_in_confirmation_email": "Adresa URL a întâlnirii este în e-mailul de confirmare",
"url_start_with_https": "Adresa URL trebuie să înceapă cu http:// or https://", "url_start_with_https": "Adresa URL trebuie să înceapă cu http:// or https://",
"number_provided": "Numărul de telefon va fi furnizat", "number_provided": "Numărul de telefon va fi furnizat",
"before_event_trigger": "înainte de începerea evenimentului", "before_event_trigger": "înainte de începerea evenimentului",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Это событие отменено", "event_cancelled": "Это событие отменено",
"emailed_information_about_cancelled_event": "Мы сообщили об этом вам и другим участникам по электронной почте.", "emailed_information_about_cancelled_event": "Мы сообщили об этом вам и другим участникам по электронной почте.",
"this_input_will_shown_booking_this_event": "Этот вопрос будет показан при бронировании события по этому шаблону", "this_input_will_shown_booking_this_event": "Этот вопрос будет показан при бронировании события по этому шаблону",
"meeting_url_in_conformation_email": "Ссылка на встречу находится в письме с подтверждением", "meeting_url_in_confirmation_email": "Ссылка на встречу находится в письме с подтверждением",
"url_start_with_https": "URL-адрес должен начинаться с http:// или https://", "url_start_with_https": "URL-адрес должен начинаться с http:// или https://",
"number_provided": "Будет указан номер телефона", "number_provided": "Будет указан номер телефона",
"before_event_trigger": "до начала события", "before_event_trigger": "до начала события",

View File

@ -1076,7 +1076,7 @@
"event_cancelled": "Ovaj događaj je otkazan", "event_cancelled": "Ovaj događaj je otkazan",
"emailed_information_about_cancelled_event": "Poslali smo imejl vama i drugim polaznicima kao obaveštenje.", "emailed_information_about_cancelled_event": "Poslali smo imejl vama i drugim polaznicima kao obaveštenje.",
"this_input_will_shown_booking_this_event": "Ovaj unos će biti prikazan kad se rezerviše ovaj događaj", "this_input_will_shown_booking_this_event": "Ovaj unos će biti prikazan kad se rezerviše ovaj događaj",
"meeting_url_in_conformation_email": "Url za sastanak je u imejlu za potvrdu", "meeting_url_in_confirmation_email": "Url za sastanak je u imejlu za potvrdu",
"url_start_with_https": "Potrebno je URL da počinje sa http:// or https://", "url_start_with_https": "Potrebno je URL da počinje sa http:// or https://",
"number_provided": "Broj telefona će biti dostavljen", "number_provided": "Broj telefona će biti dostavljen",
"before_event_trigger": "pre početka događaja", "before_event_trigger": "pre početka događaja",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Den här händelsen är inställd", "event_cancelled": "Den här händelsen är inställd",
"emailed_information_about_cancelled_event": "Vi mejlade dig och de andra deltagarna för att informera om detta.", "emailed_information_about_cancelled_event": "Vi mejlade dig och de andra deltagarna för att informera om detta.",
"this_input_will_shown_booking_this_event": "Detta visas vid bokning av denna händelse", "this_input_will_shown_booking_this_event": "Detta visas vid bokning av denna händelse",
"meeting_url_in_conformation_email": "Mötets webbadress finns i bekräftelsemejlet", "meeting_url_in_confirmation_email": "Mötets webbadress finns i bekräftelsemejlet",
"url_start_with_https": "Webbadress behöver inledas med http:// eller https://", "url_start_with_https": "Webbadress behöver inledas med http:// eller https://",
"number_provided": "Telefonnummer kommer att anges", "number_provided": "Telefonnummer kommer att anges",
"before_event_trigger": "innan händelsen startar", "before_event_trigger": "innan händelsen startar",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Bu etkinlik iptal edildi", "event_cancelled": "Bu etkinlik iptal edildi",
"emailed_information_about_cancelled_event": "Sizi ve diğer katılımcıları bilgilendirmek için bir e-posta gönderdik.", "emailed_information_about_cancelled_event": "Sizi ve diğer katılımcıları bilgilendirmek için bir e-posta gönderdik.",
"this_input_will_shown_booking_this_event": "Bu girdi, bu etkinlik için rezervasyon yapılırken gösterilecek", "this_input_will_shown_booking_this_event": "Bu girdi, bu etkinlik için rezervasyon yapılırken gösterilecek",
"meeting_url_in_conformation_email": "Toplantı URL'si onay e-postasında mevcut", "meeting_url_in_confirmation_email": "Toplantı URL'si onay e-postasında mevcut",
"url_start_with_https": "URL'nin http:// veya https:// ile başlaması gerekiyor", "url_start_with_https": "URL'nin http:// veya https:// ile başlaması gerekiyor",
"number_provided": "Telefon numarası sağlanacaktır", "number_provided": "Telefon numarası sağlanacaktır",
"before_event_trigger": "etkinlik başlamadan önce", "before_event_trigger": "etkinlik başlamadan önce",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Цей захід скасовано", "event_cancelled": "Цей захід скасовано",
"emailed_information_about_cancelled_event": "Ми сповістили вас та інших учасників електронною поштою.", "emailed_information_about_cancelled_event": "Ми сповістили вас та інших учасників електронною поштою.",
"this_input_will_shown_booking_this_event": "Це поле введення буде показано під час бронювання часу для цього заходу", "this_input_will_shown_booking_this_event": "Це поле введення буде показано під час бронювання часу для цього заходу",
"meeting_url_in_conformation_email": "URL-адресу наради вказано в листі з підтвердженням", "meeting_url_in_confirmation_email": "URL-адресу наради вказано в листі з підтвердженням",
"url_start_with_https": "URL-адреса має починатися з http:// або https://", "url_start_with_https": "URL-адреса має починатися з http:// або https://",
"number_provided": "Номер телефону буде надано", "number_provided": "Номер телефону буде надано",
"before_event_trigger": "до початку заходу", "before_event_trigger": "до початку заходу",

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "Sự kiện này bị huỷ", "event_cancelled": "Sự kiện này bị huỷ",
"emailed_information_about_cancelled_event": "Chúng tôi đã gửi email cho bạn và những người tham dự khác để cho họ biết.", "emailed_information_about_cancelled_event": "Chúng tôi đã gửi email cho bạn và những người tham dự khác để cho họ biết.",
"this_input_will_shown_booking_this_event": "Trường này sẽ được hiển thị khi đặt sự kiện này", "this_input_will_shown_booking_this_event": "Trường này sẽ được hiển thị khi đặt sự kiện này",
"meeting_url_in_conformation_email": "Url cuộc họp nằm trong email xác nhận", "meeting_url_in_confirmation_email": "Url cuộc họp nằm trong email xác nhận",
"url_start_with_https": "URL cần bắt đầu bằng http:// hoặc https://", "url_start_with_https": "URL cần bắt đầu bằng http:// hoặc https://",
"number_provided": "Số điện thoại sẽ được cung ứng", "number_provided": "Số điện thoại sẽ được cung ứng",
"before_event_trigger": "trước khi sự kiện bắt đầu", "before_event_trigger": "trước khi sự kiện bắt đầu",

View File

@ -1079,7 +1079,7 @@
"event_cancelled": "此活动已取消", "event_cancelled": "此活动已取消",
"emailed_information_about_cancelled_event": "我们已向您和其他参与者发送电子邮件来通知他们。", "emailed_information_about_cancelled_event": "我们已向您和其他参与者发送电子邮件来通知他们。",
"this_input_will_shown_booking_this_event": "在预约此活动时将显示该输入框", "this_input_will_shown_booking_this_event": "在预约此活动时将显示该输入框",
"meeting_url_in_conformation_email": "会议链接含在确认电子邮件中", "meeting_url_in_confirmation_email": "会议链接含在确认电子邮件中",
"url_start_with_https": "链接需要以 http:// 或 https:// 开头", "url_start_with_https": "链接需要以 http:// 或 https:// 开头",
"number_provided": "将提供电话号码", "number_provided": "将提供电话号码",
"before_event_trigger": "活动开始前", "before_event_trigger": "活动开始前",
@ -1945,5 +1945,6 @@
"insights_subtitle": "查看您活动的预约 insights", "insights_subtitle": "查看您活动的预约 insights",
"custom_plan": "自定义计划", "custom_plan": "自定义计划",
"include_calendar_event": "包括日历活动", "include_calendar_event": "包括日历活动",
"recently_added": "最近添加",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 在此上方添加您的新字符串 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ 在此上方添加您的新字符串 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
} }

View File

@ -1075,7 +1075,7 @@
"event_cancelled": "此活動已取消", "event_cancelled": "此活動已取消",
"emailed_information_about_cancelled_event": "我們已給您和其他與會者發送通知電子郵件。", "emailed_information_about_cancelled_event": "我們已給您和其他與會者發送通知電子郵件。",
"this_input_will_shown_booking_this_event": "輸入欄會在預約此活動的時候顯示", "this_input_will_shown_booking_this_event": "輸入欄會在預約此活動的時候顯示",
"meeting_url_in_conformation_email": "會議網址請參見確認電子郵件", "meeting_url_in_confirmation_email": "會議網址請參見確認電子郵件",
"url_start_with_https": "URL 需要以 http:// 或 https:// 開頭", "url_start_with_https": "URL 需要以 http:// 或 https:// 開頭",
"number_provided": "將提供電話號碼", "number_provided": "將提供電話號碼",
"before_event_trigger": "活動開始前", "before_event_trigger": "活動開始前",

View File

@ -207,7 +207,6 @@ html.todesktop nav a svg{
https://github.com/tailwindlabs/tailwindcss/pull/5732 https://github.com/tailwindlabs/tailwindcss/pull/5732
*/ */
@layer utilities { @layer utilities {
@layer responsive {
/* Chrome, Safari and Opera */ /* Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar { .no-scrollbar::-webkit-scrollbar {
display: none; display: none;
@ -217,7 +216,6 @@ html.todesktop nav a svg{
-ms-overflow-style: none; /* IE and Edge */ -ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
} }
}
} }
/* /*

View File

@ -34,7 +34,7 @@ export async function getAppWithMetadata(app: { dirName: string } | { slug: stri
export async function getAppRegistry() { export async function getAppRegistry() {
const dbApps = await prisma.app.findMany({ const dbApps = await prisma.app.findMany({
where: { enabled: true }, where: { enabled: true },
select: { dirName: true, slug: true, categories: true, enabled: true }, select: { dirName: true, slug: true, categories: true, enabled: true, createdAt: true },
}); });
const apps = [] as App[]; const apps = [] as App[];
const installCountPerApp = await getInstallCountPerApp(); const installCountPerApp = await getInstallCountPerApp();
@ -44,7 +44,7 @@ export async function getAppRegistry() {
// Skip if app isn't installed // Skip if app isn't installed
/* This is now handled from the DB */ /* This is now handled from the DB */
// if (!app.installed) return apps; // if (!app.installed) return apps;
app.createdAt = dbapp.createdAt.toISOString();
apps.push({ apps.push({
...app, ...app,
category: app.category || "other", category: app.category || "other",
@ -101,6 +101,7 @@ export async function getAppRegistryWithCredentials(userId: number, userAdminTea
// Skip if app isn't installed // Skip if app isn't installed
/* This is now handled from the DB */ /* This is now handled from the DB */
// if (!app.installed) return apps; // if (!app.installed) return apps;
app.createdAt = dbapp.createdAt.toISOString();
let dependencyData: { let dependencyData: {
name?: string; name?: string;
installed?: boolean; installed?: boolean;

View File

@ -403,7 +403,7 @@ export function getSuccessPageLocationMessage(
locationToDisplay == t("web_conference"); locationToDisplay == t("web_conference");
} else if (isConfirmed) { } else if (isConfirmed) {
locationToDisplay = locationToDisplay =
getHumanReadableLocationValue(location, t) + ": " + t("meeting_url_in_conformation_email"); getHumanReadableLocationValue(location, t) + ": " + t("meeting_url_in_confirmation_email");
} else { } else {
locationToDisplay = t("web_conferencing_details_to_follow"); locationToDisplay = t("web_conferencing_details_to_follow");
} }

View File

@ -179,7 +179,7 @@ function isValidNamespace(ns: string | null | undefined) {
/** /**
* It handles any URL change done through Web history API as well * It handles any URL change done through Web history API as well
* History API is currenty being used by Booker/utils/query-param * History API is currently being used by Booker/utils/query-param
*/ */
const useUrlChange = (callback: (newUrl: string) => void) => { const useUrlChange = (callback: (newUrl: string) => void) => {
const currentFullUrl = isBrowser ? new URL(document.URL) : null; const currentFullUrl = isBrowser ? new URL(document.URL) : null;

View File

@ -23,8 +23,8 @@ function RenderIcon({
src={eventLocationType.iconUrl} src={eventLocationType.iconUrl}
className={classNames( className={classNames(
"me-[10px] h-4 w-4 opacity-70 dark:opacity-100", "me-[10px] h-4 w-4 opacity-70 dark:opacity-100",
!eventLocationType.iconUrl?.startsWith("/app-store") ? "dark:invert-[.65]" : "", eventLocationType.iconUrl?.includes("-dark") ? "dark:invert-[.65]" : "",
!eventLocationType.iconUrl?.startsWith("/app-store") && isTooltip && "invert" eventLocationType.iconUrl?.includes("-dark") && isTooltip && "invert"
)} )}
alt={`${eventLocationType.label} icon`} alt={`${eventLocationType.label} icon`}
/> />

View File

@ -1,7 +1,6 @@
import type { Payment } from "@prisma/client"; import type { Payment } from "@prisma/client";
import type { EventType } from "@prisma/client"; import type { EventType } from "@prisma/client";
import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js"; import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js";
import type stripejs from "@stripe/stripe-js";
import type { StripeElementLocale } from "@stripe/stripe-js"; import type { StripeElementLocale } from "@stripe/stripe-js";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import type { SyntheticEvent } from "react"; import type { SyntheticEvent } from "react";
@ -181,27 +180,14 @@ const PaymentForm = (props: Props) => {
); );
}; };
const ELEMENT_STYLES: stripejs.Appearance = {
theme: "none",
};
const ELEMENT_STYLES_DARK: stripejs.Appearance = {
theme: "night",
variables: {
colorText: "#d6d6d6",
fontWeightNormal: "600",
borderRadius: "6px",
colorBackground: "#101010",
colorPrimary: "#d6d6d6",
},
};
export default function PaymentComponent(props: Props) { export default function PaymentComponent(props: Props) {
const stripePromise = getStripe(props.payment.data.stripe_publishable_key as any); const stripePromise = getStripe(props.payment.data.stripe_publishable_key as any);
const [darkMode, setDarkMode] = useState<boolean>(false); const [theme, setTheme] = useState<"stripe" | "night">("stripe");
useEffect(() => { useEffect(() => {
setDarkMode(window.matchMedia("(prefers-color-scheme: dark)").matches); if (document.documentElement.classList.contains("dark")) {
setTheme("night");
}
}, []); }, []);
return ( return (
@ -209,7 +195,9 @@ export default function PaymentComponent(props: Props) {
stripe={stripePromise} stripe={stripePromise}
options={{ options={{
clientSecret: props.clientSecret, clientSecret: props.clientSecret,
appearance: darkMode ? ELEMENT_STYLES_DARK : ELEMENT_STYLES, appearance: {
theme,
},
}}> }}>
<PaymentForm {...props} /> <PaymentForm {...props} />
</Elements> </Elements>

View File

@ -437,9 +437,6 @@ function FieldEditDialog({
value={fieldTypesConfigMap[fieldForm.getValues("type")]} value={fieldTypesConfigMap[fieldForm.getValues("type")]}
options={fieldTypes.filter((f) => !f.systemOnly)} options={fieldTypes.filter((f) => !f.systemOnly)}
label={t("input_type")} label={t("input_type")}
classNames={{
menuList: () => "min-h-[27.25rem]",
}}
/> />
{(() => { {(() => {
if (!variantsConfig) { if (!variantsConfig) {

View File

@ -21,6 +21,7 @@ interface getEventTypeByIdProps {
userId: number; userId: number;
prisma: PrismaClient; prisma: PrismaClient;
isTrpcCall?: boolean; isTrpcCall?: boolean;
isUserOrganizationAdmin: boolean;
} }
export default async function getEventTypeById({ export default async function getEventTypeById({
@ -28,6 +29,7 @@ export default async function getEventTypeById({
userId, userId,
prisma, prisma,
isTrpcCall = false, isTrpcCall = false,
isUserOrganizationAdmin,
}: getEventTypeByIdProps) { }: getEventTypeByIdProps) {
const userSelect = Prisma.validator<Prisma.UserSelect>()({ const userSelect = Prisma.validator<Prisma.UserSelect>()({
name: true, name: true,
@ -408,6 +410,7 @@ export default async function getEventTypeById({
team: eventTypeObject.team || null, team: eventTypeObject.team || null,
teamMembers, teamMembers,
currentUserMembership, currentUserMembership,
isUserOrganizationAdmin,
}; };
return finalObj; return finalObj;
} }

View File

@ -24,6 +24,7 @@ type CreateOptions = {
export const createHandler = async ({ ctx, input }: CreateOptions) => { export const createHandler = async ({ ctx, input }: CreateOptions) => {
const { schedulingType, teamId, metadata, ...rest } = input; const { schedulingType, teamId, metadata, ...rest } = input;
const userId = ctx.user.id; const userId = ctx.user.id;
const isManagedEventType = schedulingType === SchedulingType.MANAGED; const isManagedEventType = schedulingType === SchedulingType.MANAGED;
// Get Users default conferencing app // Get Users default conferencing app
@ -68,7 +69,9 @@ export const createHandler = async ({ ctx, input }: CreateOptions) => {
}, },
}); });
if (!hasMembership?.role || !["ADMIN", "OWNER"].includes(hasMembership.role)) { const isOrgAdmin = !!ctx.user?.organization?.isOrgAdmin;
if (!hasMembership?.role || !(["ADMIN", "OWNER"].includes(hasMembership.role) || isOrgAdmin)) {
console.warn(`User ${userId} does not have permission to create this new event type`); console.warn(`User ${userId} does not have permission to create this new event type`);
throw new TRPCError({ code: "UNAUTHORIZED" }); throw new TRPCError({ code: "UNAUTHORIZED" });
} }

View File

@ -18,5 +18,6 @@ export const getHandler = ({ ctx, input }: GetOptions) => {
userId: ctx.user.id, userId: ctx.user.id,
prisma: ctx.prisma, prisma: ctx.prisma,
isTrpcCall: true, isTrpcCall: true,
isUserOrganizationAdmin: !!ctx.user?.organization?.isOrgAdmin,
}); });
}; };

View File

@ -40,10 +40,13 @@ export const eventOwnerProcedure = authedProcedure
const isAuthorized = (function () { const isAuthorized = (function () {
if (event.team) { if (event.team) {
return event.team.members const isOrgAdmin = !!ctx.user?.organization?.isOrgAdmin;
return (
event.team.members
.filter((member) => member.role === MembershipRole.OWNER || member.role === MembershipRole.ADMIN) .filter((member) => member.role === MembershipRole.OWNER || member.role === MembershipRole.ADMIN)
.map((member) => member.userId) .map((member) => member.userId)
.includes(ctx.user.id); .includes(ctx.user.id) || isOrgAdmin
);
} }
return event.userId === ctx.user.id || event.users.find((user) => user.id === ctx.user.id); return event.userId === ctx.user.id || event.users.find((user) => user.id === ctx.user.id);
})(); })();

View File

@ -153,6 +153,8 @@ export interface App {
dependencies?: string[]; dependencies?: string[];
/** Enables video apps to be used for team events. Non Video/Conferencing apps don't honor this as they support team installation always. */ /** Enables video apps to be used for team events. Non Video/Conferencing apps don't honor this as they support team installation always. */
concurrentMeetings?: boolean; concurrentMeetings?: boolean;
createdAt?: string;
} }
export type AppFrontendPayload = Omit<App, "key"> & { export type AppFrontendPayload = Omit<App, "key"> & {

View File

@ -0,0 +1,28 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { AppFrontendPayload as App } from "@calcom/types/App";
import { AppCard } from "./AppCard";
import { Slider } from "./Slider";
export const RecentAppsSlider = <T extends App>({ items }: { items: T[] }) => {
const { t } = useLocale();
return (
<Slider<T>
title={t("recently_added")}
items={items.sort(
(a, b) => new Date(b?.createdAt || 0).valueOf() - new Date(a?.createdAt || 0).valueOf()
)}
itemKey={(app) => app.name}
options={{
perView: 3,
breakpoints: {
768 /* and below */: {
perView: 1,
},
},
}}
renderItem={(app) => <AppCard app={app} />}
/>
);
};

View File

@ -4,4 +4,5 @@ export { Slider } from "./Slider";
export { SkeletonLoader as AppSkeletonLoader } from "./SkeletonLoader"; export { SkeletonLoader as AppSkeletonLoader } from "./SkeletonLoader";
export { SkeletonLoader } from "./SkeletonLoader"; export { SkeletonLoader } from "./SkeletonLoader";
export { PopularAppsSlider } from "./PopularAppsSlider"; export { PopularAppsSlider } from "./PopularAppsSlider";
export { RecentAppsSlider } from "./RecentAppsSlider";
export { AppStoreCategories } from "./Categories"; export { AppStoreCategories } from "./Categories";

View File

@ -19,7 +19,7 @@ import { Badge } from "./Badge";
## Definition ## Definition
Badges are small status descriptors for UI elements. A badge consists of a small circle, typically containing a number or other short set of characters, that appears in proximity to another object. We provide three different type of badge such as status, alert, and brand badge. Badges are small status descriptors for UI elements. A badge consists of a small circle, typically containing a number or other short set of characters, that appears in proximity to another object. We provide three different types of badges such as status, alert, and brand badge.
Status badge communicate status information. It is generally used within a container such as accordion and tables to label status for easy scanning. Status badge communicate status information. It is generally used within a container such as accordion and tables to label status for easy scanning.
@ -58,7 +58,7 @@ Status badge communicate status information. It is generally used within a conta
## Usage ## Usage
Alet badge is used in conjunction with an item, profile or label to indicate numeric value and messages assocciated with them. Alert badge is used in conjunction with an item, profile or label to indicate numeric value and messages associated with them.
<Title offset title="Badge" suffix="Variants" /> <Title offset title="Badge" suffix="Variants" />

View File

@ -12,7 +12,7 @@ const HorizontalTabs = function ({ tabs, linkShallow, linkScroll, actions, ...pr
return ( return (
<div className="mb-4 h-9 max-w-full lg:mb-5"> <div className="mb-4 h-9 max-w-full lg:mb-5">
<nav <nav
className="no-scrollbar flex max-h-9 space-x-1 overflow-scroll rounded-md" className="no-scrollbar flex max-h-9 space-x-1 overflow-x-scroll rounded-md"
aria-label="Tabs" aria-label="Tabs"
{...props}> {...props}>
{tabs.map((tab, idx) => ( {tabs.map((tab, idx) => (

View File

@ -69,6 +69,7 @@ export {
SkeletonLoader, SkeletonLoader,
Slider, Slider,
PopularAppsSlider, PopularAppsSlider,
RecentAppsSlider,
useShouldShowArrows, useShouldShowArrows,
AppStoreCategories, AppStoreCategories,
} from "./components/apps"; } from "./components/apps";