Skip to main content
Version: 1.0.0

Home Page

Author: Carmine Antonio Bonavoglia Creation Date: 29/10/2025
Last Reviewer: Carmine Antonio Bonavoglia Last Updated: 31/10/2025

Introduction

The Home page (/src/pages/Home.js) serves as the primary dashboard and landing interface for authenticated users in ARShades Studio V2. This page implements sophisticated progressive loading patterns, intelligent caching, and role-based content delivery to optimise both performance and user experience.

Document Scope

This documentation covers:

  • Progressive loading and lazy component strategies
  • Custom cache manager implementation
  • Role-based access control mechanisms
  • Component lifecycle and state management
  • Data flow and Redux integration
  • Performance optimisations
  • Error handling patterns

Prerequisites

Readers should be familiar with:

  • React fundamentals (components, hooks, state, effects)
  • React Suspense and lazy loading patterns
  • Redux state management
  • Firebase data structures
  • Ant Design theming system

Overview

The Home page (/src/pages/Home.js) is the primary landing and dashboard interface for authenticated users in ARShades Studio V2. It serves as the central hub for accessing key features including catalogues, ARShades library assets, subscriptions, and performance analytics. The page implements sophisticated progressive loading, role-based access control, and client-side caching strategies to ensure optimal performance and user experience.

Architecture Philosophy

The Home page follows a lazy-loading, progressive enhancement architecture designed to prioritise initial page rendering whilst progressively loading additional features. This approach balances several competing concerns:

  • Fast Time-to-Interactive – General information renders immediately
  • Role-Based Access Control – Content visibility depends on user role
  • Resource Optimisation – Components load asynchronously with configurable delays
  • Intelligent Caching – Frequently accessed data is cached for 5 minutes

Component Hierarchy

Home.js (Page Container)
├── GeneralInfoSection (Eager Load - 0ms)
├── CatalogsSection (Lazy Load - 500ms)
├── ARShadesLibrarySection (Lazy Load - 1000ms)
├── SubscriptionsSection (Lazy Load - 1500ms, Role-Restricted)
└── KPISection (Lazy Load - 2000ms, Role-Restricted)

Root Component: Home.js

Location: /src/pages/Home.js

Purpose: Orchestrates the entire home page experience, managing section visibility, progressive loading, role-based access, and data initialisation.

Core Functionality

1. Cache Manager System

A custom HomeCache singleton class manages client-side caching with configurable expiration.

class HomeCache {
constructor() {
this.cache = new Map();
this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
}
}

Key Methods:

  • set(key, data) – Stores data with timestamp
  • get(key) – Retrieves data if not expired
  • clear() – Flushes entire cache
  • has(key) – Checks cache validity
  • isExpired(key) – Validates cache freshness

Cache Strategy: Each cached item is tagged with a timestamp. On retrieval, the cache automatically checks expiration. If the data exceeds the 5-minute timeout, it is automatically purged and null is returned.

Usage Pattern:

// Store in cache
homeCache.set("dashboard_metrics", data);

// Retrieve from cache
const cachedData = homeCache.get("dashboard_metrics");

2. State Management

Local Component State

const [visibleSections, setVisibleSections] = useState({
general: true, // Always visible immediately
catalogs: false,
library: false,
subscriptions: false,
kpi: false,
});

const [initialLoading, setInitialLoading] = useState(true);
const [userRole, setUserRole] = useState(null);

State Dictionary:

State VariablePurposeInitial ValueType
visibleSectionsControls rendering of each section{ general: true, ...false }Object
initialLoadingIndicates app initialisation phasetrueBoolean
userRoleCurrent user's role for authorisationnullString

Redux State Integration

const rxCatalogues = useSelector(
(state) => state.catalogues?.listaCatalogues || []
);
const dispatch = useDispatch();

Redux Collection: state.catalogues.listaCatalogues

  • Type: Array of catalogue objects
  • Purpose: Stores user's accessible catalogues
  • Update Action: setListaCatalogues(catalogues)
  • Fallback: Empty array if not loaded

3. Role-Based Access Control (RBAC)

The page implements strict role-based visibility rules for advanced features.

const canViewSubscriptionsAndKPI = (role) => {
const restrictedRoles = ["Modellista", "ModellerSupervisor"];
return !restrictedRoles.includes(role);
};

Access Rules:

