Indice

Chapitre 3 : Autres fonctionnalités

Géolocalisation

Obtenir la position

snippet.javascript
import { useState } from 'react';
import { Button, Block } from '@cap-rel/smartcommon';
 
function LocationButton({ onLocation }) {
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
 
    const getLocation = () => {
        if (!navigator.geolocation) {
            setError('Géolocalisation non supportée');
            return;
        }
 
        setLoading(true);
        setError(null);
 
        navigator.geolocation.getCurrentPosition(
            (position) => {
                setLoading(false);
                onLocation({
                    lat: position.coords.latitude,
                    lng: position.coords.longitude,
                    accuracy: position.coords.accuracy
                });
            },
            (err) => {
                setLoading(false);
                setError(err.message);
            },
            {
                enableHighAccuracy: true,
                timeout: 10000,
                maximumAge: 0
            }
        );
    };
 
    return (
        <Block>
            <Button onClick={getLocation} loading={loading}>
                Obtenir ma position
            </Button>
            {error && <p className="text-red-500 mt-2">{error}</p>}
        </Block>
    );
}

Composant Gps de SmartCommon

snippet.javascript
import { Gps } from '@cap-rel/smartcommon';
 
<Gps
    name="location"
    label="Position de l'intervention"
    onChange={(coords) => console.log(coords)}
/>

Upload de fichiers

PhotosUploader

snippet.javascript
import { PhotosUploader } from '@cap-rel/smartcommon';
 
<PhotosUploader
    name="photos"
    label="Photos"
    maxFiles={5}
    maxSize={5 * 1024 * 1024}  // 5 Mo
    onChange={(files) => console.log(files)}
/>

FilesUploader

snippet.javascript
import { FilesUploader } from '@cap-rel/smartcommon';
 
<FilesUploader
    name="documents"
    label="Documents"
    accept=".pdf,.doc,.docx"
    multiple
    maxFiles={10}
/>

Redimensionner une image

snippet.javascript
import { useFile } from '@cap-rel/smartcommon';
 
function ImageUploader() {
    const { resizeImage } = useFile();
 
    const handleFile = async (e) => {
        const file = e.target.files[0];
 
        const base64 = await resizeImage(file, {
            maxWidth: 1200,
            maxHeight: 1200,
            quality: 80
        });
 
        // Envoyer au serveur
        await api.private.post('files', {
            json: {
                filename: file.name,
                content: base64
            }
        });
    };
 
    return <input type="file" accept="image/*" onChange={handleFile} />;
}

Thème sombre

Configuration globale

snippet.javascript
// appConfig.js
export const config = {
    globalState: {
        reducers: {
            settings: {
                theme: 'light'  // 'light' ou 'dark'
            }
        }
    }
};

Appliquer le thème

snippet.javascript
import { useEffect } from 'react';
import { useGlobalStates } from '@cap-rel/smartcommon';
 
function ThemeProvider({ children }) {
    const [settings] = useGlobalStates('settings');
 
    useEffect(() => {
        document.documentElement.classList.toggle(
            'dark',
            settings.theme === 'dark'
        );
    }, [settings.theme]);
 
    return children;
}

Toggle de thème

snippet.javascript
import { useGlobalStates } from '@cap-rel/smartcommon';
import { Boolean } from '@cap-rel/smartcommon';
 
function ThemeToggle() {
    const [settings, setSettings] = useGlobalStates('settings');
 
    const toggleTheme = () => {
        setSettings({
            ...settings,
            theme: settings.theme === 'light' ? 'dark' : 'light'
        });
    };
 
    return (
        <Boolean
            value={settings.theme === 'dark'}
            onChange={toggleTheme}
            label="Mode sombre"
        />
    );
}

Signature manuscrite

snippet.javascript
import { SignaturePad } from '@cap-rel/smartcommon';
 
<SignaturePad
    name="signature"
    label="Signature du client"
    width={400}
    height={200}
/>

Scan de code-barres

Utiliser une bibliothèque comme @zxing/browser :

snippet.bash
npm install @zxing/browser @zxing/library
snippet.javascript
import { useState, useRef, useEffect } from 'react';
import { BrowserMultiFormatReader } from '@zxing/browser';
 
function BarcodeScanner({ onScan }) {
    const videoRef = useRef(null);
    const [scanning, setScanning] = useState(false);
 
    useEffect(() => {
        let reader;
 
        if (scanning) {
            reader = new BrowserMultiFormatReader();
            reader.decodeFromVideoDevice(
                undefined,
                videoRef.current,
                (result, error) => {
                    if (result) {
                        onScan(result.getText());
                        setScanning(false);
                    }
                }
            );
        }
 
        return () => {
            if (reader) {
                reader.reset();
            }
        };
    }, [scanning]);
 
    return (
        <div>
            {scanning ? (
                <video ref={videoRef} className="w-full" />
            ) : (
                <button onClick={() => setScanning(true)}>
                    Scanner un code
                </button>
            )}
        </div>
    );
}

Notifications locales

snippet.javascript
function requestNotificationPermission() {
    if ('Notification' in window) {
        Notification.requestPermission().then(permission => {
            console.log('Permission:', permission);
        });
    }
}
 
function showNotification(title, body) {
    if (Notification.permission === 'granted') {
        new Notification(title, { body });
    }
}

Points clés à retenir

  1. Géolocalisation avec navigator.geolocation ou composant Gps
  2. Upload avec PhotosUploader, FilesUploader, useFile
  3. Thème sombre via useGlobalStates et classes CSS
  4. Signature avec SignaturePad
  5. Intégrer des bibliothèques tierces selon les besoins

← Chapitre précédent | Retour au module | Module suivant : Bonnes pratiques →