- Implemented TemplateCheckpointEditDialog for creating and editing inspection checkpoints. - Added VendorActions component for managing vendor actions including edit, activate/deactivate, and delete. - Created VendorContext for managing vendor state across components. - Developed VendorGeneralInfo component to display detailed vendor information. - Introduced AedSymbol and Money components for consistent currency representation. - Added PromptDialog for user input prompts throughout the application. - Implemented RelationLink component for unified related-data display in CRUD tables. - Created InspectionTemplatesClient for API interactions related to inspection templates.
79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
"use client"
|
|
|
|
import Link from "next/link"
|
|
import type { ComponentType, MouseEvent, ReactNode } from "react"
|
|
import { Button, buttonVariants } from "@/shared/components/ui/button"
|
|
import { cn } from "@/shared/lib/utils"
|
|
|
|
type IconComponent = ComponentType<{ className?: string }>
|
|
|
|
export type RelationLinkProps = {
|
|
/** Destination href. When falsy the chip renders as a non-interactive button-styled span. */
|
|
href?: string | null
|
|
/** Primary label rendered inside the button. */
|
|
label?: ReactNode
|
|
/** Optional icon shown before the label. */
|
|
icon?: IconComponent
|
|
/** Rendered when label is empty (with or without href). Defaults to "—". */
|
|
fallback?: ReactNode
|
|
/** Optional secondary text rendered after the label (e.g. phone, plate). */
|
|
meta?: ReactNode
|
|
className?: string
|
|
}
|
|
|
|
/**
|
|
* Unified cell for related-data columns across every CRUD table.
|
|
* Renders an outlined button-style chip either way:
|
|
* - With href: clickable next/link wrapped by a Button (asChild).
|
|
* - Without href: same outline styling on a plain span so visual columns
|
|
* stay consistent across resources that don't have detail routes.
|
|
*/
|
|
export function RelationLink({
|
|
href,
|
|
label,
|
|
icon: Icon,
|
|
fallback = "—",
|
|
meta,
|
|
className,
|
|
}: RelationLinkProps) {
|
|
const hasLabel = label != null && label !== ""
|
|
|
|
if (!hasLabel && !href) {
|
|
return <span className="text-muted-foreground">{fallback}</span>
|
|
}
|
|
|
|
const body = (
|
|
<>
|
|
{Icon ? <Icon /> : null}
|
|
<span>{hasLabel ? label : fallback}</span>
|
|
{meta ? <span className="ms-1 text-muted-foreground">· {meta}</span> : null}
|
|
</>
|
|
)
|
|
|
|
if (!href) {
|
|
return (
|
|
<span
|
|
className={cn(
|
|
buttonVariants({ variant: "outline", size: "sm" }),
|
|
"cursor-default pointer-events-none",
|
|
className,
|
|
)}
|
|
>
|
|
{body}
|
|
</span>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
asChild
|
|
className={className}
|
|
onClick={(event: MouseEvent<HTMLButtonElement>) => event.stopPropagation()}
|
|
>
|
|
<Link href={href}>{body}</Link>
|
|
</Button>
|
|
)
|
|
}
|