Allowed for null products, move ingredient spreading server-side #2

Merged
jacob merged 6 commits from nullproduct into master 2025-07-28 23:22:59 +00:00
6 changed files with 45 additions and 24 deletions
Showing only changes of commit 728532a7c8 - Show all commits

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="800px" height="800px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<title>ic_fluent_missing_metadata_24_regular</title>
<desc>Created with Sketch.</desc>
<g id="🔍-System-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="ic_fluent_missing_metadata_24_regular" fill="#212121" fill-rule="nonzero">
<path d="M19.7501,2 C20.9927,2 22.0001,3.00736 22.0001,4.25 L22.0001,9.71196 C22.0001,10.5738 21.6578,11.4003 21.0484,12.0098 L21.0222,12.0361 C20.5797,11.7503 20.1003,11.5167 19.5928,11.3442 L19.9876,10.9492 C20.3157,10.6211 20.5001,10.176 20.5001,9.71196 L20.5001,4.25 C20.5001,3.83579 20.1643,3.5 19.7501,3.5 L14.2847,3.5 C13.8202,3.5 13.3748,3.68467 13.0465,4.01333 L4.53436,12.5358 C3.86414,13.2207 3.86923,14.3191 4.54908,14.9977 L9.0103,19.4522 C9.64819,20.0877 10.6535,20.1309 11.3408,19.5826 C11.5052,20.0689 11.7256,20.5295 11.9943,20.9567 C10.7373,21.7569 9.05064,21.6098 7.95104,20.5143 L3.48934,16.0592 C2.21887,14.7913 2.21724,12.7334 3.48556,11.4632 L11.9852,2.95334 C12.5948,2.34297 13.4221,2 14.2847,2 L19.7501,2 Z M17,5.50218 C17.8284,5.50218 18.5,6.17374 18.5,7.00216 C18.5,7.83057 17.8284,8.50213 17,8.50213 C16.1716,8.50213 15.5001,7.83057 15.5001,7.00216 C15.5001,6.17374 16.1716,5.50218 17,5.50218 Z M23,17.5 C23,14.4624 20.5376,12 17.5,12 C14.4624,12 12,14.4624 12,17.5 C12,20.5376 14.4624,23 17.5,23 C20.5376,23 23,20.5376 23,17.5 Z M16.8755,20.5045 C16.8755,20.1596 17.1551,19.88 17.5,19.88 C17.8449,19.88 18.1245,20.1596 18.1245,20.5045 C18.1245,20.8494 17.8449,21.129 17.5,21.129 C17.1551,21.129 16.8755,20.8494 16.8755,20.5045 Z M15.6467,15.9574 C15.6357,14.8205 16.4521,14.0031 17.5,14.0031 C18.5311,14.0031 19.3534,14.8489 19.3534,15.9526 C19.3534,16.5186 19.1682,16.866 18.6905,17.4003 L18.4247,17.6908 L18.3238,17.8063 C18.0765,18.0981 18,18.2684 18,18.5006 C18,18.7767 17.7762,19.0006 17.5,19.0006 C17.2239,19.0006 17,18.7767 17,18.5006 C17,17.9255 17.1868,17.5749 17.6711,17.0333 L17.9365,16.7432 L18.0355,16.63 C18.2782,16.3437 18.3534,16.1769 18.3534,15.9526 C18.3534,15.395 17.9724,15.0031 17.5,15.0031 C17.0063,15.0031 16.6411,15.3688 16.6465901,15.9478 C16.6493,16.2239 16.4276,16.4499 16.1514,16.4526 C15.8753,16.4552 15.6493,16.2335 15.6467,15.9574 Z" id="🎨-Color">
</path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -1,7 +1,7 @@
<template>
<div class="compact-parse-results">
<p class="parse-element teaser-image" v-if="ingredient.product && ingredient.product.img_small">
<img :src="ingredient.product.img_small" />
<p class="parse-element teaser-image">
<img :src="ingredient.product?.img_small ?? require('@/assets/missing-product.svg')" />
</p>
<p class="ingredient-details">
<span class="parse-element quantity" :class="{ missing: !(ingredient?.quantity)}">{{ ingredient?.quantity || 'qty' }}</span>

