Files
Brancheneinstufung2/competitor-analysis/components/EditableCard.tsx

129 lines
6.3 KiB
TypeScript

import React, { useState } from 'react';
interface Item {
[key: string]: any;
}
interface FieldConfig {
key: string;
label: string;
type: 'text' | 'textarea';
}
interface EditableCardProps<T extends Item> {
title: string;
items: T[];
onItemsChange: (items: T[]) => void;
fieldConfigs: FieldConfig[];
newItemTemplate: T;
renderDisplay: (item: T, index: number) => React.ReactNode;
showAddButton?: boolean;
t: {
add: string;
cancel: string;
save: string;
}
}
const PencilIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.5L14.732 3.732z" /></svg>
);
const TrashIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
);
export const EditableCard = <T extends Item,>({ title, items, onItemsChange, fieldConfigs, newItemTemplate, renderDisplay, showAddButton, t }: EditableCardProps<T>) => {
const [editingIndex, setEditingIndex] = useState<number | null>(null);
const [editItem, setEditItem] = useState<T | null>(null);
const handleEdit = (index: number) => {
setEditingIndex(index);
setEditItem({ ...items[index] });
};
const handleSave = () => {
if (editingIndex !== null && editItem) {
const newItems = [...items];
newItems[editingIndex] = editItem;
onItemsChange(newItems);
setEditingIndex(null);
setEditItem(null);
}
};
const handleCancel = () => {
setEditingIndex(null);
setEditItem(null);
};
const handleRemove = (index: number) => {
onItemsChange(items.filter((_, i) => i !== index));
};
const handleAdd = () => {
onItemsChange([...items, newItemTemplate]);
setEditingIndex(items.length);
setEditItem(newItemTemplate);
};
const handleInputChange = (key: string, value: string) => {
if (editItem) {
setEditItem({ ...editItem, [key]: value });
}
};
const inputClasses = "w-full bg-light-secondary dark:bg-brand-secondary text-light-text dark:text-brand-text border border-light-accent dark:border-brand-accent rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-brand-highlight";
return (
<div className="bg-light-secondary dark:bg-brand-secondary p-6 rounded-lg shadow-lg mb-6 border border-light-accent dark:border-brand-accent">
<div className="flex justify-between items-center mb-4">
<h3 className="text-xl font-bold">{title}</h3>
{(showAddButton ?? true) && (
<button onClick={handleAdd} className="bg-brand-accent hover:bg-brand-light text-white font-bold py-1 px-3 rounded-md text-sm transition-colors">+ {t.add}</button>
)}
</div>
<div className="space-y-4">
{items.map((item, index) => (
<div key={index} className="bg-light-primary dark:bg-brand-primary p-4 rounded-md">
{editingIndex === index && editItem ? (
<div className="space-y-3">
{fieldConfigs.map(field => (
<div key={field.key}>
<label className="block text-sm font-medium text-light-subtle dark:text-brand-light mb-1">{field.label}</label>
{field.type === 'textarea' ? (
<textarea
value={editItem[field.key]}
onChange={(e) => handleInputChange(field.key, e.target.value)}
className={inputClasses}
rows={3}
/>
) : (
<input
type="text"
value={editItem[field.key]}
onChange={(e) => handleInputChange(field.key, e.target.value)}
className={inputClasses}
/>
)}
</div>
))}
<div className="flex justify-end space-x-2 mt-2">
<button onClick={handleCancel} className="bg-gray-500 hover:bg-gray-600 text-white py-1 px-3 rounded-md text-sm transition-colors">{t.cancel}</button>
<button onClick={handleSave} className="bg-brand-highlight hover:bg-blue-600 text-white py-1 px-3 rounded-md text-sm transition-colors">{t.save}</button>
</div>
</div>
) : (
<div className="flex justify-between items-start">
<div className="flex-grow">{renderDisplay(item, index)}</div>
<div className="flex space-x-2 flex-shrink-0 ml-4">
<button onClick={() => handleEdit(index)} className="text-light-subtle dark:text-brand-light hover:text-light-text dark:hover:text-white p-1 rounded-full transition-colors"><PencilIcon /></button>
<button onClick={() => handleRemove(index)} className="text-light-subtle dark:text-brand-light hover:text-red-500 p-1 rounded-full transition-colors"><TrashIcon /></button>
</div>
</div>
)}
</div>
))}
</div>
</div>
);
};