Gowrisankar
Remove project schedule dates from UI and tie effort to allocations.
489aea9
import { useState, type FormEvent, type ReactNode } from "react";
import { Drawer } from "../ui/Drawer";
import type { ProjectInput, Team } from "../../types";
const PROJECT_COLORS = ["#0ea5e9", "#16a34a", "#f97316", "#a855f7", "#facc15", "#ef4444", "#0f766e"];
const LIFECYCLE_STATUSES = [
{ value: "planning", label: "Planning" },
{ value: "active", label: "Active" },
{ value: "on_hold", label: "On hold" },
{ value: "completed", label: "Completed" },
] as const;
interface ProjectDrawerProps {
open: boolean;
editingId: number | null;
form: ProjectInput;
setForm: (next: ProjectInput) => void;
teams: Team[];
onClose: () => void;
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
isSaving: boolean;
footerExtras?: ReactNode;
}
export function ProjectDrawer({
open,
editingId,
form,
setForm,
teams,
onClose,
onSubmit,
isSaving,
footerExtras,
}: ProjectDrawerProps) {
const [tab, setTab] = useState<"details" | "notes">("details");
const title = editingId ? `Edit ${form.name || "project"}` : "New project";
return (
<Drawer
open={open}
onClose={onClose}
title={title}
icon={<span className="project-swatch drawer-project-swatch" style={{ background: form.color }} />}
tabs={
<>
<button
className={`drawer-tab ${tab === "details" ? "active" : ""}`}
onClick={() => setTab("details")}
type="button"
>
Details
</button>
<button
className={`drawer-tab ${tab === "notes" ? "active" : ""}`}
onClick={() => setTab("notes")}
type="button"
>
Notes
</button>
</>
}
footer={
<>
{footerExtras}
<span className="drawer-footer-spacer" />
<button className="secondary-button" onClick={onClose} type="button">
Cancel
</button>
<button className="primary-button" disabled={isSaving} form="project-drawer-form" type="submit">
Save
</button>
</>
}
>
<form className="drawer-form" id="project-drawer-form" onSubmit={onSubmit}>
{tab === "details" ? (
<>
<label>
Project Name
<input
onChange={(event) => setForm({ ...form, name: event.target.value })}
required
type="text"
value={form.name}
/>
</label>
<label>
Status
<select
onChange={(event) => setForm({ ...form, is_tentative: event.target.value === "tentative" })}
value={form.is_tentative ? "tentative" : "confirmed"}
>
<option value="confirmed">Confirmed</option>
<option value="tentative">Tentative</option>
</select>
</label>
<label>
Primary Team <small>(optional)</small>
<select
onChange={(event) =>
setForm({ ...form, team_id: event.target.value ? Number(event.target.value) : null })
}
value={form.team_id ?? ""}
>
<option value="">No team</option>
{teams.map((team) => (
<option key={team.id} value={team.id}>
{team.name}
</option>
))}
</select>
</label>
<label>
Lifecycle <small>(internal)</small>
<select onChange={(event) => setForm({ ...form, status: event.target.value })} value={form.status}>
{LIFECYCLE_STATUSES.map((status) => (
<option key={status.value} value={status.value}>
{status.label}
</option>
))}
</select>
</label>
<label>
Project type
<select onChange={(event) => setForm({ ...form, type: event.target.value })} value={form.type}>
<option value="infrastructure">Infrastructure</option>
<option value="development">Development</option>
<option value="support">Support</option>
<option value="other">Other</option>
</select>
</label>
<label>
Color
<div className="color-picker">
{PROJECT_COLORS.map((color) => (
<button
aria-label={`Use color ${color}`}
className={`color-swatch ${form.color === color ? "selected" : ""}`}
key={color}
onClick={() => setForm({ ...form, color })}
style={{ background: color }}
type="button"
/>
))}
</div>
</label>
</>
) : null}
{tab === "notes" ? (
<label>
Notes
<textarea
onChange={(event) => setForm({ ...form, description: event.target.value })}
placeholder="Project notes and context"
rows={8}
value={form.description ?? ""}
/>
</label>
) : null}
</form>
</Drawer>
);
}