This commit is contained in:
DandhiAri 2025-08-07 12:27:23 +07:00
parent 9da05619c9
commit d9440ad7bb
61 changed files with 413078 additions and 1064 deletions

54
alur.txt Normal file
View File

@ -0,0 +1,54 @@
Alur Penggunaan Website
Melihat Menu dan Memesan Makanan:
Pengguna akan melihat daftar makanan dan minuman yang tersedia saat pertama kali mengakses website.
Mereka dapat memfilter menu berdasarkan kategori (misalnya, makanan, minuman).
Pengguna menambahkan item yang diinginkan ke keranjang belanja mereka. Jumlah item di keranjang akan diperbarui secara real-time.
Review Keranjang (Tahap 1 - Sederhana):
Pengguna dapat membuka tampilan keranjang (biasanya sidebar atau modal).
Di sini, mereka akan melihat ringkasan pesanan mereka: daftar item yang dipilih beserta kuantitas, harga per item, dan total harga keseluruhan.
Hanya ada satu tombol untuk melanjutkan: "Lanjut Pembayaran".
Detail Checkout (Tahap 2 - Modal Baru):
Setelah mengklik "Lanjut Pembayaran", sebuah modal atau sidebar baru akan muncul.
Pemilihan Meja:
Pengguna memilih apakah mereka "Pelanggan Baru" (memilih meja yang tersedia) atau "Sudah Ada Meja" (memilih meja yang sudah terisi).
Mereka memasukkan "Nama Pemesan". Daftar meja yang tersedia atau terisi akan ditampilkan secara real-time dari Firebase Realtime Database.
Pemilihan Metode Pembayaran:
Pengguna memilih metode pembayaran menggunakan radio button yang dikelompokkan:
Pembayaran Otomatis: Midtrans (disertai logo Midtrans)
Pembayaran Manual: Tunai (disertai logo tunai) atau QRIS (disertai logo QRIS)
Input Email (Opsional): Pengguna dapat memasukkan alamat email mereka (defaultnya guest@gmail.com) untuk menerima struk pembelian.
Konfirmasi Akhir: Satu tombol "Bayar" (atau "Konfirmasi Pesanan") akan memicu proses pembayaran.
Proses Pembayaran:
Pencatatan Pesanan Terpusat (Awal): Terlepas dari metode pembayarannya, pesanan akan dicatat ke dalam satu tabel pesanan utama di database Anda (misalnya, tabel orders) dengan status awal (misalnya, 'pending' atau 'menunggu_konfirmasi'). Detail item pesanan akan disimpan di tabel terkait (misalnya, order_items). Tabel ini berfungsi sebagai bukti pembelian universal.
Alur Midtrans:
Sistem memanggil API Midtrans untuk mendapatkan token Snap.
Pengguna diarahkan ke halaman pembayaran Midtrans.
Setelah pembayaran berhasil di Midtrans:
Midtrans akan mengirimkan notifikasi (melalui callback URL atau Webhook) ke endpoint server Anda.
Endpoint ini akan memproses notifikasi tersebut dan mengubah status pesanan di tabel orders menjadi 'dibayar' atau 'terkonfirmasi'.
Pengguna akan melihat konfirmasi pembayaran berhasil (misalnya, melalui modal atau halaman sederhana di browser mereka).
Pesanan ini segera ditampilkan secara real-time di halaman daftar order dapur.
Alur Pembayaran Manual (Tunai/QRIS):
Status pesanan di tabel orders akan tetap pada status awal (misalnya, 'menunggu_konfirmasi_manual').
Pengguna akan menerima instruksi untuk melakukan pembayaran di kasir secara manual.
Konfirmasi oleh Staf: Di sisi staff/kasir, ada antarmuka terpisah di mana staf akan memverifikasi pembayaran manual dan secara manual mengubah status pesanan menjadi 'terkonfirmasi' di sistem.
Setelah dikonfirmasi oleh staf:
Status pesanan di tabel orders diperbarui menjadi 'terkonfirmasi'.
Pesanan ini kemudian ditampilkan secara real-time di halaman daftar order dapur.
Pembaruan Status Meja Real-time:
Setelah pesanan terkonfirmasi (baik oleh Midtrans atau oleh staf untuk pembayaran manual), status meja di Firebase akan diperbarui secara real-time. Meja akan ditandai sebagai aktif/terisi, dan nama pemesan akan dicatat sebagai reserved_by.
Sistem juga akan menyinkronkan data meja terbaru dari Firebase untuk semua pengguna.
Konfirmasi dan Email Struk:
Pengguna akan menerima notifikasi di layar bahwa pesanan berhasil dikirim/dibayar.
Jika email dimasukkan, struk pembelian lengkap yang berisi detail makanan, total harga, dan detail meja akan dikirimkan ke email tersebut. Data struk ini akan diambil dari tabel pesanan terpusat.
Reset Keranjang dan Status:
Keranjang belanja akan dikosongkan, dan status formulir akan diatur ulang untuk pesanan berikutnya.

View File

@ -0,0 +1,10 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class KitchenController extends Controller
{
}

View File

@ -0,0 +1,208 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Midtrans\Notification;
use Illuminate\Support\Facades\DB;
use App\Models\Order;
use App\Models\OrderItem;
use Kreait\Firebase\Factory;
use Illuminate\Support\Facades\Log;
use Midtrans\Config;
// use Midtrans\Notification;
class OrderController extends Controller
{
public function createSnapToken(Request $request)
{
Config::$serverKey = config('services.midtrans.server_key');
Config::$isProduction = config('services.midtrans.is_production', false);
Config::$isSanitized = true;
Config::$is3ds = true;
// Simpan data order ke session
Session::put('order_data', [
'customer_name' => $request->name,
'customer_email' => $request->email,
'table_id' => $request->table_id,
'table_device_id' => $request->table_device_id,
'total_amount' => $request->amount,
'payment_method' => 'midtrans',
'cart_items' => $request->cart_items, // array dari frontend
]);
// Tambahkan item_details untuk Snap
$items = [];
foreach ($request->cart_items as $item) {
$items[] = [
'id' => $item['id'],
'price' => $item['price'],
'quantity' => $item['qty'],
'name' => $item['name'],
];
}
$params = [
'transaction_details' => [
'order_id' => 'ORDER-' . time(),
'gross_amount' => $request->amount,
],
'item_details' => $items,
'customer_details' => [
'first_name' => $request->name,
'email' => $request->email,
],
];
$snapToken = Snap::getSnapToken($params);
return response()->json(['token' => $snapToken]);
}
public function handleNotification(Request $request)
{
// Konfigurasi Midtrans
Config::$serverKey = config('services.midtrans.server_key');
Config::$isProduction = config('services.midtrans.is_production', false);
Config::$isSanitized = true;
Config::$is3ds = true;
// Ambil isi notifikasi mentah
$rawNotification = $request->getContent();
Log::info('RAW MIDTRANS NOTIFICATION:', ['body' => $rawNotification]);
$notification = json_decode($rawNotification);
if (!$notification || !isset($notification->order_id)) {
Log::error('Invalid Midtrans notification payload.', ['raw' => $rawNotification]);
return response()->json(['message' => 'Invalid payload'], 400);
}
try {
$midtransNotif = new Notification();
$orderId = $midtransNotif->order_id;
$transactionStatus = $midtransNotif->transaction_status;
$order = Order::where('midtrans_transaction_id', $orderId)->first();
Log::info('Order ditemukan:', ['order' => $order]);
// if (!$order) {
// Log::warning('Order not found: ' . $orderId);
// return response()->json(['message' => 'Order not found'], 404);
// }
// Ubah status jadi hanya 2 kondisi: confirmed / canceled
if (in_array($transactionStatus, ['capture', 'settlement'])) {
$order->transaction_status = 'confirmed';
} else {
$order->transaction_status = 'canceled';
}
$order->save();
Log::info('Order updated:', [
'order_id' => $orderId,
'transaction_status' => $order->transaction_status,
]);
return response()->json(['message' => 'Notification handled'], 200);
} catch (\Exception $e) {
Log::error('Midtrans Notification Error', ['error' => $e->getMessage()]);
return response()->json(['message' => 'Notification failed'], 500);
}
}
public function saveOrder(Request $request)
{
$snapResult = $request->input('snap_result');
$orderData = Session::get('order_data');
if (!$orderData) {
return response()->json([
'success' => false,
'message' => 'Data order tidak ditemukan di session.',
]);
}
try {
\DB::beginTransaction();
$order = Order::create([
'customer_name' => $orderData['customer_name'],
'customer_email' => $orderData['customer_email'],
'table_id' => $orderData['table_id'],
'midtrans_transaction_id' => $snapResult['order_id'] ?? null,
'total_amount' => $orderData['total_amount'],
'payment_method' => $orderData['payment_method'],
'transaction_status' => 'confirmed',
]);
foreach ($orderData['cart_items'] as $item) {
\App\Models\OrderItem::create([
'order_id' => $order->id,
'item_id' => $item['id'],
'item_name' => $item['name'],
'item_price' => $item['price'],
'quantity' => $item['qty'],
'total_price' => $item['total_price'],
]);
}
// Firebase update
$firebase = (new \Kreait\Firebase\Factory)
->withServiceAccount(storage_path('app/firebase/.firebase_credentials.json'))
->createDatabase();
$firebase->getReference($orderData['table_id'])->update([
'sensors/table_activation_sensor_active' => 1,
'reserved_by' => $orderData['customer_name'],
]);
\DB::commit();
Session::forget('order_data');
return response()->json([
'success' => true,
'message' => 'Pesanan berhasil disimpan dan meja terupdate!',
]);
} catch (\Exception $e) {
\DB::rollBack();
\Log::error('Gagal menyimpan pesanan: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'Gagal menyimpan pesanan: ' . $e->getMessage(),
]);
}
}
public function confirmOrder(Request $request)
{
$request->validate([
'order_id' => 'required|string',
]);
$order = Order::where('id', $request->order_id)->first();
Log::info('Order ditemukan:', ['order' => $order]);
// if (!$order) {
// return response()->json(['message' => 'Order not found'], 404);
// }
$order->transaction_status = 'confirmed';
$order->save();
return response()->json(['message' => 'Order status updated to confirmed'], 200);
}
public function index()
{
$order = Order::all();
return view('pages.back.orders.index', compact('order'));
}
}

View File

