113 lines
No EOL
5.3 KiB
TypeScript
Executable file
113 lines
No EOL
5.3 KiB
TypeScript
Executable file
import React, { useState, useEffect } from 'react';
|
|
import { TrashIcon } from './icons/TrashIcon';
|
|
import { ChevronDownIcon } from './icons/ChevronDownIcon';
|
|
|
|
interface ProofTypeManagerProps {
|
|
subChannels: string[];
|
|
proofTypesBySubChannel: Record<string, string[]>;
|
|
onAddProofType: (subChannel: string, value: string) => void;
|
|
onRemoveProofType: (subChannel: string, value: string) => void;
|
|
disabled: boolean;
|
|
}
|
|
|
|
export const ProofTypeManager: React.FC<ProofTypeManagerProps> = ({
|
|
subChannels,
|
|
proofTypesBySubChannel,
|
|
onAddProofType,
|
|
onRemoveProofType,
|
|
disabled
|
|
}) => {
|
|
const [selectedSubChannel, setSelectedSubChannel] = useState<string>('');
|
|
const [newItem, setNewItem] = useState('');
|
|
|
|
useEffect(() => {
|
|
// If subChannels are available, default to the first one.
|
|
if (subChannels.length > 0 && !selectedSubChannel) {
|
|
setSelectedSubChannel(subChannels[0]);
|
|
}
|
|
}, [subChannels, selectedSubChannel]);
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (newItem.trim() && selectedSubChannel) {
|
|
onAddProofType(selectedSubChannel, newItem.trim());
|
|
setNewItem('');
|
|
}
|
|
};
|
|
|
|
const currentProofTypes = proofTypesBySubChannel[selectedSubChannel] || [];
|
|
|
|
return (
|
|
<div className="bg-white rounded-lg shadow-md p-6 border border-gray-200 flex flex-col h-full">
|
|
<h2 className="text-xl font-bold text-brand-dark-blue mb-2">Proof Type Manager</h2>
|
|
<p className="text-sm text-gray-500 mb-4">Assign and manage specific proof types for each sub-channel.</p>
|
|
|
|
<div className="mb-4">
|
|
<label htmlFor="subchannel-select" className="block text-sm font-medium text-gray-700 mb-1">
|
|
Select a Sub-Channel to manage:
|
|
</label>
|
|
<div className="relative">
|
|
<select
|
|
id="subchannel-select"
|
|
value={selectedSubChannel}
|
|
onChange={(e) => setSelectedSubChannel(e.target.value)}
|
|
className="w-full bg-white border border-gray-300 rounded-md py-2 pl-3 pr-10 text-gray-900 focus:outline-none focus:ring-2 focus:ring-brand-accent appearance-none disabled:bg-gray-100"
|
|
disabled={disabled}
|
|
>
|
|
{subChannels.map(sc => (
|
|
<option key={sc} value={sc}>{sc}</option>
|
|
))}
|
|
</select>
|
|
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 text-gray-400">
|
|
<ChevronDownIcon className="h-4 w-4" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="flex gap-2 mb-4">
|
|
<input
|
|
type="text"
|
|
value={newItem}
|
|
onChange={(e) => setNewItem(e.target.value)}
|
|
placeholder="New Proof Type..."
|
|
className="flex-grow p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-brand-accent focus:border-brand-accent transition disabled:bg-gray-100 disabled:cursor-not-allowed"
|
|
disabled={disabled || !selectedSubChannel}
|
|
/>
|
|
<button
|
|
type="submit"
|
|
className="bg-brand-accent text-white font-semibold py-2 px-4 rounded-md hover:bg-brand-dark-blue transition-colors duration-300 disabled:bg-gray-400 disabled:cursor-not-allowed"
|
|
disabled={!newItem.trim() || disabled || !selectedSubChannel}
|
|
>
|
|
Add
|
|
</button>
|
|
</form>
|
|
|
|
<div className="flex-1 overflow-y-auto pr-2 -mr-2">
|
|
{currentProofTypes.length > 0 ? (
|
|
<ul className="space-y-2">
|
|
{currentProofTypes.map((item) => (
|
|
<li
|
|
key={item}
|
|
className="flex items-center justify-between bg-gray-50 p-2.5 rounded-md border border-gray-200 group"
|
|
>
|
|
<span className="text-gray-800">{item}</span>
|
|
<button
|
|
onClick={() => onRemoveProofType(selectedSubChannel, item)}
|
|
className={`text-gray-400 hover:text-red-600 transition-opacity ${disabled ? 'opacity-0 cursor-not-allowed' : 'opacity-0 group-hover:opacity-100'}`}
|
|
title={`Remove ${item}`}
|
|
disabled={disabled}
|
|
>
|
|
<TrashIcon className="h-5 w-5" />
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : (
|
|
<div className="text-center py-8 text-gray-500 bg-gray-50 rounded-md h-full flex items-center justify-center">
|
|
<p>No proof types configured for <br/> <strong className="text-gray-600">{selectedSubChannel}</strong>.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}; |