/* ========================================================= SIKOHOME ONBOARDING, PASSWORD RECOVERY & CELEBRATIONS Corrected extension — version 1.3 Replace the previous SIKOHOME extension with this version. ========================================================= */ (() => { "use strict"; const PRIVACY_VERSION = "1.0"; const STORAGE_KEY = "sikohome_privacy_consent"; /* ---------- SAFETY CHECKS ---------- */ if (typeof db === "undefined" || !db || !db.auth) { console.error("SIKOHOME: Supabase is not initialized."); return; } if (document.getElementById("sikoIntro")) { console.warn("SIKOHOME extension is already installed."); return; } const $ = id => document.getElementById(id); function message(text, type = "info") { if (typeof showAuthMessage === "function") { showAuthMessage(text, type); } else { alert(text); } } function getCurrentUser() { return typeof currentUser !== "undefined" ? currentUser : null; } /* ---------- STYLES ---------- */ const style = document.createElement("style"); style.textContent = ` .siko-overlay { position:fixed; inset:0; z-index:500; display:none; align-items:center; justify-content:center; padding:20px; background:#08090c; box-sizing:border-box; } .siko-overlay.visible { display:flex; } .siko-intro { overflow:hidden; text-align:center; } .siko-intro-bg { position:absolute; inset:0; background-size:cover; background-position:center; opacity:.65; transition:opacity 1s ease; } .siko-intro:after { content:""; position:absolute; inset:0; background:linear-gradient( 0deg, #08090c 4%, #08090c99 70%, #08090c55 ); } .siko-intro-content { position:relative; z-index:2; max-width:650px; } .siko-intro-logo { font-size:30px; font-weight:800; letter-spacing:3px; } .siko-intro-logo span { color:#ff4655; } .siko-intro-content h1 { font-family:'Playfair Display',serif; font-size:clamp(38px,8vw,66px); line-height:1.1; margin:25px 0 14px; } .siko-intro-content p { color:#d0d0d5; font-size:14px; line-height:1.8; } .siko-dots { display:flex; justify-content:center; gap:8px; margin:25px; } .siko-dot { width:7px; height:7px; border-radius:10px; background:#777; } .siko-dot.active { width:22px; background:#ff4655; } .siko-panel { width:min(650px,100%); max-height:90vh; overflow:auto; padding:25px; background:#111319; border:1px solid #ffffff18; border-radius:15px; box-sizing:border-box; } .siko-panel h2 { font-size:23px; margin-bottom:12px; } .siko-panel h3 { font-size:14px; margin:18px 0 7px; } .siko-panel p, .siko-panel li { color:#b9bbc3; font-size:12px; line-height:1.8; } .siko-panel ul { padding-left:20px; } .siko-panel button { margin-top:12px; } .siko-panel button:disabled { opacity:.4; cursor:not-allowed; } .siko-consent { display:flex; gap:10px; align-items:flex-start; padding:15px 0; margin-top:15px; border-top:1px solid #ffffff18; font-size:12px; line-height:1.6; } .siko-consent input { accent-color:#ff4655; width:17px; height:17px; flex-shrink:0; } .siko-forgot { display:block; margin:8px 0 13px auto; padding:5px 0; border:0; background:transparent; color:#ff4655; font-size:11px; font-weight:700; cursor:pointer; } .siko-forgot:disabled { opacity:.5; } .siko-recovery { z-index:520; } .siko-recovery input { display:block; width:100%; padding:12px; margin-top:12px; border-radius:8px; border:1px solid #ffffff25; background:#08090c; color:white; box-sizing:border-box; } .siko-recovery .primary-btn { width:100%; justify-content:center; } .siko-status { margin-top:12px; font-size:12px; line-height:1.6; color:#ffb9bf; } .siko-celebration { display:none; margin-bottom:22px; padding:19px; border:1px solid #d9273666; border-radius:13px; background:linear-gradient(110deg,#35131b,#17121b); } .siko-celebration.visible { display:block; } .siko-celebration h2 { font-family:'Playfair Display',serif; font-size:22px; margin-bottom:7px; } .siko-celebration p { color:#d0c5c8; font-size:12px; line-height:1.7; } @media(max-width:480px) { .siko-panel { padding:19px; } .siko-intro-content h1 { font-size:40px; } } `; document.head.appendChild(style); /* ---------- WELCOME SCREEN ---------- */ const intro = document.createElement("div"); intro.id = "sikoIntro"; intro.className = "siko-overlay siko-intro"; intro.innerHTML = `
AFRICAN CINEMA • GLOBAL STORIES

Africa has stories
worth sharing.

Discover films, meet creative talent and find opportunities across the African film industry.

`; document.body.appendChild(intro); /* ---------- PRIVACY SCREEN ---------- */ const privacy = document.createElement("div"); privacy.id = "sikoPrivacy"; privacy.className = "siko-overlay"; privacy.innerHTML = `
BEFORE YOU JOIN

Privacy and Terms

Please review these initial platform terms.

1. Information we collect

SIKOHOME may collect your name, email, phone number, country and account preferences.

2. How information is used

Information is used to manage your account, personalise your experience and provide selected updates.

3. Public profiles

Information you choose to publish in creator profiles, portfolios or posts may be visible to other users.

4. Third-party services

SIKOHOME uses third-party infrastructure, including Supabase. No online service can guarantee absolute security.

5. Copyright and conduct

Users must respect copyright, privacy and applicable laws. Do not upload or distribute content without the necessary rights.

6. Your choices

You may choose not to register. Contact and data deletion procedures must be provided in the complete published policy.

`; document.body.appendChild(privacy); /* ---------- PASSWORD RECOVERY SCREEN ---------- */ const recovery = document.createElement("div"); recovery.id = "sikoRecovery"; recovery.className = "siko-overlay siko-recovery"; recovery.innerHTML = `
ACCOUNT SECURITY

Choose a new password

Enter your new password twice.

`; document.body.appendChild(recovery); /* ---------- WELCOME SLIDESHOW ---------- */ const slides = [ "https://images.unsplash.com/photo-1489599849927-2ee91cede3ba?auto=format&fit=crop&w=1800&q=85", "https://images.unsplash.com/photo-1519608487953-e999c86e7455?auto=format&fit=crop&w=1800&q=85", "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=1800&q=85" ]; let slideIndex = 0; let slideTimer = null; let slideFadeTimer = null; function changeSlide() { const bg = $("sikoIntroBg"); if (!bg) return; bg.style.opacity = "0"; clearTimeout(slideFadeTimer); slideFadeTimer = setTimeout(() => { bg.style.backgroundImage = `url("${slides[slideIndex]}")`; bg.style.opacity = ".65"; document.querySelectorAll(".siko-dot").forEach( (dot, index) => { dot.classList.toggle( "active", index === slideIndex ); } ); slideIndex = (slideIndex + 1) % slides.length; }, 450); } function startSlideshow() { changeSlide(); clearInterval(slideTimer); slideTimer = setInterval(changeSlide, 15000); } function stopSlideshow() { clearInterval(slideTimer); clearTimeout(slideFadeTimer); slideTimer = null; slideFadeTimer = null; } /* ---------- PRIVACY CONSENT ---------- */ function hasConsent() { try { const consent = JSON.parse( localStorage.getItem(STORAGE_KEY) || "null" ); return Boolean( consent && consent.accepted === true && consent.version === PRIVACY_VERSION ); } catch (error) { return false; } } function showIntro() { intro.classList.add("visible"); startSlideshow(); } function continueAfterConsent() { privacy.classList.remove("visible"); stopSlideshow(); const user = getCurrentUser(); if (user) { if (typeof updateAccountDisplay === "function") { updateAccountDisplay(); } } else if (typeof openAuth === "function") { openAuth("signup"); } else { console.error( "SIKOHOME: Authentication screen is unavailable." ); message( "Please refresh the page and try again.", "error" ); } } $("sikoGetStarted").onclick = () => { intro.classList.remove("visible"); privacy.classList.add("visible"); }; $("sikoBack").onclick = () => { privacy.classList.remove("visible"); intro.classList.add("visible"); startSlideshow(); }; $("sikoConsentCheck").onchange = event => { $("sikoAccept").disabled = !event.target.checked; }; $("sikoAccept").onclick = () => { if (!$("sikoConsentCheck").checked) return; try { localStorage.setItem( STORAGE_KEY, JSON.stringify({ accepted: true, version: PRIVACY_VERSION, timestamp: new Date().toISOString() }) ); } catch (error) { message( "Browser storage is unavailable. Enable it to continue.", "error" ); return; } continueAfterConsent(); }; /* ---------- FORGOT PASSWORD ---------- */ function attachForgotPassword() { const passwordField = $("authPassword"); if (!passwordField || !passwordField.parentElement) { return; } if ($("sikoForgot")) return; const forgot = document.createElement("button"); forgot.type = "button"; forgot.id = "sikoForgot"; forgot.className = "siko-forgot"; forgot.textContent = "Forgot password?"; passwordField.parentElement.after(forgot); forgot.onclick = async () => { const emailField = $("authEmail"); const email = emailField ? emailField.value.trim() : ""; if (!email) { message( "Enter your account email address first.", "error" ); return; } forgot.disabled = true; forgot.textContent = "SENDING..."; try { const { error } = await db.auth.resetPasswordForEmail(email, { redirectTo: window.location.origin }); if (error) throw error; message( "If an account exists for this email, a reset link will be sent. Check your inbox.", "success" ); } catch (error) { message( error.message || "Password reset failed.", "error" ); } finally { forgot.disabled = false; forgot.textContent = "Forgot password?"; } }; } /* ---------- PASSWORD UPDATE ---------- */ $("sikoCancelRecovery").onclick = () => { recovery.classList.remove("visible"); }; $("sikoUpdatePassword").onclick = async () => { const first = $("sikoNewPassword").value; const second = $("sikoConfirmPassword").value; const status = $("sikoRecoveryMessage"); const button = $("sikoUpdatePassword"); status.textContent = ""; if (first.length < 6) { status.textContent = "Password must contain at least 6 characters."; return; } if (first !== second) { status.textContent = "The passwords do not match."; return; } button.disabled = true; button.textContent = "UPDATING..."; try { const { error } = await db.auth.updateUser({ password: first }); if (error) throw error; recovery.classList.remove("visible"); $("sikoNewPassword").value = ""; $("sikoConfirmPassword").value = ""; message( "Password updated successfully.", "success" ); } catch (error) { status.textContent = error.message || "Could not update password."; } finally { button.disabled = false; button.textContent = "UPDATE PASSWORD"; } }; /* ---------- CELEBRATION BANNER ---------- */ function ensureCelebrationBanner() { const home = $("page-home"); if (!home || $("sikoCelebration")) return; const banner = document.createElement("div"); banner.id = "sikoCelebration"; banner.className = "siko-celebration"; banner.innerHTML = `

`; home.insertBefore(banner, home.firstChild); } /* ---------- COUNTRY CELEBRATIONS ---------- */ const countryEvents = { "Kenya": { "06-01": [ "Happy Madaraka Day, Kenya!", "Celebrating freedom, identity and the stories that shape our nation." ], "10-20": [ "Happy Mashujaa Day, Kenya!", "Celebrating the heroes who helped shape Kenya." ], "12-12": [ "Happy Jamhuri Day, Kenya!", "Celebrating Kenya's independence and creative voices." ] }, "Uganda": { "10-09": [ "Happy Independence Day, Uganda!", "Celebrating Uganda's heritage and storytellers." ] }, "Tanzania": { "12-09": [ "Happy Independence Day, Tanzania!", "Celebrating Tanzania's creative voices." ] }, "Rwanda": { "07-01": [ "Happy Independence Day, Rwanda!", "Celebrating Rwanda's heritage and creative community." ] }, "Nigeria": { "10-01": [ "Happy Independence Day, Nigeria!", "Celebrating Nigerian stories, talent and creativity." ] }, "Ghana": { "03-06": [ "Happy Independence Day, Ghana!", "Celebrating Ghana's culture and storytellers." ] }, "South Africa": { "04-27": [ "Happy Freedom Day, South Africa!", "Celebrating freedom and the power of storytelling." ] }, "Ethiopia": { "05-28": [ "National Day, Ethiopia", "Celebrating Ethiopian culture and creative expression." ] }, "Cameroon": { "05-20": [ "Happy National Day, Cameroon!", "Celebrating Cameroon's people and creative voices." ] }, "Zambia": { "10-24": [ "Happy Independence Day, Zambia!", "Celebrating Zambia's heritage and talent." ] }, "Zimbabwe": { "04-18": [ "Happy Independence Day, Zimbabwe!", "Celebrating Zimbabwe's culture and creative community." ] }, "South Sudan": { "07-09": [ "Happy Independence Day, South Sudan!", "Celebrating South Sudanese stories and creativity." ] }, "Senegal": { "04-04": [ "Happy Independence Day, Senegal!", "Celebrating Senegalese culture and cinema." ] }, "Burundi": { "07-01": [ "Happy Independence Day, Burundi!", "Celebrating Burundi's heritage and storytellers." ] }, "Somalia": { "07-01": [ "Happy Somali Independence Day!", "Celebrating Somali culture and creative voices." ] }, "Egypt": { "07-23": [ "Egypt National Day", "Celebrating Egyptian heritage and storytelling." ] } }; const sharedEvents = { "01-01": [ "Happy New Year!", "A new year brings new stories, voices and opportunities across Africa." ], "05-25": [ "Happy Africa Day!", "Celebrating Africa's unity, diversity, creativity and storytellers." ], "12-25": [ "Merry Christmas!", "Wishing our SIKOHOME community a joyful celebration." ] }; function updateCelebration() { ensureCelebrationBanner(); const banner = $("sikoCelebration"); if (!banner) return; const title = $("sikoCelebrationTitle"); const description = $("sikoCelebrationMessage"); if (!title || !description) return; const now = new Date(); const dateKey = String(now.getMonth() + 1).padStart(2, "0") + "-" + String(now.getDate()).padStart(2, "0"); const user = getCurrentUser(); const profileCountry = typeof currentProfile !== "undefined" && currentProfile ? currentProfile.country : ""; const userCountry = user && user.user_metadata ? user.user_metadata.country : ""; const country = profileCountry || userCountry || ""; const event = (countryEvents[country] && countryEvents[country][dateKey]) || sharedEvents[dateKey]; if (!event) { banner.classList.remove("visible"); return; } title.textContent = event[0]; description.textContent = event[1]; banner.classList.add("visible"); } /* ---------- AUTHENTICATION EVENTS ---------- */ db.auth.onAuthStateChange(event => { if (event === "PASSWORD_RECOVERY") { recovery.classList.add("visible"); } setTimeout(updateCelebration, 500); setTimeout(updateCelebration, 1500); }); /* ---------- DYNAMIC WEBSITE ELEMENTS ---------- */ attachForgotPassword(); ensureCelebrationBanner(); const pageObserver = new MutationObserver(() => { attachForgotPassword(); ensureCelebrationBanner(); }); pageObserver.observe(document.body, { childList: true, subtree: true }); /* ---------- START EXPERIENCE ---------- */ if (!hasConsent()) { showIntro(); } else { stopSlideshow(); } updateCelebration(); setTimeout(updateCelebration, 1500); console.log( "SIKOHOME extension version 1.3 initialized." ); })();