mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
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:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user