Files
admin ea5499123e
CI / CD Pipeline / build (push) Failing after 3m57s
CI / CD Pipeline / deploy (push) Has been skipped
690519:1631 224 to 226 AI #01
2026-05-19 16:31:50 +07:00

179 lines
6.4 KiB
TypeScript

'use client';
// File: app/(admin)/admin/ai/intent-classification/[intentCode]/page.tsx
// Change Log
// - 2026-05-19: สร้างหน้า Intent Detail + Patterns (Admin, ADR-024).
import { useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import {
useIntentDefinition,
useUpdateIntentDefinition,
useIntentPatterns,
useCreateIntentPattern,
useDeleteIntentPattern,
} from '@/hooks/ai/use-intent-classification';
import { PatternForm } from '@/components/ai/intent-classification/pattern-form';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Switch } from '@/components/ui/switch';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { ArrowLeft, Plus, Trash2 } from 'lucide-react';
import type { PatternType, PatternLanguage } from '@/lib/services/ai-intent.service';
export default function IntentDetailPage() {
const params = useParams();
const router = useRouter();
const intentCode = params.intentCode as string;
const [showPatternForm, setShowPatternForm] = useState(false);
const { data: definition, isLoading: defLoading } = useIntentDefinition(intentCode);
const updateMutation = useUpdateIntentDefinition(intentCode);
const { data: patterns, isLoading: patternsLoading } = useIntentPatterns(intentCode);
const createPatternMutation = useCreateIntentPattern(intentCode);
const deletePatternMutation = useDeleteIntentPattern(intentCode);
const handleToggleActive = async (isActive: boolean) => {
await updateMutation.mutateAsync({ isActive });
};
const handleCreatePattern = async (data: {
patternType: PatternType;
patternValue: string;
language?: PatternLanguage;
priority?: number;
}) => {
await createPatternMutation.mutateAsync(data);
setShowPatternForm(false);
};
const handleDeletePattern = async (publicId: string) => {
if (!confirm('ต้องการลบ Pattern นี้?')) return;
await deletePatternMutation.mutateAsync(publicId);
};
if (defLoading) {
return <p className="text-center py-8 text-muted-foreground">...</p>;
}
if (!definition) {
return <p className="text-center py-8 text-destructive"> Intent: {intentCode}</p>;
}
return (
<div className="space-y-6">
{/* Header */}
<div className="flex items-center gap-4">
<Button
variant="ghost"
size="icon"
onClick={() => router.push('/admin/ai/intent-classification')}
>
<ArrowLeft className="h-5 w-5" />
</Button>
<div className="flex-1">
<h1 className="text-2xl font-bold font-mono">{definition.intentCode}</h1>
<p className="text-muted-foreground">{definition.descriptionTh}</p>
<p className="text-sm text-muted-foreground">{definition.descriptionEn}</p>
</div>
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">Active</span>
<Switch
checked={definition.isActive}
onCheckedChange={handleToggleActive}
/>
</div>
</div>
{/* Info Card */}
<Card>
<CardContent className="pt-4 flex gap-4">
<Badge variant="secondary">{definition.category}</Badge>
<span className="text-sm text-muted-foreground">
: {new Date(definition.createdAt).toLocaleString('th-TH')}
</span>
</CardContent>
</Card>
{/* Patterns Table */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Patterns ({patterns?.length || 0})</CardTitle>
<Button size="sm" onClick={() => setShowPatternForm(true)}>
<Plus className="h-4 w-4 mr-1" />
Pattern
</Button>
</CardHeader>
<CardContent>
{patternsLoading ? (
<p className="text-center text-muted-foreground py-4">...</p>
) : patterns && patterns.length > 0 ? (
<Table>
<TableHeader>
<TableRow>
<TableHead>Type</TableHead>
<TableHead>Pattern Value</TableHead>
<TableHead>Language</TableHead>
<TableHead>Priority</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{patterns.map((p) => (
<TableRow key={p.publicId}>
<TableCell>
<Badge variant="outline">{p.patternType}</Badge>
</TableCell>
<TableCell className="font-mono text-sm max-w-[200px] truncate">
{p.patternValue}
</TableCell>
<TableCell>{p.language}</TableCell>
<TableCell>{p.priority}</TableCell>
<TableCell>
<Badge variant={p.isActive ? 'default' : 'destructive'}>
{p.isActive ? 'Active' : 'Inactive'}
</Badge>
</TableCell>
<TableCell>
<Button
variant="ghost"
size="icon"
onClick={() => handleDeletePattern(p.publicId)}
disabled={deletePatternMutation.isPending}
>
<Trash2 className="h-4 w-4 text-destructive" />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
) : (
<p className="text-center text-muted-foreground py-4">
Pattern Pattern Matching
</p>
)}
</CardContent>
</Card>
{/* Create Pattern Form Dialog */}
<PatternForm
open={showPatternForm}
onClose={() => setShowPatternForm(false)}
onSubmit={handleCreatePattern}
isLoading={createPatternMutation.isPending}
/>
</div>
);
}