Skip to content

Commit

Permalink
Merge branch 'main' into feat/sort_options_on_bookings_v1
Browse files Browse the repository at this point in the history
  • Loading branch information
hariombalhara authored Jul 4, 2024
2 parents 3a9fc14 + 557498b commit cc3e1cf
Show file tree
Hide file tree
Showing 56 changed files with 1,165 additions and 803 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: PR Update

on:
pull_request_target:
types: [opened, synchronize, reopened, labeled]
branches:
- main
- gh-actions-test-branch
Expand Down Expand Up @@ -169,6 +170,7 @@ jobs:

required:
needs: [changes, lint, type-check, unit-test, integration-test, check-label, build, build-api-v1, build-api-v2, e2e, e2e-embed, e2e-embed-react, e2e-app-store]
if: always()
runs-on: buildjet-2vcpu-ubuntu-2204
steps:
- name: fail if conditional jobs failed
Expand Down
2 changes: 2 additions & 0 deletions apps/web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,5 @@ public/embed

# Copied app-store images
public/app-store

certificates
17 changes: 14 additions & 3 deletions apps/web/components/apps/AppList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { InstallAppButton } from "@calcom/app-store/components";
import { getEventLocationTypeFromApp, type EventLocationType } from "@calcom/app-store/locations";
import type { CredentialOwner } from "@calcom/app-store/types";
import { AppSetDefaultLinkDialog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog";
import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal";
import { BulkEditDefaultModal } from "@calcom/features/eventtypes/components/BulkEditDefaultModal";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { AppCategories } from "@calcom/prisma/enums";
import { trpc, type RouterOutputs } from "@calcom/trpc";
Expand Down Expand Up @@ -153,6 +153,8 @@ export const AppList = ({ data, handleDisconnect, variant, listClassName }: AppL
});

