feat: enhance onboarding steps with loading state and button component (#20350)
- Added loading state to ConnectedCalendars and ConnectedVideoStep components. - Replaced native button elements with a custom Button component for consistency. - Updated SetupAvailability to use async mutation methods. - Integrated loading state into the onboarding view for smoother transitions between steps.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { List } from "@calcom/ui/components/list";
|
||||
|
||||
import { AppConnectionItem } from "../components/AppConnectionItem";
|
||||
@@ -11,10 +11,11 @@ import { StepConnectionLoader } from "../components/StepConnectionLoader";
|
||||
|
||||
interface IConnectCalendarsProps {
|
||||
nextStep: () => void;
|
||||
isPageLoading: boolean;
|
||||
}
|
||||
|
||||
const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
||||
const { nextStep } = props;
|
||||
const { nextStep, isPageLoading } = props;
|
||||
const queryConnectedCalendars = trpc.viewer.connectedCalendars.useQuery({
|
||||
onboarding: true,
|
||||
eventTypeId: null,
|
||||
@@ -81,18 +82,18 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
||||
|
||||
{queryIntegrations.isPending && <StepConnectionLoader />}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
EndIcon="arrow-right"
|
||||
data-testid="save-calendar-button"
|
||||
className={classNames(
|
||||
"text-inverted bg-inverted border-inverted mt-8 flex w-full flex-row justify-center rounded-md border p-2 text-center text-sm",
|
||||
disabledNextButton ? "cursor-not-allowed opacity-20" : ""
|
||||
)}
|
||||
loading={isPageLoading}
|
||||
onClick={() => nextStep()}
|
||||
disabled={disabledNextButton}>
|
||||
{firstCalendar ? `${t("continue")}` : `${t("next_step_text")}`}
|
||||
<Icon name="arrow-right" className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { userMetadata } from "@calcom/prisma/zod-utils";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { List } from "@calcom/ui/components/list";
|
||||
|
||||
import { AppConnectionItem } from "../components/AppConnectionItem";
|
||||
@@ -11,10 +11,11 @@ import { StepConnectionLoader } from "../components/StepConnectionLoader";
|
||||
|
||||
interface ConnectedAppStepProps {
|
||||
nextStep: () => void;
|
||||
isPageLoading: boolean;
|
||||
}
|
||||
|
||||
const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
|
||||
const { nextStep } = props;
|
||||
const { nextStep, isPageLoading } = props;
|
||||
const { data: queryConnectedVideoApps, isPending } = trpc.viewer.apps.integrations.useQuery({
|
||||
variant: "conferencing",
|
||||
onlyInstalled: false,
|
||||
@@ -70,18 +71,18 @@ const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
|
||||
)}
|
||||
|
||||
{isPending && <StepConnectionLoader />}
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
EndIcon="arrow-right"
|
||||
data-testid="save-video-button"
|
||||
className={classNames(
|
||||
"text-inverted border-inverted bg-inverted mt-8 flex w-full flex-row justify-center rounded-md border p-2 text-center text-sm",
|
||||
!hasAnyInstalledVideoApps ? "cursor-not-allowed opacity-20" : ""
|
||||
)}
|
||||
disabled={!hasAnyInstalledVideoApps}
|
||||
loading={isPageLoading}
|
||||
onClick={() => nextStep()}>
|
||||
{t("next_step_text")}
|
||||
<Icon name="arrow-right" className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -51,13 +51,13 @@ const SetupAvailability = (props: ISetupAvailabilityProps) => {
|
||||
handleSubmit={async (values) => {
|
||||
try {
|
||||
if (defaultScheduleId) {
|
||||
await updateSchedule.mutate({
|
||||
await updateSchedule.mutateAsync({
|
||||
scheduleId: defaultScheduleId,
|
||||
name: t("default_schedule_name"),
|
||||
...values,
|
||||
});
|
||||
} else {
|
||||
await createSchedule.mutate({
|
||||
await createSchedule.mutateAsync({
|
||||
name: t("default_schedule_name"),
|
||||
...values,
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import type { TFunction } from "i18next";
|
||||
import { signOut } from "next-auth/react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { Suspense } from "react";
|
||||
import { Suspense, useTransition } from "react";
|
||||
import { Toaster } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -93,6 +93,7 @@ const OnboardingPage = (props: PageProps) => {
|
||||
const router = useRouter();
|
||||
const [user] = trpc.viewer.me.get.useSuspenseQuery();
|
||||
const { t } = useLocale();
|
||||
const [isNextStepLoading, startTransition] = useTransition();
|
||||
|
||||
const result = stepRouteSchema.safeParse({
|
||||
...params,
|
||||
@@ -126,7 +127,9 @@ const OnboardingPage = (props: PageProps) => {
|
||||
const goToNextStep = () => {
|
||||
const nextIndex = currentStepIndex + 1;
|
||||
const newStep = steps[nextIndex];
|
||||
router.push(`/getting-started/${stepTransform(newStep)}`);
|
||||
startTransition(() => {
|
||||
router.push(`/getting-started/${stepTransform(newStep)}`);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -161,9 +164,13 @@ const OnboardingPage = (props: PageProps) => {
|
||||
{currentStep === "user-settings" && (
|
||||
<UserSettings nextStep={goToNextStep} hideUsername={from === "signup"} />
|
||||
)}
|
||||
{currentStep === "connected-calendar" && <ConnectedCalendars nextStep={goToNextStep} />}
|
||||
{currentStep === "connected-calendar" && (
|
||||
<ConnectedCalendars nextStep={goToNextStep} isPageLoading={isNextStepLoading} />
|
||||
)}
|
||||
|
||||
{currentStep === "connected-video" && <ConnectedVideoStep nextStep={goToNextStep} />}
|
||||
{currentStep === "connected-video" && (
|
||||
<ConnectedVideoStep nextStep={goToNextStep} isPageLoading={isNextStepLoading} />
|
||||
)}
|
||||
|
||||
{currentStep === "setup-availability" && (
|
||||
<SetupAvailability nextStep={goToNextStep} defaultScheduleId={user.defaultScheduleId} />
|
||||
|
||||
Reference in New Issue
Block a user