View file

@ -135,26 +135,22 @@ button img {
<script>
import alert from '@/alert.js'
import data from '@/data.js'
import { toProductsModel, getCompletedRequests, sourcesToRequests } from './shopping.js'
import { toProductsModel, } from './shopping.js'
import MealSelectionList from './MealSelectionList.vue'
import ShoppingListItem from './ShoppingListItem.vue'
async function saveShoppingList(storeName, currentShoppingList, productGroupsPurchased) {
async function saveShoppingList(productGroupsPurchased) {
const results = productGroupsPurchased.map(item => item.requested.map(r => ({
product_id: r.ingredient.product_id,
product: r.ingredient.product,
quantity: r.ingredient.quantity,
unit: r.ingredient.unit,
list_id: -1,
ingredient_id: r.ingredient.id,
person_id: r.person_id,
list_id: null,
}))).flat();
const requestedSources = productGroupsPurchased.map(item => item.requested).flat();
const completedRequests = getCompletedRequests(currentShoppingList, results);
const servicedRequests = sourcesToRequests(requestedSources);
return await data.purchaseItems(storeName, servicedRequests, results, completedRequests);
return await data.purchaseItems(results);
}
export default {
@ -217,13 +213,19 @@ export default {
this.shoppingList.requests = this.shoppingList.requests.filter(r => r.meal?.id !== meal.id);
},
async markFound() {
await saveShoppingList('', this.shoppingList, this.selected);
await saveShoppingList(this.selected);
this.selected = [];
this.loadData();
},
async markPurchased() {
const shoppingList = await saveShoppingList('', this.shoppingList, this.selected);
const shoppingList = await saveShoppingList(this.selected);
if (!shoppingList || !shoppingList.id) {
alert.show({ type: 'error', message: 'Failed to purchase.' });
return;
}
this.selected = [];
this.$router.push(`/shopping/${shoppingList.id}`);
},

View file

@ -2,10 +2,10 @@
<!-- Show a card of the product with the total, taking up the available space and have an expanding section to view sources -->
<div class="shopping-list-item">
<img :src="productGrouping.product.img_small" class="product-image" />
<img :src="`${ productGrouping.product?.img_small ?? require('@/assets/missing-product.svg') }`" class="product-image" />
<div class="product-details">
<h3 class="header">
<strong><a :href="productGrouping.product.link">{{ productGrouping.product.name }}</a></strong>,
<strong><a :href="productGrouping.product?.link">{{ productGrouping.product.name }}</a></strong>,
<small>
<span v-for="(total, index) in remainingRequired" :key="total.id">
<span v-if="index">, </span>

View file

@ -22,6 +22,7 @@ export function mealToShoppingListSources(meal) {
return sources;
}
var emptyProductId = -1;
export function requestsToSources(requests) {
const sources = [];
for (const request of requests) {
@ -33,6 +34,12 @@ export function requestsToSources(requests) {
}
}
for (const source of sources) {
if (!source.ingredient.product) {
source.ingredient.product = { id: emptyProductId--, name: source.ingredient.name, };
}
}
return sources;
}
@ -134,7 +141,7 @@ export function toProductsModel(currentShoppingList) {
}
export function purchasedToProductModel(shoppingList) {
const purchasedProductIds = new Set(shoppingList.results.map(r => r.product.id));
const purchasedProductIds = new Set(shoppingList.results.map(r => r.product?.id ?? 0));
const purchasedSources = requestsToSources(shoppingList.requests).filter(r => purchasedProductIds.has(r.ingredient.product.id));
const grouped = {};

View file

@ -247,14 +247,14 @@ export default {
return lst;
},
async purchaseItems(storeName, requests, results, completedRequests) {
async purchaseItems(completed_requests) {
const response = await fetch(BASE_URL + "/shopping/", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ requests, results, store_name: storeName, completed_requests: completedRequests }),
body: JSON.stringify({ completed_requests }),
});
const lst = await response.json();