---
title: "Chapitre 3 : Autres fonctionnalités"
weight: 730
---

# Chapitre 3 : Autres fonctionnalités

## Géolocalisation

### Obtenir la position

```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

```javascript
import { Gps } from '@cap-rel/smartcommon';

<Gps
    name="location"
    label="Position de l'intervention"
    onChange={(coords) => console.log(coords)}
/>
```

## Upload de fichiers

### PhotosUploader

```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

```javascript
import { FilesUploader } from '@cap-rel/smartcommon';

<FilesUploader
    name="documents"
    label="Documents"
    accept=".pdf,.doc,.docx"
    multiple
    maxFiles={10}
/>
```

### Redimensionner une image

```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

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

### Appliquer le thème

```javascript
import { useEffect } from 'react';
import { useGlobalStates } from '@cap-rel/smartcommon';

function ThemeProvider({ children }) {
    const gst = useGlobalStates();

    useEffect(() => {
        document.documentElement.classList.toggle(
            'dark',
            gst.get('settings')?.theme === 'dark'
        );
    }, [gst.get('settings')?.theme]);

    return children;
}
```

### Toggle de thème

```javascript
import { useGlobalStates } from '@cap-rel/smartcommon';
import { Boolean } from '@cap-rel/smartcommon';

function ThemeToggle() {
    const gst = useGlobalStates();
    const settings = gst.get('settings');

    const toggleTheme = () => {
        gst.local.set('settings', {
            ...settings,
            theme: settings.theme === 'light' ? 'dark' : 'light'
        });
    };

    return (
        <Boolean
            value={settings?.theme === 'dark'}
            onChange={toggleTheme}
            label="Mode sombre"
        />
    );
}
```

## Signature manuscrite

```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` :

```bash
npm install @zxing/browser @zxing/library
```

```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

```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](/training/module10-fonctionnalites-avancees/i18n) | [Retour au module](/training/module10-fonctionnalites-avancees) | [Module suivant : Bonnes pratiques ->](/training/module11-bonnes-pratiques)