@ -0,0 +1,219 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Midtrans\Config;
use Midtrans\Snap;
use App\Models\Order;
use App\Models\OrderItem;
use Kreait\Firebase\Factory;
use Illuminate\Support\Facades\Log;
class PaymentController extends Controller
{
public function __construct()
{
// Konfigurasi Midtrans
Config::$serverKey = config('services.midtrans.server_key');
Config::$isProduction = config('services.midtrans.is_production');
Config::$isSanitized = true;
Config::$is3ds = true;
}
public function show($midtrans_transaction_id)
{
try {
// Ambil order_id berdasarkan transaction_id
$order = Order::where('midtrans_transaction_id', $midtrans_transaction_id)->firstOrFail();
// Detail customer
$customerDetails = [
'first_name' => substr($order->customer_name ?? 'Customer', 0, 50),
'email' => $order->customer_email ?? 'guest@gmail.com',
'phone' => '08123456789',
];
// Ambil item pesanan
$orderItems = OrderItem::where('order_id', $order->id)->get();
$itemDetails = $orderItems->map(function ($item) {
return [
'id' => $item->id,
'price' => intval($item->item_price),
'quantity' => intval($item->quantity),
'name' => substr($item->item_name, 0, 50),
];
})->toArray();
// Hitung total manual
$total = array_reduce($itemDetails, function ($carry, $item) {
return $carry + ($item['price'] * $item['quantity']);
}, 0);
$params = [
'transaction_details' => [
'order_id' => (string) $midtrans_transaction_id,
'gross_amount' => $total,
],
'customer_details' => $customerDetails,
'item_details' => $itemDetails,
'enabled_payments' => ['credit_card', 'bca_va', 'bni_va', 'bri_va'],
];
// Dapatkan Snap Token
$snapToken = Snap::getSnapToken($params);
return view('payment.show', [
'snapToken' => $snapToken,
'transactionId' => $midtrans_transaction_id,
'orderId' => $order->id,
'order' => $order
]);
} catch (\Exception $e) {
\Log::error('Error generating payment token: ' . $e->getMessage());
return redirect()->back()->withErrors('Terjadi kesalahan saat memproses pembayaran.');
}
}
public function handleCallback(Request $request)
{
try {
// Ambil data dari request
$transactionId = $request->input('order_id');
$transactionStatus = $request->input('transaction_status');
$fraudStatus = $request->input('fraud_status');
\Log::info('Midtrans callback received:', $request->all());
// Cari order berdasarkan transaction_id
$order = Order::where('midtrans_transaction_id', $transactionId)->first();
if (!$order) {
\Log::error('Order tidak ditemukan untuk transaction_id: ' . $transactionId);
return response('Order not found', 404);
}
// Tentukan status berdasarkan response Midtrans
if ($transactionStatus == 'capture') {
if ($fraudStatus == 'challenge') {
$status = 'pending';
} else if ($fraudStatus == 'accept') {
$status = 'confirmed';
}
} else if ($transactionStatus == 'settlement') {
$status = 'confirmed';
} else if ($transactionStatus == 'pending') {
$status = 'pending';
} else if (in_array($transactionStatus, ['deny', 'expire', 'cancel'])) {
$status = 'cancelled';
} else {
$status = 'pending';
}
// Update status order
$order->update([
'transaction_status' => $status,
'payment_type' => $request->input('payment_type'),
'transaction_time' => $request->input('transaction_time'),
]);
\Log::info("Order {$order->id} status updated to: {$status}");
return response('OK', 200);
} catch (\Exception $e) {
\Log::error('Error handling Midtrans callback: ' . $e->getMessage());
return response('Error', 500);
}
}
public function updateStatus(Request $request)
{
try {
// Validasi atau debugging awal
\Log::info('Update status masuk:', $request->all());
$orderId = $request->input('order_id');
$transactionStatus = $request->input('transaction_status');
$transactionId = $request->input('transaction_id');
// Contoh update tabel order
$order = Order::where('id', $orderId)->first();
if (!$order) {
return response()->json(['message' => 'Order not found'], 404);
}
$order->transaction_status = $transactionStatus;
$order->transaction_id = $transactionId;
$order->save();
return response()->json(['message' => 'Status updated']);
} catch (\Exception $e) {
\Log::error('Update gagal:', ['error' => $e->getMessage()]);
return response()->json(['error' => 'Gagal update status'], 500);
}
}
public function success($order_id)
{
\Log::info('Pembayaran sukses dari frontend: ' . $order_id);
$order = Order::where('midtrans_transaction_id', $order_id)->first();
if ($order) {
$order->transaction_status = 'confirmed';
$order->save();
try {
// Inisialisasi Firebase
$factory = (new Factory)
->withServiceAccount(config('services.firebase.credentials'))
->withDatabaseUri(config('services.firebase.database_url'));
$firebase = $factory->createDatabase();
// Update ke Firebase RTDB
$firebase->getReference($order->table_id)->update([
'reserved_by' => $order->customer_name,
'sensors/table_activation_sensor_active' => 1,
'table_occupied' => 1,
]);
Log::info("Firebase: Meja {$order->table_id} diupdate untuk order {$order->id}");
} catch (\Exception $e) {
Log::error('Gagal update Firebase dari controller success(): ' . $e->getMessage());
}
return redirect()->route('home')->with('success', 'Pembayaran berhasil.');
}
return redirect()->route('home')->withErrors('Order tidak ditemukan.');
}
public function pending(Request $request)
{
dd('Masuk ke pending', $request->all());
$transactionId = $request->input('order_id');
\Log::info('Pembayaran pending dari frontend:', $request->all());
$order = Order::where('midtrans_transaction_id', $transactionId)->first();
return redirect()->route('home')->withErrors('Order tidak ditemukan.');
}
public function error(Request $request)
{
dd('Masuk ke error', $request->all());
$transactionId = $request->input('order_id');
\Log::error('Pembayaran error dari frontend:', $request->all());
$order = Order::where('midtrans_transaction_id', $transactionId)->first();
return redirect()->route('home')->withErrors('Order tidak ditemukan.');
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Database;
use Illuminate\Support\Facades\Log;
class AdminTables extends Component
{
public $tables = [];
public $errorMessage = null;
private ?Database $firebaseDatabase = null;
public function mount()
{
try {
$factory = (new Factory)
->withServiceAccount(config('services.firebase.credentials'))
->withDatabaseUri(config('services.firebase.database_url'));
$this->firebaseDatabase = $factory->createDatabase();
} catch (\Exception $e) {
Log::error('Firebase init failed: ' . $e->getMessage());
$this->dispatch('notify', message: 'Firebase tidak terhubung.', type: 'error');
}
$this->loadTables();
}
public function loadTables()
{
if (!$this->firebaseDatabase) {
$this->tables = [];
return;
}
try {
$data = $this->firebaseDatabase->getReference()->getValue();
$this->tables = $data ?? [];
// Kirim data ke console log
$this->dispatch('logToConsole', message: json_encode($this->tables));
} catch (\Exception $e) {
$this->tables = [];
$this->dispatch('notify', message: 'Gagal mengambil data meja.', type: 'error');
}
}
public function clearTable($tableId)
{
if (!$this->firebaseDatabase) return;
try {
$this->firebaseDatabase->getReference($tableId)->update([
'reserved_by' => 'N/A',
'sensors/table_activation_sensor_active' => 0,
'table_occupied' => 0,
]);
$this->dispatch('notify', message: 'Meja ' . $tableId . ' berhasil dikosongkan.', type: 'success');
$this->loadTables();
} catch (\Exception $e) {
Log::error("Gagal kosongkan meja {$tableId}: " . $e->getMessage());
$this->dispatch('notify', message: 'Gagal mengosongkan meja.', type: 'error');
}
}
public function render()
{
$this->dispatch('logToConsole', message: json_encode($this->tables));
return view('livewire.admin-tables');
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Order;
use App\Models\OrderItem;
use Illuminate\Support\Collection;
class KitchenOrders extends Component
{
public Collection $kitchenItems;
protected $listeners = [
'orderStatusUpdated' => 'loadKitchenOrders', // Jika ada event dari luar yang memicu refresh
'refreshKitchenOrders' => 'loadKitchenOrders', // Event kustom untuk refresh manual
];
public function mount()
{
$this->loadKitchenOrders();
}
public function loadKitchenOrders()
{
$orders = Order::with(['items'])
->whereIn('transaction_status', ['settlement', 'confirmed']) // ✅ Tambahkan 'confirmed'
->get();
$items = [];
foreach ($orders as $order) {
foreach ($order->items as $item) {
$items[] = [
'id' => $item->order_id,
'name' => $item->item_name,
'quantity' => $item->quantity ?? 1,
'table_id' => $order->table_id,
'customer_name' => $order->customer_name,
'order_id' => $order->id,
'updated_at' => $order->updated_at,
'cooked' => $item->cooked ?? false,
];
}
}
$this->kitchenItems = collect($items)->groupBy('order_id');
}
public function markAsCooked($orderItemId) // Mengubah parameter menjadi orderItemId
{
$orderItem = OrderItem::find($orderItemId);
if (!$orderItem) {
$this->dispatch('notify', message: 'Item pesanan tidak ditemukan.', type: 'error');
return;
}
$orderItem->cooked = true;
$orderItem->save();
$this->loadKitchenOrders();
$this->dispatch('notify', message: 'Item "' . $orderItem->item_name . '" pada pesanan #' . $orderItem->order_id . ' ditandai sebagai sudah dimasak.', type: 'success');
}
public function markAllAsCooked($orderId)
{
$order = Order::with('items')->find($orderId);
if (!$order) return;
foreach ($order->items as $item) {
// Akses properti 'cooked' langsung dari objek $item OrderItem
if (!$item->cooked) { // <-- PERUBAHAN PENTING DI SINI
$item->cooked = true;
$item->save(); // Simpan perubahan pada setiap OrderItem
}
}
$this->loadKitchenOrders();
$this->dispatch('notify', message: 'Semua item pada pesanan #' . $orderId . ' ditandai sebagai sudah dimasak.', type: 'success');
}
public function render()
{
return view('livewire.kitchen-orders');
}
}

View File

@ -0,0 +1,112 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use Midtrans\Config;
use Midtrans\Snap;
use App\Models\Order;
use App\Models\OrderItem;
class MidtransPayment extends Component
{
public $snapToken;
public $transactionId;
public $orderId;
protected $listeners = [
'midtransSuccess' => 'handleSuccess',
'midtransPending' => 'handlePending',
'midtransError' => 'handleError',
];
public function mount($midtrans_transaction_id)
{
$this->transactionId = $midtrans_transaction_id;
// Ambil order_id berdasarkan transaction_id
$order = Order::where('midtrans_transaction_id', $this->transactionId)->firstOrFail();
$this->orderId = $order->id;
// Konfigurasi Midtrans
Config::$serverKey = config('services.midtrans.server_key');
Config::$isProduction = config('services.midtrans.is_production');
Config::$isSanitized = true;
Config::$is3ds = true;
// Detail customer
$customerDetails = [
'first_name' => substr($order->customer_name ?? 'Customer', 0, 50),
'email' => $order->customer_email ?? 'guest@gmail.com',
'phone' => '08123456789',
];
// Ambil item pesanan
$orderItems = OrderItem::where('order_id', $order->id)->get();
$itemDetails = $orderItems->map(function ($item) {
return [
'id' => $item->id,
'price' => intval($item->item_price),
'quantity' => intval($item->quantity),
'name' => substr($item->item_name, 0, 50),
];
})->toArray();
// Hitung total manual
$total = array_reduce($itemDetails, function ($carry, $item) {
return $carry + ($item['price'] * $item['quantity']);
}, 0);
$params = [
'transaction_details' => [
'order_id' => (string) $this->transactionId,
'gross_amount' => $total,
],
'customer_details' => $customerDetails,
'item_details' => $itemDetails,
'enabled_payments' => ['credit_card', 'bca_va', 'bni_va', 'bri_va'],
];
// Dapatkan Snap Token
$this->snapToken = Snap::getSnapToken($params);
}
public function handleSuccess($result)
{
\Log::info('Pembayaran sukses:', $result);
Order::where('midtrans_transaction_id', $this->transactionId)->update([
'transaction_status' => 'confirmed',
]);
session()->flash('message', 'Pembayaran berhasil!');
}
public function handlePending($result)
{
\Log::info('Pembayaran pending:', $result);
// Jika ingin disimpan sementara
Order::where('midtrans_transaction_id', $this->transactionId)->update([
'transaction_status' => 'pending',
]);
session()->flash('message', 'Pembayaran sedang diproses.');
}
public function handleError($result)
{
\Log::error('Pembayaran error:', $result);
Order::where('midtrans_transaction_id', $this->transactionId)->update([
'transaction_status' => 'cancelled',
]);
session()->flash('message', 'Terjadi kesalahan saat pembayaran.');
}
public function render()
{
return view('livewire.midtrans-payment')->layout('components.layouts.base');
}
}

169
app/Livewire/Orders.php Normal file
View File

@ -0,0 +1,169 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Order;
use Illuminate\Support\Collection;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Database;
use Illuminate\Support\Facades\Log;
class Orders extends Component
{
public Collection $orders;
public string $filterStatus = 'pending';
public ?int $selectedOrderId = null;
public ?Order $selectedOrder = null;
protected $listeners = ['orderStatusUpdated' => '$refresh'];
private ?Database $firebaseDatabase = null;
public function boot()
{
try {
$factory = (new Factory)
->withServiceAccount(config('services.firebase.credentials'))
->withDatabaseUri(config('services.firebase.database_url'));
$this->firebaseDatabase = $factory->createDatabase();
} catch (\Exception $e) {
Log::error('Firebase initialization failed: ' . $e->getMessage());
$this->dispatch('notify', message: 'Gagal menghubungkan ke Firebase.', type: 'error');
}
}
public function mount()
{
$this->loadOrders();
}
public function loadOrders()
{
$query = Order::with('items');
if ($this->filterStatus && $this->filterStatus !== 'all') {
switch ($this->filterStatus) {
case 'pending':
// Tampilkan hanya pending dari metode manual (cash/qris)
$query->where('transaction_status', 'pending');
break;
case 'pending_manual':
// Tampilkan hanya pending dari metode manual (cash/qris)
$query->where('transaction_status', 'pending')
->whereIn('payment_method', ['cash', 'qris']);
break;
case 'pending_midtrans':
// Tampilkan hanya pending dari metode manual (cash/qris)
$query->where('transaction_status', 'pending')
->where('payment_method', 'midtrans')
->whereNotNull('midtrans_transaction_id');
break;
case 'confirmed':
// Tampilkan yang confirmed manual + settlement Midtrans
$query->where(function ($q) {
$q->where('transaction_status', 'confirmed')
->orWhere('transaction_status', 'settlement');
});
break;
case 'confirmed_manual':
$query->where('transaction_status', 'confirmed')
->whereIn('payment_method', ['cash', 'qris']);
break;
case 'settlement_midtrans':
$query->where(function ($q) {
$q->where('transaction_status', 'confirmed')
->orWhere('transaction_status', 'settlement');
})
->where('payment_method', 'midtrans')
->whereNotNull('midtrans_transaction_id');
break;
default:
// Filter status seperti biasa
$query->where('transaction_status', $this->filterStatus);
break;
}
}
$this->orders = $query->latest()->get();
}
public function updatedFilterStatus()
{
$this->loadOrders();
}
public function showOrderDetails(int $orderId)
{
$this->selectedOrder = Order::with('items')->find($orderId);
$this->selectedOrderId = $orderId;
$this->dispatch('openOrderDetailsModal');
}
public function updateOrderStatus(int $orderId, string $newStatus)
{
$order = Order::find($orderId);
if (!$order) {
$this->dispatch('notify', message: 'Pesanan tidak ditemukan.', type: 'error');
return;
}
$oldStatus = $order->transaction_status;
$order->transaction_status = $newStatus;
$order->save();
if ($this->firebaseDatabase) {
$tableId = $order->table_id;
$tableRef = $this->firebaseDatabase->getReference($tableId);
try {
if ($newStatus === 'settlement' || $newStatus === 'confirmed') {
$tableRef->update([
'reserved_by' => $order->customer_name,
'sensors/table_activation_sensor_active' => 1,
'table_occupied' => 1,
]);
Log::info("Firebase: Meja {$tableId} diperbarui ke occupied oleh pesanan {$order->id}.");
} elseif ($newStatus === 'cancel' || $newStatus === 'expire') {
$tableRef->update([
'reserved_by' => 'N/A',
'sensors/table_activation_sensor_active' => 0,
'table_occupied' => 0,
]);
Log::info("Firebase: Meja {$tableId} dibebaskan karena pesanan {$order->id} {$newStatus}.");
}
} catch (\Exception $e) {
Log::error('Gagal memperbarui status meja di Firebase: ' . $e->getMessage(), [
'order_id' => $order->id,
'table_id' => $tableId,
'new_status' => $newStatus
]);
$this->dispatch('notify', message: 'Gagal memperbarui status meja di Firebase.', type: 'error');
}
} else {
Log::warning('Firebase Database instance not available. Cannot update table status.');
$this->dispatch('notify', message: 'Tidak dapat memperbarui status meja (Firebase tidak terhubung).', type: 'warning');
}
$this->loadOrders();
$this->dispatch('notify', message: 'Status pesanan ' . $order->id . ' berhasil diperbarui menjadi ' . $newStatus . '.', type: 'success');
if ($this->selectedOrderId === $orderId) {
$this->dispatch('closeOrderDetailsModal');
$this->selectedOrderId = null;
$this->selectedOrder = null;
}
}
public function render()
{
return view('livewire.orders');
}
}

36
app/Livewire/Tables.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\On; // Import untuk atribut listener
use Illuminate\Support\Collection;
use Kreait\Firebase\Factory; // Pastikan ini di-import
class Tables extends Component
{
public Collection $tablesData;
public function mount()
{
// Inisialisasi awal data meja kosong atau dari cache jika ada
$this->tablesData = collect();
}
/**
* Listener Livewire untuk menerima update data meja dari sisi klien (Firebase JS).
*/
#[On('firebaseTablesUpdated')]
public function updateTablesData(array $data)
{
// Mengubah array data dari JS menjadi Collection
$this->tablesData = collect($data);
// Debugging (opsional)
// \Log::info('Livewire received tables update:', ['data' => $data]);
}
public function render()
{
return view('livewire.tables');
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use App\Models\Order;
class OrderReceiptMail extends Mailable
{
use Queueable, SerializesModels;
public Order $order;
public function __construct(Order $order)
{
$this->order = $order->load('items'); // include items
}
public function build()
{
return $this->subject('Struk Pemesanan - ' . $this->order->id)
->view('emails.receipt');
}
}

53
app/Models/Order.php Normal file
View File

@ -0,0 +1,53 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'orders';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
// 'order_id', // Jika Anda memutuskan untuk mengembalikan kolom ini di DB
'customer_name',
'customer_email',
'table_id',
'total_amount',
'payment_method',
'transaction_status',
'midtrans_transaction_id',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'total_amount' => 'decimal:2', // Pastikan presisi 2 desimal
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the order items for the order.
*/
public function items()
{
return $this->hasMany(OrderItem::class, 'order_id', 'id');
}
}

62
app/Models/OrderItem.php Normal file
View File

@ -0,0 +1,62 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class OrderItem extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'order_items';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'order_id',
'item_id',
'item_name',
'item_price',
'quantity',
'total_price',
'cooked'
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'item_price' => 'decimal:2', // Pastikan presisi 2 desimal
'total_price' => 'decimal:2', // Pastikan presisi 2 desimal
'quantity' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the order that owns the order item.
*/
public function order()
{
return $this->belongsTo(Order::class, 'order_id', 'id');
}
/**
* Get the actual menu item associated with the order item.
*/
public function item()
{
return $this->belongsTo(Items::class, 'item_id', 'id');
}
}

View File

@ -4,7 +4,9 @@
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\DB;
use App\Models\TypeItems; use App\Models\TypeItems;
use Kreait\Firebase\Factory;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
@ -13,7 +15,10 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function register(): void public function register(): void
{ {
// // $this->app->singleton('firebase.database', function () {
// $factory = (new Factory)->withServiceAccount(config_path('firebase_credentials.json'));
// return $factory->createDatabase();
// });
} }
/** /**
@ -21,6 +26,8 @@ public function register(): void
*/ */
public function boot(): void public function boot(): void
{ {
// DB::statement("SET time_zone = '+07:00'");
View::composer('components.layouts.app.sidebar', function ($view) { View::composer('components.layouts.app.sidebar', function ($view) {
$view->with('typeitems', TypeItems::orderBy('name')->get()); $view->with('typeitems', TypeItems::orderBy('name')->get());
}); });

View File

@ -65,7 +65,7 @@
| |
*/ */
'timezone' => 'UTC', 'timezone' => 'Asia/Jakarta',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -56,6 +56,7 @@
'prefix' => '', 'prefix' => '',
'prefix_indexes' => true, 'prefix_indexes' => true,
'strict' => true, 'strict' => true,
'timezone' => '+07:00',
'engine' => null, 'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([ 'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),

View File

@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "meja-iotv0",
"private_key_id": "5eeb8a374164a1dd206e77961a344295d3e9f09c",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQJ5NLDmqcKdVm\nGBaIEalPyEIHE2CXPCxnWCAncBcBHAmcfMFS09p6EDdkrevI6qo2fysla/J9lTJR\ny5XcjAOYCSQGVwrq0ImYd+bPzSJMwfXuiAIqF/f6kOQ0Uv5DKewLRAxdvOaQ+ZZH\n+HTYUeZXcGph7cDxA0J+3JCzSqnezQsjCCB9paC8us3/kbwo9OHJCxIVGQUNFVl1\nTl3eJv3AZOzr9saP3YYDgV2E652c9OWLaLqc2adS4YzIo0kkHXumSo2/oGLbF5kA\nG+NYUY6tFWb7wSUEW27p+zImXLBmCMnYVp2A0IU6Sst1PKSVWVYZa4iUw5xJjPFG\nigEFDZB/AgMBAAECggEAW0dvhPNudsq1hM69Wq/8Ajt8EORDcC53/l2bxA+YVuk3\nocLnd+3lGa/wypqmEfYt7DX58rASp1V8une/YPaZQNuJS6px5CTMoeq6cZewGd7Y\nfOBxqonWOa++Et/uFf/VPd96WMTUivCYITln69CGZQOr8wOynz3htAX/AlCUi1mt\nrKQbirmX8o68GB0oA921u8KdFVLoIx+TzEGuXxiurwILmJtsJhjuTYzd7TAidZTO\na0Ns3p5Al6lsnd017pff1njHxYTuNRNfnM3PEEQvFxmjATVQQWyMjjjGx6u/La42\nNBG19jlRVS7RWXzctKpkZUEpUzjhLYG78CZ2KWSPWQKBgQD/n1kJg/IACBAKzWya\ngqv/4W1DhkTU/DaBIy+a1ik03GkIQcb45q+HatxHg6+8fxhlx4FtXyS7T+7vdL8b\n4+KECOfqyjsIJ3ML1Ni5hJw214SoDDwgVh5J2HFAoCvGuhM8UuYCNyx/H9wo7KRS\nzqa5sbjs0SGlZvwN7px0Mg7SMwKBgQDQdkebUcV9oCoKI3sLrIXHiJpsXkgb87Dz\n9EE/QHmWMLxQLPPSGegXf4FzYBwgWK+PODamnLc8bnbUdIou+xJ+1yD3ZsSAH4dB\nsSatdMtFVI6LcPba8zstJl8CD9jKKULYsPkL4dzlGHZTko+WjqGkIZj8Dbm+mjWE\nah93ZLg0hQKBgHnnbjjBeelV7wCX0tEkvA39XXQ0ViMUXJHdS9iVhXU2H8jWRaNx\nsAfuiDp6rJZCLkpriGe2VfgWOKZtkK4mUWISNTedVeWfmpfr26ctfKoSwaq6mvn4\n19zzoZ7mQ7o0BvRfvF0WHtxJP18s63iqIIyyGrSlT1xn7pBeWLJ5JORNAoGBAIgw\nvhd7FMs+GDkHdRvrWntBg6HI9tNMIg8/RGFOfiDhNiYrOB/LTRYM90WpRLbdOdUX\npJy1RgD1Ki0i9iQ7Y5n6ck8vlLEf5/3C/sHTy/k/hOEUrDHfNooIx4lRURDCZCmt\ndQeOSAJkOOnglm6GQJQ6XvhM/0zG8q/PpT8bTj0BAoGBAKAMiVU2fHRzi7Kw2Mmi\n+e5J+4kgoMyA8mY5hguhxiSFumS+sENtcOX5T4KLFntRrjXyZ070dvBwfLzyPXd/\nImH9lhvfpPSLhGvreUeftwMWMm0GjvQQFBueTzoaHA21cVD4MXQSBbknfEuuRtVr\nxSceo6sepT8jRDzII0A015H4\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-fbsvc@meja-iotv0.iam.gserviceaccount.com",
"client_id": "112854400819780721785",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40meja-iotv0.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

View File

@ -41,12 +41,10 @@
], ],
'midtrans' => [ 'midtrans' => [
'client_key' => env('MIDTRANS_CLIENT_KEY'),
'server_key' => env('MIDTRANS_SERVER_KEY'), 'server_key' => env('MIDTRANS_SERVER_KEY'),
'client_key' => env('MIDTRANS_CLIENT_KEY'),
'is_production' => env('MIDTRANS_IS_PRODUCTION', false), 'is_production' => env('MIDTRANS_IS_PRODUCTION', false),
'snap_url' => env('MIDTRANS_IS_PRODUCTION') 'snap_url' => env('MIDTRANS_SNAP_URL', 'https://app.sandbox.midtrans.com/snap/snap.js'),
? 'https://app.midtrans.com/snap/snap.js'
: 'https://app.sandbox.midtrans.com/snap/snap.js',
], ],
]; ];

View File

@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('orders');
}
};

View File

@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('order_items', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('order_items');
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

BIN
public/img/denah-cafe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

BIN
public/img/qr-code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -31,8 +31,14 @@
<flux:navlist.group :heading="__('Other')" class="grid"> <flux:navlist.group :heading="__('Other')" class="grid">
<flux:navlist.item icon="archive-box-arrow-down" :href="route('typeitems.index')" <flux:navlist.item icon="archive-box-arrow-down" :href="route('typeitems.index')"
:current="request()->routeIs('typeitems.index')" wire:navigate>{{ __('Type Items') }}</flux:navlist.item> :current="request()->routeIs('typeitems.index')" wire:navigate>{{ __('Type Items') }}</flux:navlist.item>
<flux:navlist.item icon="lock-closed" :href="route('tables.index')" {{-- <flux:navlist.item icon="lock-closed" :href="route('tables.index')"
:current="request()->routeIs('tables.index')" wire:navigate>{{ __('Tabels') }}</flux:navlist.item> :current="request()->routeIs('tables.index')" wire:navigate>{{ __('Tabels') }}</flux:navlist.item> --}}
<flux:navlist.item icon="shopping-cart" :href="route('orders.index')"
:current="request()->routeIs('orders.index')" wire:navigate>{{ __('Orders') }}</flux:navlist.item>
<flux:navlist.item icon="building-storefront" :href="route('kitchen.index')"
:current="request()->routeIs('kitchen.index')" wire:navigate>{{ __('Kitchen') }}</flux:navlist.item>
{{-- <flux:navlist.item icon="bookmark" :href="route('tables.index')"
:current="request()->routeIs('tables.index')" wire:navigate>{{ __('Tables') }}</flux:navlist.item> --}}
</flux:navlist.group> </flux:navlist.group>
</flux:navlist> </flux:navlist>

View File

@ -9,7 +9,7 @@
<div class="absolute inset-0 bg-neutral-900"></div> <div class="absolute inset-0 bg-neutral-900"></div>
<a href="{{ route('dashboard') }}" class="relative z-20 flex items-center text-lg font-medium" wire:navigate> <a href="{{ route('dashboard') }}" class="relative z-20 flex items-center text-lg font-medium" wire:navigate>
<span class="flex h-10 w-10 items-center justify-center rounded-md"> <span class="flex h-10 w-10 items-center justify-center rounded-md">
<x-app-logo-icon class="me-2 h-7 fill-current text-white" /> {{-- <x-app-logo-icon class="me-2 h-7 fill-current text-white" /> --}}
</span> </span>
{{ config('app.name', 'Login') }} {{ config('app.name', 'Login') }}
</a> </a>

View File

@ -1,13 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="id">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{{ $title ?? 'Website' }}</title> <title>@yield('title', 'PEMBAYARAN MIDTRANS')</title>
@vite(['resources/css/app.css', 'resources/js/app.js']) <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
@livewireStyles @livewireStyles
</head> </head>
<body class="bg-white text-gray-900"> <body>
{{ $slot }} @yield('content')
@stack('scripts')
@livewireScripts @livewireScripts
</body> </body>
</html> </html>

View File

@ -5,14 +5,30 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="midtrans-client-key" content="{{ config('services.midtrans.client_key') }}">
<meta name="midtrans-snap-url" content="{{ config('services.midtrans.snap_url') }}">
<title>{{ config('app.name', 'DFOOD') }}</title> <title>{{ config('app.name', 'DFOOD') }}</title>
{{-- Vite Assets --}}
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
<script type="text/javascript" src="{{ config('services.midtrans.snap_url') }}" <style>
data-client-key="{{ config('services.midtrans.client_key') }}"></script> .opacity-bg {
background-color: rgba(0, 0, 0, 0.75);
}
input[type="radio"],
input[type="checkbox"],
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="image"],
select,
button {
cursor: pointer;
}
</style>
@livewireStyles @livewireStyles
</head> </head>
@ -20,123 +36,50 @@
{{ $slot }} {{ $slot }}
{{-- Alpine.js harus dimuat sebelum Livewire --}} <script src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="{{ config('services.midtrans.client_key') }}"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
{{-- Livewire Scripts harus dimuat setelah Alpine.js --}} {{-- Custom Scripts --}}
@livewireScripts
{{-- Script kustom Anda harus dimuat setelah @livewireScripts --}}
<script> <script>
document.addEventListener('livewire:initialized', function() { document.addEventListener('livewire:initialized', function() {
// Livewire Event Listener untuk notifikasi umum // Event Notifikasi (global notification)
Livewire.on('notify', (data) => { Livewire.on('notify', (data) => {
console.log('Notification:', data.message); console.log('🔔 Notification:', data.message);
}); window.dispatchEvent(new CustomEvent('notify', {
detail: {
// Livewire Event Listener untuk menampilkan Midtrans Snap Pop-up message: data.message
Livewire.on('midtransSnapToken', (event) => {
const snapToken = event.token;
console.log('Received Midtrans Snap Token:', snapToken);
if (typeof Snap !== 'undefined' && snapToken) {
try {
Snap.pay(snapToken, {
onSuccess: function(result) {
console.log('Payment success:', result);
Livewire.dispatch(
'paymentSuccess'); // Inform Livewire component
},
onPending: function(result) {
console.log('Payment pending:', result);
Livewire.dispatch('notify', {
message: 'Pembayaran menunggu konfirmasi Anda.'
});
},
onError: function(result) {
console.log('Payment error:', result);
let errorMessage = 'Terjadi kesalahan pembayaran.';
if (result.status_code === '400') {
errorMessage = 'Permintaan tidak valid. Mohon coba lagi.';
} else if (result.status_code === '401') {
errorMessage =
'Autentikasi Midtrans gagal. Hubungi administrator.';
}
Livewire.dispatch('notify', {
message: errorMessage
});
},
onClose: function() {
console.log('Payment closed by user');
Livewire.dispatch('notify', {
message: 'Pembayaran dibatalkan oleh pengguna.'
});
}
});
} catch (e) {
console.error("Error calling Snap.pay:", e);
Livewire.dispatch('notify', {
message: 'Terjadi kesalahan saat memulai pembayaran.'
});
} }
} else { }));
console.error(
'Midtrans Snap.js not loaded or Snap object is undefined, or snapToken is empty.'
);
Livewire.dispatch('notify', {
message: 'Sistem pembayaran tidak siap. Mohon refresh halaman.'
});
}
}); });
// Livewire Event Listener untuk update URL di browser history // Debug Log
Livewire.on('updateUrl', (data) => { Livewire.on('logToConsole', (data) => {
const newUrl = data.url; console.log('[Livewire Log]', data.message);
if (window.history.pushState) {
window.history.pushState({
path: newUrl
}, '', newUrl);
}
});
// Livewire hook untuk logging proses (hapus di production jika tidak perlu)
Livewire.hook('message.processed', (message, component) => {
if (component.fingerprint.name === 'food-order') {
console.log('FoodOrder component updated. Current cart:', component.serverMemo.data
.cart);
}
});
// Livewire Event Listener untuk menyembunyikan progress bar navigasi
Livewire.on('start-navigation', () => {
const progressBar = document.querySelector('.livewire-progress-bar');
if (progressBar) {
progressBar.style.display = 'none';
}
}); });
// Refresh CSRF Token tiap 30 menit
setInterval(() => { setInterval(() => {
fetch('/refresh-csrf', { fetch('/refresh-csrf', {
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest' 'X-Requested-With': 'XMLHttpRequest'
} }
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
const csrfMeta = document.querySelector('meta[name="csrf-token"]'); const csrfMeta = document.querySelector('meta[name="csrf-token"]');
if (csrfMeta) { if (csrfMeta) {
csrfMeta.setAttribute('content', data.csrf_token); csrfMeta.setAttribute('content', data.csrf_token);
console.log('🔁 CSRF token refreshed:', data.csrf_token);
} }
// Tidak perlu akses internal Livewire jika ingin aman dari perubahan API internal
console.log('CSRF token refreshed:', data.csrf_token);
}) })
.catch(error => { .catch(error => {
console.error('Error refreshing CSRF token:', error); console.error('❌ Gagal refresh CSRF token:', error);
}); });
}, 1800000); // 30 menit }, 1800000); // 30 menit
}); });
</script> </script>
{{-- @stack('scripts') --}}
@livewireScripts
</body> </body>
</html> </html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Struk Pembayaran</title>
</head>
<body>
<h2>Terima kasih atas pesanan Anda!</h2>
<p><strong>Nama Customer:</strong> {{ $order->customer_name }}</p>
<p><strong>Meja:</strong> {{ $order->table_name }}</p>
<p><strong>Total Pembayaran:</strong> Rp{{ number_format($order->total, 0, ',', '.') }}</p>
<p><strong>Metode:</strong> {{ ucfirst($order->payment_method) }}</p>
<p>Pesanan Anda sedang diproses. Mohon tunjukkan bukti pembayaran ini ke kasir.</p>
<hr>
<p><small>Website Restoran - Jangan balas email ini.</small></p>
</body>
</html>

