174 lines
5.9 KiB
TypeScript
174 lines
5.9 KiB
TypeScript
import { useMemo } from 'react';
|
||
import { useQuery } from '@tanstack/react-query';
|
||
import { Checkbox } from '@/components/ui/checkbox';
|
||
import { Label } from '@/components/ui/label';
|
||
import {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from '@/components/ui/select';
|
||
import { Table, Link2 } from 'lucide-react';
|
||
import { apiRequest } from '@/lib/queryClient';
|
||
import type { DataTableSubdirectory } from '@shared/schema';
|
||
|
||
interface FormFieldTable {
|
||
id?: number;
|
||
type: string;
|
||
allowMultiple?: boolean;
|
||
options?: Record<string, any>;
|
||
}
|
||
|
||
interface SubdirectoryFieldConfigProps {
|
||
field: FormFieldTable;
|
||
index: number;
|
||
tablesData?: { tables: Array<{ id: number; name: string; columns: any[] }> };
|
||
updateField: (index: number, updates: Partial<FormFieldTable>) => void;
|
||
}
|
||
|
||
export default function SubdirectoryFieldConfig({
|
||
field,
|
||
index,
|
||
tablesData,
|
||
updateField,
|
||
}: SubdirectoryFieldConfigProps) {
|
||
const tableId = field.options?.tableId as number | undefined;
|
||
|
||
const { data: subdirectoriesData } = useQuery<{ subdirectories: DataTableSubdirectory[] }>({
|
||
queryKey: ['/api/directories', tableId, 'subdirectories'],
|
||
queryFn: async () => {
|
||
const res = await apiRequest('GET', `/api/directories/${tableId}/subdirectories`);
|
||
return res.json();
|
||
},
|
||
enabled: !!tableId,
|
||
staleTime: 60 * 1000,
|
||
});
|
||
|
||
const subdirectories = subdirectoriesData?.subdirectories || [];
|
||
const showSubdirectory = !!field.options?.showSubdirectory;
|
||
|
||
const selectedTable = useMemo(() => {
|
||
return tablesData?.tables?.find((t) => t.id === tableId);
|
||
}, [tablesData, tableId]);
|
||
|
||
const handleTableChange = (value: string) => {
|
||
if (value === 'none') {
|
||
updateField(index, {
|
||
options: {
|
||
...field.options,
|
||
tableId: undefined,
|
||
displayColumn: undefined,
|
||
showSubdirectory: undefined,
|
||
},
|
||
});
|
||
return;
|
||
}
|
||
const newTableId = parseInt(value);
|
||
const newSelectedTable = tablesData?.tables?.find((t) => t.id === newTableId);
|
||
updateField(index, {
|
||
options: {
|
||
...field.options,
|
||
tableId: newTableId,
|
||
displayColumn: newSelectedTable?.columns?.[0]?.name || undefined,
|
||
showSubdirectory: undefined,
|
||
},
|
||
});
|
||
};
|
||
|
||
const handleShowSubdirectoryChange = (checked: boolean) => {
|
||
updateField(index, {
|
||
options: {
|
||
...field.options,
|
||
showSubdirectory: checked,
|
||
},
|
||
});
|
||
};
|
||
|
||
return (
|
||
<div className="mt-3 space-y-3">
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox
|
||
checked={field.allowMultiple || false}
|
||
onCheckedChange={(checked) => updateField(index, { allowMultiple: !!checked })}
|
||
data-testid={`checkbox-field-table-allow-multiple-${index}`}
|
||
/>
|
||
<label className="text-sm font-medium">Разрешить множественный выбор</label>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div>
|
||
<label className="text-sm font-medium">Таблица</label>
|
||
<Select value={tableId?.toString() || 'none'} onValueChange={handleTableChange}>
|
||
<SelectTrigger data-testid={`select-field-table-${index}`}>
|
||
<SelectValue placeholder="Выберите таблицу" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="none">Не выбрано</SelectItem>
|
||
{tablesData?.tables?.map((table) => (
|
||
<SelectItem key={table.id} value={table.id.toString()}>
|
||
<div className="flex items-center gap-2">
|
||
<Table className="w-4 h-4" />
|
||
{table.name}
|
||
</div>
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
{tableId && (
|
||
<div>
|
||
<label className="text-sm font-medium">Отображаемый столбец</label>
|
||
<Select
|
||
value={field.options?.displayColumn || 'none'}
|
||
onValueChange={(value) =>
|
||
updateField(index, {
|
||
options: { ...field.options, displayColumn: value === 'none' ? undefined : value },
|
||
})
|
||
}
|
||
>
|
||
<SelectTrigger data-testid={`select-field-column-${index}`}>
|
||
<SelectValue placeholder="Выберите столбец" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="none">Не выбрано</SelectItem>
|
||
{selectedTable?.columns?.map((col: any, idx: number) => (
|
||
<SelectItem key={idx} value={col.name || `col-${idx}`}>
|
||
{col.name}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{tableId && (
|
||
<div className="border rounded-md p-3 space-y-3 bg-muted/20">
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox
|
||
checked={showSubdirectory}
|
||
onCheckedChange={handleShowSubdirectoryChange}
|
||
data-testid={`checkbox-field-show-subdirectory-${index}`}
|
||
/>
|
||
<label className="text-sm font-medium flex items-center gap-1.5">
|
||
<Link2 className="w-3.5 h-3.5" />
|
||
Отображать подсправочник
|
||
</label>
|
||
</div>
|
||
|
||
{showSubdirectory && (
|
||
<p className="text-xs text-muted-foreground">
|
||
При выборе строки родительского справочника будет показан подсправочник, привязанный к этой строке.
|
||
{subdirectories.length > 0
|
||
? ` Найдено подсправочников: ${subdirectories.length}.`
|
||
: ' Нет привязанных подсправочников.'}
|
||
</p>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|