From d62f865f2f09c52febc0ce9738215a047075a8cf Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 11:07:07 +0000 Subject: [PATCH] feat: Add Instagram as a lead capture option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Instagram to VALID_LEAD_TYPES in backend API - Update /api/stats endpoint to track Instagram leads - Add Instagram button (📸) to lead capture flow in UI - Add Instagram option to lead type dropdown in edit form - Update lead icon display logic and detail views - Add Instagram to stats dashboard display - Update database schema documentation - Add migration script for database constraint Closes #5 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Rolfboy --- PRD.md | 4 ++-- api/main.py | 9 +++++++-- migrations/006_add_instagram_lead_type.sql | 9 +++++++++ web/src/App.jsx | 15 ++++++++++++--- 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 migrations/006_add_instagram_lead_type.sql diff --git a/PRD.md b/PRD.md index d5941cf..e034d10 100644 --- a/PRD.md +++ b/PRD.md @@ -404,8 +404,8 @@ CREATE TABLE interactions ( total_amount INTEGER, -- Lead capture - lead_type VARCHAR(20) - CHECK (lead_type IN ('line', 'email', 'none')), + lead_type VARCHAR(20) + CHECK (lead_type IN ('line', 'email', 'instagram', 'none')), -- Objection (only if sale_type = 'none') objection VARCHAR(50) diff --git a/api/main.py b/api/main.py index 2e2de28..cd8c535 100644 --- a/api/main.py +++ b/api/main.py @@ -26,7 +26,7 @@ VALID_PERSONAS = {"parent", "gift_buyer", "expat", "future_parent"} VALID_HOOKS = {"physical_kits", "big_garden", "signage"} VALID_SALE_TYPES = {"none", "single", "bundle_3", "full_year"} -VALID_LEAD_TYPES = {"line", "email"} +VALID_LEAD_TYPES = {"line", "email", "instagram"} VALID_OBJECTIONS = { "too_expensive", "not_interested", "no_time", "already_have", "need_to_think", "language_barrier", "other" @@ -387,6 +387,10 @@ async def get_stats(period: str = "today"): "SELECT COUNT(*) FROM interactions WHERE timestamp >= $1 AND lead_type = 'email' AND deleted_at IS NULL", start_date ) + instagram_leads = await conn.fetchval( + "SELECT COUNT(*) FROM interactions WHERE timestamp >= $1 AND lead_type = 'instagram' AND deleted_at IS NULL", + start_date + ) return { "period": period, @@ -409,7 +413,8 @@ async def get_stats(period: str = "today"): "objections": {row["objection"]: row["count"] for row in objections}, "leads": { "line": line_leads or 0, - "email": email_leads or 0 + "email": email_leads or 0, + "instagram": instagram_leads or 0 } } diff --git a/migrations/006_add_instagram_lead_type.sql b/migrations/006_add_instagram_lead_type.sql new file mode 100644 index 0000000..bd319d7 --- /dev/null +++ b/migrations/006_add_instagram_lead_type.sql @@ -0,0 +1,9 @@ +-- Migration: Add Instagram to lead_type options +-- Description: Adds 'instagram' as a valid option for lead_type field + +-- Drop the existing constraint if it exists +ALTER TABLE interactions DROP CONSTRAINT IF EXISTS interactions_lead_type_check; + +-- Add the new constraint with instagram included +ALTER TABLE interactions ADD CONSTRAINT interactions_lead_type_check + CHECK (lead_type IN ('line', 'email', 'instagram', 'none') OR lead_type IS NULL); diff --git a/web/src/App.jsx b/web/src/App.jsx index 0faf27d..1773a47 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -1016,6 +1016,10 @@ function StatsScreen({ stats, statsPeriod, onPeriodChange, sellerStats, sankeyDa 📧 Email {data?.leads?.email || 0} +
+ 📸 Instagram + {data?.leads?.instagram || 0} +
{/* Phase 2 Navigation Buttons */} @@ -1152,7 +1156,7 @@ function InteractionCard({ item, onClick }) { const personaLabel = item.persona ? item.persona.replace('_', ' ') : '' const hookIcon = item.hook === 'physical_kits' ? '📦' : item.hook === 'big_garden' ? '📱' : '🪧' - const leadIcon = item.lead_type === 'line' ? '💚' : item.lead_type === 'email' ? '📧' : '' + const leadIcon = item.lead_type === 'line' ? '💚' : item.lead_type === 'email' ? '📧' : item.lead_type === 'instagram' ? '📸' : '' return (
@@ -1233,7 +1237,7 @@ function DetailScreen({ interaction, onBack, onAddNote, onDelete, onEdit }) { )}
Lead - {i.lead_type === 'line' ? '💚 LINE' : i.lead_type === 'email' ? '📧 Email' : 'None'} + {i.lead_type === 'line' ? '💚 LINE' : i.lead_type === 'email' ? '📧 Email' : i.lead_type === 'instagram' ? '📸 Instagram' : 'None'}
{i.objection && (
@@ -2014,6 +2018,10 @@ function FlowLead({ onSelect, onBack }) { 📧 Email +