251216:1644 Docunment Number: Update frontend/
This commit is contained in:
@@ -16,10 +16,15 @@ export function SequenceViewer() {
|
||||
const fetchSequences = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await numberingApi.getSequences();
|
||||
setSequences(data);
|
||||
const response = await numberingApi.getSequences();
|
||||
// Handle wrapped response { data: [...] } or direct array
|
||||
const data = Array.isArray(response) ? response : (response as { data?: NumberSequence[] })?.data ?? [];
|
||||
setSequences(data);
|
||||
} catch {
|
||||
console.error('Failed to fetch sequences');
|
||||
setSequences([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,17 +32,23 @@ export function SequenceViewer() {
|
||||
fetchSequences();
|
||||
}, []);
|
||||
|
||||
const filteredSequences = sequences.filter(s =>
|
||||
const filteredSequences = sequences.filter(
|
||||
(s) =>
|
||||
s.year.toString().includes(search) ||
|
||||
s.organizationCode?.toLowerCase().includes(search.toLowerCase()) ||
|
||||
s.disciplineCode?.toLowerCase().includes(search.toLowerCase())
|
||||
s.projectId.toString().includes(search) ||
|
||||
s.typeId.toString().includes(search)
|
||||
);
|
||||
|
||||
return (
|
||||
<Card className="p-6">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-semibold">Number Sequences</h3>
|
||||
<Button variant="outline" size="sm" onClick={fetchSequences} disabled={loading}>
|
||||
<h3 className="text-lg font-semibold">Number Counters</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={fetchSequences}
|
||||
disabled={loading}
|
||||
>
|
||||
<RefreshCw className={`mr-2 h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
|
||||
Refresh
|
||||
</Button>
|
||||
@@ -45,7 +56,7 @@ export function SequenceViewer() {
|
||||
|
||||
<div className="mb-4">
|
||||
<Input
|
||||
placeholder="Search by year, organization..."
|
||||
placeholder="Search by year, project, type..."
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
@@ -53,31 +64,32 @@ export function SequenceViewer() {
|
||||
|
||||
<div className="space-y-2">
|
||||
{filteredSequences.length === 0 && (
|
||||
<div className="text-center text-muted-foreground py-4">No sequences found</div>
|
||||
<div className="text-center text-muted-foreground py-4">
|
||||
No sequences found
|
||||
</div>
|
||||
)}
|
||||
{filteredSequences.map((seq) => (
|
||||
{filteredSequences.map((seq, index) => (
|
||||
<div
|
||||
key={seq.sequenceId}
|
||||
key={`${seq.projectId}-${seq.typeId}-${seq.year}-${index}`}
|
||||
className="flex items-center justify-between p-3 bg-slate-50 dark:bg-slate-900 rounded border"
|
||||
>
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="font-medium">Year {seq.year}</span>
|
||||
{seq.organizationCode && (
|
||||
<Badge>{seq.organizationCode}</Badge>
|
||||
)}
|
||||
{seq.disciplineCode && (
|
||||
<Badge variant="outline">{seq.disciplineCode}</Badge>
|
||||
<Badge variant="outline">Project: {seq.projectId}</Badge>
|
||||
<Badge>Type: {seq.typeId}</Badge>
|
||||
{seq.disciplineId > 0 && (
|
||||
<Badge variant="secondary">Disc: {seq.disciplineId}</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<span className="text-foreground font-medium">Current: {seq.currentNumber}</span> | Last Generated:{' '}
|
||||
<span className="font-mono">{seq.lastGeneratedNumber}</span>
|
||||
<span className="text-foreground font-medium">
|
||||
Counter: {seq.lastNumber}
|
||||
</span>{' '}
|
||||
| Originator: {seq.originatorId} | Recipient:{' '}
|
||||
{seq.recipientOrganizationId === -1 ? 'All' : seq.recipientOrganizationId}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
Updated {new Date(seq.updatedAt).toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -96,7 +96,7 @@ export function TemplateEditor({
|
||||
onSave({
|
||||
...template,
|
||||
projectId: projectId,
|
||||
correspondenceTypeId: Number(typeId),
|
||||
correspondenceTypeId: typeId && typeId !== '__default__' ? Number(typeId) : null,
|
||||
disciplineId: Number(disciplineId),
|
||||
formatTemplate: format,
|
||||
templateFormat: format, // Legacy support
|
||||
@@ -107,7 +107,7 @@ export function TemplateEditor({
|
||||
});
|
||||
};
|
||||
|
||||
const isValid = format.length > 0 && typeId;
|
||||
const isValid = format.length > 0; // typeId is optional (null = default for all types)
|
||||
|
||||
return (
|
||||
<Card className="p-6 space-y-6">
|
||||
@@ -136,12 +136,13 @@ export function TemplateEditor({
|
||||
{/* Configuration Column */}
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label>Document Type *</Label>
|
||||
<Label>Document Type (Optional)</Label>
|
||||
<Select value={typeId} onValueChange={setTypeId}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select type..." />
|
||||
<SelectValue placeholder="Default (All Types)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="__default__">Default (All Types)</SelectItem>
|
||||
{correspondenceTypes.map((type) => (
|
||||
<SelectItem key={type.id} value={type.id.toString()}>
|
||||
{type.typeCode} - {type.typeName}
|
||||
@@ -149,6 +150,9 @@ export function TemplateEditor({
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
Leave empty to create a default template for this project.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -34,7 +34,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
|
||||
setLoading(true);
|
||||
try {
|
||||
// Note: generateTestNumber expects keys: organizationId, disciplineId
|
||||
const result = await numberingApi.generateTestNumber(template.id || template.templateId || 0, {
|
||||
const result = await numberingApi.generateTestNumber(template.id ?? 0, {
|
||||
organizationId: testData.organizationId,
|
||||
disciplineId: testData.disciplineId
|
||||
});
|
||||
@@ -52,7 +52,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
|
||||
</DialogHeader>
|
||||
|
||||
<div className="text-sm text-muted-foreground mb-2">
|
||||
Template: <span className="font-mono font-bold text-foreground">{template?.templateFormat}</span>
|
||||
Template: <span className="font-mono font-bold text-foreground">{template?.formatTemplate}</span>
|
||||
</div>
|
||||
|
||||
<Card className="p-6 mt-6 bg-muted/50 rounded-lg">
|
||||
@@ -80,7 +80,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Format: {template?.templateFormat}
|
||||
Format: {template?.formatTemplate}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user