070825
This commit is contained in:
parent
9da05619c9
commit
d9440ad7bb
|
@ -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.
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class KitchenController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -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'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
});
|
});
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'timezone' => 'UTC',
|
'timezone' => 'Asia/Jakarta',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -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',
|
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
|
};
|
|
@ -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 |
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 --}}
|
||||||
|
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<x-layouts.app :title="__('Dashboard')">
|
||||||
|
{{-- Ini adalah tempat komponen Livewire BundleTable akan dirender --}}
|
||||||
|
@livewire('orders')
|
||||||
|
</x-layouts.app>
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
@extends('layouts.app') {{-- atau layout admin --}}
|
||||||
|
@section('content')
|
||||||
|
@livewire('admin-tables')
|
||||||
|
@endsection
|
|
@ -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>
|
|
@ -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>
|
|
@ -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');
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
@ -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)): ?>
|
||||||
|
|
|
@ -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**/ ?>
|
|
@ -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')); ?>
|
||||||
|
|
||||||
|
|
|
@ -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**/ ?>
|
|
|
@ -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>
|
||||||
|
|
|
@ -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**/ ?>
|
|
@ -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**/ ?>
|
|
|
@ -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(); ?>
|
||||||
|
|
||||||
|
|
|
@ -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**/ ?>
|
|
409390
storage/logs/laravel.log
409390
storage/logs/laravel.log
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue