diff --git a/messages/en.json b/messages/en.json
index ad35618..85fee41 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -445,5 +445,118 @@
"toastDeleteFailed": "Could not delete field.",
"toastDeleted": "Deleted \"{name}\"."
}
+ },
+ "Pipelines": {
+ "page": {
+ "selectPipeline": "Select Pipeline",
+ "noPipelinesYet": "No pipelines yet",
+ "managePipelines": "Manage Pipelines",
+ "addPipeline": "Add Pipeline",
+ "addDeal": "Add Deal",
+ "createToStartTracking": "Create a pipeline to start tracking deals",
+ "createPipeline": "Create Pipeline",
+ "newPipeline": "New Pipeline",
+ "pipelineName": "Pipeline Name",
+ "pipelineNamePlaceholder": "e.g., Enterprise Sales",
+ "defaultStagesDesc": "Default stages (New Lead → Won) will be created automatically.",
+ "cancel": "Cancel",
+ "creating": "Creating...",
+ "createPipelineBtn": "Create Pipeline",
+ "toastFailedLoadPipelines": "Failed to load pipelines",
+ "toastFailedMoveDeal": "Failed to move deal",
+ "toastFailedCreatePipeline": "Failed to create pipeline",
+ "toastPipelineCreated": "Pipeline created",
+ "toastNotLinkedToAccount": "Your profile is not linked to an account."
+ },
+ "board": {
+ "dropDealHere": "Drop a deal here",
+ "addDeal": "Add Deal"
+ },
+ "card": {
+ "noContact": "No contact",
+ "won": "Won",
+ "lost": "Lost"
+ },
+ "form": {
+ "editDeal": "Edit Deal",
+ "newDeal": "New Deal",
+ "title": "Title",
+ "titlePlaceholder": "Deal title",
+ "contact": "Contact",
+ "selectContact": "Select a contact",
+ "linkToConversation": "Link to Conversation",
+ "value": "Value",
+ "currency": "Currency",
+ "expectedCloseDate": "Expected Close Date",
+ "stage": "Stage",
+ "assignedTo": "Assigned To",
+ "unassigned": "Unassigned",
+ "notes": "Notes",
+ "notesPlaceholder": "Add notes...",
+ "status": "Status",
+ "markAsWon": "Mark as Won",
+ "markAsLost": "Mark as Lost",
+ "reopenDeal": "Reopen deal",
+ "cancel": "Cancel",
+ "saving": "Saving...",
+ "saveChanges": "Save Changes",
+ "createDeal": "Create Deal",
+ "deletePrompt": "Delete this deal?",
+ "confirm": "Confirm",
+ "deleting": "Deleting...",
+ "deleteDeal": "Delete Deal",
+ "toastRequired": "Title, contact, and stage are required",
+ "toastFailedSave": "Failed to save deal",
+ "toastNotSignedIn": "Not signed in",
+ "toastNotLinked": "Your profile is not linked to an account.",
+ "toastFailedCreate": "Failed to create deal",
+ "toastUpdated": "Deal updated",
+ "toastCreated": "Deal created",
+ "toastFailedStatus": "Failed to update deal status",
+ "toastMarkedWon": "Marked as won",
+ "toastMarkedLost": "Marked as lost",
+ "toastReopened": "Deal reopened",
+ "toastFailedDelete": "Failed to delete deal",
+ "toastDeleted": "Deal deleted"
+ },
+ "settings": {
+ "managePipeline": "Manage Pipeline",
+ "deletePipeline": "Delete Pipeline",
+ "deletePipelineDesc": "This will archive all deals in this pipeline. This cannot be undone.",
+ "cancel": "Cancel",
+ "deleting": "Deleting...",
+ "deletePipelineBtn": "Delete Pipeline",
+ "pipelineName": "Pipeline Name",
+ "stages": "Stages",
+ "newStageNamePlaceholder": "New stage name",
+ "add": "Add",
+ "createNewPipeline": "Create a new pipeline",
+ "saving": "Saving...",
+ "saveChanges": "Save Changes",
+ "dragToReorder": "Drag to reorder",
+ "changeColor": "Change color",
+ "toastFailedSave": "Failed to save pipeline",
+ "toastSaved": "Pipeline saved",
+ "toastFailedAddStage": "Failed to add stage",
+ "toastMoveOrDeleteDeals": "Move or delete deals in this stage first",
+ "toastFailedDeleteStage": "Failed to delete stage",
+ "toastFailedDeletePipeline": "Failed to delete pipeline",
+ "toastDeleted": "Pipeline deleted"
+ },
+ "analytics": {
+ "totalDeals": "Total Deals",
+ "totalDealsTooltip": "Count of every deal in this pipeline that isn't marked as Lost. Won deals are still included.",
+ "pipelineValue": "Pipeline Value",
+ "pipelineValueTooltip": "Sum of the dollar values of all deals in this pipeline, excluding deals marked as Lost.",
+ "avgDealSize": "Avg Deal Size",
+ "avgDealSizeTooltip": "Pipeline Value divided by Total Deals — the average value of a single non-lost deal.",
+ "weightedValue": "Weighted Value",
+ "weightedValueTooltip": "Expected revenue: each open deal's value × its stage probability. First stage ≈ 10%, stages progress up to 90%, Won = 100%. Lost deals are excluded.",
+ "wonThisMonth": "Won This Month",
+ "wonThisMonthTooltip": "Deals marked as Won since the first day of the current month.",
+ "lostThisMonth": "Lost This Month",
+ "lostThisMonthTooltip": "Deals marked as Lost since the first day of the current month.",
+ "howCalculated": "How {label} is calculated"
+ }
}
}
diff --git a/src/app/(dashboard)/pipelines/page.tsx b/src/app/(dashboard)/pipelines/page.tsx
index b7292df..fff6f98 100644
--- a/src/app/(dashboard)/pipelines/page.tsx
+++ b/src/app/(dashboard)/pipelines/page.tsx
@@ -29,6 +29,7 @@ import { toast } from "sonner";
import { useCan } from "@/hooks/use-can";
import { useAuth } from "@/hooks/use-auth";
import { GatedButton } from "@/components/ui/gated-button";
+import { useTranslations } from "next-intl";
// Pipeline creation is admin-class (settings-tier write under
// the new RLS); deal creation is operational and only requires
@@ -45,6 +46,7 @@ const SPEC_DEFAULT_STAGES = [
];
export default function PipelinesPage() {
+ const t = useTranslations("Pipelines.page");
const supabase = createClient();
const canEditSettings = useCan("edit-settings");
const canCreateDeals = useCan("send-messages");
@@ -223,11 +225,11 @@ export default function PipelinesPage() {
.update({ stage_id: newStageId })
.eq("id", dealId);
if (error) {
- toast.error("Failed to move deal");
+ toast.error(t("toastFailedMoveDeal"));
refreshDeals();
}
},
- [supabase, refreshDeals],
+ [supabase, refreshDeals, t],
);
const handleAddDeal = useCallback(
@@ -260,7 +262,7 @@ export default function PipelinesPage() {
}
// pipelines.account_id is NOT NULL post-017 with no DB default.
if (!accountId) {
- toast.error("Your profile is not linked to an account.");
+ toast.error(t("toastNotLinkedToAccount"));
setCreating(false);
return;
}
@@ -272,7 +274,7 @@ export default function PipelinesPage() {
.single();
if (error || !pipeline) {
- toast.error("Failed to create pipeline");
+ toast.error(t("toastFailedCreatePipeline"));
setCreating(false);
return;
}
@@ -290,7 +292,7 @@ export default function PipelinesPage() {
setSelectedPipelineId(pipeline.id);
await refreshPipelines();
setCreating(false);
- toast.success("Pipeline created");
+ toast.success(t("toastPipelineCreated"));
}
const selectedPipeline = pipelines.find((p) => p.id === selectedPipelineId);
@@ -323,7 +325,7 @@ export default function PipelinesPage() {
>
- {selectedPipeline?.name ?? "Select Pipeline"}
+ {selectedPipeline?.name ?? t("selectPipeline")}
@@ -333,7 +335,7 @@ export default function PipelinesPage() {
>
{pipelines.length === 0 && (
- No pipelines yet
+ {t("noPipelinesYet")}
)}
{pipelines.map((p) => (
@@ -357,7 +359,7 @@ export default function PipelinesPage() {
className="text-popover-foreground"
>
- Manage Pipelines
+ {t("managePipelines")}
)}
@@ -373,7 +375,7 @@ export default function PipelinesPage() {
className="border-border bg-card text-foreground hover:bg-muted"
>
- Add Pipeline
+ {t("addPipeline")}
- Add Deal
+ {t("addDeal")}
@@ -393,10 +395,10 @@ export default function PipelinesPage() {
- No pipelines yet
+ {t("noPipelinesYet")}
- Create a pipeline to start tracking deals
+ {t("createToStartTracking")}
- Create Pipeline
+ {t("createPipeline")}
) : (
@@ -425,21 +427,21 @@ export default function PipelinesPage() {