remake app ohome setup /notworking

This commit is contained in:
2021-10-24 22:18:31 +02:00
parent 4568076445
commit 55c6704d1b
76 changed files with 22173 additions and 749 deletions

View File

@@ -0,0 +1,198 @@
import { createSlice, createAsyncThunk, createSelector } from '@reduxjs/toolkit';
export const fetchItems = createAsyncThunk('items/fetchItems', async () => {
let items = []
await fetch('https://ohomeapi.familymoyaers.com/groceries', {
headers: {
'Accept': 'application/json'
}
})
.then((res) => res.json())
.then((data) => { items = data })
items.forEach((item) => { item.checked = false; item.modalVisible = false; })
return items
})
export const itemAdded = createAsyncThunk('items/itemAdded',
async (payload, thunkAPI) => {
let newItem = {
...payload,
amount: payload.amount,
price: payload.price && Number(payload.price),
modalVisible: false,
checked: false,
}
// let existingItem = thunkAPI.getState().items.entities.slice().find(item => item.productName === newItem.productName)
// if (existingItem) {
// alert("This item was already in " + thunkAPI.getState().lists.entities.find((list) => list._id === existingItem.listId).listName.toString())
// existingItem = {
// ...existingItem,
// person: existingItem.person + ', ' + newItem.person,
// details: existingItem.details + ', ' + newItem.details,
// amount: existingItem.amount + newItem.amount
// }
// const requestOptions = {
// method: 'PUT',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(existingItem)
// };
// await fetch('https://ohomeapi.familymoyaers.com/grocery', requestOptions)
// return { existed: true, newItem: existingItem }
// }
// else {
// const requestOptions = {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(newItem)
// };
// await fetch('https://ohomeapi.familymoyaers.com/grocery', requestOptions)
// return { existed: false, newItem: newItem }
// }
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newItem)
};
await fetch('https://ohomeapi.familymoyaers.com/grocery', requestOptions)
return { existed: false, newItem: newItem }
}
)
export const itemsRemoved = createAsyncThunk('items/itemsRemoved', async (payload, thunkAPI) => {
let productIds = []
await thunkAPI.getState().items.entities
.forEach(item =>
item.checked === true && productIds.push(item._id)
)
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productIds: productIds })
};
await fetch('https://ohomeapi.familymoyaers.com/groceries', requestOptions)
})
export const itemsRemovedByList = createAsyncThunk('items/itemsRemovedByList', async (payload) => {
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ listId: payload })
};
console.log(payload)
await fetch('https://ohomeapi.familymoyaers.com/groceriesByList', requestOptions)
return payload
})
export const itemRemoved = createAsyncThunk('items/itemRemoved', async (payload, thunkAPI) => {
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: payload })
};
await fetch('https://ohomeapi.familymoyaers.com/grocery', requestOptions)
return payload
})
const itemsSlice = createSlice({
name: 'items',
initialState: {
status: 'loading',
entities: [
]
},
reducers: {
checkToggle: {
reducer(state, action) {
let item = state.entities.find((item) => item._id === action.payload._id)
item.checked = !item.checked
},
prepare(_id) {
return {
payload: {
_id: _id
}
}
}
},
checkAll(state, action) {
let listItems = state.entities.filter(item => item.listId === action.payload)
if (listItems.slice().filter((item) => item.checked === false).length === 0) {
listItems.forEach(item => item.checked = false)
}
else {
listItems.forEach(item => item.checked = true)
}
},
modalToggle: {
reducer(state, action) {
let item = state.entities.find((item) => item._id === action.payload._id)
if (!state.entities.find((i) => i.modalVisible === true) || item.modalVisible) {
item.modalVisible = !item.modalVisible;
}
},
prepare(_id) {
return {
payload: {
_id: _id
}
}
}
},
},
extraReducers: builder => {
builder
.addCase(fetchItems.fulfilled, (state, action) => {
state.entities = action.payload;
// state.entities.unshift(...stockProducts);
state.status = 'idle'
console.log('items fetched')
})
.addCase(itemAdded.fulfilled, (state, action) => {
let newItem = action.payload.newItem
state.entities.push(newItem)
console.log('sent the new item')
// if (action.payload.existed === false) {
// state.entities.push(newItem)
// console.log('sent the new item')
// }
// else {
// let prevItem = state.entities.find(item => item._id === newItem._id)
// Object.assign(prevItem, newItem)
// console.log('edited the item')
})
.addCase(itemsRemoved.fulfilled, (state, action) => {
state.entities = state.entities.filter(item => item.checked === false)
console.log('items removed')
})
.addCase(itemsRemovedByList.fulfilled, (state, action) => {
state.entities = state.entities.filter(item => item.listId === action.payload)
})
.addCase(itemRemoved.fulfilled, (state, action) => {
state.entities.splice(state.entities.findIndex((item) => item._id === action.payload), 1)
console.log('item removed')
})
}
});
//selectors
//all items
export const selectAllSortedItems = createSelector(
state => state.items.entities,
state => state.products.entities,
(items, products) => {
return items.slice().sort((a, b) => {
let productA = products.find(product => product._id === a._id)
let tagA = productA ? productA.tag : a.tag ? a.tag : 'uncategorized'
let productB = products.find(product => product._id === b._id)
let tagB = productB ? productB.tag : b.tag ? b.tag : 'uncategorized'
return tagA.localeCompare(tagB)
});
})
//product by id
export const selectItemById = (state, _id) => state.items.entities.find(item => item._id === _id)
//item by modal visible
export const selectItemModalVisible = createSelector(
state => state.items.entities,
items => items.find(item => item.modalVisible === true)
)
export const { checkToggle, checkAll, modalToggle } = itemsSlice.actions;
export default itemsSlice.reducer;

