// UC-A3 Pubblica Richiesta — Single-page form // Sections: Tipo di servizio, Brief (con AI assist), Allegati, Budget, Deadline, Visibilità const PR_Icons = window.SonaraIcons; const { useState: useStatePR, useRef: useRefPR } = React; const SERVICE_TYPES = [ { id: "beat", label: "Beat", sub: "Strumentale pronta o custom", icon: , popular: true }, { id: "mix", label: "Mix", sub: "Bilancia, EQ, dinamica", icon: , popular: true }, { id: "master", label: "Master", sub: "Loudness e finitura per release", icon: }, { id: "vocal", label: "Vocal prod", sub: "Tuning, doubles, comping", icon: }, { id: "ep", label: "Producer per EP", sub: "Direzione artistica completa", icon: }, { id: "manager", label: "Manager", sub: "Rappresentanza e A&R", icon: }, { id: "other", label: "Altro", sub: "Specifica nel brief", icon: }, ]; const BRIEF_TEMPLATES = { beat: "Sto cercando una base trap dark, 140 BPM circa, 808 sporche e atmosfera notturna. Riferimenti: Travis Scott, Sfera Ebbasta — Tran Tran. Mi serve per un singolo da pubblicare a marzo. Voce maschile baritonale.", mix: "Ho 12 stems di un brano indie-pop, voce + chitarra acustica + basso + batteria + synth. Cerco un mix caldo, vintage, con la voce davanti. Riferimenti: Phoebe Bridgers, Iosonouncane.", master: "Ho il mix finale di un singolo elettronico, lunghezza 3:42. Vorrei un master loud ma non spinto, con dinamica preservata. Target: streaming Spotify e vinile. Riferimenti: Bicep, Floating Points.", vocal: "Cerco vocal producer per un brano pop in italiano. Ho la voce lead già registrata, mi servono cori, doubles, ad-libs e tuning naturale. Stile riferimento: Sangiovanni, Rkomi.", ep: "Sto preparando un EP di 5 brani indie-elettronico. Cerco un producer che mi accompagni dall'arrangiamento al master. Ho già le demo in voce-piano. Tempi: 3 mesi. Budget complessivo da definire.", manager: "Sono un'artista emergente con 80k stream mensili e una release ogni 2 mesi. Cerco un manager che mi supporti su strategia release, booking live e contatti label. Vivo a Milano.", other: "", }; const BUDGET_PRESETS = [ { id: "p1", label: "€50–150", min: 50, max: 150 }, { id: "p2", label: "€150–400", min: 150, max: 400 }, { id: "p3", label: "€400–800", min: 400, max: 800 }, { id: "p4", label: "€800+", min: 800, max: 2000 }, { id: "open", label: "Decideremo insieme", min: null, max: null }, ]; const DEADLINE_PRESETS = [ { id: "d1", label: "Entro 1 settimana", days: 7 }, { id: "d2", label: "Entro 2 settimane", days: 14 }, { id: "d3", label: "Entro 1 mese", days: 30 }, { id: "flex", label: "Flessibile", days: null }, ]; function PubblicaRichiestaPage() { const [serviceType, setServiceType] = useStatePR(null); const [brief, setBrief] = useStatePR(""); const [aiOpen, setAiOpen] = useStatePR(false); const [aiLoading, setAiLoading] = useStatePR(false); const [aiError, setAiError] = useStatePR(null); const [aiSuggestion, setAiSuggestion] = useStatePR(null); const [files, setFiles] = useStatePR([]); const [budget, setBudget] = useStatePR("p2"); const [budgetMin, setBudgetMin] = useStatePR(150); const [budgetMax, setBudgetMax] = useStatePR(400); const [deadline, setDeadline] = useStatePR("d2"); const [deadlineDate, setDeadlineDate] = useStatePR(""); const [visibility, setVisibility] = useStatePR("public"); const [submitted, setSubmitted] = useStatePR(false); const fileRef = useRefPR(null); // Validation const briefMin = 40; const briefValid = brief.trim().length >= briefMin; const canSubmit = serviceType && briefValid; const briefPct = Math.min(100, Math.round((brief.length / 400) * 100)); const tooShort = brief.length > 0 && brief.length < briefMin; // Handlers const onFiles = (filelist) => { const arr = Array.from(filelist || []).map(f => ({ id: Math.random().toString(36).slice(2), name: f.name, size: f.size, type: guessType(f), })); setFiles(prev => [...prev, ...arr].slice(0, 5)); }; const askAI = async () => { if (!serviceType) return; setAiOpen(true); setAiLoading(true); setAiError(null); setAiSuggestion(null); const promptCtx = SERVICE_TYPES.find(s => s.id === serviceType); const userBrief = brief.trim(); try { const prompt = `Sei un assistente che aiuta artisti italiani a scrivere un brief chiaro per pubblicare una richiesta su SONARA, una piattaforma per producer musicali. L'artista cerca: ${promptCtx.label} (${promptCtx.sub}). ${userBrief ? `Bozza dell'artista:\n"${userBrief}"\n\nRiscrivi e completa questo brief` : "L'artista non ha ancora scritto nulla. Scrivi un esempio di brief"}, in italiano, max 500 caratteri, includendo: cosa cerca esattamente, riferimenti artistici (1-2), mood/atmosfera, eventuale BPM o tonalità, contesto d'uso (singolo, EP, demo). Tono: diretto, da musicista a musicista. Niente formattazione markdown, niente intestazioni. Solo testo continuo. Inizia direttamente col contenuto.`; const text = await window.claude.complete(prompt); setAiSuggestion(text.trim()); } catch (e) { setAiError("Impossibile generare un suggerimento ora. Riprova tra poco."); } finally { setAiLoading(false); } }; const acceptAI = () => { if (aiSuggestion) setBrief(aiSuggestion); setAiOpen(false); setAiSuggestion(null); }; const onSubmit = (e) => { e.preventDefault(); if (!canSubmit) return; setSubmitted(true); window.scrollTo({ top: 0, behavior: "smooth" }); }; if (submitted) { return { setSubmitted(false); setServiceType(null); setBrief(""); setFiles([]); setBudget("p2"); setDeadline("d2"); }} type={SERVICE_TYPES.find(s => s.id === serviceType)?.label} />; } const selSvc = SERVICE_TYPES.find(s => s.id === serviceType); const selBudg = BUDGET_PRESETS.find(b => b.id === budget); const selDdln = DEADLINE_PRESETS.find(d => d.id === deadline); return (
Dashboard

Pubblica una richiesta

Descrivi cosa cerchi — i producer in linea col tuo profilo ti faranno un'offerta. Hai 2 richieste su 3 attive. e.preventDefault()}>Come funziona →

2 / 3 attive
{/* ============== Tipo di servizio ============== */}
{SERVICE_TYPES.map(s => ( ))}
{/* ============== Brief ============== */}