- 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.
136 lines
4.7 KiB
TypeScript
136 lines
4.7 KiB
TypeScript
import {
|
|
Building2,
|
|
CreditCard,
|
|
DollarSign,
|
|
Globe,
|
|
Mail,
|
|
Phone,
|
|
User,
|
|
} from "lucide-react"
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/shared/components/ui/card"
|
|
import { Badge } from "@/shared/components/ui/badge"
|
|
import { Separator } from "@/shared/components/ui/separator"
|
|
import { Money } from "@/shared/components/money"
|
|
|
|
type VendorData = {
|
|
id?: number
|
|
salutation?: string | null
|
|
first_name?: string | null
|
|
last_name?: string | null
|
|
company_name?: string | null
|
|
email?: string | null
|
|
phone?: string | null
|
|
alternate_phone?: string | null
|
|
website?: string | null
|
|
opening_balance?: number | string | null
|
|
credit_limit?: number | string | null
|
|
status?: string | null
|
|
created_at?: string
|
|
updated_at?: string
|
|
}
|
|
|
|
type VendorGeneralInfoProps = {
|
|
vendor: VendorData
|
|
}
|
|
|
|
function InfoItem({
|
|
icon: Icon,
|
|
label,
|
|
value,
|
|
}: {
|
|
icon: React.ComponentType<{ className?: string }>
|
|
label: string
|
|
value?: React.ReactNode
|
|
}) {
|
|
const isEmpty = value == null || value === ""
|
|
return (
|
|
<div className="flex items-start gap-3">
|
|
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
|
|
<Icon className="size-4" />
|
|
</div>
|
|
<div className="flex flex-col gap-0.5">
|
|
<span className="text-xs text-muted-foreground">{label}</span>
|
|
<span className="text-sm font-medium">
|
|
{isEmpty ? <span className="text-muted-foreground">—</span> : value}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function VendorGeneralInfo({ vendor }: VendorGeneralInfoProps) {
|
|
const fullName = [vendor.salutation, vendor.first_name, vendor.last_name]
|
|
.filter(Boolean)
|
|
.join(" ")
|
|
.trim()
|
|
|
|
return (
|
|
<div className="grid gap-6 md:grid-cols-2">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Building2 className="size-4" />
|
|
Vendor Information
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid gap-4">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<Badge variant="secondary">{vendor.company_name || fullName || "Unknown vendor"}</Badge>
|
|
{vendor.status && (
|
|
<Badge variant={vendor.status === "active" ? "default" : "outline"} className="capitalize">
|
|
{vendor.status}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
<Separator />
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
<InfoItem icon={Building2} label="Company" value={vendor.company_name} />
|
|
<InfoItem icon={User} label="Contact Name" value={fullName} />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<Phone className="size-4" />
|
|
Contact Details
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid gap-4 sm:grid-cols-2">
|
|
<InfoItem icon={Mail} label="Email" value={vendor.email} />
|
|
<InfoItem icon={Phone} label="Phone" value={vendor.phone} />
|
|
<InfoItem icon={Phone} label="Alternate Phone" value={vendor.alternate_phone} />
|
|
<InfoItem icon={Globe} label="Website" value={vendor.website} />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="md:col-span-2">
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center gap-2">
|
|
<DollarSign className="size-4" />
|
|
Financial Details
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid gap-4 sm:grid-cols-2">
|
|
<InfoItem
|
|
icon={DollarSign}
|
|
label="Opening Balance"
|
|
value={vendor.opening_balance != null ? <Money value={vendor.opening_balance} /> : null}
|
|
/>
|
|
<InfoItem
|
|
icon={CreditCard}
|
|
label="Credit Limit"
|
|
value={vendor.credit_limit != null ? <Money value={vendor.credit_limit} /> : null}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|