Le problème était que l'update du champ contract_pdf_s3_key utilisait le client Supabase normal (avec RLS) au lieu du client admin (service role). Cela empêchait potentiellement la mise à jour du contrat ou l'accès côté client. Changements: - Import de createClient depuis @supabase/supabase-js - Création d'un adminClient avec SUPABASE_SERVICE_ROLE_KEY - Utilisation de adminClient pour l'update au lieu de sb - Ajout de logs pour le debug
126 lines
4.9 KiB
Markdown
126 lines
4.9 KiB
Markdown
# Fix : Rafraîchissement des documents après upload manuel du contrat signé
|
|
|
|
## Problème identifié
|
|
|
|
Lorsqu'un contrat de travail était uploadé manuellement depuis la page staff (`staff/contrats/[id]`), il n'apparaissait pas immédiatement sur la page client (`contrats/[id]`).
|
|
|
|
### Cause racine
|
|
|
|
Le composant `DocumentsCard` utilisé par la page client effectuait des appels `fetch` directs dans des `useEffect` avec uniquement `contractId` comme dépendance. Ces appels n'étaient donc déclenchés qu'au montage du composant, et pas lors d'un upload manuel effectué depuis une autre page.
|
|
|
|
Côté staff, le système fonctionnait correctement car il utilisait React Query avec invalidation de cache.
|
|
|
|
## Solution implémentée
|
|
|
|
### 1. Ajout d'un mécanisme de refresh dans DocumentsCard
|
|
|
|
**Fichier** : `components/contrats/DocumentsCard.tsx`
|
|
|
|
- Ajout d'une prop `refreshTrigger?: number`
|
|
- Ajout de `refreshTrigger` comme dépendance dans tous les `useEffect` qui récupèrent les données
|
|
- Ajout de `setLoadingSignedPdf(true)` au début de `fetchSignedPdf` pour afficher un loader lors du rechargement
|
|
|
|
```typescript
|
|
interface DocumentsCardProps {
|
|
contractId: string;
|
|
contractNumber?: string;
|
|
contractData?: { ... };
|
|
showPayslips?: boolean;
|
|
refreshTrigger?: number; // ← Nouvelle prop
|
|
}
|
|
|
|
useEffect(() => {
|
|
const fetchSignedPdf = async () => {
|
|
setLoadingSignedPdf(true); // ← Ajouté
|
|
// ... code de récupération
|
|
};
|
|
fetchSignedPdf();
|
|
}, [contractId, refreshTrigger]); // ← refreshTrigger ajouté
|
|
```
|
|
|
|
### 2. Système d'événements personnalisés
|
|
|
|
**Fichier** : `components/staff/contracts/ManualSignedContractUpload.tsx`
|
|
|
|
Après un upload réussi, émission d'un événement personnalisé :
|
|
|
|
```typescript
|
|
// Émettre un événement personnalisé pour rafraîchir les documents côté client
|
|
if (typeof window !== 'undefined') {
|
|
window.dispatchEvent(new CustomEvent('refreshContractDocuments'));
|
|
}
|
|
```
|
|
|
|
### 3. Écoute de l'événement dans la page client
|
|
|
|
**Fichier** : `app/(app)/contrats/[id]/page.tsx`
|
|
|
|
- Ajout d'un state `documentsRefreshTrigger`
|
|
- Ajout d'un listener pour l'événement `refreshContractDocuments`
|
|
- Passage de `refreshTrigger` au composant `DocumentsCard`
|
|
|
|
```typescript
|
|
const [documentsRefreshTrigger, setDocumentsRefreshTrigger] = useState<number>(0);
|
|
|
|
useEffect(() => {
|
|
const handleRefreshDocuments = () => {
|
|
console.log('🔄 Rafraîchissement des documents demandé');
|
|
setDocumentsRefreshTrigger(prev => prev + 1);
|
|
};
|
|
|
|
window.addEventListener('refreshContractDocuments', handleRefreshDocuments);
|
|
|
|
return () => {
|
|
window.removeEventListener('refreshContractDocuments', handleRefreshDocuments);
|
|
};
|
|
}, []);
|
|
|
|
// Dans le JSX
|
|
<DocumentsCard
|
|
contractId={id}
|
|
contractNumber={data.numero}
|
|
contractData={{ ... }}
|
|
refreshTrigger={documentsRefreshTrigger}
|
|
/>
|
|
```
|
|
|
|
## Flux de données
|
|
|
|
1. **Upload manuel** : L'utilisateur staff upload un contrat signé via `ManualSignedContractUpload`
|
|
2. **Upload S3** : Le fichier est uploadé sur S3 et `contract_pdf_s3_key` est mis à jour dans la base de données
|
|
3. **Invalidation React Query** : La query `["signed-contract-pdf", contract.id]` est invalidée côté staff
|
|
4. **Événement custom** : Un événement `refreshContractDocuments` est émis globalement
|
|
5. **Réception côté client** : La page client écoute cet événement et incrémente `documentsRefreshTrigger`
|
|
6. **Rechargement** : `DocumentsCard` détecte le changement de `refreshTrigger` et re-déclenche ses `useEffect`
|
|
7. **Affichage** : Le contrat signé apparaît dans la liste des documents
|
|
|
|
## Avantages de cette approche
|
|
|
|
- **Compatibilité** : Fonctionne même si la page client n'est pas en React Query
|
|
- **Découplage** : Les composants ne sont pas fortement couplés
|
|
- **Extensible** : D'autres composants peuvent écouter le même événement si nécessaire
|
|
- **Performance** : Pas de polling inutile, rechargement uniquement quand nécessaire
|
|
|
|
## Tests à effectuer
|
|
|
|
- [ ] Upload manuel d'un contrat depuis la page staff
|
|
- [ ] Vérifier que le contrat apparaît sur la page client (après F5 ou event)
|
|
- [ ] Vérifier que l'upload fonctionne toujours côté staff (avec React Query)
|
|
- [ ] Vérifier les logs console pour confirmer le déclenchement de l'événement
|
|
|
|
## Commit
|
|
|
|
```
|
|
fix: Rafraîchir les documents côté client après upload manuel du contrat signé
|
|
|
|
- Ajout d'une prop refreshTrigger à DocumentsCard pour forcer le rechargement
|
|
- Ajout d'un listener d'événement custom 'refreshContractDocuments' dans la page client
|
|
- Émission de l'événement après l'upload réussi dans ManualSignedContractUpload
|
|
- Fix: Le contrat signé apparaît maintenant sur la page client après upload manuel depuis staff
|
|
```
|
|
|
|
## Notes
|
|
|
|
- Cette solution est temporaire en attendant une migration complète vers React Query dans `DocumentsCard`
|
|
- À terme, il serait préférable de centraliser toutes les requêtes de documents dans React Query
|
|
- L'événement `refreshContractDocuments` pourrait être typé avec TypeScript pour plus de sécurité
|