192 lines
6.1 KiB
TypeScript
192 lines
6.1 KiB
TypeScript
import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
import { Id, Product } from '@/lib/product';
|
|
import { dimensions_t, } from "@/lib/dimensions";
|
|
import uuid from "react-native-uuid";
|
|
import { RootState } from '@/app/store';
|
|
import { Length } from 'convert';
|
|
|
|
const initialState = {
|
|
products: [] as Product[],
|
|
units: "ft",
|
|
};
|
|
|
|
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: {
|
|
setUnits(state, action : PayloadAction<Length>) {
|
|
state.units = action.payload;
|
|
},
|
|
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 selectProducts = (state: RootState) => {
|
|
return state.products;
|
|
}
|
|
|
|
export const selectUnits = (state : RootState) => {
|
|
return (state.units || "ft") as Length;
|
|
}
|
|
|
|
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 {
|
|
setUnits,
|
|
createProduct,
|
|
deleteProduct,
|
|
changeKey,
|
|
updateAttribute,
|
|
addAttribute,
|
|
deleteAttribute,
|
|
updatePrice,
|
|
updateDimensions,
|
|
} = productsState.actions;
|
|
|
|
export default productsState.reducer;
|