veza/apps/web/src/utils/toast.ts
senke f0ba7de543 state-ownership: delete unused optimisticStoreUpdates.ts file
- Deleted apps/web/src/utils/optimisticStoreUpdates.ts (unused file)
- File was unused - no imports found in codebase
- Mutations already use React Query's onMutate pattern
- No TypeScript errors after deletion
- Actions 4.4.1.2 and 4.4.1.3 complete
2026-01-15 19:26:53 +01:00

124 lines
4.9 KiB
TypeScript

/**
* toast - Wrapper lazy pour react-hot-toast
*
* CRITICAL FIX: Charge react-hot-toast de manière lazy pour éviter
* les collisions de noms de variables (ie) lors de la minification.
*
* Le problème: react-hot-toast utilise une variable 'ie' qui entre
* en conflit avec d'autres variables minifiées dans le même chunk.
* Solution: Chargement dynamique pour isoler le module.
*
* Le module est préchargé dans main.tsx AVANT le rendu de l'app,
* donc il sera toujours disponible quand ce wrapper est utilisé.
*
* Usage:
* import toast from '@/utils/toast';
* toast.success('Message');
* toast.error('Error');
*/
// Import dynamique - cela force Vite à créer un chunk séparé
// Le module est préchargé dans main.tsx, donc il sera déjà chargé
// quand ce fichier est évalué
const toastModulePromise = import('react-hot-toast');
// Cache pour le module une fois chargé
let toastModule: typeof import('react-hot-toast') | null = null;
let isResolved = false;
// Charger le module et le mettre en cache immédiatement
toastModulePromise.then((mod) => {
// #region agent log
fetch('http://127.0.0.1:7242/ingest/09c5ea5e-2380-4cc3-92aa-d26f3b3d26f6',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'utils/toast.ts:toastModulePromise.then',message:'Toast module loaded in wrapper',data:{hasDefault:!!mod.default,moduleKeys:Object.keys(mod)},timestamp:Date.now(),sessionId:'debug-session',runId:'runtime',hypothesisId:'D'})}).catch(()=>{});
// #endregion
toastModule = mod;
isResolved = true;
}).catch((err) => {
// #region agent log
fetch('http://127.0.0.1:7242/ingest/09c5ea5e-2380-4cc3-92aa-d26f3b3d26f6',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'utils/toast.ts:toastModulePromise.catch',message:'Toast module load error in wrapper',data:{error:err.message,stack:err.stack},timestamp:Date.now(),sessionId:'debug-session',runId:'runtime',hypothesisId:'D'})}).catch(()=>{});
// #endregion
isResolved = true;
// Ignorer les erreurs de chargement
});
/**
* Récupère le module toast de manière synchrone
* Le module devrait être déjà chargé grâce au préchargement dans main.tsx
*/
function getToastModuleSync() {
// #region agent log
fetch('http://127.0.0.1:7242/ingest/09c5ea5e-2380-4cc3-92aa-d26f3b3d26f6',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'utils/toast.ts:getToastModuleSync',message:'Getting toast module',data:{hasModule:!!toastModule,isResolved},timestamp:Date.now(),sessionId:'debug-session',runId:'runtime',hypothesisId:'D'})}).catch(()=>{});
// #endregion
// Attendre que le module soit chargé (bloquant mais très rapide)
// En pratique, le module sera déjà chargé car il est préchargé dans main.tsx
if (!toastModule && isResolved) {
// Le module a échoué à charger, retourner un stub
console.error('Toast module failed to load');
return {
success: () => {},
error: () => {},
loading: () => {},
custom: () => {},
dismiss: () => {},
remove: () => {},
promise: () => Promise.resolve(),
} as any;
}
if (toastModule) {
return toastModule.default;
}
// Si le module n'est pas encore chargé, retourner un stub temporaire
// qui sera remplacé une fois le module chargé
return {
success: (...args: any[]) => {
toastModulePromise.then((mod) => mod.default.success(...args));
},
error: (...args: any[]) => {
toastModulePromise.then((mod) => mod.default.error(...args));
},
loading: (...args: any[]) => {
toastModulePromise.then((mod) => mod.default.loading(...args));
},
custom: (...args: any[]) => {
toastModulePromise.then((mod) => mod.default.custom(...args));
},
dismiss: (...args: any[]) => {
toastModulePromise.then((mod) => mod.default.dismiss(...args));
},
remove: (...args: any[]) => {
toastModulePromise.then((mod) => mod.default.remove(...args));
},
promise: (...args: any[]) => {
return toastModulePromise.then((mod) => mod.default.promise(...args));
},
} as any;
}
// Créer un proxy qui délègue toutes les méthodes à react-hot-toast
const toast = new Proxy({} as typeof import('react-hot-toast').default, {
get(_target, prop) {
const toastFn = getToastModuleSync() as any;
if (prop in toastFn) {
const method = toastFn[prop];
if (typeof method === 'function') {
return method.bind(toastFn);
}
return method;
}
return undefined;
},
apply(_target, _thisArg, args) {
const toastFn = getToastModuleSync();
if (typeof toastFn === 'function') {
return toastFn(...args);
}
// Si ce n'est pas une fonction, essayer d'appeler via le module
return toastModulePromise.then((mod) => mod.default(...args));
},
}) as typeof import('react-hot-toast').default;
export default toast;