feat(34-02): extract hardcoded strings from thread/candidate components
- CandidateCard: replace all hardcoded titles and badge text with t() - CandidateListItem: add useTranslation, replace winner/delete/open labels and +/- Notes badge - CandidateForm: add useTranslation, replace all form labels, placeholders, validation errors, submit button - ComparisonTable: move STATUS_LABELS inside component with t(), replace all ATTRIBUTE_ROWS labels, View button, impact row labels - StatusBadge: refactor STATUS_CONFIG to STATUS_ICONS + runtime STATUS_LABELS via t() - CreateThreadModal: replace title, thread name label, category label, placeholder, cancel/submit buttons, error messages - AddToThreadModal: replace modal titles, labels, placeholders, back/cancel/submit buttons, error messages - threads.json: extend candidateForm with category, notes, pros, cons, product link labels and all placeholders
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useFormatters } from "../hooks/useFormatters";
|
||||
import type { CandidateDelta } from "../hooks/useImpactDeltas";
|
||||
import { LucideIcon } from "../lib/iconData";
|
||||
@@ -55,6 +56,7 @@ export function CandidateCard({
|
||||
rank,
|
||||
delta,
|
||||
}: CandidateCardProps) {
|
||||
const { t } = useTranslation("threads");
|
||||
const { weight, price } = useFormatters();
|
||||
const navigate = useNavigate();
|
||||
const openConfirmDeleteCandidate = useUIStore(
|
||||
@@ -90,10 +92,10 @@ export function CandidateCard({
|
||||
}
|
||||
}}
|
||||
className="absolute top-2 left-2 z-10 px-2 py-0.5 flex items-center gap-1 rounded-full text-xs font-medium bg-amber-100/90 text-amber-700 hover:bg-amber-200 opacity-0 group-hover:opacity-100 transition-all cursor-pointer"
|
||||
title="Pick as winner"
|
||||
title={t("candidateCard.pickAsWinner")}
|
||||
>
|
||||
<LucideIcon name="trophy" size={12} />
|
||||
Winner
|
||||
{t("candidateCard.winner")}
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
@@ -110,7 +112,7 @@ export function CandidateCard({
|
||||
}
|
||||
}}
|
||||
className={`absolute top-2 ${productUrl ? "right-10" : "right-2"} z-10 w-6 h-6 flex items-center justify-center rounded-full bg-gray-100/80 text-gray-400 hover:bg-red-100 hover:text-red-500 opacity-0 group-hover:opacity-100 transition-all cursor-pointer`}
|
||||
title="Delete candidate"
|
||||
title={t("candidateCard.deleteCandidate")}
|
||||
>
|
||||
<svg
|
||||
className="w-3.5 h-3.5"
|
||||
@@ -141,7 +143,7 @@ export function CandidateCard({
|
||||
}
|
||||
}}
|
||||
className="absolute top-2 right-2 z-10 w-6 h-6 flex items-center justify-center rounded-full bg-gray-100/80 text-gray-400 hover:bg-gray-200 hover:text-gray-600 opacity-0 group-hover:opacity-100 transition-all cursor-pointer"
|
||||
title="Open product link"
|
||||
title={t("candidateCard.openProductLink")}
|
||||
>
|
||||
<svg
|
||||
className="w-3.5 h-3.5"
|
||||
@@ -214,7 +216,7 @@ export function CandidateCard({
|
||||
<StatusBadge status={status} onStatusChange={onStatusChange} />
|
||||
{(pros || cons) && (
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-purple-50 text-purple-700">
|
||||
+/- Notes
|
||||
{t("candidateCard.prosCons")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user