RoleCan View SubscriptionsCan View KPINotes
Super Admin✅ Yes✅ YesFull access globally
Admin✅ Yes✅ YesFull access within client scope
Member✅ Yes✅ YesFull access within client scope
Modellista❌ No❌ NoModel creation role, restricted
ModellerSupervisor❌ No❌ NoModel supervision role, restricted
Default (other roles)✅ Yes✅ YesDefault to permitted

Implementation: Restricted roles (defined in restrictedRoles array) are explicitly blacklisted. All other roles receive access by default.

4. Component Lifecycle Management

Phase 1: Initialisation

useEffect(() => {
const loadUserData = () => {
// Retrieve user role from secure storage
const role = secureGetItem("role");
setUserRole(role);

// Load catalogues if not already in Redux
if (rxCatalogues.length === 0) {
const savedCatalogues = localStorage.getItem("catalogues");
if (savedCatalogues) {
try {
const parsedCatalogues = JSON.parse(savedCatalogues);
dispatch(setListaCatalogues(parsedCatalogues));
} catch (error) {
console.error("Error parsing saved catalogues:", error);
}
}
}
};

loadUserData();
setInitialLoading(false);
}, [rxCatalogues.length, dispatch]);

Initialisation Flow:

  1. Retrieve user role from encrypted storage (secureGetItem)
  2. Check if catalogues are already in Redux state
  3. If not, attempt to load from localStorage as fallback
  4. Parse and dispatch to Redux
  5. Mark initial loading as complete

Phase 2: Progressive Loading

useEffect(() => {
if (initialLoading || !userRole) return;

const loadSectionsProgressively = () => {
const canViewAdvanced = canViewSubscriptionsAndKPI(userRole);

const delays = [
{ section: "catalogs", delay: 500 },
{ section: "library", delay: 1000 },
...(canViewAdvanced
? [
{ section: "subscriptions", delay: 1500 },
{ section: "kpi", delay: 2000 },
]
: []),
];

delays.forEach(({ section, delay }) => {
setTimeout(() => {
setVisibleSections((prev) => ({
...prev,
[section]: true,
}));
}, delay);
});
};

loadSectionsProgressively();
}, [initialLoading, userRole]);

Progressive Loading Timeline:

Time (ms)SectionEvent
0GeneralInfoSectionRenders immediately (eager)
500CatalogsSectionBecomes visible, begins lazy loading
1000ARShadesLibrarySectionBecomes visible, begins lazy loading
1500SubscriptionsSectionConditional on role, becomes visible
2000KPISectionConditional on role, becomes visible

Benefits:

  • Fast First Paint – General information visible within 0ms
  • Resource Distribution – Component loading spread across 2 seconds
  • User Feedback – Progressive content reveals indicate active loading
  • Network Optimisation – Prevents thundering herd of simultaneous requests

5. Component Rendering

Lazy-Loaded Component Pattern

const SectionLoader = ({ height = "200px" }) => (
<div
style={{
height,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: token.colorFillQuaternary,
borderRadius: "0.5rem",
marginBottom: "2rem",
}}
>
<Spin size="large" />
</div>
);

Placeholder Behaviour:

  • Displays whilst component is hidden or lazy-loading
  • Uses Ant Design theme tokens for consistent styling
  • Configurable height for different section sizes
  • Visual feedback via spinning loader animation

Conditional Rendering

General Information (Always Visible):

<div style={{ marginBottom: "2rem" }}>
<Suspense fallback={<SectionLoader height="150px" />}>
<GeneralInfoSection />
</Suspense>
</div>

Catalogues Section (Lazy-Loaded):

<div style={{ marginBottom: "2rem" }}>
{visibleSections.catalogs ? (
<Suspense fallback={<SectionLoader height="200px" />}>
<CatalogsSection />
</Suspense>
) : (
<SectionLoader height="200px" />
)}
</div>

Role-Restricted Sections (Conditional Access):

{
canViewAdvanced && (
<div style={{ marginBottom: "2rem" }}>
{visibleSections.subscriptions ? (
<Suspense fallback={<SectionLoader height="200px" />}>
<SubscriptionsSection />
</Suspense>
) : (
<SectionLoader height="200px" />
)}
</div>
);
}

6. Lazy-Loaded Child Components

GeneralInfoSection

File: /src/components/Home/GeneralInfoSection.js

Purpose: Displays general user information, account overview, and dashboard introduction.

Rendering: Eager-loaded, renders immediately without delay.

Typical Content:

  • User greeting and welcome message
  • Quick statistics overview
  • Account status information

CatalogsSection

File: /src/components/Home/CatalogsSection.js

Purpose: Displays user's accessible catalogues and catalogue management interface.

Rendering: Lazy-loaded at 500ms delay.

