import React, { useState, useCallback, useMemo, useEffect, useRef, RefObject } from 'react'; import ReactDOM from 'react-dom/client'; import { Map, Cpu, Award, Heart, Share2, CheckCircle, ChevronLeft, ChevronRight, BarChart2, X, Instagram, Linkedin } from 'lucide-react'; // --- Type/Interface Definitions (from all files) --- interface FlipCardProps { icon: React.ReactNode; frontTitle: string; backTitle: string; backText: string; } interface ImageLightboxProps { images: string[]; currentIndex: number; originRect: DOMRect; onClose: () => void; onNext: () => void; onPrev: () => void; } interface PortfolioItem { title: string; folder: string; images: string[]; tooltip: string | null; } interface PortfolioCardProps { item: PortfolioItem; onImageClick: (item: PortfolioItem, imageIndex: number, element: HTMLImageElement) => void; isChecked: boolean; onToggle: (title: string) => void; } interface FooterProps { onOpenModal: () => void; isFormValid: boolean; } interface ContactModalProps { isOpen: boolean; onClose: () => void; contactData: { name: string; email: string; phone: string; role: string; school: string; }; onContactDataChange: (e: React.ChangeEvent) => void; onSubmit: () => void; } interface LightboxState { images: string[]; currentIndex: number; originElement: HTMLElement; } // Props for state-lifted components interface ProblemSectionProps { rankings: Record; setRankings: React.Dispatch>>; openChallenge: string; setOpenChallenge: (value: string) => void; } interface PortfolioSectionProps { selectedItems: Record; onToggleItem: (title: string) => void; onToggleSelectAll: () => void; onDeselectAll: () => void; portfolioItemTitles: string[]; } interface BenefitsSectionProps { selectedBenefits: Record; onToggleBenefit: (id: string) => void; } interface SimulatorSectionProps { totalAlunos: string; setTotalAlunos: (value: string) => void; metaConversao: number; setMetaConversao: (value: number) => void; frequenciaSemanal: number; setFrequenciaSemanal: (value: number) => void; mensalidadeCurricular: string; setMensalidadeCurricular: (value: string) => void; selectedModel: string; onSelectModel: (model: string) => void; } // --- Hooks (from hooks/useFadeIn.ts) --- const useFadeIn = (): [RefObject, boolean] => { const [isVisible, setIsVisible] = useState(false); const ref = useRef(null); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setIsVisible(true); if (ref.current) { observer.unobserve(ref.current); } } }, { threshold: 0.1, } ); if (ref.current) { observer.observe(ref.current); } return () => { if (ref.current) { // eslint-disable-next-line react-hooks/exhaustive-deps observer.unobserve(ref.current); } }; }, []); return [ref, isVisible]; }; // --- Common Components (from components/common/*) --- const FlipCard: React.FC = ({ icon, frontTitle, backTitle, backText }) => { return (
{/* Front */}
{icon}

{frontTitle}

{/* Back */}

{backTitle}

