Files
stats/apps/web/src/components/report/reportSlice.ts
2023-12-17 13:44:45 +01:00

183 lines
4.3 KiB
TypeScript

import type {
IChartBreakdown,
IChartEvent,
IChartInput,
IChartRange,
IChartType,
IInterval,
} from '@/types';
import { alphabetIds, isMinuteIntervalEnabledByRange } from '@/utils/constants';
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
type InitialState = IChartInput & {
dirty: boolean;
startDate: string | null;
endDate: string | null;
};
// First approach: define the initial state using that type
const initialState: InitialState = {
dirty: false,
name: 'Untitled',
chartType: 'linear',
interval: 'day',
breakdowns: [],
events: [],
range: 30,
startDate: null,
endDate: null,
};
export const reportSlice = createSlice({
name: 'report',
initialState,
reducers: {
resetDirty(state) {
return {
...state,
dirty: false,
};
},
reset() {
return initialState;
},
setReport(state, action: PayloadAction<IChartInput>) {
return {
...action.payload,
startDate: null,
endDate: null,
dirty: false,
};
},
setName(state, action: PayloadAction<string>) {
state.dirty = true;
state.name = action.payload;
},
// Events
addEvent: (state, action: PayloadAction<Omit<IChartEvent, 'id'>>) => {
state.dirty = true;
state.events.push({
id: alphabetIds[state.events.length]!,
...action.payload,
});
},
removeEvent: (
state,
action: PayloadAction<{
id: string;
}>
) => {
state.dirty = true;
state.events = state.events.filter(
(event) => event.id !== action.payload.id
);
},
changeEvent: (state, action: PayloadAction<IChartEvent>) => {
state.dirty = true;
state.events = state.events.map((event) => {
if (event.id === action.payload.id) {
return action.payload;
}
return event;
});
},
// Breakdowns
addBreakdown: (
state,
action: PayloadAction<Omit<IChartBreakdown, 'id'>>
) => {
state.dirty = true;
state.breakdowns.push({
id: alphabetIds[state.breakdowns.length]!,
...action.payload,
});
},
removeBreakdown: (
state,
action: PayloadAction<{
id: string;
}>
) => {
state.dirty = true;
state.breakdowns = state.breakdowns.filter(
(event) => event.id !== action.payload.id
);
},
changeBreakdown: (state, action: PayloadAction<IChartBreakdown>) => {
state.dirty = true;
state.breakdowns = state.breakdowns.map((breakdown) => {
if (breakdown.id === action.payload.id) {
return action.payload;
}
return breakdown;
});
},
// Interval
changeInterval: (state, action: PayloadAction<IInterval>) => {
state.dirty = true;
state.interval = action.payload;
},
// Chart type
changeChartType: (state, action: PayloadAction<IChartType>) => {
state.dirty = true;
state.chartType = action.payload;
if (
!isMinuteIntervalEnabledByRange(state.range) &&
state.interval === 'minute'
) {
state.interval = 'hour';
}
},
// Date range
changeStartDate: (state, action: PayloadAction<string>) => {
state.dirty = true;
state.startDate = action.payload;
},
// Date range
changeEndDate: (state, action: PayloadAction<string>) => {
state.dirty = true;
state.endDate = action.payload;
},
changeDateRanges: (state, action: PayloadAction<IChartRange>) => {
state.dirty = true;
state.range = action.payload;
if (action.payload === 0.3 || action.payload === 0.6) {
state.interval = 'minute';
} else if (action.payload === 0 || action.payload === 1) {
state.interval = 'hour';
} else if (action.payload <= 30) {
state.interval = 'day';
} else {
state.interval = 'month';
}
},
},
});
// Action creators are generated for each case reducer function
export const {
reset,
setReport,
setName,
addEvent,
removeEvent,
changeEvent,
addBreakdown,
removeBreakdown,
changeBreakdown,
changeInterval,
changeDateRanges,
changeChartType,
resetDirty,
} = reportSlice.actions;
export default reportSlice.reducer;