This commit is contained in:
seb
2026-07-31 08:34:51 +02:00
parent a95b7f4b1e
commit 797ea59bed
24 changed files with 1151 additions and 130 deletions

103
src/store/companySlice.js Normal file
View File

@@ -0,0 +1,103 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { company } from '../api';
import { normalizeCompany } from '../utils/companyForm';
import {
bootstrapSession,
createCompany,
loginWithGoogle,
logout,
selectCompany,
} from './authSlice';
export const loadCurrentCompany = createAsyncThunk(
'company/loadCurrent',
async (_, { getState }) => {
const companyId = getState().auth.user?.selectedCompanyId;
if (!companyId) return null;
const data = await company.getById(companyId);
return normalizeCompany(data.company);
},
);
export const updateCompany = createAsyncThunk(
'company/update',
async (payload, { getState }) => {
const companyId = getState().auth.user?.selectedCompanyId;
if (!companyId) throw new Error('Kein Unternehmen ausgewählt.');
await company.update(companyId, payload);
const data = await company.getById(companyId);
return normalizeCompany(data.company, payload);
},
);
const initialState = {
current: null,
status: 'idle',
error: null,
};
const companySlice = createSlice({
name: 'company',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(loadCurrentCompany.pending, (state) => {
state.status = 'loading';
state.error = null;
})
.addCase(loadCurrentCompany.fulfilled, (state, action) => {
state.status = 'succeeded';
state.current = action.payload;
})
.addCase(loadCurrentCompany.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
})
.addCase(updateCompany.pending, (state) => {
state.status = 'loading';
state.error = null;
})
.addCase(updateCompany.fulfilled, (state, action) => {
state.status = 'succeeded';
state.current = action.payload;
})
.addCase(updateCompany.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
})
.addCase(logout.fulfilled, (state) => {
state.current = null;
state.status = 'idle';
state.error = null;
});
},
});
export const selectCurrentCompany = (state) => state.company.current;
export const selectCompanyId = (state) => state.company.current?.id ?? null;
export const selectCompanyStatus = (state) => state.company.status;
export const selectCompanyError = (state) => state.company.error;
export const selectCompanyName = (state) => state.company.current?.name ?? '';
export const selectCompanyIso639 = (state) => state.company.current?.iso639 ?? 'de';
export const selectCompanyTaxrate = (state) => state.company.current?.taxrate ?? null;
export const selectCompanyReducedTaxrate = (state) => state.company.current?.reducedtaxrate ?? null;
export const selectCompanyRootCategoryId = (state) => state.company.current?.rootCategoryId ?? null;
export function companyLoadListener(listenerMiddleware) {
listenerMiddleware.startListening({
matcher: (action) =>
bootstrapSession.fulfilled.match(action) ||
loginWithGoogle.fulfilled.match(action) ||
selectCompany.fulfilled.match(action) ||
createCompany.fulfilled.match(action),
effect: async (_action, api) => {
const companyId = api.getState().auth.user?.selectedCompanyId;
if (companyId) {
api.dispatch(loadCurrentCompany());
}
},
});
}
export default companySlice.reducer;