fix build
This commit is contained in:
parent
c0f78c6e18
commit
564e9e510f
@ -2,6 +2,7 @@ import DashboardPage from '@/base/components/layout/dashboard/dashboard-page'
|
||||
import { ExpenseGeneralInfo } from '@/modules/expenses/expense-general-info'
|
||||
import { ExpenseItemsSection } from '@/modules/expenses/expense-items-section'
|
||||
import { ExpensePaymentsSection } from '@/modules/expenses/expense-payments-section'
|
||||
import { formatTaxLabel } from '@/shared/utils/formatters'
|
||||
import { getServerApi } from '@garage/api/server'
|
||||
|
||||
export default async function ExpenseDetailPage(props: { params: Promise<{ id: string }> }) {
|
||||
@ -14,7 +15,7 @@ export default async function ExpenseDetailPage(props: { params: Promise<{ id: s
|
||||
return <div className="text-muted-foreground">Expense not found.</div>
|
||||
}
|
||||
|
||||
const taxLabel = data.tax?.title ? `${data.tax.title} (${data.tax.rate}%)` : undefined
|
||||
const taxLabel = formatTaxLabel(data.tax, '') || undefined
|
||||
|
||||
return (
|
||||
<DashboardPage header={null}>
|
||||
|
||||
@ -17,7 +17,7 @@ export const expenseItemFormSchema = z.object({
|
||||
purchase_information: z.boolean().default(true),
|
||||
purchase_price: z.coerce.number().min(0).optional(),
|
||||
purchase_chart_of_account: z.string().optional(),
|
||||
// purchase_preferred_vendor: relationFieldSchema,
|
||||
purchase_preferred_vendor: relationFieldSchema,
|
||||
// Sales
|
||||
sales_information: z.boolean().default(false),
|
||||
selling_price: z.coerce.number().min(0).optional(),
|
||||
|
||||
@ -3,7 +3,47 @@
|
||||
import { CrudShowResponse, ExpensesClient } from "@garage/api"
|
||||
import { createContext, useContext } from "react"
|
||||
|
||||
export type ExpenseContextValue = CrudShowResponse<ExpensesClient>['data']
|
||||
type BaseExpenseContextValue = NonNullable<CrudShowResponse<ExpensesClient>["data"]>
|
||||
|
||||
type ExpenseNamedRelation = {
|
||||
id?: number
|
||||
name?: string | null
|
||||
title?: string | null
|
||||
}
|
||||
|
||||
type ExpenseVendorRelation = ExpenseNamedRelation & {
|
||||
company_name?: string | null
|
||||
first_name?: string | null
|
||||
last_name?: string | null
|
||||
}
|
||||
|
||||
type ExpenseJobCardRelation = {
|
||||
id?: number
|
||||
order_number?: string | null
|
||||
estimate_number?: string | null
|
||||
title?: string | null
|
||||
}
|
||||
|
||||
type ExpenseTaxRelation = ExpenseNamedRelation & {
|
||||
rate?: string | number | null
|
||||
}
|
||||
|
||||
type ExpenseLabel = {
|
||||
id?: number
|
||||
title?: string | null
|
||||
color_code?: string | null
|
||||
}
|
||||
|
||||
export type ExpenseContextValue = BaseExpenseContextValue & {
|
||||
discount?: string | null
|
||||
discount_amount_major?: number | null
|
||||
vendor?: ExpenseVendorRelation | null
|
||||
department?: ExpenseNamedRelation | null
|
||||
category?: ExpenseNamedRelation | null
|
||||
job_card?: ExpenseJobCardRelation | null
|
||||
tax?: ExpenseTaxRelation | null
|
||||
labels?: ExpenseLabel[] | null
|
||||
}
|
||||
|
||||
|
||||
const ExpenseContext = createContext<ExpenseContextValue | null>(null)
|
||||
|
||||
@ -19,6 +19,7 @@ import { useAuthApi } from "@/shared/useApi"
|
||||
import { useResourceForm } from "@/shared/hooks/use-resource-form"
|
||||
import { useFormMutation } from "@/shared/hooks/use-form-mutation"
|
||||
import { getTodayDate, toRelation, toId } from "@/shared/lib/utils"
|
||||
import { formatTaxLabel } from "@/shared/utils/formatters"
|
||||
|
||||
import {
|
||||
expenseFormSchema,
|
||||
@ -89,7 +90,7 @@ function mapToFormValues(data: unknown): ExpenseFormValues {
|
||||
category: toRelation(d.category_id, d.category?.name ?? d.category?.title ?? d.category_name),
|
||||
vendor: toRelation(d.vendor_id, d.vendor?.company_name ?? d.vendor?.name ?? d.vendor_name),
|
||||
department: toRelation(d.department_id, d.department?.name ?? d.department_name),
|
||||
tax: toRelation(d.tax_id, d.tax?.title ? `${d.tax.title} (${d.tax.rate}%)` : undefined),
|
||||
tax: toRelation(d.tax_id, formatTaxLabel(d.tax, d.tax_title ?? "") || undefined),
|
||||
title: d.title || "",
|
||||
invoice_number: d.invoice_number || "",
|
||||
expense_date: d.expense_date ? d.expense_date.split("T")[0] : "",
|
||||
|
||||
@ -20,8 +20,7 @@ import {
|
||||
} from "@/shared/components/ui/card"
|
||||
import { Badge } from "@/shared/components/ui/badge"
|
||||
import { cn } from "@/shared/lib/utils"
|
||||
import { formatDate, formatCurrency, formatEnum } from "@/shared/utils/formatters"
|
||||
import { getFullName } from "@/shared/utils/getFullName"
|
||||
import { formatDate, formatCurrency, formatEnum, formatTaxLabel } from "@/shared/utils/formatters"
|
||||
import { useExpense } from "./expense-context"
|
||||
|
||||
function InfoItem({
|
||||
@ -68,9 +67,7 @@ export function ExpenseGeneralInfo() {
|
||||
const labels = (expense as any)?.labels || []
|
||||
const balanceDue = expense.balance_due ?? null
|
||||
const paymentsM = expense.payments_made ?? null
|
||||
const taxLabel = expense.tax?.title
|
||||
? `${expense.tax.title} (${expense.tax.rate}%)`
|
||||
: "Tax"
|
||||
const taxLabel = formatTaxLabel(expense.tax, "Tax")
|
||||
|
||||
return (
|
||||
<div className="grid gap-6">
|
||||
@ -122,7 +119,7 @@ export function ExpenseGeneralInfo() {
|
||||
{/* ── Vendor ── */}
|
||||
<Card className="flex flex-col gap-1 p-4">
|
||||
<span className="text-xs font-medium text-muted-foreground uppercase tracking-wide">Vendor</span>
|
||||
<span className="mt-1 text-lg font-semibold">{vendor.company_name || getFullName(vendor as any) || "—"}</span>
|
||||
<span className="mt-1 text-lg font-semibold">{vendor.name || "—"}</span>
|
||||
</Card>
|
||||
|
||||
{/* ── Expense Details ── */}
|
||||
|
||||
@ -21,6 +21,7 @@ import { useAuthApi } from "@/shared/useApi"
|
||||
import { useResourceForm } from "@/shared/hooks/use-resource-form"
|
||||
import { useFormMutation } from "@/shared/hooks/use-form-mutation"
|
||||
import { toRelation, toId } from "@/shared/lib/utils"
|
||||
import { formatTaxLabel } from "@/shared/utils/formatters"
|
||||
import { useFormContext } from "react-hook-form"
|
||||
|
||||
import {
|
||||
@ -120,7 +121,7 @@ function mapToFormValues(data: unknown): InvoiceFormValues {
|
||||
has_insurance: d.has_insurance ?? false,
|
||||
discount: d.discount || "no",
|
||||
discount_amount: d.discount_amount != null ? Number(d.discount_amount) : undefined,
|
||||
tax: toRelation(d.tax_id, d.tax_title ?? d.tax?.title),
|
||||
tax: toRelation(d.tax_id, d.tax_title ?? (formatTaxLabel(d.tax, "") || undefined)),
|
||||
deposit_to: d.deposit_to || "",
|
||||
notes: d.notes || "",
|
||||
terms_and_conditions: d.terms_and_conditions || "",
|
||||
|
||||
@ -36,7 +36,7 @@ export function InvoiceSequenceForm({ resourceId, initialData, onSuccess }: Invo
|
||||
const isEditing = !!resourceId
|
||||
|
||||
const form = useForm<InvoiceSequenceFormValues>({
|
||||
resolver: zodResolver(invoiceSequenceSchema),
|
||||
resolver: zodResolver(invoiceSequenceSchema) as any,
|
||||
defaultValues: {
|
||||
title: "",
|
||||
sequence_title: "",
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
import { DepartmentInlineForm } from "@/modules/services/inline-forms/department-inline-form"
|
||||
import { toast } from "sonner"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import { formatTaxLabel } from "@/shared/utils/formatters"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { DEPARTMENT_ROUTES, TAX_ROUTES } from "@garage/api"
|
||||
@ -71,7 +72,7 @@ function mapToFormValues(data: unknown): JobCardExpenseItemFormValues {
|
||||
? { value: String(d.department.id), label: d.department.name ?? String(d.department.id) }
|
||||
: null,
|
||||
tax: d.tax_id != null
|
||||
? { value: String(d.tax_id), label: d.tax ? `${d.tax.title} (${d.tax.rate}%)` : String(d.tax_id) }
|
||||
? { value: String(d.tax_id), label: formatTaxLabel(d.tax, String(d.tax_id)) }
|
||||
: null,
|
||||
quantity: d.quantity ?? 1,
|
||||
rate: d.rate != null ? Number(d.rate) : 0,
|
||||
|
||||
@ -20,6 +20,7 @@ import { useAuthApi } from "@/shared/useApi"
|
||||
import { useResourceForm } from "@/shared/hooks/use-resource-form"
|
||||
import { useFormMutation } from "@/shared/hooks/use-form-mutation"
|
||||
import { toRelation, toId } from "@/shared/lib/utils"
|
||||
import { formatTaxLabel } from "@/shared/utils/formatters"
|
||||
|
||||
import {
|
||||
jobCardFormSchema,
|
||||
@ -106,7 +107,7 @@ function mapToFormValues(data: unknown): JobCardFormValues {
|
||||
sales_person: toRelation(d.sales_person_id, d.sales_person ? `${d.sales_person.first_name} ${d.sales_person.last_name}` : undefined),
|
||||
insurance_type: toRelation(d.insurance_type_id, d.insurance_type?.name),
|
||||
insurer: toRelation(d.insurer_id, d.insurer ? `${d.insurer.first_name} ${d.insurer.last_name}`.trim() || d.insurer.company_name : undefined),
|
||||
tax: toRelation(d.tax_id, d.tax ? `${d.tax.title} (${d.tax.rate}%)` : undefined),
|
||||
tax: toRelation(d.tax_id, formatTaxLabel(d.tax, "") || undefined),
|
||||
order_number: d.order_number || "",
|
||||
estimate_number: d.estimate_number || "",
|
||||
status: d.status || "draft",
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
import { DepartmentInlineForm } from "@/modules/services/inline-forms/department-inline-form"
|
||||
import { toast } from "sonner"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import { formatTaxLabel } from "@/shared/utils/formatters"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { DEPARTMENT_ROUTES, TAX_ROUTES } from "@garage/api"
|
||||
@ -71,7 +72,7 @@ function mapToFormValues(data: unknown): JobCardPartFormValues {
|
||||
? { value: String(d.department.id), label: d.department.name ?? String(d.department.id) }
|
||||
: null,
|
||||
tax: d.tax_id != null
|
||||
? { value: String(d.tax_id), label: d.tax ? `${d.tax.title} (${d.tax.rate}%)` : String(d.tax_id) }
|
||||
? { value: String(d.tax_id), label: formatTaxLabel(d.tax, String(d.tax_id)) }
|
||||
: null,
|
||||
quantity: d.quantity ?? 1,
|
||||
rate: d.rate != null ? Number(d.rate) : 0,
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
import { DepartmentInlineForm } from "@/modules/services/inline-forms/department-inline-form"
|
||||
import { toast } from "sonner"
|
||||
import { useAuthApi } from "@/shared/useApi"
|
||||
import { formatTaxLabel } from "@/shared/utils/formatters"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { RateType, DEPARTMENT_ROUTES, TAX_ROUTES } from "@garage/api"
|
||||
@ -80,7 +81,7 @@ function mapToFormValues(data: unknown): JobCardServiceFormValues {
|
||||
? { value: String(d.department.id), label: d.department.name ?? String(d.department.id) }
|
||||
: undefined as any,
|
||||
tax: d.tax_id != null
|
||||
? { value: String(d.tax_id), label: d.tax ? `${d.tax.title} (${d.tax.rate}%)` : String(d.tax_id) }
|
||||
? { value: String(d.tax_id), label: formatTaxLabel(d.tax, String(d.tax_id)) }
|
||||
: null,
|
||||
rate_type: d.rate_type ?? "flat_rate",
|
||||
labor_rate: d.labor_rate
|
||||
|
||||
@ -56,6 +56,25 @@ export function formatEnum(value?: string | null): string {
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
type TaxLabelValue = {
|
||||
name?: string | null
|
||||
title?: string | null
|
||||
rate?: string | number | null
|
||||
}
|
||||
|
||||
export function formatTaxLabel(
|
||||
value?: TaxLabelValue | null,
|
||||
emptyFallback = "—",
|
||||
): string {
|
||||
const label = value?.name ?? value?.title
|
||||
const rate = value?.rate
|
||||
|
||||
if (!label) return emptyFallback
|
||||
if (rate == null || rate === "") return label
|
||||
|
||||
return `${label} (${rate}%)`
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a number with locale-aware thousand separators.
|
||||
* e.g. 150000 → "150,000"
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
export const getFullName = <T extends { first_name?: string | undefined; last_name?: string | undefined }>(user?: T) => {
|
||||
type NameLike = {
|
||||
first_name?: string | null
|
||||
last_name?: string | null
|
||||
}
|
||||
|
||||
export const getFullName = <T extends NameLike>(user?: T | null) => {
|
||||
const firstName = user?.first_name ?? ""
|
||||
const lastName = user?.last_name ?? ""
|
||||
return `${firstName} ${lastName}`.trim()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user