.
This commit is contained in:
parent
d216119a91
commit
482dd5ef56
@ -15,20 +15,20 @@ interface CustomerCardProps {
|
|||||||
|
|
||||||
function buildAddress(customer: CustomerSummary) {
|
function buildAddress(customer: CustomerSummary) {
|
||||||
// Línea 1: calle(s)
|
// Línea 1: calle(s)
|
||||||
const line1 = [customer.street, customer.street2].filter(Boolean).join(", ");
|
const line1 = [customer.address.street, customer.address.street2].filter(Boolean).join(", ");
|
||||||
|
|
||||||
// Línea 2: CP + ciudad con espacio no rompible entre CP y ciudad
|
// Línea 2: CP + ciudad con espacio no rompible entre CP y ciudad
|
||||||
const line2Parts: string[] = [];
|
const line2Parts: string[] = [];
|
||||||
if (customer.postal_code && customer.city) {
|
if (customer.address.postal_code && customer.address.city) {
|
||||||
line2Parts.push(`${customer.postal_code}\u00A0${customer.city}`); // CP Ciudad
|
line2Parts.push(`${customer.address.postal_code}\u00A0${customer.address.city}`); // CP Ciudad
|
||||||
} else {
|
} else {
|
||||||
if (customer.postal_code) line2Parts.push(customer.postal_code);
|
if (customer.address.postal_code) line2Parts.push(customer.address.postal_code);
|
||||||
if (customer.city) line2Parts.push(customer.city);
|
if (customer.address.city) line2Parts.push(customer.address.city);
|
||||||
}
|
}
|
||||||
const line2 = line2Parts.join(" ");
|
const line2 = line2Parts.join(" ");
|
||||||
|
|
||||||
// Línea 3: provincia + país
|
// Línea 3: provincia + país
|
||||||
const line3 = [customer.province, customer.country].filter(Boolean).join(", ");
|
const line3 = [customer.address.province, customer.address.country].filter(Boolean).join(", ");
|
||||||
|
|
||||||
const stack = [line1, line2, line3].filter(Boolean);
|
const stack = [line1, line2, line3].filter(Boolean);
|
||||||
const inline = stack.join(" · "); // separador compacto
|
const inline = stack.join(" · "); // separador compacto
|
||||||
|
|||||||
@ -1,5 +1,23 @@
|
|||||||
import type { CustomerSelectionOption } from "@erp/customers";
|
import type { CustomerSelectionOption } from "@erp/customers";
|
||||||
import { Button } from "@repo/shadcn-ui/components";
|
import {
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@repo/shadcn-ui/components";
|
||||||
|
import { cn } from "@repo/shadcn-ui/lib/utils";
|
||||||
|
import {
|
||||||
|
Building2Icon,
|
||||||
|
ExternalLinkIcon,
|
||||||
|
MailIcon,
|
||||||
|
MapPinIcon,
|
||||||
|
PhoneIcon,
|
||||||
|
PlusIcon,
|
||||||
|
RefreshCwIcon,
|
||||||
|
UserIcon,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
import { useTranslation } from "../../../../../i18n";
|
import { useTranslation } from "../../../../../i18n";
|
||||||
|
|
||||||
@ -8,8 +26,40 @@ type SelectedRecipientSummaryProps = {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
|
||||||
recipient?: CustomerSelectionOption | null;
|
recipient?: CustomerSelectionOption | null;
|
||||||
|
|
||||||
onChangeClick: () => void;
|
onChangeClick: () => void;
|
||||||
onCreateClick?: () => void;
|
onCreateClick?: () => void;
|
||||||
|
onViewClick?: (recipient: CustomerSelectionOption) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildCustomerAddress = (recipient: CustomerSelectionOption): string => {
|
||||||
|
return [
|
||||||
|
recipient.street,
|
||||||
|
recipient.street2,
|
||||||
|
[recipient.postalCode, recipient.city].filter(Boolean).join(" "),
|
||||||
|
recipient.province,
|
||||||
|
recipient.country,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(", ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCustomerStatusBadgeClassName = (status: string): string => {
|
||||||
|
const normalizedStatus = status.toLowerCase();
|
||||||
|
|
||||||
|
if (["active", "activo", "enabled"].includes(normalizedStatus)) {
|
||||||
|
return "border-emerald-200 bg-emerald-50 text-emerald-700";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["inactive", "inactivo", "disabled"].includes(normalizedStatus)) {
|
||||||
|
return "border-muted bg-muted text-muted-foreground";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["blocked", "bloqueado"].includes(normalizedStatus)) {
|
||||||
|
return "border-destructive/20 bg-destructive/10 text-destructive";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "border-border bg-muted/50 text-muted-foreground";
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectedRecipientSummary = ({
|
export const SelectedRecipientSummary = ({
|
||||||
@ -19,43 +69,177 @@ export const SelectedRecipientSummary = ({
|
|||||||
recipient,
|
recipient,
|
||||||
onChangeClick,
|
onChangeClick,
|
||||||
onCreateClick,
|
onCreateClick,
|
||||||
|
onViewClick,
|
||||||
}: SelectedRecipientSummaryProps) => {
|
}: SelectedRecipientSummaryProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const showActions = !(readOnly || disabled);
|
||||||
|
const address = recipient ? buildCustomerAddress(recipient) : "";
|
||||||
|
const phone = recipient?.primaryPhone ?? recipient?.primaryMobile;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div
|
||||||
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
|
className={cn(
|
||||||
<div className="min-w-0">
|
"rounded-lg border p-4",
|
||||||
{recipient ? (
|
recipient ? "border-primary/20 bg-primary/[0.03]" : "bg-muted/20",
|
||||||
<div className="mt-2 space-y-1">
|
disabled && "opacity-70"
|
||||||
<p className="truncate font-medium">{recipient.name}</p>
|
)}
|
||||||
{recipient.tin ? (
|
>
|
||||||
<p className="truncate text-sm text-muted-foreground">{recipient.tin}</p>
|
<div className="flex flex-col gap-4 md:flex-row md:justify-between">
|
||||||
) : null}
|
<div className="flex min-w-0 flex-1 gap-4">
|
||||||
</div>
|
<div
|
||||||
) : (
|
className={cn(
|
||||||
<p className="mt-2 text-sm text-muted-foreground">
|
"flex size-14 shrink-0 items-center justify-center rounded-full",
|
||||||
{t("customers.selected_customer.empty", "No hay ningún cliente seleccionado")}
|
recipient ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"
|
||||||
</p>
|
)}
|
||||||
)}
|
>
|
||||||
|
{recipient?.isCompany ? (
|
||||||
|
<Building2Icon className="size-6" />
|
||||||
|
) : (
|
||||||
|
<UserIcon className="size-6" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="min-w-0 space-y-2">
|
||||||
|
{recipient ? (
|
||||||
|
<div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(260px,0.8fr)]">
|
||||||
|
<div className="min-w-0 space-y-2">
|
||||||
|
<div className="min-w-0 space-y-1">
|
||||||
|
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
||||||
|
<p className="truncate text-base font-semibold">{recipient.name}</p>
|
||||||
|
|
||||||
|
{recipient.status ? (
|
||||||
|
<Badge
|
||||||
|
className={cn(
|
||||||
|
"border",
|
||||||
|
getCustomerStatusBadgeClassName(recipient.status)
|
||||||
|
)}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
{recipient.status}
|
||||||
|
</Badge>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{recipient.tradeName && recipient.tradeName !== recipient.name ? (
|
||||||
|
<p className="truncate text-sm text-muted-foreground">
|
||||||
|
{recipient.tradeName}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{recipient.tin ? (
|
||||||
|
<p className="text-xs text-muted-foreground">{recipient.tin}</p>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1 text-sm text-muted-foreground">
|
||||||
|
{recipient.primaryEmail ? (
|
||||||
|
<div className="flex min-w-0 items-center gap-1">
|
||||||
|
<MailIcon className="size-3.5 shrink-0" />
|
||||||
|
<span className="truncate">{recipient.primaryEmail}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{phone ? (
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<PhoneIcon className="size-3.5 shrink-0" />
|
||||||
|
{phone}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="min-w-0 space-y-2 lg:border-l lg:pl-4">
|
||||||
|
{address ? (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger
|
||||||
|
render={
|
||||||
|
<div className="flex items-start gap-1 text-sm text-muted-foreground">
|
||||||
|
<MapPinIcon className="mt-0.5 size-3.5 shrink-0" />
|
||||||
|
<span className="line-clamp-3">{address}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TooltipContent align="start" className="max-w-md">
|
||||||
|
{address}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{t("customers.selected_customer.no_address", "Sin dirección registrada")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">
|
||||||
|
{t("customers.selected_customer.empty_title", "Cliente no seleccionado")}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{t("customers.selected_customer.empty", "Selecciona o crea un cliente")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
{showActions ? (
|
||||||
{onCreateClick && !readOnly && !disabled && (
|
<div className="flex shrink-0 flex-wrap gap-2 md:flex-col md:items-stretch">
|
||||||
<Button onClick={onCreateClick} type="button" variant="outline">
|
{recipient && onViewClick ? (
|
||||||
{t("customers.selected_customer.new_customer", "Nuevo cliente")}
|
<Button onClick={() => onViewClick(recipient)} type="button" variant="ghost">
|
||||||
</Button>
|
<ExternalLinkIcon className="mr-2 size-4" />
|
||||||
)}
|
{t("customers.selected_customer.view", "Ver cliente")}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{onChangeClick && !readOnly && !disabled && (
|
{onCreateClick ? (
|
||||||
<Button onClick={onChangeClick} type="button" variant="secondary">
|
<Button onClick={onCreateClick} type="button" variant="outline">
|
||||||
|
<PlusIcon className="mr-2 size-4" />
|
||||||
|
{t("customers.selected_customer.new_customer", "Nuevo cliente")}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={onChangeClick}
|
||||||
|
type="button"
|
||||||
|
variant={recipient ? "secondary" : "default"}
|
||||||
|
>
|
||||||
|
<RefreshCwIcon className="mr-2 size-4" />
|
||||||
{recipient
|
{recipient
|
||||||
? t("customers.selected_customer.change", "Cambiar cliente")
|
? t("customers.selected_customer.change", "Cambiar cliente")
|
||||||
: t("customers.selected_customer.select", "Seleccionar cliente")}
|
: t("customers.selected_customer.select", "Seleccionar cliente")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
</div>
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const buildAddress = (recipient: CustomerSelectionOption): string => {
|
||||||
|
// Línea 1: calle(s)
|
||||||
|
const line1 = [recipient.street, recipient.street2].filter(Boolean).join(", ");
|
||||||
|
|
||||||
|
// Línea 2: CP + ciudad con espacio no rompible entre CP y ciudad
|
||||||
|
const line2Parts: string[] = [];
|
||||||
|
if (recipient.postalCode && recipient.city) {
|
||||||
|
line2Parts.push(`${recipient.postalCode}\u00A0${recipient.city}`); // CP Ciudad
|
||||||
|
} else {
|
||||||
|
if (recipient.postalCode) line2Parts.push(recipient.postalCode);
|
||||||
|
if (recipient.city) line2Parts.push(recipient.city);
|
||||||
|
}
|
||||||
|
const line2 = line2Parts.join(" ");
|
||||||
|
|
||||||
|
// Línea 3: provincia + país
|
||||||
|
const line3 = [recipient.province, recipient.country].filter(Boolean).join(", ");
|
||||||
|
|
||||||
|
const stack = [line1, line2, line3].filter(Boolean);
|
||||||
|
const inline = stack.join(" · "); // separador compacto
|
||||||
|
const full = stack.join(", ");
|
||||||
|
|
||||||
|
return { has: stack.length > 0, stack, inline, full };
|
||||||
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
TextAreaField,
|
TextAreaField,
|
||||||
TextField,
|
TextField,
|
||||||
} from "@repo/rdx-ui/components";
|
} from "@repo/rdx-ui/components";
|
||||||
|
import { FileTextIcon } from "lucide-react";
|
||||||
|
|
||||||
import { useTranslation } from "../../../../i18n";
|
import { useTranslation } from "../../../../i18n";
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ export const ProformaUpdateHeaderEditor = ({
|
|||||||
return (
|
return (
|
||||||
<FormSectionCard
|
<FormSectionCard
|
||||||
description={t("form_groups.proformas.basic_info.description")}
|
description={t("form_groups.proformas.basic_info.description")}
|
||||||
|
disabled={disabled}
|
||||||
|
icon={<FileTextIcon className="size-5" />}
|
||||||
title={t("form_groups.proformas.basic_info.title")}
|
title={t("form_groups.proformas.basic_info.title")}
|
||||||
>
|
>
|
||||||
<FormSectionGrid>
|
<FormSectionGrid>
|
||||||
@ -83,7 +86,6 @@ export const ProformaUpdateHeaderEditor = ({
|
|||||||
placeholder={t("form_fields.proformas.notes.placeholder")}
|
placeholder={t("form_fields.proformas.notes.placeholder")}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</FormSectionGrid>
|
</FormSectionGrid>
|
||||||
</FormSectionCard>
|
</FormSectionCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { FormSectionCard } from "@repo/rdx-ui/components";
|
import { FormSectionCard } from "@repo/rdx-ui/components";
|
||||||
|
import { ListIcon } from "lucide-react";
|
||||||
import type { ComponentProps } from "react";
|
import type { ComponentProps } from "react";
|
||||||
|
|
||||||
import { useTranslation } from "../../../../i18n";
|
import { useTranslation } from "../../../../i18n";
|
||||||
@ -19,6 +20,8 @@ export const ProformaUpdateItemsEditor = ({
|
|||||||
return (
|
return (
|
||||||
<FormSectionCard
|
<FormSectionCard
|
||||||
description={t("form_groups.items.description")}
|
description={t("form_groups.items.description")}
|
||||||
|
disabled={disabled}
|
||||||
|
icon={<ListIcon className="size-5" />}
|
||||||
title={t("form_groups.items.title")}
|
title={t("form_groups.items.title")}
|
||||||
>
|
>
|
||||||
<ProformaLineEditor
|
<ProformaLineEditor
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import type { CustomerSelectionOption } from "@erp/customers";
|
import type { CustomerSelectionOption } from "@erp/customers";
|
||||||
import { FormSectionCard } from "@repo/rdx-ui/components";
|
import { FormSectionCard } from "@repo/rdx-ui/components";
|
||||||
|
import { UserIcon } from "lucide-react";
|
||||||
|
|
||||||
import { useTranslation } from "../../../../i18n";
|
import { useTranslation } from "../../../../i18n";
|
||||||
import { SelectedRecipientSummary } from "../blocks";
|
import { SelectedRecipientSummary } from "../blocks";
|
||||||
@ -24,7 +25,15 @@ export const ProformaUpdateRecipientEditor = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormSectionCard title={t("form_groups.proformas.customer.title")}>
|
<FormSectionCard
|
||||||
|
description={t(
|
||||||
|
"form_groups.proformas.customer.description",
|
||||||
|
"Cliente destinatario de la proforma"
|
||||||
|
)}
|
||||||
|
disabled={disabled}
|
||||||
|
icon={<UserIcon className="size-5" />}
|
||||||
|
title={t("form_groups.proformas.customer.title", "Cliente")}
|
||||||
|
>
|
||||||
<SelectedRecipientSummary
|
<SelectedRecipientSummary
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChangeClick={onChangeCustomerClick}
|
onChangeClick={onChangeCustomerClick}
|
||||||
|
|||||||
@ -76,7 +76,7 @@ export const ProformaUpdatePage = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
title={t("pages.proformas.update.title")}
|
title={<>{t("pages.proformas.update.title")}</>}
|
||||||
/>
|
/>
|
||||||
</AppHeader>
|
</AppHeader>
|
||||||
<AppContent className="space-y-4 max-w-5xl mx-auto">
|
<AppContent className="space-y-4 max-w-5xl mx-auto">
|
||||||
|
|||||||
@ -5,25 +5,21 @@
|
|||||||
*/
|
*/
|
||||||
export interface CustomerSelectionOption {
|
export interface CustomerSelectionOption {
|
||||||
id: string;
|
id: string;
|
||||||
//status: string;
|
status: string;
|
||||||
|
|
||||||
//isCompany: boolean;
|
isCompany: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
//tradeName: string;
|
tradeName: string | null;
|
||||||
tin: string;
|
tin: string | null;
|
||||||
|
|
||||||
/*street: string;
|
street: string | null;
|
||||||
street2: string;
|
street2: string | null;
|
||||||
city: string;
|
city: string | null;
|
||||||
province: string;
|
province: string | null;
|
||||||
postalCode: string;
|
postalCode: string | null;
|
||||||
country: string;
|
country: string | null;
|
||||||
*/
|
|
||||||
|
|
||||||
//emailPrimary: string;
|
primaryEmail: string | null;
|
||||||
//primaryPhone: string;
|
primaryPhone: string | null;
|
||||||
//primaryMobile: string;
|
primaryMobile: string | null;
|
||||||
|
|
||||||
languageCode: string;
|
|
||||||
currencyCode: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,11 +13,18 @@ export const buildCustomerSelectionOption = (
|
|||||||
|
|
||||||
isCompany: customer.isCompany,
|
isCompany: customer.isCompany,
|
||||||
name: customer.name,
|
name: customer.name,
|
||||||
|
tradeName: customer.tradeName,
|
||||||
tin: customer.tin,
|
tin: customer.tin,
|
||||||
|
|
||||||
EmailPrimary: customer.EmailPrimary,
|
street: customer.address.street,
|
||||||
|
street2: null,
|
||||||
|
city: customer.address.city,
|
||||||
|
province: customer.address.province,
|
||||||
|
postalCode: customer.address.postalCode,
|
||||||
|
country: customer.address.country,
|
||||||
|
|
||||||
languageCode: customer.languageCode,
|
primaryEmail: customer.contact.primaryEmail,
|
||||||
currencyCode: customer.currencyCode,
|
primaryPhone: customer.contact.primaryPhone,
|
||||||
|
primaryMobile: customer.contact.primaryMobile,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,7 +13,11 @@ import type { ReactNode } from "react";
|
|||||||
interface FormSectionCardProps {
|
interface FormSectionCardProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
icon?: ReactNode;
|
||||||
|
disabled?: boolean;
|
||||||
|
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|
||||||
className?: string;
|
className?: string;
|
||||||
headerClassName?: string;
|
headerClassName?: string;
|
||||||
contentClassName?: string;
|
contentClassName?: string;
|
||||||
@ -22,7 +26,11 @@ interface FormSectionCardProps {
|
|||||||
export const FormSectionCard = ({
|
export const FormSectionCard = ({
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
icon,
|
||||||
|
disabled = false,
|
||||||
|
|
||||||
children,
|
children,
|
||||||
|
|
||||||
className,
|
className,
|
||||||
headerClassName,
|
headerClassName,
|
||||||
contentClassName,
|
contentClassName,
|
||||||
@ -30,17 +38,32 @@ export const FormSectionCard = ({
|
|||||||
const hasHeader = Boolean(title || description);
|
const hasHeader = Boolean(title || description);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={cn("", className)}>
|
<Card className={cn(className)}>
|
||||||
<FieldSet>
|
<FieldSet disabled={disabled}>
|
||||||
{hasHeader ? (
|
{hasHeader ? (
|
||||||
<CardHeader className={headerClassName}>
|
<CardHeader className={cn("flex flex-row items-start gap-4", headerClassName)}>
|
||||||
<FieldLegend>
|
<FieldLegend className="w-full">
|
||||||
<div className="space-y-1">
|
<div className="flex items-start gap-3">
|
||||||
{title ? (
|
{icon ? (
|
||||||
<CardTitle className="text-base font-semibold tracking-tight">{title}</CardTitle>
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-10 shrink-0 items-center justify-center rounded-md",
|
||||||
|
disabled ? "bg-muted text-muted-foreground" : "bg-primary/10 text-primary"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{description ? <CardDescription>{description}</CardDescription> : null}
|
<div className="space-y-1">
|
||||||
|
{title ? (
|
||||||
|
<CardTitle className="text-base font-semibold tracking-tight">
|
||||||
|
{title}
|
||||||
|
</CardTitle>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{description ? <CardDescription>{description}</CardDescription> : null}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</FieldLegend>
|
</FieldLegend>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user