// SONARA — Messaggi page (artista) const MIcons = window.SonaraIcons; // ============= DATA ============= const CHATS_DATA = [ { id: "c1", name: "Marco Vega", initials: "MV", avatarTone: "violet", online: true, verified: true, context: { type: "project", label: "Mix Pro · 'Fade Away'", projectId: "p-4821" }, lastTime: "14:32", unread: 2, preview: "Ti ho mandato la v2 con il low-end un po' più caldo, fammi sapere se cambi qualcosa…", role: "Mix engineer · @marcovega", messages: [ { id: "m1", who: "them", time: "13:24", body: "Ciao Luca! Ho lavorato sulla traccia oggi pomeriggio.", day: "Oggi" }, { id: "m2", who: "them", time: "13:25", body: "Ho fatto una passata di EQ sulle voci, ridotto un po' la sibilanza e bilanciato le armonie nel ritornello." }, { id: "m3", who: "them", time: "13:26", body: "kind: attach", attach: { name: "Fade Away — Mix v2.wav", size: "3:42 · 78 MB", kind: "audio" } }, { id: "m4", who: "me", time: "14:02", body: "Top, ascolto e ti dico subito 🙏" }, { id: "m5", who: "me", time: "14:18", body: "Ok il mix è solidissimo. Solo: il basso secondo me va un filo giù tra 1:48 e 2:10, schiaccia la voce nel break." }, { id: "m6", who: "them", time: "14:32", body: "Ti ho mandato la v2 con il low-end un po' più caldo, fammi sapere se cambi qualcosa." }, ], }, { id: "c2", name: "Sara K.", initials: "SK", avatarTone: "pink", online: true, verified: true, context: { type: "predeal" }, lastTime: "12:15", unread: 1, preview: "Ciao, ho letto la tua richiesta. Ti scrivo dal mio numero personale 3331234… [contatto nascosto]", role: "Vocal producer · @sarak", messages: [ { id: "m1", who: "them", time: "12:08", body: "Ciao Luca, ho letto la tua richiesta open per il vocal coach.", day: "Oggi" }, { id: "m2", who: "them", time: "12:09", body: "Lavoro con artisti R&B/soul, posso aiutarti su tecnica e arrangement vocale. Sentiamoci in call?" }, { id: "m3", who: "them", time: "12:15", body: { type: "masked", parts: [ { kind: "text", value: "Ciao, ti scrivo direttamente al mio numero personale " }, { kind: "mask", reason: "phone", placeholder: "[contatto nascosto — accetta prima l'offerta]" }, { kind: "text", value: " così sentiamo subito. Oppure email " }, { kind: "mask", reason: "email", placeholder: "[contatto nascosto]" }, { kind: "text", value: "." }, ]} }, ], }, { id: "c3", name: "Hearfield Studio", initials: "HS", avatarTone: "muted-color", online: false, verified: true, context: { type: "project", label: "Mastering · 'Velvet EP'", projectId: "p-4756" }, lastTime: "ieri", unread: 0, preview: "Tutto pronto! I master sono già stati caricati nella sezione progetto.", role: "Mastering studio", messages: [], }, { id: "c4", name: "@nightowl", initials: "NO", avatarTone: "amber", online: false, verified: true, context: { type: "predeal" }, lastTime: "ieri", unread: 0, preview: "Ti mando l'offerta entro fine giornata 🙏", role: "Beatmaker · @nightowl", messages: [], }, { id: "c5", name: "@luxx", initials: "LX", avatarTone: "green", online: true, verified: true, context: { type: "predeal" }, lastTime: "lun", unread: 0, preview: "Tu: Ascoltato! Lo prendo, ti scrivo dopo per i dettagli.", role: "Producer · @luxx", messages: [], }, { id: "c6", name: "@desertcat", initials: "DC", avatarTone: "violet", online: false, verified: false, context: { type: "predeal" }, lastTime: "27 apr", unread: 0, preview: "Ok grazie, alla prossima!", role: "Producer · @desertcat", messages: [], }, ]; // ============= ICONS ============= const SendIcon = ({ size = 18 }) => ( ); const SearchIc = ({ size = 16 }) => ( ); const VerifiedIc = ({ size = 12 }) => ( ); const PaperclipIc = ({ size = 18 }) => ( ); const MicIc = ({ size = 18 }) => ( ); const PlayIc = ({ size = 12 }) => ( ); const PhoneIc = ({ size = 16 }) => ( ); const VideoIc = ({ size = 16 }) => ( ); const DotsIc = ({ size = 16 }) => ( ); const ArrowLeftIc = ({ size = 16 }) => ( ); const ShieldIc = ({ size = 16 }) => ( ); const CloseIc = ({ size = 14 }) => ( ); const FolderIc = ({ size = 16 }) => ( ); const SmileIc = ({ size = 18 }) => ( ); const AudioIc = ({ size = 16 }) => ( ); const CheckCheckIc = ({ size = 12 }) => ( ); // ============= LIST ITEM ============= function ChatItem({ chat, active, onClick }) { return (
0 ? "unread" : ""}`} onClick={onClick}>
{chat.initials}
{chat.context.type === "project" && ( Progetto )} {chat.context.type === "predeal" && ( 🔒 Pre-deal )}
{chat.name} {chat.verified && }
{chat.preview}
{chat.lastTime} {chat.unread > 0 && {chat.unread}}
); } // ============= MESSAGE BUBBLE ============= function MessageBubble({ msg, prevWho, chat }) { const mine = msg.who === "me"; const showAv = !mine && (!prevWho || prevWho !== msg.who); // Voice / attach detection const body = msg.body; let renderedBody; if (msg.kind === "voice" || (typeof body === "object" && body?.type === "voice")) { renderedBody = (
{[8, 14, 22, 10, 18, 24, 14, 20, 12, 26, 16, 22, 10, 18, 14, 22, 10, 16, 20, 14, 8, 16].map((h, i) => ( ))}
0:18
); } else if (msg.body === "kind: attach" || msg.attach) { const a = msg.attach; renderedBody = (
{a.name}
{a.size}
); } else if (typeof body === "object" && body?.type === "masked") { renderedBody = ( <> {body.parts.map((p, i) => p.kind === "text" ? {p.value} : {p.placeholder} )} ); } else { renderedBody = body; } return (
{showAv &&
{chat.initials}
} {!showAv && !mine &&
}
{renderedBody}
{msg.time} {mine && }
); } // ============= THREAD ============= function Thread({ chat, onBack }) { const [draft, setDraft] = React.useState(""); if (!chat) { return (
Seleziona una conversazione
Apri una chat dalla lista a sinistra per leggere i messaggi e rispondere.
); } const showBanner = chat.context.type === "predeal"; return (
{chat.initials}
{chat.name} {chat.verified && }
{chat.online && } {chat.online ? "Online ora" : `Visto ${chat.lastTime}`} · {chat.role}
{chat.context.type === "project" && (
Stai chattando su {chat.context.label} Apri progetto →
)} {showBanner && (
🔒
Chat pre-deal protetta
I contatti diretti (telefono, email, social) sono nascosti finché non accetti un'offerta. Lo facciamo per proteggerti — tutti i pagamenti vivono in escrow Sonara.
)}
{chat.messages.length > 0 &&
{chat.messages[0].day}
} {chat.messages.map((m, i) => ( 0 ? chat.messages[i-1].who : null} chat={chat}/> ))}