Skip to content

Commit

Permalink
Merge branch 'main' into fix-platform-event-type-atom-team-availabili…
Browse files Browse the repository at this point in the history
…ty-tab
  • Loading branch information
SomayChauhan authored Oct 21, 2024
2 parents 3d70882 + b0e3e4c commit c115dff
Show file tree
Hide file tree
Showing 100 changed files with 3,636 additions and 545 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ To develop locally:
nvm use
```
You first might need to install the specific version and then use it:
You first might need to install the specific version:
```sh
nvm install && nvm use
nvm install
```
You can install nvm from [here](https://github.com/nvm-sh/nvm).
Expand Down
14 changes: 4 additions & 10 deletions apps/api/v1/pages/api/slots/_get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,8 @@ describe("GET /api/slots", () => {
buildMockData();
await handler(req, res);
console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) });
expect(JSON.parse(res._getData())).toMatchInlineSnapshot(`
{
"slots": {},
}
`);
const response = JSON.parse(res._getData());
expect(response.slots).toEqual(expect.objectContaining({}));
});
test("Returns and event type available slots with passed timeZone", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
Expand All @@ -87,11 +84,8 @@ describe("GET /api/slots", () => {
buildMockData();
await handler(req, res);
console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) });
expect(JSON.parse(res._getData())).toMatchInlineSnapshot(`
{
"slots": {},
}
`);
const response = JSON.parse(res._getData());
expect(response.slots).toEqual(expect.objectContaining({}));
});
});
});
Expand Down
21 changes: 7 additions & 14 deletions apps/web/components/apps/installation/ConfigureStepCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const EventTypeGroup = ({
}: ConfigureStepCardProps & {
groupIndex: number;
setUpdatedEventTypesStatus: Dispatch<SetStateAction<TUpdatedEventTypesStatus>>;
submitRefs: Array<React.RefObject<HTMLButtonElement>>;
submitRefs: React.MutableRefObject<(HTMLButtonElement | null)[]>;
}) => {
const { control } = useFormContext<TEventTypesForm>();
const { fields, update } = useFieldArray({
Expand Down Expand Up @@ -174,7 +174,9 @@ const EventTypeGroup = ({
return res;
});
}}
ref={submitRefs[index]}
ref={(el) => {
submitRefs.current[index] = el;
}}
{...props}
/>
)
Expand All @@ -193,17 +195,8 @@ export const ConfigureStepCard: FC<ConfigureStepCardProps> = (props) => {
keyName: "fieldId",
});
const eventTypeGroups = watch("eventTypeGroups");
const submitRefs = useRef<Array<Array<React.RefObject<HTMLButtonElement>>>>([]);
const submitRefs = useRef<(HTMLButtonElement | null)[]>([]);

submitRefs.current = eventTypeGroups.reduce(
(arr: Array<Array<React.RefObject<HTMLButtonElement>>>, field) => {
const res = field.eventTypes
.filter((eventType) => eventType.selected)
.map((_ref) => React.createRef<HTMLButtonElement>());
return [...arr, res];
},
[]
);
const mainForSubmitRef = useRef<HTMLButtonElement>(null);
const [updatedEventTypesStatus, setUpdatedEventTypesStatus] = useState<TUpdatedEventTypesStatus>(
eventTypeGroups.reduce((arr: Array<{ id: number; updated: boolean }[]>, field) => {
Expand Down Expand Up @@ -245,7 +238,7 @@ export const ConfigureStepCard: FC<ConfigureStepCardProps> = (props) => {
<EventTypeGroup
groupIndex={groupIndex}
setUpdatedEventTypesStatus={setUpdatedEventTypesStatus}
submitRefs={submitRefs.current[groupIndex]}
submitRefs={submitRefs}
{...props}
/>
</div>
Expand All @@ -258,7 +251,7 @@ export const ConfigureStepCard: FC<ConfigureStepCardProps> = (props) => {
type="button"
data-testid="configure-step-save"
onClick={() => {
submitRefs.current.map((group) => group?.map((ref) => ref.current?.click()));
submitRefs.current.forEach((ref) => ref?.click());
setSubmit(true);
}}
loading={loading}>
Expand Down
63 changes: 60 additions & 3 deletions apps/web/components/booking/BookingListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { BookingStatus, SchedulingType } from "@calcom/prisma/enums";
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
import type { RouterInputs, RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { Ensure } from "@calcom/types/utils";
import type { ActionType } from "@calcom/ui";
import {
Badge,
Expand Down Expand Up @@ -48,6 +49,7 @@ import { AddGuestsDialog } from "@components/dialog/AddGuestsDialog";
import { ChargeCardDialog } from "@components/dialog/ChargeCardDialog";
import { EditLocationDialog } from "@components/dialog/EditLocationDialog";
import { ReassignDialog } from "@components/dialog/ReassignDialog";
import { RerouteDialog } from "@components/dialog/RerouteDialog";
import { RescheduleDialog } from "@components/dialog/RescheduleDialog";

type BookingListingStatus = RouterInputs["viewer"]["bookings"]["get"]["filters"]["status"];
Expand All @@ -65,9 +67,43 @@ type BookingItemProps = BookingItem & {
};
};

type ParsedBooking = ReturnType<typeof buildParsedBooking>;
type TeamEvent = Ensure<NonNullable<ParsedBooking["eventType"]>, "team">;
type TeamEventBooking = Omit<ParsedBooking, "eventType"> & {
eventType: TeamEvent;
};
type ReroutableBooking = Ensure<TeamEventBooking, "routedFromRoutingFormReponse">;

function buildParsedBooking(booking: BookingItemProps) {
// The way we fetch bookings there could be eventType object even without an eventType, but id confirms its existence
const bookingEventType = booking.eventType.id
? (booking.eventType as Ensure<
typeof booking.eventType,
// It would only ensure that the props are present, if they are optional in the original type. So, it is safe to assert here.
"id" | "length" | "title" | "slug" | "schedulingType" | "team"
>)
: null;

const bookingMetadata = bookingMetadataSchema.parse(booking.metadata ?? null);
return {
...booking,
eventType: bookingEventType,
metadata: bookingMetadata,
};
}

const isBookingReroutable = (booking: ParsedBooking): booking is ReroutableBooking => {
// We support only team bookings for now for rerouting
// Though `routedFromRoutingFormReponse` could be there for a non-team booking, we don't want to support it for now.
// Let's not support re-routing for a booking without an event-type for now.
// Such a booking has its event-type deleted and there might not be something to reroute to.
return !!booking.routedFromRoutingFormReponse && !!booking.eventType?.team;
};

function BookingListItem(booking: BookingItemProps) {
const { userId, userTimeZone, userTimeFormat, userEmail } = booking.loggedInUser;
const parsedBooking = buildParsedBooking(booking);

const { userId, userTimeZone, userTimeFormat, userEmail } = booking.loggedInUser;
const {
t,
i18n: { language },
Expand Down Expand Up @@ -107,7 +143,7 @@ function BookingListItem(booking: BookingItemProps) {
const paymentAppData = getPaymentAppData(booking.eventType);

const location = booking.location as ReturnType<typeof getEventLocationValue>;
const locationVideoCallUrl = bookingMetadataSchema.parse(booking?.metadata || {})?.videoCallUrl;
const locationVideoCallUrl = parsedBooking.metadata?.videoCallUrl;

const { resolvedTheme, forcedTheme } = useGetTheme();
const hasDarkTheme = !forcedTheme && resolvedTheme === "dark";
Expand Down Expand Up @@ -191,6 +227,18 @@ function BookingListItem(booking: BookingItemProps) {
setIsOpenRescheduleDialog(true);
},
},
...(isBookingReroutable(parsedBooking)
? [
{
id: "reroute",
label: t("reroute"),
onClick: () => {
setRerouteDialogIsOpen(true);
},
icon: "waypoints" as const,
},
]
: []),
{
id: "change_location",
label: t("edit_location"),
Expand Down Expand Up @@ -275,6 +323,7 @@ function BookingListItem(booking: BookingItemProps) {
const [isOpenReassignDialog, setIsOpenReassignDialog] = useState(false);
const [isOpenSetLocationDialog, setIsOpenLocationDialog] = useState(false);
const [isOpenAddGuestsDialog, setIsOpenAddGuestsDialog] = useState(false);
const [rerouteDialogIsOpen, setRerouteDialogIsOpen] = useState(false);
const setLocationMutation = trpc.viewer.bookings.editLocation.useMutation({
onSuccess: () => {
showToast(t("location_updated"), "success");
Expand Down Expand Up @@ -360,6 +409,7 @@ function BookingListItem(booking: BookingItemProps) {
phoneNumber: attendee.phoneNumber,
};
});

return (
<>
<RescheduleDialog
Expand Down Expand Up @@ -620,6 +670,13 @@ function BookingListItem(booking: BookingItemProps) {
)}
</td>
</tr>
{isBookingReroutable(parsedBooking) && (
<RerouteDialog
isOpenDialog={rerouteDialogIsOpen}
setIsOpenDialog={setRerouteDialogIsOpen}
booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
/>
)}
</>
);
}
Expand Down Expand Up @@ -722,7 +779,7 @@ const FirstAttendee = ({
className=" hover:text-blue-500"
href={`mailto:${user.email}`}
onClick={(e) => e.stopPropagation()}>
{user.name}
{user.name || user.email}
</a>
);
};
Expand Down
Loading

0 comments on commit c115dff

Please sign in to comment.