fix: Resolve black pages issue - Add missing auth slice and update checker
Fixed critical issues causing tracking pages to display black: 1. PWA service worker caching old JavaScript chunks 2. Missing auth Redux slice causing undefined errors ## Service Worker Update Checker - Added /public/check-updates.js script - Checks for SW updates every 60 seconds - Auto-reloads page when new SW is activated - Forces update check on page load - Prevents future cache staleness issues ## Auth Redux Slice - Created store/slices/authSlice.ts with User interface - Added auth reducer to Redux store configuration - Included auth in persist whitelist - Provides selectors: selectUser, selectFamilyId, etc. - Fixes "Cannot read properties of undefined (reading 'user')" error ## Root Cause Tracking pages reference state.auth.user.familyId but auth slice didn't exist in Redux store, causing TypeError on all tracking pages. Build: ✅ PASSED Files: 3 new, 2 modified 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@ export default function RootLayout({
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="theme-color" content="#FFB6C1" />
|
||||
<link rel="apple-touch-icon" href="/icon-192x192.png" />
|
||||
<script src="/check-updates.js" defer></script>
|
||||
</head>
|
||||
<body className={inter.className}>
|
||||
<AxeProvider>
|
||||
|
||||
26
maternal-web/public/check-updates.js
Normal file
26
maternal-web/public/check-updates.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Service Worker Update Checker
|
||||
* Detects when a new build is available and prompts user to reload
|
||||
*/
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
// Check for updates every 60 seconds
|
||||
setInterval(() => {
|
||||
navigator.serviceWorker.getRegistration().then(registration => {
|
||||
if (registration) {
|
||||
registration.update();
|
||||
}
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
// Listen for service worker updates
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
console.log('[SW] New service worker activated, reloading page...');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
// Force update check on load
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.update();
|
||||
});
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
61
maternal-web/store/slices/authSlice.ts
Normal file
61
maternal-web/store/slices/authSlice.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import type { RootState } from '../store';
|
||||
|
||||
export interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
familyId: string;
|
||||
}
|
||||
|
||||
export interface AuthState {
|
||||
user: User | null;
|
||||
token: string | null;
|
||||
isAuthenticated: boolean;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const initialState: AuthState = {
|
||||
user: null,
|
||||
token: null,
|
||||
isAuthenticated: false,
|
||||
loading: false,
|
||||
};
|
||||
|
||||
const authSlice = createSlice({
|
||||
name: 'auth',
|
||||
initialState,
|
||||
reducers: {
|
||||
setUser: (state, action: PayloadAction<User>) => {
|
||||
state.user = action.payload;
|
||||
state.isAuthenticated = true;
|
||||
},
|
||||
setToken: (state, action: PayloadAction<string>) => {
|
||||
state.token = action.payload;
|
||||
},
|
||||
setAuth: (state, action: PayloadAction<{ user: User; token: string }>) => {
|
||||
state.user = action.payload.user;
|
||||
state.token = action.payload.token;
|
||||
state.isAuthenticated = true;
|
||||
},
|
||||
logout: (state) => {
|
||||
state.user = null;
|
||||
state.token = null;
|
||||
state.isAuthenticated = false;
|
||||
},
|
||||
setLoading: (state, action: PayloadAction<boolean>) => {
|
||||
state.loading = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setUser, setToken, setAuth, logout, setLoading } = authSlice.actions;
|
||||
|
||||
// Selectors
|
||||
export const selectUser = (state: RootState) => state.auth?.user;
|
||||
export const selectToken = (state: RootState) => state.auth?.token;
|
||||
export const selectIsAuthenticated = (state: RootState) => state.auth?.isAuthenticated ?? false;
|
||||
export const selectAuthLoading = (state: RootState) => state.auth?.loading ?? false;
|
||||
export const selectFamilyId = (state: RootState) => state.auth?.user?.familyId;
|
||||
|
||||
export default authSlice.reducer;
|
||||
@@ -4,6 +4,7 @@ import storage from 'redux-persist/lib/storage'; // defaults to localStorage for
|
||||
import { combineReducers } from '@reduxjs/toolkit';
|
||||
|
||||
// Slices
|
||||
import authReducer from './slices/authSlice';
|
||||
import offlineReducer from './slices/offlineSlice';
|
||||
import activitiesReducer from './slices/activitiesSlice';
|
||||
import childrenReducer from './slices/childrenSlice';
|
||||
@@ -19,10 +20,11 @@ const persistConfig = {
|
||||
version: 1,
|
||||
storage,
|
||||
// Only persist these slices (exclude network status as it should be fresh on reload)
|
||||
whitelist: ['offline', 'activities', 'children'],
|
||||
whitelist: ['auth', 'offline', 'activities', 'children'],
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer,
|
||||
offline: offlineReducer,
|
||||
activities: activitiesReducer,
|
||||
children: childrenReducer,
|
||||
|
||||
Reference in New Issue
Block a user