3TE/src/pages/configuration/RegulatorsConfigurationPage.tsx

523 lines
20 KiB
TypeScript

import { useState } from 'react'
import { useStorage } from '@/hooks/useStorage'
import { NaturalRegulator } from '@/types'
import Card from '@/components/base/Card'
import Button from '@/components/base/Button'
import Input from '@/components/base/Input'
import Table from '@/components/base/Table'
import { validateRequired, validateNumber } from '@/utils/validators'
import './RegulatorsConfigurationPage.css'
export default function RegulatorsConfigurationPage() {
const { data, addEntity, updateEntity, deleteEntity, loading } = useStorage()
const [editingId, setEditingId] = useState<string | null>(null)
const [formData, setFormData] = useState<Partial<NaturalRegulator>>({
name: '',
type: '',
applicationConditions: '',
dosageRequirements: {
min: 0,
max: 0,
unit: 'kg/t',
},
regulatoryCharacteristics: {},
})
const [errors, setErrors] = useState<Record<string, string>>({})
if (loading || !data) {
return (
<div className="regulators-config-page">
<div className="page-loading">Loading...</div>
</div>
)
}
// Safely normalize regulators to ensure all required fields exist
const regulators: NaturalRegulator[] = (data.regulators || [])
.filter(reg => reg && reg.id && reg.name) // Filter out invalid entries
.map(reg => ({
id: reg.id,
name: reg.name || '',
type: reg.type || '',
applicationConditions: reg.applicationConditions || '',
dosageRequirements: reg.dosageRequirements || {
min: 0,
max: 0,
unit: 'kg/t' as const,
},
regulatoryCharacteristics: reg.regulatoryCharacteristics || {},
createdAt: reg.createdAt || new Date().toISOString(),
updatedAt: reg.updatedAt,
notes: reg.notes,
}))
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
const newErrors: Record<string, string> = {}
newErrors.name = validateRequired(formData.name)
newErrors.type = validateRequired(formData.type)
newErrors.applicationConditions = validateRequired(formData.applicationConditions)
newErrors.dosageMin = validateNumber(formData.dosageRequirements?.min, 0)
newErrors.dosageMax = validateNumber(formData.dosageRequirements?.max, formData.dosageRequirements?.min)
setErrors(newErrors)
if (Object.values(newErrors).some((error) => error !== undefined)) {
return
}
const regulator: NaturalRegulator = {
id: editingId || crypto.randomUUID(),
name: formData.name!,
type: formData.type!,
regulatoryCharacteristics: formData.regulatoryCharacteristics || {},
applicationConditions: formData.applicationConditions!,
dosageRequirements: formData.dosageRequirements!,
createdAt: editingId ? regulators.find((r) => r.id === editingId)?.createdAt || new Date().toISOString() : new Date().toISOString(),
updatedAt: new Date().toISOString(),
}
if (editingId) {
updateEntity('regulators', editingId, regulator)
} else {
addEntity('regulators', regulator)
}
resetForm()
}
const resetForm = () => {
setFormData({
name: '',
type: '',
applicationConditions: '',
dosageRequirements: {
min: 0,
max: 0,
unit: 'kg/t',
},
regulatoryCharacteristics: {},
})
setEditingId(null)
setErrors({})
}
const handleEdit = (regulator: NaturalRegulator) => {
setFormData({
name: regulator.name || '',
type: regulator.type || '',
applicationConditions: regulator.applicationConditions || '',
dosageRequirements: regulator.dosageRequirements || {
min: 0,
max: 0,
unit: 'kg/t',
},
regulatoryCharacteristics: regulator.regulatoryCharacteristics || {},
})
setEditingId(regulator.id)
}
const handleDelete = (id: string) => {
if (confirm('Are you sure you want to delete this regulator?')) {
deleteEntity('regulators', id)
}
}
const tableColumns = [
{
key: 'name',
header: 'Name',
render: (regulator: NaturalRegulator) => regulator.name || '-',
},
{
key: 'type',
header: 'Type',
render: (regulator: NaturalRegulator) => regulator.type || '-',
},
{
key: 'dosage',
header: 'Dosage',
render: (regulator: NaturalRegulator) => {
const dosage = regulator.dosageRequirements
if (!dosage) return '-'
return `${dosage.min} - ${dosage.max} ${dosage.unit}`
},
},
{
key: 'actions',
header: 'Actions',
render: (regulator: NaturalRegulator) => (
<div className="table-actions">
<Button variant="secondary" onClick={() => handleEdit(regulator)}>
Edit
</Button>
<Button variant="danger" onClick={() => handleDelete(regulator.id)}>
Delete
</Button>
</div>
),
},
]
return (
<div className="regulators-config-page">
<h1 className="page-title">Natural Regulators Configuration</h1>
<div className="page-content">
<Card title={editingId ? 'Edit Regulator' : 'Add Regulator'} className="form-card">
<form onSubmit={handleSubmit}>
<div className="form-row">
<Input
label="Name *"
value={formData.name || ''}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
error={errors.name}
/>
<Input
label="Type *"
value={formData.type || ''}
onChange={(e) => setFormData({ ...formData, type: e.target.value })}
error={errors.type}
/>
</div>
<Input
label="Application Conditions *"
value={formData.applicationConditions || ''}
onChange={(e) => setFormData({ ...formData, applicationConditions: e.target.value })}
error={errors.applicationConditions}
/>
<div className="form-row">
<Input
label="Dosage Min *"
type="number"
min="0"
value={formData.dosageRequirements?.min || ''}
onChange={(e) =>
setFormData({
...formData,
dosageRequirements: {
...formData.dosageRequirements!,
min: parseFloat(e.target.value) || 0,
},
})
}
error={errors.dosageMin}
/>
<Input
label="Dosage Max *"
type="number"
min={formData.dosageRequirements?.min || 0}
value={formData.dosageRequirements?.max || ''}
onChange={(e) =>
setFormData({
...formData,
dosageRequirements: {
...formData.dosageRequirements!,
max: parseFloat(e.target.value) || 0,
},
})
}
error={errors.dosageMax}
/>
<Select
label="Dosage Unit *"
value={formData.dosageRequirements?.unit || 'kg/t'}
onChange={(e) =>
setFormData({
...formData,
dosageRequirements: {
...formData.dosageRequirements!,
unit: e.target.value as 'kg/t' | 'L/t' | '%',
},
})
}
options={[
{ value: 'kg/t', label: 'kg/t' },
{ value: 'L/t', label: 'L/t' },
{ value: '%', label: '%' },
]}
/>
</div>
{/* Regulatory Characteristics Section */}
<div className="form-section">
<h3 className="form-section-title">Regulatory Characteristics (Typical)</h3>
{/* Nutrient Requirements */}
<div className="form-subsection">
<h4 className="form-subsection-title">Nutrient Requirements</h4>
<div className="form-row">
<Input
label="Nitrogen (N or NTK)"
type="number"
step="0.01"
min="0"
value={formData.regulatoryCharacteristics?.nitrogen || ''}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
nitrogen: e.target.value ? parseFloat(e.target.value) : undefined,
},
})}
/>
<Input
label="Ammoniacal Nitrogen (N-NH₄)"
type="number"
step="0.01"
min="0"
value={formData.regulatoryCharacteristics?.ammoniacalNitrogen || ''}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
ammoniacalNitrogen: e.target.value ? parseFloat(e.target.value) : undefined,
},
})}
/>
</div>
<div className="form-row">
<Input
label="Phosphorus (P)"
type="number"
step="0.01"
min="0"
value={formData.regulatoryCharacteristics?.phosphorus || ''}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
phosphorus: e.target.value ? parseFloat(e.target.value) : undefined,
},
})}
/>
<Input
label="Potassium (K)"
type="number"
step="0.01"
min="0"
value={formData.regulatoryCharacteristics?.potassium || ''}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
potassium: e.target.value ? parseFloat(e.target.value) : undefined,
},
})}
/>
</div>
<div className="form-row">
<Input
label="Carbon:Nitrogen Ratio (C:N)"
type="number"
step="0.1"
min="0"
value={formData.regulatoryCharacteristics?.carbonNitrogenRatio || ''}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
carbonNitrogenRatio: e.target.value ? parseFloat(e.target.value) : undefined,
},
})}
/>
<Input
label="pH Adjustment (-14 to 14)"
type="number"
step="0.1"
min="-14"
max="14"
value={formData.regulatoryCharacteristics?.phAdjustment || ''}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
phAdjustment: e.target.value ? parseFloat(e.target.value) : undefined,
},
})}
helpText="Negative values reduce pH, positive values increase pH"
/>
</div>
</div>
{/* Heavy Metals and Toxic Elements */}
<div className="form-subsection">
<h4 className="form-subsection-title">Heavy Metals and Toxic Elements (Capabilities)</h4>
<div className="checkbox-grid">
{[
{ key: 'arsenicElimination', label: 'Arsenic (As) Elimination' },
{ key: 'zincElimination', label: 'Zinc Elimination' },
{ key: 'aluminumElimination', label: 'Aluminum Elimination' },
{ key: 'copperElimination', label: 'Copper Elimination' },
{ key: 'heavyMetalsElimination', label: 'Heavy Metals Elimination' },
{ key: 'metalBinding', label: 'Metal Binding' },
].map((item) => (
<label key={item.key} className="checkbox-item">
<input
type="checkbox"
checked={Boolean((formData.regulatoryCharacteristics?.[item.key as keyof NonNullable<typeof formData.regulatoryCharacteristics>] as boolean))}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
[item.key]: e.target.checked,
},
})}
/>
<span>{item.label}</span>
</label>
))}
</div>
</div>
{/* Biological Contaminants */}
<div className="form-subsection">
<h4 className="form-subsection-title">Biological Contaminants (Capabilities)</h4>
<div className="checkbox-grid">
<label className="checkbox-item">
<input
type="checkbox"
checked={formData.regulatoryCharacteristics?.pathogenReduction || false}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
pathogenReduction: e.target.checked,
},
})}
/>
<span>Pathogen Reduction</span>
</label>
</div>
</div>
{/* Chemical Parameters */}
<div className="form-subsection">
<h4 className="form-subsection-title">Chemical Parameters (Capabilities)</h4>
<div className="checkbox-grid">
{[
{ key: 'lowCNRatioEnrichment', label: 'Low C:N Ratio Enrichment' },
{ key: 'medicationElimination', label: 'Medication Elimination' },
{ key: 'depositElimination', label: 'Deposit Elimination' },
{ key: 'odorElimination', label: 'Odor Elimination' },
{ key: 'turbidityReduction', label: 'Turbidity Reduction' },
{ key: 'sodiumReduction', label: 'Sodium (Na⁺) Reduction' },
{ key: 'chlorineReduction', label: 'Chlorine (Cl⁻) Reduction' },
{ key: 'electricalConductivityReduction', label: 'Electrical Conductivity Reduction' },
{ key: 'sulfideElimination', label: 'Sulfide Elimination' },
{ key: 'methaneElimination', label: 'Methane Elimination' },
{ key: 'co2Elimination', label: 'CO₂ Elimination' },
{ key: 'polyphenolElimination', label: 'Polyphenol Elimination' },
{ key: 'refractoryFractionsElimination', label: 'Refractory Structural Fractions Elimination' },
].map((item) => {
const key = item.key as keyof NonNullable<typeof formData.regulatoryCharacteristics>
return (
<label key={item.key} className="checkbox-item">
<input
type="checkbox"
checked={Boolean(formData.regulatoryCharacteristics?.[key])}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
[item.key]: e.target.checked,
},
})}
/>
<span>{item.label}</span>
</label>
)
})}
</div>
</div>
{/* Biological Processes */}
<div className="form-subsection">
<h4 className="form-subsection-title">Biological Processes (Capabilities)</h4>
<div className="checkbox-grid">
{[
{ key: 'microbiologicalCompetition', label: 'Microbiological Competition' },
{ key: 'oilEmulsification', label: 'Oil Emulsification' },
].map((item) => {
const key = item.key as keyof NonNullable<typeof formData.regulatoryCharacteristics>
return (
<label key={item.key} className="checkbox-item">
<input
type="checkbox"
checked={Boolean(formData.regulatoryCharacteristics?.[key])}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
[item.key]: e.target.checked,
},
})}
/>
<span>{item.label}</span>
</label>
)
})}
</div>
</div>
{/* pH Regulation */}
<div className="form-subsection">
<h4 className="form-subsection-title">pH Regulation (Capabilities)</h4>
<div className="checkbox-grid">
{[
{ key: 'acidityReduction', label: 'Acidity Reduction' },
{ key: 'phIncrease', label: 'pH Increase' },
{ key: 'phReduction', label: 'pH Reduction' },
].map((item) => {
const key = item.key as keyof NonNullable<typeof formData.regulatoryCharacteristics>
return (
<label key={item.key} className="checkbox-item">
<input
type="checkbox"
checked={Boolean(formData.regulatoryCharacteristics?.[key])}
onChange={(e) => setFormData({
...formData,
regulatoryCharacteristics: {
...(formData.regulatoryCharacteristics || {}),
[item.key]: e.target.checked,
},
})}
/>
<span>{item.label}</span>
</label>
)
})}
</div>
</div>
</div>
<div className="form-actions">
<Button type="submit" variant="primary">
{editingId ? 'Update' : 'Add'} Regulator
</Button>
{editingId && (
<Button type="button" variant="secondary" onClick={resetForm}>
Cancel
</Button>
)}
</div>
</form>
</Card>
<Card title="Natural Regulators" className="table-card">
{regulators.length > 0 ? (
<Table columns={tableColumns} data={regulators} emptyMessage="No regulators configured" />
) : (
<div className="table-empty">
<p>No regulators configured</p>
</div>
)}
</Card>
</div>
</div>
)
}