260220:1143 20260220 TASK-BEFE-001 Fix Drawing Master Data Pages
All checks were successful
Build and Deploy / deploy (push) Successful in 4m50s
All checks were successful
Build and Deploy / deploy (push) Successful in 4m50s
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
Query,
|
Query,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
ParseIntPipe,
|
ParseIntPipe,
|
||||||
|
Logger,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import {
|
import {
|
||||||
ApiTags,
|
ApiTags,
|
||||||
@@ -27,6 +28,8 @@ import { RequirePermission } from '../../common/decorators/require-permission.de
|
|||||||
@UseGuards(JwtAuthGuard, RbacGuard)
|
@UseGuards(JwtAuthGuard, RbacGuard)
|
||||||
@Controller('drawings/master-data')
|
@Controller('drawings/master-data')
|
||||||
export class DrawingMasterDataController {
|
export class DrawingMasterDataController {
|
||||||
|
private readonly logger = new Logger(DrawingMasterDataController.name);
|
||||||
|
|
||||||
constructor(private readonly masterDataService: DrawingMasterDataService) {}
|
constructor(private readonly masterDataService: DrawingMasterDataService) {}
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
@@ -38,9 +41,12 @@ export class DrawingMasterDataController {
|
|||||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||||
@RequirePermission('document.view')
|
@RequirePermission('document.view')
|
||||||
getVolumes(@Query('projectId', ParseIntPipe) projectId: number) {
|
getVolumes(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||||
|
this.logger.log(`Fetching Contract Volumes for Project ID: ${projectId}`);
|
||||||
return this.masterDataService.findAllVolumes(projectId);
|
return this.masterDataService.findAllVolumes(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||||
|
|
||||||
@Post('contract/volumes')
|
@Post('contract/volumes')
|
||||||
@ApiOperation({ summary: 'Create Volume' })
|
@ApiOperation({ summary: 'Create Volume' })
|
||||||
@RequirePermission('master_data.drawing_category.manage')
|
@RequirePermission('master_data.drawing_category.manage')
|
||||||
@@ -89,9 +95,14 @@ export class DrawingMasterDataController {
|
|||||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||||
@RequirePermission('document.view')
|
@RequirePermission('document.view')
|
||||||
getCategories(@Query('projectId', ParseIntPipe) projectId: number) {
|
getCategories(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||||
|
this.logger.log(
|
||||||
|
`Fetching Contract Categories for Project ID: ${projectId}`
|
||||||
|
);
|
||||||
return this.masterDataService.findAllCategories(projectId);
|
return this.masterDataService.findAllCategories(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||||
|
|
||||||
@Post('contract/categories')
|
@Post('contract/categories')
|
||||||
@ApiOperation({ summary: 'Create Category' })
|
@ApiOperation({ summary: 'Create Category' })
|
||||||
@RequirePermission('master_data.drawing_category.manage')
|
@RequirePermission('master_data.drawing_category.manage')
|
||||||
@@ -140,9 +151,14 @@ export class DrawingMasterDataController {
|
|||||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||||
@RequirePermission('document.view')
|
@RequirePermission('document.view')
|
||||||
getContractSubCats(@Query('projectId', ParseIntPipe) projectId: number) {
|
getContractSubCats(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||||
|
this.logger.log(
|
||||||
|
`Fetching Contract Sub-Categories for Project ID: ${projectId}`
|
||||||
|
);
|
||||||
return this.masterDataService.findAllContractSubCats(projectId);
|
return this.masterDataService.findAllContractSubCats(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||||
|
|
||||||
@Post('contract/sub-categories')
|
@Post('contract/sub-categories')
|
||||||
@ApiOperation({ summary: 'Create Contract Sub-Category' })
|
@ApiOperation({ summary: 'Create Contract Sub-Category' })
|
||||||
@RequirePermission('master_data.drawing_category.manage')
|
@RequirePermission('master_data.drawing_category.manage')
|
||||||
@@ -228,9 +244,14 @@ export class DrawingMasterDataController {
|
|||||||
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
@ApiQuery({ name: 'projectId', required: true, type: Number })
|
||||||
@RequirePermission('document.view')
|
@RequirePermission('document.view')
|
||||||
getShopMainCats(@Query('projectId', ParseIntPipe) projectId: number) {
|
getShopMainCats(@Query('projectId', ParseIntPipe) projectId: number) {
|
||||||
|
this.logger.log(
|
||||||
|
`Fetching Shop Main Categories for Project ID: ${projectId}`
|
||||||
|
);
|
||||||
return this.masterDataService.findAllShopMainCats(projectId);
|
return this.masterDataService.findAllShopMainCats(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... (Create/Update/Delete methods remain unchanged) ...
|
||||||
|
|
||||||
@Post('shop/main-categories')
|
@Post('shop/main-categories')
|
||||||
@ApiOperation({ summary: 'Create Shop Main Category' })
|
@ApiOperation({ summary: 'Create Shop Main Category' })
|
||||||
@RequirePermission('master_data.drawing_category.manage')
|
@RequirePermission('master_data.drawing_category.manage')
|
||||||
@@ -285,6 +306,9 @@ export class DrawingMasterDataController {
|
|||||||
@Query('projectId', ParseIntPipe) projectId: number,
|
@Query('projectId', ParseIntPipe) projectId: number,
|
||||||
@Query('mainCategoryId') mainCategoryId?: number
|
@Query('mainCategoryId') mainCategoryId?: number
|
||||||
) {
|
) {
|
||||||
|
this.logger.log(
|
||||||
|
`Fetching Shop Sub-Categories for Project ID: ${projectId}, MainCategory: ${mainCategoryId}`
|
||||||
|
);
|
||||||
return this.masterDataService.findAllShopSubCats(
|
return this.masterDataService.findAllShopSubCats(
|
||||||
projectId,
|
projectId,
|
||||||
mainCategoryId ? Number(mainCategoryId) : undefined
|
mainCategoryId ? Number(mainCategoryId) : undefined
|
||||||
|
|||||||
@@ -232,10 +232,10 @@ function ManageMappings({ projectId }: { projectId: number }) {
|
|||||||
<SelectValue placeholder="Select Sub-Category to add..." />
|
<SelectValue placeholder="Select Sub-Category to add..." />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{subCategories
|
{(subCategories || [])
|
||||||
.filter(
|
.filter(
|
||||||
(s: ContractSubCategory) =>
|
(s: ContractSubCategory) =>
|
||||||
!mappings.find((m: { subCategory: { id: number } }) => m.subCategory.id === s.id)
|
!(mappings || []).find((m: { subCategory: { id: number } }) => m.subCategory?.id === s.id)
|
||||||
)
|
)
|
||||||
.map((s: ContractSubCategory) => (
|
.map((s: ContractSubCategory) => (
|
||||||
<SelectItem key={s.id} value={String(s.id)}>
|
<SelectItem key={s.id} value={String(s.id)}>
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
"use client";
|
'use client';
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from 'react';
|
||||||
import { GenericCrudTable } from "@/components/admin/reference/generic-crud-table";
|
import { GenericCrudTable } from '@/components/admin/reference/generic-crud-table';
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from '@tanstack/react-table';
|
||||||
import {
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
Select,
|
import { Loader2, CheckCircle, XCircle } from 'lucide-react';
|
||||||
SelectContent,
|
import { useProjects } from '@/hooks/use-master-data';
|
||||||
SelectItem,
|
import { drawingMasterDataService } from '@/lib/services/drawing-master-data.service';
|
||||||
SelectTrigger,
|
import { Badge } from '@/components/ui/badge';
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
import { Loader2, CheckCircle, XCircle } from "lucide-react";
|
|
||||||
import { useProjects } from "@/hooks/use-master-data";
|
|
||||||
import { drawingMasterDataService } from "@/lib/services/drawing-master-data.service";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
|
|
||||||
interface SubCategory {
|
interface SubCategory {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -28,46 +22,41 @@ export default function ShopSubCategoriesPage() {
|
|||||||
const [selectedProjectId, setSelectedProjectId] = useState<number | undefined>(undefined);
|
const [selectedProjectId, setSelectedProjectId] = useState<number | undefined>(undefined);
|
||||||
const { data: projects = [], isLoading: isLoadingProjects } = useProjects();
|
const { data: projects = [], isLoading: isLoadingProjects } = useProjects();
|
||||||
|
|
||||||
|
console.log('Projects Data:', projects);
|
||||||
|
|
||||||
const columns: ColumnDef<SubCategory>[] = [
|
const columns: ColumnDef<SubCategory>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: "subCategoryCode",
|
accessorKey: 'subCategoryCode',
|
||||||
header: "Code",
|
header: 'Code',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<Badge variant="outline" className="font-mono">
|
<Badge variant="outline" className="font-mono">
|
||||||
{row.getValue("subCategoryCode")}
|
{row.getValue('subCategoryCode')}
|
||||||
</Badge>
|
</Badge>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "subCategoryName",
|
accessorKey: 'subCategoryName',
|
||||||
header: "Sub-category Name",
|
header: 'Sub-category Name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "description",
|
accessorKey: 'description',
|
||||||
header: "Description",
|
header: 'Description',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => <span className="text-muted-foreground text-sm">{row.getValue('description') || '-'}</span>,
|
||||||
<span className="text-muted-foreground text-sm">
|
|
||||||
{row.getValue("description") || "-"}
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "isActive",
|
accessorKey: 'isActive',
|
||||||
header: "Active",
|
header: 'Active',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) =>
|
||||||
row.getValue("isActive") ? (
|
row.getValue('isActive') ? (
|
||||||
<CheckCircle className="h-4 w-4 text-green-600" />
|
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||||
) : (
|
) : (
|
||||||
<XCircle className="h-4 w-4 text-red-600" />
|
<XCircle className="h-4 w-4 text-red-600" />
|
||||||
)
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "sortOrder",
|
accessorKey: 'sortOrder',
|
||||||
header: "Order",
|
header: 'Order',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => <span className="font-mono">{row.getValue('sortOrder')}</span>,
|
||||||
<span className="font-mono">{row.getValue("sortOrder")}</span>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -75,7 +64,7 @@ export default function ShopSubCategoriesPage() {
|
|||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<span className="text-sm font-medium">Project:</span>
|
<span className="text-sm font-medium">Project:</span>
|
||||||
<Select
|
<Select
|
||||||
value={selectedProjectId?.toString() ?? ""}
|
value={selectedProjectId?.toString() ?? ''}
|
||||||
onValueChange={(v) => setSelectedProjectId(v ? parseInt(v) : undefined)}
|
onValueChange={(v) => setSelectedProjectId(v ? parseInt(v) : undefined)}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-[300px]">
|
<SelectTrigger className="w-[300px]">
|
||||||
@@ -101,9 +90,7 @@ export default function ShopSubCategoriesPage() {
|
|||||||
<div className="p-6 space-y-6">
|
<div className="p-6 space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold">Shop Drawing Sub-categories</h1>
|
<h1 className="text-2xl font-bold">Shop Drawing Sub-categories</h1>
|
||||||
<p className="text-muted-foreground mt-1">
|
<p className="text-muted-foreground mt-1">Manage sub-categories (หมวดหมู่ย่อย) for shop drawings</p>
|
||||||
Manage sub-categories (หมวดหมู่ย่อย) for shop drawings
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{projectFilter}
|
{projectFilter}
|
||||||
<div className="text-center py-12 text-muted-foreground border rounded-lg border-dashed">
|
<div className="text-center py-12 text-muted-foreground border rounded-lg border-dashed">
|
||||||
@@ -119,25 +106,29 @@ export default function ShopSubCategoriesPage() {
|
|||||||
entityName="Sub-category"
|
entityName="Sub-category"
|
||||||
title="Shop Drawing Sub-categories"
|
title="Shop Drawing Sub-categories"
|
||||||
description="Manage sub-categories (หมวดหมู่ย่อย) for shop drawings"
|
description="Manage sub-categories (หมวดหมู่ย่อย) for shop drawings"
|
||||||
queryKey={["shop-drawing-sub-categories", String(selectedProjectId)]}
|
queryKey={['shop-drawing-sub-categories', String(selectedProjectId)]}
|
||||||
fetchFn={() => drawingMasterDataService.getShopSubCategories(selectedProjectId)}
|
fetchFn={() => drawingMasterDataService.getShopSubCategories(selectedProjectId)}
|
||||||
createFn={(data) => drawingMasterDataService.createShopSubCategory({
|
createFn={(data) =>
|
||||||
|
drawingMasterDataService.createShopSubCategory({
|
||||||
...data,
|
...data,
|
||||||
projectId: selectedProjectId,
|
projectId: selectedProjectId,
|
||||||
isActive: data.isActive === "true" || data.isActive === true
|
isActive: data.isActive === 'true' || data.isActive === true,
|
||||||
})}
|
})
|
||||||
updateFn={(id, data) => drawingMasterDataService.updateShopSubCategory(id, {
|
}
|
||||||
|
updateFn={(id, data) =>
|
||||||
|
drawingMasterDataService.updateShopSubCategory(id, {
|
||||||
...data,
|
...data,
|
||||||
isActive: data.isActive === "true" || data.isActive === true
|
isActive: data.isActive === 'true' || data.isActive === true,
|
||||||
})}
|
})
|
||||||
|
}
|
||||||
deleteFn={(id) => drawingMasterDataService.deleteShopSubCategory(id)}
|
deleteFn={(id) => drawingMasterDataService.deleteShopSubCategory(id)}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
fields={[
|
fields={[
|
||||||
{ name: "subCategoryCode", label: "Sub-category Code", type: "text", required: true },
|
{ name: 'subCategoryCode', label: 'Sub-category Code', type: 'text', required: true },
|
||||||
{ name: "subCategoryName", label: "Sub-category Name", type: "text", required: true },
|
{ name: 'subCategoryName', label: 'Sub-category Name', type: 'text', required: true },
|
||||||
{ name: "description", label: "Description", type: "textarea" },
|
{ name: 'description', label: 'Description', type: 'textarea' },
|
||||||
{ name: "isActive", label: "Active", type: "checkbox" },
|
{ name: 'isActive', label: 'Active', type: 'checkbox' },
|
||||||
{ name: "sortOrder", label: "Sort Order", type: "text", required: true },
|
{ name: 'sortOrder', label: 'Sort Order', type: 'text', required: true },
|
||||||
]}
|
]}
|
||||||
filters={projectFilter}
|
filters={projectFilter}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user