// CENTRAL DA MARCA — Mariana Cabral · store persistente + autenticação + fluxo de 3 etapas. // SELECIONAR ≠ APROVAR IDEIA ≠ APROVAR DESIGN — três ações distintas e independentes. // Exporta window.MC_STORE (function () { const LS = "mc_central_v3"; const SS = "mc_central_auth_v1"; const clone = (x) => JSON.parse(JSON.stringify(x)); const nowISO = () => new Date().toISOString(); const D = window.MC_DATA; function seedIdeias() { // todas as ideias entram como novas sugestões, aguardando aprovação — todos os temas visíveis return D.IDEIAS.map((base) => Object.assign({ selecionada: false, status: "Nova sugestão", prioridade: base.prioridade || "Média", campanha: "", responsavel: "", dataDesejada: "", comentarioMariana: "", comentarioAgencia: "", criadaEm: "Julho/2026", historico: [], design: null, }, base)); } function seed() { const aprov = (D.APROVACOES || []).map((a) => Object.assign({ selecionada: false, status: "Aguardando aprovação final", prioridade: a.prioridade || "Média", campanha: "", responsavel: "Agência Logue", dataDesejada: "", comentarioMariana: "", comentarioAgencia: "", criadaEm: "Julho/2026", historico: [{ ts: nowISO(), user: "Agência Logue", acao: "Design enviado para aprovação" }], design: { legenda: a.resumo || "", cta: a.cta || "", formato: a.formato, dataSugerida: "A definir", versao: 1, historicoVersoes: ["v1"], comentarios: [], link: a.link || "" }, }, a)); return { ideias: seedIdeias().concat(aprov), captacoes: D.CAPTACOES ? clone(D.CAPTACOES) : [], campanha: { membros: 1, meta: 0, notas: "", passos: [ { id: "p1", t: "Organizar o perfil @clube emocional", done: false }, { id: "p2", t: "Otimizar a área de membros", done: false }, { id: "p3", t: "Postar 2 vídeos longos no YouTube", done: false }, { id: "p4", t: "Impulsionar post no Instagram", done: false, dep: "p1", depNota: "após organizar o perfil" }, ] }, lastVisit: nowISO(), }; } function merge(s) { const m = Object.assign(seed(), s); const base = seed().campanha; m.campanha = Object.assign({}, base, s.campanha); if (m.campanha.membros == null) m.campanha.membros = base.membros; if (!m.campanha.passos || !m.campanha.passos.length) m.campanha.passos = base.passos; return m; } function load() { try { const r = localStorage.getItem(LS); if (r) { const s = JSON.parse(r); if (s && s.ideias) return merge(s); } } catch (e) {} return seed(); } let state = load(); const subs = new Set(); const save = () => { try { localStorage.setItem(LS, JSON.stringify(state)); } catch (e) {} if (window.MC_CLOUD && window.MC_CLOUD.configured()) window.MC_CLOUD.push(state); }; function set(mut) { const next = clone(state); mut(next); state = next; save(); subs.forEach((f) => f()); } const findI = (s, id) => s.ideias.find((x) => x.id === id); const log = (idea, acao, user) => { idea.historico = idea.historico || []; idea.historico.push({ ts: nowISO(), user: user || "Mariana Cabral", acao }); }; const uid = (p) => p + Math.random().toString(36).slice(2, 8); // ─── AUTENTICAÇÃO (hash SHA-256, sem senha em claro no código) ─── async function sha256(str) { const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(str)); return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join(""); } const Store = { get: () => state, subscribe: (fn) => { subs.add(fn); return () => subs.delete(fn); }, reset: () => { state = seed(); save(); subs.forEach((f) => f()); }, // AUTH isAuthed: () => { try { return sessionStorage.getItem(SS) === "1"; } catch (e) { return false; } }, login: async (user, pass) => { const u = (user || "").trim().toLowerCase(); const digest = await sha256(u + ":" + (pass || "")); const ok = digest === D.AUTH_HASH; if (ok) { try { sessionStorage.setItem(SS, "1"); } catch (e) {} subs.forEach((f) => f()); } return ok; }, logout: () => { try { sessionStorage.removeItem(SS); } catch (e) {} subs.forEach((f) => f()); }, // ── ETAPA 1 · SELECIONAR (lista de interesse — não autoriza nada) ── toggleSelecionar: (id) => set((s) => { const i = findI(s, id); if (i) i.selecionada = !i.selecionada; }), selecionarLote: (ids, val) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) i.selecionada = val; })), // ── ETAPA 2 · APROVAR IDEIA (autoriza a agência a produzir) ── aprovarIdeia: (id) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Aprovada para produção"; if (!i.responsavel) i.responsavel = "Agência Logue"; log(i, "Ideia aprovada para produção — agência autorizada a criar"); }), pedirAjuste: (id, texto, tags) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Ajustes solicitados"; i.comentarioMariana = texto || i.comentarioMariana; log(i, "Ajustes solicitados" + (tags && tags.length ? ": " + tags.join(", ") : "") + (texto ? " — " + texto : "")); }), naoAprovar: (id) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Não aprovada"; log(i, "Ideia não aprovada"); }), guardarDepois: (id) => set((s) => { const i = findI(s, id); if (!i) return; i.selecionada = true; if (i.status === "Nova sugestão") i.status = "Em análise"; log(i, "Guardada para depois"); }), // edições diretas editarTitulo: (id, v) => set((s) => { const i = findI(s, id); if (i) i.titulo = v; }), alterarFormato: (id, v) => set((s) => { const i = findI(s, id); if (i) i.formato = v; }), definirPrioridade: (id, v) => set((s) => { const i = findI(s, id); if (i) i.prioridade = v; }), definirDataDesejada: (id, v) => set((s) => { const i = findI(s, id); if (i) i.dataDesejada = v; }), definirCampanha: (id, v) => set((s) => { const i = findI(s, id); if (i) i.campanha = v; }), definirResponsavel: (id, v) => set((s) => { const i = findI(s, id); if (i) i.responsavel = v; }), addComentario: (id, v) => set((s) => { const i = findI(s, id); if (i && v) { i.comentarioMariana = v; log(i, "Comentário: " + v); } }), duplicar: (id) => set((s) => { const i = findI(s, id); if (!i) return; const cp = clone(i); cp.id = uid("i"); cp.titulo = i.titulo + " (cópia)"; cp.selecionada = false; cp.status = "Nova sugestão"; cp.historico = []; cp.design = null; s.ideias.unshift(cp); }), arquivar: (id) => set((s) => { const i = findI(s, id); if (i) { i.status = "Arquivada"; log(i, "Arquivada"); } }), // ── AÇÕES EM LOTE ── aprovarLote: (ids) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) { i.status = "Aprovada para produção"; if (!i.responsavel) i.responsavel = "Agência Logue"; log(i, "Aprovada em lote para produção"); } })), pedirAjustesLote: (ids, texto) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) { i.status = "Ajustes solicitados"; if (texto) i.comentarioMariana = texto; log(i, "Ajuste solicitado em lote" + (texto ? ": " + texto : "")); } })), definirCampanhaLote: (ids, v) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) i.campanha = v; })), definirPrioridadeLote: (ids, v) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) i.prioridade = v; })), definirMesLote: (ids, v) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) i.dataDesejada = v; })), enviarAgenciaLote: (ids) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i && (i.status === "Nova sugestão" || i.status === "Em análise")) { i.status = "Aprovada para produção"; i.responsavel = "Agência Logue"; log(i, "Enviada para a agência (lote)"); } })), arquivarLote: (ids) => set((s) => ids.forEach((id) => { const i = findI(s, id); if (i) { i.status = "Arquivada"; log(i, "Arquivada em lote"); } })), // setter direto de status (usado pelo kanban) setStatus: (id, status) => set((s) => { const i = findI(s, id); if (!i) return; if (i.status === status) return; if (status === "Aguardando aprovação final" && !i.design) { i.design = { legenda: i.resumo, cta: i.cta || "", formato: i.formato, dataSugerida: i.dataDesejada || "A definir", versao: 1, historicoVersoes: ["v1 — " + new Date().toLocaleDateString("pt-BR")], comentarios: [] }; } i.status = status; log(i, "Movida para: " + status); }), // ── SIMULAÇÃO DA AGÊNCIA (produção → entrega de design) ── avancarProducao: (id) => set((s) => { const i = findI(s, id); if (!i) return; const fluxo = { "Aprovada para produção": "Em roteiro", "Em roteiro": "Em design", "Em design": "Em edição", "Em edição": "Aguardando aprovação final" }; const prox = fluxo[i.status]; if (!prox) return; i.status = prox; if (prox === "Aguardando aprovação final") { i.design = i.design || { legenda: i.resumo, cta: i.cta || "", formato: i.formato, dataSugerida: i.dataDesejada || "A definir", versao: 1, historicoVersoes: ["v1 — " + new Date().toLocaleDateString("pt-BR")], comentarios: [] }; log(i, "Design enviado para aprovação", "Agência Logue"); } else { log(i, "Produção avançou para: " + prox, "Agência Logue"); } }), // ── ETAPA 3 · APROVAR DESIGN (autoriza agendamento / publicação) ── aprovarDesign: (id) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Aprovada"; log(i, "Design aprovado para publicação"); }), novoParaAprovacao: ({ titulo, formato, link, legenda }) => set((s) => { const i = { id: uid("ap-"), titulo: titulo.trim(), resumo: (legenda || "").trim(), formato: formato || "Carrossel", objetivo: "", pilar: "", funil: "", prioridade: "Média", porque: "", estrutura: "", cta: "", selecionada: false, status: "Aguardando aprovação final", campanha: "", responsavel: "Agência Logue", dataDesejada: "", comentarioMariana: "", comentarioAgencia: "", criadaEm: "Julho/2026", design: { legenda: (legenda || "").trim(), cta: "", formato: formato || "Carrossel", dataSugerida: "A definir", versao: 1, comentarios: [], link: (link || "").trim() }, historico: [], }; log(i, "Conteúdo enviado para aprovação", "Agência Logue"); s.ideias.unshift(i); }), reprovarDesign: (id, texto) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Não aprovada"; if (i.design) { i.design.comentarios = i.design.comentarios || []; if (texto) i.design.comentarios.push({ ts: nowISO(), texto }); } log(i, "Conteúdo reprovado — não segue para publicação" + (texto ? ": " + texto : "")); }), aprovarEAgendar: (id, data) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Agendada"; if (i.design) i.design.dataSugerida = data || i.design.dataSugerida; log(i, "Design aprovado e agendado" + (data ? " para " + data : "")); }), publicar: (id) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Publicada"; log(i, "Publicada"); }), solicitarAlteracaoDesign: (id, texto) => set((s) => { const i = findI(s, id); if (!i) return; i.status = "Em design"; if (i.design) { i.design.comentarios = i.design.comentarios || []; i.design.comentarios.push({ ts: nowISO(), texto }); } log(i, "Alteração de design solicitada" + (texto ? ": " + texto : "")); }), comentarDesign: (id, texto) => set((s) => { const i = findI(s, id); if (i && i.design) { i.design.comentarios = i.design.comentarios || []; i.design.comentarios.push({ ts: nowISO(), texto }); log(i, "Comentário no design: " + texto); } }), // ── CAPTAÇÕES (calendário de B-roll) ── addCaptacao: (ev) => set((s) => { s.captacoes.push(Object.assign({ id: uid("cap") }, ev)); }), updateCaptacao: (id, patch) => set((s) => { const e = s.captacoes.find((x) => x.id === id); if (e) Object.assign(e, patch); }), removeCaptacao: (id) => set((s) => { s.captacoes = s.captacoes.filter((x) => x.id !== id); }), // ── CAMPANHA ── setCampanha: (patch) => set((s) => { s.campanha = Object.assign({}, s.campanha, patch); }), ajustarMembros: (delta) => set((s) => { const cur = s.campanha.membros != null ? s.campanha.membros : 1; s.campanha = Object.assign({}, s.campanha, { membros: Math.max(0, cur + delta) }); }), togglePasso: (id) => set((s) => { s.campanha = Object.assign({}, s.campanha, { passos: (s.campanha.passos || []).map((p) => p.id === id ? Object.assign({}, p, { done: !p.done }) : p) }); }), escolherTemaCampanha: (id) => set((s) => { const i = findI(s, id); if (!i) return; i.selecionada = !i.selecionada; i.campanha = i.selecionada ? "Clube da Maturidade Emocional" : ""; log(i, i.selecionada ? "Escolhida para a campanha do Clube" : "Removida da campanha do Clube"); }), // seletores resumo: () => { const I = state.ideias; const by = (f) => I.filter(f).length; return { novas: by((i) => i.status === "Nova sugestão"), analise: by((i) => i.status === "Em análise"), selecionadas: by((i) => i.selecionada), producao: by((i) => ["Aprovada para produção", "Em roteiro", "Em design", "Em edição"].includes(i.status)), aguardandoDesign: by((i) => i.status === "Aguardando aprovação final"), ajustes: by((i) => i.status === "Ajustes solicitados"), prontas: by((i) => i.status === "Aprovada"), agendadas: by((i) => i.status === "Agendada"), publicadas: by((i) => i.status === "Publicada"), }; }, }; // hook React simples Store.useStore = function () { const [, force] = React.useState(0); React.useEffect(() => Store.subscribe(() => force((n) => n + 1)), []); return { state, actions: Store }; }; window.MC_STORE = Store; // Hidrata da nuvem no boot (se configurada). A nuvem é a fonte de verdade entre dispositivos. if (window.MC_CLOUD && window.MC_CLOUD.configured()) { window.MC_CLOUD.pull().then((remote) => { if (remote && remote.ideias) { state = merge(remote); try { localStorage.setItem(LS, JSON.stringify(state)); } catch (e) {} subs.forEach((f) => f()); } else { // Nuvem vazia (primeiro uso): envia o estado atual para semear o registro. window.MC_CLOUD.push(state); } }); } })();