const { t } = useLocale();
const [eventTypeIds, setEventTypeIds] = useState<number[]>([]);
const { data: bulkEventTypes } = trpc.viewer.eventTypes.bulkEventFetch.useQuery();
const updateLocationsMutation = trpc.viewer.eventTypes.bulkUpdateToDefaultLocation.useMutation({
onSuccess: () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
Expand All @@ -178,11 +180,20 @@ export const AppList = ({ data, handleDisconnect, variant, listClassName }: AppL
)}

{bulkUpdateModal && (
<BulkEditDefaultForEventsModal
bulkUpdateFunction={updateLocationsMutation.mutate}
<BulkEditDefaultModal
handleSubmit={() => {
updateLocationsMutation.mutate({
eventTypeIds,
});
}}
open={bulkUpdateModal}
setOpen={setBulkUpdateModal}
isPending={updateLocationsMutation.isPending}
title={t("default_conferencing_bulk_title")}
description={t("default_conferencing_bulk_description")}
data={bulkEventTypes?.eventTypes}
ids={eventTypeIds}
setIds={setEventTypeIds}
/>
)}
</>
Expand Down
38 changes: 20 additions & 18 deletions apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import classNames from "classnames";
// eslint-disable-next-line no-restricted-imports
import { debounce, noop } from "lodash";
import { noop } from "lodash";
import { useSession } from "next-auth/react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import type { RefCallback } from "react";
import { useEffect, useMemo, useState } from "react";
import { useEffect, useState } from "react";

import { getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { fetchUsername } from "@calcom/lib/fetchUsername";
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
import { useDebounce } from "@calcom/lib/hooks/useDebounce";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
import type { RouterOutputs } from "@calcom/trpc/react";
Expand Down Expand Up @@ -71,30 +72,31 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
const isCurrentUsernamePremium =
user && user.metadata && hasKeyInMetadata(user, "isPremium") ? !!user.metadata.isPremium : false;
const [isInputUsernamePremium, setIsInputUsernamePremium] = useState(false);
const debouncedApiCall = useMemo(
() =>
debounce(async (username: string) => {
// TODO: Support orgSlug
const { data } = await fetchUsername(username, null);
setMarkAsError(!data.available && !!currentUsername && username !== currentUsername);
setIsInputUsernamePremium(data.premium);
setUsernameIsAvailable(data.available);
}, 150),
[currentUsername]
);
// debounce the username input, set the delay to 600ms to be consistent with signup form
const debouncedUsername = useDebounce(inputUsernameValue, 600);

useEffect(() => {
// Use the current username or if it's not set, use the one available from stripe
setInputUsernameValue(currentUsername || stripeCustomer?.username || "");
}, [setInputUsernameValue, currentUsername, stripeCustomer?.username]);

useEffect(() => {
if (!inputUsernameValue) {
debouncedApiCall.cancel();
return;
async function checkUsername(username: string | undefined) {
if (!username) {
setUsernameIsAvailable(false);
setMarkAsError(false);
setIsInputUsernamePremium(false);
return;
}

const { data } = await fetchUsername(username, null);
setMarkAsError(!data.available && !!currentUsername && username !== currentUsername);
setIsInputUsernamePremium(data.premium);
setUsernameIsAvailable(data.available);
}
debouncedApiCall(inputUsernameValue);
}, [debouncedApiCall, inputUsernameValue]);

checkUsername(debouncedUsername);
}, [debouncedUsername, currentUsername]);

const updateUsername = trpc.viewer.updateProfile.useMutation({
onSuccess: async () => {
Expand Down
42 changes: 20 additions & 22 deletions apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import classNames from "classnames";
// eslint-disable-next-line no-restricted-imports
import { debounce, noop } from "lodash";
import { noop } from "lodash";
import { useSession } from "next-auth/react";
import type { RefCallback } from "react";
import { useEffect, useMemo, useState } from "react";
import { useEffect, useState } from "react";

import { fetchUsername } from "@calcom/lib/fetchUsername";
import { useDebounce } from "@calcom/lib/hooks/useDebounce";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
import { trpc } from "@calcom/trpc/react";
Expand Down Expand Up @@ -41,31 +42,28 @@ const UsernameTextfield = (props: ICustomUsernameProps & Partial<React.Component
const [markAsError, setMarkAsError] = useState(false);
const [openDialogSaveUsername, setOpenDialogSaveUsername] = useState(false);

const debouncedApiCall = useMemo(
() =>
debounce(async (username) => {
// TODO: Support orgSlug
// debounce the username input, set the delay to 600ms to be consistent with signup form
const debouncedUsername = useDebounce(inputUsernameValue, 600);

useEffect(() => {
async function checkUsername(username: string | undefined) {
if (!username) {
setUsernameIsAvailable(false);
setMarkAsError(false);
return;
}

if (currentUsername !== username) {
const { data } = await fetchUsername(username, null);
setMarkAsError(!data.available);
setUsernameIsAvailable(data.available);
}, 150),
[]
);

useEffect(() => {
if (!inputUsernameValue) {
debouncedApiCall.cancel();
setUsernameIsAvailable(false);
setMarkAsError(false);
return;
} else {
setUsernameIsAvailable(false);
}
}

if (currentUsername !== inputUsernameValue) {
debouncedApiCall(inputUsernameValue);
} else {
setUsernameIsAvailable(false);
}
}, [inputUsernameValue, debouncedApiCall, currentUsername]);
checkUsername(debouncedUsername);
}, [debouncedUsername, currentUsername]);

const updateUsernameMutation = trpc.viewer.updateProfile.useMutation({
onSuccess: async () => {
Expand Down
1 change: 1 addition & 0 deletions apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
eventSlug: slug,
isTeamEvent,
org,
fromRedirectOfNonOrgLink: context.query.orgRedirection === "true",
});

if (!eventData) {
Expand Down
28 changes: 17 additions & 11 deletions apps/web/modules/bookings/views/bookings-single-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ export default function Success(props: PageProps) {
function getTitle(): string {
const titleSuffix = props.recurringBookings ? "_recurring" : "";
const titlePrefix = isRoundRobin ? "round_robin_" : "";
if (isCancelled) {
if (isCancelled || isBookingInPast) {
return "";
}
if (needsConfirmation) {
Expand Down Expand Up @@ -340,6 +340,8 @@ export default function Success(props: PageProps) {

const providerName = guessEventLocationType(location)?.label;
const rescheduleProviderName = guessEventLocationType(rescheduleLocation)?.label;
const isBookingInPast = new Date(bookingInfo.endTime) < new Date();
const isReschedulable = !isCancelled && !isBookingInPast;

const bookingCancelledEventProps = {
booking: bookingInfo,
Expand Down Expand Up @@ -412,7 +414,7 @@ export default function Success(props: PageProps) {
imageSrc={`${bookingInfo.user.avatarUrl}`}
/>
)}
{giphyImage && !needsConfirmation && !isCancelled && (
{giphyImage && !needsConfirmation && isReschedulable && (
// eslint-disable-next-line @next/next/no-img-element
<img src={giphyImage} className="w-full rounded-lg" alt="Gif from Giphy" />
)}
Expand All @@ -421,32 +423,36 @@ export default function Success(props: PageProps) {
"mx-auto flex h-12 w-12 items-center justify-center rounded-full",
isRoundRobin &&
"border-cal-bg dark:border-cal-bg-muted absolute bottom-0 right-0 z-10 h-12 w-12 border-8",
!giphyImage && !isCancelled && !needsConfirmation ? "bg-success" : "",
!giphyImage && !isCancelled && needsConfirmation ? "bg-subtle" : "",
isCancelled ? "bg-error" : ""
!giphyImage && isReschedulable && !needsConfirmation ? "bg-success" : "",
!giphyImage && isReschedulable && needsConfirmation ? "bg-subtle" : "",
isCancelled || isBookingInPast ? "bg-error" : ""
)}>
{!giphyImage && !needsConfirmation && !isCancelled && (
{!giphyImage && !needsConfirmation && isReschedulable && (
<Icon name="check" className="h-5 w-5 text-green-600 dark:text-green-400" />
)}
{needsConfirmation && !isCancelled && (
{needsConfirmation && isReschedulable && (
<Icon name="calendar" className="text-emphasis h-5 w-5" />
)}
{isCancelled && <Icon name="x" className="h-5 w-5 text-red-600 dark:text-red-200" />}
{(isCancelled || isBookingInPast) && (
<Icon name="x" className="h-5 w-5 text-red-600 dark:text-red-200" />
)}
</div>
</div>
<div className="mb-8 mt-6 text-center last:mb-0">
<h3
className="text-emphasis text-2xl font-semibold leading-6"
data-testid={isCancelled ? "cancelled-headline" : ""}
id="modal-headline">
{needsConfirmation && !isCancelled
{needsConfirmation && isReschedulable
? props.recurringBookings
? t("booking_submitted_recurring")
: t("booking_submitted")
: isCancelled
? seatReferenceUid
? t("no_longer_attending")
: t("event_cancelled")
: isBookingInPast
? t("event_expired")
: props.recurringBookings
? t("meeting_is_scheduled_recurring")
: t("meeting_is_scheduled")}
Expand Down Expand Up @@ -650,7 +656,7 @@ export default function Success(props: PageProps) {
)}
{!requiresLoginToUpdate &&
(!needsConfirmation || !userIsOwner) &&
!isCancelled &&
isReschedulable &&
(!isCancellationMode ? (
<>
<hr className="border-subtle mb-8" />
Expand Down Expand Up @@ -708,7 +714,7 @@ export default function Success(props: PageProps) {
{userIsOwner &&
!needsConfirmation &&
!isCancellationMode &&
!isCancelled &&
isReschedulable &&
!!calculatedDuration && (
<>
<hr className="border-subtle mt-8" />
Expand Down
Loading

0 comments on commit cc3e1cf

Please sign in to comment.