View File

@@ -0,0 +1,97 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchLists = createAsyncThunk('items/fetchLists', async () => {
let lists = []
await fetch('https://ohomeapi.familymoyaers.com/groceryLists', {
headers: {
'Accept': 'application/json'
}
})
.then((res) => res.json())
.then((data) => { lists = data })
console.log(lists)
lists.forEach((list) => { list.open = false })
return lists
})
export const listAdded = createAsyncThunk('items/listAdded',
async (payload) => {
let list = {
...payload,
open: false
}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(list)
};
await fetch('https://ohomeapi.familymoyaers.com/groceryList', requestOptions)
.then((res) => res.json())
.then((data) => { list._id = data })
return list
}
)
export const listRemoved = createAsyncThunk('items/listRemoved', async (payload, thunkAPI) => {
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ listId: payload })
};
await fetch('https://ohomeapi.familymoyaers.com/groceryList', requestOptions)
return payload
})
export const listEdited = createAsyncThunk('items/listEdited', async (payload) => {
const requestOptions = {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
};
await fetch('https://ohomeapi.familymoyaers.com/groceryList', requestOptions)
return payload
})
const listsSlice = createSlice({
name: 'lists',
initialState: {
status: 'loading',
entities: [
]
},
reducers: {
toggleOpen(state, action) {
state.entities.forEach(list => list._id !== action.payload && (list.open = false))
let list = state.entities.find((list) => list._id === action.payload)
list && (list.open = !list.open)
},
},
extraReducers: builder => {
builder
.addCase(fetchLists.fulfilled, (state, action) => {
state.entities = action.payload;
// state.entities.unshift(...stockProducts);
state.status = 'idle'
// console.log('items fetched')
})
.addCase(listAdded.fulfilled, (state, action) => {
state.entities.push(action.payload)
// console.log('sent the new item')
})
.addCase(listRemoved.fulfilled, (state, action) => {
state.entities.splice(state.entities.findIndex((list) => list._id === action.payload), 1)
// console.log('item removed')
})
.addCase(listEdited.fulfilled, (state, action) => {
let list = state.entities.find(list=> list._id === action.payload._id)
list.listName = action.payload.listName
list.listDescription = action.payload.listDescription
// console.log('item removed')
})
}
});
export const selectOpenListId = (state) => {
let list = state.lists.entities.find(list => list.open === true)
return list && list._id }
// export const { checkToggle, checkAll, modalToggle } = itemsSlice.actions;
export const { toggleOpen } = listsSlice.actions;
export default listsSlice.reducer;

View File

