Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/Http/Controllers/BringExportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ public function __invoke(Request $request, Country $country): View
$recipeIds = $this->parseRecipeIds($request->string('recipes')->toString());
$servingsMap = $this->parseServings($request->string('servings')->toString());

$recipes = Recipe::query()
->whereIn('id', $recipeIds)
$recipes = Recipe::whereIn('id', $recipeIds)
->where('country_id', $country->id)
->with('ingredients')
->get();
Expand Down Expand Up @@ -127,6 +126,7 @@ protected function aggregateIngredients(Collection $recipes, array $servingsMap)
foreach ($byUnit as $unit => $total) {
$parts[] = number_format($total, $total == (int) $total ? 0 : 1) . ' ' . $unit;
}

$amountStr = implode(', ', $parts);
}

Expand Down Expand Up @@ -156,11 +156,11 @@ protected function getYieldsDataForServings(Recipe $recipe, int $servings): arra
$result = [];
/** @var list<array<string, mixed>> $ingredients */
$ingredients = $yield['ingredients'] ?? [];
foreach ($ingredients as $ing) {
$name = (string) ($ing['name'] ?? '');
foreach ($ingredients as $ingredient) {
$name = (string) ($ingredient['name'] ?? '');
$result[$name] = [
'amount' => isset($ing['amount']) ? (float) $ing['amount'] : null,
'unit' => (string) ($ing['unit'] ?? ''),
'amount' => isset($ingredient['amount']) ? (float) $ingredient['amount'] : null,
'unit' => (string) ($ingredient['unit'] ?? ''),
];
}

Expand Down
52 changes: 52 additions & 0 deletions app/Livewire/ShoppingList/MiniCart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace App\Livewire\ShoppingList;

use App\Models\Recipe;
use App\Support\Facades\Flux;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Livewire\Attributes\Computed;
use Livewire\Attributes\On;
use Livewire\Component;

class MiniCart extends Component
{
public string $shoppingListUrl = '';

/** @var list<int> */
public array $recipeIds = [];

public function mount(): void
{
$this->shoppingListUrl = localized_route('localized.shopping-list.index');
}

/** @param list<int|string> $ids */
#[On('mini-cart-open')]
public function open(array $ids): void
{
$this->recipeIds = array_map(intval(...), $ids);
Flux::showModal('mini-cart-modal');
}

/** @return Collection<int, Recipe> */
#[Computed]
public function recipes(): Collection
{
if ($this->recipeIds === []) {
return collect();
}

return Recipe::whereIn('id', $this->recipeIds)
->get(['id', 'name'])
->keyBy('id');
}

public function render(): View
{
return view('livewire.shopping-list.mini-cart');
}
}
1 change: 1 addition & 0 deletions lang/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Fjern fra indkøbsliste",
"View on HelloFresh": "Se på HelloFresh",
"View PDF": "Se PDF",
"View Shopping List": "Se indkøbsliste",
"Confirm Action": "Bekræft handling",
"Are you sure?": "Er du sikker?",
"Confirm": "Bekræft",
Expand Down
2 changes: 2 additions & 0 deletions lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@
"No saved shopping lists": "Keine gespeicherten Einkaufslisten",
"Save your shopping lists from the shopping list page to access them later.": "Speichere deine Einkaufslisten von der Einkaufslisten-Seite, um später darauf zuzugreifen.",
"Go to Shopping List": "Zur Einkaufsliste",
"View Shopping List": "Einkaufsliste ansehen",
"recipes in shopping list": "Rezepte in der Einkaufsliste",
"Saved :date": "Gespeichert :date",
"Made with": "Erstellt mit",
"by": "von",
Expand Down
2 changes: 2 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@
"No saved shopping lists": "No saved shopping lists",
"Save your shopping lists from the shopping list page to access them later.": "Save your shopping lists from the shopping list page to access them later.",
"Go to Shopping List": "Go to Shopping List",
"View Shopping List": "View Shopping List",
"recipes in shopping list": "recipes in shopping list",
"Saved :date": "Saved :date",
"Made with": "Made with",
"by": "by",
Expand Down
1 change: 1 addition & 0 deletions lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Eliminar de la lista de compras",
"View on HelloFresh": "Ver en HelloFresh",
"View PDF": "Ver PDF",
"View Shopping List": "Ver lista de compras",
"Confirm Action": "Confirmar acción",
"Are you sure?": "¿Estás seguro?",
"Confirm": "Confirmar",
Expand Down
1 change: 1 addition & 0 deletions lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Retirer de la liste de courses",
"View on HelloFresh": "Voir sur HelloFresh",
"View PDF": "Voir le PDF",
"View Shopping List": "Voir la liste de courses",
"Confirm Action": "Confirmer l'action",
"Are you sure?": "Êtes-vous sûr ?",
"Confirm": "Confirmer",
Expand Down
1 change: 1 addition & 0 deletions lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Rimuovi dalla lista della spesa",
"View on HelloFresh": "Visualizza su HelloFresh",
"View PDF": "Visualizza PDF",
"View Shopping List": "Visualizza lista della spesa",
"Confirm Action": "Conferma azione",
"Are you sure?": "Sei sicuro?",
"Confirm": "Conferma",
Expand Down
1 change: 1 addition & 0 deletions lang/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Fjern fra handleliste",
"View on HelloFresh": "Se på HelloFresh",
"View PDF": "Se PDF",
"View Shopping List": "Se handleliste",
"Confirm Action": "Bekreft handling",
"Are you sure?": "Er du sikker?",
"Confirm": "Bekreft",
Expand Down
1 change: 1 addition & 0 deletions lang/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Verwijderen van boodschappenlijst",
"View on HelloFresh": "Bekijken op HelloFresh",
"View PDF": "PDF bekijken",
"View Shopping List": "Boodschappenlijst bekijken",
"Confirm Action": "Actie bevestigen",
"Are you sure?": "Weet je het zeker?",
"Confirm": "Bevestigen",
Expand Down
1 change: 1 addition & 0 deletions lang/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"Remove from shopping list": "Ta bort från inköpslista",
"View on HelloFresh": "Visa på HelloFresh",
"View PDF": "Visa PDF",
"View Shopping List": "Visa inköpslista",
"Confirm Action": "Bekräfta åtgärd",
"Are you sure?": "Är du säker?",
"Confirm": "Bekräfta",
Expand Down
28 changes: 27 additions & 1 deletion resources/views/components/layouts/localized.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'ogDescription' => null,
'ogImage' => null,
])
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}-{{ resolve('current.country')->code }}">
<head>
<meta charset="utf-8">
Expand Down Expand Up @@ -45,6 +45,32 @@
<flux:toast />
</flux:toast.group>
@endpersist
{{-- Mini Shopping List Floating Button (hidden on shopping list page) --}}
@unless(request()->routeIs('localized.shopping-list.*'))
<div
x-data="{ footerVisible: false }"
x-init="
const footer = document.getElementById('site-footer');
if (footer) {
new IntersectionObserver(([e]) => footerVisible = e.isIntersecting, { threshold: 0 }).observe(footer);
}
"
x-show="$store.shoppingList && $store.shoppingList.count > 0"
x-cloak
class="fixed right-4 sm:right-6 bottom-4 sm:bottom-6 z-50 sm:transition-transform sm:duration-300 sm:ease-out"
:class="footerVisible ? 'sm:-translate-y-6' : 'sm:translate-y-0'"
>
<button
type="button"
x-on:click="Livewire.dispatch('mini-cart-open', { ids: $store.shoppingList.items })"
class="flex items-center gap-ui rounded-full bg-green-500 px-4 py-3 text-white shadow-lg hover:bg-green-600 transition-colors"
>
<flux:icon.shopping-basket variant="mini" />
<span x-text="$store.shoppingList.count"></span>
</button>
</div>
<livewire:shopping-list.mini-cart />
@endunless
@vite(['resources/js/app.js'])
@livewireScripts
@fluxScripts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<flux:footer class="bg-zinc-50 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-700 print:hidden !py-4 text-sm">
<flux:footer id="site-footer" class="bg-zinc-50 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-700 print:hidden !py-4 text-sm">
<div class="flex flex-col sm:flex-row items-center justify-between gap-ui">
<div class="flex items-center gap-ui">
<flux:link href="https://github.com/Muetze42/hellofresh-database" target="_blank" class="inline-flex items-center gap-1 hover:text-zinc-700 dark:hover:text-zinc-200">
Expand Down
41 changes: 41 additions & 0 deletions resources/views/livewire/shopping-list/mini-cart.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<div>
<flux:modal name="mini-cart-modal" class="md:w-xl">
<div class="space-y-section">
<flux:heading size="lg">{{ __('Shopping List') }}</flux:heading>

