Files
Codewalkers/packages/web/src/components/CreateInitiativeDialog.tsx
2026-02-07 00:33:12 +01:00

112 lines
3.1 KiB
TypeScript

import { useEffect, useState } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { toast } from "sonner";
import { trpc } from "@/lib/trpc";
import { ProjectPicker } from "./ProjectPicker";
interface CreateInitiativeDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function CreateInitiativeDialog({
open,
onOpenChange,
}: CreateInitiativeDialogProps) {
const [name, setName] = useState("");
const [projectIds, setProjectIds] = useState<string[]>([]);
const [error, setError] = useState<string | null>(null);
const utils = trpc.useUtils();
const createMutation = trpc.createInitiative.useMutation({
onSuccess: () => {
utils.listInitiatives.invalidate();
onOpenChange(false);
toast.success("Initiative created");
},
onError: (err) => {
setError(err.message);
},
});
// Reset form when dialog opens
useEffect(() => {
if (open) {
setName("");
setProjectIds([]);
setError(null);
}
}, [open]);
function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError(null);
createMutation.mutate({
name: name.trim(),
projectIds: projectIds.length > 0 ? projectIds : undefined,
});
}
const canSubmit = name.trim().length > 0 && !createMutation.isPending;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>Create Initiative</DialogTitle>
<DialogDescription>
Create a new initiative to plan and execute work.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="initiative-name">Name</Label>
<Input
id="initiative-name"
placeholder="e.g. User Authentication"
value={name}
onChange={(e) => setName(e.target.value)}
autoFocus
/>
</div>
<div className="space-y-2">
<Label>
Projects{" "}
<span className="text-muted-foreground font-normal">
(optional)
</span>
</Label>
<ProjectPicker value={projectIds} onChange={setProjectIds} />
</div>
{error && (
<p className="text-sm text-destructive">{error}</p>
)}
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
>
Cancel
</Button>
<Button type="submit" disabled={!canSubmit}>
{createMutation.isPending ? "Creating..." : "Create"}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}