110 lines
3.6 KiB
JavaScript
110 lines
3.6 KiB
JavaScript
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
|
|
import { auth, company } from '../api';
|
|
|
|
export const bootstrapSession = createAsyncThunk('auth/bootstrap', async (session) => {
|
|
if (session) return session;
|
|
return 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, '', '/');
|
|
});
|
|
|
|
function mergeUser(state, incoming) {
|
|
if (!incoming) return state.user;
|
|
const selectedCompanyId =
|
|
incoming.selectedCompanyId ?? state.user?.selectedCompanyId ?? null;
|
|
return { ...state.user, ...incoming, selectedCompanyId };
|
|
}
|
|
|
|
const initialState = {
|
|
user: null,
|
|
googleClientId: null,
|
|
status: 'loading',
|
|
};
|
|
|
|
const authSlice = createSlice({
|
|
name: 'auth',
|
|
initialState,
|
|
reducers: {},
|
|
extraReducers: (builder) => {
|
|
builder
|
|
.addCase(bootstrapSession.fulfilled, (state, action) => {
|
|
const session = action.payload;
|
|
state.googleClientId = session.googleClientId ?? state.googleClientId;
|
|
if (!session.user) {
|
|
if (state.status !== 'authed') {
|
|
state.user = null;
|
|
state.status = 'anon';
|
|
}
|
|
return;
|
|
}
|
|
state.user = mergeUser(state, session.user);
|
|
state.status = 'authed';
|
|
})
|
|
.addCase(bootstrapSession.rejected, (state) => {
|
|
if (state.status === 'loading') {
|
|
state.user = null;
|
|
state.status = 'anon';
|
|
}
|
|
})
|
|
.addCase(loginWithGoogle.fulfilled, (state, action) => {
|
|
const session = action.payload;
|
|
state.user = session.user;
|
|
state.googleClientId = session.googleClientId ?? state.googleClientId;
|
|
state.status = 'authed';
|
|
})
|
|
.addCase(loginWithGoogle.rejected, (state) => {
|
|
state.user = null;
|
|
state.status = 'anon';
|
|
})
|
|
.addCase(selectCompany.fulfilled, (state, action) => {
|
|
state.user = mergeUser(state, action.payload);
|
|
state.status = 'authed';
|
|
})
|
|
.addCase(createCompany.fulfilled, (state, action) => {
|
|
state.user = mergeUser(state, action.payload);
|
|
state.status = 'authed';
|
|
})
|
|
.addCase(createCompany.rejected, (state, action) => {
|
|
console.error('[redux] createCompany.rejected', action.error?.message, action.payload);
|
|
})
|
|
.addCase(logout.fulfilled, (state) => {
|
|
state.user = null;
|
|
state.status = 'anon';
|
|
});
|
|
},
|
|
});
|
|
|
|
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.user?.selectedCompanyId == null;
|
|
|
|
export default authSlice.reducer;
|