@@ -0,0 +1,171 @@
import { createSlice, createAsyncThunk, createSelector } from '@reduxjs/toolkit';
export const fetchProducts = createAsyncThunk('products/fetchProducts', async () => {
let products = []
await fetch('https://ohomeapi.familymoyaers.com/products', {
headers: {
'Accept': 'application/json'
}
})
.then((res) => res.json())
.then((data) => { products = data })
products.forEach((product) => { product.checked = false; product.modalVisible = false; })
return products
})
export const productAdded = createAsyncThunk('products/productAdded',
async (payload) => {
let newProduct = {
...payload,
type: 'product',
price: Number(payload.price),
modalVisible: false,
checked: false,
}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newProduct)
};
await fetch('https://ohomeapi.familymoyaers.com/product', requestOptions)
.then((res) => res.json())
.then((data) => { newProduct._id = data })
return newProduct
}
)
export const productsRemoved = createAsyncThunk('products/productsRemoved', async (payload, thunkAPI) => {
let productIds = []
await thunkAPI.getState().products.entities
.forEach(product =>
product.checked === true && productIds.push(product._id)
)
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productIds: productIds })
};
await fetch('https://ohomeapi.familymoyaers.com/products', requestOptions)
})
export const productRemoved = createAsyncThunk('products/productRemoved', async (payload) => {
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: payload })
};
await fetch('https://ohomeapi.familymoyaers.com/product', requestOptions)
return payload
})
export const productsUploaded = createAsyncThunk('products/productsUploaded', async (payload) => {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
};
fetch('https://ohomeapi.familymoyaers.com/products', requestOptions)
return payload
})
const productsSlice = createSlice({
name: 'products',
initialState: {
status: 'loading',
entities: [
]
},
reducers: {
checkToggle: {
reducer(state, action) {
let product = state.entities.find((product) => product._id === action.payload._id)
product.checked = !product.checked;
},
prepare(_id) {
return {
payload: {
_id: _id
}
}
}
},
modalToggle: {
reducer(state, action) {
let product = state.entities.find((product) => product._id === action.payload._id)
if (!state.entities.find((p) => p.modalVisible === true) || product.modalVisible) {
product.modalVisible = !product.modalVisible;
}
},
prepare(_id) {
return {
payload: {
_id: _id
}
}
}
},
},
extraReducers: builder => {
builder
.addCase(fetchProducts.fulfilled, (state, action) => {
state.entities = action.payload
state.status = 'idle'
console.log('products fetched')
})
.addCase(productAdded.fulfilled, (state, action) => {
state.entities.push(action.payload);
console.log('sended the item')
})
.addCase(productsRemoved.fulfilled, (state, action) => {
state.entities = state.entities.filter(product => product.checked === false)
console.log('products removed')
})
.addCase(productRemoved.fulfilled, (state, action) => {
state.entities.splice(state.entities.findIndex((product) => product._id === action.payload), 1)
console.log('product removed')
})
.addCase(productsUploaded.fulfilled, (state, action) => {
action.payload.forEach(product => state.entities.push(product))
})
}
});
//selectors
//all products
export const selectAllProducts = state => state.products.entities
export const selectAllSortedProducts = state => state.products.entities.slice().sort((a, b) => a.tag.localeCompare(b.tag))
//product by id
export const selectProductsByTag = (state, tag) => state.products.entities.filter(product => product.tag === tag)
export const selectProductById = (state, _id) => {
let product = state.products.entities.find(product => product._id === _id)
if (product) {
return product
}
else {
return {
productName: _id,
tag: 'uncategorized',
}
}
}
export const selectProductByItem = (state, item) => {
let product = state.products.entities.find(product => product._id === item._id)
if (product) {
return product
}
else {
return {
productName: item._id,
tag: item.tag ? item.tag : 'uncategorized',
price: item.price && item.price,
}
}
}
export const selectProductModalVisible = createSelector(
state => state.products.entities,
products => products.find(product => product.modalVisible === true)
)
export const { checkToggle, modalToggle } = productsSlice.actions;
export default productsSlice.reducer;

View File

@@ -0,0 +1,49 @@
import { createSlice} from '@reduxjs/toolkit';
const initialState = {
status: 'idle',
entities: [
{ tagName: 'uncategorized', color: '#92a69b' },
{ tagName: 'Vegetables', color: '#BDD684' },
{ tagName: 'Grains', color: '#FA9600' },
{ tagName: 'Meal', color: '#ffe2a3' },
{ tagName: 'Meat', color: '#ef5350' },
{ tagName: 'Dairy', color: '#E8E8E8' },
{ tagName: 'Preservable', color: '#8ac8e6' },
{ tagName: 'Spices', color: '#d8eb34' },
{ tagName: 'Drinks', color: '#00e0b7' },
{ tagName: 'Snack', color: '#9575CD' },
{ tagName: 'Fruit', color: '#8fff40' },
{ tagName: 'Sauce', color: '#FCCABB' },
{ tagName: 'Baking', color: '#edb600' },
{ tagName: 'Cleaning', color: '#26EDEA' },
{ tagName: 'Hygiene', color: '#FC92F9' },
{ tagName: 'Pets', color: '#a0fc92' },
{ tagName: 'Equipment', color: '#C8C8E6' },
]
}
const tagsSlice = createSlice({
name: 'tags',
initialState,
reducers: {
tagAdded: {
reducer(state, action) {
state.push(action.payload)
},
prepare(tagName, color) {
return {
payload: {
tagName,
color
}
}
}
}
}
})
export const findTag = (state, tagName) => state.tags.entities.find(tag => tag.tagName === tagName)
export const selectAllTags = (state) => state.tags.entities
export const { tagAdded } = tagsSlice.actions
export default tagsSlice.reducer

