mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 06:43:06 +00:00
/conteudos + /conteudos/<slug>: catálogo filtrável (Tipo · Cidade · Região · Tema · Instituição + termo na URL canônica), play sob demanda (Vídeo/Áudio só carregam no toque; Foto com preview leve), Baixar e Compartilhar do próprio card com a mensagem de voto por tipo (wa.me sem destinatário, editável; "A mídia" usa a folha nativa e cai em download onde o aparelho não suportar) e o card personalizado como peça sintética do catálogo → /cards. - leitura pública nova (contentPieceReads) cacheada na tag contentPieces com o gate where status=publicado + contentPieceIsPublic; a rota GET /conteudos/<slug>/midia reusa buildPrivateMediaResponse (range, disposition, private no-store, 404 uniforme) com download jorge-solla-1313-<slug>.<ext> e a allowlist inline do dono estendida (webp/gif/avif + áudios das peças) - contrato público puro do catálogo (filtros/VM/download) + mensagens de voto (contentPieceShare); OG com fallback do global; conteudos entra nos slugs reservados; kill switch por peça vale na hora (lista, página, rodapé/selo); descoberta condicional no CampaignFooter e no header local - UI portada classe-a-classe do design aprovado (cenas 01–08, com as cenas 06–08 estendidas no trigger a); sem migration, sem Consent e sem access novo; contentMedia segue privada (sem segunda cópia de mídia) - testes: 2 unit specs novos, 18 casos int (leitura pública + rota de mídia) e e2e frontendConteudos (5 casos); manifest e curado atualizados - follow-up de engenharia: #1276 (docs/plans/escala-dry-pos-s27.md) Closes #1255
54 lines
2.3 KiB
TypeScript
54 lines
2.3 KiB
TypeScript
/**
|
|
* S27 — pure share contract of the Central de Conteúdos: the vote message per
|
|
* piece type (the literals of the gate, always editable by the voter) and the
|
|
* link each piece shares. The system never sends anything: the sheet opens the
|
|
* sender's own WhatsApp with the text prefilled (`wa.me`, no recipient).
|
|
*
|
|
* The S4 home vocabulary (`src/lib/contentShare.ts`) stays its own owner — a
|
|
* different message family with its own pinned contract.
|
|
*/
|
|
import type { ContentPieceType } from '@/lib/contentPiece'
|
|
import { contentPiecePublicPath } from '@/lib/contentPieceCatalog'
|
|
import { buildContentShareLink } from '@/lib/contentShare'
|
|
import { buildWhatsAppTextShareUrl } from '@/lib/phone'
|
|
|
|
/** Link-piece sources share the platform URL; an archived piece shares its page. */
|
|
export type ContentPieceShareSource = {
|
|
slug: string
|
|
isLink: boolean
|
|
sourceUrl: string | null
|
|
}
|
|
|
|
/**
|
|
* Vote message per piece type (gate literals, "assumidas — validar com a
|
|
* comunicação"): the voter reviews the text in the sheet before opening
|
|
* WhatsApp, so the template is a starting point, never an automatic send.
|
|
*/
|
|
export const contentPieceVoteMessage = (
|
|
type: ContentPieceType,
|
|
title: string,
|
|
link: string,
|
|
): string => {
|
|
if (type === 'video') {
|
|
return `Estamos na reta final e o Jorge Solla 1313 precisa do seu voto. Olha esse vídeo: ${title} — ${link}. Peça voto pra Solla 1313 pra quem você conhece.`
|
|
}
|
|
if (type === 'audio') {
|
|
return `Ouça e mande pro grupo: ${title} — ${link}. Peça voto pra Solla 1313.`
|
|
}
|
|
return `Fiz/achei esse material do Solla 1313: ${title} — ${link}. Peça voto pra Solla 1313 também.`
|
|
}
|
|
|
|
/**
|
|
* The link a piece shares: the canonical platform URL for a link piece (never
|
|
* a second copy), the public piece page for an archived one. Absolute against
|
|
* the visitor's origin so the message carries a clickable URL (the S4
|
|
* fail-soft resolver is the single owner of that absolutization).
|
|
*/
|
|
export const contentPieceShareLink = (piece: ContentPieceShareSource, origin: string): string =>
|
|
piece.isLink && piece.sourceUrl
|
|
? piece.sourceUrl
|
|
: buildContentShareLink(contentPiecePublicPath(piece.slug), origin)
|
|
|
|
/** `wa.me/?text=` with the prefilled message — no recipient, no automatic send. */
|
|
export const buildContentPieceWhatsAppUrl = (message: string): string =>
|
|
buildWhatsAppTextShareUrl(message)
|