diff --git a/frontend/src/components/AsideMenuLayer.tsx b/frontend/src/components/AsideMenuLayer.tsx index 59c5526..85a66f3 100644 --- a/frontend/src/components/AsideMenuLayer.tsx +++ b/frontend/src/components/AsideMenuLayer.tsx @@ -3,10 +3,9 @@ import { mdiLogout, mdiClose } from '@mdi/js' import BaseIcon from './BaseIcon' import AsideMenuList from './AsideMenuList' import { MenuAsideItem } from '../interfaces' -import { useAppSelector } from '../stores/hooks' +import { useAppDispatch, useAppSelector } from '../stores/hooks' import Link from 'next/link'; -import { useAppDispatch } from '../stores/hooks'; import { createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; diff --git a/frontend/src/components/NavBarItem.tsx b/frontend/src/components/NavBarItem.tsx index eb155e3..fb0fca2 100644 --- a/frontend/src/components/NavBarItem.tsx +++ b/frontend/src/components/NavBarItem.tsx @@ -1,6 +1,5 @@ -import React, {useEffect, useRef} from 'react' +import React, { useEffect, useRef, useState } from 'react' import Link from 'next/link' -import { useState } from 'react' import { mdiChevronUp, mdiChevronDown } from '@mdi/js' import BaseDivider from './BaseDivider' import BaseIcon from './BaseIcon' diff --git a/frontend/src/layouts/Authenticated.tsx b/frontend/src/layouts/Authenticated.tsx index 1b9907d..73d8391 100644 --- a/frontend/src/layouts/Authenticated.tsx +++ b/frontend/src/layouts/Authenticated.tsx @@ -1,5 +1,4 @@ -import React, { ReactNode, useEffect } from 'react' -import { useState } from 'react' +import React, { ReactNode, useEffect, useState } from 'react' import jwt from 'jsonwebtoken'; import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js' import menuAside from '../menuAside' diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index 043a78b..90a4faa 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -1,166 +1,675 @@ - -import React, { useEffect, useState } from 'react'; -import type { ReactElement } from 'react'; +import { FormEvent, ReactElement, useMemo, useState } from 'react'; import Head from 'next/head'; import Link from 'next/link'; import BaseButton from '../components/BaseButton'; -import CardBox from '../components/CardBox'; -import SectionFullScreen from '../components/SectionFullScreen'; import LayoutGuest from '../layouts/Guest'; -import BaseDivider from '../components/BaseDivider'; -import BaseButtons from '../components/BaseButtons'; import { getPageTitle } from '../config'; -import { useAppSelector } from '../stores/hooks'; -import CardBoxComponentTitle from "../components/CardBoxComponentTitle"; -import { getPexelsImage, getPexelsVideo } from '../helpers/pexels'; +type ClassroomMode = 'Live Classroom' | 'AI Exam Hall' | 'Parent Conference' | 'Teacher Studio'; +type LanguageMode = 'Arabic + English' | 'English only' | 'Arabic only'; +type StorageProfile = 'Google Drive vault' | 'Local encrypted archive' | 'Hybrid mirrored backup'; -export default function Starter() { - const [illustrationImage, setIllustrationImage] = useState({ - src: undefined, - photographer: undefined, - photographer_url: undefined, - }) - const [illustrationVideo, setIllustrationVideo] = useState({video_files: []}) - const [contentType, setContentType] = useState('image'); - const [contentPosition, setContentPosition] = useState('right'); - const textColor = useAppSelector((state) => state.style.linkColor); +type ClassroomPlan = { + id: string; + name: string; + supervisor: string; + mode: ClassroomMode; + languageMode: LanguageMode; + storageProfile: StorageProfile; + learners: number; + objective: string; + features: string[]; + createdAt: string; +}; - const title = 'Autonomous Video Platform' +const featureOptions = [ + 'AI proctoring', + 'Mediasoup SFU', + 'P2P fallback', + 'Whiteboard canvas', + 'Breakout rooms', + 'Collaborative notes', + 'Live polls', + 'AI copilot', + 'Recording pipeline', + 'Gradebook sync', +]; - // Fetch Pexels image/video - useEffect(() => { - async function fetchData() { - const image = await getPexelsImage(); - const video = await getPexelsVideo(); - setIllustrationImage(image); - setIllustrationVideo(video); - } - fetchData(); - }, []); +const modeAccent: Record = { + 'Live Classroom': 'from-cyan-300 to-blue-500', + 'AI Exam Hall': 'from-amber-300 to-orange-500', + 'Parent Conference': 'from-emerald-300 to-teal-500', + 'Teacher Studio': 'from-fuchsia-300 to-violet-500', +}; - const imageBlock = (image) => ( -
-
- - Photo by {image?.photographer} on Pexels - -
-
+const storageDescriptions: Record = { + 'Google Drive vault': 'Uploads, recordings, backups, and static assets route to the BritishCE44 Drive vault after OAuth consent.', + 'Local encrypted archive': 'Core services keep encrypted classroom artifacts on HTTPS localhost for offline-first operation.', + 'Hybrid mirrored backup': 'Local PostgreSQL/Redis state remains authoritative while encrypted archives are mirrored to Google Drive.', +}; + +const starterClassrooms: ClassroomPlan[] = [ + { + id: 'ce44-room-01', + name: 'CE44 English Foundation Room 01', + supervisor: 'Majed Kaid Alsharabi', + mode: 'Live Classroom', + languageMode: 'Arabic + English', + storageProfile: 'Hybrid mirrored backup', + learners: 32, + objective: 'Run a bilingual lesson with whiteboard practice, polls, recording, and AI-generated revision notes.', + features: ['Mediasoup SFU', 'Whiteboard canvas', 'AI copilot', 'Recording pipeline', 'Live polls'], + createdAt: 'Template', + }, + { + id: 'ce44-exam-secure', + name: 'Secure AI Exam Hall', + supervisor: 'Academic Admin', + mode: 'AI Exam Hall', + languageMode: 'English only', + storageProfile: 'Google Drive vault', + learners: 80, + objective: 'Deliver monitored assessments with AI proctoring, identity checks, and bilingual report exports.', + features: ['AI proctoring', 'Mediasoup SFU', 'P2P fallback', 'Gradebook sync', 'Recording pipeline'], + createdAt: 'Template', + }, +]; + +const deploymentTracks = [ + ['Web App', 'Active control-plane UI for classrooms, LMS planning, admin review, and browser-based collaboration workflows.'], + ['Windows EXE', 'Packaging track for a local HTTPS server bundle with single consent prompt and offline-ready services.'], + ['Android APK', 'Mobile classroom track for camera, microphone, Drive consent, learner attendance, and parent access.'], +]; + +const suiteCards = [ + ['40+ classrooms', 'Pre-modeled digital rooms for live lessons, exams, parent conferences, labs, clubs, and teacher studios.'], + ['LMS core', 'Courses, assignments, gradebook, AI-graded tests, parent portal, and bilingual Arabic/English reports.'], + ['AI-native class flow', 'Copilot summaries, proctoring signals, collaborative notes, live polls, and catch-up packs.'], + ['Hybrid server model', 'HTTPS localhost for WebRTC/API/database with Google Drive for cloud storage, backups, and static assets.'], + ['Admin-only expansion', 'Tables, sheets, modules, and settings are planned as expandable only by the authorized admin role.'], + ['Media resilience', 'Mediasoup SFU-first architecture with P2P fallback, low-bandwidth mode, recording, and recovery hooks.'], +]; + +const buildClassroomId = (name: string) => + name + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-|-$)/g, '') + .slice(0, 36) || `classroom-${Date.now()}`; + +const getCapacityPlan = (learnerCount: number) => { + if (learnerCount > 180) { + return 'Cascading SFU district mode'; + } + + if (learnerCount > 40) { + return 'Mediasoup SFU classroom cluster'; + } + + return 'SFU room with P2P fallback'; +}; + +export default function BritishCE44Platform() { + const [classrooms, setClassrooms] = useState(starterClassrooms); + const [selectedClassroomId, setSelectedClassroomId] = useState(starterClassrooms[0].id); + const [name, setName] = useState(''); + const [supervisor, setSupervisor] = useState('Majed Kaid Alsharabi'); + const [mode, setMode] = useState('Live Classroom'); + const [languageMode, setLanguageMode] = useState('Arabic + English'); + const [storageProfile, setStorageProfile] = useState('Hybrid mirrored backup'); + const [learners, setLearners] = useState('40'); + const [objective, setObjective] = useState(''); + const [features, setFeatures] = useState(['Mediasoup SFU', 'AI copilot', 'Whiteboard canvas']); + const [formError, setFormError] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); + + const selectedClassroom = useMemo( + () => classrooms.find((classroom) => classroom.id === selectedClassroomId) ?? classrooms[0], + [classrooms, selectedClassroomId] + ); + + const projectedCapacity = useMemo(() => getCapacityPlan(Number(learners) || 0), [learners]); + + const selectedStorageDescription = storageDescriptions[storageProfile]; + + const enabledCount = useMemo( + () => [ + classrooms.length >= 2, + featureOptions.length >= 10, + Boolean(selectedClassroom), + storageProfile === 'Hybrid mirrored backup', + ].filter(Boolean).length, + [classrooms.length, selectedClassroom, storageProfile] + ); + + const toggleFeature = (feature: string) => { + setFeatures((currentFeatures) => + currentFeatures.includes(feature) + ? currentFeatures.filter((item) => item !== feature) + : [...currentFeatures, feature] ); + }; - const videoBlock = (video) => { - if (video?.video_files?.length > 0) { - return ( -
- - -
) - } + const resetForm = () => { + setName(''); + setSupervisor('Majed Kaid Alsharabi'); + setMode('Live Classroom'); + setLanguageMode('Arabic + English'); + setStorageProfile('Hybrid mirrored backup'); + setLearners('40'); + setObjective(''); + setFeatures(['Mediasoup SFU', 'AI copilot', 'Whiteboard canvas']); + }; + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + setFormError(''); + setSuccessMessage(''); + + const trimmedName = name.trim(); + const trimmedSupervisor = supervisor.trim(); + const trimmedObjective = objective.trim(); + const learnerCount = Number(learners); + + if (trimmedName.length < 3) { + setFormError('Give the classroom a clear name with at least 3 characters.'); + return; + } + + if (trimmedSupervisor.length < 2) { + setFormError('Add the responsible supervisor or teacher for this classroom.'); + return; + } + + if (!Number.isInteger(learnerCount) || learnerCount < 2 || learnerCount > 1000) { + setFormError('Expected learners must be a whole number from 2 to 1000.'); + return; + } + + if (trimmedObjective.length < 16) { + setFormError('Describe the class objective in at least 16 characters.'); + return; + } + + if (features.length < 2) { + setFormError('Select at least two BritishCE44 classroom capabilities.'); + return; + } + + const baseId = buildClassroomId(trimmedName); + const id = classrooms.some((classroom) => classroom.id === baseId) + ? `${baseId}-${classrooms.length + 1}` + : baseId; + const createdClassroom: ClassroomPlan = { + id, + name: trimmedName, + supervisor: trimmedSupervisor, + mode, + languageMode, + storageProfile, + learners: learnerCount, + objective: trimmedObjective, + features, + createdAt: 'Just now', }; + setClassrooms((currentClassrooms) => [createdClassroom, ...currentClassrooms]); + setSelectedClassroomId(id); + setSuccessMessage(`${trimmedName} is planned as ${projectedCapacity.toLowerCase()} with ${storageProfile.toLowerCase()}.`); + resetForm(); + }; + + const classroomUrl = selectedClassroom ? `https://localhost:3001/britishce44/classrooms/${selectedClassroom.id}` : ''; + return ( -
+
- {getPageTitle('Starter Page')} + {getPageTitle('BritishCE44 Enterprise Ultimate Platform')} + - -
- {contentType === 'image' && contentPosition !== 'background' - ? imageBlock(illustrationImage) - : null} - {contentType === 'video' && contentPosition !== 'background' - ? videoBlock(illustrationVideo) - : null} -
- - - -
-

This is a React.js/Node.js app generated by the Flatlogic Web App Generator

-

For guides and documentation please check - your local README.md and the Flatlogic documentation

-
- - - - - -
+
+
+ + + CE44 + + + BritishCE44 + Enterprise Ultimate Platform + + + +
-
- -
-

© 2026 {title}. All rights reserved

- - Privacy Policy - -
+ +
+
+
+
+
+
+
+
+ + RFP demo slice: AI-native online school control plane +
+

+ BritishCE44 Online School for secure, bilingual, AI-powered classrooms. +

+

+ A public product surface for the requested BritishCE44 Enterprise Ultimate Platform: 40+ digital + classrooms, WebRTC collaboration, AI proctoring, LMS workflows, parent reporting, and a hybrid + localhost plus Google Drive architecture. +

+ +
+ {[ + ['40+', 'classrooms'], + ['4K', 'WebRTC target'], + ['AR/EN', 'reporting'], + ['3', 'delivery tracks'], + ].map(([value, label]) => ( +
+
{value}
+
{label}
+
+ ))} +
+
+ +
+
+
+
+

Live classroom preview

+

{selectedClassroom?.name}

+
+ + Supervisor-ready + +
+
+ {['Teacher video', 'Whiteboard', 'AI copilot', 'Learner pods'].map((tile, index) => ( +
+
+ {tile} + 0{index + 1} +
+
+ ))} +
+
+

Hybrid server contract

+

+ Core API, WebRTC signaling, database, and real-time state stay on HTTPS localhost. Google Drive is + positioned as the consent-based vault for recordings, course materials, static assets, and encrypted backups. +

+
+
+ {deploymentTracks.map(([title]) => ( +
+ {title} +
+ ))} +
+
+
+
+
+ +
+
+

Education suite

+

A Teams, Zoom, Meet, and Jitsi challenger for schools.

+

+ This interface turns the RFP into a visible roadmap and demo workflow while leaving safe extension points + for Mediasoup, Redis, PostgreSQL, packaging, Google Drive OAuth, and AI services. +

+
+
+ {suiteCards.map(([title, copy]) => ( +
+
+

{title}

+

{copy}

+
+ ))} +
+
+ +
+
+

Classroom planner

+

Configure a BritishCE44 digital classroom.

+

+ Choose the room type, bilingual mode, WebRTC/AI features, learner capacity, and the preferred hybrid + storage profile. The planner validates inputs and adds the classroom to the local demo registry. +

+ +
+

Selected storage profile

+

{selectedStorageDescription}

+

Projected media plan: {projectedCapacity}

+
+ + {successMessage ? ( +
+

Classroom plan created

+

{successMessage}

+
+ ) : null} +
+ +
+ {formError ? ( +
+ {formError} +
+ ) : null} + +
+ + + + + + +
+ +