View File

@@ -0,0 +1,26 @@
import { createSlice} from '@reduxjs/toolkit';
const initialState = {
peers: 0,
}
const informationSlice = createSlice({
name: 'information',
initialState,
reducers: {
peersChanged: {
reducer(state, action) {
state.peers += action.payload.amount
},
prepare(amount) {
return {
payload: {
amount
}
}
}
}
}
})
export const { peersChanged } = informationSlice.actions
export default informationSlice.reducer

View File

@@ -0,0 +1,85 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchRecipes = createAsyncThunk('recipes/fetchRecipes', async () => {
let recipes = []
await fetch('https://ohomeapi.familymoyaers.com/recipes', {
headers: {
'Accept': 'application/json'
}
})
.then((res) => res.json())
.then((data) => { recipes = data })
recipes.forEach(recipe => recipe.ingredients.forEach(ingredient => ingredient.checked = false))
return recipes
})
export const addRecipe = createAsyncThunk('recipes/addRecipe', async (payload) => {
const size = new TextEncoder().encode(JSON.stringify(payload)).length
console.log(size)
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
};
await fetch('https://ohomeapi.familymoyaers.com/recipe', requestOptions)
return payload
})
export const updateRecipe = createAsyncThunk('recipes/updateRecipe', async (payload) => {
const requestOptions = {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
};
await fetch('https://ohomeapi.familymoyaers.com/recipe', requestOptions)
return payload
})
export const removeRecipe = createAsyncThunk('recipes/removeRecipe', async (payload) => {
const requestOptions = {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: payload })
};
await fetch('https://ohomeapi.familymoyaers.com/recipe', requestOptions)
return payload
})
const recipesSlice = createSlice({
name: 'recipes',
initialState: {
status: 'loading',
entities: []
},
reducers: {
ingredientCheckToggle(state, action) {
let ingredient = state.entities.find(recipe => recipe._id === action.payload.id).ingredients.find(ingredient => ingredient.productName === action.payload.productName)
ingredient.checked = !ingredient.checked
}
},
extraReducers: builder => {
builder
.addCase(fetchRecipes.fulfilled, (state, action) => {
state.entities = action.payload
state.status = 'idle'
console.log('RECIPES fetched')
})
.addCase(addRecipe.fulfilled, (state, action) => {
state.entities.push(action.payload)
console.log('RECIPE added')
})
.addCase(updateRecipe.fulfilled, (state, action) => {
let index = state.entities.findIndex(recipe => recipe._id === action.payload._id)
state.entities.splice(index, 1, action.payload)
})
.addCase(removeRecipe.fulfilled, (state, action) => {
state.entities.splice(state.entities.findIndex(recipe => recipe._id === action.payload), 1)
console.log('RECIPE removed')
})
}
})
export const findRecipeById = (state, id) => state.recipes.entities.find(recipe => recipe._id === id)
export const { ingredientCheckToggle } = recipesSlice.actions
export default recipesSlice.reducer

23
src/redux/store.js Normal file
View File

@@ -0,0 +1,23 @@
import { configureStore } from '@reduxjs/toolkit';
import itemsReducer from './slices/groceryList/itemsSlice';
import productsReducer from './slices/groceryList/productsSlice';
import lists from './slices/groceryList/listsSlice';
import tagsReducer from './slices/groceryList/tagsSlice';
// import informationReducer from './slices/informationSlice';
import recipes from './slices/recipesSlice';
export default configureStore({
reducer: {
lists: lists,
items: itemsReducer,
products: productsReducer,
recipes: recipes,
tags: tagsReducer,
},
})