feat(10-01): wire pros/cons through client hooks, form, and card indicator

- CandidateResponse: add pros/cons string|null fields
- CandidateForm: add pros/cons to FormData, INITIAL_FORM, pre-fill, payload
- CandidateForm: add Pros/Cons textarea inputs (after Notes, before Product Link)
- CandidateCard: add pros/cons props, render purple +/- Notes badge when present
- Thread detail route: pass pros/cons props to CandidateCard
This commit is contained in:
2026-03-16 21:36:10 +01:00
parent 7a64a1887d
commit 4f2aefe7a4
4 changed files with 57 additions and 0 deletions

View File

@@ -19,6 +19,8 @@ interface FormData {
notes: string;
productUrl: string;
imageFilename: string | null;
pros: string;
cons: string;
}
const INITIAL_FORM: FormData = {
@@ -29,6 +31,8 @@ const INITIAL_FORM: FormData = {
notes: "",
productUrl: "",
imageFilename: null,
pros: "",
cons: "",
};
export function CandidateForm({
@@ -61,6 +65,8 @@ export function CandidateForm({
notes: candidate.notes ?? "",
productUrl: candidate.productUrl ?? "",
imageFilename: candidate.imageFilename,
pros: candidate.pros ?? "",
cons: candidate.cons ?? "",
});
}
} else if (mode === "add") {
@@ -110,6 +116,8 @@ export function CandidateForm({
notes: form.notes.trim() || undefined,
productUrl: form.productUrl.trim() || undefined,
imageFilename: form.imageFilename ?? undefined,
pros: form.pros.trim() || undefined,
cons: form.cons.trim() || undefined,
};
if (mode === "add") {
@@ -239,6 +247,42 @@ export function CandidateForm({
/>
</div>
{/* Pros */}
<div>
<label
htmlFor="candidate-pros"
className="block text-sm font-medium text-gray-700 mb-1"
>
Pros
</label>
<textarea
id="candidate-pros"
value={form.pros}
onChange={(e) => setForm((f) => ({ ...f, pros: e.target.value }))}
rows={3}
className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent resize-none"
placeholder="One pro per line..."
/>
</div>
{/* Cons */}
<div>
<label
htmlFor="candidate-cons"
className="block text-sm font-medium text-gray-700 mb-1"
>
Cons
</label>
<textarea
id="candidate-cons"
value={form.cons}
onChange={(e) => setForm((f) => ({ ...f, cons: e.target.value }))}
rows={3}
className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-400 focus:border-transparent resize-none"
placeholder="One con per line..."
/>
</div>
{/* Product Link */}
<div>
<label