Typical Content:

  • List of user's catalogues
  • Catalogue previews with thumbnails
  • Quick-access buttons for catalogue operations
  • Catalogue status indicators

Data Source:

  • Redux state: state.catalogues.listaCatalogues
  • Firebase collection: Catalogues

ARShadesLibrarySection

File: /src/components/Home/ARShadesLibrarySection.js

Purpose: Provides access to the ARShades Library asset collection for eyewear customisation.

Rendering: Lazy-loaded at 1000ms delay.

Typical Content:

  • Asset library browsing
  • Available 3D models and templates
  • Asset preview and download options
  • Usage statistics

Data Source:

  • Firebase collection: CataloguesVariants
  • Service function: getModelsFromFirebase()

SubscriptionsSection

File: /src/components/Home/SubscriptionsSection.js

Purpose: Shows user subscriptions, plan details, and subscription management.

Rendering: Lazy-loaded at 1500ms delay, role-restricted.

Access Restrictions: NOT visible to Modellista or ModellerSupervisor roles.

Typical Content:

  • Active subscriptions
  • Plan details and tier information
  • Usage quotas and limits
  • Upgrade/downgrade options

KPISection

File: /src/components/Home/KPISection.js

Purpose: Displays Key Performance Indicators (KPI) and analytics dashboard.

Rendering: Lazy-loaded at 2000ms delay, role-restricted.

Access Restrictions: NOT visible to Modellista or ModellerSupervisor roles.

Typical Content:

  • Dashboard KPI metrics
  • Charts and visualisations (line charts, pie charts)
  • Performance analytics
  • Trend analysis and historical data

Data Source: /src/services/home.js

  • Function: fetchAggregateData()
  • Function: returnDashboardData()
  • Function: NumberAnimated() component for animated counters

Data Flow

User Role Retrieval

Local Storage (encrypted)

secureGetItem("role")

State: userRole

Passed to: canViewSubscriptionsAndKPI()

Controls: Section visibility & Redux state availability

Catalogue Data Flow

Redux State: state.catalogues.listaCatalogues
↓ (if empty)
↓ localStorage.getItem("catalogues")

↓ (if found)
↓ JSON.parse()

↓ dispatch(setListaCatalogues())

Redux State Updated

Child components: CatalogsSection

Progressive Section Loading

User loads Home page

