Files
calendar/apps/web/modules/onboarding/components/OnboardingCard.tsx
T
sean-brydonandGitHub 19641ffc05 feat: organization v3 redesign onboarding (#24967)
## What does this PR do?

- Redesigns the organization onboarding flow by merging the brand and details pages
- Improves the organization details page with a scrollable interface and visual previews
- Adds a new organization-specific browser preview component

## Visual Demo (For contributors especially)

#### Image Demo:
- The PR replaces the separate brand page with an integrated details page that includes logo and banner uploads
- The new organization browser view shows a preview of the organization profile with the selected branding

## Mandatory Tasks (DO NOT REMOVE)

- [ ] I have self-reviewed the code.
- [ ] I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
- [ ] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

- Go through the organization onboarding flow
- Test uploading logos and banners
- Verify that the organization browser preview updates in real-time with the form inputs
- Confirm that the form validation works correctly for organization name and slug
- Check that the scrollable interface works properly with fade effects at top and bottom

## Checklist

- I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code follows the style guidelines of this project
- I have commented my code, particularly in hard-to-understand areas
- I have checked if my changes generate no new warnings

















































<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Split organization brand from the details step and added live previews for organizations and teams. Revamped org/team invites with reusable components, a dedicated email-invite page, and a CSV upload modal.

- **New Features**
  - Separate Brand step with logo, banner, and color; instant org preview via OnboardingOrganizationBrowserView.
  - Teams browser preview added; invites include email substep (/onboarding/organization/invite/email, /onboarding/teams/invite/email), CSV upload (template + parsing), and Google Workspace (behind flag).
  - Shared components (EmailInviteForm, InviteOptions, RoleSelector) used across org and team invites.

- **Refactors**
  - Updated org flow: Details → Brand → Teams → Invites; OnboardingLayout now supports dynamic step counts (org=4, team=3, personal=2).
  - UI polish (OnboardingCard header padding) and org-specific previews now replace generic views across details/brand/invites/teams; ensured org welcome modal takes precedence over personal.

<sup>Written for commit d9b55c0b5505aa0d4ca1c4298a513bcd90606915. Summary will update automatically on new commits.</sup>

<!-- End of auto-generated description by cubic. -->
2025-11-13 10:45:42 +00:00

41 lines
1.2 KiB
TypeScript

import type { ReactNode } from "react";
import { SkeletonText } from "@calcom/ui/components/skeleton";
type OnboardingCardProps = {
title: string;
subtitle: string;
children: ReactNode;
footer: ReactNode;
isLoading?: boolean;
};
export const OnboardingCard = ({ title, subtitle, children, footer, isLoading }: OnboardingCardProps) => {
return (
<div className="relative flex h-full min-h-0 w-full flex-col">
{/* Card Header */}
<div className="flex w-full gap-1.5 px-5 py-4">
<div className="flex w-full flex-col gap-1">
<h1 className="font-cal text-xl font-semibold leading-6">{title}</h1>
<p className="text-subtle text-sm font-medium leading-tight">{subtitle}</p>
</div>
</div>
{/* Content */}
<div className="flex h-full min-h-0 w-full flex-1 flex-col gap-4">
{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>
{/* Footer */}
<div className="flex w-full items-center justify-start px-5 py-4">{footer}</div>
</div>
);
};