260320:1131 Refactor Overrall #01
Build and Deploy / deploy (push) Has been cancelled

This commit is contained in:
admin
2026-03-20 11:31:27 +07:00
parent f1b81a7d0d
commit 1d3479770b
147 changed files with 1745 additions and 1567 deletions
@@ -308,7 +308,7 @@ export default function ContractsPage() {
<SelectValue placeholder="Select Project" />
</SelectTrigger>
<SelectContent>
{(projects as any[])?.map((p) => (
{(projects as { id?: number; uuid?: string; projectCode: string; projectName: string }[])?.map((p) => (
<SelectItem key={p.uuid || p.id} value={String(p.id || p.uuid)}>
{p.projectCode} - {p.projectName}
</SelectItem>
@@ -70,7 +70,7 @@ export default function ContractCategoriesPage() {
)}
</SelectTrigger>
<SelectContent>
{(projects as any[]).map((project) => (
{(projects as { id?: number; uuid?: string; projectCode: string; projectName: string }[]).map((project) => (
<SelectItem key={project.uuid || project.id} value={String(project.id || project.uuid)}>
{project.projectCode} - {project.projectName}
</SelectItem>
@@ -103,9 +103,7 @@ export default function ContractCategoriesPage() {
description="Manage main categories (หมวดหมู่หลัก) for contract drawings"
queryKey={['contract-drawing-categories', String(selectedProjectId)]}
fetchFn={async () => {
console.log(`Fetching Contract Categories for project ${selectedProjectId}`);
const data = await drawingMasterDataService.getContractCategories(selectedProjectId);
console.log('Contract Categories Data:', data);
return data;
}}
createFn={(data: Record<string, unknown>) => drawingMasterDataService.createContractCategory({ ...(data as unknown as CreateContractCategoryDto), projectId: selectedProjectId })}
@@ -62,7 +62,7 @@ export default function ContractSubCategoriesPage() {
)}
</SelectTrigger>
<SelectContent>
{(projects as any[]).map((project) => (
{(projects as { id?: number; uuid?: string; projectCode: string; projectName: string }[]).map((project) => (
<SelectItem key={project.uuid || project.id} value={String(project.id || project.uuid)}>
{project.projectCode} - {project.projectName}
</SelectItem>
@@ -95,9 +95,7 @@ export default function ContractSubCategoriesPage() {
description="Manage sub-categories (หมวดหมู่ย่อย) for contract drawings"
queryKey={['contract-drawing-sub-categories', String(selectedProjectId)]}
fetchFn={async () => {
console.log(`Fetching Contract Sub-Categories for project ${selectedProjectId}`);
const data = await drawingMasterDataService.getContractSubCategories(selectedProjectId);
console.log('Contract Sub-Categories Data:', data);
return data;
}}
createFn={(data: Record<string, unknown>) =>
@@ -74,7 +74,7 @@ export default function ContractVolumesPage() {
)}
</SelectTrigger>
<SelectContent>
{(projects as any[]).map((project) => (
{(projects as { id?: number; uuid?: string; projectCode: string; projectName: string }[]).map((project) => (
<SelectItem key={project.uuid || project.id} value={String(project.id || project.uuid)}>
{project.projectCode} - {project.projectName}
</SelectItem>
@@ -73,7 +73,7 @@ export default function ShopMainCategoriesPage() {
)}
</SelectTrigger>
<SelectContent>
{(projects as any[]).map((project) => (
{(projects as { id?: number; uuid?: string; projectCode: string; projectName: string }[]).map((project) => (
<SelectItem key={project.uuid || project.id} value={String(project.id || project.uuid)}>
{project.projectCode} - {project.projectName}
</SelectItem>
@@ -106,9 +106,7 @@ export default function ShopMainCategoriesPage() {
description="Manage main categories (หมวดหมู่หลัก) for shop drawings"
queryKey={['shop-drawing-main-categories', String(selectedProjectId)]}
fetchFn={async () => {
console.log(`Fetching Shop Main Categories for project ${selectedProjectId}`);
const data = await drawingMasterDataService.getShopMainCategories(selectedProjectId);
console.log('Shop Main Categories Data:', data);
return data;
}}
createFn={(data: Record<string, unknown>) =>
@@ -22,8 +22,6 @@ export default function ShopSubCategoriesPage() {
const [selectedProjectId, setSelectedProjectId] = useState<string | undefined>(undefined);
const { data: projects = [], isLoading: isLoadingProjects } = useProjects();
console.log('Projects Data:', projects);
const columns: ColumnDef<SubCategory>[] = [
{
accessorKey: 'subCategoryCode',
@@ -75,7 +73,7 @@ export default function ShopSubCategoriesPage() {
)}
</SelectTrigger>
<SelectContent>
{(projects as any[]).map((project) => (
{(projects as { id?: number; uuid?: string; projectCode: string; projectName: string }[]).map((project) => (
<SelectItem key={project.uuid || project.id} value={String(project.id || project.uuid)}>
{project.projectCode} - {project.projectName}
</SelectItem>
@@ -108,9 +106,7 @@ export default function ShopSubCategoriesPage() {
description="Manage sub-categories (หมวดหมู่ย่อย) for shop drawings"
queryKey={['shop-drawing-sub-categories', String(selectedProjectId)]}
fetchFn={async () => {
console.log(`Fetching Shop Sub-Categories for project ${selectedProjectId}`);
const data = await drawingMasterDataService.getShopSubCategories(selectedProjectId);
console.log('Shop Sub-Categories Data:', data);
return data;
}}
createFn={(data: Record<string, unknown>) =>
@@ -42,7 +42,6 @@ export default function EditTemplatePage() {
}
} catch (error) {
toast.error('Failed to load template');
console.error('[EditTemplatePage] fetchTemplate:', error);
} finally {
setLoading(false);
}
@@ -57,7 +56,6 @@ export default function EditTemplatePage() {
router.push('/admin/doc-control/numbering');
} catch (error) {
toast.error('Failed to update template');
console.error('[EditTemplatePage] handleSave:', error);
}
};
@@ -27,7 +27,6 @@ export default function NewTemplatePage() {
router.push("/admin/numbering");
} catch (error) {
toast.error('Failed to create template');
console.error('[NewTemplatePage]', error);
}
};
@@ -15,6 +15,13 @@ import { toast } from 'sonner';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useProjects, useCorrespondenceTypes, useContracts, useDisciplines } from '@/hooks/use-master-data';
interface ProjectItem {
id: number | string;
uuid?: string;
projectName: string;
projectCode: string;
}
import { ManualOverrideForm } from '@/components/numbering/manual-override-form';
import { MetricsDashboard } from '@/components/numbering/metrics-dashboard';
import { AuditLogsTable } from '@/components/numbering/audit-logs-table';
@@ -30,8 +37,8 @@ export default function NumberingPage() {
useEffect(() => {
if (projects.length > 0 && !selectedProjectId) {
const first = projects[0] as any;
setSelectedProjectId(String(first.id ?? first.uuid));
const first = projects[0] as ProjectItem;
setSelectedProjectId(String(first.uuid ?? first.id));
}
}, [projects, selectedProjectId]);
@@ -41,14 +48,14 @@ export default function NumberingPage() {
const [isTesting, setIsTesting] = useState(false);
const [testTemplate, setTestTemplate] = useState<NumberingTemplate | null>(null);
const selectedProject = projects.find((p: any) => String(p.id ?? p.uuid) === selectedProjectId) as any;
const selectedProject = (projects as ProjectItem[]).find((p) => String(p.uuid ?? p.id) === selectedProjectId);
const selectedProjectName = selectedProject?.projectName || 'Unknown Project';
// Master Data
const { data: correspondenceTypes = [] } = useCorrespondenceTypes();
const { data: contracts = [] } = useContracts(selectedProjectId as any); // Passing UUID/ID string
const firstContract = contracts[0] as any;
const contractId = firstContract?.id || firstContract?.uuid;
const { data: contracts = [] } = useContracts(selectedProjectId);
const firstContract = contracts[0] as { id?: number; uuid?: string } | undefined;
const contractId = firstContract?.uuid ?? firstContract?.id;
const { data: disciplines = [] } = useDisciplines(contractId);
const { data: templateResponse, isLoading: isLoadingTemplates } = useTemplates();
@@ -57,7 +64,7 @@ export default function NumberingPage() {
// Extract templates array from response
const templates: NumberingTemplate[] = Array.isArray(templateResponse)
? templateResponse
: ((templateResponse as any)?.data ?? []);
: ((templateResponse as { data?: NumberingTemplate[] } | undefined)?.data ?? []);
const handleEdit = (template?: NumberingTemplate) => {
setActiveTemplate(template);
@@ -84,7 +91,7 @@ export default function NumberingPage() {
<div className="p-6 max-w-4xl mx-auto animate-in fade-in slide-in-from-bottom-4">
<TemplateEditor
template={activeTemplate}
projectId={selectedProjectId as any}
projectId={selectedProjectId}
projectName={selectedProjectName}
correspondenceTypes={correspondenceTypes}
disciplines={disciplines}
@@ -108,8 +115,8 @@ export default function NumberingPage() {
<SelectValue placeholder="Select Project" />
</SelectTrigger>
<SelectContent>
{(projects as any[]).map((project) => (
<SelectItem key={project.id ?? project.uuid} value={String(project.id ?? project.uuid)}>
{(projects as ProjectItem[]).map((project) => (
<SelectItem key={String(project.uuid ?? project.id)} value={String(project.uuid ?? project.id)}>
{project.projectCode} - {project.projectName}
</SelectItem>
))}
@@ -137,7 +144,7 @@ export default function NumberingPage() {
<div className="lg:col-span-2 space-y-4">
<div className="grid gap-4">
{templates
.filter((t: any) => !t.projectId || String(t.project?.id ?? t.project?.uuid) === selectedProjectId || t.project?.uuid === selectedProjectId)
.filter((t) => !t.projectId || String(t.project?.id ?? t.project?.uuid) === selectedProjectId || t.project?.uuid === selectedProjectId)
.map((template) => (
<Card key={template.id} className="p-6 hover:shadow-md transition-shadow">
<div className="flex justify-between items-start">
@@ -202,11 +209,11 @@ export default function NumberingPage() {
<TabsContent value="tools" className="space-y-4">
<div className="grid gap-4 md:grid-cols-2">
<ManualOverrideForm projectId={selectedProjectId as any} />
<VoidReplaceForm projectId={selectedProjectId as any} />
<ManualOverrideForm projectId={selectedProjectId} />
<VoidReplaceForm projectId={selectedProjectId} />
<CancelNumberForm />
<div className="md:col-span-2">
<BulkImportForm projectId={selectedProjectId as any} />
<BulkImportForm projectId={selectedProjectId} />
</div>
</div>
</TabsContent>
@@ -58,12 +58,15 @@ export default function DisciplinesPage() {
fetchFn={async () => {
const items = await masterDataService.getDisciplines(selectedContractId ? selectedContractId : undefined);
// ADR-019: Map contractId INT → contract UUID for edit mode select matching
return (items as any[]).map((item: any) => ({
...item,
contractId: item.contract?.id || item.contract?.uuid || String(item.contractId),
}));
return (items as Record<string, unknown>[]).map((item) => {
const rec = item as { contract?: { id?: number; uuid?: string }; contractId?: number };
return {
...item,
contractId: rec.contract?.id || rec.contract?.uuid || String(rec.contractId),
};
});
}}
createFn={(data: Record<string, unknown>) => masterDataService.createDiscipline(data as any)}
createFn={(data) => masterDataService.createDiscipline(data as unknown as Parameters<typeof masterDataService.createDiscipline>[0])}
updateFn={(id, data) => Promise.reject('Not implemented yet')}
deleteFn={(id) => masterDataService.deleteDiscipline(id)}
columns={columns}
@@ -61,12 +61,15 @@ export default function RfaTypesPage() {
fetchFn={async () => {
const items = await masterDataService.getRfaTypes(selectedContractId ? selectedContractId : undefined);
// ADR-019: Map contractId INT → contract UUID for edit mode select matching
return (items as any[]).map((item: any) => ({
...item,
contractId: item.contract?.id || item.contract?.uuid || String(item.contractId),
}));
return (items as Record<string, unknown>[]).map((item) => {
const rec = item as { contract?: { id?: number; uuid?: string }; contractId?: number };
return {
...item,
contractId: rec.contract?.id || rec.contract?.uuid || String(rec.contractId),
};
});
}}
createFn={(data: Record<string, unknown>) => masterDataService.createRfaType(data as any)}
createFn={(data) => masterDataService.createRfaType(data as unknown as Parameters<typeof masterDataService.createRfaType>[0])}
updateFn={(id, data) => masterDataService.updateRfaType(id, data)}
deleteFn={(id) => masterDataService.deleteRfaType(id)}
columns={columns}
@@ -73,10 +73,13 @@ export default function TagsPage() {
fetchFn={async () => {
const items = await masterDataService.getTags();
// ADR-019: Map project_id INT → project UUID for edit mode select matching
return (items as any[]).map((item: any) => ({
...item,
project_id: item.project?.id || item.project?.uuid || (item.project_id ? String(item.project_id) : null),
}));
return (items as Record<string, unknown>[]).map((item) => {
const rec = item as { project?: { id?: number; uuid?: string }; project_id?: number };
return {
...item,
project_id: rec.project?.id || rec.project?.uuid || (rec.project_id ? String(rec.project_id) : null),
};
});
}}
createFn={(data: Record<string, unknown>) => masterDataService.createTag(formatPayload(data) as unknown as CreateTagDto)}
updateFn={(id, data) => masterDataService.updateTag(id, formatPayload(data))}
@@ -71,7 +71,6 @@ export default function WorkflowEditPage() {
}
} catch (error) {
toast.error('Failed to save workflow');
console.error(error);
}
};
@@ -33,7 +33,6 @@ export default function NewWorkflowPage() {
router.push('/admin/doc-control/workflows');
} catch (error) {
toast.error('Failed to create workflow');
console.error('[NewWorkflowPage]', error);
} finally {
setSaving(false);
}
@@ -28,7 +28,6 @@ export default function SessionManagementPage() {
},
onError: (error) => {
toast.error('Failed to revoke session');
console.error(error);
},
});
+4 -4
View File
@@ -86,8 +86,8 @@ export default function AdminPage() {
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{stats.map((stat, index) => (
<Card key={index} className="hover:shadow-md transition-shadow">
{stats.map((stat) => (
<Card key={stat.title} className="hover:shadow-md transition-shadow">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">{stat.title}</CardTitle>
<stat.icon className={`h-4 w-4 ${stat.color}`} />
@@ -111,8 +111,8 @@ export default function AdminPage() {
<div>
<h2 className="text-xl font-semibold mb-4">Quick Access</h2>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{quickLinks.map((link, index) => (
<Link key={index} href={link.href}>
{quickLinks.map((link) => (
<Link key={link.href} href={link.href}>
<Card className="h-full hover:bg-muted/50 transition-colors cursor-pointer border-l-4 border-l-transparent hover:border-l-primary">
<CardHeader>
<CardTitle className="flex items-center text-lg">
-2
View File
@@ -63,7 +63,6 @@ export default function LoginPage() {
if (result?.error) {
// กรณี Login ไม่สำเร็จ
console.error("Login failed:", result.error);
toast.error("เข้าสู่ระบบไม่สำเร็จ", {
description: "ชื่อผู้ใช้งานหรือรหัสผ่านไม่ถูกต้อง กรุณาลองใหม่",
});
@@ -77,7 +76,6 @@ export default function LoginPage() {
router.push("/dashboard");
router.refresh(); // Refresh เพื่อให้ Server Component รับรู้ Session ใหม่
} catch (error) {
console.error("Login error:", error);
toast.error("เกิดข้อผิดพลาด", {
description: "ระบบขัดข้อง กรุณาลองใหม่อีกครั้ง หรือติดต่อผู้ดูแลระบบ",
});
@@ -32,7 +32,7 @@ export default function MigrationErrorsPage() {
const res = await migrationService.getErrors({ limit: 100 });
setItems(res.items);
} catch (error) {
console.error("Failed to fetch errors", error);
// Failed to fetch errors - loading state handles display
} finally {
setLoading(false);
}
@@ -13,6 +13,7 @@ import {
} from "@/components/ui/table";
import { Checkbox } from "@/components/ui/checkbox";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { format } from "date-fns";
@@ -41,7 +42,7 @@ export default function MigrationReviewQueuePage() {
setItems(res.items);
setSelectedIds([]); // reset selection on fetch
} catch (error) {
console.error("Failed to fetch queue", error);
// Failed to fetch queue - loading state handles display
} finally {
setLoading(false);
}
@@ -56,7 +57,7 @@ export default function MigrationReviewQueuePage() {
};
const handleToggleSelect = (id: number) => {
setSelectedIds((prev) =>
setSelectedIds((prev) =>
prev.includes(id) ? prev.filter((i) => i !== id) : [...prev, id]
);
};
@@ -65,7 +66,7 @@ export default function MigrationReviewQueuePage() {
if (selectedIds.length === 0) return;
try {
setSubmitting(true);
const batchItems = items
.filter((i) => selectedIds.includes(i.id))
.map((item) => ({
@@ -94,11 +95,10 @@ export default function MigrationReviewQueuePage() {
{ items: batchItems, batchId },
batchId
);
fetchData();
} catch (error) {
console.error("Batch commit failed", error);
alert("Batch commit failed. See console for details.");
toast.error("Batch commit failed.");
} finally {
setSubmitting(false);
}
@@ -115,12 +115,12 @@ export default function MigrationReviewQueuePage() {
</div>
<div className="flex items-center gap-4">
{selectedIds.length > 0 && (
<Button
variant="default"
onClick={handleBatchApprove}
<Button
variant="default"
onClick={handleBatchApprove}
disabled={submitting}
>
<CheckSquareIcon className="mr-2 h-4 w-4" />
<CheckSquareIcon className="mr-2 h-4 w-4" />
{submitting ? "Processing..." : `Batch Approve (${selectedIds.length})`}
</Button>
)}
@@ -158,7 +158,7 @@ export default function MigrationReviewQueuePage() {
<TableHeader>
<TableRow>
<TableHead className="w-[50px]">
<Checkbox
<Checkbox
checked={items.length > 0 && selectedIds.length === items.length}
onCheckedChange={handleToggleSelectAll}
aria-label="Select all"
@@ -176,7 +176,7 @@ export default function MigrationReviewQueuePage() {
{items.map((item) => (
<TableRow key={item.id}>
<TableCell>
<Checkbox
<Checkbox
checked={selectedIds.includes(item.id)}
onCheckedChange={() => handleToggleSelect(item.id)}
aria-label={`Select item ${item.id}`}
@@ -185,14 +185,14 @@ export default function MigrationReviewQueuePage() {
<TableCell className="font-medium">{item.documentNumber}</TableCell>
<TableCell>{item.aiSuggestedCategory || "Unknown"}</TableCell>
<TableCell>
<Badge
<Badge
variant={
!item.aiConfidence
? "destructive"
: item.aiConfidence > 0.8
? "default"
: item.aiConfidence > 0.5
? "secondary"
!item.aiConfidence
? "destructive"
: item.aiConfidence > 0.8
? "default"
: item.aiConfidence > 0.5
? "secondary"
: "destructive"
}
>
@@ -87,7 +87,6 @@ export default function MigrationReviewPage() {
});
}
} catch (error) {
console.error("Failed to load queue item", error);
toast.error("Failed to load queue item");
} finally {
setLoading(false);
@@ -100,7 +99,7 @@ export default function MigrationReviewPage() {
try {
setSubmitting(true);
const issues = item.aiIssues || {};
const payload = {
document_number: values.document_number,
subject: values.subject,
@@ -123,12 +122,12 @@ export default function MigrationReviewPage() {
// Mock idempotency key based on timestamp to ensure uniqueness per approval retry
const idempotencyKey = `review-${item.id}-${Date.now()}`;
await migrationService.approveQueueItem(item.id, payload, idempotencyKey);
toast.success("Document approved and imported successfully");
router.push("/admin/migration");
} catch (error: any) {
console.error("Failed to approve item", error);
toast.error(error?.response?.data?.message || "Failed to approve and import");
} catch (error: unknown) {
const err = error as { response?: { data?: { message?: string } } };
toast.error(err?.response?.data?.message || "Failed to approve and import");
} finally {
setSubmitting(false);
}
@@ -142,8 +141,7 @@ export default function MigrationReviewPage() {
await migrationService.rejectQueueItem(item.id);
toast.success("Document rejected");
router.push("/admin/migration");
} catch (error: any) {
console.error("Failed to reject item", error);
} catch (error: unknown) {
toast.error("Failed to reject document");
} finally {
setSubmitting(false);
@@ -158,7 +156,7 @@ export default function MigrationReviewPage() {
return <div className="py-10 text-center text-red-500">Document not found</div>;
}
const pdfUrl = item.aiIssues?.source_file_path
const pdfUrl = item.aiIssues?.source_file_path
? migrationService.getStagingFileUrl(item.aiIssues.source_file_path)
: null;
@@ -240,7 +238,7 @@ export default function MigrationReviewPage() {
</FormItem>
)}
/>
<div className="grid grid-cols-2 gap-4">
<FormField
control={form.control}
@@ -343,9 +341,9 @@ export default function MigrationReviewPage() {
<XCircleIcon className="w-4 h-4 mr-2" />
Reject
</Button>
<Button
type="submit"
className="flex-1 bg-green-600 hover:bg-green-700 text-white"
<Button
type="submit"
className="flex-1 bg-green-600 hover:bg-green-700 text-white"
disabled={submitting || item.status !== 'PENDING'}
>
<CheckCircleIcon className="w-4 h-4 mr-2" />
@@ -43,6 +43,12 @@ import Link from "next/link";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
// Force dynamic rendering to prevent build-time prerendering issues
export const dynamic = 'force-dynamic';
// Ensure this page is never statically generated
export const fetchCache = 'force-no-store';
// Form validation schema
const formSchema = z.object({
correspondenceId: z.string().min(1, "Please select a document"),
@@ -1,5 +1,11 @@
import { CorrespondenceForm } from "@/components/correspondences/form";
// Force dynamic rendering to prevent build-time prerendering issues
export const dynamic = 'force-dynamic';
// Ensure this page is never statically generated
export const fetchCache = 'force-no-store';
export default function NewCorrespondencePage() {
return (
<div className="max-w-4xl mx-auto py-6">
@@ -1,5 +1,11 @@
import { DrawingUploadForm } from "@/components/drawings/upload-form";
// Force dynamic rendering to prevent build-time prerendering issues
export const dynamic = 'force-dynamic';
// Ensure this page is never statically generated
export const fetchCache = 'force-no-store';
export default function DrawingUploadPage() {
return (
<div className="max-w-4xl mx-auto py-6">
+1 -1
View File
@@ -69,7 +69,7 @@ export default function ProfilePage() {
reset();
} catch (error) {
toast.error('ไม่สามารถเปลี่ยนรหัสผ่านได้: รหัสผ่านปัจจุบันไม่ถูกต้อง');
console.error('[ProfilePage] onPasswordSubmit:', error);
// Password change failed - toast shown
} finally {
setIsLoading(false);
}
@@ -29,6 +29,12 @@ import {
} from "@/components/ui/card";
import { toast } from "sonner";
// Force dynamic rendering to prevent build-time prerendering issues
export const dynamic = 'force-dynamic';
// Ensure this page is never statically generated
export const fetchCache = 'force-no-store';
// 1. กำหนด Schema สำหรับตรวจสอบข้อมูล (Validation)
// อ้างอิงจาก Data Dictionary ตาราง projects
const projectSchema = z.object({
@@ -74,7 +80,6 @@ export default function CreateProjectPage() {
try {
// เรียก API สร้างโครงการ (Mockup URL)
// ใน Phase หลัง Backend จะเตรียม Endpoint POST /projects ไว้ให้
console.log("Submitting project data:", data);
// จำลองการส่งข้อมูล (Artificial Delay)
await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -86,7 +91,7 @@ export default function CreateProjectPage() {
router.refresh();
} catch (error) {
toast.error('เกิดข้อผิดพลาดในการสร้างโครงการ');
console.error('[CreateProjectPage]', error);
// Project creation failed - toast shown
} finally {
setIsLoading(false);
}
@@ -1,5 +1,11 @@
import { RFAForm } from "@/components/rfas/form";
// Force dynamic rendering to prevent build-time prerendering issues
export const dynamic = 'force-dynamic';
// Ensure this page is never statically generated
export const fetchCache = 'force-no-store';
export default function NewRFAPage() {
return (
<div className="max-w-4xl mx-auto py-6">
@@ -8,6 +8,9 @@ import { TransmittalForm } from "@/components/transmittal/transmittal-form";
// Force dynamic rendering to prevent build-time prerendering issues
export const dynamic = 'force-dynamic';
// Ensure this page is never statically generated
export const fetchCache = 'force-no-store';
export default function CreateTransmittalPage() {
return (
<section className="space-y-6 max-w-4xl">
-85
View File
@@ -1,85 +0,0 @@
/* File: app/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
/* Base Color: Slate (Professional/Enterprise look) */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
/* Primary: Brand Blue for Actions */
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
/* Secondary: Muted/Gray for secondary actions */
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
/* Muted: For disabled or subtle text */
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
/* Accent: For hover states or highlights */
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
/* Destructive: For delete/danger actions */
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
/* Borders & Inputs */
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}
.dark {
/* Dark Mode (Prepared for future use) */
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}