Skip to main content

Tech Stack

Sociales is built with modern web technologies optimized for performance and developer experience:

Core Framework

  • React 18.2.0 - UI library with concurrent rendering features
  • Vite 5.1.4 - Next-generation build tool for faster development
  • React Router DOM 6.22.0 - Client-side routing with lazy loading support

Backend Services

  • Firebase 10.8.0 - Authentication and backend services
    • Firebase Authentication for Google Sign-In
    • Firebase App initialization

Development Tools

  • ESLint - Code linting with React-specific rules
  • gh-pages - Automated deployment to GitHub Pages

Application Entry Point

The application initializes in src/main.jsx using HashRouter for GitHub Pages compatibility:
import React from 'react'
import ReactDOM from 'react-dom/client'
import { HashRouter } from 'react-router-dom'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
    <React.StrictMode>
        <HashRouter>
            <App />
        </HashRouter>
    </React.StrictMode>,
)
HashRouter is used instead of BrowserRouter because GitHub Pages doesn’t support server-side routing. This allows the app to work correctly with direct URL access.

Routing Structure

The application uses React Router with code splitting for optimal performance:
import React, { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';
import Layout from './components/Layout';

// Lazy load pages for better initial performance
const Home = lazy(() => import('./pages/Home'));
const SubjectSelection = lazy(() => import('./pages/SubjectSelection'));
const LessonsList = lazy(() => import('./pages/LessonsList'));
const LessonView = lazy(() => import('./pages/LessonView'));

function App() {
    return (
        <Suspense fallback={<PageLoader />}>
            <Routes>
                <Route path="/" element={<Layout />}>
                    <Route index element={<SubjectSelection />} />
                    <Route path="sociales" element={<Home />} />
                    <Route path="grade/:gradeId" element={<LessonsList />} />
                    <Route path="grade/:gradeId/lesson/:lessonId" element={<LessonView />} />
                </Route>
            </Routes>
        </Suspense>
    );
}

Route Structure

RouteComponentPurpose
/SubjectSelectionLanding page for subject selection
/socialesHomeSocial studies home page
/grade/:gradeIdLessonsListList of lessons for a specific grade
/grade/:gradeId/lesson/:lessonIdLessonViewIndividual lesson content

Performance Optimizations

Code Splitting

All page components are lazy-loaded using React’s lazy() and Suspense:
const Home = lazy(() => import('./pages/Home'));
This reduces the initial bundle size and improves the First Contentful Paint (FCP) metric.

Loading States

A custom PageLoader component provides visual feedback during page transitions:
const PageLoader = () => (
    <div style={{ 
        padding: '2rem', 
        textAlign: 'center', 
        fontFamily: 'var(--font-heading)', 
        color: 'var(--primary-color)' 
    }}>
        <h2>Cargando... 📚</h2>
    </div>
);

Authentication Architecture

Sociales uses Firebase Authentication with a React Context provider. See the authentication implementation in src/context/AuthContext.jsx:
import { createContext, useContext, useState, useEffect } from 'react';
import { getAuth, onAuthStateChanged, signInWithPopup, GoogleAuthProvider, signOut } from 'firebase/auth';
import app from '../firebase/config';

const AuthContext = createContext();

export const useAuth = () => useContext(AuthContext);

export const AuthProvider = ({ children }) => {
    const [currentUser, setCurrentUser] = useState(null);
    const [loading, setLoading] = useState(true);
    const auth = getAuth(app);

    useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setCurrentUser(user);
            setLoading(false);
        });

        return unsubscribe;
    }, []);

    const loginWithGoogle = () => {
        const provider = new GoogleAuthProvider();
        return signInWithPopup(auth, provider);
    };

    const logout = () => {
        return signOut(auth);
    };

    const value = {
        currentUser,
        loginWithGoogle,
        logout
    };

    return (
        <AuthContext.Provider value={value}>
            {!loading && children}
        </AuthContext.Provider>
    );
};

Authentication Features

  • Google Sign-In via Firebase Authentication
  • Auth State Management using React Context
  • Loading States to prevent layout shifts during auth checks
  • Auth Listener that updates user state in real-time

Using Authentication in Components

import { useAuth } from '../context/AuthContext';

function MyComponent() {
    const { currentUser, loginWithGoogle, logout } = useAuth();
    
    if (!currentUser) {
        return <button onClick={loginWithGoogle}>Sign in with Google</button>;
    }
    
    return (
        <div>
            <p>Welcome, {currentUser.displayName}!</p>
            <button onClick={logout}>Sign out</button>
        </div>
    );
}

Build Configuration

Vite is configured with a base path for GitHub Pages deployment:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  base: '/sociales/',
})
The base: '/sociales/' setting ensures all assets load correctly when deployed to the GitHub Pages subdirectory.

Build docs developers (and LLMs) love