diff --git a/apps/web/components/ui/UsernameAvailability/index.tsx b/apps/web/components/ui/UsernameAvailability/index.tsx index e8d67a18ef..dfbadb2b00 100644 --- a/apps/web/components/ui/UsernameAvailability/index.tsx +++ b/apps/web/components/ui/UsernameAvailability/index.tsx @@ -6,6 +6,7 @@ import { Controller, useForm } from "react-hook-form"; import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider"; import { WEBSITE_URL, IS_SELF_HOSTED } from "@calcom/lib/constants"; +import slugify from "@calcom/lib/slugify"; import { trpc } from "@calcom/trpc/react"; import type { AppRouter } from "@calcom/trpc/types/server/routers/_app"; @@ -16,6 +17,7 @@ import type { TRPCClientErrorLike } from "@trpc/client"; interface UsernameAvailabilityFieldProps { onSuccessMutation?: () => void; onErrorMutation?: (error: TRPCClientErrorLike) => void; + disabled?: boolean; } interface ICustomUsernameProps extends UsernameAvailabilityFieldProps { @@ -37,14 +39,19 @@ const UsernameTextfield = dynamic(() => import("./UsernameTextfield").then((m) = }); export const UsernameAvailability = (props: ICustomUsernameProps) => { - const { isPremium, ...otherProps } = props; + const { isPremium, disabled, ...otherProps } = props; const UsernameAvailabilityComponent = isPremium ? PremiumTextfield : UsernameTextfield; - return ; + // PremiumTextfield uses `readonly` prop, UsernameTextfield uses `disabled` prop + const componentProps = isPremium + ? { ...otherProps, readonly: disabled } + : { ...otherProps, disabled }; + return ; }; export const UsernameAvailabilityField = ({ onSuccessMutation, onErrorMutation, + disabled, }: UsernameAvailabilityFieldProps) => { const searchParams = useSearchParams(); const [user] = trpc.viewer.me.get.useSuspenseQuery(); @@ -56,7 +63,7 @@ export const UsernameAvailabilityField = ({ : { username: currentUsernameState || "", setQuery: setCurrentUsernameState }; const formMethods = useForm({ defaultValues: { - username: currentUsername, + username: slugify(currentUsername || user.username || ""), }, }); @@ -78,10 +85,14 @@ export const UsernameAvailabilityField = ({ setCurrentUsername={setCurrentUsername} inputUsernameValue={value} usernameRef={ref} - setInputUsernameValue={onChange} + setInputUsernameValue={(val) => { + const displayValue = slugify(val, true); + formMethods.setValue("username", displayValue); + onChange?.(displayValue); + }} onSuccessMutation={onSuccessMutation} onErrorMutation={onErrorMutation} - disabled={!!user.organization?.id} + disabled={disabled ?? !!user.organization?.id} addOnLeading={`${usernamePrefix}/`} isPremium={isPremium} /> diff --git a/apps/web/modules/onboarding/components/onboarding-calendar-browser-view.tsx b/apps/web/modules/onboarding/components/onboarding-calendar-browser-view.tsx index f45e562c50..085e67eaad 100644 --- a/apps/web/modules/onboarding/components/onboarding-calendar-browser-view.tsx +++ b/apps/web/modules/onboarding/components/onboarding-calendar-browser-view.tsx @@ -1,91 +1,58 @@ "use client"; -import { WEBAPP_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Icon, type IconName } from "@calcom/ui/components/icon"; +import { useMemo } from "react"; + +import dayjs from "@calcom/dayjs"; +import { Calendar } from "@calcom/features/calendars/weeklyview"; +import { weekdayDates } from "@calcom/features/calendars/weeklyview/utils"; +import { CURRENT_TIMEZONE } from "@calcom/lib/timezoneConstants"; + +import { useOnboardingCalendarEvents } from "../hooks/useOnboardingCalendarEvents"; export const OnboardingCalendarBrowserView = () => { - const { t } = useLocale(); - const webappUrl = WEBAPP_URL.replace(/^https?:\/\//, ""); + const { startDate, endDate } = useMemo(() => { + return weekdayDates(0, new Date(), 6); + }, []); - const calendarIntegrations: Array<{ - name: string; - description: string; - icon: IconName; - }> = [ - { - name: t("google_calendar"), - description: t("onboarding_calendar_browser_view_google_description"), - icon: "calendar", - }, - { - name: t("outlook_calendar"), - description: t("onboarding_calendar_browser_view_outlook_description"), - icon: "mail", - }, - { - name: t("apple_calendar"), - description: t("onboarding_calendar_browser_view_apple_description"), - icon: "calendar-days", - }, - ]; + const { events } = useOnboardingCalendarEvents({ startDate, endDate }); + + // Memoize calendar props to prevent unnecessary re-initializations + const calendarProps = useMemo( + () => ({ + timezone: CURRENT_TIMEZONE, + startDate, + endDate, + events: events || [], + gridCellsPerHour: 4, + hoverEventDuration: 0, + showBackgroundPattern: false, + showBorder: false, + borderColor: "subtle" as const, + hideHeader: true, + eventsDisabled: true, + sortEvents: true, + isPending: false, // Explicitly set to false to prevent loading spinner + loading: false, // Also set loading to false just in case + onEventClick: () => {}, + onEmptyCellClick: () => {}, + onDateChange: () => {}, + showTimezone: true, + }), + [startDate, endDate, events] + ); return ( -
- {/* Browser header */} -
- {/* Navigation buttons */} -
- - - -
-
- -

