feat: Add online user guide with screenshots (#203) #204
@@ -47,6 +47,9 @@ const AdminLogsMobileScreen = lazy(() => import('./features/admin/mobile/AdminLo
|
|||||||
const AdminCommunityStationsPage = lazy(() => import('./features/admin/pages/AdminCommunityStationsPage').then(m => ({ default: m.AdminCommunityStationsPage })));
|
const AdminCommunityStationsPage = lazy(() => import('./features/admin/pages/AdminCommunityStationsPage').then(m => ({ default: m.AdminCommunityStationsPage })));
|
||||||
const AdminCommunityStationsMobileScreen = lazy(() => import('./features/admin/mobile/AdminCommunityStationsMobileScreen').then(m => ({ default: m.AdminCommunityStationsMobileScreen })));
|
const AdminCommunityStationsMobileScreen = lazy(() => import('./features/admin/mobile/AdminCommunityStationsMobileScreen').then(m => ({ default: m.AdminCommunityStationsMobileScreen })));
|
||||||
|
|
||||||
|
// Public pages (lazy-loaded)
|
||||||
|
const GuidePage = lazy(() => import('./pages/GuidePage/GuidePage').then(m => ({ default: m.GuidePage })));
|
||||||
|
|
||||||
// Auth pages (lazy-loaded)
|
// Auth pages (lazy-loaded)
|
||||||
const SignupPage = lazy(() => import('./features/auth/pages/SignupPage').then(m => ({ default: m.SignupPage })));
|
const SignupPage = lazy(() => import('./features/auth/pages/SignupPage').then(m => ({ default: m.SignupPage })));
|
||||||
const VerifyEmailPage = lazy(() => import('./features/auth/pages/VerifyEmailPage').then(m => ({ default: m.VerifyEmailPage })));
|
const VerifyEmailPage = lazy(() => import('./features/auth/pages/VerifyEmailPage').then(m => ({ default: m.VerifyEmailPage })));
|
||||||
@@ -368,7 +371,7 @@ function App() {
|
|||||||
// Skip on auth routes -- their query params must survive until Auth0 SDK processes them
|
// Skip on auth routes -- their query params must survive until Auth0 SDK processes them
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
if (path === '/callback' || path === '/signup' || path === '/verify-email') return;
|
if (path === '/callback' || path === '/signup' || path === '/verify-email' || path === '/guide') return;
|
||||||
const screen = routeToScreen[path];
|
const screen = routeToScreen[path];
|
||||||
if (screen && screen !== activeScreen) {
|
if (screen && screen !== activeScreen) {
|
||||||
navigateToScreen(screen, { source: 'url-sync' });
|
navigateToScreen(screen, { source: 'url-sync' });
|
||||||
@@ -380,7 +383,7 @@ function App() {
|
|||||||
// Auth0 SDK needs for handleRedirectCallback (child effects fire before parent effects)
|
// Auth0 SDK needs for handleRedirectCallback (child effects fire before parent effects)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
if (path === '/callback' || path === '/signup' || path === '/verify-email') return;
|
if (path === '/callback' || path === '/signup' || path === '/verify-email' || path === '/guide') return;
|
||||||
const targetPath = screenToRoute[activeScreen];
|
const targetPath = screenToRoute[activeScreen];
|
||||||
if (targetPath && path !== targetPath) {
|
if (targetPath && path !== targetPath) {
|
||||||
window.history.replaceState(null, '', targetPath);
|
window.history.replaceState(null, '', targetPath);
|
||||||
@@ -499,8 +502,9 @@ function App() {
|
|||||||
const isSignupRoute = location.pathname === '/signup';
|
const isSignupRoute = location.pathname === '/signup';
|
||||||
const isVerifyEmailRoute = location.pathname === '/verify-email';
|
const isVerifyEmailRoute = location.pathname === '/verify-email';
|
||||||
const isOnboardingRoute = location.pathname === '/onboarding';
|
const isOnboardingRoute = location.pathname === '/onboarding';
|
||||||
|
const isGuideRoute = location.pathname === '/guide';
|
||||||
const isAuthRoute = isSignupRoute || isVerifyEmailRoute || isOnboardingRoute;
|
const isAuthRoute = isSignupRoute || isVerifyEmailRoute || isOnboardingRoute;
|
||||||
const shouldShowHomePage = !isGarageRoute && !isCallbackRoute && !isAuthRoute;
|
const shouldShowHomePage = !isGarageRoute && !isCallbackRoute && !isAuthRoute && !isGuideRoute;
|
||||||
|
|
||||||
const [callbackTimedOut, setCallbackTimedOut] = useState(false);
|
const [callbackTimedOut, setCallbackTimedOut] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -635,6 +639,21 @@ function App() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isGuideRoute) {
|
||||||
|
return (
|
||||||
|
<ThemeProvider>
|
||||||
|
<React.Suspense fallback={
|
||||||
|
<div className="flex items-center justify-center min-h-screen bg-nero">
|
||||||
|
<div className="text-lg text-avus">Loading guide...</div>
|
||||||
|
</div>
|
||||||
|
}>
|
||||||
|
<GuidePage />
|
||||||
|
</React.Suspense>
|
||||||
|
<DebugInfo />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Signup route is public - no authentication required
|
// Signup route is public - no authentication required
|
||||||
if (isSignupRoute) {
|
if (isSignupRoute) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
238
frontend/src/pages/GuidePage/GuidePage.tsx
Normal file
238
frontend/src/pages/GuidePage/GuidePage.tsx
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
import { useState, useEffect, useCallback, Suspense } from 'react';
|
||||||
|
import { useAuth0 } from '@auth0/auth0-react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { GuideTableOfContents } from './GuideTableOfContents';
|
||||||
|
import { guideSections } from './guideTypes';
|
||||||
|
import {
|
||||||
|
GettingStartedSection,
|
||||||
|
DashboardSection,
|
||||||
|
VehiclesSection,
|
||||||
|
FuelLogsSection,
|
||||||
|
MaintenanceSection,
|
||||||
|
GasStationsSection,
|
||||||
|
DocumentsSection,
|
||||||
|
SettingsSection,
|
||||||
|
SubscriptionSection,
|
||||||
|
MobileExperienceSection,
|
||||||
|
} from './sections';
|
||||||
|
|
||||||
|
export const GuidePage = () => {
|
||||||
|
const { loginWithRedirect, isAuthenticated } = useAuth0();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [activeSection, setActiveSection] = useState(guideSections[0].id);
|
||||||
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleAuthAction = useCallback(() => {
|
||||||
|
if (isAuthenticated) {
|
||||||
|
navigate('/garage');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loginWithRedirect({ appState: { returnTo: '/garage' } });
|
||||||
|
}, [isAuthenticated, navigate, loginWithRedirect]);
|
||||||
|
|
||||||
|
const handleSignup = useCallback(() => {
|
||||||
|
navigate('/signup');
|
||||||
|
}, [navigate]);
|
||||||
|
|
||||||
|
// Track scroll position for nav background and active section
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
setIsScrolled(window.scrollY > 50);
|
||||||
|
|
||||||
|
// Determine active section from scroll position
|
||||||
|
const sectionElements = guideSections.map((s) => ({
|
||||||
|
id: s.id,
|
||||||
|
element: document.getElementById(s.id),
|
||||||
|
}));
|
||||||
|
|
||||||
|
for (let i = sectionElements.length - 1; i >= 0; i--) {
|
||||||
|
const { id, element } = sectionElements[i];
|
||||||
|
if (element) {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
if (rect.top <= 120) {
|
||||||
|
setActiveSection(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const sectionFallback = (
|
||||||
|
<div className="py-8 text-center text-titanio/50">Loading section...</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-nero text-avus">
|
||||||
|
{/* Navigation Bar - matches HomePage style */}
|
||||||
|
<nav
|
||||||
|
className={`fixed top-0 left-0 right-0 z-50 transition-colors duration-300 ${
|
||||||
|
isScrolled ? 'bg-nero/95 backdrop-blur-sm' : 'bg-nero'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="w-full px-4 md:px-8 lg:px-12">
|
||||||
|
<div className="flex justify-between items-center h-16">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<a href="/" className="flex items-center">
|
||||||
|
<img
|
||||||
|
src="/images/logos/motovaultpro-title-slogan.png"
|
||||||
|
alt="MotoVaultPro - Precision Vehicle Management"
|
||||||
|
className="h-8 md:h-10 w-auto"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Desktop Menu */}
|
||||||
|
<div className="hidden md:flex items-center space-x-8">
|
||||||
|
<a href="/#home" className="text-white/75 hover:text-white transition-colors">
|
||||||
|
Home
|
||||||
|
</a>
|
||||||
|
<a href="/#features" className="text-white/75 hover:text-white transition-colors">
|
||||||
|
Features
|
||||||
|
</a>
|
||||||
|
<a href="/#about" className="text-white/75 hover:text-white transition-colors">
|
||||||
|
About
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="/guide"
|
||||||
|
className="text-primary-400 font-semibold transition-colors"
|
||||||
|
>
|
||||||
|
Guide
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
onClick={handleSignup}
|
||||||
|
className="border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 hover:border-primary-500 font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
|
>
|
||||||
|
Sign Up
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleAuthAction}
|
||||||
|
className="bg-primary-500 hover:bg-primary-600 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Menu Button */}
|
||||||
|
<div className="md:hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||||
|
className="text-white/80 hover:text-white focus:outline-none"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="h-6 w-6"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
{mobileMenuOpen ? (
|
||||||
|
<path d="M6 18L18 6M6 6l12 12" />
|
||||||
|
) : (
|
||||||
|
<path d="M4 6h16M4 12h16M4 18h16" />
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile Menu */}
|
||||||
|
{mobileMenuOpen && (
|
||||||
|
<div className="md:hidden py-4 space-y-3 bg-nero/95 backdrop-blur-sm border-t border-white/10">
|
||||||
|
<a href="/" className="block text-white/75 hover:text-white transition-colors py-2">
|
||||||
|
Home
|
||||||
|
</a>
|
||||||
|
<a href="/#features" className="block text-white/75 hover:text-white transition-colors py-2">
|
||||||
|
Features
|
||||||
|
</a>
|
||||||
|
<a href="/#about" className="block text-white/75 hover:text-white transition-colors py-2">
|
||||||
|
About
|
||||||
|
</a>
|
||||||
|
<a href="/guide" className="block text-primary-400 font-semibold py-2">
|
||||||
|
Guide
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
onClick={handleSignup}
|
||||||
|
className="w-full border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
|
>
|
||||||
|
Sign Up
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleAuthAction}
|
||||||
|
className="w-full bg-primary-500 hover:bg-primary-600 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Page Content */}
|
||||||
|
<div className="pt-20 px-4 md:px-8 lg:px-12 max-w-7xl mx-auto">
|
||||||
|
{/* Page Header */}
|
||||||
|
<div className="py-8 md:py-12 border-b border-white/10 mb-8">
|
||||||
|
<h1 className="text-3xl md:text-4xl font-bold text-avus mb-3">
|
||||||
|
User Guide
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-titanio/70">
|
||||||
|
Precision Vehicle Management -- Track every mile. Own every detail.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Layout: TOC sidebar + content */}
|
||||||
|
<div className="flex flex-col md:flex-row gap-8 pb-16">
|
||||||
|
<GuideTableOfContents activeSection={activeSection} />
|
||||||
|
|
||||||
|
<main className="flex-1 min-w-0">
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<GettingStartedSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<DashboardSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<VehiclesSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<FuelLogsSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<MaintenanceSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<GasStationsSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<DocumentsSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<SettingsSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<SubscriptionSection />
|
||||||
|
</Suspense>
|
||||||
|
<Suspense fallback={sectionFallback}>
|
||||||
|
<MobileExperienceSection />
|
||||||
|
</Suspense>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<footer className="bg-black text-white py-8 px-4 md:px-8 border-t border-white/10">
|
||||||
|
<div className="max-w-7xl mx-auto text-center">
|
||||||
|
<p className="text-white/50">
|
||||||
|
© {new Date().getFullYear()} FB Technologies LLC. All rights reserved.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
92
frontend/src/pages/GuidePage/GuideTableOfContents.tsx
Normal file
92
frontend/src/pages/GuidePage/GuideTableOfContents.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
|
||||||
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
|
import { guideSections } from './guideTypes';
|
||||||
|
|
||||||
|
interface GuideTableOfContentsProps {
|
||||||
|
activeSection: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GuideTableOfContents = ({ activeSection }: GuideTableOfContentsProps) => {
|
||||||
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
|
const [tocExpanded, setTocExpanded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const check = () => setIsMobile(window.innerWidth < 768);
|
||||||
|
check();
|
||||||
|
window.addEventListener('resize', check);
|
||||||
|
return () => window.removeEventListener('resize', check);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClick = (sectionId: string) => {
|
||||||
|
const element = document.getElementById(sectionId);
|
||||||
|
if (element) {
|
||||||
|
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
if (isMobile) {
|
||||||
|
setTocExpanded(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tocContent = (
|
||||||
|
<nav aria-label="Table of contents">
|
||||||
|
<ul className="space-y-1">
|
||||||
|
{guideSections.map((section) => (
|
||||||
|
<li key={section.id}>
|
||||||
|
<button
|
||||||
|
onClick={() => handleClick(section.id)}
|
||||||
|
className={`w-full text-left px-3 py-3 rounded-md text-sm transition-colors ${
|
||||||
|
activeSection === section.id
|
||||||
|
? 'bg-primary-500/15 text-primary-400 font-semibold'
|
||||||
|
: 'text-titanio/70 hover:text-titanio hover:bg-white/5'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{section.title}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
return (
|
||||||
|
<div className="mb-6">
|
||||||
|
<Accordion
|
||||||
|
expanded={tocExpanded}
|
||||||
|
onChange={(_, expanded) => setTocExpanded(expanded)}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.03)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.08)',
|
||||||
|
borderRadius: '8px !important',
|
||||||
|
'&:before': { display: 'none' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AccordionSummary
|
||||||
|
expandIcon={<ExpandMoreIcon sx={{ color: 'rgba(168,184,192,0.7)' }} />}
|
||||||
|
sx={{
|
||||||
|
color: 'rgba(242,243,246,0.9)',
|
||||||
|
fontWeight: 600,
|
||||||
|
minHeight: 48,
|
||||||
|
'& .MuiAccordionSummary-content': { margin: '12px 0' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Table of Contents
|
||||||
|
</AccordionSummary>
|
||||||
|
<AccordionDetails sx={{ pt: 0 }}>
|
||||||
|
{tocContent}
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<aside className="sticky top-20 w-64 flex-shrink-0 max-h-[calc(100vh-6rem)] overflow-y-auto pr-4">
|
||||||
|
<h2 className="text-sm font-semibold text-titanio/50 uppercase tracking-wider mb-4 px-3">
|
||||||
|
Contents
|
||||||
|
</h2>
|
||||||
|
{tocContent}
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
};
|
||||||
26
frontend/src/pages/GuidePage/components/GuideScreenshot.tsx
Normal file
26
frontend/src/pages/GuidePage/components/GuideScreenshot.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
interface GuideScreenshotProps {
|
||||||
|
src: string;
|
||||||
|
alt: string;
|
||||||
|
caption?: string;
|
||||||
|
mobile?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GuideScreenshot = ({ src, alt, caption, mobile }: GuideScreenshotProps) => {
|
||||||
|
return (
|
||||||
|
<figure className={`my-6 ${mobile ? 'max-w-[375px]' : 'max-w-4xl'} mx-auto`}>
|
||||||
|
<div className="rounded-lg overflow-hidden border border-white/10 shadow-lg shadow-black/20">
|
||||||
|
<img
|
||||||
|
src={src}
|
||||||
|
alt={alt}
|
||||||
|
loading="lazy"
|
||||||
|
className="w-full h-auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{caption && (
|
||||||
|
<figcaption className="mt-2 text-center text-sm text-titanio/70 italic">
|
||||||
|
{caption}
|
||||||
|
</figcaption>
|
||||||
|
)}
|
||||||
|
</figure>
|
||||||
|
);
|
||||||
|
};
|
||||||
68
frontend/src/pages/GuidePage/components/GuideTable.tsx
Normal file
68
frontend/src/pages/GuidePage/components/GuideTable.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Paper,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
interface GuideTableProps {
|
||||||
|
headers: string[];
|
||||||
|
rows: string[][];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GuideTable = ({ headers, rows }: GuideTableProps) => {
|
||||||
|
return (
|
||||||
|
<TableContainer
|
||||||
|
component={Paper}
|
||||||
|
sx={{
|
||||||
|
my: 3,
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.03)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.08)',
|
||||||
|
borderRadius: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table size="small">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
{headers.map((header, idx) => (
|
||||||
|
<TableCell
|
||||||
|
key={idx}
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
color: 'rgba(168,184,192,0.9)',
|
||||||
|
borderBottom: '1px solid rgba(255,255,255,0.08)',
|
||||||
|
fontSize: '0.85rem',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{header}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{rows.map((row, rowIdx) => (
|
||||||
|
<TableRow key={rowIdx}>
|
||||||
|
{row.map((cell, cellIdx) => (
|
||||||
|
<TableCell
|
||||||
|
key={cellIdx}
|
||||||
|
sx={{
|
||||||
|
color: 'rgba(168,184,192,0.75)',
|
||||||
|
borderBottom: '1px solid rgba(255,255,255,0.04)',
|
||||||
|
fontSize: '0.85rem',
|
||||||
|
verticalAlign: 'top',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cell}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
114
frontend/src/pages/GuidePage/guideTypes.ts
Normal file
114
frontend/src/pages/GuidePage/guideTypes.ts
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
export interface GuideSubSection {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GuideSection {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
subSections: GuideSubSection[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const guideSections: GuideSection[] = [
|
||||||
|
{
|
||||||
|
id: 'getting-started',
|
||||||
|
title: '1. Getting Started',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'creating-an-account', title: 'Creating an Account' },
|
||||||
|
{ id: 'logging-in', title: 'Logging In' },
|
||||||
|
{ id: 'onboarding', title: 'Onboarding' },
|
||||||
|
{ id: 'trouble-logging-in', title: 'Trouble Logging In' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dashboard',
|
||||||
|
title: '2. Dashboard',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'your-fleet-overview', title: 'Your Fleet Overview' },
|
||||||
|
{ id: 'quick-actions', title: 'Quick Actions' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vehicles',
|
||||||
|
title: '3. Vehicles',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'viewing-your-vehicles', title: 'Viewing Your Vehicles' },
|
||||||
|
{ id: 'adding-a-vehicle', title: 'Adding a Vehicle' },
|
||||||
|
{ id: 'vin-decode', title: 'VIN Decode' },
|
||||||
|
{ id: 'vehicle-detail-page', title: 'Vehicle Detail Page' },
|
||||||
|
{ id: 'editing-a-vehicle', title: 'Editing a Vehicle' },
|
||||||
|
{ id: 'deleting-a-vehicle', title: 'Deleting a Vehicle' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'fuel-logs',
|
||||||
|
title: '4. Fuel Logs',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'fuel-logs-overview', title: 'Fuel Logs Overview' },
|
||||||
|
{ id: 'logging-fuel', title: 'Logging Fuel' },
|
||||||
|
{ id: 'receipt-scanning', title: 'Receipt Scanning' },
|
||||||
|
{ id: 'editing-and-deleting-fuel-logs', title: 'Editing and Deleting Fuel Logs' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'maintenance',
|
||||||
|
title: '5. Maintenance',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'maintenance-records', title: 'Maintenance Records' },
|
||||||
|
{ id: 'adding-a-maintenance-record', title: 'Adding a Maintenance Record' },
|
||||||
|
{ id: 'maintenance-schedules', title: 'Maintenance Schedules' },
|
||||||
|
{ id: 'creating-a-schedule', title: 'Creating a Schedule' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'gas-stations',
|
||||||
|
title: '6. Gas Stations',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'finding-stations', title: 'Finding Stations' },
|
||||||
|
{ id: 'saved-stations', title: 'Saved Stations' },
|
||||||
|
{ id: 'premium-93-stations', title: 'Premium 93 Stations' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'documents',
|
||||||
|
title: '7. Documents',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'documents-overview', title: 'Documents Overview' },
|
||||||
|
{ id: 'adding-a-document', title: 'Adding a Document' },
|
||||||
|
{ id: 'document-types', title: 'Document Types' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'settings',
|
||||||
|
title: '8. Settings',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'profile', title: 'Profile' },
|
||||||
|
{ id: 'security-and-privacy', title: 'Security and Privacy' },
|
||||||
|
{ id: 'subscription', title: 'Subscription' },
|
||||||
|
{ id: 'notifications', title: 'Notifications' },
|
||||||
|
{ id: 'appearance-and-units', title: 'Appearance and Units' },
|
||||||
|
{ id: 'data-import-and-export', title: 'Data Import and Export' },
|
||||||
|
{ id: 'account-actions', title: 'Account Actions' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'subscription-tiers',
|
||||||
|
title: '9. Subscription Tiers and Pro Features',
|
||||||
|
subSections: [
|
||||||
|
{ id: 'tier-comparison', title: 'Tier Comparison' },
|
||||||
|
{ id: 'vin-camera-scanning', title: 'VIN Camera Scanning (Pro)' },
|
||||||
|
{ id: 'fuel-receipt-scanning', title: 'Fuel Receipt Scanning (Pro)' },
|
||||||
|
{ id: 'maintenance-receipt-scanning', title: 'Maintenance Receipt Scanning (Pro)' },
|
||||||
|
{ id: 'maintenance-manual-pdf', title: 'Maintenance Manual PDF (Pro)' },
|
||||||
|
{ id: 'email-ingestion', title: 'Email Ingestion (Pro)' },
|
||||||
|
{ id: 'shared-vehicle-documents', title: 'Shared Vehicle Documents (Pro)' },
|
||||||
|
{ id: 'community-station-submissions', title: 'Community Station Submissions (Pro)' },
|
||||||
|
{ id: 'managing-your-subscription', title: 'Managing Your Subscription' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mobile-experience',
|
||||||
|
title: '10. Mobile Experience',
|
||||||
|
subSections: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const DashboardSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="dashboard" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">2. Dashboard</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 2...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const DocumentsSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="documents" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">7. Documents</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 3...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const FuelLogsSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="fuel-logs" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">4. Fuel Logs</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 2...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const GasStationsSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="gas-stations" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">6. Gas Stations</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 3...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const GettingStartedSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="getting-started" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">1. Getting Started</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 2...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const MaintenanceSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="maintenance" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">5. Maintenance</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 2...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const MobileExperienceSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="mobile-experience" className="py-8 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">10. Mobile Experience</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 3...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const SettingsSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="settings" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">8. Settings</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 3...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const SubscriptionSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="subscription-tiers" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">9. Subscription Tiers and Pro Features</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 3...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export const VehiclesSection = () => {
|
||||||
|
return (
|
||||||
|
<section id="vehicles" className="py-8 border-b border-white/5 scroll-mt-24">
|
||||||
|
<h2 className="text-2xl font-bold text-avus mb-4">3. Vehicles</h2>
|
||||||
|
<p className="text-titanio/70">Content loading in Milestone 2...</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
12
frontend/src/pages/GuidePage/sections/index.ts
Normal file
12
frontend/src/pages/GuidePage/sections/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { lazy } from 'react';
|
||||||
|
|
||||||
|
export const GettingStartedSection = lazy(() => import('./GettingStartedSection').then(m => ({ default: m.GettingStartedSection })));
|
||||||
|
export const DashboardSection = lazy(() => import('./DashboardSection').then(m => ({ default: m.DashboardSection })));
|
||||||
|
export const VehiclesSection = lazy(() => import('./VehiclesSection').then(m => ({ default: m.VehiclesSection })));
|
||||||
|
export const FuelLogsSection = lazy(() => import('./FuelLogsSection').then(m => ({ default: m.FuelLogsSection })));
|
||||||
|
export const MaintenanceSection = lazy(() => import('./MaintenanceSection').then(m => ({ default: m.MaintenanceSection })));
|
||||||
|
export const GasStationsSection = lazy(() => import('./GasStationsSection').then(m => ({ default: m.GasStationsSection })));
|
||||||
|
export const DocumentsSection = lazy(() => import('./DocumentsSection').then(m => ({ default: m.DocumentsSection })));
|
||||||
|
export const SettingsSection = lazy(() => import('./SettingsSection').then(m => ({ default: m.SettingsSection })));
|
||||||
|
export const SubscriptionSection = lazy(() => import('./SubscriptionSection').then(m => ({ default: m.SubscriptionSection })));
|
||||||
|
export const MobileExperienceSection = lazy(() => import('./MobileExperienceSection').then(m => ({ default: m.MobileExperienceSection })));
|
||||||
Reference in New Issue
Block a user