<!-- This is an auto-generated description by cubic. --> ## Summary by cubic Revamps onboarding with subtle route transitions, new org/teams illustrations, and clearer invite flows with real-time previews. Adds “Skip for now” on invites and guardrails to avoid incomplete team creation. - **New Features** - Added email invite pages for organizations and teams with shared EmailInviteForm and RoleSelector. - Built a live invite browser preview that renders a 3×3 grid and updates as you type; works for orgs and teams. - Applied route-keyed framer-motion transitions to layout, cards, and browser views for smoother page changes. - Continuation prompt now detects saved org or team and routes to the right next step; localized copy. - Added loading state to plan selection to prevent double navigation. - Refreshed Organizations welcome modal with a new animated ring illustration and better scrolling. - Added “Skip for now” to org and team invite-by-email steps to proceed without invites. - Calendar browser preview now focuses on a time window around “now” for a more realistic demo. - Added an optional floating footer to keep actions visible on long, scrollable lists. - **Refactors and Fixes** - Unified invite browser and replaced the org preview on the org email step. - Split and simplified legacy invite views; team and org routes are cleaner and easier to extend. - Streamlined the team invite step by removing a redundant action; non-admins are redirected to the email invite page. - Prevented creating teams with empty details by redirecting back to team details. - Minor UI cleanup: tighter borders, padding, and mobile max-heights across onboarding screens. - Hide team select on org invites when no teams exist. <sup>Written for commit ae7f5277ab998560ae6e2f3f9144852a7b4959a7. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. -->
94 lines
2.6 KiB
TypeScript
94 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import { usePathname } from "next/navigation";
|
|
import type { ReactNode } from "react";
|
|
|
|
import { SkeletonText } from "@calcom/ui/components/skeleton";
|
|
|
|
type OnboardingCardProps = {
|
|
title: string;
|
|
subtitle: string;
|
|
children: ReactNode;
|
|
footer: ReactNode;
|
|
isLoading?: boolean;
|
|
floatingFooter?: boolean;
|
|
};
|
|
|
|
export const OnboardingCard = ({
|
|
title,
|
|
subtitle,
|
|
children,
|
|
footer,
|
|
isLoading,
|
|
floatingFooter = false,
|
|
}: OnboardingCardProps) => {
|
|
const pathname = usePathname();
|
|
|
|
// Animation variants for entry and exit
|
|
const containerVariants = {
|
|
initial: {
|
|
opacity: 0,
|
|
y: 20,
|
|
},
|
|
animate: {
|
|
opacity: 1,
|
|
y: 0,
|
|
},
|
|
exit: {
|
|
opacity: 0,
|
|
y: -20,
|
|
},
|
|
};
|
|
|
|
return (
|
|
<div className="relative flex h-full min-h-0 w-full flex-col">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={pathname}
|
|
className="flex h-full min-h-0 w-full flex-col"
|
|
variants={containerVariants}
|
|
initial="initial"
|
|
animate="animate"
|
|
exit="exit"
|
|
transition={{
|
|
duration: 0.5,
|
|
ease: "backOut",
|
|
}}>
|
|
{/* Card Header */}
|
|
<div className="mb-2 flex w-full gap-1.5 py-2 md:mb-0 md:py-4">
|
|
<div className="flex w-full flex-col gap-2">
|
|
<h1 className="font-cal text-xl font-semibold leading-6">{title}</h1>
|
|
<p className="text-subtle text-sm leading-tight">{subtitle}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div
|
|
className={`flex h-full min-h-0 w-full flex-1 flex-col gap-4 [container-type:size] ${
|
|
floatingFooter ? "pb-10" : ""
|
|
}`}>
|
|
{isLoading ? (
|
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
<SkeletonText className="h-40 w-full" />
|
|
<SkeletonText className="h-40 w-full" />
|
|
</div>
|
|
) : (
|
|
children
|
|
)}
|
|
</div>
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
|
|
{/* Footer */}
|
|
{floatingFooter ? (
|
|
<div className="absolute bottom-0 left-0 right-[12px] z-10 flex items-center justify-start rounded-[12px] bg-[rgba(255,255,255,0.01)] p-2 shadow-[0px_12px_32px_-6px_rgba(0,0,0,0.12),0px_0px_0px_1px_rgba(111,107,107,0.1),0px_1px_3px_0px_rgba(63,70,75,0.1)] backdrop-blur-[6px] backdrop-filter">
|
|
{footer}
|
|
</div>
|
|
) : (
|
|
<div className="mt-4 flex w-full items-center justify-start py-2">{footer}</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|