Add frontend loading imporvements

This commit is contained in:
Urtzi Alfaro
2025-12-27 21:30:42 +01:00
parent 6e3a6590d6
commit 54662dde79
21 changed files with 799 additions and 363 deletions

View File

@@ -39,8 +39,19 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const initializeAuth = async () => {
setIsInitializing(true);
// Wait a bit for zustand persist to rehydrate
await new Promise(resolve => setTimeout(resolve, 100));
// Check if zustand has already rehydrated
if (!(useAuthStore.persist as any).hasHydrated?.()) {
// Wait for rehydration event with minimal timeout fallback
await Promise.race([
new Promise<void>(resolve => {
const unsubscribe = useAuthStore.persist.onFinishHydration(() => {
unsubscribe();
resolve();
});
}),
new Promise(resolve => setTimeout(resolve, 50))
]);
}
// Check if we have stored auth data
if (authStore.token && authStore.refreshToken) {

View File

@@ -35,12 +35,15 @@ interface SSEProviderProps {
export const SSEProvider: React.FC<SSEProviderProps> = ({ children }) => {
const [isConnected, setIsConnected] = useState(false);
const [lastEvent, setLastEvent] = useState<SSEEvent | null>(null);
const eventSourceRef = useRef<EventSource | null>(null);
const eventListenersRef = useRef<Map<string, Set<(data: any) => void>>>(new Map());
const reconnectTimeoutRef = useRef<NodeJS.Timeout>();
const reconnectAttempts = useRef(0);
// Global deduplication: Track processed event IDs to prevent duplicate callbacks
const processedEventIdsRef = useRef<Set<string>>(new Set());
const { isAuthenticated, token } = useAuthStore();
const currentTenant = useCurrentTenant();
@@ -130,6 +133,23 @@ export const SSEProvider: React.FC<SSEProviderProps> = ({ children }) => {
eventSource.addEventListener('alert', (event) => {
try {
const data = JSON.parse(event.data);
// GLOBAL DEDUPLICATION: Skip if this event was already processed
if (data.id && processedEventIdsRef.current.has(data.id)) {
console.log('⏭️ [SSE] Skipping duplicate alert:', data.id);
return;
}
// Mark event as processed
if (data.id) {
processedEventIdsRef.current.add(data.id);
// Limit cache size (keep last 1000 event IDs)
if (processedEventIdsRef.current.size > 1000) {
const firstId = Array.from(processedEventIdsRef.current)[0];
processedEventIdsRef.current.delete(firstId);
}
}
const sseEvent: SSEEvent = {
type: 'alert',
data,
@@ -208,6 +228,22 @@ export const SSEProvider: React.FC<SSEProviderProps> = ({ children }) => {
eventSource.addEventListener('notification', (event) => {
try {
const data = JSON.parse(event.data);
// GLOBAL DEDUPLICATION: Skip if this event was already processed
if (data.id && processedEventIdsRef.current.has(data.id)) {
console.log('⏭️ [SSE] Skipping duplicate notification:', data.id);
return;
}
// Mark event as processed
if (data.id) {
processedEventIdsRef.current.add(data.id);
if (processedEventIdsRef.current.size > 1000) {
const firstId = Array.from(processedEventIdsRef.current)[0];
processedEventIdsRef.current.delete(firstId);
}
}
const sseEvent: SSEEvent = {
type: 'notification',
data,