Ver código fonte

add the new route addproduct, dont fineshed

gdias 4 meses atrás
pai
commit
29f82fe11d

+ 297 - 0
src/lib/component/AddProducts.svelte

@@ -0,0 +1,297 @@
+<script>
+	import { onMount } from 'svelte';
+	import { goto } from '$app/navigation';
+	import { page } from '$app/stores';
+
+	let selectedCategory = null;
+	let isPaymentModalOpen = false;
+	let selectedPaymentMethod = null;
+
+	let tableIdNum = 0;
+	let currentTable = undefined;
+	let currentOrder = undefined;
+	let products = [];
+	let categories = [];
+
+	$: tableIdNum = parseInt($page.params.tableId || '0');
+
+	async function fetchTableAndOrder() {
+		try {
+			const resTable = await fetch(`/api/table/${tableIdNum}`);
+			currentTable = await resTable.json();
+
+			if (currentTable?.orderId) {
+				const resOrder = await fetch(`/api/order/${currentTable.orderId}`);
+				currentOrder = await resOrder.json();
+			} else {
+				currentOrder = undefined;
+			}
+		} catch (error) {
+			console.error('Erro ao buscar dados da mesa:', error);
+		}
+	}
+
+	async function fetchProductsAndCategories() {
+		try {
+			const res = await fetch('/api/products');
+			const data = await res.json();
+			products = data.products;
+			categories = data.categories;
+		} catch (error) {
+			console.error('Erro ao buscar produtos:', error);
+		}
+	}
+
+	onMount(async () => {
+		await fetchTableAndOrder();
+		await fetchProductsAndCategories();
+	});
+
+	$: if (categories.length > 0 && !selectedCategory) {
+		selectedCategory = categories[0].name;
+	}
+
+	$: if (currentTable && currentTable.status === 'FREE') {
+		console.warn('Mesa n\u00e3o est\u00e1 ocupada ou foi liberada.');
+		goto('/tables');
+	}
+
+	$: filteredProducts = selectedCategory
+		? products.filter((p) => p.category.name === selectedCategory)
+		: products;
+
+	async function handleAddItem(product) {
+		const payload = { productId: product.id, quantity: 1 };
+		await fetch(`/api/order/${currentTable.orderId}/add-item`, {
+			method: 'POST',
+			headers: { 'Content-Type': 'application/json' },
+			body: JSON.stringify(payload)
+		});
+		await fetchTableAndOrder();
+	}
+
+	async function updateItemQuantity(tableId, itemId, newQuantity) {
+		await fetch(`/api/order/${currentTable.orderId}/update-item`, {
+			method: 'PUT',
+			headers: { 'Content-Type': 'application/json' },
+			body: JSON.stringify({ itemId, quantity: newQuantity })
+		});
+		await fetchTableAndOrder();
+	}
+
+	async function removeItemFromOrder(tableId, itemId) {
+		await fetch(`/api/order/${currentTable.orderId}/remove-item`, {
+			method: 'DELETE',
+			headers: { 'Content-Type': 'application/json' },
+			body: JSON.stringify({ itemId })
+		});
+		await fetchTableAndOrder();
+	}
+
+	async function handlePaymentConfirm() {
+		if (!selectedPaymentMethod) {
+			console.warn('Selecione uma forma de pagamento');
+			return;
+		}
+		await fetch(`/api/order/${currentTable.orderId}/close`, {
+			method: 'POST',
+			headers: { 'Content-Type': 'application/json' },
+			body: JSON.stringify({ paymentMethod: selectedPaymentMethod })
+		});
+		isPaymentModalOpen = false;
+		goto('/tables');
+	}
+</script>
+
+<!-- restante do componente permanece o mesmo -->
+
+{#if !currentTable || (currentTable.status !== 'FREE' && !currentOrder)}
+	<div class="py-10 text-center">Carregando...</div>
+{:else}
+	<div class="container mx-auto">
+		<div class="mb-6 flex items-center">
+			<button
+				on:click={() => goto('/tables')}
+				class="mr-4 rounded-lg bg-gray-800 p-2 hover:bg-gray-700"
+			>
+				<!-- <img src="/icons/arrow-left.svg" alt="Voltar" class="w-5 h-5" /> -->
+			</button>
+			<h1 class="text-2xl font-bold">Mesa {tableIdNum}</h1>
+		</div>
+
+		<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
+			<div class="overflow-hidden rounded-lg bg-gray-800 shadow-lg lg:col-span-2">
+				<div class="bg-gray-700 p-4">
+					<h2 class="text-lg font-semibold">Adicionar Produtos</h2>
+				</div>
+
+				<div class="bg-gray-750 flex overflow-x-auto border-b border-gray-700 p-2">
+					{#each categories as category}
+						<button
+							class="mx-1 whitespace-nowrap rounded-md px-4 py-2 text-sm font-medium {selectedCategory ===
+							category.name
+								? 'bg-indigo-600 text-white'
+								: 'bg-gray-700 text-gray-300 hover:bg-gray-600'}"
+							on:click={() => (selectedCategory = category.name)}
+						>
+							{category.name}
+						</button>
+					{/each}
+				</div>
+
+				<div
+					class="grid max-h-[calc(100vh-400px)] grid-cols-2 gap-4 overflow-y-auto p-4 sm:grid-cols-3 md:grid-cols-4"
+				>
+					{#each filteredProducts as product}
+						<button
+							class="hover:bg-gray-650 rounded-lg bg-gray-700 p-4 text-left"
+							on:click={() => handleAddItem(product)}
+						>
+							<div class="flex h-full flex-col">
+								<h3 class="mb-2 line-clamp-2 font-medium">{product.name}</h3>
+								<div class="mt-auto flex items-center justify-between">
+									<span class="font-semibold text-emerald-400">R$ {product.price.toFixed(2)}</span>
+									<!-- <img src="/icons/plus.svg" alt="Adicionar" class="w-5 h-5 text-emerald-400" /> -->
+								</div>
+								{#if product.sendToKitchen}
+									<span class="mt-2 rounded-full bg-yellow-800 px-2 py-0.5 text-xs text-yellow-300"
+										>Cozinha</span
+									>
+								{/if}
+							</div>
+						</button>
+					{/each}
+				</div>
+			</div>
+
+			<div
+				class="flex h-full flex-col overflow-hidden rounded-lg bg-gray-800 shadow-lg md:h-[calc(100vh-200px)]"
+			>
+				<div class="bg-gray-700 p-4">
+					<h2 class="text-lg font-semibold">Comanda</h2>
+				</div>
+
+				<div class="flex-1 overflow-y-auto p-4">
+					{#if currentOrder?.items.length === 0}
+						<div class="py-6 text-center text-gray-400">
+							<!-- <img src="/icons/shopping-cart.svg" class="w-10 h-10 mx-auto mb-2 opacity-50" alt="Nenhum item" /> -->
+							<p>Nenhum item adicionado</p>
+						</div>
+					{:else}
+						{#each currentOrder.items as item, index}
+							<div class="bg-gray-750 flex items-center justify-between rounded-lg p-3">
+								<div class="flex-1">
+									<h3 class="font-medium">{item.product.name}</h3>
+									<p class="text-sm text-gray-400">
+										R$ {(item.priceAtOrder ?? 0).toFixed(2)} x {item.quantity}
+									</p>
+								</div>
+								<div class="flex items-center space-x-2">
+									<button
+										on:click={() => updateItemQuantity(tableIdNum, item.id, item.quantity - 1)}
+										class="rounded bg-gray-700 p-1 hover:bg-gray-600"
+									>
+										<!-- <img src="/icons/minus.svg" class="w-4 h-4" alt="Diminuir" /> -->
+									</button>
+									<span class="w-8 text-center">{item.quantity}</span>
+									<button
+										on:click={() => updateItemQuantity(tableIdNum, item.id, item.quantity + 1)}
+										class="rounded bg-gray-700 p-1 hover:bg-gray-600"
+									>
+										<!-- <img src="/icons/plus.svg" class="w-4 h-4" alt="Aumentar" /> -->
+									</button>
+									<button
+										on:click={() => removeItemFromOrder(tableIdNum, item.id)}
+										class="ml-2 rounded bg-red-700 p-1 hover:bg-red-600"
+									>
+										<!-- <img src="/icons/trash.svg" class="w-4 h-4" alt="Remover" /> -->
+									</button>
+								</div>
+							</div>
+						{/each}
+					{/if}
+				</div>
+
+				<div class="bg-gray-750 border-t border-gray-700 p-4">
+					<div class="mb-2 flex justify-between">
+						<span class="font-medium">Subtotal:</span>
+						<span>R$ {currentOrder?.totalAmount.toFixed(2)}</span>
+					</div>
+
+					<button
+						on:click={() => (isPaymentModalOpen = true)}
+						disabled={currentOrder?.items.length === 0}
+						class="flex w-full items-center justify-center rounded-lg bg-emerald-600 py-3 font-medium hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50"
+					>
+						<!-- <img src="/icons/credit-card.svg" class="w-5 h-5 mr-2" alt="Pagamento" /> -->
+						Fechar Atendimento
+					</button>
+				</div>
+			</div>
+		</div>
+
+		{#if isPaymentModalOpen}
+			<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/70 p-4">
+				<div class="w-full max-w-lg rounded-lg bg-gray-800 p-6 shadow-xl">
+					<h2 class="mb-4 text-xl font-bold">Finalizar Pedido</h2>
+
+					<div class="mb-6">
+						<h3 class="mb-3 text-lg font-medium">Resumo do Pedido</h3>
+						<div class="mb-4 max-h-60 overflow-y-auto sm:max-h-80">
+							{#each currentOrder.items as item, index}
+								<div class="flex justify-between border-b border-gray-700 py-2">
+									<span>{item.quantity}x {item.product.name}</span>
+									<span>R$ {((item.priceAtOrder ?? 0) * item.quantity).toFixed(2)}</span>
+								</div>
+							{/each}
+						</div>
+						<div class="flex justify-between text-lg font-semibold">
+							<span>Total:</span>
+							<span>R$ {currentOrder.totalAmount.toFixed(2)}</span>
+						</div>
+					</div>
+
+					<h3 class="mb-3 text-lg font-medium">Forma de Pagamento</h3>
+					<div class="mb-6 grid grid-cols-1 gap-3 sm:grid-cols-2">
+						{#each ['CASH', 'PIX', 'DEBIT', 'CREDIT'] as method}
+							<button
+								class="flex flex-col items-center justify-center rounded-lg border-2 p-4 transition-colors {selectedPaymentMethod ===
+								method
+									? 'border-emerald-500 bg-emerald-900/20'
+									: 'border-gray-700 hover:border-gray-600'}"
+								on:click={() => (selectedPaymentMethod = method)}
+							>
+								<!-- <img src="/icons/{method.toLowerCase()}.svg" class="w-8 h-8 mb-2" alt={method} /> -->
+								<span
+									>{method === 'CASH'
+										? 'Dinheiro'
+										: method === 'PIX'
+											? 'Pix'
+											: method === 'DEBIT'
+												? 'Cart\u00e3o de D\u00e9bito'
+												: 'Cart\u00e3o de Cr\u00e9dito'}</span
+								>
+							</button>
+						{/each}
+					</div>
+
+					<div class="flex space-x-3">
+						<button
+							on:click={() => (isPaymentModalOpen = false)}
+							class="flex-1 rounded-lg bg-gray-700 py-3 font-medium hover:bg-gray-600"
+						>
+							Cancelar
+						</button>
+						<button
+							on:click={handlePaymentConfirm}
+							disabled={!selectedPaymentMethod}
+							class="flex-1 rounded-lg bg-emerald-600 py-3 font-medium hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50"
+						>
+							Confirmar Pagamento
+						</button>
+					</div>
+				</div>
+			</div>
+		{/if}
+	</div>
+{/if}

+ 2 - 1
src/lib/component/Commands.svelte

@@ -129,9 +129,10 @@
 					<div class="mb-2 text-sm text-gray-400">
 						{getElapsedTime(order.createdAt)}
 					</div>
+					<!--adicionar aqui link para o addproduct preciso salvar uma variavel com o order_id e etc para aparecer apenas o item da comanda em especifico-->
 					<button
 						class="mb-2 w-full rounded bg-emerald-600 py-2 hover:bg-emerald-700"
-						on:click={() => openOrder(order.id)}
+						on:click={() => goto('/dashboard/addproducts')}
 					>
 						Adicionar items
 					</button>