@if($this->recipes->isNotEmpty())
<div class="max-h-80 overflow-y-auto -mx-2">
<ul class="divide-y divide-zinc-100 dark:divide-zinc-700">
@foreach($this->recipes as $recipe)
<li wire:key="mini-cart-{{ $recipe->id }}" class="flex items-center justify-between gap-2 px-2 py-2 hover:bg-zinc-50 dark:hover:bg-zinc-700/50 rounded">
<span class="truncate text-sm">{{ $recipe->name }}</span>
<button
type="button"
x-on:click="$store.shoppingList?.remove({{ $recipe->id }}); $wire.open($store.shoppingList?.items ?? [])"
class="shrink-0 rounded p-1 text-zinc-400 hover:bg-red-100 hover:text-red-600 dark:hover:bg-red-900/30 dark:hover:text-red-400"
title="{{ __('Remove') }}"
>
<flux:icon.x variant="micro" />
</button>
</li>
@endforeach
</ul>
</div>
@else
<flux:text class="text-zinc-500">
{{ __('Your shopping list is empty') }}
</flux:text>
@endif

<flux:button
variant="primary"
class="w-full"
icon="clipboard-list"
:href="$shoppingListUrl"
wire:navigate
>
{{ __('View Shopping List') }}
</flux:button>
</div>
</flux:modal>
</div>
Loading