initial
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user