Skip to content

Commit b185cd2

Browse files
authored
feat: login overlay re design (calcom#27800)
1 parent 4c804cd commit b185cd2

2 files changed

Lines changed: 129 additions & 149 deletions

File tree

apps/web/modules/videos/views/videos-single-view.tsx

Lines changed: 123 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
1313
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
1414
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
1515
import classNames from "@calcom/ui/classNames";
16+
import { Badge } from "@calcom/ui/components/badge";
1617
import { Button } from "@calcom/ui/components/button";
1718
import { Dialog, DialogContent } from "@calcom/ui/components/dialog";
1819
import { Input } from "@calcom/ui/components/form";
@@ -120,7 +121,7 @@ export default function JoinCall(props: PageProps) {
120121
}
121122

122123
return callFrame;
123-
} catch (err) {
124+
} catch (_err) {
124125
return DailyIframe.getCallInstance();
125126
}
126127
},
@@ -160,8 +161,6 @@ export default function JoinCall(props: PageProps) {
160161
activeMeetingPassword,
161162
activeMeetingUrl,
162163
createCallFrame,
163-
loggedInUserName,
164-
overrideName,
165164
guestCredentials,
166165
]);
167166

@@ -182,7 +181,7 @@ export default function JoinCall(props: PageProps) {
182181
<div style={{ zIndex: 2, position: "relative" }}>
183182
{calVideoLogo ? (
184183
<img
185-
className="min-w-16 min-h-16 fixed z-10 hidden aspect-square h-16 w-16 rounded-full sm:inline-block"
184+
className="fixed z-10 hidden aspect-square h-16 min-h-16 w-16 min-w-16 rounded-full sm:inline-block"
186185
src={calVideoLogo}
187186
alt="My Org Logo"
188187
style={{
@@ -206,6 +205,8 @@ export default function JoinCall(props: PageProps) {
206205
<LogInOverlay
207206
isOpen={!hideLoginModal}
208207
bookingUid={booking.uid}
208+
bookingTitle={booking.title}
209+
hostName={booking.user?.name ?? ""}
209210
loggedInUserName={loggedInUserName ?? undefined}
210211
overrideName={overrideName}
211212
requireEmailForGuests={requireEmailForGuests}
@@ -292,6 +293,8 @@ function ProgressBar(props: ProgressBarProps) {
292293
interface LogInOverlayProps {
293294
isOpen: boolean;
294295
bookingUid: string;
296+
bookingTitle: string;
297+
hostName: string;
295298
loggedInUserName?: string;
296299
overrideName?: string;
297300
requireEmailForGuests?: boolean;
@@ -308,6 +311,8 @@ export function LogInOverlay(props: LogInOverlayProps) {
308311
const { t } = useLocale();
309312
const {
310313
bookingUid,
314+
bookingTitle,
315+
hostName,
311316
isOpen: _open,
312317
loggedInUserName,
313318
overrideName,
@@ -441,100 +446,75 @@ export function LogInOverlay(props: LogInOverlayProps) {
441446

442447
return (
443448
<Dialog open={isOpen} onOpenChange={setIsOpen}>
444-
<DialogContent
445-
title={t("join_video_call")}
446-
description={t("choose_how_you_d_like_to_appear_on_the_call")}
447-
className="p-6 sm:max-w-lg"
448-
onInteractOutside={(e) => e.preventDefault()}>
449-
<div className="mt-2 pb-4">
450-
<div className="stack-y-4">
451-
<div>
452-
<div className="font-semibold">{t("join_as_guest")}</div>
453-
<p className="text-subtle text-sm">{t("ideal_for_one_time_calls")}</p>
454-
</div>
455-
456-
{requireEmailForGuests ? (
457-
<div className="flex flex-col gap-4">
458-
<Input
459-
type="text"
460-
placeholder={t("your_name")}
461-
className="w-full flex-1"
462-
value={userName}
463-
onChange={handleUserNameChange}
464-
onKeyDown={handleKeyDown}
465-
disabled={isLoading}
466-
autoFocus
467-
/>
468-
469-
<Input
470-
type="email"
471-
placeholder={t("email_address")}
472-
className="w-full flex-1"
473-
value={userEmail}
474-
onChange={handleEmailChange}
475-
onKeyDown={handleKeyDown}
476-
disabled={isLoading}
477-
/>
478-
479-
<Button
480-
color="secondary"
481-
className="w-fit self-end"
482-
onClick={handleContinueAsGuest}
483-
loading={isLoading}>
484-
{t("continue")}
485-
</Button>
449+
<DialogContent className="p-6 sm:max-w-md" onInteractOutside={(e) => e.preventDefault()}>
450+
<div className="flex flex-col gap-5">
451+
<div className="flex items-center justify-between rounded-lg border border-subtle p-3">
452+
<div className="flex items-center gap-3">
453+
<div className="flex h-10 w-10 items-center justify-center rounded-md bg-subtle">
454+
<Icon name="calendar-days" className="h-5 w-5 text-default" />
486455
</div>
487-
) : (
488-
<div className="flex gap-4">
489-
<Input
490-
type="text"
491-
placeholder={t("your_name")}
492-
className="w-full flex-1"
493-
value={userName}
494-
onChange={handleUserNameChange}
495-
onKeyDown={handleKeyDown}
496-
disabled={isLoading}
497-
autoFocus
498-
/>
499-
<Button color="secondary" onClick={handleContinueAsGuest} loading={isLoading}>
500-
{t("continue")}
501-
</Button>
456+
<div>
457+
<p className="font-semibold text-emphasis text-sm">{bookingTitle}</p>
458+
<p className="text-subtle text-xs">{t("hosted_by", { name: hostName })}</p>
502459
</div>
503-
)}
460+
</div>
461+
<Badge variant="success" withDot>
462+
{t("ready")}
463+
</Badge>
504464
</div>
505465

506-
{error && (
507-
<div className="mt-4 rounded-md bg-red-50 p-3 dark:bg-red-900/20">
508-
<div className="flex">
509-
<div className="ml-3">
510-
<p className="text-sm font-medium text-red-800 dark:text-red-200">{error}</p>
511-
</div>
512-
</div>
513-
</div>
514-
)}
466+
<div>
467+
<h3 className="font-bold text-emphasis text-lg">{t("ready_to_join")}</h3>
468+
<p className="text-sm text-subtle">{t("enter_name_to_join_call")}</p>
469+
</div>
515470

516-
{/* Divider */}
517-
<hr className="my-6 h-0.5 border-t-0 bg-neutral-100 dark:bg-white/10" />
471+
<div className="flex flex-col gap-3">
472+
<Input
473+
type="text"
474+
placeholder={t("your_name")}
475+
className="w-full"
476+
value={userName}
477+
onChange={handleUserNameChange}
478+
onKeyDown={handleKeyDown}
479+
disabled={isLoading}
480+
autoFocus
481+
/>
518482

519-
<div className="stack-y-4 mt-5">
520-
<div>
521-
<h4 className="text-base font-semibold text-black dark:text-white">
522-
{t("sign_in_to_cal_com")}
523-
</h4>
524-
<p className="text-sm text-gray-500 dark:text-gray-300">
525-
{t("track_meetings_and_manage_schedule")}
526-
</p>
527-
</div>
483+
{requireEmailForGuests && (
484+
<Input
485+
type="email"
486+
placeholder={t("email_address")}
487+
className="w-full"
488+
value={userEmail}
489+
onChange={handleEmailChange}
490+
onKeyDown={handleKeyDown}
491+
disabled={isLoading}
492+
/>
493+
)}
528494

529495
<Button
530496
color="primary"
531497
className="w-full justify-center"
532-
onClick={() =>
533-
(window.location.href = `${WEBAPP_URL}/auth/login?callbackUrl=${WEBAPP_URL}/video/${bookingUid}`)
534-
}>
535-
{t("sign_in")}
498+
onClick={handleContinueAsGuest}
499+
loading={isLoading}>
500+
{t("join_call_as_guest")}
536501
</Button>
537502
</div>
503+
504+
{error && (
505+
<div className="rounded-md bg-error p-3">
506+
<p className="font-medium text-error text-sm">{error}</p>
507+
</div>
508+
)}
509+
510+
<p className="text-center text-sm text-subtle">
511+
<a
512+
href={`${WEBAPP_URL}/auth/login?callbackUrl=${WEBAPP_URL}/video/${bookingUid}`}
513+
className="text-emphasis underline">
514+
{t("sign_in")}
515+
</a>{" "}
516+
{t("to_track_no_shows")}
517+
</p>
538518
</div>
539519
</DialogContent>
540520
</Dialog>
@@ -562,72 +542,66 @@ export function VideoMeetingInfo(props: VideoMeetingInfo) {
562542
});
563543

564544
return (
565-
<>
566-
<aside
567-
className={classNames(
568-
"no-scrollbar fixed left-0 top-0 z-30 flex h-full w-64 transform justify-between overflow-x-hidden overflow-y-scroll transition-all duration-300 ease-in-out",
569-
open ? "translate-x-0" : "-translate-x-[232px]"
570-
)}>
571-
<main className="prose-sm prose max-w-64 prose-a:text-white prose-h3:text-white prose-h3:font-cal scroll-bar scrollbar-track-w-20 overflow-x-hidden! bg-default w-full overflow-scroll border-r border-gray-300/20 p-4 text-white shadow-sm backdrop-blur-lg">
572-
<h3>{t("what")}:</h3>
573-
<p>{booking.title}</p>
574-
<h3>{t("invitee_timezone")}:</h3>
575-
<p>{timeZone}</p>
576-
<h3>{t("when")}:</h3>
577-
<p suppressHydrationWarning={true}>
578-
{formatToLocalizedDate(startTime)} <br />
579-
{formatToLocalizedTime({ date: startTime, timeZone })}
580-
</p>
581-
<h3>{t("time_left")}</h3>
582-
<ProgressBar
583-
key={String(open)}
584-
endTime={endTime.toISOString()}
585-
startTime={startTime.toISOString()}
586-
/>
587-
588-
<h3>{t("who")}:</h3>
589-
<p>
590-
{booking?.user?.name} - {t("organizer")}
591-
{!booking?.eventType?.hideOrganizerEmail && (
592-
<>
593-
: <a href={`mailto:${booking?.user?.email}`}>{booking?.user?.email}</a>
594-
</>
595-
)}
596-
</p>
597-
598-
{booking.attendees.length
599-
? booking.attendees.map((attendee) => (
600-
<p key={attendee.id}>
601-
{attendee.name}<a href={`mailto:${attendee.email}`}>{attendee.email}</a>
602-
</p>
603-
))
604-
: null}
605-
606-
{booking.description && (
545+
<aside
546+
className={classNames(
547+
"no-scrollbar fixed top-0 left-0 z-30 flex h-full w-64 transform justify-between overflow-x-hidden overflow-y-scroll transition-all duration-300 ease-in-out",
548+
open ? "translate-x-0" : "-translate-x-[232px]"
549+
)}>
550+
<main className="prose-sm prose scroll-bar scrollbar-track-w-20 overflow-x-hidden! w-full max-w-64 overflow-scroll border-subtle border-r bg-default p-4 prose-h3:font-cal prose-a:text-emphasis prose-h3:text-emphasis text-emphasis shadow-sm backdrop-blur-lg">
551+
<h3>{t("what")}:</h3>
552+
<p>{booking.title}</p>
553+
<h3>{t("invitee_timezone")}:</h3>
554+
<p>{timeZone}</p>
555+
<h3>{t("when")}:</h3>
556+
<p suppressHydrationWarning={true}>
557+
{formatToLocalizedDate(startTime)} <br />
558+
{formatToLocalizedTime({ date: startTime, timeZone })}
559+
</p>
560+
<h3>{t("time_left")}</h3>
561+
<ProgressBar key={String(open)} endTime={endTime.toISOString()} startTime={startTime.toISOString()} />
562+
563+
<h3>{t("who")}:</h3>
564+
<p>
565+
{booking?.user?.name} - {t("organizer")}
566+
{!booking?.eventType?.hideOrganizerEmail && (
607567
<>
608-
<h3>{t("description")}:</h3>
609-
610-
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: Content is sanitized via markdownToSafeHTML */}
611-
<div
612-
className="prose-sm prose prose-invert"
613-
dangerouslySetInnerHTML={{ __html: markdownToSafeHTML(booking.description) }}
614-
/>
568+
: <a href={`mailto:${booking?.user?.email}`}>{booking?.user?.email}</a>
615569
</>
616570
)}
617-
</main>
618-
<div className="flex items-center justify-center">
619-
<button
620-
aria-label={`${open ? "close" : "open"} booking description sidebar`}
621-
className="h-20 w-6 rounded-r-md border border-l-0 border-gray-300/20 bg-black/60 text-white shadow-sm backdrop-blur-lg"
622-
onClick={() => setOpen(!open)}>
623-
<Icon
624-
name="chevron-right"
625-
aria-hidden
626-
className={classNames(open && "rotate-180", "w-5 transition-all duration-300 ease-in-out")}
571+
</p>
572+
573+
{booking.attendees.length
574+
? booking.attendees.map((attendee) => (
575+
<p key={attendee.id}>
576+
{attendee.name}<a href={`mailto:${attendee.email}`}>{attendee.email}</a>
577+
</p>
578+
))
579+
: null}
580+
581+
{booking.description && (
582+
<>
583+
<h3>{t("description")}:</h3>
584+
585+
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: Content is sanitized via markdownToSafeHTML */}
586+
<div
587+
className="prose-sm prose prose-invert"
588+
dangerouslySetInnerHTML={{ __html: markdownToSafeHTML(booking.description) }}
627589
/>
628-
</button>
629-
</div>
630-
</aside>
631-
</>
590+
</>
591+
)}
592+
</main>
593+
<div className="flex items-center justify-center">
594+
<button
595+
aria-label={`${open ? "close" : "open"} booking description sidebar`}
596+
className="h-20 w-6 rounded-r-md border border-gray-300/20 border-l-0 bg-black/60 text-white shadow-sm backdrop-blur-lg"
597+
onClick={() => setOpen(!open)}>
598+
<Icon
599+
name="chevron-right"
600+
aria-hidden
601+
className={classNames(open && "rotate-180", "w-5 transition-all duration-300 ease-in-out")}
602+
/>
603+
</button>
604+
</div>
605+
</aside>
632606
);
633607
}

apps/web/public/static/locales/en/common.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,12 @@
745745
"custom_attendee_location": "Custom attendee location",
746746
"continue_as_guest": "Continue as guest",
747747
"join_as_guest": "Join as guest",
748+
"join_call_as_guest": "Join call as guest",
749+
"ready_to_join": "Ready to join?",
750+
"enter_name_to_join_call": "Enter your name to join the call",
751+
"hosted_by": "Hosted by {{name}}",
752+
"ready": "Ready",
753+
"to_track_no_shows": "to track no-shows",
748754
"ideal_for_one_time_calls": "Ideal for one-time calls",
749755
"hosts_must_use_login": "Hosts must login to cal.com and then join this meeting",
750756
"invalid_guest_email": "We don't recognize this email address for this meeting. Double-check you're using the same email that received the invitation.",

0 commit comments

Comments
 (0)