View File

@ -0,0 +1,81 @@
<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-database-compat.js"></script>
<script>
const firebaseConfig = {
apiKey: "ISI_API_KEY_MU",
authDomain: "PROJECT_ID.firebaseapp.com",
databaseURL: "https://PROJECT_ID.firebaseio.com",
projectId: "PROJECT_ID",
storageBucket: "PROJECT_ID.appspot.com",
messagingSenderId: "....",
appId: "...."
};
firebase.initializeApp(firebaseConfig);
const db = firebase.database();
// Ambil data dari root Firebase
db.ref('/').on('value', (snapshot) => {
const data = snapshot.val();
renderTables(data);
});
function renderTables(data) {
const tableBody = document.getElementById('firebase-table-body');
tableBody.innerHTML = ''; // kosongkan isi lama
for (const key in data) {
const table = data[key];
const row = document.createElement('tr');
row.innerHTML = `
<td class="p-2 border">${key}</td>
<td class="p-2 border">${table.reserved_by || 'N/A'}</td>
<td class="p-2 border">${table.table_occupied ? 'Terisi' : 'Kosong'}</td>
<td class="p-2 border">${table.sensors?.table_activation_sensor_active ? 'Aktif' : 'Tidak'}</td>
<td class="p-2 border">${table.time_remaining_minutes ?? 0} menit</td>
<td class="p-2 border">
<button class="bg-red-600 text-white px-2 py-1 text-xs rounded hover:bg-red-700"
onclick="clearTable('${key}')">
Kosongkan
</button>
</td>
`;
tableBody.appendChild(row);
}
}
function clearTable(tableId) {
db.ref(`/${tableId}`).update({
reserved_by: 'N/A',
table_occupied: 0,
sensors: {
table_activation_sensor_active: 0
}
}).then(() => {
alert(`Meja ${tableId} berhasil dikosongkan`);
}).catch((error) => {
alert('Gagal kosongkan meja: ' + error.message);
});
}
</script>
<div class="p-4">
<h2 class="text-xl font-bold mb-4">Status Meja dari Firebase (Realtime)</h2>
<table class="table-auto w-full border text-sm">
<thead class="bg-gray-200">
<tr>
<th class="p-2 border">ID Meja</th>
<th class="p-2 border">Nama Pemesan</th>
<th class="p-2 border">Status</th>
<th class="p-2 border">Sensor Aktif</th>
<th class="p-2 border">Sisa Waktu</th>
<th class="p-2 border">Aksi</th>
</tr>
</thead>
<tbody id="firebase-table-body">
<tr>
<td colspan="6" class="text-center text-gray-500 p-4">Memuat data meja...</td>
</tr>
</tbody>
</table>
</div>

View File

@ -1,4 +1,35 @@
<div class="flex h-screen bg-gray-100 font-sans"> <div class="flex h-screen bg-gray-100 font-sans" x-data="{
notification: false,
message: '',
notificationType: 'success',
isProcessingButton: false,
getNotificationClasses() {
// Fungsi untuk mendapatkan kelas CSS berdasarkan tipe notifikasi
switch (this.notificationType) {
case 'success':
return 'bg-green-500';
case 'warning':
return 'bg-yellow-500';
case 'error':
return 'bg-red-500';
case 'info':
return 'bg-blue-500';
default:
return 'bg-gray-700';
}
},
// Inisialisasi Alpine.js
init() {
// Listener untuk notifikasi global dari Livewire Component
Livewire.on('notify', (data) => {
this.notification = true;
this.message = data.message;
this.notificationType = data.type || 'success';
setTimeout(() => this.notification = false, 4000);
});
}
}">
{{-- Kiri: Sidemenu Kategori --}} {{-- Kiri: Sidemenu Kategori --}}
<div class="w-64 bg-white shadow-lg overflow-y-auto p-4 z-20"> <div class="w-64 bg-white shadow-lg overflow-y-auto p-4 z-20">
<h1 class="text-5xl font-bold mb-6 text-center text-gray-800">DFOOD</h1> <h1 class="text-5xl font-bold mb-6 text-center text-gray-800">DFOOD</h1>
@ -8,7 +39,7 @@
<li class="mb-2"> <li class="mb-2">
<a href="#" wire:click.prevent="filterByType({{ $type->id }})" <a href="#" wire:click.prevent="filterByType({{ $type->id }})"
class="block rounded overflow-hidden shadow-md transition-all duration-200 class="block rounded overflow-hidden shadow-md transition-all duration-200
{{ $typeItemId == $type->id ? 'ring-2 ring-green-600 ring-offset-2' : 'hover:scale-105' }}"> {{ $typeItemId == $type->id ? 'ring-2 ring-green-600 ring-offset-2' : 'hover:scale-105' }}">
@php @php
$imageUrl = $type->image_url; $imageUrl = $type->image_url;
if (!filter_var($imageUrl, FILTER_VALIDATE_URL)) { if (!filter_var($imageUrl, FILTER_VALIDATE_URL)) {
@ -76,82 +107,6 @@ class="fixed top-0 right-0 h-full w-96 bg-white shadow-xl z-30 flex flex-col tra
@if (empty($cartItems)) @if (empty($cartItems))
<p class="text-gray-500 text-center py-10">Keranjang kosong.</p> <p class="text-gray-500 text-center py-10">Keranjang kosong.</p>
@else @else
{{-- Di dalam modal keranjang, di bagian 'Pilih Meja Anda' --}}
<div class="p-4 bg-white rounded-lg shadow-md mb-6">
<h3 class="text-xl font-semibold mb-4 text-gray-800">Pilih Meja Anda</h3>
{{-- Checkbox untuk memilih jenis pemesanan meja --}}
<div class="mb-4 flex items-center">
<input type="checkbox" id="is-existing-customer" wire:model.live="isExistingCustomer"
class="mr-2 form-checkbox h-5 w-5 text-blue-600">
<label for="is-existing-customer" class="text-gray-700 text-sm font-bold">Saya sudah memesan
meja.</label>
</div>
{{-- Kondisional untuk menampilkan dropdown meja tersedia atau meja terisi --}}
@if (!$isExistingCustomer)
{{-- Dropdown untuk Meja Tersedia --}}
<div class="mb-4">
<label for="available-table-select" class="block text-gray-700 text-sm font-bold mb-2">Meja
Tersedia:</label>
<select id="available-table-select" wire:model.live="selectedTableId" wire:key="select-available"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
{{ $tableIdFromUrl && $selectedOccupiedTableId === null ? 'disabled' : '' }}>
<option value="">-- Pilih Meja Tersedia --</option>
@foreach ($availableTables as $table)
<option value="{{ $table['id'] }}">
{{ $table['device_id'] }} || TERSEDIA
</option>
@endforeach
</select>
@error('selectedTableId')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@elseif ($isExistingCustomer)
<div class="mb-4">
<label for="occupied-table-select"
class="block text-gray-700 text-sm font-bold mb-2">Meja Sudah Terisi (Konfirmasi
Nama):</label>
<select id="occupied-table-select" wire:model.live="selectedOccupiedTableId" wire:key="select-occupied"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
{{ $tableIdFromUrl && $selectedTableId === null ? 'disabled' : '' }}>
<option value="">-- Pilih Meja Terisi --</option>
@foreach ($occupiedTables as $table)
<option value="{{ $table['id'] }}">
{{ $table['device_id'] }} || Oleh: {{ $table['reserved_by'] }}
</option>
@endforeach
</select>
@error('selectedOccupiedTableId')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@endif
{{-- Input Nama Pemesan (TERBARU: Hanya muncul jika showCustomerNameInput TRUE) --}}
@if ($showCustomerNameInput)
<div class="mb-4">
<label for="customer-name-input" class="block text-gray-700 text-sm font-bold mb-2">Nama
Pemesan:</label>
<input type="text" id="customer-name-input" wire:model.live="inputCustomerName"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Masukkan nama Anda" {{ $isCustomerNameInputDisabled ? 'disabled' : '' }}>
@error('inputCustomerName')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@endif
{{-- Tombol Lihat Denah Meja --}}
<div class="mb-4">
<button wire:click="showMap"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Lihat Denah Meja
</button>
</div>
</div>
{{-- Daftar Item Keranjang --}} {{-- Daftar Item Keranjang --}}
<ul class="divide-y divide-gray-200 mb-4" tabindex="0"> <ul class="divide-y divide-gray-200 mb-4" tabindex="0">
@foreach ($cartItems as $item) @foreach ($cartItems as $item)
@ -183,57 +138,15 @@ class="px-2 py-1 bg-green-100 text-green-700 rounded hover:bg-green-200">
<div class="mb-4 text-right text-xl text-gray-900">Total: Rp <div class="mb-4 text-right text-xl text-gray-900">Total: Rp
{{ number_format($cartTotal, 0, ',', '.') }}</div> {{ number_format($cartTotal, 0, ',', '.') }}</div>
{{-- Input Email (jika showEmailInput true) --}}
@if ($showEmailInput)
<div class="mt-4 mb-4">
<label for="customerEmail" class="block text-gray-700 text-sm font-bold mb-2">Email Anda:</label>
<input type="email" id="customerEmail" wire:model.defer="customerEmail"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="nama@contoh.com">
@error('customerEmail')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@endif
{{-- Tombol Pembayaran --}} {{-- Tombol Pembayaran --}}
<div class="flex flex-col space-y-3 mt-4"> <div class="flex flex-col space-y-3 mt-4">
<button wire:click="checkout" <button wire:click="goToCheckoutDetails" type="button" wire:loading.attr="disabled"
class="bg-green-600 hover:bg-green-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-green-500 font-semibold text-lg" wire:loading.class="opacity-50"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50"> class="bg-green-600 hover:bg-green-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-green-500 font-semibold text-lg
<span wire:loading.remove wire:target="checkout">Bayar Sekarang (Midtrans)</span> disabled:bg-gray-400 disabled:cursor-not-allowed"
<span wire:loading wire:target="checkout">Processing...</span> {{ empty($cartItems) ? 'disabled' : '' }}>
</button> <span wire:loading.remove>Lanjut Pembayaran</span>
<span wire:loading>Processing...</span>
{{-- Menggunakan $showEmailInput untuk toggle form, bukan tombol terpisah --}}
@if (!$showEmailInput && empty(auth()->user()->email))
<button wire:click="$toggle('showEmailInput')"
class="bg-blue-600 hover:bg-blue-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 font-semibold text-lg"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="$toggle('showEmailInput')">Bayar Nanti (Kirim Email
Receipt)</span>
<span wire:loading wire:target="$toggle('showEmailInput')">Processing...</span>
</button>
@elseif($showEmailInput)
<button wire:click="sendReceiptEmail"
class="bg-indigo-500 hover:bg-indigo-600 text-white font-bold py-2 px-4 rounded-lg"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="sendReceiptEmail">Kirim Email & Pesan</span>
<span wire:loading wire:target="sendReceiptEmail">Mengirim...</span>
</button>
<button wire:click="$toggle('showEmailInput')"
class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded-lg"
type="button">
Batal
</button>
@endif
<button wire:click="skipPayment"
class="bg-gray-600 hover:bg-gray-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-gray-500 font-semibold text-lg"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="skipPayment">Lewati Pembayaran</span>
<span wire:loading wire:target="skipPayment">Processing...</span>
</button> </button>
</div> </div>
</div> </div>
@ -241,13 +154,12 @@ class="bg-gray-600 hover:bg-gray-700 text-white py-2 rounded focus:outline-none
{{-- Overlay untuk sidebar keranjang --}} {{-- Overlay untuk sidebar keranjang --}}
@if ($showCart) @if ($showCart)
<div class="fixed inset-0 z-20" wire:click="closeCart"> <div class="fixed inset-0 opacity-bg z-20" wire:click="closeCart">
<div class="absolute inset-0 blur-background"></div> {{-- Div blur palsu --}}
</div> </div>
@endif @endif
{{-- Tombol Keranjang Mengambang --}} {{-- Tombol Keranjang Mengambang --}}
<div class="fixed bottom-4 right-4 z-10"> {{-- Z-index diatur lebih rendah dari sidebar dan modal --}} <div class="fixed bottom-4 right-4">
<button wire:click="openCart" <button wire:click="openCart"
class="bg-green-600 text-white rounded-full py-3 px-6 shadow-lg hover:bg-green-700 transition flex items-center gap-3"> class="bg-green-600 text-white rounded-full py-3 px-6 shadow-lg hover:bg-green-700 transition flex items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7" fill="none" viewBox="0 0 24 24" <svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7" fill="none" viewBox="0 0 24 24"
@ -255,21 +167,27 @@ class="bg-green-600 text-white rounded-full py-3 px-6 shadow-lg hover:bg-green-7
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" /> d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
</svg> </svg>
<span class="font-semibold text-xl">Keranjang ({{ array_sum($cart) }})</span> <span class="font-semibold text-xl">Keranjang
<span class="bg-white text-green-600 rounded-full px-2 py-1 text-base ml-2">
{{ array_sum($cart) }}
</span>
</span>
</button> </button>
</div> </div>
{{-- Modal Denah Meja --}}
@if ($showMapModal) @if ($showMapModal)
<div class="fixed inset-0 bg-black bg-opacity-75 z-[60] flex items-center justify-center" role="dialog" <div class="fixed inset-0 opacity-bg z-[71] flex items-center justify-center" role="dialog" aria-modal="true"
aria-modal="true" aria-labelledby="map-title"> aria-labelledby="map-title" x-show="$wire.showMapModal"
x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-90">
<div class="bg-white w-full max-w-2xl lg:max-w-4xl xl:max-w-5xl rounded shadow-lg p-6 relative"> <div class="bg-white w-full max-w-2xl lg:max-w-4xl xl:max-w-5xl rounded shadow-lg p-6 relative">
<h2 id="map-title" class="text-xl font-bold mb-4">Denah Meja Cafe</h2> <h2 id="map-title" class="text-xl font-bold mb-4">Denah Meja Restoran</h2>
<div class="relative w-full overflow-hidden border border-gray-300 rounded-lg" <div class="relative w-full overflow-hidden border border-gray-300 rounded-lg"
style="max-height: 80vh;"> style="max-height: 80vh;">
<img src="{{ asset('img/denah_cafe.jpg') }}" alt="Denah Cafe" <img src="{{ asset('img/denah-cafe.png') }}" alt="Denah Restoran"
class="w-full h-auto object-contain"> class="w-full h-auto object-contain max-h-[400px] mx-auto">
</div> </div>
<div class="mt-6 text-right"> <div class="mt-6 text-right">
@ -287,18 +205,288 @@ class="absolute top-2 right-2 text-gray-500 hover:text-gray-700 focus:outline-no
</div> </div>
</div> </div>
@endif @endif
@if ($showCheckoutDetailsModal)
<div class="fixed inset-0 opacity-bg z-[70] text-gray-700 flex items-center justify-center" role="dialog"
aria-modal="true" aria-labelledby="checkout-details-title" x-show="$wire.showCheckoutDetailsModal"
x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 translate-y-4"
x-transition:enter-end="opacity-100 translate-y-0" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0" x-transition:leave-end="opacity-0 translate-y-4"
@click.away="$wire.closeCheckoutDetailsModal()" @transition:after-enter="isProcessingButton = false">
<div class="bg-white w-full max-w-2xl rounded-lg shadow-lg p-6 relative">
<h2 id="checkout-details-title" class="text-2xl font-bold mb-4 text-gray-800 text-center">Checkout
</h2>
<button wire:click="closeCheckoutDetailsModal"
class="absolute top-3 right-3 text-gray-500 hover:text-gray-700 focus:outline-none"
aria-label="Tutup" type="button">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<div x-data="{ notification: false, message: '' }" <form wire:submit.prevent="processOrderConfirmation">
x-on:notify.window="notification = true; message = $event.detail.message; setTimeout(() => notification = false, 3000)" <div class="flex flex-col md:flex-row gap-6">
x-cloak>
<div x-show="notification" x-transition:enter="transition ease-out duration-300" {{-- Kolom Kiri --}}
<div class="flex-1 p-4 bg-white rounded-lg shadow-md">
<div class="mb-6">
<label class="block text-sm font-bold text-gray-700 mb-3">PESAN MEJA</label>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div
class="flex items-center p-3 rounded-md border border-gray-300 hover:bg-blue-50 cursor-pointer transition duration-200 ease-in-out
@if ($isExistingCustomer == '0') bg-blue-100 border-blue-500 @endif">
<input type="radio" id="customer-new" name="customer_type"
wire:model.live="isExistingCustomer" value="0"
class="mr-3 h-5 w-5 text-blue-600 focus:ring-blue-500">
<label for="customer-new" class="text-gray-700 text-base font-medium">BELUM
MEMESAN</label>
</div>
<div
class="flex items-cente p-3 rounded-md border border-gray-300 hover:bg-blue-50 cursor-pointer transition duration-200 ease-in-out
@if ($isExistingCustomer == '1') bg-blue-100 border-blue-500 @endif">
<input type="radio" id="customer-existing" name="customer_type"
wire:model.live="isExistingCustomer" value="1"
class="mr-3 h-5 w-5 text-blue-600 focus:ring-blue-500">
<label for="customer-existing"
class="text-gray-700 text-base font-medium">SUDAH MEMESAN</label>
</div>
</div>
</div>
<h3 class="text-md mb-2 font-bold">Pilih Meja Anda</h3>
{{-- Meja tersedia --}}
@if (!$isExistingCustomer)
<div class="mb-4">
<label for="available-table-select-checkout"
class="block text-gray-700 text-sm font-bold mb-2">Meja Tersedia:</label>
<select id="available-table-select-checkout" wire:model.live="selectedTableId"
class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
{{ $tableIdFromUrl && $selectedOccupiedTableId === null ? 'disabled' : '' }}>
<option value="">-- Pilih Meja Tersedia --</option>
@foreach ($availableTables as $table)
<option value="{{ $table['id'] }}">{{ $table['device_id'] }} || TERSEDIA
</option>
@endforeach
</select>
@error('selectedTableId')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@endif
{{-- Meja terisi --}}
@if ($isExistingCustomer)
<div class="mb-4">
<label for="occupied-table-select-checkout"
class="block text-gray-700 text-sm font-bold mb-2">Meja Sudah Terisi
(Konfirmasi Nama):</label>
<select id="occupied-table-select-checkout"
wire:model.live="selectedOccupiedTableId"
class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
{{ $tableIdFromUrl && $selectedTableId === null ? 'disabled' : '' }}>
<option value="">-- Pilih Meja Terisi --</option>
@foreach ($occupiedTables as $table)
<option value="{{ $table['id'] }}">{{ $table['device_id'] }} || Oleh:
{{ $table['reserved_by'] }}</option>
@endforeach
</select>
@error('selectedOccupiedTableId')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@endif
{{-- Input Nama --}}
@if ($showCustomerNameInput)
<div class="mb-4">
<label for="customer-name-input-checkout"
class="block text-gray-700 text-sm font-bold mb-2">Nama Pemesan:</label>
<input type="text" id="customer-name-input-checkout"
wire:model.live="inputCustomerName"
class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Masukkan nama Anda"
{{ $isCustomerNameInputDisabled ? 'disabled' : '' }}>
@error('inputCustomerName')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
@endif
{{-- Lihat Denah --}}
<div class="mb-4">
<button wire:click="showMap" type="button"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Lihat Denah Meja
</button>
</div>
</div>
{{-- Kolom Kanan --}}
<div class="flex-1 p-4 bg-white rounded-lg shadow-md">
<div class="mb-6 border rounded-lg">
<h3 class="text-md text-gray-800 font-bold">Pilih Metode Pembayaran:</h3>
<div>
<p class="text-sm mb-2">Pembayaran Otomatis</p>
<label class="flex items-center mb-2 cursor-pointer">
<input type="radio" wire:model.live="selectedPaymentMethod"
value="midtrans" class="form-radio h-5 w-5 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="currentColor" class="inline-block h-6 w-auto ml-2 mr-2">
<path d="M4.5 3.75a3 3 0 0 0-3 3v.75h21v-.75a3 3 0 0 0-3-3h-15Z" />
<path fill-rule="evenodd"
d="M22.5 9.75h-21v7.5a3 3 0 0 0 3 3h15a3 3 0 0 0 3-3v-7.5Zm-18 3.75a.75.75 0 0 1 .75-.75h6a.75.75 0 0 1 0 1.5h-6a.75.75 0 0 1-.75-.75Zm.75 2.25a.75.75 0 0 0 0 1.5h3a.75.75 0 0 0 0-1.5h-3Z"
clip-rule="evenodd" />
</svg>
<span class="text-gray-700 font-bold text-sm">Credit Card/Virtual
Account</span>
</label>
</div>
<div>
<p class="text-sm mb-2">Pembayaran Manual</p>
<label class="flex items-center cursor-pointer pb-2">
<input type="radio" wire:model.live="selectedPaymentMethod" value="cash"
class="form-radio h-5 w-5 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="currentColor" alt="Tunai Logo"
class="inline-block size-6 h-6 w-auto ml-2 mr-2">
<path d="M12 7.5a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5Z" />
<path fillRule="evenodd"
d="M1.5 4.875C1.5 3.839 2.34 3 3.375 3h17.25c1.035 0 1.875.84 1.875 1.875v9.75c0 1.036-.84 1.875-1.875 1.875H3.375A1.875 1.875 0 0 1 1.5 14.625v-9.75ZM8.25 9.75a3.75 3.75 0 1 1 7.5 0 3.75 3.75 0 0 1-7.5 0ZM18.75 9a.75.75 0 0 0-.75.75v.008c0 .414.336.75.75.75h.008a.75.75 0 0 0 .75-.75V9.75a.75.75 0 0 0-.75-.75h-.008ZM4.5 9.75A.75.75 0 0 1 5.25 9h.008a.75.75 0 0 1 .75.75v.008a.75.75 0 0 1-.75.75H5.25a.75.75 0 0 1-.75-.75V9.75Z"
clipRule="evenodd" />
<path
d="M2.25 18a.75.75 0 0 0 0 1.5c5.4 0 10.63.722 15.6 2.075 1.19.324 2.4-.558 2.4-1.82V18.75a.75.75 0 0 0-.75-.75H2.25Z" />
</svg>
<span class="text-gray-700 font-bold text-sm">Tunai</span>
</label>
<label class="flex items-center cursor-pointer">
<input type="radio" wire:model.live="selectedPaymentMethod" value="qris"
class="form-radio h-5 w-5 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="currentColor" class="inline-block h-6 w-auto ml-2 mr-2 size-6">
<path fill-rule="evenodd"
d="M3 4.875C3 3.839 3.84 3 4.875 3h4.5c1.036 0 1.875.84 1.875 1.875v4.5c0 1.036-.84 1.875-1.875 1.875h-4.5A1.875 1.875 0 0 1 3 9.375v-4.5ZM4.875 4.5a.375.375 0 0 0-.375.375v4.5c0 .207.168.375.375.375h4.5a.375.375 0 0 0 .375-.375v-4.5a.375.375 0 0 0-.375-.375h-4.5Zm7.875.375c0-1.036.84-1.875 1.875-1.875h4.5C20.16 3 21 3.84 21 4.875v4.5c0 1.036-.84 1.875-1.875 1.875h-4.5a1.875 1.875 0 0 1-1.875-1.875v-4.5Zm1.875-.375a.375.375 0 0 0-.375.375v4.5c0 .207.168.375.375.375h4.5a.375.375 0 0 0 .375-.375v-4.5a.375.375 0 0 0-.375-.375h-4.5ZM6 6.75A.75.75 0 0 1 6.75 6h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75A.75.75 0 0 1 6 7.5v-.75Zm9.75 0A.75.75 0 0 1 16.5 6h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75ZM3 14.625c0-1.036.84-1.875 1.875-1.875h4.5c1.036 0 1.875.84 1.875 1.875v4.5c0 1.035-.84 1.875-1.875 1.875h-4.5A1.875 1.875 0 0 1 3 19.125v-4.5Zm1.875-.375a.375.375 0 0 0-.375.375v4.5c0 .207.168.375.375.375h4.5a.375.375 0 0 0 .375-.375v-4.5a.375.375 0 0 0-.375-.375h-4.5Zm7.875-.75a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm6 0a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75ZM6 16.5a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm9.75 0a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm-3 3a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm6 0a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Z"
clip-rule="evenodd" />
</svg>
<span class="text-gray-700 font-bold text-sm">QRIS</span>
</label>
</div>
@error('selectedPaymentMethod')
<span class="text-red-500 text-sm mt-2 block text-center">{{ $message }}</span>
@enderror
</div>
<div class="mb-4 hidden">
<label for="customerEmail" class="block text-gray-800 text-sm font-bold mb-2">
Email Anda (Opsional):
</label>
<p class="text-gray-600 text-xs mb-2">
Email digunakan untuk menerima struk pesanan.
</p>
<input type="email" id="customerEmail" wire:model.live="customerEmail"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="nama@contoh.com">
@error('customerEmail')
<span class="text-red-500 text-sm mt-1">{{ $message }}</span>
@enderror
</div>
<div class="text-center mt-6">
<div class="mb-4 text-right text-xl text-gray-900">Total: Rp
{{ number_format($cartTotal, 0, ',', '.') }}</div>
<button wire:click="processOrderConfirmation"
class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-4 rounded focus:outline-none focus:shadow-outline disabled:opacity-50 disabled:cursor-not-allowed"
type="submit" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="processOrderConfirmation">Bayar</span>
<span wire:loading wire:target="processOrderConfirmation">Processing...</span>
</button>
</div>
</div>
</div>
</form>
</div>
</div>
@endif
@if ($showQrisPayment)
<div class="fixed inset-0 opacity-bg flex items-center justify-center z-[75]">
<div class="bg-white p-6 rounded-lg max-w-md w-full">
<h2 class="text-xl font-bold mb-4">Pembayaran QRIS</h2>
<div class="mb-4">
<p class="mb-2">Silakan scan QR code berikut untuk pembayaran:</p>
<img src="{{ $qrisImageUrl }}" alt="QRIS Payment Code"
class="w-full h-auto border border-gray-300">
</div>
<div class="flex justify-end space-x-3">
<button wire:click="$set('showQrisPayment', false)" class="px-4 py-2 bg-gray-300 rounded">
Batal
</button>
<button wire:click="confirmQrisPayment" class="px-4 py-2 bg-blue-500 text-white rounded">
Konfirmasi Pembayaran
</button>
</div>
</div>
</div>
@endif
{{-- Notifikasi (dipindahkan ke x-data root) --}}
<div x-show="notification" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform translate-y-2"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-2"
class="fixed bottom-8 left-1/2 -translate-x-1/2 text-white px-4 py-2 rounded-lg shadow-lg z-[9999]"
:class="getNotificationClasses()" x-cloak>
<p x-text="message"></p>
</div>
@if (session('success'))
<div x-data="{ show: true, message: '{{ session('success') }}', getNotificationClasses() { return 'bg-green-500'; } }" x-show="show" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform translate-y-2" x-transition:enter-start="opacity-0 transform translate-y-2"
x-transition:enter-end="opacity-100 transform translate-y-0" x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave="transition ease-in duration-200" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform translate-y-0" x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-2" x-transition:leave-end="opacity-0 transform translate-y-2" x-init="setTimeout(() => show = false, 4000)"
class="fixed bottom-8 left-1/2 -translate-x-1/2 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg z-50"> class="fixed bottom-8 left-1/2 -translate-x-1/2 text-white px-4 py-2 rounded-lg shadow-lg z-[9999]"
:class="getNotificationClasses()" x-cloak>
<p x-text="message"></p> <p x-text="message"></p>
</div> </div>
</div> @endif
</div> </div>
{{-- @push('scripts')
<script>
Livewire.on('startMidtransPayment', async (orderData) => {
try {
const response = await fetch("{{ route('midtrans.token') }}", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').getAttribute("content"),
},
body: JSON.stringify(orderData),
});
const { token } = await response.json();
snap.pay(token, {
onSuccess: function(result) {
Livewire.dispatch('midtransSuccess', result); // ini nama listener di Livewire
},
onPending: function(result) {
console.log("Pending:", result);
},
onError: function(result) {
console.error("Error pembayaran:", result);
}
});
} catch (error) {
console.error("Gagal memulai pembayaran:", error);
}
});
</script>
@endpush --}}

