thai-uxui
This commit is contained in:
@@ -13,7 +13,7 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
id: 'entityCode',
|
||||
accessorFn: (row) => row.entityCode ?? row.entityId,
|
||||
header: ({ column }: { column: Column<ApprovalListItem, unknown> }) => (
|
||||
<DataTableColumnHeader column={column} title='Request' />
|
||||
<DataTableColumnHeader column={column} title='คำขอ' />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className='flex flex-col'>
|
||||
@@ -27,8 +27,8 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
</div>
|
||||
),
|
||||
meta: {
|
||||
label: 'Request',
|
||||
placeholder: 'Search approvals...',
|
||||
label: 'คำขอ',
|
||||
placeholder: 'ค้นหางานอนุมัติ...',
|
||||
variant: 'text' as const,
|
||||
icon: Icons.search
|
||||
},
|
||||
@@ -45,11 +45,11 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
label: 'Status',
|
||||
variant: 'multiSelect' as const,
|
||||
options: [
|
||||
{ value: 'pending', label: 'Pending' },
|
||||
{ value: 'approved', label: 'Approved' },
|
||||
{ value: 'rejected', label: 'Rejected' },
|
||||
{ value: 'returned', label: 'Returned' },
|
||||
{ value: 'cancelled', label: 'Cancelled' }
|
||||
{ value: 'pending', label: 'รออนุมัติ' },
|
||||
{ value: 'approved', label: 'อนุมัติแล้ว' },
|
||||
{ value: 'rejected', label: 'ไม่อนุมัติ' },
|
||||
{ value: 'returned', label: 'ตีกลับ' },
|
||||
{ value: 'cancelled', label: 'ยกเลิก' }
|
||||
]
|
||||
},
|
||||
enableColumnFilter: true
|
||||
@@ -58,13 +58,13 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
id: 'entityType',
|
||||
accessorKey: 'entityType',
|
||||
header: ({ column }: { column: Column<ApprovalListItem, unknown> }) => (
|
||||
<DataTableColumnHeader column={column} title='Entity' />
|
||||
<DataTableColumnHeader column={column} title='เอกสาร' />
|
||||
),
|
||||
cell: ({ row }) => row.original.entityType.replaceAll('_', ' '),
|
||||
meta: {
|
||||
label: 'Entity',
|
||||
label: 'เอกสาร',
|
||||
variant: 'multiSelect' as const,
|
||||
options: [{ value: 'quotation', label: 'Quotation' }]
|
||||
options: [{ value: 'quotation', label: 'ใบเสนอราคา' }]
|
||||
},
|
||||
enableColumnFilter: true
|
||||
},
|
||||
@@ -72,11 +72,11 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
id: 'currentStep',
|
||||
accessorKey: 'currentStep',
|
||||
header: ({ column }: { column: Column<ApprovalListItem, unknown> }) => (
|
||||
<DataTableColumnHeader column={column} title='Current Step' />
|
||||
<DataTableColumnHeader column={column} title='ขั้นตอนปัจจุบัน' />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className='flex flex-col'>
|
||||
<span>Step {row.original.currentStep}</span>
|
||||
<span>ขั้น {row.original.currentStep}</span>
|
||||
<span className='text-muted-foreground text-xs'>
|
||||
{row.original.currentStepRoleName ?? '-'}
|
||||
</span>
|
||||
@@ -87,7 +87,7 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
id: 'requestedBy',
|
||||
accessorFn: (row) => row.requestedByName ?? row.requestedBy,
|
||||
header: ({ column }: { column: Column<ApprovalListItem, unknown> }) => (
|
||||
<DataTableColumnHeader column={column} title='Requested By' />
|
||||
<DataTableColumnHeader column={column} title='ผู้ส่งอนุมัติ' />
|
||||
),
|
||||
cell: ({ row }) => row.original.requestedByName ?? row.original.requestedBy
|
||||
},
|
||||
@@ -95,7 +95,7 @@ export function getApprovalColumns(): ColumnDef<ApprovalListItem>[] {
|
||||
id: 'requestedAt',
|
||||
accessorKey: 'requestedAt',
|
||||
header: ({ column }: { column: Column<ApprovalListItem, unknown> }) => (
|
||||
<DataTableColumnHeader column={column} title='Requested At' />
|
||||
<DataTableColumnHeader column={column} title='วันที่ส่งอนุมัติ' />
|
||||
),
|
||||
cell: ({ row }) => new Date(row.original.requestedAt).toLocaleString()
|
||||
}
|
||||
|
||||
@@ -60,35 +60,35 @@ export function ApprovalRequestPanel({
|
||||
const approveAction = useMutation({
|
||||
...approveApprovalMutation,
|
||||
onSuccess: () => {
|
||||
toast.success('Approval step completed');
|
||||
toast.success('อนุมัติขั้นตอนนี้สำเร็จ');
|
||||
setRemark('');
|
||||
},
|
||||
onError: (error) =>
|
||||
toast.error(error instanceof Error ? error.message : 'Unable to approve request')
|
||||
toast.error(error instanceof Error ? error.message : 'ไม่สามารถอนุมัติคำขอได้')
|
||||
});
|
||||
const rejectAction = useMutation({
|
||||
...rejectApprovalMutation,
|
||||
onSuccess: () => {
|
||||
toast.success('Approval request rejected');
|
||||
toast.success('ไม่อนุมัติคำขอสำเร็จ');
|
||||
setRemark('');
|
||||
},
|
||||
onError: (error) =>
|
||||
toast.error(error instanceof Error ? error.message : 'Unable to reject request')
|
||||
toast.error(error instanceof Error ? error.message : 'ไม่สามารถไม่อนุมัติคำขอได้')
|
||||
});
|
||||
const returnAction = useMutation({
|
||||
...returnApprovalMutation,
|
||||
onSuccess: () => {
|
||||
toast.success('Approval request returned to draft');
|
||||
toast.success('ตีกลับคำขอเพื่อแก้ไขสำเร็จ');
|
||||
setRemark('');
|
||||
},
|
||||
onError: (error) =>
|
||||
toast.error(error instanceof Error ? error.message : 'Unable to return request')
|
||||
toast.error(error instanceof Error ? error.message : 'ไม่สามารถตีกลับคำขอได้')
|
||||
});
|
||||
const cancelAction = useMutation({
|
||||
...cancelApprovalMutation,
|
||||
onSuccess: () => toast.success('Approval request cancelled'),
|
||||
onSuccess: () => toast.success('ยกเลิกคำขออนุมัติสำเร็จ'),
|
||||
onError: (error) =>
|
||||
toast.error(error instanceof Error ? error.message : 'Unable to cancel request')
|
||||
toast.error(error instanceof Error ? error.message : 'ไม่สามารถยกเลิกคำขอได้')
|
||||
});
|
||||
const isActing =
|
||||
approveAction.isPending ||
|
||||
@@ -100,30 +100,30 @@ export function ApprovalRequestPanel({
|
||||
<div className='space-y-6'>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Request Information</CardTitle>
|
||||
<CardDescription>Current workflow state for this approval request.</CardDescription>
|
||||
<CardTitle>ข้อมูลคำขอ</CardTitle>
|
||||
<CardDescription>สถานะปัจจุบันของคำขออนุมัติเอกสารนี้</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='grid gap-4 md:grid-cols-2 xl:grid-cols-4'>
|
||||
<FieldItem label='Workflow' value={approval.workflow.name} />
|
||||
<div className='space-y-1'>
|
||||
<div className='text-muted-foreground text-xs'>Status</div>
|
||||
<div className='text-muted-foreground text-xs'>สถานะ</div>
|
||||
<ApprovalStatusBadge status={approval.request.status} />
|
||||
</div>
|
||||
<FieldItem label='Entity Type' value={approval.request.entityType.replaceAll('_', ' ')} />
|
||||
<FieldItem label='Entity Code' value={approval.entityCode ?? approval.request.entityId} />
|
||||
<FieldItem label='Entity Title' value={approval.entityTitle} />
|
||||
<FieldItem label='ประเภทเอกสาร' value={approval.request.entityType.replaceAll('_', ' ')} />
|
||||
<FieldItem label='รหัสเอกสาร' value={approval.entityCode ?? approval.request.entityId} />
|
||||
<FieldItem label='ชื่อเอกสาร' value={approval.entityTitle} />
|
||||
<FieldItem
|
||||
label='Requested At'
|
||||
label='วันที่ส่งอนุมัติ'
|
||||
value={new Date(approval.request.requestedAt).toLocaleString()}
|
||||
/>
|
||||
<FieldItem label='Requested By' value={approval.request.requestedBy} />
|
||||
<FieldItem label='ผู้ส่งอนุมัติ' value={approval.request.requestedBy} />
|
||||
<FieldItem
|
||||
label='Current Step'
|
||||
label='ขั้นตอนปัจจุบัน'
|
||||
value={
|
||||
approval.currentStep
|
||||
? `Step ${approval.currentStep.stepNumber} - ${approval.currentStep.roleName}`
|
||||
: approval.request.status === 'approved'
|
||||
? 'Completed'
|
||||
? 'เสร็จสิ้น'
|
||||
: '-'
|
||||
}
|
||||
/>
|
||||
@@ -132,7 +132,7 @@ export function ApprovalRequestPanel({
|
||||
<Button asChild variant='outline'>
|
||||
<Link href={entityHref}>
|
||||
<Icons.arrowRight className='mr-2 h-4 w-4' />
|
||||
Open Related Document
|
||||
เปิดเอกสารที่เกี่ยวข้อง
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
@@ -143,7 +143,7 @@ export function ApprovalRequestPanel({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Workflow</CardTitle>
|
||||
<CardDescription>Sequential approver chain configured for this document.</CardDescription>
|
||||
<CardDescription>ลำดับผู้อนุมัติที่กำหนดไว้สำหรับเอกสารนี้</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='space-y-3'>
|
||||
{approval.steps.map((step) => {
|
||||
@@ -157,12 +157,12 @@ export function ApprovalRequestPanel({
|
||||
>
|
||||
<div>
|
||||
<div className='font-medium'>
|
||||
Step {step.stepNumber} - {step.roleName}
|
||||
ขั้น {step.stepNumber} - {step.roleName}
|
||||
</div>
|
||||
<div className='text-muted-foreground text-sm'>{step.roleCode}</div>
|
||||
</div>
|
||||
<Badge variant={isCurrent ? 'secondary' : isCompleted ? 'default' : 'outline'}>
|
||||
{isCurrent ? 'Current' : isCompleted ? 'Completed' : 'Pending'}
|
||||
{isCurrent ? 'ปัจจุบัน' : isCompleted ? 'เสร็จสิ้น' : 'รอดำเนินการ'}
|
||||
</Badge>
|
||||
</div>
|
||||
);
|
||||
@@ -172,16 +172,16 @@ export function ApprovalRequestPanel({
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Actions</CardTitle>
|
||||
<CardTitle>การดำเนินการ</CardTitle>
|
||||
<CardDescription>
|
||||
Approvers can approve, reject, or return on their assigned step.
|
||||
ผู้อนุมัติสามารถอนุมัติ ไม่อนุมัติ หรือตีกลับในขั้นที่รับผิดชอบได้
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='space-y-4'>
|
||||
<Textarea
|
||||
value={remark}
|
||||
onChange={(event) => setRemark(event.target.value)}
|
||||
placeholder='Optional remark for approval history'
|
||||
placeholder='หมายเหตุเพิ่มเติมสำหรับประวัติการอนุมัติ'
|
||||
rows={4}
|
||||
/>
|
||||
<div className='flex flex-wrap gap-2'>
|
||||
@@ -193,7 +193,7 @@ export function ApprovalRequestPanel({
|
||||
}
|
||||
>
|
||||
<Icons.circleCheck className='mr-2 h-4 w-4' />
|
||||
Approve
|
||||
อนุมัติ
|
||||
</Button>
|
||||
) : null}
|
||||
{canReject && canHandleCurrentStep && isPending ? (
|
||||
@@ -205,7 +205,7 @@ export function ApprovalRequestPanel({
|
||||
}
|
||||
>
|
||||
<Icons.warning className='mr-2 h-4 w-4' />
|
||||
Reject
|
||||
ไม่อนุมัติ
|
||||
</Button>
|
||||
) : null}
|
||||
{canReturn && canHandleCurrentStep && isPending ? (
|
||||
@@ -217,7 +217,7 @@ export function ApprovalRequestPanel({
|
||||
}
|
||||
>
|
||||
<Icons.chevronLeft className='mr-2 h-4 w-4' />
|
||||
Return
|
||||
ตีกลับ
|
||||
</Button>
|
||||
) : null}
|
||||
{canCancelCurrentRequest ? (
|
||||
@@ -227,36 +227,36 @@ export function ApprovalRequestPanel({
|
||||
onClick={() => cancelAction.mutate(approval.request.id)}
|
||||
>
|
||||
<Icons.close className='mr-2 h-4 w-4' />
|
||||
Cancel Request
|
||||
ยกเลิกคำขอ
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
{!canHandleCurrentStep && isPending ? (
|
||||
<div className='text-muted-foreground text-sm'>
|
||||
Current step is assigned to{' '}
|
||||
ขั้นตอนปัจจุบันถูกมอบหมายให้{' '}
|
||||
<span className='font-medium'>{approval.currentStep?.roleName ?? 'another role'}</span>.
|
||||
</div>
|
||||
) : null}
|
||||
{!isPending ? (
|
||||
<div className='text-muted-foreground text-sm'>
|
||||
This request is already {approval.request.status.replaceAll('_', ' ')}.
|
||||
คำขอนี้อยู่ในสถานะ {approval.request.status.replaceAll('_', ' ')} แล้ว
|
||||
</div>
|
||||
) : null}
|
||||
{isActing ? (
|
||||
<div className='text-muted-foreground text-xs'>Saving approval action...</div>
|
||||
<div className='text-muted-foreground text-xs'>กำลังบันทึกการอนุมัติ...</div>
|
||||
) : null}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Timeline</CardTitle>
|
||||
<CardDescription>Full audit trail of request submission and approval actions.</CardDescription>
|
||||
<CardTitle>ไทม์ไลน์</CardTitle>
|
||||
<CardDescription>ประวัติการส่งคำขอและการดำเนินการอนุมัติทั้งหมด</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className='space-y-4'>
|
||||
{!approval.timeline.length ? (
|
||||
<div className='text-muted-foreground rounded-lg border border-dashed p-8 text-center text-sm'>
|
||||
No approval actions recorded yet.
|
||||
ยังไม่มีประวัติการอนุมัติ
|
||||
</div>
|
||||
) : (
|
||||
approval.timeline.map((item, index) => (
|
||||
@@ -272,7 +272,7 @@ export function ApprovalRequestPanel({
|
||||
{item.actorName ?? item.actedBy}
|
||||
</span>
|
||||
<span className='text-muted-foreground text-xs'>
|
||||
Step {item.stepNumber}
|
||||
ขั้น {item.stepNumber}
|
||||
</span>
|
||||
</div>
|
||||
<div className='text-muted-foreground text-xs'>
|
||||
|
||||
@@ -5,6 +5,13 @@ import { Icons } from '@/components/icons';
|
||||
|
||||
export function ApprovalStatusBadge({ status }: { status: string }) {
|
||||
const normalized = status.toLowerCase();
|
||||
const labelMap: Record<string, string> = {
|
||||
pending: 'รออนุมัติ',
|
||||
approved: 'อนุมัติแล้ว',
|
||||
rejected: 'ไม่อนุมัติ',
|
||||
returned: 'ตีกลับ',
|
||||
cancelled: 'ยกเลิก'
|
||||
};
|
||||
const variant =
|
||||
normalized === 'approved'
|
||||
? 'default'
|
||||
@@ -25,7 +32,7 @@ export function ApprovalStatusBadge({ status }: { status: string }) {
|
||||
return (
|
||||
<Badge variant={variant} className='capitalize'>
|
||||
<Icon className='h-3 w-3' />
|
||||
{status.replaceAll('_', ' ')}
|
||||
{labelMap[normalized] ?? status.replaceAll('_', ' ')}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user