All files / munch-ease-frontend/src/composables useShopping.ts

0% Statements 0/85
0% Branches 0/1
0% Functions 0/1
0% Lines 0/85

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86                                                                                                                                                                           
import * as sdk from '@/api/sdk'
import type { ShoppingListItemWithRefs, Product, Meal } from '@/domain/types'

export type GroupByProduct = { type: 'product'; product: Product; shoppingListItems: ShoppingListItemWithRefs[] }
export type GroupByName = { type: 'name'; name: string; shoppingListItems: ShoppingListItemWithRefs[] }
export type Group = GroupByProduct | GroupByName

export function groupsToItems(groups: Group[]): ShoppingListItemWithRefs[] {
  return groups.map((g) => g.shoppingListItems).flat()
}

export function uniqueMeals(shoppingListItems: ShoppingListItemWithRefs[]): Meal[] {
  const mealsWithDuplicates = shoppingListItems.map((item) => item.meal).filter((m): m is Meal => !!m)
  const mealsLookup: Record<string | number, Meal> = mealsWithDuplicates.reduce<Record<string | number, Meal>>(
    (acc, meal) => {
      acc[meal.id] ??= meal
      return acc
    },
    {}
  )
  return Object.values(mealsLookup)
}

export function itemsToGroups(shoppingListItems: ShoppingListItemWithRefs[]): Group[] {
  const ingredients_by_product_id: Record<string | number, GroupByProduct> = {}
  const ingredients_by_name: Record<string, GroupByName> = {}
  for (const item of shoppingListItems) {
    if (item.ingredient?.product) {
      let group = ingredients_by_product_id[item.ingredient.product.id]
      if (!group) {
        group = ingredients_by_product_id[item.ingredient.product.id] = {
          type: 'product',
          product: item.ingredient.product,
          shoppingListItems: [],
        }
      }
      group.shoppingListItems.push(item)
    } else {
      const name = item.ingredient?.name ?? ''
      let group = ingredients_by_name[name]
      if (!group) {
        group = ingredients_by_name[name] = {
          type: 'name',
          name,
          shoppingListItems: [],
        }
      }
      group.shoppingListItems.push(item)
    }
  }
  return [...Object.values(ingredients_by_product_id), ...Object.values(ingredients_by_name)]
}

export function useShopping() {
  const groupsFrom = (items?: ShoppingListItemWithRefs[]): Group[] => itemsToGroups(items ?? [])
  const mealsFrom = (items?: ShoppingListItemWithRefs[]): Meal[] => uniqueMeals(items ?? [])
  return {
    getCurrentShoppingList: sdk.getCurrentShoppingList,
    getShoppingList: sdk.getShoppingList,
    purchaseShoppingList: sdk.purchaseShoppingList,
    requestMeal: sdk.requestMeal,
    unrequestMeal: sdk.unrequestMeal,
    getMyShoppingList: sdk.getMyShoppingList,
    saveMyShoppingList: sdk.saveMyShoppingList,
    // View-model helpers
    groupsFrom,
    mealsFrom,
    async purchaseFromGroups(groups: Group[]) {
      const items = groupsToItems(groups).map((i): sdk.PurchaseRequest => {
        if (typeof i.id === 'number' && i.id >= 0) {
          return { type: 'existing', id: i.id, personId: i.personId, ingredientId: i.ingredient?.id ?? null }
        }
        return {
          type: 'refs',
          personId: i.personId,
          ingredientId: i.ingredient?.id ?? null,
          recipeId: i.recipe?.id ?? null,
          mealId: i.meal?.id ?? null,
        }
      })
      if (!items?.length) return null
      return sdk.purchaseShoppingList(items)
    },
  }
}