View File

@ -0,0 +1,63 @@
<div class="p-6 text-white">
<h2 class="text-xl font-semibold mb-4">Daftar Pesanan untuk Dimasak</h2>
<div class="overflow-x-auto rounded-lg bg-[#1f1f1f]">
<table class="min-w-full text-sm text-white">
<thead class="bg-[#2c2c2c] text-gray-300 uppercase text-xs">
<tr>
<th class="px-4 py-3 text-left">Menu Pesanan</th>
<th class="px-4 py-3 text-left">Nama Item</th>
<th class="px-4 py-3 text-left">Meja</th>
<th class="px-4 py-3 text-left">Customer</th>
<th class="px-4 py-3 text-left">Waktu Pesan</th>
<th class="px-4 py-3 text-left">Status</th>
<th class="px-4 py-3 text-left">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($kitchenItems as $orderId => $items)
<tr class="border-t border-gray-700 hover:bg-[#2a2a2a] transition">
<td class="px-4 py-2 font-semibold">{{ $orderId }}</td>
<td class="px-4 py-2">
<ul class="list-disc list-inside">
@foreach ($items as $item)
<li>{{ $item['name'] }} (x{{ $item['quantity'] }})</li>
@endforeach
</ul>
</td>
<td class="px-4 py-2">{{ $items[0]['table_id'] }}</td>
<td class="px-4 py-2">{{ $items[0]['customer_name'] }}</td>
<td class="px-4 py-2">{{ \Carbon\Carbon::parse($item['updated_at'])->diffForHumans() }}</td>
<td class="px-4 py-2">
@php
$allCooked = collect($items)->every(fn($i) => $i['cooked']);
@endphp
@if ($allCooked)
<span class="text-green-400 font-medium">Done</span>
@else
<span class="text-orange-400 font-medium">Process</span>
@endif
</td>
<td class="px-4 py-2">
@if (!$allCooked)
<button wire:click="markAllAsCooked({{ $orderId }})"
class="bg-blue-600 hover:bg-blue-700 text-white text-xs px-3 py-1 rounded shadow">
Sudah Dimasak
</button>
@else
<span class="text-green-500 text-xs"> Semua sudah dimasak</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="6" class="px-4 py-6 text-center text-gray-400">Tidak ada pesanan yang perlu
dimasak.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,26 @@
@extends('components.layouts.base')
@section('title', 'Pembayaran Midtrans')
@section('content')
<h3>Memproses pembayaran... Mohon tunggu</h3>
<script src="https://app.sandbox.midtrans.com/snap/snap.js"
data-client-key="{{ config('services.midtrans.client_key') }}"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
snap.pay('{{ $snapToken }}', {
onSuccess: function(result) {
window.location.href = '/payment/success/' + result.order_id;
},
onPending: function(result) {
window.location.href = '/payment/pending?order_id=' + result.order_id;
},
onError: function(result) {
window.location.href = '/payment/error?order_id=' + result.order_id;
},
});
});
</script>
@endsection

View File

@ -0,0 +1,130 @@
<div class="p-6">
<h1 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">Daftar Pesanan</h1>
{{-- Filter Status --}}
<div class="mb-4">
<label for="filterStatus" class="block text-sm font-medium text-gray-700 dark:text-gray-200">
Filter berdasarkan Status:
</label>
<select wire:model.live="filterStatus" id="filterStatus"
class="w-full px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="all">Semua</option>
<option value="pending">Pending Transaksi</option>
<option value="pending_manual">Pending Transaksi Manual</option>
<option value="pending_midtrans">Pending Transaksi Midtrans</option>
<option value="confirmed">Sukses (Manual + Midtrans)</option>
<option value="confirmed_manual">Sukses Manual</option>
<option value="settlement_midtrans">Sukses Midtrans</option>
<option value="cancel">Dibatalkan</option>
<option value="expire">Kadaluarsa</option>
</select>
</div>
{{-- Daftar Pesanan --}}
<div class="bg-white dark:bg-gray-900 shadow overflow-hidden sm:rounded-lg">
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
@forelse ($orders as $order)
<li class="p-4 hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer"
wire:click="showOrderDetails({{ $order->id }})">
<div class="flex justify-between items-center">
<div>
<p class="text-lg font-semibold text-indigo-600 dark:text-indigo-400">
Order ID: {{ $order->id }}
</p>
<p class="text-sm text-gray-600 dark:text-gray-300">
Pelanggan: {{ $order->customer_name ?? 'Anonim' }}
</p>
<p class="text-sm text-gray-600 dark:text-gray-300">
Meja: {{ $order->table_id }}
</p>
</div>
<div class="text-right">
<p class="text-md font-medium text-gray-900 dark:text-white">
Total: Rp {{ number_format($order->total_amount, 2, ',', '.') }}
</p>
<p
class="text-sm
{{ $order->transaction_status === 'settlement' || $order->transaction_status === 'confirmed'
? 'text-green-500'
: ($order->transaction_status === 'pending' || $order->transaction_status === 'waiting_for_manual_confirmation'
? 'text-yellow-500'
: 'text-red-500') }}">
Status: {{ ucfirst(str_replace('_', ' ', $order->transaction_status)) }}
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">
{{ \Carbon\Carbon::parse($order->created_at)->timezone('Asia/Jakarta')->format('d M Y H:i:s') }}
</p>
</div>
</div>
</li>
@empty
<li class="p-4 text-gray-500 dark:text-gray-400 text-center">
Tidak ada pesanan ditemukan dengan status ini.
</li>
@endforelse
</ul>
</div>
{{-- Modal Detail Pesanan --}}
<div x-data="{ open: @entangle('selectedOrderId').live }" x-show="open"
class="fixed inset-0 bg-gray-600/80 dark:bg-black/70 z-50 flex items-center justify-center">
<div x-show="open" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90" x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
class="relative p-6 bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-lg w-full mx-auto my-auto text-gray-900 dark:text-gray-100">
@if ($selectedOrder)
<h3 class="text-xl font-bold mb-4">Detail Pesanan #{{ $selectedOrder->id }}</h3>
<p><strong>Nama Pelanggan:</strong> {{ $selectedOrder->customer_name ?? 'Anonim' }}</p>
<p><strong>Email Pelanggan:</strong> {{ $selectedOrder->customer_email ?? '-' }}</p>
<p><strong>ID Meja:</strong> {{ $selectedOrder->table_id }}</p>
<p><strong>Metode Pembayaran:</strong> {{ ucfirst($selectedOrder->payment_method) }}</p>
<p><strong>Status Transaksi:</strong> <span
class="font-semibold">{{ ucfirst(str_replace('_', ' ', $selectedOrder->transaction_status)) }}</span>
</p>
@if ($selectedOrder->midtrans_transaction_id)
<p><strong>Midtrans Transaksi ID:</strong> {{ $selectedOrder->midtrans_transaction_id }}</p>
@endif
<p><strong>Total Jumlah:</strong> Rp {{ number_format($selectedOrder->total_amount, 2, ',', '.') }}</p>
<p><strong>Waktu Pesan:</strong> {{ \Carbon\Carbon::parse($selectedOrder->created_at)->timezone('Asia/Jakarta')->format('d M Y H:i:s') }}</p>
<h4 class="text-lg font-semibold mt-4 mb-2">Item Pesanan:</h4>
<ul class="list-disc pl-5">
@forelse($selectedOrder->items as $item)
<li>
{{ $item->item_name }} ({{ $item->quantity }}x) - Rp
{{ number_format($item->item_price, 2, ',', '.') }} = Rp
{{ number_format($item->total_price, 2, ',', '.') }}
</li>
@empty
<li>Tidak ada item untuk pesanan ini.</li>
@endforelse
</ul>
<div class="mt-6 flex justify-end space-x-2">
{{-- Tombol Aksi Status --}}
@if (
$selectedOrder->transaction_status === 'pending' ||
$selectedOrder->transaction_status === 'waiting_for_manual_confirmation')
<button wire:click="updateOrderStatus({{ $selectedOrder->id }}, 'confirmed')"
class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
Tandai Terkonfirmasi
</button>
@endif
@if ($selectedOrder->transaction_status !== 'cancel' && $selectedOrder->transaction_status !== 'expire')
<button wire:click="updateOrderStatus({{ $selectedOrder->id }}, 'cancel')"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
Batalkan Pesanan
</button>
@endif
<button x-on:click="open = false"
class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded">
Tutup
</button>
</div>
@else
<p>Memuat detail pesanan...</p>
@endif
</div>
</div>
</div>

View File

