This commit is contained in:
seb
2026-07-31 07:02:51 +02:00
parent 9dac151854
commit a95b7f4b1e
14 changed files with 1064 additions and 831 deletions

93
src/store/authSlice.js Normal file
View File

@@ -0,0 +1,93 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { auth, company } from '../api';
export const bootstrapSession = createAsyncThunk('auth/bootstrap', async () => auth.me());
export const loginWithGoogle = createAsyncThunk('auth/login', async (credential) => {
const { session } = await auth.loginWithGoogle(credential);
if (!session?.user) {
throw new Error('Login ok but session cookie not accepted (/api/auth/me still unauthorized)');
}
return session;
});
export const selectCompany = createAsyncThunk('auth/selectCompany', async (companyId) => {
const data = await company.select(companyId);
return data.user ?? { selectedCompanyId: companyId };
});
export const createCompany = createAsyncThunk('auth/createCompany', async (payload) => {
const data = await company.create(payload);
if (data.user) return data.user;
if (data.company?.id) {
const selected = await company.select(data.company.id);
return selected.user ?? { selectedCompanyId: data.company.id };
}
throw new Error('Unternehmen angelegt, aber keine Benutzerdaten erhalten.');
});
export const logout = createAsyncThunk('auth/logout', async () => {
await auth.logout();
window.history.replaceState(null, '', '/');
});
const initialState = {
user: null,
googleClientId: null,
status: 'loading',
companyReady: false,
};
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(bootstrapSession.fulfilled, (state, action) => {
const session = action.payload;
state.user = session.user ?? null;
state.googleClientId = session.googleClientId ?? null;
state.status = session.user ? 'authed' : 'anon';
state.companyReady = session.user?.selectedCompanyId != null;
})
.addCase(bootstrapSession.rejected, (state) => {
state.user = null;
state.status = 'anon';
state.companyReady = false;
})
.addCase(loginWithGoogle.fulfilled, (state, action) => {
const session = action.payload;
state.user = session.user;
state.googleClientId = session.googleClientId ?? state.googleClientId;
state.status = 'authed';
state.companyReady = session.user?.selectedCompanyId != null;
})
.addCase(loginWithGoogle.rejected, (state) => {
state.user = null;
state.status = 'anon';
state.companyReady = false;
})
.addCase(selectCompany.fulfilled, (state, action) => {
state.user = { ...state.user, ...action.payload };
state.companyReady = true;
})
.addCase(createCompany.fulfilled, (state, action) => {
state.user = { ...state.user, ...action.payload };
state.companyReady = true;
})
.addCase(logout.fulfilled, (state) => {
state.user = null;
state.status = 'anon';
state.companyReady = false;
});
},
});
export const selectAuthStatus = (state) => state.auth.status;
export const selectAuthUser = (state) => state.auth.user;
export const selectGoogleClientId = (state) => state.auth.googleClientId;
export const selectNeedsCompanySetup = (state) =>
state.auth.status === 'authed' && !state.auth.companyReady;
export default authSlice.reducer;

8
src/store/index.js Normal file
View File

@@ -0,0 +1,8 @@
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './authSlice';
export const store = configureStore({
reducer: {
auth: authReducer,
},
});