{webappUrl}/settings/calendars

-
- +
+
+ + {dayjs(startDate).format("MMM D")} + + {dayjs(endDate).format("MMM D, YYYY")} +
- {/* Content */} -
-
- {/* Header */} -
-
-

- {t("connect_your_calendar")} -

-

- {t("onboarding_calendar_browser_view_subtitle")} -

-
-
- - {/* Calendar Integrations List */} -
- {calendarIntegrations.map((integration, index) => ( -
- {index > 0 &&
} -
-
-
- -
-
-

{integration.name}

-

- {integration.description} -

-
-
-
- {t("connected")} -
-
-
- ))} -
-
+ {/* Calendar View */} +
+
); diff --git a/apps/web/modules/onboarding/organization/teams/organization-teams-view.tsx b/apps/web/modules/onboarding/organization/teams/organization-teams-view.tsx index 645c618b74..c86d07b372 100644 --- a/apps/web/modules/onboarding/organization/teams/organization-teams-view.tsx +++ b/apps/web/modules/onboarding/organization/teams/organization-teams-view.tsx @@ -10,8 +10,9 @@ import { Button } from "@calcom/ui/components/button"; import { Form, TextField } from "@calcom/ui/components/form"; import { Icon } from "@calcom/ui/components/icon"; -import { OnboardingCard } from "../../personal/_components/OnboardingCard"; -import { OnboardingLayout } from "../../personal/_components/OnboardingLayout"; +import { OnboardingBrowserView } from "../../components/onboarding-browser-view"; +import { OnboardingCard } from "../../components/OnboardingCard"; +import { OnboardingLayout } from "../../components/OnboardingLayout"; import { useOnboardingStore } from "../../store/onboarding-store"; type OrganizationTeamsViewProps = { @@ -65,6 +66,7 @@ export const OrganizationTeamsView = ({ userEmail }: OrganizationTeamsViewProps) return ( + {/* Left column - Main content */} + + {/* Right column - Browser view */} + ); }; diff --git a/apps/web/modules/onboarding/personal/calendar/personal-calendar-view.tsx b/apps/web/modules/onboarding/personal/calendar/personal-calendar-view.tsx index f30674773e..dcbfda7dff 100644 --- a/apps/web/modules/onboarding/personal/calendar/personal-calendar-view.tsx +++ b/apps/web/modules/onboarding/personal/calendar/personal-calendar-view.tsx @@ -4,11 +4,11 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui/components/button"; +import { OnboardingCard } from "../../components/OnboardingCard"; +import { OnboardingLayout } from "../../components/OnboardingLayout"; import { OnboardingCalendarBrowserView } from "../../components/onboarding-calendar-browser-view"; import { useSubmitPersonalOnboarding } from "../../hooks/useSubmitPersonalOnboarding"; import { InstallableAppCard } from "../_components/InstallableAppCard"; -import { OnboardingCard } from "../../components/OnboardingCard"; -import { OnboardingLayout } from "../../components/OnboardingLayout"; import { useAppInstallation } from "../_components/useAppInstallation"; type PersonalCalendarViewProps = { diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index cfb3d04cd7..c6d3df8069 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -3972,5 +3972,33 @@ "repeats_num_times": "Repeats {{count}} times", "view_booking_details": "View Booking Details", "view": "View", + "team_bio": "Team Bio", + "team_bio_placeholder": "Tell us about your team...", + "onboarding_invite_subtitle": "Connect your Google workspace, invite via email, upload a CSV file or copy the invite link and share it with your teammates to add them to your Team.", + "upload_csv_subtitle": "Upload a CSV file with team member emails to bulk invite", + "need_template": "Need a template?", + "download_csv_template_description": "Download our CSV template to ensure your file is formatted correctly", + "download_template": "Download template", + "upload_your_file": "Upload your file", + "upload_csv_description": "Select a CSV file with email addresses and optional roles", + "choose_file": "Choose file", + "please_upload_csv_file": "Please upload a CSV file", + "template_downloaded": "Template downloaded successfully", + "please_select_file": "Please select a file to upload", + "csv_file_empty": "CSV file is empty or invalid", + "csv_missing_email_column": "CSV file must contain an 'email' column", + "csv_uploaded_successfully": "Successfully uploaded {{count}} invites", + "error_uploading_csv": "Error uploading CSV file", + "onboarding_browser_view_demo": "Demo", + "onboarding_browser_view_demo_description": "Schedule a demo call with us", + "onboarding_browser_view_quick_meeting": "Quick meeting", + "onboarding_browser_view_quick_meeting_description": "A quick chat", + "onboarding_browser_view_longer_meeting": "Longer meeting", + "onboarding_browser_view_longer_meeting_description": "A longer chat", + "onboarding_browser_view_in_person_description": "Meet in person", + "onboarding_browser_view_ask_question": "Ask a question", + "onboarding_browser_view_ask_question_description": "Ask a question", + "onboarding_browser_view_default_bio": "Find a time that suits you", + "book_now": "Book now", "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" } diff --git a/packages/config/tailwind-preset.js b/packages/config/tailwind-preset.js index b0c04a3ba1..3d192c3958 100644 --- a/packages/config/tailwind-preset.js +++ b/packages/config/tailwind-preset.js @@ -220,6 +220,8 @@ module.exports = { }, screens: { pwa: { raw: "(display-mode: standalone)" }, + "3xl": "1920px", + "4xl": "2560px", }, keyframes: { "fade-in-up": {