@ -0,0 +1,79 @@
<div class="p-6">
<h1 class="text-2xl font-bold mb-6">Status Meja Real-time</h1>
{{-- Firebase Script (Pastikan sudah ada di layout utama atau tambahkan di sini) --}}
{{-- Jika Anda belum menyertakan Firebase SDK di halaman Anda, tambahkan ini di <head> atau di bagian bawah <body> layout utama --}}
{{-- <script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-app-compat.js"></script> --}}
{{-- <script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-database-compat.js"></script> --}}
<div x-data="{
firebaseConfig: {!! json_encode(config('services.firebase_client_config')) !!}, // Pastikan Anda memiliki config ini (lihat catatan di bawah)
initFirebase() {
if (!firebase.apps.length) {
firebase.initializeApp(this.firebaseConfig);
}
const db = firebase.database();
const tablesRef = db.ref('tables'); // Ganti 'tables' jika path di Firebase berbeda
tablesRef.on('value', (snapshot) => {
const data = snapshot.val();
const processedData = [];
if (data) {
// Firebase mengembalikan objek, kita ubah jadi array untuk Livewire
for (const tableId in data) {
if (data.hasOwnProperty(tableId)) {
processedData.push({ id: tableId, ...data[tableId] });
}
}
}
// Urutkan berdasarkan ID meja (misal: 'A1', 'A2', 'B1')
processedData.sort((a, b) => {
const idA = a.id.toUpperCase();
const idB = b.id.toUpperCase();
if (idA < idB) return -1;
if (idA > idB) return 1;
return 0;
});
// Dispatch event ke Livewire component dengan data terbaru
Livewire.dispatch('firebaseTablesUpdated', { data: processedData });
// console.log('Firebase data dispatched:', processedData); // Debugging
}, (error) => {
console.error('Firebase read failed: ' + error.code);
});
}
}" x-init="initFirebase()">
@if($tablesData->isEmpty())
<p class="text-gray-500 text-center">Memuat status meja dari Firebase...</p>
@else
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
@foreach ($tablesData as $table)
<div @class([
'p-4 rounded-lg shadow-md text-center',
'bg-green-100 border border-green-400' => $table['status'] === 'available',
'bg-red-100 border border-red-400' => $table['status'] === 'occupied',
'bg-yellow-100 border border-yellow-400' => $table['status'] === 'reserved', // Contoh status lain
'bg-gray-100 border border-gray-400' => !isset($table['status']), // Default jika status tidak ada
])>
<h2 class="text-xl font-semibold mb-2">Meja {{ $table['id'] }}</h2>
<p class="text-lg font-medium">Status:
<span @class([
'font-bold',
'text-green-700' => $table['status'] === 'available',
'text-red-700' => $table['status'] === 'occupied',
'text-yellow-700' => $table['status'] === 'reserved',
])>
{{ ucfirst($table['status'] ?? 'Tidak Diketahui') }}
</span>
</p>
@if(isset($table['reserved_by']) && $table['status'] === 'occupied')
<p class="text-sm text-gray-700 mt-1">Dipesan oleh: {{ $table['reserved_by'] }}</p>
@endif
{{-- Anda bisa menambahkan tombol aksi di sini, misalnya untuk mengubah status meja (jika staf bisa) --}}
</div>
@endforeach
</div>
@endif
</div>
</div>

View File

@ -1,25 +0,0 @@
@component('mail::message')
# Pesanan Anda Telah Diterima!
Terima kasih telah berbelanja di DFOOD. Berikut adalah detail pesanan Anda:
@if($meja)
{{-- Mengakses sebagai array. Hanya device_id yang tersedia. --}}
**Meja yang dipilih:** {{ $meja['device_id'] ?? $meja['id'] ?? 'N/A' }}
@endif
@component('mail::table')
| Item | Qty | Harga Satuan | Total Harga |
| :------------- | :-- | :----------- | :---------- |
@foreach($cartItems as $item)
| {{ $item['name'] }} | {{ $item['qty'] }} | Rp {{ number_format($item['price'], 0, ',', '.') }} | Rp {{ number_format($item['total_price'], 0, ',', '.') }} |
@endforeach
@endcomponent
### Total Pembayaran: Rp {{ number_format($cartTotal, 0, ',', '.') }}
Jika Anda memiliki pertanyaan, jangan ragu untuk menghubungi kami.
Terima kasih,<br>
{{ config('app.name') }}
@endcomponent

View File

@ -0,0 +1,4 @@
<x-layouts.app :title="__('Dashboard')">
{{-- Ini adalah tempat komponen Livewire BundleTable akan dirender --}}
@livewire('orders')
</x-layouts.app>

View File

@ -1,10 +1,22 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ $title ?? 'Laravel' }}</title> <title>{{ $title ?? 'DFOOD Auth' }}</title>
<link rel="preconnect" href="https://fonts.bunny.net"> <link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" /> <link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
<style>
input[type="radio"],
input[type="checkbox"],
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="image"],
select,
button {
cursor: pointer;
}
</style>
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
@fluxAppearance @fluxAppearance

View File

@ -0,0 +1,77 @@
@extends('components.layouts.base')
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="max-w-md mx-auto bg-white rounded-lg shadow-md p-6">
<h1 class="text-2xl font-bold text-center mb-6">Pembayaran</h1>
<div class="mb-4">
<p class="text-gray-600">Order ID: <span class="font-semibold">{{ $order->id }}</span></p>
<p class="text-gray-600">Transaction ID: <span class="font-semibold">{{ $transactionId }}</span></p>
</div>
<button id="pay-button" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition duration-200">
Bayar Sekarang
</button>
</div>
</div>
<script src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="{{ config('services.midtrans.client_key') }}"></script>
<script type="text/javascript">
document.getElementById('pay-button').onclick = function(){
snap.pay('{{ $snapToken }}', {
onSuccess: function(result){
console.log('Payment success:', result);
// Kirim data ke server
fetch('{{ route('payment.success') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify(result)
}).then(response => {
if (response.ok) {
window.location.href = '{{ route('payment.success') }}?order_id=' + result.order_id;
}
});
},
onPending: function(result){
console.log('Payment pending:', result);
fetch('{{ route('payment.pending') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify(result)
}).then(response => {
if (response.ok) {
window.location.href = '{{ route('payment.pending') }}?order_id=' + result.order_id;
}
});
},
onError: function(result){
console.log('Payment error:', result);
fetch('{{ route('payment.error') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify(result)
}).then(response => {
if (response.ok) {
window.location.href = '{{ route('payment.error') }}?order_id=' + result.order_id;
}
});
}
});
};
</script>
@endsection

View File

@ -0,0 +1,4 @@
@extends('layouts.app') {{-- atau layout admin --}}
@section('content')
@livewire('admin-tables')
@endsection

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ $title ?? 'Midtrans Page' }}</title>
@livewireStyles
@stack('styles')
</head>
<body class="bg-gray-50 text-gray-800 font-sans">
@livewire('midtrans-payment')
@livewireScripts
@stack('scripts')
</body>
</html>

View File

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Midtrans Snap Test</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<script type="text/javascript"
src="https://app.sandbox.midtrans.com/snap/snap.js"
data-client-key="{{ config('services.midtrans.client_key') }}"></script>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-lg text-center">
<h1 class="text-2xl font-bold mb-4">Uji Coba Midtrans Snap</h1>
<p class="mb-6 text-gray-700">Klik tombol di bawah untuk menampilkan pop-up pembayaran Midtrans.</p>
<button id="pay-button" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Bayar Sekarang!
</button>
<div id="after-payment-options" class="mt-8 hidden">
<p class="text-lg mb-4">Pembayaran telah diproses atau ditutup.</p>
<a href="/food-order" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded inline-block">
Mulai Order Baru
</a>
<button id="retest-button" class="bg-purple-500 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded inline-block ml-4">
Ulangi Tes Pembayaran
</button>
</div>
<script type="text/javascript">
const payButton = document.getElementById('pay-button');
const afterPaymentOptions = document.getElementById('after-payment-options');
const retestButton = document.getElementById('retest-button');
const snapToken = "{{ $snapToken }}";
function showAfterPaymentOptions() {
payButton.classList.add('hidden');
afterPaymentOptions.classList.remove('hidden');
}
if (snapToken) {
payButton.addEventListener('click', function () {
snap.pay(snapToken, {
enabledPayments: ['credit_card', 'bca_va', 'bni_va', 'bri_va', 'other_va'],
onSuccess: function(result){
alert("Pembayaran Berhasil! Cek konsol untuk detail.");
console.log(result);
showAfterPaymentOptions();
},
onPending: function(result){
alert("Pembayaran Pending! Cek konsol untuk detail.");
console.log(result);
showAfterPaymentOptions();
},
onError: function(result){
alert("Pembayaran Gagal! Cek konsol untuk detail.");
console.log(result);
showAfterPaymentOptions();
},
onClose: function(){
alert('Anda menutup pop-up tanpa menyelesaikan pembayaran.');
showAfterPaymentOptions();
}
});
});
retestButton.addEventListener('click', function() {
window.location.reload();
});
} else {
alert("Snap Token tidak ditemukan. Periksa log server Anda.");
console.error("Snap Token is empty or null.");
}
</script>
</div>
</body>
</html>

View File

@ -16,17 +16,17 @@
Route::get('reset-password/{token}', ResetPassword::class)->name('password.reset'); Route::get('reset-password/{token}', ResetPassword::class)->name('password.reset');
}); });
Route::middleware('auth')->group(function () { // Route::middleware('auth')->group(function () {
Route::get('verify-email', VerifyEmail::class) // // Route::get('verify-email', VerifyEmail::class)
->name('verification.notice'); // // ->name('verification.notice');
Route::get('verify-email/{id}/{hash}', VerifyEmailController::class) // // Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1']) // // ->middleware(['signed', 'throttle:6,1'])
->name('verification.verify'); // // ->name('verification.verify');
Route::get('confirm-password', ConfirmPassword::class) // // Route::get('confirm-password', ConfirmPassword::class)
->name('password.confirm'); // // ->name('password.confirm');
}); // });
Route::post('logout', App\Livewire\Actions\Logout::class) Route::post('logout', App\Livewire\Actions\Logout::class)
->name('logout'); ->name('logout');

View File

