This commit is contained in:
2026-07-02 22:13:33 +02:00
parent b343ad8a38
commit ba6c35f76d
30 changed files with 2752 additions and 2 deletions
+94
View File
@@ -0,0 +1,94 @@
import React, { useState } from "react";
import { api } from "../api";
const PALETTE = ["#3E5C50", "#2F6F4F", "#8A6D3B", "#4C5B7A", "#A63B2A", "#C4622D"];
export default function ProjectForm({ project, onClose, onSaved }) {
const [name, setName] = useState(project?.name || "");
const [description, setDescription] = useState(project?.description || "");
const [color, setColor] = useState(project?.color || PALETTE[0]);
const [error, setError] = useState(null);
const [saving, setSaving] = useState(false);
async function submit(e) {
e.preventDefault();
setError(null);
if (!name.trim()) {
setError("Bitte einen Projektnamen eingeben.");
return;
}
setSaving(true);
try {
const payload = { name, description, color };
if (project) {
await api.projects.update(project.id, payload);
} else {
await api.projects.create(payload);
}
onSaved();
} catch (err) {
setError(err.message);
} finally {
setSaving(false);
}
}
return (
<div className="form-modal-backdrop" onMouseDown={onClose}>
<div className="form-modal" onMouseDown={(e) => e.stopPropagation()}>
<h3>{project ? "Projekt bearbeiten" : "Projekt anlegen"}</h3>
<form onSubmit={submit}>
<div className="field">
<label htmlFor="pr-name">Projektname</label>
<input
id="pr-name"
value={name}
onChange={(e) => setName(e.target.value)}
autoFocus
/>
</div>
<div className="field">
<label htmlFor="pr-desc">Beschreibung (optional)</label>
<textarea
id="pr-desc"
rows={2}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</div>
<div className="field">
<label>Farbe</label>
<div style={{ display: "flex", gap: 8 }}>
{PALETTE.map((c) => (
<button
type="button"
key={c}
onClick={() => setColor(c)}
aria-label={`Farbe ${c} waehlen`}
style={{
width: 24,
height: 24,
borderRadius: "50%",
background: c,
border:
color === c ? "2px solid var(--ink)" : "2px solid transparent",
cursor: "pointer"
}}
/>
))}
</div>
</div>
{error && <p className="error-text">{error}</p>}
<div className="form-actions">
<button type="button" className="btn" onClick={onClose}>
Abbrechen
</button>
<button type="submit" className="btn btn-primary" disabled={saving}>
{saving ? "Speichert..." : "Speichern"}
</button>
</div>
</form>
</div>
</div>
);
}