import React, { useState, useEffect, useRef, useCallback } from "react"; /* ============================================================ NIGHTINGALE EDUCATIONAL TRUST — portfolio site + admin panel Design: "dawn chorus" — deep dusk teal fading to sunrise gold, a nightingale drawn across a music-staff branch as the signature motif (ties to the school's real anthem "Nightingale ke Sitare"). Trust objectives use a numbered list because a trust deed's objectives genuinely are an enumerated clause. ============================================================ */ const STORAGE_KEY = "site-content"; const ADMIN_KEY_STORE = "admin-password"; const DEFAULT_ADMIN_PASSWORD = "nightingale2026"; const DEFAULT_DATA = { trustName: "NIGHTINGALE EDUCATIONAL TRUST", shortName: "Nightingale Trust", tagline: "Nurturing every voice, since 2003.", established: "2003", regLine: "A registered charitable education trust · Uluberia, Howrah", logoUrl: "", navLinks: [ { label: "Home", page: "home" }, { label: "About the Trust", page: "about" }, { label: "Gallery", page: "gallery" }, { label: "Contact", page: "contact" }, ], heroEyebrow: "Est. 2003 · Rajkhola, Uluberia", heroHeading: "A trust built on English, computers, and one small bird's idea of courage.", heroBody: "Nightingale Educational Trust runs Nightingale Nursery, Uluberia's CBSE school for English & computer-based learning — and everything the trust does grows from the same conviction: every child deserves a clear, confident voice.", aboutHeading: "Our story", aboutBody: "Nightingale Educational Trust was formed to give Uluberia a school that took English fluency and computer literacy seriously from the very first classroom. What began as a single nursery on Rajkhola Road has grown into a small community of students, teachers, and families who return every year for the annual function, the sports season, and the songs the children write themselves. The trust exists to keep that growing — responsibly, and for more children each year.", objectives: [ "To establish, run, and manage educational institutions imparting quality education from pre-primary to secondary level.", "To promote English-medium and computer-based learning accessible to children of Uluberia and the surrounding areas.", "To provide scholarships, study materials, and financial assistance to meritorious and underprivileged students.", "To organise co-curricular, cultural, and sports activities for the holistic development of every child.", "To conduct teacher-training programmes and community welfare initiatives in the field of education.", ], trustees: [ { name: "Add trustee name", role: "Managing Trustee" }, { name: "Add trustee name", role: "Trustee, Academics" }, { name: "Add trustee name", role: "Trustee, Finance" }, ], gallery: [ { url: "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdnAmjJGIs9yw1xyIMOjYiDYE5urRkTki7rGeri2aB77UaZOeqGG8Buy-WXIh2Z8_ItIhNd5cwZQ71pJv5NDR1qhl5_Y-rvCKkuGoX3Ek1GaGmbpEWakotQxjWlemZcEfxMmzOzxMotSl6OhScDvfTQ0wEBBggZ2STKNgLOAXPMCfc6JXvzT5sVTsiz4qs/s1280/Yellow%20and%20White%20Simple%20Classroom%20Zoom%20Meet%20Zoom%20Virtual%20Background_20240715_232818_0000.png", caption: "Classroom life at Nightingale Nursery", }, { url: "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR9ddKlKNeKyk19FMZ_3zsmWr4SP_vcAZ1xqHr8IvfJDdhqf-C_gLtpYUSxHv1CED23R-Ln5F4P7UExcFRlzUDl_FdObu_XicldI0Q2GS3VGHjBUZAVf4hTTv5TXJum7bUxopXxFdgRpJcsMKJwgF6nccAXH29ONwS4cdZCzINA9X0LlaflTecVPXraQ/s1280/IMG-20250328-WA0003.jpg", caption: "Students at a school event", }, { url: "https://blogger.googleusercontent.com/img/a/AVvXsEhQ-L7ul2vZsW_Aq5UlF-49f_BOEMvGrdTjyzwSyqPrNbjnFQXzjK5v-2ZoMskJG9L_s6DBn8aEk0VB0f7lqc4PuPQjWHjN3zqxWF3UHiuvKObFbtzhW_UKnYuR-xOiBb5oH6JxMMXlUSputy9AW7DR_Z_cPTySAq5a2httN1FHKqUGL7Q0EeCfxe23=s530", caption: "Practical science class", }, { url: "https://blogger.googleusercontent.com/img/a/AVvXsEh9IWIAYh_tKLAs5Vxf9RhQTZfAVrSKEgsjfW6krNTGPP_yA3cQwNgixjjQD0b8b35oCinyoIYRNOJLQgQJ7Xw2DUSgjtmWgvTG7Z9ZHkmTaV40HBla2Qe6wircqtT-cWDXQqfBCRbFu__HQfcDxH5wwKjGxC2zvsVcseP_XYNokF8_-gJfVEk3d0Ew=s662", caption: "A page from the school's Daily Diary", }, ], contact: { address: "Nightingale Nursery, Rajkhola, Uluberia, Howrah, West Bengal 711316", whatsapp: "+91 98741 92235", email: "info@nightingalenursery.in", website: "nightingalenursery.in", }, footerText: "Nightingale Educational Trust is the parent body of Nightingale Nursery, Uluberia.", }; /* ---------------- storage helpers ---------------- */ async function loadSite() { try { const res = await window.storage.get(STORAGE_KEY, true); if (res && res.value) return JSON.parse(res.value); } catch (e) { /* not found yet */ } return null; } async function saveSite(data) { await window.storage.set(STORAGE_KEY, JSON.stringify(data), true); } async function loadAdminPassword() { try { const res = await window.storage.get(ADMIN_KEY_STORE, true); if (res && res.value) return res.value; } catch (e) { /* not found yet */ } return null; } async function saveAdminPassword(pw) { await window.storage.set(ADMIN_KEY_STORE, pw, true); } /* ---------------- scroll reveal hook ---------------- */ function useReveal() { const ref = useRef(null); const [shown, setShown] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; const obs = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setShown(true); obs.disconnect(); } }, { threshold: 0.15 } ); obs.observe(el); return () => obs.disconnect(); }, []); return [ref, shown]; } function Reveal({ children, className = "", delay = 0 }) { const [ref, shown] = useReveal(); return (
{children}
); } /* ---------------- nightingale signature SVG ---------------- */ function NightingaleMark({ animate = true, className = "" }) { return ( {/* staff / branch lines */} {/* bird body */} ); } /* ============================================================ PUBLIC SITE ============================================================ */ function Header({ data, page, setPage, setAdminOpen }) { const [open, setOpen] = useState(false); return (
); } function Hero({ data }) { return (
); } function QuickFacts({ data }) { const facts = [ { label: "Established", value: data.established }, { label: "Location", value: "Uluberia, Howrah" }, { label: "Medium", value: "English & Computer-based" }, { label: "Runs", value: "Nightingale Nursery (CBSE)" }, ]; return (
{facts.map((f, i) => (

{f.label}

{f.value}

))}
); } function HomePage({ data, setPage }) { return ( <>

About the trust

{data.aboutHeading}

{data.aboutBody}

A glimpse

From the school

{data.gallery.slice(0, 3).map((g, i) => (
{g.caption}
{g.caption}
))}
); } function AboutPage({ data }) { return (

Est. {data.established}

{data.trustName}

{data.aboutBody}

Objectives of the trust

    {data.objectives.map((o, i) => (
  1. {String(i + 1).padStart(2, "0")} {o}
  2. ))}

Board of trustees

{data.trustees.map((t, i) => (

{t.name}

{t.role}

))}
); } function GalleryPage({ data }) { return (

Gallery

Moments from Nightingale

{data.gallery.map((g, i) => (
{g.caption}
{g.caption}
))} {data.gallery.length === 0 && (

No photos yet — add some from the admin panel.

)}
); } function ContactPage({ data }) { const c = data.contact; const waLink = `https://wa.me/${c.whatsapp.replace(/[^\d]/g, "")}`; return (

Get in touch

Contact the trust

Address

{c.address}

WhatsApp

{c.whatsapp}

Message on WhatsApp →

Email

{c.email}

Website

{c.website}

); } function Footer({ data, setPage }) { return (

{data.shortName}

{data.footerText}

{data.navLinks.map((l) => ( ))}

© {new Date().getFullYear()} {data.trustName}. All rights reserved.

); } /* ============================================================ ADMIN PANEL ============================================================ */ function AdminPanel({ data, setData, onClose, adminPassword, setAdminPassword }) { const [authed, setAuthed] = useState(false); const [pwInput, setPwInput] = useState(""); const [pwError, setPwError] = useState(""); const [draft, setDraft] = useState(data); const [tab, setTab] = useState("header"); const [status, setStatus] = useState(""); useEffect(() => setDraft(data), [data]); function tryLogin(e) { e.preventDefault(); if (pwInput === adminPassword) { setAuthed(true); setPwError(""); } else { setPwError("Wrong password. Try again."); } } async function persist(next) { setDraft(next); setData(next); await saveSite(next); setStatus("Saved."); setTimeout(() => setStatus(""), 1500); } function updateField(path, value) { const next = { ...draft }; let obj = next; for (let i = 0; i < path.length - 1; i++) obj = obj[path[i]]; obj[path[path.length - 1]] = value; persist(next); } function updateListItem(listKey, idx, field, value) { const next = { ...draft }; const list = [...next[listKey]]; if (field === null) { list[idx] = value; } else { list[idx] = { ...list[idx], [field]: value }; } next[listKey] = list; persist(next); } function addListItem(listKey, blank) { const next = { ...draft }; next[listKey] = [...next[listKey], blank]; persist(next); } function removeListItem(listKey, idx) { const next = { ...draft }; next[listKey] = next[listKey].filter((_, i) => i !== idx); persist(next); } if (!authed) { return (

Admin access

Sign in to edit the site

setPwInput(e.target.value)} className="admin-input" autoFocus /> {pwError &&

{pwError}

}

Default password: {DEFAULT_ADMIN_PASSWORD}

); } const tabs = [ { id: "header", label: "Header & Logo" }, { id: "hero", label: "Home / Hero" }, { id: "about", label: "About & Objectives" }, { id: "trustees", label: "Trustees" }, { id: "gallery", label: "Gallery" }, { id: "contact", label: "Contact" }, { id: "footer", label: "Footer" }, { id: "security", label: "Password" }, ]; return (

Editing {draft.shortName}

{status && {status}}
{tab === "header" && (
updateField(["trustName"], e.target.value)} /> updateField(["shortName"], e.target.value)} /> updateField(["logoUrl"], e.target.value)} /> {draft.navLinks.map((l, i) => (
updateListItem("navLinks", i, "label", e.target.value)} placeholder="Label" />
))}
)} {tab === "hero" && (
updateField(["heroEyebrow"], e.target.value)} />