Chapitre 1 : Structure du projet
Vue d'ensemble
Un projet SmartMaker se compose de deux parties :
- mobile/ : Code source React (développement)
- pwa/ : Application compilée + API PHP (production)
Arborescence complète
monmodule/ # Module Dolibarr
├── mobile/ # CODE SOURCE REACT
│ ├── src/
│ │ ├── App.jsx # Composant racine
│ │ ├── main.jsx # Point d'entrée
│ │ ├── appConfig.js # Configuration
│ │ ├── components/
│ │ │ ├── app/
│ │ │ │ └── Router/ # Configuration routes
│ │ │ │ ├── index.jsx
│ │ │ │ └── Guards/ # Protection routes
│ │ │ └── pages/
│ │ │ ├── public/ # Pages sans auth
│ │ │ │ ├── LoginPage/
│ │ │ │ └── WelcomePage/
│ │ │ ├── private/ # Pages avec auth
│ │ │ │ ├── HomePage/
│ │ │ │ └── ItemPage/
│ │ │ └── errors/
│ │ │ └── Error404Page/
│ │ ├── redux/ # Store Redux (optionnel)
│ │ │ └── reducers/
│ │ ├── i18n/ # Configuration i18next
│ │ ├── utils/ # Helpers, constantes
│ │ └── locales/ # Fichiers de traductions
│ ├── public/
│ │ ├── images/ # Icônes PWA
│ │ └── locales/ # Traductions
│ ├── index.html # Template HTML
│ ├── package.json # Dépendances npm
│ ├── vite.config.js # Configuration Vite
│ └── .env # Variables d'environnement
│
├── pwa/ # APPLICATION COMPILÉE + API
│ ├── api.php # Point d'entrée API
│ └── dist/ # Fichiers React compilés
│
├── smartmaker-api/ # BACKEND PHP
│ ├── Controllers/ # Logique métier
│ └── Mappers/ # Conversion Dolibarr -> DTO
│
└── smartmaker-api-prepend.php # Bootstrap PHP
Détail des fichiers clés
main.jsx - Point d'entrée
// src/main.jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';
import './index.css';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>
);
C'est le fichier appelé par index.html. Il monte l'application React dans le DOM.
App.jsx - Composant racine
// src/App.jsx
import { Provider } from '@cap-rel/smartcommon';
import { Router } from './components/app/Router';
import { config } from './appConfig';
export const App = () => (
<Provider config={config}>
<Router />
</Provider>
);
Le Provider de SmartCommon englobe toute l'application et fournit :
- Configuration globale
- État Redux
- Contexte API
- i18next
appConfig.js - Configuration
// src/appConfig.js
export const config = {
debug: import.meta.env.DEV,
api: {
prefixUrl: import.meta.env.VITE_API_URL,
timeout: 30000,
paths: {
login: "login",
logout: "logout",
refresh: "refresh"
}
},
storage: {
local: ["session", "settings"]
},
globalState: {
reducers: {
session: null,
settings: { lng: "fr" },
items: []
}
},
pages: {
"/": { "/settings": "slideLeft", "*": "fade" },
"*": "fade"
}
};
Détaillé dans le chapitre suivant.
index.html - Template
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mon Application</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Vite injecte automatiquement les scripts compilés en production.
Organisation des composants
Structure recommandée pour une page
components/pages/private/ItemPage/
├── index.jsx # Composant principal
├── ItemPage.module.css # Styles (optionnel)
└── components/ # Sous-composants locaux (optionnel)
├── ItemHeader.jsx
└── ItemActions.jsx
Exemple de page
// components/pages/private/ItemPage/index.jsx
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { Page, Block, Spinner } from '@cap-rel/smartcommon';
import { useApi, useStates } from '@cap-rel/smartcommon';
export const ItemPage = () => {
const { id } = useParams();
const api = useApi();
const st = useStates({
initialStates: {
item: null,
loading: true,
error: null
}
});
useEffect(() => {
const fetchItem = async () => {
try {
const data = await api.private.get(`items/${id}`).json();
st.set('item', data);
} catch (err) {
st.set('error', err.message);
} finally {
st.set('loading', false);
}
};
fetchItem();
}, [id]);
if (st.get('loading')) {
return <Page><Spinner /></Page>;
}
if (st.get('error')) {
return <Page><Block>Erreur : {st.get('error')}</Block></Page>;
}
const item = st.get('item');
return (
<Page title={item.label}>
<Block>
<p>{item.description}</p>
</Block>
</Page>
);
};
Le Router
Configuration des routes
// components/app/Router/index.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { PublicRoutes, PrivateRoutes } from './Guards';
// Pages
import { LoginPage } from '../../pages/public/LoginPage';
import { HomePage } from '../../pages/private/HomePage';
import { ItemPage } from '../../pages/private/ItemPage';
import { Error404Page } from '../../pages/errors/Error404Page';
export const Router = () => {
return (
<BrowserRouter>
<Routes>
{/* Routes publiques */}
<Route element={<PublicRoutes />}>
<Route path="/login" element={<LoginPage />} />
</Route>
{/* Routes protégées */}
<Route element={<PrivateRoutes />}>
<Route path="/" element={<HomePage />} />
<Route path="/items/:id" element={<ItemPage />} />
</Route>
{/* Fallback */}
<Route path="*" element={<Error404Page />} />
</Routes>
</BrowserRouter>
);
};
Guards d'authentification
// components/app/Router/Guards/index.jsx
import { Outlet, Navigate } from 'react-router-dom';
import { useGlobalStates } from '@cap-rel/smartcommon';
export const PrivateRoutes = () => {
const gst = useGlobalStates();
return gst.get('session') ? <Outlet /> : <Navigate to="/login" />;
};
export const PublicRoutes = () => {
const gst = useGlobalStates();
return gst.get('session') ? <Navigate to="/" /> : <Outlet />;
};
Variables d'environnement
# .env
VITE_API_URL=https://mondomaine.com/modules/monmodule/pwa/api.php
Accès dans le code :
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
Important : Les variables doivent commencer par VITE_ pour être exposées au client.
Dossier pwa/ - Production
Après compilation (npm run build), les fichiers sont générés dans pwa/dist/ :
pwa/
├── api.php # Point d'entrée API (à créer)
└── dist/
├── index.html # HTML avec assets injectés
├── assets/
│ ├── index-abc123.js # Bundle JS
│ └── index-def456.css # Bundle CSS
└── images/
Points clés à retenir
- mobile/ = code source pour développement
- pwa/ = code compilé pour production
- App.jsx englobe tout avec le Provider SmartCommon
- appConfig.js centralise la configuration
- Router gère les routes avec guards d'authentification
- Variables d'environnement préfixées par VITE_