Phase 1: Initialisation (useEffect #1)
→ Load role → Load catalogues
→ Set initialLoading = false

Phase 2: Progressive Loading (useEffect #2)
→ Trigger at 0ms, 500ms, 1000ms, 1500ms, 2000ms
→ Update visibleSections state

Rendering phase for each section
→ Suspense boundary catches async operations
→ SectionLoader placeholder whilst loading
→ Component renders when ready

Security Considerations

Encrypted Storage

secureGetItem("role"); // Decrypts encrypted role from localStorage

Implementation: Uses AES encryption with environment variable keys (REACT_APP_ESK).

Security Features:

  • Encrypted storage in localStorage (cannot be read as plaintext)
  • Automatic corruption detection and cleanup
  • Fallback to null if decryption fails

Protected Data:

  • User role
  • User email
  • User ID
  • Sensitive profile information

Redux State Protection

const rxCatalogues = useSelector(
(state) => state.catalogues?.listaCatalogues || []
);

Safety Patterns:

  • Optional chaining (?.) prevents null reference errors
  • Fallback to empty array prevents undefined state
  • Redux state immutability prevents accidental mutations

Performance Optimisations

1. Lazy Component Loading

const GeneralInfoSection = lazy(() =>
import("../components/Home/GeneralInfoSection")
);

Benefits:

  • Code splitting via dynamic imports
  • Separate bundle chunks per component
  • Reduced initial bundle size
  • Components load only when needed

2. Suspense Boundaries

<Suspense fallback={<SectionLoader height="200px" />}>
<CatalogsSection />
</Suspense>

Benefits:

  • Graceful handling of async component loading
  • Placeholder UI whilst awaiting component code
  • Prevents white screen of death
  • Better perceived performance

3. Progressive Delay Strategy

const delays = [
{ section: "catalogs", delay: 500 },
{ section: "library", delay: 1000 },
{ section: "subscriptions", delay: 1500 },
{ section: "kpi", delay: 2000 },
];

Benefits:

  • Spreads network requests across timeline
  • Prevents browser parallelisation limits (typically 6 concurrent)
  • Reduces CPU saturation from simultaneous rendering
  • Improves perceived responsiveness

4. Client-Side Caching

const homeCache = new HomeCache(); // 5-minute cache

Benefits:

  • Reduces redundant Firebase queries
  • Decreases API latency perception
  • Improves offline resilience
  • Reduces server load

Error Handling

Graceful Degradation

Catalogue Loading Fallback:

if (rxCatalogues.length === 0) {
const savedCatalogues = localStorage.getItem("catalogues");
// ... loads from localStorage if Redux is empty
}

Error Recovery:

catch (error) {
console.error("Error parsing saved catalogues:", error);
// Silently continues; user sees empty catalogues instead of crash
}

Initial Loading State

if (initialLoading) {
return (
<div style={{...}}>
<Spin size="large" />
</div>
);
}

Purpose:

  • Prevents rendering before critical data is loaded
  • Shows full-screen spinner during initialisation
  • Ensures user role is available before section checks

Redux Integration

Actions Dispatched

Action: setListaCatalogues(catalogues)

Type: SET_LISTA_CATALOGUES

Payload: Array of catalogue objects

Side Effects:

  • Updates state.catalogues.listaCatalogues
  • Persists to localStorage as backup
  • Available to all consumer components via useSelector

Object Schema:

interface Catalogue {
id: string;
appIdIos?: string;
appPackage?: string;
appPackageIos?: string;
codePath?: string;
dataConsumption?: string;
descriptionEn?: string;
descriptionIt?: string;
hdrEnvironment?: string;
isPublic?: boolean;
list_service?: string[];
nameCatalog?: string;
showSingleDotList?: boolean;
skin?: string;
storage_consumption?: {
consumption: number;
modelsNumber: number;
};
takePicTemplate?: string;
urlLogo?: string;
webDomain?: string;
webUrl?: string;
}

UI Framework Integration

Ant Design Theme Integration

const { token } = theme.useToken();

// Usage in SectionLoader
backgroundColor: token.colorFillQuaternary,
borderRadius: "0.5rem",

Theme Tokens Used:

  • token.colorFillQuaternary – Secondary background colour

Benefits:

  • Automatic dark mode support
  • Consistent design system application
  • Responsive to theme changes

Styling Strategy

Inline Styles

style={{
padding: "0 16px"
}}

Applied at:

  • Page container
  • Section wrappers
  • Loader placeholders

Purpose:

  • Quick responsive spacing
  • Consistent margin/padding (2rem = 32px between sections)
  • Theme-aware colours via Ant Design tokens

Testing Considerations

Test Scenarios

  1. Role-Based Access

    • Verify Modellista users cannot see KPI section
    • Verify Admin users see all sections
    • Test role changes affect visibility
  2. Progressive Loading

    • Verify initial load shows only GeneralInfoSection
    • Check section visibility timing
    • Ensure proper placeholder display
  3. Catalogue Initialisation

    • Test with existing Redux state
    • Test with localStorage fallback
    • Test with corrupted JSON in localStorage
  4. Error Handling

    • Test with missing role
    • Test with empty catalogues
    • Test with Firebase unavailable
  5. Performance

    • Monitor lazy-load timing
    • Verify no unnecessary re-renders
    • Check cache effectiveness

Future Enhancements

Proposed Improvements

  1. Configurable Delay Timing – Allow administrators to adjust progressive load delays
  2. Section Pinning – Enable users to pin favourite sections to top
  3. Customisable Section Order – Let users reorder sections by preference
  4. Advanced Analytics – Add filtering and drill-down capabilities to KPI section
  5. Offline Support – Implement service workers for offline access
  6. Real-Time Updates – Add Firestore listeners for live data synchronisation
  7. A/B Testing – Test different loading strategies and delays
  8. Performance Monitoring – Track and report Core Web Vitals
  • /src/components/Home/GeneralInfoSection.js
  • /src/components/Home/CatalogsSection.js
  • /src/components/Home/ARShadesLibrarySection.js
  • /src/components/Home/SubscriptionsSection.js
  • /src/components/Home/KPISection.js
  • /src/components/Home/HomeCard.js – Reusable card component
  • /src/components/Home/StatCard.js – Statistics display card
  • /src/components/Home/UserCard.js – User profile card
  • /src/components/Home/LineChart.js – Chart visualisation
  • /src/components/Home/PieChart.js – Chart visualisation
  • /src/services/home.js – Data fetching and aggregation
  • /src/data/utils.js – Encryption and storage utilities
  • /src/redux/Catalogues/actions.js – Redux actions
  • /src/redux/Catalogues/types.js – Action type constants

Useful References