Fix COSS migration regressions (menu group, dialog padding, destructive button, auth form layout)

- MenuGroupLabel must live inside a MenuGroup (Base UI context) — wrap the
  label in nav-user, team-switcher, and nav-notifications. Fixes the
  'MenuGroupContext is missing' runtime error.
- Patient form/detail dialogs: COSS DialogPopup has no inner padding; move the
  body into DialogPanel (form as 'contents') so fields get p-6 instead of being
  flush to the edges.
- Settings 'Delete' button used the default variant + bg override, keeping a
  near-white border-primary in dark mode. Use variant='destructive'.
- Auth forms: COSS Field is items-start (no stretch). Make the submit button and
  the password-row/grid w-full, and underline the bottom sign-in/up link.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-03 18:50:54 +03:00
parent 4d6a5dc008
commit 98c5341604
8 changed files with 76 additions and 55 deletions
+7 -4
View File
@@ -14,9 +14,10 @@ import {
} from "@/components/ui/card";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
@@ -180,13 +181,15 @@ function ExpandableCard({
>
{children}
</DialogTrigger>
<DialogContent className="max-h-[80dvh] gap-4 overflow-y-auto sm:max-w-lg">
<DialogPopup className="max-h-[80dvh] sm:max-w-lg">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
{description ? <DialogDescription>{description}</DialogDescription> : null}
</DialogHeader>
{detail}
</DialogContent>
<DialogPanel className="min-h-0 flex-1 overflow-y-auto">
{detail}
</DialogPanel>
</DialogPopup>
</Dialog>
);
}
@@ -7,10 +7,11 @@ import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
@@ -234,7 +235,7 @@ export function PatientFormDialog({
return (
<Dialog onOpenChange={onOpenChange} open={open}>
<DialogContent className="flex max-h-[85dvh] flex-col gap-4 overflow-hidden sm:max-w-lg">
<DialogPopup className="max-h-[85dvh] sm:max-w-lg">
<DialogHeader>
<DialogTitle>{isEdit ? "Edit record" : "Add patient"}</DialogTitle>
<DialogDescription>
@@ -244,11 +245,11 @@ export function PatientFormDialog({
</DialogDescription>
</DialogHeader>
<form
className="flex min-h-0 flex-1 flex-col gap-4"
onSubmit={handleSubmit}
>
<div className="no-scrollbar flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto">
<form className="contents" onSubmit={handleSubmit}>
<DialogPanel
scrollFade={false}
className="no-scrollbar flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto"
>
<Field label="File number">
<div className="flex items-center gap-2">
<Input readOnly value={fileNumber} />
@@ -511,7 +512,7 @@ export function PatientFormDialog({
)}
rows={visits}
/>
</div>
</DialogPanel>
<DialogFooter className="flex-col items-stretch gap-2 sm:flex-row sm:items-center">
{error && (
@@ -525,7 +526,7 @@ export function PatientFormDialog({
</Button>
</DialogFooter>
</form>
</DialogContent>
</DialogPopup>
</Dialog>
);
}
+11 -6
View File
@@ -78,8 +78,8 @@ export function LoginForm({
value={email}
/>
</Field>
<Field>
<div className="flex items-center">
<Field className="w-full">
<div className="flex w-full items-center">
<FieldLabel htmlFor="password">
{t("auth.login.passwordLabel")}
</FieldLabel>
@@ -99,13 +99,18 @@ export function LoginForm({
value={password}
/>
</Field>
<Field>
<Button disabled={submitting} type="submit">
<Field className="w-full">
<Button className="w-full" disabled={submitting} type="submit">
{submitting ? t("auth.login.submitting") : t("auth.login.submit")}
</Button>
<FieldDescription className="text-center">
<FieldDescription className="w-full text-center">
{t("auth.login.noAccount")}{" "}
<Link href="/signup">{t("auth.login.signUpLink")}</Link>
<Link
className="font-medium text-foreground underline underline-offset-4"
href="/signup"
>
{t("auth.login.signUpLink")}
</Link>
</FieldDescription>
</Field>
</div>
@@ -171,9 +171,7 @@ export function ProfilePanel() {
keys. This action cannot be undone.
</p>
</div>
<Button className="rounded-lg bg-destructive text-white hover:bg-destructive/90">
Delete
</Button>
<Button variant="destructive">Delete</Button>
</SettingsCard>
</SettingsSection>
</>
@@ -4,6 +4,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Menu,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuPopup,
@@ -31,7 +32,9 @@ export function NotificationsPopover({
<Menu>
<MenuTrigger render={<Button variant="ghost" size="icon" className="rounded-full" aria-label="Open notifications" />}><BellIcon className="size-5" /></MenuTrigger>
<MenuPopup side="right" className="w-80 my-6">
<MenuGroupLabel>{t("nav.notifications")}</MenuGroupLabel>
<MenuGroup>
<MenuGroupLabel>{t("nav.notifications")}</MenuGroupLabel>
</MenuGroup>
<MenuSeparator />
{notifications.map(({ id, avatar, fallback, text, time }) => (
<MenuItem key={id} className="flex items-start gap-3">
+14 -11
View File
@@ -7,6 +7,7 @@ import { useRouter } from "next/navigation";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import {
Menu,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuPopup,
@@ -97,17 +98,19 @@ export function NavUser() {
side={isMobile ? "bottom" : isCollapsed ? "right" : "top"}
sideOffset={8}
>
<MenuGroupLabel className="flex items-center gap-2 py-2 text-foreground">
<Avatar className="size-8">
<AvatarFallback>{initials}</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">{name}</span>
<span className="truncate text-xs text-muted-foreground">
{email}
</span>
</div>
</MenuGroupLabel>
<MenuGroup>
<MenuGroupLabel className="flex items-center gap-2 py-2 text-foreground">
<Avatar className="size-8">
<AvatarFallback>{initials}</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">{name}</span>
<span className="truncate text-xs text-muted-foreground">
{email}
</span>
</div>
</MenuGroupLabel>
</MenuGroup>
<MenuSeparator />
<MenuItem render={<Link href="/settings" />}>
<SettingsIcon />
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
import {
Menu,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuPopup,
@@ -69,21 +70,23 @@ export function OrgSwitcher() {
side={isMobile ? "bottom" : isCollapsed ? "right" : "bottom"}
sideOffset={4}
>
<MenuGroupLabel className="text-xs text-muted-foreground">
Clinics
</MenuGroupLabel>
{(orgs ?? []).map((org) => (
<MenuItem
className="gap-2 p-2"
key={org.id}
onClick={() => setActive(org.id)}
>
<div className="flex size-6 items-center justify-center rounded-sm border">
<Building2 className="size-4 shrink-0" />
</div>
<span className="truncate">{org.name}</span>
</MenuItem>
))}
<MenuGroup>
<MenuGroupLabel className="text-xs text-muted-foreground">
Clinics
</MenuGroupLabel>
{(orgs ?? []).map((org) => (
<MenuItem
className="gap-2 p-2"
key={org.id}
onClick={() => setActive(org.id)}
>
<div className="flex size-6 items-center justify-center rounded-sm border">
<Building2 className="size-4 shrink-0" />
</div>
<span className="truncate">{org.name}</span>
</MenuItem>
))}
</MenuGroup>
<MenuSeparator />
<MenuItem
className="gap-2 p-2"
+11 -6
View File
@@ -108,8 +108,8 @@ export function SignupForm({
value={email}
/>
</Field>
<Field>
<Field className="grid grid-cols-2 gap-4">
<Field className="w-full">
<Field className="grid w-full grid-cols-2 gap-4">
<Field>
<FieldLabel htmlFor="password">
{t("auth.signup.passwordLabel")}
@@ -141,15 +141,20 @@ export function SignupForm({
{t("auth.signup.passwordHint", { count: MIN_PASSWORD })}
</FieldDescription>
</Field>
<Field>
<Button disabled={submitting} type="submit">
<Field className="w-full">
<Button className="w-full" disabled={submitting} type="submit">
{submitting
? t("auth.signup.submitting")
: t("auth.signup.submit")}
</Button>
<FieldDescription className="text-center">
<FieldDescription className="w-full text-center">
{t("auth.signup.haveAccount")}{" "}
<Link href="/login">{t("auth.signup.signInLink")}</Link>
<Link
className="font-medium text-foreground underline underline-offset-4"
href="/login"
>
{t("auth.signup.signInLink")}
</Link>
</FieldDescription>
</Field>
</div>