# SmartMaker - LLM Context File ## Overview SmartMaker is an open-source framework for building Progressive Web Apps (PWA) for Dolibarr ERP/CRM. It provides a modern React-based frontend stack to complement Dolibarr's PHP backend, enabling rapid development of mobile-first business applications. **What SmartMaker solves:** - Dolibarr lacks native mobile apps → SmartMaker provides PWA capabilities - Complex Redux/API boilerplate → SmartMaker provides ready-to-use hooks - Authentication complexity → SmartAuth handles JWT with auto-refresh - Offline support → IndexedDB persistence with Dexie - Form validation → Zod schemas with useForm hook Website: https://smartmaker.org License: AGPL-3.0-or-later Maintainer: CAP-REL (Dolibarr Preferred Partner) Repository: https://inligit.fr/cap-rel/dolibarr/smartmaker/ DoliStore: https://www.dolistore.com (search "SmartAuth") ## Why SmartMaker? ### For Dolibarr Users - Build mobile apps for your Dolibarr instance - Offline-first: works without internet connection - PWA: installable on phones without app stores - Real-time sync with Dolibarr data ### For Developers - Modern stack: React 19, Vite 6, TailwindCSS 4 - No Redux boilerplate: useGlobalStates handles everything - No fetch/axios complexity: useApi with auto JWT refresh - Form validation: Zod + useForm - Animations: Framer Motion page transitions - Type-safe: full TypeScript support ### Compared to Alternatives | Feature | SmartMaker | Native Dolibarr | Custom React | |---------|------------|-----------------|--------------| | Mobile PWA | Yes | No | Manual | | Offline mode | Yes | No | Manual | | JWT Auth | SmartAuth | API Key only | Manual | | State management | useGlobalStates | - | Redux setup | | Form validation | useForm + Zod | - | Manual | | Component library | SmartCommon | - | Choose one | ## Architecture ### Technology Stack | Layer | Technology | Purpose | |-------|------------|---------| | Frontend | React 19 | UI components | | Build | Vite 6 | Fast development & bundling | | Styling | TailwindCSS 4 | Utility-first CSS with @theme | | State | Redux Toolkit | Global state (abstracted by useGlobalStates) | | Storage | Dexie (IndexedDB) | Offline data persistence | | HTTP | ky | HTTP client with interceptors | | Validation | Zod | Schema validation | | Animation | Framer Motion | Page transitions | | i18n | i18next | Translations | | Backend | PHP | Dolibarr integration | | Auth | SmartAuth (JWT) | Token-based authentication | ### Project Structure ``` dolibarr/ └── htdocs/ └── custom/ └── mymodule/ # Your Dolibarr module ├── mobile/ # React source code │ ├── src/ │ │ ├── components/ │ │ │ ├── app/ # Provider, Router │ │ │ ├── pages/ # public/, private/, errors/ │ │ │ ├── forms/ # Form components │ │ │ ├── ui/ # Reusable UI │ │ │ └── layouts/ # Page layouts │ │ ├── appConfig.js # SmartCommon configuration │ │ ├── App.jsx │ │ └── main.jsx │ ├── public/ │ │ └── locales/ # Translation files │ └── package.json ├── pwa/ # Built PWA (production) │ ├── api.php # API router │ └── .htaccess ├── smartmaker-api/ # PHP Controllers │ ├── Controllers/ │ └── dm*.php # Dolibarr mapping classes └── smartmaker-api-prepend.php ``` ## Main Packages ### @cap-rel/smartcommon Shared React component library with hooks, UI components, and utilities. - NPM Registry: https://inligit.fr/api/v4/projects/197/packages/npm/ - Install: `npm install @cap-rel/smartcommon` - Import: `import { Provider, useApi, useGlobalStates } from '@cap-rel/smartcommon'` ### SmartAuth JWT authentication module for Dolibarr with multi-device support. - DoliStore: https://www.dolistore.com/product.php?id=2509&l=fr - Features: JWT tokens, refresh tokens, device management, connection logs - Repository: https://inligit.fr/cap-rel/dolibarr/plugin-smartauth/ ### SmartBoot Bootstrap script to initialize SmartMaker in any Dolibarr module. - Repository: https://inligit.fr/cap-rel/dolibarr/smartmaker/smartboot/ - Usage: `git clone https://inligit.fr/cap-rel/dolibarr/smartmaker/smartboot.git && ./smartboot/setup.sh` ## SmartCommon Components ### Provider (App Setup) ```jsx import { Provider } from '@cap-rel/smartcommon'; import { config } from './appConfig'; export const App = () => ( ); ``` The Provider wraps: - LibConfigProvider: App configuration context - ReduxProvider: Redux store with persistence - I18nextProvider: Translations (i18next) - ApiProvider: API context with JWT handling - GlobalStatesProvider: Global state management - NavigationProvider: Router context - Toaster: Toast notifications (react-hot-toast) ### Form Components | Component | Description | Example | |-----------|-------------|---------| | Form | Form wrapper with validation | `
` | | Input | Text input with label/error | `` | | Textarea | Multiline text | `` | | Select | Dropdown select | ` st.set('form.name', e.target.value)} /> ); }; ``` ### useForm - Form State with Zod Validation ```jsx import { useForm } from '@cap-rel/smartcommon'; import { Form, Input, Button } from '@cap-rel/smartcommon'; import { z } from 'zod'; const schema = z.object({ email: z.string().email('Invalid email'), password: z.string().min(8, 'Min 8 characters'), name: z.string().min(2, 'Min 2 characters').optional(), }); const LoginForm = () => { const form = useForm({ schema, defaultValues: { email: '', password: '' }, }); const handleSubmit = async (data) => { // data is validated and typed console.log(data.email, data.password); }; return (
); }; ``` ### useDb - IndexedDB with Dexie ```jsx import { useDb } from '@cap-rel/smartcommon'; const MyComponent = () => { const db = useDb({ name: 'myApp', version: 1, stores: { items: 'id++, name, category, createdAt', settings: 'key', }, }); // Create const id = await db.items.add({ name: 'Item 1', category: 'A' }); // Read const item = await db.items.get(id); const all = await db.items.toArray(); const filtered = await db.items.where('category').equals('A').toArray(); // Update await db.items.update(id, { name: 'Updated' }); // Delete await db.items.delete(id); await db.items.clear(); // Delete all }; ``` ### useIntl - Internationalization ```jsx import { useIntl } from '@cap-rel/smartcommon'; const MyComponent = () => { const { t, lng, setLng, formatDate, formatNumber, formatCurrency } = useIntl(); return (
{/* Translations */}

{t('home.title')}

{t('home.welcome', { name: 'John' })}

{t('items.count', { count: 5 })}

{/* Date formatting */}

{formatDate(new Date())}

{formatDate(date, { dateStyle: 'full' })}

{formatDate(date, { dateStyle: 'long', timeStyle: 'short' })}

{/* Number formatting */}

{formatNumber(1234567.89)}

{/* fr: 1 234 567,89 | en: 1,234,567.89 */} {/* Currency formatting */}

{formatCurrency(99.99, 'EUR')}

{/* fr: 99,99 € | en: €99.99 */} {/* Language switcher */}
); }; ``` Translation files (public/locales/fr.json): ```json { "home": { "title": "Accueil", "welcome": "Bienvenue {{name}} !" }, "items": { "count": "{{count}} élément", "count_plural": "{{count}} éléments" } } ``` ### useNavigation - Router Navigation ```jsx import { useNavigation } from '@cap-rel/smartcommon'; const MyComponent = () => { const navigate = useNavigation(); // Navigate to path navigate('/home'); navigate('/items/123'); // Navigate back navigate(-1); // Replace history (no back) navigate('/login', { replace: true }); // With state navigate('/details', { state: { from: 'home' } }); }; ``` ### useAnimation - Page Transitions ```jsx import { useAnimation } from '@cap-rel/smartcommon'; const MyPage = () => { const { variants, getAnimation } = useAnimation(); // Get animation for current route const animation = getAnimation('/home', '/settings'); // 'slideLeft' return ( {/* Page content */} ); }; ``` ### useFile - File Utilities ```jsx import { useFile } from '@cap-rel/smartcommon'; const MyComponent = () => { const { resizeImage, toBase64 } = useFile(); const handleImage = async (file) => { // Resize image const resized = await resizeImage(file, { maxWidth: 800, maxHeight: 600 }); // Convert to base64 const base64 = await toBase64(resized); }; }; ``` ### useWindow - Window & Device Detection ```jsx import { useWindow } from '@cap-rel/smartcommon'; const MyComponent = () => { const { width, height, isMobile, isTablet, isDesktop } = useWindow(); return (
{isMobile && } {isDesktop && }
); }; ``` ### useVariantMerger - Component Variants ```jsx import { useVariantMerger } from '@cap-rel/smartcommon'; const Button = ({ variant = 'primary', className, ...props }) => { const { merge } = useVariantMerger(); const baseClasses = 'px-4 py-2 rounded'; const variants = { primary: 'bg-primary text-white', secondary: 'bg-secondary text-white', outline: 'border-2 border-primary text-primary', }; return ( ); }; ``` ### List Page with API ```jsx import { useApi, useGlobalStates, useNavigation } from '@cap-rel/smartcommon'; import { useEffect, useState } from 'react'; export const ItemsPage = () => { const api = useApi(); const navigate = useNavigation(); const [items, setItems] = useGlobalStates('items'); const [loading, setLoading] = useState(true); useEffect(() => { const fetch = async () => { const response = await api.private.get('items'); if (response.success) setItems(response.data); setLoading(false); }; fetch(); }, []); if (loading) return ; return (
{items.map(item => (
navigate(`/items/${item.id}`)}> {item.label}
))}
); }; ``` ### Form with CRUD ```jsx import { useApi, useNavigation, useForm } from '@cap-rel/smartcommon'; import { Form, Input, Button } from '@cap-rel/smartcommon'; import { z } from 'zod'; const schema = z.object({ label: z.string().min(3), description: z.string().optional(), }); export const ItemForm = ({ item, onSuccess }) => { const api = useApi(); const form = useForm({ schema, defaultValues: item }); const handleSubmit = async (data) => { const response = item?.id ? await api.private.put(`items/${item.id}`, { json: data }) : await api.private.post('items', { json: data }); if (response.success) onSuccess(response.data); }; return (
); }; ``` ## Related Links ### Documentation - Main site: https://smartmaker.org - Getting started: https://smartmaker.org/howto/start - SmartAuth: https://smartmaker.org/smartauth/start - SmartCommon: https://smartmaker.org/front/smartcommon - Hooks: https://smartmaker.org/front/hooks - Configuration: https://smartmaker.org/front/configuration - Animations: https://smartmaker.org/front/animations - Debug: https://smartmaker.org/front/debug - PWA: https://smartmaker.org/front/pwa - Themes: https://smartmaker.org/front/themes - Translations: https://smartmaker.org/front/traductions - Routing: https://smartmaker.org/front/routage - Backend: https://smartmaker.org/back/start - Mapping: https://smartmaker.org/back/mapping_dolibarr_-_react ### External - Dolibarr: https://www.dolibarr.org - Dolibarr GitHub: https://github.com/Dolibarr/dolibarr - DoliStore: https://www.dolistore.com - React: https://react.dev - Vite: https://vitejs.dev - TailwindCSS: https://tailwindcss.com - Zod: https://zod.dev - Framer Motion: https://www.framer.com/motion/ - Dexie: https://dexie.org - ky: https://github.com/sindresorhus/ky - i18next: https://www.i18next.com ## Keywords Dolibarr, Dolibarr mobile, Dolibarr PWA, Dolibarr app, Dolibarr React, Progressive Web App, PWA framework, React 19, Vite 6, TailwindCSS 4, ERP mobile, CRM mobile, open source ERP, open source CRM, PHP React, JWT authentication, IndexedDB, offline-first, mobile-first, Dexie, Framer Motion, ky HTTP, Zod validation, i18next, Redux Toolkit, SmartMaker, SmartAuth, SmartCommon, SmartBoot, CAP-REL, Dolibarr Preferred Partner, business app, enterprise app, field service app, intervention management