@ -1,14 +1,22 @@
<?php <?php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Log;
use App\Livewire\Settings\Appearance; use App\Livewire\Settings\Appearance;
use App\Livewire\Settings\Password; use App\Livewire\Settings\Password;
use App\Livewire\Settings\Profile; use App\Livewire\Settings\Profile;
use App\Livewire\FoodOrder; use App\Livewire\FoodOrder;
use App\Livewire\SelectTable; use App\Livewire\SelectTable;
use Illuminate\Support\Facades\Route; use App\Livewire\KitchenOrders;
use App\Livewire\Tables;
use App\Livewire\MidtransPayment;
use App\Http\Controllers\TypeItemsController; use App\Http\Controllers\TypeItemsController;
use App\Http\Controllers\ItemsController; use App\Http\Controllers\ItemsController;
use App\Http\Controllers\MejaController; use App\Http\Controllers\OrderController;
use App\Http\Controllers\PaymentController;
use Midtrans\Config;
use Midtrans\Snap;
Route::get('/refresh-csrf', function () { Route::get('/refresh-csrf', function () {
return response()->json(['csrf_token' => csrf_token()]); return response()->json(['csrf_token' => csrf_token()]);
@ -24,6 +32,23 @@
Route::get('/menu/{typeSlug?}', FoodOrder::class)->name('menu.byType'); Route::get('/menu/{typeSlug?}', FoodOrder::class)->name('menu.byType');
Route::get('/pilih-meja', SelectTable::class)->name('select.table'); Route::get('/pilih-meja', SelectTable::class)->name('select.table');
Route::get('/payment/{midtrans_transaction_id}', MidtransPayment::class)->name('midtrans.payment');
// Routes untuk hasil pembayaran (bisa pakai Controller biasa untuk hasil akhir)
// Route::get('/payment/success', [PaymentController::class, 'success'])->name('payment.success');
// Route::get('/payment/pending', [PaymentController::class, 'pending'])->name('payment.pending');
// Route::get('/payment/error', [PaymentController::class, 'error'])->name('payment.error');
Route::get('/payment/success/{order_id}', [PaymentController::class, 'success'])->name('payment.success');
// Route untuk webhook Midtrans (penting!)
Route::post('/payment/notification', [PaymentController::class, 'notification'])->name('payment.notification');
Route::post('/order/update-status', [OrderController::class, 'confirmOrder'])->name('order.confirm');
Route::put('/payment/update-status', [PaymentController::class, 'updateStatus']);
Route::view('dashboard', 'dashboard')->middleware(['auth', 'verified'])->name('dashboard'); Route::view('dashboard', 'dashboard')->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware(['auth'])->group(function () { Route::middleware(['auth'])->group(function () {
@ -33,11 +58,18 @@
Route::resource('typeitems',TypeItemsController::class); Route::resource('typeitems',TypeItemsController::class);
Route::resource('items',ItemsController::class); Route::resource('items',ItemsController::class);
Route::resource('tables',MejaController::class); // Route::resource('tables',MejaController::class);
Route::resource('orders',OrderController::class);
Route::get('/kitchen', KitchenOrders::class)->name('kitchen.index');
// Route::get('/admin/meja', function () {
// return view('tables');
// })->name('tables.index');
// Route::get('/admin/meja', Tables::class)->name('tables.index');
Route::get('settings/profile', Profile::class)->name('settings.profile'); Route::get('settings/profile', Profile::class)->name('settings.profile');
Route::get('settings/password', Password::class)->name('settings.password'); Route::get('settings/password', Password::class)->name('settings.password');
Route::get('settings/appearance', Appearance::class)->name('settings.appearance'); Route::get('settings/appearance', Appearance::class)->name('settings.appearance');
}); });
require __DIR__.'/auth.php'; require __DIR__.'/auth.php';

View File

@ -1,19 +0,0 @@
<?php
namespace Facades\Livewire\Features\SupportFileUploads;
use Illuminate\Support\Facades\Facade;
/**
* @mixin \Livewire\Features\SupportFileUploads\GenerateSignedUploadUrl
*/
class GenerateSignedUploadUrl extends Facade
{
/**
* Get the registered name of the component.
*/
protected static function getFacadeAccessor(): string
{
return 'Livewire\Features\SupportFileUploads\GenerateSignedUploadUrl';
}
}

View File

@ -0,0 +1,64 @@
<div class="p-6 text-white">
<h2 class="text-xl font-semibold mb-4">Daftar Pesanan untuk Dimasak</h2>
<div class="overflow-x-auto rounded-lg bg-[#1f1f1f]">
<table class="min-w-full text-sm text-white">
<thead class="bg-[#2c2c2c] text-gray-300 uppercase text-xs">
<tr>
<th class="px-4 py-3 text-left">Menu Pesanan</th>
<th class="px-4 py-3 text-left">Nama Item</th>
<th class="px-4 py-3 text-left">Meja</th>
<th class="px-4 py-3 text-left">Customer</th>
<th class="px-4 py-3 text-left">Waktu Pesan</th>
<th class="px-4 py-3 text-left">Status</th>
<th class="px-4 py-3 text-left">Aksi</th>
</tr>
</thead>
<tbody>
<!--[if BLOCK]><![endif]--><?php $__empty_1 = true; $__currentLoopData = $kitchenItems; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $orderId => $items): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr class="border-t border-gray-700 hover:bg-[#2a2a2a] transition">
<td class="px-4 py-2 font-semibold"><?php echo e($orderId); ?></td>
<td class="px-4 py-2">
<ul class="list-disc list-inside">
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $items; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<li><?php echo e($item['name']); ?> (x<?php echo e($item['quantity']); ?>)</li>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?><!--[if ENDBLOCK]><![endif]-->
</ul>
</td>
<td class="px-4 py-2"><?php echo e($items[0]['table_id']); ?></td>
<td class="px-4 py-2"><?php echo e($items[0]['customer_name']); ?></td>
<td class="px-4 py-2"><?php echo e(\Carbon\Carbon::parse($item['updated_at'])->diffForHumans()); ?></td>
<td class="px-4 py-2">
<?php
$allCooked = collect($items)->every(fn($i) => $i['cooked']);
?>
<!--[if BLOCK]><![endif]--><?php if($allCooked): ?>
<span class="text-green-400 font-medium">Done</span>
<?php else: ?>
<span class="text-orange-400 font-medium">Process</span>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</td>
<td class="px-4 py-2">
<!--[if BLOCK]><![endif]--><?php if(!$allCooked): ?>
<button wire:click="markAllAsCooked(<?php echo e($orderId); ?>)"
class="bg-blue-600 hover:bg-blue-700 text-white text-xs px-3 py-1 rounded shadow">
Sudah Dimasak
</button>
<?php else: ?>
<span class="text-green-500 text-xs"> Semua sudah dimasak</span>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="6" class="px-4 py-6 text-center text-gray-400">Tidak ada pesanan yang perlu
dimasak.</td>
</tr>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</tbody>
</table>
</div>
</div>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/livewire/kitchen-orders.blade.php ENDPATH**/ ?>

View File

@ -1,4 +1,35 @@
<div class="flex h-screen bg-gray-100 font-sans"> <div class="flex h-screen bg-gray-100 font-sans" x-data="{
notification: false,
message: '',
notificationType: 'success',
isProcessingButton: false,
getNotificationClasses() {
// Fungsi untuk mendapatkan kelas CSS berdasarkan tipe notifikasi
switch (this.notificationType) {
case 'success':
return 'bg-green-500';
case 'warning':
return 'bg-yellow-500';
case 'error':
return 'bg-red-500';
case 'info':
return 'bg-blue-500';
default:
return 'bg-gray-700';
}
},
// Inisialisasi Alpine.js
init() {
// Listener untuk notifikasi global dari Livewire Component
Livewire.on('notify', (data) => {
this.notification = true;
this.message = data.message;
this.notificationType = data.type || 'success';
setTimeout(() => this.notification = false, 4000);
});
}
}">
<div class="w-64 bg-white shadow-lg overflow-y-auto p-4 z-20"> <div class="w-64 bg-white shadow-lg overflow-y-auto p-4 z-20">
<h1 class="text-5xl font-bold mb-6 text-center text-gray-800">DFOOD</h1> <h1 class="text-5xl font-bold mb-6 text-center text-gray-800">DFOOD</h1>
@ -8,7 +39,7 @@
<li class="mb-2"> <li class="mb-2">
<a href="#" wire:click.prevent="filterByType(<?php echo e($type->id); ?>)" <a href="#" wire:click.prevent="filterByType(<?php echo e($type->id); ?>)"
class="block rounded overflow-hidden shadow-md transition-all duration-200 class="block rounded overflow-hidden shadow-md transition-all duration-200
<?php echo e($typeItemId == $type->id ? 'ring-2 ring-green-600 ring-offset-2' : 'hover:scale-105'); ?>"> <?php echo e($typeItemId == $type->id ? 'ring-2 ring-green-600 ring-offset-2' : 'hover:scale-105'); ?>">
<?php <?php
$imageUrl = $type->image_url; $imageUrl = $type->image_url;
if (!filter_var($imageUrl, FILTER_VALIDATE_URL)) { if (!filter_var($imageUrl, FILTER_VALIDATE_URL)) {
@ -78,104 +109,6 @@ class="fixed top-0 right-0 h-full w-96 bg-white shadow-xl z-30 flex flex-col tra
<p class="text-gray-500 text-center py-10">Keranjang kosong.</p> <p class="text-gray-500 text-center py-10">Keranjang kosong.</p>
<?php else: ?> <?php else: ?>
<div class="p-4 bg-white rounded-lg shadow-md mb-6">
<h3 class="text-xl font-semibold mb-4 text-gray-800">Pilih Meja Anda</h3>
<div class="mb-4 flex items-center">
<input type="checkbox" id="is-existing-customer" wire:model.live="isExistingCustomer"
class="mr-2 form-checkbox h-5 w-5 text-blue-600">
<label for="is-existing-customer" class="text-gray-700 text-sm font-bold">Saya sudah memesan
meja.</label>
</div>
<!--[if BLOCK]><![endif]--><?php if(!$isExistingCustomer): ?>
<div class="mb-4">
<label for="available-table-select" class="block text-gray-700 text-sm font-bold mb-2">Meja
Tersedia:</label>
<select id="available-table-select" wire:model.live="selectedTableId" wire:key="select-available"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
<?php echo e($tableIdFromUrl && $selectedOccupiedTableId === null ? 'disabled' : ''); ?>>
<option value="">-- Pilih Meja Tersedia --</option>
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $availableTables; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $table): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($table['id']); ?>">
<?php echo e($table['device_id']); ?> || TERSEDIA
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?><!--[if ENDBLOCK]><![endif]-->
</select>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['selectedTableId'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php elseif($isExistingCustomer): ?>
<div class="mb-4">
<label for="occupied-table-select"
class="block text-gray-700 text-sm font-bold mb-2">Meja Sudah Terisi (Konfirmasi
Nama):</label>
<select id="occupied-table-select" wire:model.live="selectedOccupiedTableId" wire:key="select-occupied"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
<?php echo e($tableIdFromUrl && $selectedTableId === null ? 'disabled' : ''); ?>>
<option value="">-- Pilih Meja Terisi --</option>
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $occupiedTables; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $table): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($table['id']); ?>">
<?php echo e($table['device_id']); ?> || Oleh: <?php echo e($table['reserved_by']); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?><!--[if ENDBLOCK]><![endif]-->
</select>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['selectedOccupiedTableId'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<!--[if BLOCK]><![endif]--><?php if($showCustomerNameInput): ?>
<div class="mb-4">
<label for="customer-name-input" class="block text-gray-700 text-sm font-bold mb-2">Nama
Pemesan:</label>
<input type="text" id="customer-name-input" wire:model.live="inputCustomerName"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Masukkan nama Anda" <?php echo e($isCustomerNameInputDisabled ? 'disabled' : ''); ?>>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['inputCustomerName'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<div class="mb-4">
<button wire:click="showMap"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Lihat Denah Meja
</button>
</div>
</div>
<ul class="divide-y divide-gray-200 mb-4" tabindex="0"> <ul class="divide-y divide-gray-200 mb-4" tabindex="0">
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $cartItems; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> <!--[if BLOCK]><![endif]--><?php $__currentLoopData = $cartItems; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<li class="py-3 flex justify-between items-center"> <li class="py-3 flex justify-between items-center">
@ -207,63 +140,14 @@ class="px-2 py-1 bg-green-100 text-green-700 rounded hover:bg-green-200">
<?php echo e(number_format($cartTotal, 0, ',', '.')); ?></div> <?php echo e(number_format($cartTotal, 0, ',', '.')); ?></div>
<!--[if BLOCK]><![endif]--><?php if($showEmailInput): ?>
<div class="mt-4 mb-4">
<label for="customerEmail" class="block text-gray-700 text-sm font-bold mb-2">Email Anda:</label>
<input type="email" id="customerEmail" wire:model.defer="customerEmail"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="nama@contoh.com">
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['customerEmail'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<div class="flex flex-col space-y-3 mt-4"> <div class="flex flex-col space-y-3 mt-4">
<button wire:click="checkout" <button wire:click="goToCheckoutDetails" type="button" wire:loading.attr="disabled"
class="bg-green-600 hover:bg-green-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-green-500 font-semibold text-lg" wire:loading.class="opacity-50"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50"> class="bg-green-600 hover:bg-green-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-green-500 font-semibold text-lg
<span wire:loading.remove wire:target="checkout">Bayar Sekarang (Midtrans)</span> disabled:bg-gray-400 disabled:cursor-not-allowed"
<span wire:loading wire:target="checkout">Processing...</span> <?php echo e(empty($cartItems) ? 'disabled' : ''); ?>>
</button> <span wire:loading.remove>Lanjut Pembayaran</span>
<span wire:loading>Processing...</span>
<!--[if BLOCK]><![endif]--><?php if(!$showEmailInput && empty(auth()->user()->email)): ?>
<button wire:click="$toggle('showEmailInput')"
class="bg-blue-600 hover:bg-blue-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 font-semibold text-lg"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="$toggle('showEmailInput')">Bayar Nanti (Kirim Email
Receipt)</span>
<span wire:loading wire:target="$toggle('showEmailInput')">Processing...</span>
</button>
<?php elseif($showEmailInput): ?>
<button wire:click="sendReceiptEmail"
class="bg-indigo-500 hover:bg-indigo-600 text-white font-bold py-2 px-4 rounded-lg"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="sendReceiptEmail">Kirim Email & Pesan</span>
<span wire:loading wire:target="sendReceiptEmail">Mengirim...</span>
</button>
<button wire:click="$toggle('showEmailInput')"
class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded-lg"
type="button">
Batal
</button>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<button wire:click="skipPayment"
class="bg-gray-600 hover:bg-gray-700 text-white py-2 rounded focus:outline-none focus:ring-2 focus:ring-gray-500 font-semibold text-lg"
type="button" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="skipPayment">Lewati Pembayaran</span>
<span wire:loading wire:target="skipPayment">Processing...</span>
</button> </button>
</div> </div>
</div> </div>
@ -271,13 +155,12 @@ class="bg-gray-600 hover:bg-gray-700 text-white py-2 rounded focus:outline-none
<!--[if BLOCK]><![endif]--><?php if($showCart): ?> <!--[if BLOCK]><![endif]--><?php if($showCart): ?>
<div class="fixed inset-0 z-20" wire:click="closeCart"> <div class="fixed inset-0 opacity-bg z-20" wire:click="closeCart">
<div class="absolute inset-0 blur-background"></div>
</div> </div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]--> <?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<div class="fixed bottom-4 right-4 z-10"> <div class="fixed bottom-4 right-4">
<button wire:click="openCart" <button wire:click="openCart"
class="bg-green-600 text-white rounded-full py-3 px-6 shadow-lg hover:bg-green-700 transition flex items-center gap-3"> class="bg-green-600 text-white rounded-full py-3 px-6 shadow-lg hover:bg-green-700 transition flex items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7" fill="none" viewBox="0 0 24 24" <svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7" fill="none" viewBox="0 0 24 24"
@ -285,21 +168,28 @@ class="bg-green-600 text-white rounded-full py-3 px-6 shadow-lg hover:bg-green-7
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" /> d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
</svg> </svg>
<span class="font-semibold text-xl">Keranjang (<?php echo e(array_sum($cart)); ?>)</span> <span class="font-semibold text-xl">Keranjang
<span class="bg-white text-green-600 rounded-full px-2 py-1 text-base ml-2">
<?php echo e(array_sum($cart)); ?>
</span>
</span>
</button> </button>
</div> </div>
<!--[if BLOCK]><![endif]--><?php if($showMapModal): ?> <!--[if BLOCK]><![endif]--><?php if($showMapModal): ?>
<div class="fixed inset-0 bg-black bg-opacity-75 z-[60] flex items-center justify-center" role="dialog" <div class="fixed inset-0 opacity-bg z-[71] flex items-center justify-center" role="dialog" aria-modal="true"
aria-modal="true" aria-labelledby="map-title"> aria-labelledby="map-title" x-show="$wire.showMapModal"
x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-90">
<div class="bg-white w-full max-w-2xl lg:max-w-4xl xl:max-w-5xl rounded shadow-lg p-6 relative"> <div class="bg-white w-full max-w-2xl lg:max-w-4xl xl:max-w-5xl rounded shadow-lg p-6 relative">
<h2 id="map-title" class="text-xl font-bold mb-4">Denah Meja Cafe</h2> <h2 id="map-title" class="text-xl font-bold mb-4">Denah Meja Restoran</h2>
<div class="relative w-full overflow-hidden border border-gray-300 rounded-lg" <div class="relative w-full overflow-hidden border border-gray-300 rounded-lg"
style="max-height: 80vh;"> style="max-height: 80vh;">
<img src="<?php echo e(asset('img/denah_cafe.jpg')); ?>" alt="Denah Cafe" <img src="<?php echo e(asset('img/denah-cafe.png')); ?>" alt="Denah Restoran"
class="w-full h-auto object-contain"> class="w-full h-auto object-contain max-h-[400px] mx-auto">
</div> </div>
<div class="mt-6 text-right"> <div class="mt-6 text-right">
@ -317,19 +207,292 @@ class="absolute top-2 right-2 text-gray-500 hover:text-gray-700 focus:outline-no
</div> </div>
</div> </div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]--> <?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<!--[if BLOCK]><![endif]--><?php if($showCheckoutDetailsModal): ?>
<div class="fixed inset-0 opacity-bg z-[70] text-gray-700 flex items-center justify-center" role="dialog"
aria-modal="true" aria-labelledby="checkout-details-title" x-show="$wire.showCheckoutDetailsModal"
x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 translate-y-4"
x-transition:enter-end="opacity-100 translate-y-0" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0" x-transition:leave-end="opacity-0 translate-y-4"
@click.away="$wire.closeCheckoutDetailsModal()" @transition:after-enter="isProcessingButton = false">
<div class="bg-white w-full max-w-2xl rounded-lg shadow-lg p-6 relative">
<h2 id="checkout-details-title" class="text-2xl font-bold mb-4 text-gray-800 text-center">Checkout
</h2>
<button wire:click="closeCheckoutDetailsModal"
class="absolute top-3 right-3 text-gray-500 hover:text-gray-700 focus:outline-none"
aria-label="Tutup" type="button">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<div x-data="{ notification: false, message: '' }" <form wire:submit.prevent="processOrderConfirmation">
x-on:notify.window="notification = true; message = $event.detail.message; setTimeout(() => notification = false, 3000)" <div class="flex flex-col md:flex-row gap-6">
x-cloak>
<div x-show="notification" x-transition:enter="transition ease-out duration-300"
<div class="flex-1 p-4 bg-white rounded-lg shadow-md">
<div class="mb-6">
<label class="block text-sm font-bold text-gray-700 mb-3">PESAN MEJA</label>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div
class="flex items-center p-3 rounded-md border border-gray-300 hover:bg-blue-50 cursor-pointer transition duration-200 ease-in-out
<?php if($isExistingCustomer == '0'): ?> bg-blue-100 border-blue-500 <?php endif; ?>">
<input type="radio" id="customer-new" name="customer_type"
wire:model.live="isExistingCustomer" value="0"
class="mr-3 h-5 w-5 text-blue-600 focus:ring-blue-500">
<label for="customer-new" class="text-gray-700 text-base font-medium">BELUM
MEMESAN</label>
</div>
<div
class="flex items-cente p-3 rounded-md border border-gray-300 hover:bg-blue-50 cursor-pointer transition duration-200 ease-in-out
<?php if($isExistingCustomer == '1'): ?> bg-blue-100 border-blue-500 <?php endif; ?>">
<input type="radio" id="customer-existing" name="customer_type"
wire:model.live="isExistingCustomer" value="1"
class="mr-3 h-5 w-5 text-blue-600 focus:ring-blue-500">
<label for="customer-existing"
class="text-gray-700 text-base font-medium">SUDAH MEMESAN</label>
</div>
</div>
</div>
<h3 class="text-md mb-2 font-bold">Pilih Meja Anda</h3>
<!--[if BLOCK]><![endif]--><?php if(!$isExistingCustomer): ?>
<div class="mb-4">
<label for="available-table-select-checkout"
class="block text-gray-700 text-sm font-bold mb-2">Meja Tersedia:</label>
<select id="available-table-select-checkout" wire:model.live="selectedTableId"
class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
<?php echo e($tableIdFromUrl && $selectedOccupiedTableId === null ? 'disabled' : ''); ?>>
<option value="">-- Pilih Meja Tersedia --</option>
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $availableTables; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $table): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($table['id']); ?>"><?php echo e($table['device_id']); ?> || TERSEDIA
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?><!--[if ENDBLOCK]><![endif]-->
</select>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['selectedTableId'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<!--[if BLOCK]><![endif]--><?php if($isExistingCustomer): ?>
<div class="mb-4">
<label for="occupied-table-select-checkout"
class="block text-gray-700 text-sm font-bold mb-2">Meja Sudah Terisi
(Konfirmasi Nama):</label>
<select id="occupied-table-select-checkout"
wire:model.live="selectedOccupiedTableId"
class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
<?php echo e($tableIdFromUrl && $selectedTableId === null ? 'disabled' : ''); ?>>
<option value="">-- Pilih Meja Terisi --</option>
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $occupiedTables; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $table): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($table['id']); ?>"><?php echo e($table['device_id']); ?> || Oleh:
<?php echo e($table['reserved_by']); ?></option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?><!--[if ENDBLOCK]><![endif]-->
</select>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['selectedOccupiedTableId'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<!--[if BLOCK]><![endif]--><?php if($showCustomerNameInput): ?>
<div class="mb-4">
<label for="customer-name-input-checkout"
class="block text-gray-700 text-sm font-bold mb-2">Nama Pemesan:</label>
<input type="text" id="customer-name-input-checkout"
wire:model.live="inputCustomerName"
class="shadow border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Masukkan nama Anda"
<?php echo e($isCustomerNameInputDisabled ? 'disabled' : ''); ?>>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['inputCustomerName'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<div class="mb-4">
<button wire:click="showMap" type="button"
class="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Lihat Denah Meja
</button>
</div>
</div>
<div class="flex-1 p-4 bg-white rounded-lg shadow-md">
<div class="mb-6 border rounded-lg">
<h3 class="text-md text-gray-800 font-bold">Pilih Metode Pembayaran:</h3>
<div>
<p class="text-sm mb-2">Pembayaran Otomatis</p>
<label class="flex items-center mb-2 cursor-pointer">
<input type="radio" wire:model.live="selectedPaymentMethod"
value="midtrans" class="form-radio h-5 w-5 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="currentColor" class="inline-block h-6 w-auto ml-2 mr-2">
<path d="M4.5 3.75a3 3 0 0 0-3 3v.75h21v-.75a3 3 0 0 0-3-3h-15Z" />
<path fill-rule="evenodd"
d="M22.5 9.75h-21v7.5a3 3 0 0 0 3 3h15a3 3 0 0 0 3-3v-7.5Zm-18 3.75a.75.75 0 0 1 .75-.75h6a.75.75 0 0 1 0 1.5h-6a.75.75 0 0 1-.75-.75Zm.75 2.25a.75.75 0 0 0 0 1.5h3a.75.75 0 0 0 0-1.5h-3Z"
clip-rule="evenodd" />
</svg>
<span class="text-gray-700 font-bold text-sm">Credit Card/Virtual
Account</span>
</label>
</div>
<div>
<p class="text-sm mb-2">Pembayaran Manual</p>
<label class="flex items-center cursor-pointer pb-2">
<input type="radio" wire:model.live="selectedPaymentMethod" value="cash"
class="form-radio h-5 w-5 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="currentColor" alt="Tunai Logo"
class="inline-block size-6 h-6 w-auto ml-2 mr-2">
<path d="M12 7.5a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5Z" />
<path fillRule="evenodd"
d="M1.5 4.875C1.5 3.839 2.34 3 3.375 3h17.25c1.035 0 1.875.84 1.875 1.875v9.75c0 1.036-.84 1.875-1.875 1.875H3.375A1.875 1.875 0 0 1 1.5 14.625v-9.75ZM8.25 9.75a3.75 3.75 0 1 1 7.5 0 3.75 3.75 0 0 1-7.5 0ZM18.75 9a.75.75 0 0 0-.75.75v.008c0 .414.336.75.75.75h.008a.75.75 0 0 0 .75-.75V9.75a.75.75 0 0 0-.75-.75h-.008ZM4.5 9.75A.75.75 0 0 1 5.25 9h.008a.75.75 0 0 1 .75.75v.008a.75.75 0 0 1-.75.75H5.25a.75.75 0 0 1-.75-.75V9.75Z"
clipRule="evenodd" />
<path
d="M2.25 18a.75.75 0 0 0 0 1.5c5.4 0 10.63.722 15.6 2.075 1.19.324 2.4-.558 2.4-1.82V18.75a.75.75 0 0 0-.75-.75H2.25Z" />
</svg>
<span class="text-gray-700 font-bold text-sm">Tunai</span>
</label>
<label class="flex items-center cursor-pointer">
<input type="radio" wire:model.live="selectedPaymentMethod" value="qris"
class="form-radio h-5 w-5 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="currentColor" class="inline-block h-6 w-auto ml-2 mr-2 size-6">
<path fill-rule="evenodd"
d="M3 4.875C3 3.839 3.84 3 4.875 3h4.5c1.036 0 1.875.84 1.875 1.875v4.5c0 1.036-.84 1.875-1.875 1.875h-4.5A1.875 1.875 0 0 1 3 9.375v-4.5ZM4.875 4.5a.375.375 0 0 0-.375.375v4.5c0 .207.168.375.375.375h4.5a.375.375 0 0 0 .375-.375v-4.5a.375.375 0 0 0-.375-.375h-4.5Zm7.875.375c0-1.036.84-1.875 1.875-1.875h4.5C20.16 3 21 3.84 21 4.875v4.5c0 1.036-.84 1.875-1.875 1.875h-4.5a1.875 1.875 0 0 1-1.875-1.875v-4.5Zm1.875-.375a.375.375 0 0 0-.375.375v4.5c0 .207.168.375.375.375h4.5a.375.375 0 0 0 .375-.375v-4.5a.375.375 0 0 0-.375-.375h-4.5ZM6 6.75A.75.75 0 0 1 6.75 6h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75A.75.75 0 0 1 6 7.5v-.75Zm9.75 0A.75.75 0 0 1 16.5 6h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75ZM3 14.625c0-1.036.84-1.875 1.875-1.875h4.5c1.036 0 1.875.84 1.875 1.875v4.5c0 1.035-.84 1.875-1.875 1.875h-4.5A1.875 1.875 0 0 1 3 19.125v-4.5Zm1.875-.375a.375.375 0 0 0-.375.375v4.5c0 .207.168.375.375.375h4.5a.375.375 0 0 0 .375-.375v-4.5a.375.375 0 0 0-.375-.375h-4.5Zm7.875-.75a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm6 0a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75ZM6 16.5a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm9.75 0a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm-3 3a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Zm6 0a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 .75.75v.75a.75.75 0 0 1-.75.75h-.75a.75.75 0 0 1-.75-.75v-.75Z"
clip-rule="evenodd" />
</svg>
<span class="text-gray-700 font-bold text-sm">QRIS</span>
</label>
</div>
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['selectedPaymentMethod'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-2 block text-center"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<div class="mb-4 hidden">
<label for="customerEmail" class="block text-gray-800 text-sm font-bold mb-2">
Email Anda (Opsional):
</label>
<p class="text-gray-600 text-xs mb-2">
Email digunakan untuk menerima struk pesanan.
</p>
<input type="email" id="customerEmail" wire:model.live="customerEmail"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="nama@contoh.com">
<!--[if BLOCK]><![endif]--><?php $__errorArgs = ['customerEmail'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="text-red-500 text-sm mt-1"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<div class="text-center mt-6">
<div class="mb-4 text-right text-xl text-gray-900">Total: Rp
<?php echo e(number_format($cartTotal, 0, ',', '.')); ?></div>
<button wire:click="processOrderConfirmation"
class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-4 rounded focus:outline-none focus:shadow-outline disabled:opacity-50 disabled:cursor-not-allowed"
type="submit" wire:loading.attr="disabled" wire:loading.class="opacity-50">
<span wire:loading.remove wire:target="processOrderConfirmation">Bayar</span>
<span wire:loading wire:target="processOrderConfirmation">Processing...</span>
</button>
</div>
</div>
</div>
</form>
</div>
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<!--[if BLOCK]><![endif]--><?php if($showQrisPayment): ?>
<div class="fixed inset-0 opacity-bg flex items-center justify-center z-[75]">
<div class="bg-white p-6 rounded-lg max-w-md w-full">
<h2 class="text-xl font-bold mb-4">Pembayaran QRIS</h2>
<div class="mb-4">
<p class="mb-2">Silakan scan QR code berikut untuk pembayaran:</p>
<img src="<?php echo e($qrisImageUrl); ?>" alt="QRIS Payment Code"
class="w-full h-auto border border-gray-300">
</div>
<div class="flex justify-end space-x-3">
<button wire:click="$set('showQrisPayment', false)" class="px-4 py-2 bg-gray-300 rounded">
Batal
</button>
<button wire:click="confirmQrisPayment" class="px-4 py-2 bg-blue-500 text-white rounded">
Konfirmasi Pembayaran
</button>
</div>
</div>
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<div x-show="notification" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform translate-y-2"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-2"
class="fixed bottom-8 left-1/2 -translate-x-1/2 text-white px-4 py-2 rounded-lg shadow-lg z-[9999]"
:class="getNotificationClasses()" x-cloak>
<p x-text="message"></p>
</div>
<!--[if BLOCK]><![endif]--><?php if(session('success')): ?>
<div x-data="{ show: true, message: '<?php echo e(session('success')); ?>', getNotificationClasses() { return 'bg-green-500'; } }" x-show="show" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform translate-y-2" x-transition:enter-start="opacity-0 transform translate-y-2"
x-transition:enter-end="opacity-100 transform translate-y-0" x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave="transition ease-in duration-200" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 transform translate-y-0" x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform translate-y-2" x-transition:leave-end="opacity-0 transform translate-y-2" x-init="setTimeout(() => show = false, 4000)"
class="fixed bottom-8 left-1/2 -translate-x-1/2 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg z-50"> class="fixed bottom-8 left-1/2 -translate-x-1/2 text-white px-4 py-2 rounded-lg shadow-lg z-[9999]"
:class="getNotificationClasses()" x-cloak>
<p x-text="message"></p> <p x-text="message"></p>
</div> </div>
</div> <?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</div> </div>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/livewire/food-order.blade.php ENDPATH**/ ?> <?php /**PATH E:\!PROJECT\dfood-website\resources\views/livewire/food-order.blade.php ENDPATH**/ ?>

View File

@ -46,31 +46,31 @@
<?php switch ($variant): case ('outline'): ?> <?php switch ($variant): case ('outline'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon"> <svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"/> <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 0 0-16.536-1.84M7.5 14.25 5.106 5.272M6 20.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm12.75 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z"/>
</svg> </svg>
<?php break; ?> <?php break; ?>
<?php case ('solid'): ?> <?php case ('solid'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon"> <svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z" clip-rule="evenodd"/> <path d="M2.25 2.25a.75.75 0 0 0 0 1.5h1.386c.17 0 .318.114.362.278l2.558 9.592a3.752 3.752 0 0 0-2.806 3.63c0 .414.336.75.75.75h15.75a.75.75 0 0 0 0-1.5H5.378A2.25 2.25 0 0 1 7.5 15h11.218a.75.75 0 0 0 .674-.421 60.358 60.358 0 0 0 2.96-7.228.75.75 0 0 0-.525-.965A60.864 60.864 0 0 0 5.68 4.509l-.232-.867A1.875 1.875 0 0 0 3.636 2.25H2.25ZM3.75 20.25a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM16.5 20.25a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0Z"/>
</svg> </svg>
<?php break; ?> <?php break; ?>
<?php case ('mini'): ?> <?php case ('mini'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> <svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 5Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"/> <path d="M1 1.75A.75.75 0 0 1 1.75 1h1.628a1.75 1.75 0 0 1 1.734 1.51L5.18 3a65.25 65.25 0 0 1 13.36 1.412.75.75 0 0 1 .58.875 48.645 48.645 0 0 1-1.618 6.2.75.75 0 0 1-.712.513H6a2.503 2.503 0 0 0-2.292 1.5H17.25a.75.75 0 0 1 0 1.5H2.76a.75.75 0 0 1-.748-.807 4.002 4.002 0 0 1 2.716-3.486L3.626 2.716a.25.25 0 0 0-.248-.216H1.75A.75.75 0 0 1 1 1.75ZM6 17.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0ZM15.5 19a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"/>
</svg> </svg>
<?php break; ?> <?php break; ?>
<?php case ('micro'): ?> <?php case ('micro'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" data-slot="icon"> <svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M6.701 2.25c.577-1 2.02-1 2.598 0l5.196 9a1.5 1.5 0 0 1-1.299 2.25H2.804a1.5 1.5 0 0 1-1.3-2.25l5.197-9ZM8 4a.75.75 0 0 1 .75.75v3a.75.75 0 1 1-1.5 0v-3A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"/> <path d="M1.75 1.002a.75.75 0 1 0 0 1.5h1.835l1.24 5.113A3.752 3.752 0 0 0 2 11.25c0 .414.336.75.75.75h10.5a.75.75 0 0 0 0-1.5H3.628A2.25 2.25 0 0 1 5.75 9h6.5a.75.75 0 0 0 .73-.578l.846-3.595a.75.75 0 0 0-.578-.906 44.118 44.118 0 0 0-7.996-.91l-.348-1.436a.75.75 0 0 0-.73-.573H1.75ZM5 14a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM13 14a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/>
</svg> </svg>
<?php break; ?> <?php break; ?>
<?php endswitch; ?> <?php endswitch; ?>
<?php /**PATH E:\!PROJECT\dfood-website\vendor\livewire\flux\src/../stubs/resources/views/flux/icon/exclamation-triangle.blade.php ENDPATH**/ ?> <?php /**PATH E:\!PROJECT\dfood-website\vendor\livewire\flux\src/../stubs/resources/views/flux/icon/shopping-cart.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,38 @@
<?php if (isset($component)) { $__componentOriginal5863877a5171c196453bfa0bd807e410 = $component; } ?>
<?php if (isset($attributes)) { $__attributesOriginal5863877a5171c196453bfa0bd807e410 = $attributes; } ?>
<?php $component = Illuminate\View\AnonymousComponent::resolve(['view' => 'components.layouts.app','data' => ['title' => __('Dashboard')]] + (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag ? $attributes->all() : [])); ?>
<?php $component->withName('layouts.app'); ?>
<?php if ($component->shouldRender()): ?>
<?php $__env->startComponent($component->resolveView(), $component->data()); ?>
<?php if (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
<?php $attributes = $attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
<?php endif; ?>
<?php $component->withAttributes(['title' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(__('Dashboard'))]); ?>
<?php
$__split = function ($name, $params = []) {
return [$name, $params];
};
[$__name, $__params] = $__split('orders');
$__html = app('livewire')->mount($__name, $__params, 'lw-143918417-0', $__slots ?? [], get_defined_vars());
echo $__html;
unset($__html);
unset($__name);
unset($__params);
unset($__split);
if (isset($__slots)) unset($__slots);
?>
<?php echo $__env->renderComponent(); ?>
<?php endif; ?>
<?php if (isset($__attributesOriginal5863877a5171c196453bfa0bd807e410)): ?>
<?php $attributes = $__attributesOriginal5863877a5171c196453bfa0bd807e410; ?>
<?php unset($__attributesOriginal5863877a5171c196453bfa0bd807e410); ?>
<?php endif; ?>
<?php if (isset($__componentOriginal5863877a5171c196453bfa0bd807e410)): ?>
<?php $component = $__componentOriginal5863877a5171c196453bfa0bd807e410; ?>
<?php unset($__componentOriginal5863877a5171c196453bfa0bd807e410); ?>
<?php endif; ?>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/pages/back/orders/index.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,77 @@
<?php $attributes ??= new \Illuminate\View\ComponentAttributeBag;
$__newAttributes = [];
$__propNames = \Illuminate\View\ComponentAttributeBag::extractPropNames(([
'variant' => 'outline',
]));
foreach ($attributes->all() as $__key => $__value) {
if (in_array($__key, $__propNames)) {
$$__key = $$__key ?? $__value;
} else {
$__newAttributes[$__key] = $__value;
}
}
$attributes = new \Illuminate\View\ComponentAttributeBag($__newAttributes);
unset($__propNames);
unset($__newAttributes);
foreach (array_filter(([
'variant' => 'outline',
]), 'is_string', ARRAY_FILTER_USE_KEY) as $__key => $__value) {
$$__key = $$__key ?? $__value;
}
$__defined_vars = get_defined_vars();
foreach ($attributes->all() as $__key => $__value) {
if (array_key_exists($__key, $__defined_vars)) unset($$__key);
}
unset($__defined_vars); ?>
<?php
$classes = Flux::classes('shrink-0')
->add(match($variant) {
'outline' => '[:where(&)]:size-6',
'solid' => '[:where(&)]:size-6',
'mini' => '[:where(&)]:size-5',
'micro' => '[:where(&)]:size-4',
});
?>
<?php switch ($variant): case ('outline'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 21v-7.5a.75.75 0 0 1 .75-.75h3a.75.75 0 0 1 .75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349M3.75 21V9.349m0 0a3.001 3.001 0 0 0 3.75-.615A2.993 2.993 0 0 0 9.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 0 0 2.25 1.016c.896 0 1.7-.393 2.25-1.015a3.001 3.001 0 0 0 3.75.614m-16.5 0a3.004 3.004 0 0 1-.621-4.72l1.189-1.19A1.5 1.5 0 0 1 5.378 3h13.243a1.5 1.5 0 0 1 1.06.44l1.19 1.189a3 3 0 0 1-.621 4.72M6.75 18h3.75a.75.75 0 0 0 .75-.75V13.5a.75.75 0 0 0-.75-.75H6.75a.75.75 0 0 0-.75.75v3.75c0 .414.336.75.75.75Z"/>
</svg>
<?php break; ?>
<?php case ('solid'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
<path d="M5.223 2.25c-.497 0-.974.198-1.325.55l-1.3 1.298A3.75 3.75 0 0 0 7.5 9.75c.627.47 1.406.75 2.25.75.844 0 1.624-.28 2.25-.75.626.47 1.406.75 2.25.75.844 0 1.623-.28 2.25-.75a3.75 3.75 0 0 0 4.902-5.652l-1.3-1.299a1.875 1.875 0 0 0-1.325-.549H5.223Z"/>
<path fill-rule="evenodd" d="M3 20.25v-8.755c1.42.674 3.08.673 4.5 0A5.234 5.234 0 0 0 9.75 12c.804 0 1.568-.182 2.25-.506a5.234 5.234 0 0 0 2.25.506c.804 0 1.567-.182 2.25-.506 1.42.674 3.08.675 4.5.001v8.755h.75a.75.75 0 0 1 0 1.5H2.25a.75.75 0 0 1 0-1.5H3Zm3-6a.75.75 0 0 1 .75-.75h3a.75.75 0 0 1 .75.75v3a.75.75 0 0 1-.75.75h-3a.75.75 0 0 1-.75-.75v-3Zm8.25-.75a.75.75 0 0 0-.75.75v5.25c0 .414.336.75.75.75h3a.75.75 0 0 0 .75-.75v-5.25a.75.75 0 0 0-.75-.75h-3Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php case ('mini'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path d="M2.879 7.121A3 3 0 0 0 7.5 6.66a2.997 2.997 0 0 0 2.5 1.34 2.997 2.997 0 0 0 2.5-1.34 3 3 0 1 0 4.622-3.78l-.293-.293A2 2 0 0 0 15.415 2H4.585a2 2 0 0 0-1.414.586l-.292.292a3 3 0 0 0 0 4.243ZM3 9.032a4.507 4.507 0 0 0 4.5-.29A4.48 4.48 0 0 0 10 9.5a4.48 4.48 0 0 0 2.5-.758 4.507 4.507 0 0 0 4.5.29V16.5h.25a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75v-3.5a.75.75 0 0 0-.75-.75h-2.5a.75.75 0 0 0-.75.75v3.5a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1 0-1.5H3V9.032Z"/>
</svg>
<?php break; ?>
<?php case ('micro'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" data-slot="icon">
<path d="M4.5 7c.681 0 1.3-.273 1.75-.715C6.7 6.727 7.319 7 8 7s1.3-.273 1.75-.715A2.5 2.5 0 1 0 11.5 2h-7a2.5 2.5 0 0 0 0 5ZM6.25 8.097A3.986 3.986 0 0 1 4.5 8.5c-.53 0-1.037-.103-1.5-.29v4.29h-.25a.75.75 0 0 0 0 1.5h.5a.754.754 0 0 0 .138-.013A.5.5 0 0 0 3.5 14H6a.5.5 0 0 0 .5-.5v-3A.5.5 0 0 1 7 10h2a.5.5 0 0 1 .5.5v3a.5.5 0 0 0 .5.5h2.5a.5.5 0 0 0 .112-.013c.045.009.09.013.138.013h.5a.75.75 0 1 0 0-1.5H13V8.21c-.463.187-.97.29-1.5.29a3.986 3.986 0 0 1-1.75-.403A3.986 3.986 0 0 1 8 8.5a3.986 3.986 0 0 1-1.75-.403Z"/>
</svg>
<?php break; ?>
<?php endswitch; ?>
<?php /**PATH E:\!PROJECT\dfood-website\vendor\livewire\flux\src/../stubs/resources/views/flux/icon/building-storefront.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,26 @@
<?php $__env->startSection('title', 'Pembayaran Midtrans'); ?>
<?php $__env->startSection('content'); ?>
<h3>Memproses pembayaran... Mohon tunggu</h3>
<script src="https://app.sandbox.midtrans.com/snap/snap.js"
data-client-key="<?php echo e(config('services.midtrans.client_key')); ?>"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
snap.pay('<?php echo e($snapToken); ?>', {
onSuccess: function(result) {
window.location.href = '/payment/success/' + result.order_id;
},
onPending: function(result) {
window.location.href = '/payment/pending?order_id=' + result.order_id;
},
onError: function(result) {
window.location.href = '/payment/error?order_id=' + result.order_id;
},
});
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('components.layouts.base', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH E:\!PROJECT\dfood-website\resources\views/livewire/midtrans-payment.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Struk Pembayaran</title>
</head>
<body>
<h2>Terima kasih atas pesanan Anda!</h2>
<p><strong>Nama Customer:</strong> <?php echo e($order->customer_name); ?></p>
<p><strong>Meja:</strong> <?php echo e($order->table_name); ?></p>
<p><strong>Total Pembayaran:</strong> Rp<?php echo e(number_format($order->total, 0, ',', '.')); ?></p>
<p><strong>Metode:</strong> <?php echo e(ucfirst($order->payment_method)); ?></p>
<p>Pesanan Anda sedang diproses. Mohon tunjukkan bukti pembayaran ini ke kasir.</p>
<hr>
<p><small>Website Restoran - Jangan balas email ini.</small></p>
</body>
</html>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/emails/receipt.blade.php ENDPATH**/ ?>

View File

@ -179,16 +179,17 @@
<?php $component = $__componentOriginalda376aa217444bbd92367ba1444eb3b8; ?> <?php $component = $__componentOriginalda376aa217444bbd92367ba1444eb3b8; ?>
<?php unset($__componentOriginalda376aa217444bbd92367ba1444eb3b8); ?> <?php unset($__componentOriginalda376aa217444bbd92367ba1444eb3b8); ?>
<?php endif; ?> <?php endif; ?>
<?php if (isset($component)) { $__componentOriginalda376aa217444bbd92367ba1444eb3b8 = $component; } ?> <?php if (isset($component)) { $__componentOriginalda376aa217444bbd92367ba1444eb3b8 = $component; } ?>
<?php if (isset($attributes)) { $__attributesOriginalda376aa217444bbd92367ba1444eb3b8 = $attributes; } ?> <?php if (isset($attributes)) { $__attributesOriginalda376aa217444bbd92367ba1444eb3b8 = $attributes; } ?>
<?php $component = Illuminate\View\AnonymousComponent::resolve(['view' => 'e60dd9d2c3a62d619c9acb38f20d5aa5::navlist.item','data' => ['icon' => 'lock-closed','href' => route('tables.index'),'current' => request()->routeIs('tables.index'),'wire:navigate' => true]] + (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag ? $attributes->all() : [])); ?> <?php $component = Illuminate\View\AnonymousComponent::resolve(['view' => 'e60dd9d2c3a62d619c9acb38f20d5aa5::navlist.item','data' => ['icon' => 'shopping-cart','href' => route('orders.index'),'current' => request()->routeIs('orders.index'),'wire:navigate' => true]] + (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag ? $attributes->all() : [])); ?>
<?php $component->withName('flux::navlist.item'); ?> <?php $component->withName('flux::navlist.item'); ?>
<?php if ($component->shouldRender()): ?> <?php if ($component->shouldRender()): ?>
<?php $__env->startComponent($component->resolveView(), $component->data()); ?> <?php $__env->startComponent($component->resolveView(), $component->data()); ?>
<?php if (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag): ?> <?php if (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
<?php $attributes = $attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?> <?php $attributes = $attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
<?php endif; ?> <?php endif; ?>
<?php $component->withAttributes(['icon' => 'lock-closed','href' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(route('tables.index')),'current' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(request()->routeIs('tables.index')),'wire:navigate' => true]); ?><?php echo e(__('Tabels')); ?> <?php echo $__env->renderComponent(); ?> <?php $component->withAttributes(['icon' => 'shopping-cart','href' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(route('orders.index')),'current' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(request()->routeIs('orders.index')),'wire:navigate' => true]); ?><?php echo e(__('Orders')); ?> <?php echo $__env->renderComponent(); ?>
<?php endif; ?> <?php endif; ?>
<?php if (isset($__attributesOriginalda376aa217444bbd92367ba1444eb3b8)): ?> <?php if (isset($__attributesOriginalda376aa217444bbd92367ba1444eb3b8)): ?>
<?php $attributes = $__attributesOriginalda376aa217444bbd92367ba1444eb3b8; ?> <?php $attributes = $__attributesOriginalda376aa217444bbd92367ba1444eb3b8; ?>
@ -198,6 +199,26 @@
<?php $component = $__componentOriginalda376aa217444bbd92367ba1444eb3b8; ?> <?php $component = $__componentOriginalda376aa217444bbd92367ba1444eb3b8; ?>
<?php unset($__componentOriginalda376aa217444bbd92367ba1444eb3b8); ?> <?php unset($__componentOriginalda376aa217444bbd92367ba1444eb3b8); ?>
<?php endif; ?> <?php endif; ?>
<?php if (isset($component)) { $__componentOriginalda376aa217444bbd92367ba1444eb3b8 = $component; } ?>
<?php if (isset($attributes)) { $__attributesOriginalda376aa217444bbd92367ba1444eb3b8 = $attributes; } ?>
<?php $component = Illuminate\View\AnonymousComponent::resolve(['view' => 'e60dd9d2c3a62d619c9acb38f20d5aa5::navlist.item','data' => ['icon' => 'building-storefront','href' => route('kitchen.index'),'current' => request()->routeIs('kitchen.index'),'wire:navigate' => true]] + (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag ? $attributes->all() : [])); ?>
<?php $component->withName('flux::navlist.item'); ?>
<?php if ($component->shouldRender()): ?>
<?php $__env->startComponent($component->resolveView(), $component->data()); ?>
<?php if (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
<?php $attributes = $attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
<?php endif; ?>
<?php $component->withAttributes(['icon' => 'building-storefront','href' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(route('kitchen.index')),'current' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(request()->routeIs('kitchen.index')),'wire:navigate' => true]); ?><?php echo e(__('Kitchen')); ?> <?php echo $__env->renderComponent(); ?>
<?php endif; ?>
<?php if (isset($__attributesOriginalda376aa217444bbd92367ba1444eb3b8)): ?>
<?php $attributes = $__attributesOriginalda376aa217444bbd92367ba1444eb3b8; ?>
<?php unset($__attributesOriginalda376aa217444bbd92367ba1444eb3b8); ?>
<?php endif; ?>
<?php if (isset($__componentOriginalda376aa217444bbd92367ba1444eb3b8)): ?>
<?php $component = $__componentOriginalda376aa217444bbd92367ba1444eb3b8; ?>
<?php unset($__componentOriginalda376aa217444bbd92367ba1444eb3b8); ?>
<?php endif; ?>
<?php echo $__env->renderComponent(); ?> <?php echo $__env->renderComponent(); ?>
<?php endif; ?> <?php endif; ?>
<?php if (isset($__attributesOriginal8b1fe5c87f0876e7c101dbc6fe82a9a4)): ?> <?php if (isset($__attributesOriginal8b1fe5c87f0876e7c101dbc6fe82a9a4)): ?>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title><?php echo $__env->yieldContent('title', 'PEMBAYARAN MIDTRANS'); ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="<?php echo e(csrf_token()); ?>">
<?php echo \Livewire\Mechanisms\FrontendAssets\FrontendAssets::styles(); ?>
</head>
<body>
<?php echo $__env->yieldContent('content'); ?>
<?php echo $__env->yieldPushContent('scripts'); ?>
<?php echo \Livewire\Mechanisms\FrontendAssets\FrontendAssets::scripts(); ?>
</body>
</html>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/components/layouts/base.blade.php ENDPATH**/ ?>

View File

@ -9,26 +9,7 @@
<div class="absolute inset-0 bg-neutral-900"></div> <div class="absolute inset-0 bg-neutral-900"></div>
<a href="<?php echo e(route('dashboard')); ?>" class="relative z-20 flex items-center text-lg font-medium" wire:navigate> <a href="<?php echo e(route('dashboard')); ?>" class="relative z-20 flex items-center text-lg font-medium" wire:navigate>
<span class="flex h-10 w-10 items-center justify-center rounded-md"> <span class="flex h-10 w-10 items-center justify-center rounded-md">
<?php if (isset($component)) { $__componentOriginal159d6670770cb479b1921cea6416c26c = $component; } ?>
<?php if (isset($attributes)) { $__attributesOriginal159d6670770cb479b1921cea6416c26c = $attributes; } ?>
<?php $component = Illuminate\View\AnonymousComponent::resolve(['view' => 'components.app-logo-icon','data' => ['class' => 'me-2 h-7 fill-current text-white']] + (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag ? $attributes->all() : [])); ?>
<?php $component->withName('app-logo-icon'); ?>
<?php if ($component->shouldRender()): ?>
<?php $__env->startComponent($component->resolveView(), $component->data()); ?>
<?php if (isset($attributes) && $attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
<?php $attributes = $attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
<?php endif; ?>
<?php $component->withAttributes(['class' => 'me-2 h-7 fill-current text-white']); ?>
<?php echo $__env->renderComponent(); ?>
<?php endif; ?>
<?php if (isset($__attributesOriginal159d6670770cb479b1921cea6416c26c)): ?>
<?php $attributes = $__attributesOriginal159d6670770cb479b1921cea6416c26c; ?>
<?php unset($__attributesOriginal159d6670770cb479b1921cea6416c26c); ?>
<?php endif; ?>
<?php if (isset($__componentOriginal159d6670770cb479b1921cea6416c26c)): ?>
<?php $component = $__componentOriginal159d6670770cb479b1921cea6416c26c; ?>
<?php unset($__componentOriginal159d6670770cb479b1921cea6416c26c); ?>
<?php endif; ?>
</span> </span>
<?php echo e(config('app.name', 'Login')); ?> <?php echo e(config('app.name', 'Login')); ?>

View File

@ -1,40 +0,0 @@
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">Pilih Meja Anda</h1>
<!--[if BLOCK]><![endif]--><?php if(session()->has('message')): ?>
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline"><?php echo e(session('message')); ?></span>
</div>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<div class="relative mb-8">
<img src="<?php echo e(asset('images/denah-contoh.png')); ?>" alt="Denah Restoran" class="w-full h-auto rounded-lg shadow-lg">
<!--[if BLOCK]><![endif]--><?php $__currentLoopData = $availableTables; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $table): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<button wire:click="selectTable('<?php echo e($table['id']); ?>')"
class="absolute bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-full shadow-lg"
style="top: <?php echo e(rand(10, 80)); ?>%; left: <?php echo e(rand(10, 80)); ?>%;">
<?php echo e($table['name']); ?>
</button>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?><!--[if ENDBLOCK]><![endif]-->
</div>
<h2 class="text-xl font-semibold mb-3">Daftar Meja Tersedia:</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!--[if BLOCK]><![endif]--><?php $__empty_1 = true; $__currentLoopData = $availableTables; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $table): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<div class="bg-white p-4 rounded-lg shadow-md flex justify-between items-center">
<span class="text-lg font-medium"><?php echo e($table['name']); ?></span>
<button wire:click="selectTable('<?php echo e($table['id']); ?>')"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Pilih
</button>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<p class="text-gray-500 col-span-full">Tidak ada meja yang tersedia saat ini.</p>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</div>
</div>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/livewire/select-table.blade.php ENDPATH**/ ?>

View File

@ -5,14 +5,30 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="<?php echo e(csrf_token()); ?>"> <meta name="csrf-token" content="<?php echo e(csrf_token()); ?>">
<meta name="midtrans-client-key" content="<?php echo e(config('services.midtrans.client_key')); ?>">
<meta name="midtrans-snap-url" content="<?php echo e(config('services.midtrans.snap_url')); ?>">
<title><?php echo e(config('app.name', 'DFOOD')); ?></title> <title><?php echo e(config('app.name', 'DFOOD')); ?></title>
<?php echo app('Illuminate\Foundation\Vite')(['resources/css/app.css', 'resources/js/app.js']); ?> <?php echo app('Illuminate\Foundation\Vite')(['resources/css/app.css', 'resources/js/app.js']); ?>
<script type="text/javascript" src="<?php echo e(config('services.midtrans.snap_url')); ?>" <style>
data-client-key="<?php echo e(config('services.midtrans.client_key')); ?>"></script> .opacity-bg {
background-color: rgba(0, 0, 0, 0.75);
}
input[type="radio"],
input[type="checkbox"],
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="image"],
select,
button {
cursor: pointer;
}
</style>
<?php echo \Livewire\Mechanisms\FrontendAssets\FrontendAssets::styles(); ?> <?php echo \Livewire\Mechanisms\FrontendAssets\FrontendAssets::styles(); ?>
</head> </head>
@ -22,124 +38,51 @@
<?php echo e($slot); ?> <?php echo e($slot); ?>
<script src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="<?php echo e(config('services.midtrans.client_key')); ?>"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<?php echo \Livewire\Mechanisms\FrontendAssets\FrontendAssets::scripts(); ?>
<script> <script>
document.addEventListener('livewire:initialized', function() { document.addEventListener('livewire:initialized', function() {
// Livewire Event Listener untuk notifikasi umum // Event Notifikasi (global notification)
Livewire.on('notify', (data) => { Livewire.on('notify', (data) => {
console.log('Notification:', data.message); console.log('🔔 Notification:', data.message);
}); window.dispatchEvent(new CustomEvent('notify', {
detail: {
// Livewire Event Listener untuk menampilkan Midtrans Snap Pop-up message: data.message
Livewire.on('midtransSnapToken', (event) => {
const snapToken = event.token;
console.log('Received Midtrans Snap Token:', snapToken);
if (typeof Snap !== 'undefined' && snapToken) {
try {
Snap.pay(snapToken, {
onSuccess: function(result) {
console.log('Payment success:', result);
Livewire.dispatch(
'paymentSuccess'); // Inform Livewire component
},
onPending: function(result) {
console.log('Payment pending:', result);
Livewire.dispatch('notify', {
message: 'Pembayaran menunggu konfirmasi Anda.'
});
},
onError: function(result) {
console.log('Payment error:', result);
let errorMessage = 'Terjadi kesalahan pembayaran.';
if (result.status_code === '400') {
errorMessage = 'Permintaan tidak valid. Mohon coba lagi.';
} else if (result.status_code === '401') {
errorMessage =
'Autentikasi Midtrans gagal. Hubungi administrator.';
}
Livewire.dispatch('notify', {
message: errorMessage
});
},
onClose: function() {
console.log('Payment closed by user');
Livewire.dispatch('notify', {
message: 'Pembayaran dibatalkan oleh pengguna.'
});
}
});
} catch (e) {
console.error("Error calling Snap.pay:", e);
Livewire.dispatch('notify', {
message: 'Terjadi kesalahan saat memulai pembayaran.'
});
} }
} else { }));
console.error(
'Midtrans Snap.js not loaded or Snap object is undefined, or snapToken is empty.'
);
Livewire.dispatch('notify', {
message: 'Sistem pembayaran tidak siap. Mohon refresh halaman.'
});
}
}); });
// Livewire Event Listener untuk update URL di browser history // Debug Log
Livewire.on('updateUrl', (data) => { Livewire.on('logToConsole', (data) => {
const newUrl = data.url; console.log('[Livewire Log]', data.message);
if (window.history.pushState) {
window.history.pushState({
path: newUrl
}, '', newUrl);
}
});
// Livewire hook untuk logging proses (hapus di production jika tidak perlu)
Livewire.hook('message.processed', (message, component) => {
if (component.fingerprint.name === 'food-order') {
console.log('FoodOrder component updated. Current cart:', component.serverMemo.data
.cart);
}
});
// Livewire Event Listener untuk menyembunyikan progress bar navigasi
Livewire.on('start-navigation', () => {
const progressBar = document.querySelector('.livewire-progress-bar');
if (progressBar) {
progressBar.style.display = 'none';
}
}); });
// Refresh CSRF Token tiap 30 menit
setInterval(() => { setInterval(() => {
fetch('/refresh-csrf', { fetch('/refresh-csrf', {
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest' 'X-Requested-With': 'XMLHttpRequest'
} }
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
const csrfMeta = document.querySelector('meta[name="csrf-token"]'); const csrfMeta = document.querySelector('meta[name="csrf-token"]');
if (csrfMeta) { if (csrfMeta) {
csrfMeta.setAttribute('content', data.csrf_token); csrfMeta.setAttribute('content', data.csrf_token);
console.log('🔁 CSRF token refreshed:', data.csrf_token);
} }
// Tidak perlu akses internal Livewire jika ingin aman dari perubahan API internal
console.log('CSRF token refreshed:', data.csrf_token);
}) })
.catch(error => { .catch(error => {
console.error('Error refreshing CSRF token:', error); console.error('❌ Gagal refresh CSRF token:', error);
}); });
}, 1800000); // 30 menit }, 1800000); // 30 menit
}); });
</script> </script>
<?php echo \Livewire\Mechanisms\FrontendAssets\FrontendAssets::scripts(); ?>
</body> </body>
</html> </html>

View File

@ -0,0 +1,138 @@
<div class="p-6">
<h1 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">Daftar Pesanan</h1>
<div class="mb-4">
<label for="filterStatus" class="block text-sm font-medium text-gray-700 dark:text-gray-200">
Filter berdasarkan Status:
</label>
<select wire:model.live="filterStatus" id="filterStatus"
class="w-full px-4 py-2 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="all">Semua</option>
<option value="pending">Pending Transaksi</option>
<option value="pending_manual">Pending Transaksi Manual</option>
<option value="pending_midtrans">Pending Transaksi Midtrans</option>
<option value="confirmed">Sukses (Manual + Midtrans)</option>
<option value="confirmed_manual">Sukses Manual</option>
<option value="settlement_midtrans">Sukses Midtrans</option>
<option value="cancel">Dibatalkan</option>
<option value="expire">Kadaluarsa</option>
</select>
</div>
<div class="bg-white dark:bg-gray-900 shadow overflow-hidden sm:rounded-lg">
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
<!--[if BLOCK]><![endif]--><?php $__empty_1 = true; $__currentLoopData = $orders; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $order): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<li class="p-4 hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer"
wire:click="showOrderDetails(<?php echo e($order->id); ?>)">
<div class="flex justify-between items-center">
<div>
<p class="text-lg font-semibold text-indigo-600 dark:text-indigo-400">
Order ID: <?php echo e($order->id); ?>
</p>
<p class="text-sm text-gray-600 dark:text-gray-300">
Pelanggan: <?php echo e($order->customer_name ?? 'Anonim'); ?>
</p>
<p class="text-sm text-gray-600 dark:text-gray-300">
Meja: <?php echo e($order->table_id); ?>
</p>
</div>
<div class="text-right">
<p class="text-md font-medium text-gray-900 dark:text-white">
Total: Rp <?php echo e(number_format($order->total_amount, 2, ',', '.')); ?>
</p>
<p
class="text-sm
<?php echo e($order->transaction_status === 'settlement' || $order->transaction_status === 'confirmed'
? 'text-green-500'
: ($order->transaction_status === 'pending' || $order->transaction_status === 'waiting_for_manual_confirmation'
? 'text-yellow-500'
: 'text-red-500')); ?>">
Status: <?php echo e(ucfirst(str_replace('_', ' ', $order->transaction_status))); ?>
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">
<?php echo e(\Carbon\Carbon::parse($order->created_at)->timezone('Asia/Jakarta')->format('d M Y H:i:s')); ?>
</p>
</div>
</div>
</li>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<li class="p-4 text-gray-500 dark:text-gray-400 text-center">
Tidak ada pesanan ditemukan dengan status ini.
</li>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</ul>
</div>
<div x-data="{ open: <?php if ((object) ('selectedOrderId') instanceof \Livewire\WireDirective) : ?>window.Livewire.find('<?php echo e($__livewire->getId()); ?>').entangle('<?php echo e('selectedOrderId'->value()); ?>')<?php echo e('selectedOrderId'->hasModifier('live') ? '.live' : ''); ?><?php else : ?>window.Livewire.find('<?php echo e($__livewire->getId()); ?>').entangle('<?php echo e('selectedOrderId'); ?>')<?php endif; ?>.live }" x-show="open"
class="fixed inset-0 bg-gray-600/80 dark:bg-black/70 z-50 flex items-center justify-center">
<div x-show="open" x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90" x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
class="relative p-6 bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-lg w-full mx-auto my-auto text-gray-900 dark:text-gray-100">
<!--[if BLOCK]><![endif]--><?php if($selectedOrder): ?>
<h3 class="text-xl font-bold mb-4">Detail Pesanan #<?php echo e($selectedOrder->id); ?></h3>
<p><strong>Nama Pelanggan:</strong> <?php echo e($selectedOrder->customer_name ?? 'Anonim'); ?></p>
<p><strong>Email Pelanggan:</strong> <?php echo e($selectedOrder->customer_email ?? '-'); ?></p>
<p><strong>ID Meja:</strong> <?php echo e($selectedOrder->table_id); ?></p>
<p><strong>Metode Pembayaran:</strong> <?php echo e(ucfirst($selectedOrder->payment_method)); ?></p>
<p><strong>Status Transaksi:</strong> <span
class="font-semibold"><?php echo e(ucfirst(str_replace('_', ' ', $selectedOrder->transaction_status))); ?></span>
</p>
<!--[if BLOCK]><![endif]--><?php if($selectedOrder->midtrans_transaction_id): ?>
<p><strong>Midtrans Transaksi ID:</strong> <?php echo e($selectedOrder->midtrans_transaction_id); ?></p>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<p><strong>Total Jumlah:</strong> Rp <?php echo e(number_format($selectedOrder->total_amount, 2, ',', '.')); ?></p>
<p><strong>Waktu Pesan:</strong> <?php echo e(\Carbon\Carbon::parse($selectedOrder->created_at)->timezone('Asia/Jakarta')->format('d M Y H:i:s')); ?></p>
<h4 class="text-lg font-semibold mt-4 mb-2">Item Pesanan:</h4>
<ul class="list-disc pl-5">
<!--[if BLOCK]><![endif]--><?php $__empty_1 = true; $__currentLoopData = $selectedOrder->items; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<li>
<?php echo e($item->item_name); ?> (<?php echo e($item->quantity); ?>x) - Rp
<?php echo e(number_format($item->item_price, 2, ',', '.')); ?> = Rp
<?php echo e(number_format($item->total_price, 2, ',', '.')); ?>
</li>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<li>Tidak ada item untuk pesanan ini.</li>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</ul>
<div class="mt-6 flex justify-end space-x-2">
<!--[if BLOCK]><![endif]--><?php if(
$selectedOrder->transaction_status === 'pending' ||
$selectedOrder->transaction_status === 'waiting_for_manual_confirmation'): ?>
<button wire:click="updateOrderStatus(<?php echo e($selectedOrder->id); ?>, 'confirmed')"
class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
Tandai Terkonfirmasi
</button>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<!--[if BLOCK]><![endif]--><?php if($selectedOrder->transaction_status !== 'cancel' && $selectedOrder->transaction_status !== 'expire'): ?>
<button wire:click="updateOrderStatus(<?php echo e($selectedOrder->id); ?>, 'cancel')"
class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
Batalkan Pesanan
</button>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
<button x-on:click="open = false"
class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded">
Tutup
</button>
</div>
<?php else: ?>
<p>Memuat detail pesanan...</p>
<?php endif; ?><!--[if ENDBLOCK]><![endif]-->
</div>
</div>
</div>
<?php /**PATH E:\!PROJECT\dfood-website\resources\views/livewire/orders.blade.php ENDPATH**/ ?>

View File

@ -1,76 +0,0 @@
<?php $attributes ??= new \Illuminate\View\ComponentAttributeBag;
$__newAttributes = [];
$__propNames = \Illuminate\View\ComponentAttributeBag::extractPropNames(([
'variant' => 'outline',
]));
foreach ($attributes->all() as $__key => $__value) {
if (in_array($__key, $__propNames)) {
$$__key = $$__key ?? $__value;
} else {
$__newAttributes[$__key] = $__value;
}
}
$attributes = new \Illuminate\View\ComponentAttributeBag($__newAttributes);
unset($__propNames);
unset($__newAttributes);
foreach (array_filter(([
'variant' => 'outline',
]), 'is_string', ARRAY_FILTER_USE_KEY) as $__key => $__value) {
$$__key = $$__key ?? $__value;
}
$__defined_vars = get_defined_vars();
foreach ($attributes->all() as $__key => $__value) {
if (array_key_exists($__key, $__defined_vars)) unset($$__key);
}
unset($__defined_vars); ?>
<?php
$classes = Flux::classes('shrink-0')
->add(match($variant) {
'outline' => '[:where(&)]:size-6',
'solid' => '[:where(&)]:size-6',
'mini' => '[:where(&)]:size-5',
'micro' => '[:where(&)]:size-4',
});
?>
<?php switch ($variant): case ('outline'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z"/>
</svg>
<?php break; ?>
<?php case ('solid'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M12 1.5a5.25 5.25 0 0 0-5.25 5.25v3a3 3 0 0 0-3 3v6.75a3 3 0 0 0 3 3h10.5a3 3 0 0 0 3-3v-6.75a3 3 0 0 0-3-3v-3c0-2.9-2.35-5.25-5.25-5.25Zm3.75 8.25v-3a3.75 3.75 0 1 0-7.5 0v3h7.5Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php case ('mini'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M10 1a4.5 4.5 0 0 0-4.5 4.5V9H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2h-.5V5.5A4.5 4.5 0 0 0 10 1Zm3 8V5.5a3 3 0 1 0-6 0V9h6Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php case ('micro'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php endswitch; ?>
<?php /**PATH E:\!PROJECT\dfood-website\vendor\livewire\flux\src/../stubs/resources/views/flux/icon/lock-closed.blade.php ENDPATH**/ ?>

View File

@ -1,11 +1,23 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><?php echo e($title ?? 'Laravel'); ?></title> <title><?php echo e($title ?? 'DFOOD Auth'); ?></title>
<link rel="preconnect" href="https://fonts.bunny.net"> <link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" /> <link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
<style>
input[type="radio"],
input[type="checkbox"],
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="image"],
select,
button {
cursor: pointer;
}
</style>
<?php echo app('Illuminate\Foundation\Vite')(['resources/css/app.css', 'resources/js/app.js']); ?> <?php echo app('Illuminate\Foundation\Vite')(['resources/css/app.css', 'resources/js/app.js']); ?>
<?php echo app('flux')->fluxAppearance(); ?> <?php echo app('flux')->fluxAppearance(); ?>

View File

@ -1,77 +0,0 @@
<?php $attributes ??= new \Illuminate\View\ComponentAttributeBag;
$__newAttributes = [];
$__propNames = \Illuminate\View\ComponentAttributeBag::extractPropNames(([
'variant' => 'outline',
]));
foreach ($attributes->all() as $__key => $__value) {
if (in_array($__key, $__propNames)) {
$$__key = $$__key ?? $__value;
} else {
$__newAttributes[$__key] = $__value;
}
}
$attributes = new \Illuminate\View\ComponentAttributeBag($__newAttributes);
unset($__propNames);
unset($__newAttributes);
foreach (array_filter(([
'variant' => 'outline',
]), 'is_string', ARRAY_FILTER_USE_KEY) as $__key => $__value) {
$$__key = $$__key ?? $__value;
}
$__defined_vars = get_defined_vars();
foreach ($attributes->all() as $__key => $__value) {
if (array_key_exists($__key, $__defined_vars)) unset($$__key);
}
unset($__defined_vars); ?>
<?php
$classes = Flux::classes('shrink-0')
->add(match($variant) {
'outline' => '[:where(&)]:size-6',
'solid' => '[:where(&)]:size-6',
'mini' => '[:where(&)]:size-5',
'micro' => '[:where(&)]:size-4',
});
?>
<?php switch ($variant): case ('outline'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z"/>
</svg>
<?php break; ?>
<?php case ('solid'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M5.25 2.25a3 3 0 0 0-3 3v4.318a3 3 0 0 0 .879 2.121l9.58 9.581c.92.92 2.39 1.186 3.548.428a18.849 18.849 0 0 0 5.441-5.44c.758-1.16.492-2.629-.428-3.548l-9.58-9.581a3 3 0 0 0-2.122-.879H5.25ZM6.375 7.5a1.125 1.125 0 1 0 0-2.25 1.125 1.125 0 0 0 0 2.25Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php case ('mini'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M4.5 2A2.5 2.5 0 0 0 2 4.5v3.879a2.5 2.5 0 0 0 .732 1.767l7.5 7.5a2.5 2.5 0 0 0 3.536 0l3.878-3.878a2.5 2.5 0 0 0 0-3.536l-7.5-7.5A2.5 2.5 0 0 0 8.38 2H4.5ZM5 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php case ('micro'): ?>
<svg <?php echo e($attributes->class($classes)); ?> data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M4.5 2A2.5 2.5 0 0 0 2 4.5v2.879a2.5 2.5 0 0 0 .732 1.767l4.5 4.5a2.5 2.5 0 0 0 3.536 0l2.878-2.878a2.5 2.5 0 0 0 0-3.536l-4.5-4.5A2.5 2.5 0 0 0 7.38 2H4.5ZM5 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"/>
</svg>
<?php break; ?>
<?php endswitch; ?>
<?php /**PATH E:\!PROJECT\dfood-website\vendor\livewire\flux\src/../stubs/resources/views/flux/icon/tag.blade.php ENDPATH**/ ?>

File diff suppressed because it is too large Load Diff