garage-erp/apps/dashboard/modules/bills/bill-status-badge.tsx
humam kerdiah 4f0a2f790f feat: add logo field to settings schema and update settings client to handle file uploads
feat: integrate dialog close context in vendor select field and CRUD dialog components

feat: enhance vendor general info to format status using utility function

feat: implement form dialog context for managing dialog close actions

feat: add async select field dialog close context for better form handling

fix: update form mutation hook to close dialog on successful submission

feat: extend document print types to include expense and credit note

feat: add settings update payload type to include logo and other fields

feat: create employee attendance and work history pages with resource management

feat: implement payment made and received detail pages with actions

feat: add quick shortcuts component for easy navigation in the dashboard

feat: create actions for payment made and received with print and delete options

feat: implement dialog close context for better dialog management

feat: add error parsing utility for improved error handling in API responses
2026-05-19 17:56:39 +04:00

88 lines
2.7 KiB
TypeScript

"use client"
import { BillStatus, parseApiError } from "@garage/api"
import { Badge, badgeVariants } from "@/shared/components/ui/badge"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/shared/components/ui/select"
import { confirm } from "@/shared/components/confirm-dialog"
import { useAuthApi } from "@/shared/useApi"
import { useRouter } from "next/navigation"
import { toast } from "sonner"
import { useState } from "react"
import { formatEnum } from "@/shared/utils/formatters"
const STATUS_TRIGGER_CLASS_NAMES: Record<string, string> = {
draft: badgeVariants({ variant: "outline" }),
open: badgeVariants({ variant: "secondary" }),
un_paid: badgeVariants({ variant: "destructive" }),
partially_paid: badgeVariants({ variant: "default" }),
paid: badgeVariants({ variant: "default" }),
}
function isBillStatus(value: unknown): value is BillStatus {
return typeof value === "string" && BillStatus.includes(value as BillStatus)
}
type BillStatusBadgeProps = {
bill: {
id: string
status: string | null | undefined
}
}
export default function BillStatusBadge({ bill }: BillStatusBadgeProps) {
const api = useAuthApi()
const router = useRouter()
const [isLoading, setIsLoading] = useState(false)
const { id: billId, status } = bill
if (!isBillStatus(status)) return null
const handleStatusChange = async (nextStatus: string) => {
if (!isBillStatus(nextStatus)) return
const confirmed = await confirm({
title: "Update Bill Status",
description: `Change bill status to ${formatEnum(nextStatus)}?`,
})
if (!confirmed) return
try {
setIsLoading(true)
await api.bills.update(billId, { status: nextStatus })
toast.success("Bill status updated")
router.refresh()
} catch (error) {
toast.error(parseApiError(error, "Failed to update bill status"))
} finally {
setIsLoading(false)
}
}
return (
<Select value={status} onValueChange={handleStatusChange} disabled={isLoading}>
<SelectTrigger
className={`border-0 size-auto p-0 h-auto font-medium ${STATUS_TRIGGER_CLASS_NAMES[status]}`}
>
<SelectValue placeholder="Select status">
{formatEnum(status)}
</SelectValue>
</SelectTrigger>
<SelectContent>
{BillStatus.map((s) => (
<SelectItem key={s} value={s}>
{formatEnum(s)}
</SelectItem>
))}
</SelectContent>
</Select>
)
}