import React, { useState, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import type { ColumnDef } from '@tanstack/react-table'; import { getDirectusClient, readItems, createItem, updateItem, deleteItem } from '@/lib/directus/client'; import { DataTable } from '../shared/DataTable'; import { CRUDModal } from '../shared/CRUDModal'; import { DeleteConfirm } from '../shared/DeleteConfirm'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; // Validation schema const cartesianSchema = z.object({ pattern_key: z.string().min(1, 'Pattern key is required'), pattern_type: z.string().min(1, 'Pattern type is required'), formula: z.string().min(1, 'Formula is required'), example_output: z.string().optional(), description: z.string().optional(), }); type CartesianFormData = z.infer; interface CartesianPattern { id: string; pattern_key: string; pattern_type: string; formula: string; example_output?: string; description?: string; } export default function CartesianManager() { const [patterns, setPatterns] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [isDeleteOpen, setIsDeleteOpen] = useState(false); const [editingPattern, setEditingPattern] = useState(null); const [deletingPattern, setDeletingPattern] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const { register, handleSubmit, reset, setValue, formState: { errors }, } = useForm({ resolver: zodResolver(cartesianSchema), }); // Load data const loadPatterns = async () => { setIsLoading(true); try { const client = getDirectusClient(); const data = await client.request( readItems('cartesian_patterns', { fields: ['*'], sort: ['pattern_type', 'pattern_key'], }) ); setPatterns(data as CartesianPattern[]); } catch (error) { console.error('Error loading cartesian patterns:', error); } finally { setIsLoading(false); } }; useEffect(() => { loadPatterns(); }, []); // Handle create/edit const onSubmit = async (data: CartesianFormData) => { setIsSubmitting(true); try { const client = getDirectusClient(); if (editingPattern) { await client.request( updateItem('cartesian_patterns', editingPattern.id, data) ); } else { await client.request(createItem('cartesian_patterns', data)); } await loadPatterns(); setIsModalOpen(false); reset(); setEditingPattern(null); } catch (error) { console.error('Error saving pattern:', error); alert('Failed to save pattern'); } finally { setIsSubmitting(false); } }; // Handle delete const handleDelete = async () => { if (!deletingPattern) return; setIsSubmitting(true); try { const client = getDirectusClient(); await client.request(deleteItem('cartesian_patterns', deletingPattern.id)); await loadPatterns(); setIsDeleteOpen(false); setDeletingPattern(null); } catch (error) { console.error('Error deleting pattern:', error); alert('Failed to delete pattern'); } finally { setIsSubmitting(false); } }; // Handle edit click const handleEdit = (pattern: CartesianPattern) => { setEditingPattern(pattern); Object.keys(pattern).forEach((key) => { setValue(key as any, (pattern as any)[key]); }); setIsModalOpen(true); }; // Handle add click const handleAdd = () => { setEditingPattern(null); reset(); setIsModalOpen(true); }; // Handle delete click const handleDeleteClick = (pattern: CartesianPattern) => { setDeletingPattern(pattern); setIsDeleteOpen(true); }; // Export data const handleExport = () => { const dataStr = JSON.stringify(patterns, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `cartesian-patterns-${new Date().toISOString().split('T')[0]}.json`; link.click(); }; // Table columns const columns: ColumnDef[] = [ { accessorKey: 'pattern_key', header: 'Pattern Key', cell: ({ row }) => ( {row.original.pattern_key} ), }, { accessorKey: 'pattern_type', header: 'Type', cell: ({ row }) => ( {row.original.pattern_type} ), }, { accessorKey: 'formula', header: 'Formula', cell: ({ row }) => ( {row.original.formula.length > 50 ? row.original.formula.substring(0, 50) + '...' : row.original.formula} ), }, { accessorKey: 'example_output', header: 'Example', cell: ({ row }) => ( {row.original.example_output ? (row.original.example_output.length > 40 ? row.original.example_output.substring(0, 40) + '...' : row.original.example_output) : '—'} ), }, { id: 'actions', header: 'Actions', cell: ({ row }) => (
), }, ]; const patternTypes = new Set(patterns.map(p => p.pattern_type)); return (
{/* Stats */}
Total Patterns
{patterns.length}
Pattern Types
{patternTypes.size}
Avg Formula Length
{patterns.length > 0 ? Math.round(patterns.reduce((sum, p) => sum + p.formula.length, 0) / patterns.length) : 0}
{/* Data Table */} {/* Create/Edit Modal */} { setIsModalOpen(false); setEditingPattern(null); reset(); }} title={editingPattern ? 'Edit Cartesian Pattern' : 'Create Cartesian Pattern'} description="Define content generation patterns using Cartesian product logic" onSubmit={handleSubmit(onSubmit)} isSubmitting={isSubmitting} >
{errors.pattern_key && (

{errors.pattern_key.message}

)}
{errors.pattern_type && (

{errors.pattern_type.message}

)}