Chapitre 3 : Autres fonctionnalités
Géolocalisation
Obtenir la position
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
import { Gps } from '@cap-rel/smartcommon';
<Gps
name="location"
label="Position de l'intervention"
onChange={(coords) => console.log(coords)}
/>
Upload de fichiers
PhotosUploader
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
import { FilesUploader } from '@cap-rel/smartcommon';
<FilesUploader
name="documents"
label="Documents"
accept=".pdf,.doc,.docx"
multiple
maxFiles={10}
/>
Redimensionner une image
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
// appConfig.js
export const config = {
globalState: {
reducers: {
settings: {
theme: 'light' // 'light' ou 'dark'
}
}
}
};
Appliquer le thème
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
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
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 :
npm install @zxing/browser @zxing/library
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
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
- Géolocalisation avec navigator.geolocation ou composant Gps
- Upload avec PhotosUploader, FilesUploader, useFile
- Thème sombre via useGlobalStates et classes CSS
- Signature avec SignaturePad
- Intégrer des bibliothèques tierces selon les besoins
← Chapitre précédent | Retour au module | Module suivant : Bonnes pratiques ->