PliWould/features/product/productSlice.ts

186 lines
6.0 KiB
TypeScript

import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { area_t, dimensions_t, Id, length_t, Product, ProductData } from '@/lib/product';
import uuid from "react-native-uuid";
import { RootState } from '@/app/store';
import { classToPlain, plainToClass } from 'class-transformer';
const initialState = {
products: [] as ProductData[],
}
export type UpdateAttribute = {
product_id: Id,
attributeKey: string,
attributeValue: any,
}
export type UpdateAttributeKey = {
product_id: Id,
oldKey: string,
newKey: string,
}
export type AddAttribute = {
product_id: Id,
}
const cp = (obj: any) => JSON.parse(JSON.stringify(obj));
const productsState = createSlice({
name: 'products-slice',
initialState,
reducers: {
createProduct(state, action: PayloadAction<ProductData>) {
if (!state) {
return initialState
}
const product = action.payload;
if (!product.id) product.id = uuid.v4().toString();
state.products = [...state.products, action.payload];
return state;
},
deleteProduct(state, action: PayloadAction<Id>) {
if (!state) return initialState;
return {
...state,
products: [...state.products.filter((prod) => {
return prod.id?.valueOf() !== action.payload.valueOf();
})],
}
},
updateAttribute(state, action: PayloadAction<UpdateAttribute>) {
const { product_id, attributeKey, attributeValue } = action.payload
if (!state) return initialState;
return {
...state,
products: state.products.map(prod => {
if (prod.id !== product_id) return prod;
const attributes = cp(prod.attributes);
attributes[attributeKey] = attributeValue;
return {
...prod,
attributes,
}
})
};
},
changeKey(state, action: PayloadAction<UpdateAttributeKey>) {
if (!state) return initialState;
const { product_id, oldKey, newKey } = action.payload
return {
...state,
products: state.products.map(prod => {
if (prod.id !== product_id) return prod;
const attributes = cp(prod.attributes);
attributes[newKey] = attributes[oldKey];
delete attributes[oldKey];
attributes.id = prod.id;
return {
...prod,
attributes,
}
})
};
},
addAttribute(state, action: PayloadAction<Id>) {
if (!state) return initialState;
const product_id = action.payload;
state.products = state.products.map(prod => {
if (prod.id !== product_id) return prod;
const i = (Object.keys(prod.attributes || {}).filter(k => k.match(/attribute [\d]+/)) || []).length;
const newAttribute = `attribute ${i + 1}`;
return {
...prod,
attributes: {
...prod.attributes,
[newAttribute]: `value`,
}
}
});
return state;
},
deleteAttribute(state, action: PayloadAction<{ product_id: Id, attribute: string }>) {
if (!state) return initialState;
const { product_id, attribute } = action.payload;
return {
...state,
products: state.products.map(prod => {
if (prod.id !== product_id) return prod;
const attributes = Object.fromEntries(Object.entries(prod).filter(([k, v]) => (k !== attribute)));
return {
...prod,
attributes,
}
}),
};
},
updatePrice(state, action: PayloadAction<{ product_id: Id, pricePerUnit: number }>) {
if (!state) return initialState;
const { product_id, pricePerUnit } = action.payload;
state.products = state.products.map(prod => {
if (prod.id !== product_id) return prod;
prod.pricePerUnit = pricePerUnit;
return prod;
});
return state;
},
updateDimensions(state, action: PayloadAction<{ product_id: Id, dimensions: dimensions_t }>) {
if (!state) return initialState;
const { product_id, dimensions } = action.payload;
console.log("Changing dimensions: %o", action.payload);
return {
...state,
products: state.products.map(prod => {
if (prod.id !== product_id) return prod;
return {
...prod,
dimensions,
}
}),
};
},
}
});
export const selectProductsDatas = (state: RootState) => {
return state.products;
}
export const selectProducts = createSelector([selectProductsDatas], productsData => {
return productsData.map(d => Product.fromObject(d));
})
export const selectProductIds = createSelector([selectProducts], products => {
return products.map(p => p.id);
})
export const selectProductAttributes = createSelector([selectProducts], products => {
return Object.fromEntries(products.map(p => {
return [
p.id,
p.attributesAsList,
]
}))
})
export const actions = {
...productsState.actions
};
export const {
createProduct,
deleteProduct,
changeKey,
updateAttribute,
addAttribute,
deleteAttribute,
updatePrice,
updateDimensions,
} = productsState.actions;
export default productsState.reducer;