import { useState } from "react"; import { Link } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Shield, Menu, X } from "lucide-react"; const navLinks = [ { label: "Overview", page: "Home" }, { label: "Timeline", page: "History" }, { label: "Personnel", page: "Staff" }, { label: "Documents", page: "Documents" }, ]; export default function Layout({ children, currentPageName }) { const [menuOpen, setMenuOpen] = useState(false); return (
{/* Staff Banner */}
FOR STAFF USE ONLY — ROSEMARY PSYCHIATRIC INSTITUTE — NEW HOPE INITIATIVE
{/* Header */}
The New Hope Initiative
ROSEMARY PSYCHIATRIC INSTITUTE · EST. 1941
{/* Desktop Nav */} {/* Mobile Menu Toggle */}
{/* Mobile Nav */} {menuOpen && (
{navLinks.map((link) => ( setMenuOpen(false)} className={`block px-6 py-3 text-xs font-mono tracking-widest uppercase transition-colors ${currentPageName === link.page ? "text-accent bg-muted" : "text-muted-foreground hover:text-foreground hover:bg-muted" }`} > {link.label} ))}
)}
{/* Page Content */}
{children}
{/* Footer */}
); }{ "name": "StaffMember", "type": "object", "properties": { "name": { "type": "string" }, "title": { "type": "string" }, "department": { "type": "string", "enum": [ "Clinical", "Administration", "Research", "Social Work", "Nursing", "Psychology" ] }, "years_active": { "type": "string", "description": "e.g. 1952\u20131978" }, "bio": { "type": "string" }, "clearance_level": { "type": "string", "enum": [ "Level 1", "Level 2", "Level 3", "Classified" ], "default": "Level 1" }, "status": { "type": "string", "enum": [ "Active", "Retired", "Deceased", "Unknown" ], "default": "Active" } import { createClient } from '@base44/sdk'; import { appParams } from '@/lib/app-params'; const { appId, token, functionsVersion, appBaseUrl } = appParams; //Create a client with authentication required export const base44 = createClient({ appId, token, functionsVersion, serverUrl: '', requiresAuth: false, appBaseUrl }); import { Toaster } from "@/components/ui/toaster" import { QueryClientProvider } from '@tanstack/react-query' import { queryClientInstance } from '@/lib/query-client' import { pagesConfig } from './pages.config' import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import PageNotFound from './lib/PageNotFound'; import { AuthProvider, useAuth } from '@/lib/AuthContext'; import UserNotRegisteredError from '@/components/UserNotRegisteredError'; const { Pages, Layout, mainPage } = pagesConfig; const mainPageKey = mainPage ?? Object.keys(Pages)[0]; const MainPage = mainPageKey ? Pages[mainPageKey] : <>; const LayoutWrapper = ({ children, currentPageName }) => Layout ? {children} : <>{children}; const AuthenticatedApp = () => { const { isLoadingAuth, isLoadingPublicSettings, authError, navigateToLogin } = useAuth(); // Show loading spinner while checking app public settings or auth if (isLoadingPublicSettings || isLoadingAuth) { return (
); } // Handle authentication errors if (authError) { if (authError.type === 'user_not_registered') { return ; } else if (authError.type === 'auth_required') { // Redirect to login automatically navigateToLogin(); return null; } } // Render the main app return ( } /> {Object.entries(Pages).map(([path, Page]) => ( } /> ))} } /> ); }; function App() { return ( ) } export default App @import url('https://fonts.googleapis.com/css2?family=Special+Elite&family=IBM+Plex+Mono:wght@300;400;500&family=IM+Fell+English:ital@0;1&display=swap'); @tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { --background: 20 10% 6%; --foreground: 40 20% 82%; --card: 20 10% 9%; --card-foreground: 40 20% 82%; --popover: 20 10% 9%; --popover-foreground: 40 20% 82%; --primary: 0 60% 40%; --primary-foreground: 40 20% 92%; --secondary: 40 15% 15%; --secondary-foreground: 40 20% 75%; --muted: 20 10% 13%; --muted-foreground: 40 10% 50%; --accent: 38 55% 45%; --accent-foreground: 20 10% 6%; --destructive: 0 70% 45%; --destructive-foreground: 40 20% 92%; --border: 40 10% 18%; --input: 40 10% 18%; --ring: 0 60% 40%; --radius: 0.25rem; } } @layer base { * { @apply border-border; } body { @apply bg-background text-foreground; font-family: 'IBM Plex Mono', monospace; } h1, h2, h3, h4 { font-family: 'Special Elite', cursive; } } /* Noise texture overlay */ body::before { content: ''; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E"); pointer-events: none; z-index: 9999; opacity: 0.4; } .redacted { background: hsl(var(--foreground)); color: transparent; user-select: none; border-radius: 2px; } .stamp { font-family: 'Special Elite', cursive; border: 3px solid hsl(var(--primary)); color: hsl(var(--primary)); padding: 4px 12px; transform: rotate(-4deg); display: inline-block; opacity: 0.85; letter-spacing: 0.15em; import { useState } from "react"; import { Link } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Shield, Menu, X } from "lucide-react"; const navLinks = [ { label: "Overview", page: "Home" }, { label: "Timeline", page: "History" }, { label: "Personnel", page: "Staff" }, { label: "Documents", page: "Documents" }, ]; export default function Layout({ children, currentPageName }) { const [menuOpen, setMenuOpen] = useState(false); return (
{/* Staff Banner */}
FOR STAFF USE ONLY — ROSEMARY PSYCHIATRIC INSTITUTE — NEW HOPE INITIATIVE
{/* Header */}
The New Hope Initiative
ROSEMARY PSYCHIATRIC INSTITUTE · EST. 1941
{/* Desktop Nav */} {/* Mobile Menu Toggle */}
{/* Mobile Nav */} {menuOpen && (
{navLinks.map((link) => ( setMenuOpen(false)} className={`block px-6 py-3 text-xs font-mono tracking-widest uppercase transition-colors ${currentPageName === link.page ? "text-accent bg-muted" : "text-muted-foreground hover:text-foreground hover:bg-muted" }`} > {link.label} import React from 'react' import ReactDOM from 'react-dom/client' import App from '@/App.jsx' import '@/index.css' ReactDOM.createRoot(document.getElementById('root')).render( ) /** * pages.config.js - Page routing configuration * * This file is AUTO-GENERATED. Do not add imports or modify PAGES manually. * Pages are auto-registered when you create files in the ./pages/ folder. * * THE ONLY EDITABLE VALUE: mainPage * This controls which page is the landing page (shown when users visit the app). * * Example file structure: * * import HomePage from './pages/HomePage'; * import Dashboard from './pages/Dashboard'; * import Settings from './pages/Settings'; * * export const PAGES = { * "HomePage": HomePage, * "Dashboard": Dashboard, * "Settings": Settings, * } * * export const pagesConfig = { * mainPage: "HomePage", * Pages: PAGES, * }; * * Example with Layout (wraps all pages): * * import Home from './pages/Home'; * import Settings from './pages/Settings'; * import __Layout from './Layout.jsx'; * * export const PAGES = { * "Home": Home, * "Settings": Settings, * } * * export const pagesConfig = { * mainPage: "Home", * Pages: PAGES, * Layout: __Layout, * }; * * To change the main page from HomePage to Dashboard, use find_replace: * Old: mainPage: "HomePage", * New: mainPage: "Dashboard", * * The mainPage value must match a key in the PAGES object exactly. */ import Home from './pages/Home'; import History from './pages/History'; import Staff from './pages/Staff'; import Documents from './pages/Documents'; import __Layout from './Layout.jsx'; export const PAGES = { "Home": Home, "History": History, "Staff": Staff, "Documents": Documents, } export const pagesConfig = { mainPage: "Home", Pages: PAGES, Layout: __Layout, };#env .env .env.* # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules dist dist-ssr *.local # Editor directories and files .vscode/* !.vscode/extensions.json .idea .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? .env{ "$schema": "https://ui.shadcn.com/schema.json", "style": "new-york", "rsc": false, "tsx": false, "tailwind": { "config": "tailwind.config.js", "css": "src/index.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" }, "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks" }, "iconLibrary": "lucide" }import globals from "globals"; import pluginJs from "@eslint/js"; import pluginReact from "eslint-plugin-react"; import pluginReactHooks from "eslint-plugin-react-hooks"; import pluginUnusedImports from "eslint-plugin-unused-imports"; export default [ { files: [ "src/components/**/*.{js,mjs,cjs,jsx}", "src/pages/**/*.{js,mjs,cjs,jsx}", "src/Layout.jsx", ], ignores: ["src/lib/**/*", "src/components/ui/**/*"], ...pluginJs.configs.recommended, ...pluginReact.configs.flat.recommended, languageOptions: { globals: globals.browser, parserOptions: { ecmaVersion: 2022, sourceType: "module", ecmaFeatures: { jsx: true, }, }, }, settings: { react: { version: "detect", }, }, plugins: { react: pluginReact, "react-hooks": pluginReactHooks, "unused-imports": pluginUnusedImports, }, rules: { "no-unused-vars": "off", "react/jsx-uses-vars": "error", "react/jsx-uses-react": "error", "unused-imports/no-unused-imports": "error", "unused-imports/no-unused-vars": [ "warn", { vars: "all", varsIgnorePattern: "^_", args: "after-used", argsIgnorePattern: "^_", }, ], "react/prop-types": "off", "react/react-in-jsx-scope": "off", "react/no-unknown-property": [ "error", { ignore: ["cmdk-input-wrapper", "toast-close"] }, ], "react-hooks/rules-of-hooks": "error", }, }, ]; Base44 APP
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] }, "jsx": "react-jsx", "module": "esnext", "moduleResolution": "bundler", "lib": ["esnext", "dom"], "target": "esnext", "checkJs": true, "skipLibCheck": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "resolveJsonModule": true, "types": [] }, "include": ["src/components/**/*.js", "src/pages/**/*.jsx", "src/Layout.jsx"], "exclude": ["node_modules", "dist", "src/vite-plugins", "src/components/ui", "src/api", "src/lib"] } { "name": "base44-app", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "lint": "eslint . --quiet", "lint:fix": "eslint . --fix", "typecheck": "tsc -p ./jsconfig.json", "preview": "vite preview" }, "dependencies": { "@base44/sdk": "^0.8.0", "@base44/vite-plugin": "^1.0.0", "@hello-pangea/dnd": "^17.0.0", "@hookform/resolvers": "^4.1.2", "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-alert-dialog": "^1.1.6", "@radix-ui/react-aspect-ratio": "^1.1.2", "@radix-ui/react-avatar": "^1.1.3", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-collapsible": "^1.1.3", "@radix-ui/react-context-menu": "^2.2.6", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", "@radix-ui/react-hover-card": "^1.1.6", "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-menubar": "^1.1.6", "@radix-ui/react-navigation-menu": "^1.2.5", "@radix-ui/react-popover": "^1.1.6", "@radix-ui/react-progress": "^1.1.2", "@radix-ui/react-radio-group": "^1.2.3", "@radix-ui/react-scroll-area": "^1.2.3", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-separator": "^1.1.2", "@radix-ui/react-slider": "^1.2.3", "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-switch": "^1.1.3", "@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-toast": "^1.2.2", "@radix-ui/react-toggle": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.8", "@stripe/react-stripe-js": "^3.0.0", "@stripe/stripe-js": "^5.2.0", "@tanstack/react-query": "^5.84.1", "canvas-confetti": "^1.9.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.0.0", "date-fns": "^3.6.0", "embla-carousel-react": "^8.5.2", "framer-motion": "^11.16.4", "html2canvas": "^1.4.1", "input-otp": "^1.4.2", "jspdf": "^4.0.0", "lodash": "^4.17.21", "lucide-react": "^0.475.0", "moment": "^2.30.1", "next-themes": "^0.4.4", "react": "^18.2.0", "react-day-picker": "^8.10.1", "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", "react-hot-toast": "^2.6.0", "react-leaflet": "^4.2.1", "react-markdown": "^9.0.1", "react-quill": "^2.0.0", "react-resizable-panels": "^2.1.7", "react-router-dom": "^6.26.0", "recharts": "^2.15.4", "sonner": "^2.0.1", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", "three": "^0.171.0", "vaul": "^1.1.2", "zod": "^3.24.2" }, "devDependencies": { "@eslint/js": "^9.19.0", "@types/node": "^22.13.5", "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "baseline-browser-mapping": "^2.8.32", "eslint": "^9.19.0", "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.18", "eslint-plugin-unused-imports": "^4.3.0", "globals": "^15.14.0", "postcss": "^8.5.3", "tailwindcss": "^3.4.17", "typescript": "^5.8.2", "vite": "^6.1.0" } }export default { plugins: { tailwindcss: {}, autoprefixer: {}, }, }/** @type {import('tailwindcss').Config} */ export default { darkMode: ["class"], content: ["./index.html", "./src/**/*.{js,jsx,ts,tsx}"], theme: { extend: { colors: { background: "hsl(var(--background))", foreground: "hsl(var(--foreground))", card: { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))", }, popover: { DEFAULT: "hsl(var(--popover))", foreground: "hsl(var(--popover-foreground))", }, primary: { DEFAULT: "hsl(var(--primary))", foreground: "hsl(var(--primary-foreground))", }, secondary: { DEFAULT: "hsl(var(--secondary))", foreground: "hsl(var(--secondary-foreground))", }, muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))", }, accent: { DEFAULT: "hsl(var(--accent))", foreground: "hsl(var(--accent-foreground))", }, destructive: { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))", }, border: "hsl(var(--border))", input: "hsl(var(--input))", ring: "hsl(var(--ring))", }, fontFamily: { elite: ["'Special Elite'", "cursive"], mono: ["'IBM Plex Mono'", "monospace"], fell: ["'IM Fell English'", "serif"], }, borderRadius: { lg: "var(--radius)", md: "calc(var(--radius) - 2px)", sm: "calc(var(--radius) - 4px)", }, }, }, plugins: [require("tailwindcss-animate")], };import base44 from "@base44/vite-plugin" import react from '@vitejs/plugin-react' import { defineConfig } from 'vite' // https://vite.dev/config/ export default defineConfig({ logLevel: 'error', // Suppress warnings, only show errors plugins: [ base44({ // Support for legacy code that imports the base44 SDK with @/integrations, @/entities, etc. // can be removed if the code has been updated to use the new SDK imports from @base44/sdk legacySDKImports: process.env.BASE44_LEGACY_SDK_IMPORTS === 'true', hmrNotifier: true, navigationNotifier: true, analyticsTracker: true, visualEditAgent: true }), react(), ] });