{backText}

); }; const ImageLightbox: React.FC = ({ images, currentIndex, originRect, onClose, onNext, onPrev }) => { const [isAnimating, setIsAnimating] = useState(false); const [isClosing, setIsClosing] = useState(false); const imageUrl = images[currentIndex]; const handleClose = useCallback(() => { setIsClosing(true); const timer = setTimeout(() => { onClose(); }, 300); // This duration must match the CSS transition duration return () => clearTimeout(timer); }, [onClose]); // Effect to handle keyboard keys useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose(); if (images.length > 1) { if (e.key === 'ArrowRight') onNext(); if (e.key === 'ArrowLeft') onPrev(); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [handleClose, onNext, onPrev, images.length]); // Effect to trigger the opening animation useEffect(() => { const timer = setTimeout(() => setIsAnimating(true), 10); return () => clearTimeout(timer); }, []); // Style for the animating container const containerStyle: React.CSSProperties = { position: 'fixed', transition: 'all 300ms cubic-bezier(0.4, 0, 0.2, 1)', zIndex: 60, top: `${originRect.top}px`, left: `${originRect.left}px`, width: `${originRect.width}px`, height: `${originRect.height}px`, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'transparent', boxShadow: 'none', borderRadius: 0, padding: 0, }; if (isAnimating && !isClosing) { containerStyle.top = '50%'; containerStyle.left = '50%'; containerStyle.width = 'auto'; containerStyle.height = 'auto'; containerStyle.transform = 'translate(-50%, -50%)'; containerStyle.background = 'transparent'; containerStyle.boxShadow = 'none'; containerStyle.borderRadius = 0; containerStyle.padding = 0; } return (
Imagem ampliada {images.length > 1 && ( <> )}
); }; const PortfolioCard: React.FC = ({ item, onImageClick, isChecked, onToggle }) => { const [currentIndex, setCurrentIndex] = useState(0); const basePath = 'https://labirintar.github.io/comercial/diagnostico/'; const nextImage = (e: React.MouseEvent) => { e.stopPropagation(); setCurrentIndex((prevIndex) => (prevIndex + 1) % item.images.length); }; const prevImage = (e: React.MouseEvent) => { e.stopPropagation(); setCurrentIndex((prevIndex) => (prevIndex - 1 + item.images.length) % item.images.length); }; const handleImageError = (e: React.SyntheticEvent) => { e.currentTarget.onerror = null; e.currentTarget.src = 'https://picsum.photos/400/300?grayscale'; }; return (
{item.images.map((imgFile, index) => { const fullUrl = `${basePath}${item.folder}/${imgFile}`; return ( {`${item.title} onImageClick(item, index, e.currentTarget)} /> ); })}
{item.images.length > 1 && ( <> )} {item.tooltip && (
{item.tooltip}
)}

{item.title}

onToggle(item.title)} />
); }; // --- Main Components (from components/*) --- const TopBar: React.FC = () => { const [menuOpen, setMenuOpen] = useState(false); return ( <>
{menuOpen && (
Logo LABIRINTAR
Para escolas Experiências Quem somos Rede Blog Contato Entrar
)} ); }; const Hero: React.FC = () => { const [logoRef, isLogoVisible] = useFadeIn(); const [titleRef, isTitleVisible] = useFadeIn(); const [subtitleRef, isSubtitleVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; return (
Logo Labirintar

Educar é dar sentido ao tempo.

E sentido se constrói em rede.

); }; const visionCards = [ { title: 'Plataforma Inteligente: o sistema que organiza o contraturno', text: 'Conectamos escolas, educadores e famílias por meio de uma plataforma viva que organiza fluxos, registros e comunicação. A tecnologia da Labirintar sustenta continuidade, reduz sobrecarga e transforma experiências em aprendizado institucional.', }, { title: 'Geração de Receita: Sustentabilidade sem improviso', text: 'Organizamos o uso dos espaços e do tempo da escola de forma estruturada, permitindo que o contraturno gere receita recorrente, previsível e alinhada ao projeto pedagógico, sem aumentar a complexidade operacional da gestão.', }, { title: 'Desenvolvimento integral: experiência com intencionalidade pedagógica', text: 'Nossas experiências não são recreação isolada. Elas fazem parte de percursos educativos fundamentados em ciência, escuta sensível e documentação, promovendo o desenvolvimento cognitivo, socioemocional, cultural e relacional das crianças.', }, { title: 'Ecossistema Colaborativo: rede, governança e aprendizado coletivo', text: 'A Labirintar não opera por contratos isolados, mas por rede. Educadores, escolas e equipe atuam conectados por critérios claros, formação contínua e governança viva, fortalecendo vínculos, qualidade e impacto ao longo do tempo.', }, ]; const ChallengeIntroSection: React.FC = () => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; return (

Mais tempo não basta.
Educação integral exige estrutura viva.

Quando o tempo escolar se amplia sem uma estrutura pedagógica consistente,
as experiências se fragmentam, e o que poderia ser potência vira desgaste para a escola, os educadores e as crianças.

{/* Primeiro bloco */}

O que acontece na prática

  • O contraturno se transforma em um conjunto de atividades desconectadas
  • A coordenação pedagógica fica sobrecarregada com gestão operacional
  • Falta continuidade e coerência pedagógica ao longo do tempo
  • Educadores entram e saem, enfraquecendo vínculos e processos
  • Famílias não conseguem perceber valor e sentido no cotidiano vivido
{/* Segundo bloco */}

Com isso, grandes oportunidades se perdem

  • O contraturno deixa de aprofundar experiências verdadeiramente significativas
  • A escola não consolida uma identidade pedagógica clara no contraturno
  • As crianças vivenciam muitas atividades, mas poucos percursos de aprendizagem contínua
  • Educadores atuam sem pertencimento estruturado ou perspectiva de permanência
  • O contraturno não alcança todo o seu potencial pedagógico, relacional e econômico
); }; const solutionIntroCards = [ { title: "Curadoria Pedagógica", subtitle: "Experiência com intencionalidade", text: "A curadoria pedagógica acontece na escolha, acompanhamento e avaliação das atividades integradas ao projeto educacional da escola, com base na escuta das infâncias e em evidências pedagógicas.\n\nCada experiência compõe um percurso educativo, com intencionalidade clara e atenção ao desenvolvimento integral.\n\nNossa excelência não está na quantidade de ofertas, mas na qualidade do sentido construído ao longo do tempo.", }, { title: "Tecnologia Digital", subtitle: "O sistema que organiza o contraturno", text: "A tecnologia da Labirintar é infraestrutura. Ela organiza experiências, educadores, horários e registros pedagógicos em um único fluxo integrado.\n\nIsso reduz a carga operacional da escola, dá visibilidade ao que acontece no contraturno e libera tempo e energia para que o pedagógico aconteça com mais presença e profundidade.", }, { title: "Rede de Educadores", subtitle: "Qualidade com continuidade", text: "A Labirintar atua com uma rede curada de educadores, alinhados em visão pedagógica, prática cotidiana e compromisso com o percurso das crianças.\n\nEssa continuidade reduz rotatividade, fortalece vínculos e permite que a experiência educativa se aprofunde, semestre após semestre, escola após escola.", }, { title: "Comunidade Colaborativa", subtitle: "Um ecossistema que aprende", text: "A qualidade não se sustenta sozinha. Ela se constrói em comunidade. Trocas entre educadores, registros de prática, acompanhamento contínuo e espaços de reflexão coletiva permitem que a rede aprenda com a própria experiência, refine decisões e eleve a qualidade ao longo do tempo.", }, ]; const SolutionIntroSection: React.FC = () => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-opacity duration-1000 ease-out ${isVisible ? 'opacity-100' : 'opacity-0'}`; return (

Quando o Tempo Integral ganha estrutura, a experiência muda.

A Labirintar organiza o contraturno como uma infraestrutura educativa viva - integrando pedagogia, tecnologia digital e rede de educadores em um sistema coerente.

{solutionIntroCards.map((card, index) => (

{card.title}

{card.subtitle}

{card.text}

))}

Quando pedagogia, tecnologia, pessoas e comunidades se organizam como sistema, o Tempo Integral deixa de ser improviso e passa a ser infraestrutura.

); }; const VisionSection: React.FC = () => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-opacity duration-1000 ease-out ${isVisible ? 'opacity-100' : 'opacity-0'}`; return (

A escola em tempo integral precisa mais do que tempo.
Precisa de estrutura que sustente experiências com sentido.

A Labirintar organiza o contraturno como parte viva do projeto educativo da escola - conectando pessoas, experiências e decisões em um sistema coerente.

{visionCards.map((card, index) => (

{card.title}

{card.text}

))}
); }; const challenges = [ { id: 'diferenciar', text: 'Diferenciar-se sem onerar a operação' }, { id: 'reter', text: 'Atrair e reter alunos com propostas significativas' }, { id: 'espacos', text: 'Transformar espaços ociosos em ambientes vivos' }, { id: 'organizar', text: 'Organizar o contraturno sem sobrecarregar a coordenação' }, { id: 'continuidade', text: 'Garantir continuidade pedagógica' }, { id: 'reduzirRotatividade', text: 'Reduzir rotatividade de educadores' }, ]; const ProblemSection: React.FC = ({ rankings, setRankings, openChallenge, setOpenChallenge }) => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; const commitments = [ 'Organização do contraturno sem sobrecarregar a coordenação pedagógica e equipe docente.', 'Implantação de curadoria especializada focada na qualidade pedagógica', 'Redução na rotatividade de educadores que atuam no contraturno', 'Manutenção dos alunos matriculados e ampliação da oferta para novos alunos', 'Valorização dos diferenciais institucionais nas campanhas de comunicação', 'Divulgação estruturada do que acontece no contraturno, transformando as experiências vividas em dados estruturados que irão orientar decisões futuras' ]; return (

A cartografia dos desafios reais
do Tempo Integral

Com base nos desafios que escutamos no chão das escolas com as quais caminhamos, a Labirintar se compromete com:

    {commitments.map((commitment, index) => (
  • {commitment}
  • ))}
); }; const solutionCards: FlipCardProps[] = [ { icon: , frontTitle: 'Tecnologia', backTitle: 'Organiza o contraturno como sistema ', backText: 'Plataforma que integra experiências, educadores, horários e registros pedagógicos em um único fluxo. Menos carga operacional para a escola. Mais espaço para o pedagógico acontecer.' }, { icon: , frontTitle: 'Rede de Educadores Empreendedores', backTitle: 'Qualidade com continuidade', backText: 'Rede curada de educadores alinhados em visão, prática e compromisso pedagógico. Reduz rotatividade. Constrói percurso educativo consistente ao longo do tempo.' }, { icon: , frontTitle: 'Curadoria Pedagógica', backTitle: 'Experiência com intenção ', backText: 'Nada de atividades soltas. Cada experiência tem intencionalidade pedagógica, coerência com o projeto da escola e foco no desenvolvimento integral das crianças.' }, { icon: , frontTitle: 'Comunidade Colaborativa', backTitle: 'Um ecossistema que aprende ', backText: 'Escolas, educadores e Labirintar aprendem juntos. Trocas, registros e acompanhamento contínuo refinam práticas e elevam a qualidade com o tempo.' } ]; const SolutionSection: React.FC = () => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-opacity duration-1000 ease-out ${isVisible ? 'opacity-100' : 'opacity-0'}`; return (

Quando o Tempo Integral ganha estrutura, a experiência muda

A Labirintar integra pedagogia, pessoas e tecnologia para transformar o contraturno em um percurso educativo contínuo, viável e com sentido.

{solutionCards.map((card, index) => ( ))}

A Labirintar não entrega atividades. Ela organiza o Tempo Integral como infraestrutura educativa viva.

); }; const WayOfDoingSection: React.FC = () => { const [sectionRef, isVisible] = useFadeIn(); const routineItems = [ "Corpo como território de conhecimento (presença e intencionalidade)", "Currículo Essencial (problematização)", "Conhecimento como acontecimento (ação e cooperação)", "Cartografia do cotidiano (reflexão e documentação)", "Ética da presença (cuidado)", ]; const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; return (
{/* overlay branco semi-transparente */}
{/* conteúdo centralizado */}

Nosso jeito de fazer

Aula como experiência

Por que eu quero viver isso?

Aprendizagem por meio de projetos de indagação

{" "} O que podemos aprender juntos?


Pesquisa etnográfica

Que atitude de escuta cultivamos para compreender a cultura da escola?{" "}

Pedagogia Viva:
Rotina estruturante

    {routineItems.map((item) => (
  • {item}
  • ))}
); }; const portfolioData: PortfolioItem[] = [ { title: "Marcenaria", folder: "marcenaria", images: [ "IMG_3203.png", "IMG_1809.jpeg", "IMG_1810.jpeg", "IMG_1835.jpeg", "IMG_1836.jpeg", "IMG_1837.jpeg", ], tooltip: null, }, { title: "Circo", folder: "circo", images: [ "IMG_3200.png", "IMG_1813.jpeg", "IMG_1839.jpeg", "IMG_1840.jpeg", "IMG_1841.jpeg", "IMG_1842.jpeg", "IMG_1843.jpeg", "IMG_1844.jpeg", "bc110c9c-a8e1-452a-94b7-5a0c6ce0d3b8.jpeg", "e3b3b2a3-a15e-4e24-be2f-b529a24e3a60.jpeg", "f80d9019-6851-4b2f-af19-5a8dd0edcaf7.jpeg", ], tooltip: null, }, { title: "Fazeres Manuais", folder: "fazeresmanuais", images: [ "IMG_3198.png", "82d08da1-ed2c-4bfd-908a-4b6e75999604.jpeg", "IMG_1822.jpeg", "IMG_1846.jpeg", "IMG_1847.jpeg", "IMG_1848.jpeg", "IMG_1849.jpeg", "IMG_1850.jpeg", "IMG_1851.jpeg", "IMG_1852.jpeg", "IMG_1853.jpeg", ], tooltip: null, }, { title: "Tecnologia", folder: "tecnologia", images: [ "IMG_3199.png", "IMG_1807.jpeg", "IMG_1808.jpeg", "IMG_1894.jpeg", "IMG_1895.jpeg", "IMG_1896.jpeg", "IMG_1897.jpeg", "IMG_1898.jpeg", "IMG_1899.jpeg", "IMG_1900.jpeg", "IMG_1901.jpeg", "IMG_1902.jpeg", "IMG_1903.jpeg", "IMG_1904.jpeg", "IMG_1905.jpeg", "IMG_1906.jpeg", ], tooltip: null, }, { title: "CidadeVamos", folder: "cidadevamos", images: [ "IMG_3201.png", "IMG_1948.jpeg", "IMG_1912.jpeg", "IMG_1913.jpeg", "IMG_1914.jpeg", "IMG_1915.jpeg", "IMG_1916.jpeg", "IMG_1917.jpeg", "IMG_1918.jpeg", "IMG_1919.jpeg", "IMG_1920.jpeg", "IMG_1921.jpeg", "IMG_1922.jpeg", "IMG_1923.jpeg", "IMG_1924.jpeg", "IMG_1925.jpeg", "IMG_1926.jpeg", ], tooltip: null, }, // { // title: "Infância Sem Excesso", // folder: "infanciasemexcesso", // images: [ // "IMG_3202.png", // "IMG_1944.jpeg", // "IMG_1946.jpeg", // "IMG_1930.jpeg", // "IMG_1931.jpeg", // "IMG_1932.jpeg", // "IMG_1933.jpeg", // "IMG_1934.jpeg", // "IMG_1937.jpeg", // "IMG_1938.jpeg", // "IMG_1939.jpeg", // "IMG_1940.jpeg", // "IMG_1941.jpeg", // "IMG_1942.jpeg", // "IMG_1936.jpeg", // "IMG_1945.jpeg", // "IMG_1927.jpeg", // "IMG_1935.jpeg", // "IMG_1928.jpeg", // "IMG_1929.jpeg", // ], // tooltip: null, // }, { title: "Prática Esportiva", folder: "praticaesportiva", images: [ "IMG_3197.png", "IMG_1907.jpeg", "IMG_1908.jpeg", "IMG_1910.jpeg", "IMG_1911.jpeg", "IMG_1969.jpeg", "IMG_1970.jpeg", "IMG_1971.jpeg", "IMG_1972.jpeg", "IMG_1973.jpeg", "IMG_1974.jpeg", "IMG_1975.jpeg", "IMG_1976.jpeg", "IMG_1977.jpeg", "IMG_1978.jpeg", ], tooltip: null, }, // { // title: "Brincar Livre", // folder: "brincarlivre", // images: [ // "IMG_3204.png", // "IMG_1801.jpeg", // "IMG_1804.jpeg", // "IMG_1811.jpeg", // "IMG_1830.jpeg", // "IMG_1831.jpeg", // "IMG_1832.jpeg", // "IMG_1979.jpeg", // "IMG_1980.jpeg", // "IMG_1981.jpeg", // "IMG_1982.jpeg", // "IMG_1983.jpeg", // "IMG_1984.jpeg", // "IMG_1985.jpeg", // "IMG_1986.jpeg", // "IMG_1987.jpeg", // "IMG_1988.jpeg", // ], // tooltip: null, // }, { title: "Mindfulness", folder: "mindfulness", images: [ "IMG_3196.png", "4f98ae78-9869-4179-95df-93919ee1616f.jpeg", "87b6d7f1-94a9-4b8e-adfd-5b0bda9ff2e0.jpeg", "IMG_1812.jpeg", "IMG_1854.jpeg", "IMG_1855.jpeg", "IMG_1857.jpeg", ], tooltip: null, }, { title: "Ateliês", folder: "atelie", images: [ "IMG_3204.png", "IMG_1820.jpeg", "IMG_1861.jpeg", "IMG_1862.jpeg", "IMG_1863.jpeg", "IMG_1865.jpeg", "IMG_1866.jpeg", "IMG_1867.jpeg", "IMG_1868.jpeg", "IMG_1869.jpeg", "IMG_1870.jpeg", "IMG_1871.jpeg", "IMG_1872.jpeg", "CrioLivros1.jpg", "CrioLivros2.jpg", "CrioLivros3.jpg", "CrioLivros4.jpg", "CrioLivros5.jpg", "IMG_1873.jpeg", "IMG_1874.jpeg", "IMG_1875.jpeg", "IMG_1881.jpeg", "IMG_1883.jpeg", "IMG_1884.jpeg", "IMG_1885.jpeg", "IMG_1886.jpeg", "IMG_1887.jpeg", "IMG_1888.jpeg", "IMG_1890.jpeg", "IMG_1891.jpeg", "IMG_1962.jpeg", "IMG_1963.jpeg", "IMG_1964.jpeg", "IMG_1965.jpeg", "IMG_1966.jpeg", "IMG_3195.jpeg", "fa97fcb7-9657-435d-8e72-e67d85f09b8b.jpeg", ], tooltip: null, }, { title: "Drone Educativo", folder: "droneeducativo", images: [ "IMG_1901.jpg", "IMG_1902.jpg", "IMG_1903.jpg", "IMG_1904.jpg", "IMG_1905.jpg", "IMG_1906.jpg", "IMG_1907.jpg", "IMG_1908.jpg", ], tooltip: null, }, { title: "Xadrez", folder: "xadrez", images: [ "IMG_2001.jpg", "IMG_2002.jpg", "IMG_2003.jpg", "IMG_2004.jpg", "IMG_2005.jpg", "IMG_2006.jpg", "IMG_2007.jpg", "IMG_2008.jpg", ], tooltip: null, }, ]; const PortfolioSection: React.FC = ({ selectedItems, onToggleItem, onToggleSelectAll, onDeselectAll, portfolioItemTitles }) => { const [sectionRef, isVisible] = useFadeIn(); const [copyButtonText, setCopyButtonText] = useState('Copiar Link do Diagnóstico'); // Lightbox state const [lightboxState, setLightboxState] = useState(null); const selectAllCheckboxRef = useRef(null); const numSelected = useMemo(() => Object.values(selectedItems).filter(Boolean).length, [selectedItems]); const allSelected = useMemo(() => numSelected > 0 && numSelected === portfolioItemTitles.length, [numSelected, portfolioItemTitles.length]); const isIndeterminate = useMemo(() => numSelected > 0 && numSelected < portfolioItemTitles.length, [numSelected, portfolioItemTitles.length]); useEffect(() => { if (selectAllCheckboxRef.current) { selectAllCheckboxRef.current.indeterminate = isIndeterminate; } }, [isIndeterminate]); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; const handleCopyLink = useCallback(() => { const link = 'https://labirintar.github.io/comercial/diagnostico/formulario.html'; navigator.clipboard.writeText(link).then(() => { setCopyButtonText('Link Copiado!'); setTimeout(() => setCopyButtonText('Copiar Link do Diagnóstico'), 2000); }).catch(err => console.error('Failed to copy link: ', err)); }, []); const basePath = 'https://clubesa.github.io/simuladorRede3d/diagnostico/'; const handleOpenLightbox = useCallback((item: PortfolioItem, imageIndex: number, element: HTMLElement) => { const imageUrls = item.images.map(imgFile => `${basePath}${item.folder}/${imgFile}`); element.style.visibility = 'hidden'; setLightboxState({ images: imageUrls, currentIndex: imageIndex, originElement: element }); }, []); const handleCloseLightbox = useCallback(() => { if (lightboxState) { lightboxState.originElement.style.visibility = 'visible'; } setLightboxState(null); }, [lightboxState]); const handleNextLightboxImage = useCallback(() => { if (lightboxState) { setLightboxState(prev => prev ? ({ ...prev, currentIndex: (prev.currentIndex + 1) % prev.images.length }) : null); } }, [lightboxState]); const handlePrevLightboxImage = useCallback(() => { if (lightboxState) { setLightboxState(prev => prev ? ({ ...prev, currentIndex: (prev.currentIndex - 1 + prev.images.length) % prev.images.length }) : null); } }, [lightboxState]); useEffect(() => { const body = document.body; if (lightboxState) { body.style.overflow = 'hidden'; } else { body.style.overflow = ''; } return () => { body.style.overflow = ''; }; }, [lightboxState]); return (

Experiências

{/*
*/} {/* Card 1: Select All */} {/*

Selecione as experiências que melhor compõem com o projeto pedagógico da sua escola.

*/} {/*portfolioData.map((item) => ( ))*/} {/* Card 3: Info & Deselect All */} {/*

Não sabe quais experiências escolher, entre em contato, pois oferecemos um formulário diagnóstico para mapear os interesses dos alunos.

0} onChange={onDeselectAll} disabled={numSelected === 0} />
*/}

Experiências educativas estruturadas, com intencionalidade clara e coerência com o cotidiano escolar.

{/* Pesquisa Diagnostica

Não tem certeza de quais experiências escolher?

Use nosso formulário de diagnóstico para pesquisar os interesses de alunos e famílias. Copie o link e compartilhe com sua equipe pedagógica.

{lightboxState && ( )}*/}
); }; const PartnershipCard = ({ title, description, border, details, note, activityDuration }: any) => (

{title}

{activityDuration}

{details.map((line: any, index: number) => (

))}

{note}

); const PartnershipSection: React.FC = () => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; return (

Modelo de Parceria

35% Escola', "25% Labirintar", "30% Educador Empreendedor", "10% Provedor Educacional", ]} note="A escola oferece o espaço, a Labirintar faz o resto. Por uma assinatura mensal de R$ 2.000, cuidamos de toda a operação: educadores empreendedores, gestão, curadoria e tecnologia. A escola participa da receita e transforma o extracurricular em fonte de valor, não de custo." />
); }; const SimulatorSection: React.FC = ({ totalAlunos, setTotalAlunos, metaConversao, setMetaConversao, frequenciaSemanal, setFrequenciaSemanal, mensalidadeCurricular, setMensalidadeCurricular, selectedModel, onSelectModel }) => { const [sectionRef, isVisible] = useFadeIn(); const ticketPrices: { [key: number]: number } = { 1: 298, 2: 447, 3: 759, 4: 948, 5: 948 }; const formatCurrency = (value: number) => { if (isNaN(value)) return 'R$ 0,00'; return value.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); }; const totalAlunosNum = Number(totalAlunos) || 0; const mensalidadeCurricularNum = Number(mensalidadeCurricular) || 0; const alunosExtra = useMemo(() => Math.round((totalAlunosNum * metaConversao) / 100), [totalAlunosNum, metaConversao]); const mensalidadeExtra = useMemo(() => ticketPrices[frequenciaSemanal], [frequenciaSemanal]); const percentualCurricular = useMemo(() => { if (!mensalidadeCurricularNum || mensalidadeCurricularNum <= 0) return '-'; return `${((mensalidadeExtra / mensalidadeCurricularNum) * 100).toFixed(1)}%`; }, [mensalidadeExtra, mensalidadeCurricularNum]); const totalRevenue = useMemo(() => alunosExtra * mensalidadeExtra, [alunosExtra, mensalidadeExtra]); const gainModel1 = useMemo(() => totalRevenue * 0.20, [totalRevenue]); const costModel2 = useMemo(() => (mensalidadeCurricularNum > 0 ? mensalidadeCurricularNum : 2000), [mensalidadeCurricularNum]); const gainModel2 = useMemo(() => (totalRevenue * 0.30) - costModel2, [totalRevenue, costModel2]); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; return (

Simule o seu Potencial de Ganho

{/* --- INPUTS --- */}
{/* Total de Alunos */}
setTotalAlunos(e.target.value)} className="w-full p-3 border-2 border-accent-blue rounded-lg text-lg bg-white" />
{/* Meta de Conversão */}
{metaConversao}%
setMetaConversao(Number(e.target.value))} className="w-full h-2 bg-accent-blue rounded-lg appearance-none cursor-pointer thumb:bg-primary" />
{/* Alunos no Extra */}
{/* Frequência Semanal */}
{frequenciaSemanal}x / semana
setFrequenciaSemanal(Number(e.target.value))} className="w-full h-2 bg-accent-blue rounded-lg appearance-none cursor-pointer" />
{/* Financial Comparison */}
setMensalidadeCurricular(e.target.value)} className="w-full p-3 border-2 border-accent-blue rounded-lg text-lg bg-white" />
{/* --- RESULTS --- */} {alunosExtra > 0 && (

Ganho com Modelo 1 (Split)

{formatCurrency(gainModel1)}

20% da receita total de {formatCurrency(totalRevenue)}

onSelectModel(e.target.value)} className="w-5 h-5 accent-primary cursor-pointer" />

Ganho com Modelo 2 (Assinatura)

{formatCurrency(gainModel2)}

30% ({formatCurrency(totalRevenue * 0.4)}) - Assinatura ({formatCurrency(costModel2)})

onSelectModel(e.target.value)} className="w-5 h-5 accent-primary cursor-pointer" />
)}
); }; const benefits = [ { id: 'b1', value: 'Novas receitas', label: 'Receita recorrente com previsibilidade, sem criar uma nova operação interna' }, { id: 'b2', value: 'Ocupação de espaços', label: 'Uso inteligente dos espaços, transformando ociosidade em valor educativo' }, { id: 'b3', value: 'Aumento de matrículas', label: 'Aumento de matrículas e retenção, por diferenciação real no projeto pedagógico' }, { id: 'b4', value: 'Educação Integral', label: 'Alinhamento com a Educação Integral, na prática, não só no discurso' }, { id: 'b5', value: 'Simplificação da gestão', label: 'Gestão do contraturno simplificada, com menos sobrecarga da coordenação' }, { id: 'b6', value: 'Reputação de inovação', label: 'Fortalecimento da reputação de inovação, com coerência e consistência' }, { id: 'b7', value: 'Engajamento das famílias', label: 'Mais engajamento das famílias, por experiências que fazem sentido no tempo' }, ]; const BenefitsSection: React.FC = ({ selectedBenefits, onToggleBenefit }) => { const [sectionRef, isVisible] = useFadeIn(); const getFadeInClass = (isVisible: boolean) => `transition-all duration-1000 ease-out ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`; return (
{/* overlay para legibilidade */}
{/* conteúdo centralizado */}

O que sua escola ganha ao organizar o Tempo Integral como sistema?

Quando o contraturno deixa de ser um conjunto de atividades isoladas e passa a ser organizado como um sistema educativo, a escola ganha:

{benefits.map(benefit => (
onToggleBenefit(benefit.id)} />
))}
); }; const Footer: React.FC = ({ onOpenModal, isFormValid }) => { const [formData, setFormData] = useState({ name: '', email: '', phone: '', role: '', school: '' }); const [isSubmitting, setIsSubmitting] = useState(false); const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; if (name === 'phone') { setFormData(prev => ({ ...prev, [name]: formatPhoneNumber(value) })); } else { setFormData(prev => ({ ...prev, [name]: value })); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!validatePhoneNumber(formData.phone)) { alert('Por favor, insira um telefone válido no formato (00) 99999-9999'); return; } setIsSubmitting(true); try { const response = await fetch('https://script.google.com/macros/s/AKfycbwgfSc9VBe2FViJNYVCDiiWGHm_4cl3f9zSLsTCo4ZKNjieMwiJJbxjIXiXopgiHR3C/exec', { method: 'POST', mode: 'no-cors', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ action: 'contact', timestamp: new Date().toISOString(), ...formData }) }); alert('Mensagem enviada com sucesso! Nossa equipe entrará em contato em breve.'); setFormData({ name: '', email: '', phone: '', role: '', school: '' }); } catch (error) { console.error('Erro ao enviar formulário:', error); alert('Erro ao enviar mensagem. Por favor, tente novamente.'); } finally { setIsSubmitting(false); } }; const handleButtonClick = () => { if (!isFormValid) { alert('Preencha os campos acima corretamente para conseguir clicar nesse botão.'); return; } onOpenModal(); }; return (

Vamos organizar juntos o Tempo Integral da sua escola?

Preencha seus dados e nossa equipe entra em contato para compreender o contexto da sua instituição e desenhar uma proposta alinhada ao seu projeto pedagógico.

); }; // Função para formatar telefone brasileiro const formatPhoneNumber = (value: string): string => { // Remove tudo que não é número const numbers = value.replace(/\D/g, ''); // Limita a 11 dígitos (DDD + 9 dígitos) const limitedNumbers = numbers.slice(0, 11); // Aplica a máscara if (limitedNumbers.length <= 2) { return `(${limitedNumbers}`; } else if (limitedNumbers.length <= 7) { return `(${limitedNumbers.slice(0, 2)}) ${limitedNumbers.slice(2)}`; } else { return `(${limitedNumbers.slice(0, 2)}) ${limitedNumbers.slice(2, 7)}-${limitedNumbers.slice(7)}`; } }; // Função para validar telefone brasileiro const validatePhoneNumber = (value: string): boolean => { const numbers = value.replace(/\D/g, ''); // Deve ter 10 ou 11 dígitos (com ou sem o 9) return numbers.length >= 10 && numbers.length <= 11; }; const InputGroup: React.FC<{ label: string; id: string; name: string; type?: string; placeholder?: string; required?: boolean; value: string; onChange: (e: React.ChangeEvent) => void; isPhone?: boolean; }> = ({ label, id, name, type = 'text', placeholder, required = true, value, onChange, isPhone = false }) => { const handleChange = (e: React.ChangeEvent) => { if (isPhone) { const formattedValue = formatPhoneNumber(e.target.value); e.target.value = formattedValue; } onChange(e); }; return (
); }; const ContactModal: React.FC = ({ isOpen, onClose, contactData, onContactDataChange, onSubmit }) => { if (!isOpen) return null; return (
e.stopPropagation()} // Prevent closing when clicking inside >

Informações de Contato

Deixe seus dados para que nossa equipe possa retornar.

{ e.preventDefault(); onSubmit(); }}>
); }; // ================================================================================================= // MAIN APP COMPONENT // ================================================================================================= const APPS_SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbwgfSc9VBe2FViJNYVCDiiWGHm_4cl3f9zSLsTCo4ZKNjieMwiJJbxjIXiXopgiHR3C/exec'; const App: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const debounceTimer = useRef(null); const sessionId = useRef(null); // --- State for all form fields --- const [rankings, setRankings] = useState>({ diferenciar: '', reter: '', espacos: '', }); const [openChallenge, setOpenChallenge] = useState(''); const [selectedExperiences, setSelectedExperiences] = useState>({}); const [selectedPartnershipModel, setSelectedPartnershipModel] = useState(''); const [selectedBenefits, setSelectedBenefits] = useState>({}); const [simTotalAlunos, setSimTotalAlunos] = useState(''); const [simMetaConversao, setSimMetaConversao] = useState(10); const [simFrequenciaSemanal, setSimFrequenciaSemanal] = useState(2); const [simMensalidadeCurricular, setSimMensalidadeCurricular] = useState(''); const [contactData, setContactData] = useState({ name: '', email: '', phone: '', role: '', school: '' }); // --- Enable smooth scrolling globally --- useEffect(() => { document.documentElement.style.scrollBehavior = 'smooth'; return () => { document.documentElement.style.scrollBehavior = 'auto'; }; }, []); // --- Generate unique session ID on first load --- useEffect(() => { if (!sessionId.current) { sessionId.current = crypto.randomUUID(); } }, []); // --- Calculated values from simulator --- const { alunosExtra, mensalidadeExtra, percentualCurricular, totalRevenue, gainModel1, gainModel2 } = useMemo(() => { const ticketPrices: { [key: number]: number } = { 1: 298, 2: 447, 3: 759, 4: 948, 5: 948 }; const totalAlunosNum = Number(simTotalAlunos) || 0; const mensalidadeCurricularNum = Number(simMensalidadeCurricular) || 0; const alunosExtra = Math.round((totalAlunosNum * simMetaConversao) / 100); const mensalidadeExtra = ticketPrices[simFrequenciaSemanal]; const percentualCurricular = (!mensalidadeCurricularNum || mensalidadeCurricularNum <= 0) ? '-' : `${((mensalidadeExtra / mensalidadeCurricularNum) * 100).toFixed(1)}%`; const totalRevenue = alunosExtra * mensalidadeExtra; const gainModel1 = totalRevenue * 0.20; const costModel2 = (mensalidadeCurricularNum > 0 ? mensalidadeCurricularNum : 2000); const gainModel2 = (totalRevenue * 0.30) - costModel2; return { alunosExtra, mensalidadeExtra, percentualCurricular, totalRevenue, gainModel1, gainModel2 }; }, [simTotalAlunos, simMetaConversao, simFrequenciaSemanal, simMensalidadeCurricular]); const portfolioItemTitles = useMemo(() => portfolioData.map(item => item.title), []); const isFormValid = useMemo(() => { const isProblemSectionValid = Object.values(rankings).every(r => r !== '') && openChallenge.trim() !== ''; const isPortfolioSectionValid = Object.values(selectedExperiences).some(v => v); const isPartnershipSectionValid = selectedPartnershipModel !== ''; const isBenefitsSectionValid = Object.values(selectedBenefits).some(v => v); const isSimulatorValid = simTotalAlunos.trim() !== '' && simMensalidadeCurricular.trim() !== ''; return isProblemSectionValid && isPortfolioSectionValid && isPartnershipSectionValid && isBenefitsSectionValid && isSimulatorValid; }, [rankings, openChallenge, selectedExperiences, selectedPartnershipModel, selectedBenefits, simTotalAlunos, simMensalidadeCurricular]); // --- Data Syncing with Google Sheets --- const syncDataWithSheet = useCallback(() => { if (!APPS_SCRIPT_URL.startsWith('https://')) { console.warn('APPS_SCRIPT_URL is not set. Data will not be saved.'); return; } const fullFormData = { SessionID: sessionId.current, Timestamp: new Date().toISOString(), ContatoNome: contactData.name, ContatoEmail: contactData.email, ContatoTelefone: contactData.phone, ContatoCargo: contactData.role, ContatoEscola: contactData.school, RankingDiferenciar: rankings.diferenciar, RankingReter: rankings.reter, RankingEspacos: rankings.espacos, DesafioAberto: openChallenge, ExperienciasSelecionadas: Object.keys(selectedExperiences).filter(k => selectedExperiences[k]).join(', '), SimuladorTotalAlunos: simTotalAlunos, SimuladorMetaConversao: simMetaConversao, SimuladorFrequenciaSemanal: simFrequenciaSemanal, SimuladorMensalidadeCurricular: simMensalidadeCurricular, CalculadoAlunosExtra: alunosExtra, CalculadoMensalidadeExtra: mensalidadeExtra, CalculadoPercentualCurricular: percentualCurricular, CalculadoReceitaTotal: totalRevenue, CalculadoGanhoModelo1: gainModel1, CalculadoGanhoModelo2: gainModel2, ModeloParceriaSelecionado: selectedPartnershipModel, BeneficiosSelecionados: Object.keys(selectedBenefits).filter(k => selectedBenefits[k]).map(id => benefits.find(b => b.id === id)?.label || '').join(', '), }; fetch(APPS_SCRIPT_URL, { method: 'POST', body: JSON.stringify(fullFormData), headers: { 'Content-Type': 'text/plain;charset=utf-8', }, }) .then(response => response.json()) .then(data => console.log('Sync success:', data)) .catch(error => console.error('Sync error:', error)); }, [ contactData, rankings, openChallenge, selectedExperiences, simTotalAlunos, simMetaConversao, simFrequenciaSemanal, simMensalidadeCurricular, selectedPartnershipModel, selectedBenefits, alunosExtra, mensalidadeExtra, percentualCurricular, totalRevenue, gainModel1, gainModel2 ]); // Debounced useEffect to sync data on any change /*useEffect(() => { if (debounceTimer.current) { clearTimeout(debounceTimer.current); } debounceTimer.current = window.setTimeout(() => { syncDataWithSheet(); }, 1500); // Wait 1.5s after user stops typing return () => { if (debounceTimer.current) { clearTimeout(debounceTimer.current); } }; }, [syncDataWithSheet]);*/ const handleToggleExperience = useCallback((title: string) => { setSelectedExperiences(prev => ({ ...prev, [title]: !prev[title] })); }, []); const handleToggleSelectAllExperiences = useCallback(() => { const numSelected = Object.values(selectedExperiences).filter(Boolean).length; const allSelected = numSelected === portfolioItemTitles.length; const newSelectedItems: Record = {}; if (!allSelected) { portfolioItemTitles.forEach(title => { newSelectedItems[title] = true; }); } setSelectedExperiences(newSelectedItems); }, [selectedExperiences, portfolioItemTitles]); const handleDeselectAllExperiences = useCallback(() => { setSelectedExperiences({}); }, []); const handleToggleBenefit = useCallback((id: string) => { setSelectedBenefits(prev => ({ ...prev, [id]: !prev[id] })); }, []); const handleContactDataChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setContactData(prev => ({ ...prev, [name]: value })); }; const handleOpenModal = useCallback(() => setIsModalOpen(true), []); const handleCloseModal = useCallback(() => setIsModalOpen(false), []); const handleFinalSubmit = () => { // Validar telefone antes de enviar if (!validatePhoneNumber(contactData.phone)) { alert("Por favor, insira um telefone válido no formato (00) 99999-9999"); return; } // Final sync before submission syncDataWithSheet(); alert("Obrigado! Suas respostas foram enviadas com sucesso."); handleCloseModal(); // Reset all state setRankings({ diferenciar: '', reter: '', espacos: '' }); setOpenChallenge(''); setSelectedExperiences({}); setSelectedPartnershipModel(''); setSelectedBenefits({}); setSimTotalAlunos(''); setSimMetaConversao(10); setSimFrequenciaSemanal(2); setSimMensalidadeCurricular(''); setContactData({ name: '', email: '', phone: '', role: '', school: '' }); // Optional: Reload to start a fresh session // window.location.reload(); }; return (
{/* */} {/* */} {/* */}
); }; const root = ReactDOM.createRoot(document.getElementById('root')!); root.render();