138 lines
4.1 KiB
TypeScript
138 lines
4.1 KiB
TypeScript
import { useMemo } from 'react';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { apiRequest } from '@/lib/queryClient';
|
|
import TableFieldSelect from '@/components/TableFieldSelect';
|
|
import TableFieldMultiSelect from '@/components/TableFieldMultiSelect';
|
|
import type { DataTableSubdirectory } from '@shared/schema';
|
|
|
|
interface TableFieldValue {
|
|
parentId?: string | null;
|
|
childId?: string | null;
|
|
}
|
|
|
|
interface TableFieldWithSubdirectoryProps {
|
|
fieldId: number;
|
|
fieldCode: string;
|
|
placeholder?: string;
|
|
options?: unknown;
|
|
value: any;
|
|
onChange: (value: string) => void;
|
|
allowMultiple?: boolean;
|
|
}
|
|
|
|
function parseTableValue(value: any): TableFieldValue {
|
|
if (value == null || value === '') return { parentId: null, childId: null };
|
|
if (typeof value === 'string') {
|
|
try {
|
|
const parsed = JSON.parse(value);
|
|
if (parsed && typeof parsed === 'object') {
|
|
return {
|
|
parentId: parsed.parentId != null ? String(parsed.parentId) : null,
|
|
childId: parsed.childId != null ? String(parsed.childId) : null,
|
|
};
|
|
}
|
|
} catch {
|
|
// fallback: plain string is parentId
|
|
}
|
|
return { parentId: value, childId: null };
|
|
}
|
|
if (typeof value === 'object') {
|
|
return {
|
|
parentId: value.parentId != null ? String(value.parentId) : null,
|
|
childId: value.childId != null ? String(value.childId) : null,
|
|
};
|
|
}
|
|
return { parentId: String(value), childId: null };
|
|
}
|
|
|
|
function serializeTableValue(parentId: string | null | undefined, childId: string | null | undefined): string {
|
|
const p = parentId || null;
|
|
const c = childId || null;
|
|
if (!p) return '';
|
|
if (!c) return p;
|
|
return JSON.stringify({ parentId: p, childId: c });
|
|
}
|
|
|
|
export default function TableFieldWithSubdirectory({
|
|
fieldId,
|
|
fieldCode,
|
|
placeholder,
|
|
options,
|
|
value,
|
|
onChange,
|
|
allowMultiple,
|
|
}: TableFieldWithSubdirectoryProps) {
|
|
const opts = options && !Array.isArray(options) ? (options as Record<string, any>) : {};
|
|
const tableId = opts.tableId as number | undefined;
|
|
const showSubdirectory = !!opts.showSubdirectory;
|
|
|
|
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 && showSubdirectory,
|
|
staleTime: 60 * 1000,
|
|
});
|
|
|
|
const { parentId, childId } = parseTableValue(value);
|
|
|
|
const subdirectory = useMemo(() => {
|
|
if (!parentId) return undefined;
|
|
return subdirectoriesData?.subdirectories?.find((s) =>
|
|
s.parentRowIds?.includes(Number(parentId))
|
|
);
|
|
}, [subdirectoriesData, parentId]);
|
|
|
|
const handleParentChange = (newParentId: string) => {
|
|
onChange(serializeTableValue(newParentId || null, null));
|
|
};
|
|
|
|
const handleChildChange = (newChildId: string) => {
|
|
onChange(serializeTableValue(parentId, newChildId || null));
|
|
};
|
|
|
|
if (!showSubdirectory || allowMultiple) {
|
|
const SelectComponent = allowMultiple ? TableFieldMultiSelect : TableFieldSelect;
|
|
return (
|
|
<SelectComponent
|
|
fieldId={fieldId}
|
|
fieldCode={fieldCode}
|
|
placeholder={placeholder}
|
|
options={options}
|
|
value={parentId || ''}
|
|
onChange={onChange as any}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const parentOptions = opts;
|
|
const childOptions = subdirectory
|
|
? { ...opts, tableId: subdirectory.childTableId }
|
|
: opts;
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
<TableFieldSelect
|
|
fieldId={fieldId}
|
|
fieldCode={fieldCode}
|
|
placeholder={placeholder || 'Выберите значение...'}
|
|
options={parentOptions}
|
|
value={parentId || ''}
|
|
onChange={handleParentChange}
|
|
/>
|
|
{subdirectory && (
|
|
<TableFieldSelect
|
|
fieldId={fieldId}
|
|
fieldCode={`${fieldCode}_sub`}
|
|
placeholder={subdirectory.childTable?.name || 'Выберите подсправочник...'}
|
|
options={childOptions}
|
|
value={childId || ''}
|
|
onChange={handleChildChange}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|