248 lines
7.9 KiB
JavaScript
248 lines
7.9 KiB
JavaScript
import { useState } from 'react';
|
|
import { Plus, Edit2, Trash2, X, Check } from 'lucide-react';
|
|
|
|
export default function ExperienceForm({ data, onUpdate }) {
|
|
const [editingId, setEditingId] = useState(null);
|
|
const [editForm, setEditForm] = useState(null);
|
|
|
|
const defaultForm = {
|
|
role: '',
|
|
company: '',
|
|
period: '',
|
|
type: 'Vollzeit',
|
|
description: '',
|
|
highlights: []
|
|
};
|
|
|
|
const startAdd = () => {
|
|
setEditingId('new');
|
|
setEditForm({ ...defaultForm, id: Date.now() });
|
|
};
|
|
|
|
const startEdit = (exp) => {
|
|
setEditingId(exp.id);
|
|
setEditForm({ ...exp });
|
|
};
|
|
|
|
const cancelEdit = () => {
|
|
setEditingId(null);
|
|
setEditForm(null);
|
|
};
|
|
|
|
const saveEdit = () => {
|
|
if (!editForm.role || !editForm.company) return;
|
|
|
|
if (editingId === 'new') {
|
|
onUpdate([...data, editForm]);
|
|
} else {
|
|
onUpdate(data.map(e => e.id === editingId ? editForm : e));
|
|
}
|
|
cancelEdit();
|
|
};
|
|
|
|
const deleteItem = (id) => {
|
|
onUpdate(data.filter(e => e.id !== id));
|
|
};
|
|
|
|
const addHighlight = () => {
|
|
setEditForm(prev => ({
|
|
...prev,
|
|
highlights: [...(prev.highlights || []), '']
|
|
}));
|
|
};
|
|
|
|
const updateHighlight = (index, value) => {
|
|
setEditForm(prev => ({
|
|
...prev,
|
|
highlights: prev.highlights.map((h, i) => i === index ? value : h)
|
|
}));
|
|
};
|
|
|
|
const removeHighlight = (index) => {
|
|
setEditForm(prev => ({
|
|
...prev,
|
|
highlights: prev.highlights.filter((_, i) => i !== index)
|
|
}));
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white rounded-xl p-6 shadow-sm border border-slate-100">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h2 className="text-xl font-semibold text-slate-900">Berufserfahrung</h2>
|
|
{editingId !== 'new' && (
|
|
<button
|
|
onClick={startAdd}
|
|
className="flex items-center gap-2 px-3 py-1.5 bg-primary-100 text-primary-700 rounded-lg hover:bg-primary-200 transition-colors text-sm"
|
|
>
|
|
<Plus size={16} />
|
|
Hinzufügen
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
{editingId === 'new' && editForm && (
|
|
<div className="mb-4 p-4 bg-primary-50 rounded-lg border border-primary-200">
|
|
<EditForm
|
|
form={editForm}
|
|
setForm={setEditForm}
|
|
onSave={saveEdit}
|
|
onCancel={cancelEdit}
|
|
onAddHighlight={addHighlight}
|
|
onUpdateHighlight={updateHighlight}
|
|
onRemoveHighlight={removeHighlight}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-3">
|
|
{data.map((exp) => (
|
|
<div key={exp.id}>
|
|
{editingId === exp.id ? (
|
|
<div className="p-4 bg-primary-50 rounded-lg border border-primary-200">
|
|
<EditForm
|
|
form={editForm}
|
|
setForm={setEditForm}
|
|
onSave={saveEdit}
|
|
onCancel={cancelEdit}
|
|
onAddHighlight={addHighlight}
|
|
onUpdateHighlight={updateHighlight}
|
|
onRemoveHighlight={removeHighlight}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<div className="flex items-start gap-3 p-4 bg-slate-50 rounded-lg group">
|
|
<div className="flex-1">
|
|
<h3 className="font-medium text-slate-900">{exp.role}</h3>
|
|
<p className="text-sm text-slate-600">{exp.company} • {exp.period}</p>
|
|
<span className="inline-block mt-1 px-2 py-0.5 text-xs bg-slate-200 text-slate-600 rounded">
|
|
{exp.type}
|
|
</span>
|
|
</div>
|
|
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
<button
|
|
onClick={() => startEdit(exp)}
|
|
className="p-1.5 text-slate-500 hover:text-primary-600 hover:bg-primary-50 rounded"
|
|
>
|
|
<Edit2 size={16} />
|
|
</button>
|
|
<button
|
|
onClick={() => deleteItem(exp.id)}
|
|
className="p-1.5 text-slate-500 hover:text-red-600 hover:bg-red-50 rounded"
|
|
>
|
|
<Trash2 size={16} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function EditForm({ form, setForm, onSave, onCancel, onAddHighlight, onUpdateHighlight, onRemoveHighlight }) {
|
|
const handleChange = (e) => {
|
|
const { name, value } = e.target;
|
|
setForm(prev => ({ ...prev, [name]: value }));
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
<div className="grid md:grid-cols-2 gap-3">
|
|
<input
|
|
type="text"
|
|
name="role"
|
|
value={form.role || ''}
|
|
onChange={handleChange}
|
|
placeholder="Rolle / Position"
|
|
className="px-3 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
/>
|
|
<input
|
|
type="text"
|
|
name="company"
|
|
value={form.company || ''}
|
|
onChange={handleChange}
|
|
placeholder="Unternehmen"
|
|
className="px-3 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
/>
|
|
</div>
|
|
<div className="grid md:grid-cols-2 gap-3">
|
|
<input
|
|
type="text"
|
|
name="period"
|
|
value={form.period || ''}
|
|
onChange={handleChange}
|
|
placeholder="Zeitraum (z.B. 2021 - 2025)"
|
|
className="px-3 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
/>
|
|
<select
|
|
name="type"
|
|
value={form.type || 'Vollzeit'}
|
|
onChange={handleChange}
|
|
className="px-3 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
>
|
|
<option>Vollzeit</option>
|
|
<option>Teilzeit</option>
|
|
<option>Werkstudent</option>
|
|
<option>SHK</option>
|
|
<option>Freelance</option>
|
|
</select>
|
|
</div>
|
|
<textarea
|
|
name="description"
|
|
value={form.description || ''}
|
|
onChange={handleChange}
|
|
placeholder="Kurze Beschreibung"
|
|
rows={2}
|
|
className="w-full px-3 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
/>
|
|
|
|
<div>
|
|
<label className="text-sm font-medium text-slate-700 mb-1 block">Highlights</label>
|
|
{(form.highlights || []).map((h, i) => (
|
|
<div key={i} className="flex gap-2 mb-2">
|
|
<input
|
|
type="text"
|
|
value={h}
|
|
onChange={(e) => onUpdateHighlight(i, e.target.value)}
|
|
placeholder="Highlight..."
|
|
className="flex-1 px-3 py-2 rounded-lg border border-slate-200 focus:outline-none focus:ring-2 focus:ring-primary-500 text-sm"
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={() => onRemoveHighlight(i)}
|
|
className="p-2 text-slate-400 hover:text-red-500"
|
|
>
|
|
<X size={16} />
|
|
</button>
|
|
</div>
|
|
))}
|
|
<button
|
|
type="button"
|
|
onClick={onAddHighlight}
|
|
className="text-sm text-primary-600 hover:text-primary-700"
|
|
>
|
|
+ Highlight hinzufügen
|
|
</button>
|
|
</div>
|
|
|
|
<div className="flex gap-2 pt-2">
|
|
<button
|
|
onClick={onSave}
|
|
className="flex items-center gap-1 px-3 py-1.5 bg-primary-600 text-white rounded-lg hover:bg-primary-700 text-sm"
|
|
>
|
|
<Check size={16} />
|
|
Speichern
|
|
</button>
|
|
<button
|
|
onClick={onCancel}
|
|
className="flex items-center gap-1 px-3 py-1.5 bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 text-sm"
|
|
>
|
|
<X size={16} />
|
|
Abbrechen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |