From 17907f00528d50578245cd153027ce73edcadfdc Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Sun, 2 Aug 2026 18:00:43 +0000 Subject: [PATCH] feat(CC-090): add Pitch Builder page (7-section pitch form, startup/grant templates, TXT export) --- src/app/dashboard/pitch/page.tsx | 134 +++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/app/dashboard/pitch/page.tsx diff --git a/src/app/dashboard/pitch/page.tsx b/src/app/dashboard/pitch/page.tsx new file mode 100644 index 0000000..600c2ac --- /dev/null +++ b/src/app/dashboard/pitch/page.tsx @@ -0,0 +1,134 @@ +'use client'; + +import { useState } from 'react'; +import { useSession } from '../../../components/session-provider'; + +interface PitchSection { id: string; label: string; placeholder: string; hint: string; } + +const SECTIONS: PitchSection[] = [ + { id: 'problem', label: '1. Problema', placeholder: 'Ce problemă reală rezolvi?', hint: 'Specific, cuantificabil, cu cine se confruntă' }, + { id: 'solution', label: '2. Soluția', placeholder: 'Cum o rezolvi?', hint: 'Propunerea ta de valoare în 2 propoziții' }, + { id: 'market', label: '3. Piața', placeholder: 'Cât de mare e piața? TAM / SAM / SOM', hint: 'Date concrete, surse credibile' }, + { id: 'traction', label: '4. Tracțiune', placeholder: 'Ce ai demonstrat deja?', hint: 'Clienți, venituri, utilizatori, partnership-uri' }, + { id: 'model', label: '5. Model de business',placeholder: 'Cum faci bani?', hint: 'Prețuri, canale, unit economics' }, + { id: 'team', label: '6. Echipa', placeholder: 'De ce voi sunteți cei potriviți?', hint: 'Experiență relevantă, unfair advantage' }, + { id: 'ask', label: '7. Cererea (Ask)', placeholder: 'Ce cauți? Investiție, parteneriat, pilot?', hint: 'Sumă / termen / use of funds' }, +]; + +const TEMPLATES: Record>> = { + startup: { + problem: '', + solution: '', + market: 'TAM: €_M | SAM: €_M | SOM: €_M (an 1)', + traction: '', + model: 'SaaS - €_ / lună per utilizator. ARR țintă: €_M', + ask: 'Runda seed: €_ pentru 18 luni runway', + }, + grant: { + problem: '', + solution: '', + market: 'Beneficiari direcți: _ persoane. Impact regional / național.', + traction: '', + model: 'Grant nerambursabil. Cofinanțare: _%. Durată proiect: _ luni.', + ask: 'Suma solicitată: €_ din programul _', + }, +}; + +export default function PitchPage() { + const { activeTenant } = useSession(); + const [sections, setSections] = useState>({}); + const [pitchName, setPitchName] = useState(''); + const [template, setTemplate] = useState('blank'); + const [exported, setExported] = useState(false); + + function applyTemplate(t: string) { + setTemplate(t); + if (t !== 'blank') setSections((p) => ({ ...p, ...TEMPLATES[t] })); + } + + function wordCount(s: string) { return s.trim().split(/\s+/).filter(Boolean).length; } + const totalWords = Object.values(sections).reduce((sum, s) => sum + wordCount(s), 0); + const filledSections = SECTIONS.filter((s) => (sections[s.id] ?? '').trim().length > 0).length; + + function exportPitch() { + const lines = [ + `PITCH: ${pitchName || 'Fără titlu'}`, + `Generat: ${new Date().toLocaleDateString('ro-RO')}`, + '', + ...SECTIONS.map((s) => [ + `## ${s.label}`, + sections[s.id]?.trim() || '(necompletat)', + '', + ]).flat(), + ]; + const blob = new Blob([lines.join('\n')], { type: 'text/plain;charset=utf-8' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `pitch-${(pitchName || 'ceo-os').replace(/\s+/g, '-').toLowerCase()}.txt`; + a.click(); + URL.revokeObjectURL(url); + setExported(true); + setTimeout(() => setExported(false), 3000); + } + + return ( +
+
+
+

Pitch Builder

+

{filledSections}/{SECTIONS.length} secțiuni · {totalWords} cuvinte

+
+ +
+ + {/* Meta */} +
+ setPitchName(e.target.value)} + className="w-full rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+

Template:

+ {(['blank', 'startup', 'grant'] as const).map((t) => ( + + ))} +
+
+ + {/* Progress bar */} +
+
+
+ + {/* Sections */} +
+ {SECTIONS.map((s) => { + const val = sections[s.id] ?? ''; + const wc = wordCount(val); + return ( +
+
+ + {wc} cuvinte +
+

{s.hint}

+