brf/client/admin/hooks/use_items_reducer.ts
2025-12-18 07:31:37 +01:00

130 lines
2.4 KiB
TypeScript

import { useReducer } from 'preact/hooks'
type DefaultItem = {
id: number
}
const ADD = 'add'
type AddAction<I> = {
type: typeof ADD
payload: I
}
const add = <I>(item: I): AddAction<I> => ({
type: ADD,
payload: item,
})
const DEL = 'delete'
type DeleteAction = {
type: typeof DEL
id: number
}
const del = (id: number): DeleteAction => ({
type: DEL,
id,
})
const LOAD = 'load'
type LoadAction<I> = {
type: typeof LOAD
payload: I[]
}
const load = <I>(items: I[]): LoadAction<I> => ({
type: LOAD,
payload: items,
})
const RESET = 'reset'
type ResetAction<I> = {
type: typeof RESET
payload: I[]
}
const reset = <I>(items: I[] = []): ResetAction<I> => ({
type: RESET,
payload: items,
})
const UPDATE = 'update'
type UpdateAction<I> = {
type: typeof UPDATE
id: number
payload: I
}
const update = <I>(id: number, item: I): UpdateAction<I> => ({
type: UPDATE,
id,
payload: item,
})
export const actions = {
add,
del,
load,
reset,
update,
}
type Action<I> = AddAction<I> | DeleteAction | LoadAction<I> | ResetAction<I> | UpdateAction<I>
export const itemsReducer = <I extends DefaultItem>(state: I[], action: Action<I>) => {
switch (action.type) {
case ADD:
return [...state, action.payload]
case DEL: {
const index = state.findIndex((item) => item.id === action.id)
if (index > -1) {
return [...state.slice(0, index), ...state.slice(index + 1)]
}
return state
}
case LOAD: {
return [...state, ...action.payload]
}
case RESET: {
return [...action.payload]
}
case UPDATE: {
const index = state.findIndex((item) => item.id === action.id)
if (index > -1) {
const newItem = {
...state[index],
...action.payload,
}
return [...state.slice(0, index), newItem, ...state.slice(index + 1)]
}
return state
}
default:
return state
}
}
export default <I extends DefaultItem>(init: I[] = []) => {
const [items, dispatch] = useReducer(itemsReducer<I>, init)
const actions = {
add: (item: I) => dispatch(add<I>(item)),
del: (id: number) => dispatch(del(id)),
load: (items: I[]) => dispatch(load<I>(items)),
reset: (items: I[]) => dispatch(reset<I>(items)),
update: (id: number, item: I) => dispatch(update<I>(id, item)),
}
return [items, actions] as [I[], typeof actions]
}