import { useEffect, useState } from "react"; import TabNavigation from "./components/TabNavigation"; import SetupWizard from "./pages/SetupWizard"; import Onboarding from "./pages/Onboarding"; import Dashboard from "./pages/Dashboard"; import AutoPost from "./pages/AutoPost"; import Scheduler from "./pages/Scheduler"; import Analytics from "./pages/Analytics"; import Profiles from "./pages/Profiles"; import Settings from "./pages/Settings"; import Activity from "./pages/Activity"; type Tab = "dashboard" | "scheduler" | "autopost" | "analytics" | "profiles" | "settings" | "activity"; // Human-readable copy for the ?error= codes the PHP connect/SSO handlers // redirect back with. Without this the flows fail silently. const ERROR_MESSAGES: Record = { missing_params: "The connection callback was missing required parameters. Please try connecting again.", invalid_state: "Your connection link expired or was already used. Please click Connect again.", invalid_key: "Viraly rejected the connection key. Please try connecting again, or contact support if it keeps happening.", not_connected: "Your site is not connected to Viraly yet. Please connect it first.", sso_expired: "This page was open for a while and the sign-in link expired. Please try again now that the page has refreshed.", sso_key_invalid: "Your Viraly connection is no longer valid. Please reconnect from the Settings tab.", sso_unavailable: "Viraly could not be reached to sign you in. Please try again in a moment.", }; export default function App() { const params = new URLSearchParams(window.location.search); const tabMap: Record = { dashboard: "dashboard", connect: "profiles", compose: "scheduler", calendar: "scheduler", scheduler: "scheduler", autopost: "autopost", activity: "activity", analytics: "analytics", settings: "settings", profiles: "profiles", about: "settings", }; // ?tab= wins; otherwise the submenu page that mounted us sets // data-initial-tab (clean submenu slugs carry no tab query param). const rootTab = document.getElementById("viraly-app")?.dataset.initialTab || ""; const rawTab = params.get("tab") || rootTab || "dashboard"; const initialTab = tabMap[rawTab] || "dashboard"; const [showConnectedBanner] = useState(() => params.get("connected") === "1"); const [errorCode, setErrorCode] = useState(() => params.get("error")); const [keyInvalid, setKeyInvalid] = useState(false); const [activeTab, setActiveTabState] = useState(initialTab); const setActiveTab = (tab: Tab) => { setActiveTabState(tab); const url = new URL(window.location.href); url.searchParams.set("tab", tab); window.history.replaceState({}, "", url.toString()); }; // Strip the consumed error param so a reload does not re-show a stale error. useEffect(() => { if (errorCode) { const url = new URL(window.location.href); url.searchParams.delete("error"); window.history.replaceState({}, "", url.toString()); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // The WP proxy flags upstream 401/403 as key_invalid (revoked/rotated key); // surface one persistent reconnect banner instead of per-page empty states. useEffect(() => { const onKeyInvalid = () => setKeyInvalid(true); window.addEventListener("viraly:key-invalid", onKeyInvalid); return () => window.removeEventListener("viraly:key-invalid", onKeyInvalid); }, []); const [wizardSkipped, setWizardSkipped] = useState(false); const errorBanner = errorCode ? (
{ERROR_MESSAGES[errorCode] || "Something went wrong. Please try again."}
) : null; if (!viralyWP.isConnected) { if (!wizardSkipped && !sessionStorage.getItem("viraly_wizard_skipped")) { return (
{errorBanner} { setWizardSkipped(true); sessionStorage.setItem("viraly_wizard_skipped", "1"); }} />
); } return (
{errorBanner}
); } const renderTab = () => { switch (activeTab) { case "dashboard": return ; case "scheduler": return ; case "autopost": return ; case "analytics": return ; case "profiles": return ; case "settings": return ; case "activity": return ; default: return ; } }; return (
{errorBanner} {keyInvalid && (
Your Viraly connection is no longer valid (it may have been revoked or rotated). Head to{" "} {" "} to reconnect your site.
)} {showConnectedBanner && (
Your site is connected! Head to{" "} {" "} to connect your social accounts.
)}
{renderTab()}
); }