Directory Overview
Q-Sopa follows a standard React application structure with clear separation of concerns:
q-sopa/
├── public/ # Static assets
├── src/ # Source code
│ ├── assets/ # Images and media files
│ ├── components/ # Reusable React components
│ ├── pages/ # Page-level components
│ ├── services/ # API and external services
│ ├── App.jsx # Root application component
│ ├── App.css # Root application styles
│ ├── main.jsx # Application entry point
│ └── index.css # Global styles
├── index.html # HTML template
├── package.json # Dependencies and scripts
├── vite.config.js # Vite configuration
└── eslint.config.js # ESLint configuration
Source Directory Structure
Entry Points
main.jsx
Application bootstrap and React root rendering
App.jsx
Root component that loads the main page
main.jsx
The entry point that initializes the React application:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
Key Features:
- Uses React 19’s
createRoot API
- Wraps app in
StrictMode for development warnings
- Imports global styles before components
App.jsx
The root application component:
import Menu from "./pages/Menu";
import "./App.css";
function App() {
return <Menu />;
}
export default App
Currently, the app renders only the Menu page. This structure allows for easy expansion to multiple pages with routing.
Components Directory
Reusable UI components are organized in src/components/ with a consistent structure:
components/
├── Categories/
│ ├── Categories.jsx
│ └── Categories.css
├── LogoSplash/
│ ├── LogoSplash.jsx
│ └── LogoSplash.css
├── ProductCard/
│ ├── ProductCard.jsx
│ └── ProductCard.css
├── navbar/
│ ├── Navbar.jsx
│ └── Navbar.css
└── footer/
├── footer.jsx
└── footer.css
Each component follows the component-scoped CSS pattern where styles are co-located with their components.
Component Examples
Navbar Component (src/components/navbar/Navbar.jsx):
import "./Navbar.css";
import logo from "../../assets/logo_Q-spoa.jpg";
import Categories from "../Categories/Categories";
export default function Navbar({ onCategoryChange }) {
return (
<header className="navbar-wrapper">
<div className="navbar">
{/* Logo */}
<div className="navbar-left">
<a href="#">
<img src={logo} alt="Burger Bistro Logo" className="navbar-logo" />
</a>
</div>
{/* Categories */}
<div className="navbar-center">
<Categories onCategoryChange={onCategoryChange} />
</div>
</div>
</header>
);
}
ProductCard Component (src/components/ProductCard/ProductCard.jsx):
import "./ProductCard.css";
export default function ProductCard({ title, price, image, badge }) {
return (
<div className="product-card">
{badge && <div className="badge">{badge}</div>}
<img src={image} alt={title} />
<div className="product-info">
<h4>{title}</h4>
<span>${price}</span>
</div>
<button className="product-btn">Ingredientes</button>
</div>
);
}
Pages Directory
Page-level components that represent full views:
pages/
├── Menu.jsx
└── Menu.css
Menu Page (src/pages/Menu.jsx):
import { useState, useEffect } from "react";
import Navbar from "../components/navbar/Navbar";
import Footer from "../components/footer/footer";
import ProductCard from "../components/ProductCard/ProductCard";
import LogoSplash from "../components/LogoSplash/LogoSplash";
import { getProductsByCategory } from "../services/api";
import "./Menu.css";
export default function Menu() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [activeCategoryId, setActiveCategoryId] = useState(null);
const handleCategoryChange = (categoryId) => {
setActiveCategoryId(categoryId);
};
useEffect(() => {
if (activeCategoryId === null) return;
setLoading(true);
setError(null);
getProductsByCategory(activeCategoryId)
.then((data) => setProducts(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, [activeCategoryId]);
return (
<>
<Navbar onCategoryChange={handleCategoryChange} />
<main className="menu-container">
{/* Content rendering logic */}
</main>
<Footer />
</>
);
}
Key Patterns:
- Uses React Hooks for state management (
useState, useEffect)
- Implements data fetching with loading and error states
- Conditional rendering based on application state
Services Directory
API and external service integrations:
API Service (src/services/api.js):
const BASE_URL = "https://apiqsp-production.up.railway.app";
export const getCategorias = async () => {
const res = await fetch(`${BASE_URL}/categories`);
if (!res.ok) throw new Error("Error al cargar categorías");
return res.json();
};
export const getComidas = async () => {
const res = await fetch(`${BASE_URL}/products`);
if (!res.ok) throw new Error("Error al cargar comidas");
return res.json();
};
export const getProductsByCategory = async (categoryId) => {
const res = await fetch(`${BASE_URL}/products/category/${categoryId}`);
if (!res.ok) throw new Error("Error al cargar productos de la categoría");
return res.json();
};
All API calls are centralized in the services directory, making it easy to update endpoints or add new API integrations.
Assets Directory
Static assets like images and logos:
assets/
├── logo_Q-spoa.jpg
└── react.svg
Assets are imported directly in components:
import logo from "../../assets/logo_Q-spoa.jpg";
Naming Conventions
File Naming
Components
PascalCase for component filesProductCard.jsx, Navbar.jsx
Styles
Match component nameProductCard.css, Navbar.css
Services
camelCase for utility filesapi.js, helpers.js
Pages
PascalCase for page componentsMenu.jsx, Home.jsx
CSS Class Naming
The project uses BEM-inspired (Block Element Modifier) naming:
.navbar-wrapper /* Block */
.navbar-left /* Block with location modifier */
.navbar-logo /* Element */
.category-btn /* Block */
.category-btn.active /* Block with state modifier */
Component Export Pattern
All components use default exports:
export default function ComponentName() {
// component logic
}
Services use named exports:
export const getCategorias = async () => { /* ... */ };
export const getProductsByCategory = async () => { /* ... */ };
Component Architecture Patterns
Container/Presentational Pattern
- Pages act as containers managing state and data fetching
- Components are presentational, receiving data via props
State Management
Local State
Uses React’s useState for component-level state
Side Effects
Manages side effects with useEffect for data fetching
Props Drilling
Passes callbacks and data through props (no global state library yet)
Responsive Design
Components implement responsive behavior through:
- CSS media queries
- Conditional rendering (desktop vs mobile)
- Mobile-first drawer navigation pattern
The Categories component implements a sophisticated mobile drawer that shows on screens below 768px. See the Styling Guide for implementation details.
Next Steps
Development Setup
Set up your development environment
Styling Guide
Learn about CSS patterns and styling approach