Skip to content

Quotation Page

Full ManpowerHub quotations list page block with KPI cards, validity tracking, filters, and route callbacks.

Open in

Quotations

Draft, send, revise, and accept manpower quotations

Total quotations
5

All quote records in the workspace

Pipeline
3

Draft, sent, and revised quotes

Accepted value
AED 12,570.00

Sum of accepted standard rates

Needs attention
3

Expired or valid within 7 days

Recent quotations

5 quotations - Validity, rate cards, and customer scope

QuoteCustomerSubjectStatusValid UntilStandard Value
KAT/QTN/2026/05/041
Al Naboodah ContractingANB-OPS-118
Manpower supply for Al Quoz industrial expansion
2 categories - OT reference AED 610.00
Sent
2026-06-1917 days left
AED 6,100.00
KAT/QTN/2026/05/040
Emaar Properties PJSCEMAAR-DTB-903
Downtown Burj Phase 3 night-shift manpower
2 categories - OT reference AED 1,360.00
Accepted
2026-06-1715 days left
AED 12,570.00
KAT/QTN/2026/05/039
Sobha Realty Corporate OfficeSOBHA-HQ-221
Corporate office maintenance support
1 categories - OT reference AED 228.00
Draft
2026-05-285 days overdue
AED 2,040.00
KAT/QTN/2026/05/038
Al Futtaim CarillionAFC-FST-510
Festival City expansion revised manpower schedule
1 categories - OT reference AED 540.00
Revised
2026-05-2310 days overdue
AED 4,920.00
KAT/QTN/2026/05/037
Shapoorji Pallonji M.E.YAS-VIL-778
Yas Island villas civil manpower package
2 categories - OT reference AED 1,190.00
Expired
2026-05-20Expired
AED 10,600.00
pnpm dlx shadcn@latest add @woxcn/manpowerhub-quotation

Install the ManpowerHub theme first, then add the block:

npx shadcn@latest add https://woxcn-registry.woxware.io/r/manpowerhub-quotation.json

This installs the list block at components/blocks/manpowerhub-quotation.tsx along with its ManpowerHub component dependencies. Drop <QuotationPage /> inside an AppShellScrollBody for the full shell layout.

QuotationPage is a controlled list component. It renders quotation rows that you provide and calls handlers when users navigate to create, edit, view, download, delete, or change status. Create/edit forms should live on your app routes, not inside this block.

import { QuotationPage } from "@/components/blocks/manpowerhub-quotation";
export default function QuotationsRoute() {
const { data: quotations, mutate } = useQuotations(); // your data fetching
return (
<QuotationPage
quotations={quotations}
kpiTrend={kpiTrend}
onDeleteQuotation={async (id) => {
await api.quotations.delete(id);
mutate();
}}
onStatusChangeQuotation={async (id, status) => {
await api.quotations.update(id, { status });
mutate();
}}
onCreateQuotation={() => router.push("/quotations/new")}
onEditQuotation={(quotation) => router.push(`/quotations/${quotation.id}/edit`)}
onViewQuotation={(quotation) => router.push(`/quotations/${quotation.id}`)}
onDownloadQuotation={(quotation) =>
window.open(`/api/quotations/${quotation.id}/pdf`)
}
/>
);
}

Use the quotation list block for the index route and the quotation view block for the read-only detail route.

/quotations -> manpowerhub-quotation
/quotations/new -> your create form route
/quotations/:id -> manpowerhub-quotation-view
/quotations/:id/edit -> your edit form route

The delete confirmation dialog is built into the block and calls onDeleteQuotation after the user confirms.

  • quotations: required list of quotation records to render.
  • kpiTrend: optional sparkline data for the four KPI cards. Defaults to flat lines.
  • onDeleteQuotation: required delete handler. Receives quotation id.
  • onStatusChangeQuotation: required status handler. Receives (id, status).
  • onCreateQuotation: optional handler for the New quote button. If omitted, the button is hidden.
  • onEditQuotation: optional handler for the row Edit action. If omitted, Edit is hidden.
  • onViewQuotation: optional handler for the row View action.
  • onDownloadQuotation: optional handler for the Download PDF action.
type QuotationStatus = "draft" | "sent" | "accepted" | "expired" | "revised";
interface QuotationItem {
id: string;
category: string;
quantity: number;
rateAed: number;
otRateAed: number;
sortOrder?: number;
}
interface Quotation {
id: string;
quotationNumber: string;
customerRefId: string;
status: QuotationStatus;
customerName: string;
customerEmail: string;
customerPhone: string;
proposalSubject: string;
scopeOfWork: string;
signatoryName: string;
signatoryTitle: string;
customDearSir?: string | null;
customWorkingHours?: string | null;
customOvertimeTerms?: string | null;
issueDate: string;
validUntil: string;
items: QuotationItem[];
}
interface KpiTrend {
total: number[];
pipeline: number[];
accepted: number[];
expiring: number[];
}