Skip to content

Commit

Permalink
Update Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasTischer committed Oct 19, 2024
1 parent c9158e8 commit 89af175
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 52 deletions.
9 changes: 4 additions & 5 deletions frontend/app/(dashboard)/_components/user-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/new-york/ui/dropdown-menu';
import { useRetrieveUserQuery } from '@/redux/features/authApiSlice';
import { RootState } from '@/redux/store';
import { useSelector } from 'react-redux';

export function UserNav() {
const {
data: user,
isLoading,
isFetching,
} = useRetrieveUserQuery();
const user = useSelector((state: RootState) => state.auth.user);
console.log('user in navbar', user);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand Down
13 changes: 5 additions & 8 deletions frontend/app/(dashboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import { useRetrieveUserQuery } from '@/redux/features/authApiSlice';
import { List, Spinner } from '@/components/common';
import { useSelector } from 'react-redux';
import { RootState } from '@/redux/store';

export default function Page() {
const { data: user, isLoading, isFetching } = useRetrieveUserQuery();

const user = useSelector((state: RootState) => state.auth.user);
console.log('user', user);

const config = [
{
Expand All @@ -21,13 +25,6 @@ export default function Page() {
},
];

if (isLoading || isFetching) {
return (
<div className='flex justify-center my-8'>
<Spinner lg />
</div>
);
}

return (
<>
Expand Down
16 changes: 12 additions & 4 deletions frontend/hooks/use-verify.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useEffect } from 'react';
import { useAppDispatch } from '@/redux/hooks';
import { setAuth, finishInitialLoad } from '@/redux/features/authSlice';
import { useVerifyMutation } from '@/redux/features/authApiSlice';
import { setAuth, setUser, finishInitialLoad } from '@/redux/features/authSlice';
import { useRetrieveUserQuery, useVerifyMutation } from '@/redux/features/authApiSlice';

export default function useVerify() {
const dispatch = useAppDispatch();

const [verify] = useVerifyMutation();
const [verify] = useVerifyMutation();

const { data: userData } = useRetrieveUserQuery();

useEffect(() => {
verify(undefined)
Expand All @@ -17,5 +19,11 @@ export default function useVerify() {
.finally(() => {
dispatch(finishInitialLoad());
});
}, []);
}, []);

useEffect(() => {
if (userData) {
dispatch(setUser(userData));
}
}, [userData, dispatch]);
}
40 changes: 23 additions & 17 deletions frontend/redux/features/authSlice.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { createSlice } from '@reduxjs/toolkit';
import { User } from '@/typings';
import { PayloadAction, createSlice } from '@reduxjs/toolkit';

interface AuthState {
isAuthenticated: boolean;
isLoading: boolean;
isLoading: boolean;
user: User | null;
}

const initialState = {
isAuthenticated: false,
isLoading: true,
isLoading: true,
user: null,
} as AuthState;

const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
setAuth: state => {
state.isAuthenticated = true;
},
logout: state => {
state.isAuthenticated = false;
},
finishInitialLoad: state => {
state.isLoading = false;
},
},
name: 'auth',
initialState,
reducers: {
setAuth: (state) => {
state.isAuthenticated = true;
},
setUser(state, action: PayloadAction<User>) {
state.user = action.payload;
},
logout: (state) => {
state.isAuthenticated = false;
},
finishInitialLoad: (state) => {
state.isLoading = false;
},
},
});

export const { setAuth, logout, finishInitialLoad } = authSlice.actions;
export const { setAuth, setUser, logout, finishInitialLoad } = authSlice.actions;
export default authSlice.reducer;
31 changes: 31 additions & 0 deletions frontend/redux/localStorage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// utils/localStorage.js

import { RootState } from './store';

export const loadState = () => {
try {
if (typeof window !== 'undefined') {
console.log('You are on the browser');
return undefined;
} else {
console.log('You are on the server');
// 👉️ can't use localStorage
}
const serializedState = localStorage.getItem('state');
if (serializedState === null) {
return undefined;
}
return JSON.parse(serializedState);
} catch (err) {
return undefined;
}
};

export const saveState = (state: RootState) => {
try {
const serializedState = JSON.stringify(state);
localStorage.setItem('state', serializedState);
} catch {
// ignore write errors
}
};
20 changes: 13 additions & 7 deletions frontend/redux/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
'use client';

import { store } from './store';
import { useRef } from 'react';
import { Provider } from 'react-redux';
import { AppStore, makeStore } from './store';

interface Props {
children: React.ReactNode;
}
export default function StoreProvider({
children,
}: {
children: React.ReactNode;
}) {
const storeRef = useRef<AppStore>();
if (!storeRef.current) {
// Create the store instance the first time this renders
storeRef.current = makeStore();
}

export default function CustomProvider({ children }: Props) {
return <Provider store={store}>{children}</Provider>;
return <Provider store={storeRef.current}>{children}</Provider>;
}
37 changes: 26 additions & 11 deletions frontend/redux/store.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import { configureStore } from '@reduxjs/toolkit';
import { apiSlice } from './services/apiSlice';
import authReducer from './features/authSlice';
import { loadState, saveState } from './localStorage'; // Import the utility functions

export const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
auth: authReducer,
},
middleware: getDefaultMiddleware =>
getDefaultMiddleware().concat(apiSlice.middleware),
devTools: process.env.NODE_ENV !== 'production',
});
export const makeStore = () => {
let preloadedState; // Load any saved state

export type RootState = ReturnType<(typeof store)['getState']>;
export type AppDispatch = (typeof store)['dispatch'];
const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
auth: authReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiSlice.middleware),
preloadedState, // Pass the loaded state
devTools: process.env.NODE_ENV !== 'production',
});

store.subscribe(() => {
saveState(store.getState()); // Save the current state to local storage
});

return store;
};

// Infer the type of makeStore
export type AppStore = ReturnType<typeof makeStore>;
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<AppStore['getState']>;
export type AppDispatch = AppStore['dispatch'];
7 changes: 7 additions & 0 deletions frontend/typings.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
export type Todo = {
id: number;
};

export type User = {
id: number;
first_name: string;
last_name: string;
email: string;
};

0 comments on commit 89af175

Please sign in to comment.