Kodingan terkini terfresh terbaru terbaik
This commit is contained in:
parent
5a13e481a0
commit
7c88680e65
|
@ -27,7 +27,7 @@ class LoginController extends Controller
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/venue/capitano';
|
protected $redirectTo = '/home';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
|
@ -47,6 +47,17 @@ public function logout(Request $request)
|
||||||
$request->session()->invalidate();
|
$request->session()->invalidate();
|
||||||
$request->session()->regenerateToken();
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
return redirect('/venue/das');
|
session()->flash('error', 'Berhasil logout!');
|
||||||
|
return redirect('/home');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function authenticated(Request $request, $user)
|
||||||
|
{
|
||||||
|
session()->flash('success', 'Login berhasil!');
|
||||||
|
if ($user->role === 'admin') {
|
||||||
|
return redirect('/admin');
|
||||||
|
}
|
||||||
|
return redirect()->intended($this->redirectTo);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class RegisterController extends Controller
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/';
|
protected $redirectTo = '/home';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Venue;
|
||||||
|
use App\Models\Table;
|
||||||
|
use App\Models\Booking;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class AdminController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$venue = Venue::find(auth()->user()->venue_id);
|
||||||
|
|
||||||
|
$todayBookings = Booking::whereDate('created_at', now())
|
||||||
|
->whereHas('table', function ($query) use ($venue) {
|
||||||
|
$query->where('venue_id', $venue->id);
|
||||||
|
})
|
||||||
|
->count();
|
||||||
|
|
||||||
|
$totalTables = Table::where('venue_id', $venue->id)->count();
|
||||||
|
$usedTables = Table::where('venue_id', $venue->id)->where('status', 'booked')->count();
|
||||||
|
$availableTables = Table::where('venue_id', $venue->id)->where('status', 'available')->count();
|
||||||
|
|
||||||
|
$recentBookings = Booking::whereHas('table', function ($query) use ($venue) {
|
||||||
|
$query->where('venue_id', $venue->id);
|
||||||
|
})
|
||||||
|
->latest()
|
||||||
|
->take(5)
|
||||||
|
->with(['user', 'table'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('admin.dashboard', compact(
|
||||||
|
'venue',
|
||||||
|
'todayBookings',
|
||||||
|
'totalTables',
|
||||||
|
'usedTables',
|
||||||
|
'availableTables',
|
||||||
|
'recentBookings'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\Booking;
|
||||||
|
|
||||||
|
class BookingsController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$bookings = Booking::with(['table', 'user'])
|
||||||
|
->orderBy('start_time', 'desc')
|
||||||
|
->paginate(10);
|
||||||
|
|
||||||
|
return view('admin.bookings.index', compact('bookings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Table;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class TableController extends Controller
|
||||||
|
{
|
||||||
|
public function kelolaMeja()
|
||||||
|
{
|
||||||
|
$tables = Table::where('venue_id', auth()->user()->venue_id)->paginate(10);
|
||||||
|
return view('admin.tables.index', compact('tables'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function editTable($id)
|
||||||
|
{
|
||||||
|
$table = Table::findOrFail($id);
|
||||||
|
return view('admin.tables.edit', compact('table'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateTable(Request $request, $id)
|
||||||
|
{
|
||||||
|
$table = Table::findOrFail($id);
|
||||||
|
|
||||||
|
$table->update([
|
||||||
|
'name' => $request->name,
|
||||||
|
'brand' => $request->brand,
|
||||||
|
'status' => $request->status,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('admin.tables.index')->with('success', 'Data meja berhasil diperbarui.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\pages;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
use App\Models\Booking;
|
||||||
|
use App\Models\Table;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class BookingController extends Controller
|
||||||
|
{
|
||||||
|
public function store(Request $request) {
|
||||||
|
$request->validate([
|
||||||
|
'table_id' => 'required|exists:tables,id',
|
||||||
|
'start_time' => 'required|date',
|
||||||
|
'end_time' => 'required|date|after:start_time',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cek apakah meja sedang dibooking pada waktu tersebut
|
||||||
|
$conflict = Booking::where('table_id', $request->table_id)
|
||||||
|
->where(function($query) use ($request) {
|
||||||
|
$query->whereBetween('start_time', [$request->start_time, $request->end_time])
|
||||||
|
->orWhereBetween('end_time', [$request->start_time, $request->end_time])
|
||||||
|
->orWhere(function($query) use ($request) {
|
||||||
|
$query->where('start_time', '<', $request->start_time)
|
||||||
|
->where('end_time', '>', $request->end_time);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->where('status', '!=', 'cancelled') // skip booking yang dibatalkan
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($conflict) {
|
||||||
|
return response()->json(['message' => 'Meja sudah dibooking di jam tersebut'], 409);
|
||||||
|
}
|
||||||
|
|
||||||
|
Booking::create([
|
||||||
|
'table_id' => $request->table_id,
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
'start_time' => $request->start_time,
|
||||||
|
'end_time' => $request->end_time,
|
||||||
|
'status' => 'booked',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Booking berhasil']);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
// public function __construct()
|
||||||
{
|
// {
|
||||||
$this->middleware('auth');
|
// $this->middleware('auth');
|
||||||
}
|
// }
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
return view('pages.home');
|
return view('pages.home');
|
||||||
|
|
|
@ -3,67 +3,27 @@
|
||||||
namespace App\Http\Controllers\pages;
|
namespace App\Http\Controllers\pages;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Venue; // Pastikan model Venue di-import
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class VenueController extends Controller
|
class VenueController extends Controller
|
||||||
{
|
{
|
||||||
public function venue($venueName) {
|
public function venue($venueName) {
|
||||||
$venues = [
|
// Mengambil venue berdasarkan nama yang diberikan
|
||||||
'capitano' => [
|
$venue = Venue::where('name', 'like', '%' . ucfirst($venueName) . '%')->first();
|
||||||
'name' => 'Capitano Billiard',
|
|
||||||
'location' => 'Genteng',
|
// Jika venue tidak ditemukan, tampilkan error 404
|
||||||
'address' => 'Jl. Hasanudin No.II, Dusun Krajan, Genteng Wetan, Kec. Genteng, Kabupaten Banyuwangi',
|
if (!$venue) {
|
||||||
'price' => 30000,
|
|
||||||
'image' => 'images/billiard2.jpg',
|
|
||||||
'tables' => [
|
|
||||||
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 2', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 3', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 4', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 5', 'brand' => 'A Plus Premier', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 6', 'brand' => 'A Plus Premier', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 7', 'brand' => 'A Plus Premier', 'status' => 'Available'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'osing' => [
|
|
||||||
'name' => 'Osing Billiard Center',
|
|
||||||
'location' => 'Lidah',
|
|
||||||
'address' => 'Dusun Krajan, Kalirejo, Kec. Kabat, Kabupaten Banyuwangi',
|
|
||||||
'price' => 25000,
|
|
||||||
'image' => 'images/billiard3.jpg',
|
|
||||||
'tables' => [
|
|
||||||
['name' => 'Table 1', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 2', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 3', 'brand' => 'Xingjue', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 4', 'brand' => 'Xingjue', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 5', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 6', 'brand' => 'Xingjue', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 7', 'brand' => 'Xingjue', 'status' => 'Available'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'das' => [
|
|
||||||
'name' => 'DAS Game & Billiard',
|
|
||||||
'location' => 'Jalen',
|
|
||||||
'address' => 'Jl. Samiran, Jalen Parungan, Setail, Kec. Genteng, Kabupaten Banyuwangi',
|
|
||||||
'price' => 20000,
|
|
||||||
'image' => 'images/billiard4.jpg',
|
|
||||||
'tables' => [
|
|
||||||
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 2', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 3', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 4', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 5', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
|
||||||
['name' => 'Table 6', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 7', 'brand' => 'Cosmic', 'status' => 'Available'],
|
|
||||||
['name' => 'Table 8', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!isset($venues[$venueName])) {
|
|
||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('pages.venue', ['venue' => $venues[$venueName]]);
|
// Ambil tabel-tabel terkait dengan venue
|
||||||
|
$tables = $venue->tables;
|
||||||
|
|
||||||
|
// Mengirim data venue dan tabel ke view
|
||||||
|
return view('pages.venue', [
|
||||||
|
'venue' => $venue,
|
||||||
|
'tables' => $tables
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,5 +64,6 @@ class Kernel extends HttpKernel
|
||||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
|
'is_admin' => \App\Http\Middleware\IsAdmin::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class IsAdmin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (auth()->check() && auth()->user()->role === 'admin') {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403); // atau redirect('/login')
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Booking extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['table_id', 'user_id', 'start_time', 'end_time', 'status'];
|
||||||
|
|
||||||
|
public function table()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Table::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Table extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['venue_id', 'name', 'brand', 'status'];
|
||||||
|
|
||||||
|
public function venue()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Venue::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bookings()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Booking::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Venue extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['name', 'location', 'address', 'image'];
|
||||||
|
|
||||||
|
public function tables()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Table::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('venues', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name'); // Nama venue
|
||||||
|
$table->string('location'); // Lokasi venue (misalnya: Jakarta)
|
||||||
|
$table->string('address'); // Alamat venue
|
||||||
|
$table->integer('price');
|
||||||
|
$table->string('image')->nullable(); // Gambar venue (opsional)
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('venues');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?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('tables', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('venue_id')->constrained(); // Referensi ke tabel venues
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('brand');
|
||||||
|
$table->enum('status', ['Available', 'Booked'])->default('Available');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('tables');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?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('bookings', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('table_id')->constrained(); // Referensi ke tabel tables
|
||||||
|
$table->foreignId('user_id')->constrained(); // Referensi ke tabel users
|
||||||
|
$table->dateTime('start_time');
|
||||||
|
$table->dateTime('end_time');
|
||||||
|
$table->enum('status', ['Booked', 'Cancelled', 'Completed'])->default('Booked');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('bookings');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?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::table('users', function (Blueprint $table) {
|
||||||
|
// Hanya menambahkan kolom venue_id dengan foreign key
|
||||||
|
$table->unsignedBigInteger('venue_id')->nullable()->after('role');
|
||||||
|
$table->foreign('venue_id')->references('id')->on('venues')->onDelete('set null');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
// Menghapus foreign key dan kolom venue_id
|
||||||
|
if (Schema::hasColumn('users', 'venue_id')) {
|
||||||
|
$table->dropForeign(['venue_id']); // Menghapus foreign key constraint
|
||||||
|
$table->dropColumn('venue_id'); // Menghapus kolom venue_id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use App\Models\Venue;
|
||||||
|
use App\Models\Table;
|
||||||
|
|
||||||
|
class VenueSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$venues = [
|
||||||
|
'capitano' => [
|
||||||
|
'name' => 'Capitano Billiard',
|
||||||
|
'location' => 'Genteng',
|
||||||
|
'address' => 'Jl. Hasanudin No.II, Dusun Krajan, Genteng Wetan, Kec. Genteng, Kabupaten Banyuwangi',
|
||||||
|
'price' => 30000,
|
||||||
|
'image' => 'images/billiard2.jpg',
|
||||||
|
'tables' => [
|
||||||
|
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 2', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 3', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 4', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 5', 'brand' => 'A Plus Premier', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 6', 'brand' => 'A Plus Premier', 'status' => 'Booked'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'osing' => [
|
||||||
|
'name' => 'Osing Billiard Center',
|
||||||
|
'location' => 'Lidah',
|
||||||
|
'address' => 'Dusun Krajan, Kalirejo, Kec. Kabat, Kabupaten Banyuwangi',
|
||||||
|
'price' => 25000,
|
||||||
|
'image' => 'images/billiard3.jpg',
|
||||||
|
'tables' => [
|
||||||
|
['name' => 'Table 1', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 2', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 3', 'brand' => 'Xingjue', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 4', 'brand' => 'Xingjue', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 5', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 6', 'brand' => 'Xingjue', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 7', 'brand' => 'Xingjue', 'status' => 'Available'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'das' => [
|
||||||
|
'name' => 'DAS Game & Billiard',
|
||||||
|
'location' => 'Jalen',
|
||||||
|
'address' => 'Jl. Samiran, Jalen Parungan, Setail, Kec. Genteng, Kabupaten Banyuwangi',
|
||||||
|
'price' => 20000,
|
||||||
|
'image' => 'images/billiard4.jpg',
|
||||||
|
'tables' => [
|
||||||
|
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 2', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 3', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 4', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 5', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
||||||
|
['name' => 'Table 6', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 7', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
['name' => 'Table 8', 'brand' => 'Cosmic', 'status' => 'Booked'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($venues as $venueData) {
|
||||||
|
// Membuat venue baru
|
||||||
|
$venue = Venue::create([
|
||||||
|
'name' => $venueData['name'],
|
||||||
|
'location' => $venueData['location'],
|
||||||
|
'address' => $venueData['address'],
|
||||||
|
'price' => $venueData['price'],
|
||||||
|
'image' => $venueData['image'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Menambahkan tabel untuk setiap venue
|
||||||
|
foreach ($venueData['tables'] as $tableData) {
|
||||||
|
$venue->tables()->create($tableData); // Menambahkan meja ke venue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="p-4">
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Daftar Booking</h1>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto bg-white rounded shadow">
|
||||||
|
<table class="min-w-full table-auto">
|
||||||
|
<thead class="bg-gray-100">
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-2 text-left">User</th>
|
||||||
|
<th class="px-4 py-2 text-left">Meja</th>
|
||||||
|
<th class="px-4 py-2 text-left">Mulai</th>
|
||||||
|
<th class="px-4 py-2 text-left">Selesai</th>
|
||||||
|
<th class="px-4 py-2 text-left">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@forelse ($bookings as $booking)
|
||||||
|
<tr class="border-b">
|
||||||
|
<td class="px-4 py-2">{{ $booking->user->name }}</td>
|
||||||
|
<td class="px-4 py-2">{{ $booking->table->name }}</td>
|
||||||
|
<td class="px-4 py-2">{{ \Carbon\Carbon::parse($booking->start_time)->format('H:i d/m') }}</td>
|
||||||
|
<td class="px-4 py-2">{{ \Carbon\Carbon::parse($booking->end_time)->format('H:i d/m') }}</td>
|
||||||
|
<td class="px-4 py-2">
|
||||||
|
<span
|
||||||
|
class="text-sm px-2 py-1 rounded
|
||||||
|
{{ $booking->status === 'booked' ? 'bg-blue-200 text-blue-800' : ($booking->status === 'selesai' ? 'bg-green-200 text-green-800' : 'bg-red-200 text-red-800') }}">
|
||||||
|
{{ ucfirst($booking->status) }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="px-4 py-2 text-center text-gray-500">Belum ada data booking.</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,57 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="p-4">
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Admin {{ $venue->name }}</h1>
|
||||||
|
<p>Selamat datang, {{ auth()->user()->name }}!</p>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 my-6">
|
||||||
|
<a href="#" class="bg-blue-500 text-white p-4 rounded-lg">
|
||||||
|
<p class="text-sm">Jumlah Booking Hari Ini</p>
|
||||||
|
<p class="text-2xl font-bold">{{ $todayBookings }}</p>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="bg-gray-600 text-white p-4 rounded-lg">
|
||||||
|
<p class="text-sm">Total Meja</p>
|
||||||
|
<p class="text-2xl font-bold">{{ $totalTables }}</p>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="bg-red-600 text-white p-4 rounded-lg">
|
||||||
|
<p class="text-sm">Meja Sedang Digunakan</p>
|
||||||
|
<p class="text-2xl font-bold">{{ $usedTables }}</p>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="bg-green-600 text-white p-4 rounded-lg">
|
||||||
|
<p class="text-sm">Meja Tersedia</p>
|
||||||
|
<p class="text-2xl font-bold">{{ $availableTables }}</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="font-semibold text-lg mt-8 mb-2">Booking Terbaru</h2>
|
||||||
|
|
||||||
|
@if($recentBookings->isEmpty())
|
||||||
|
<p class="text-gray-500">Belum ada booking terbaru.</p>
|
||||||
|
@else
|
||||||
|
<div class="bg-white rounded shadow overflow-x-auto">
|
||||||
|
<table class="w-full table-auto">
|
||||||
|
<thead class="bg-gray-100">
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-2 text-left">Nama User</th>
|
||||||
|
<th class="px-4 py-2 text-left">Meja</th>
|
||||||
|
<th class="px-4 py-2 text-left">Waktu</th>
|
||||||
|
<th class="px-4 py-2 text-left">Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($recentBookings as $booking)
|
||||||
|
<tr class="border-t">
|
||||||
|
<td class="px-4 py-2">{{ $booking->user->name }}</td>
|
||||||
|
<td class="px-4 py-2">{{ $booking->table->name }}</td>
|
||||||
|
<td class="px-4 py-2">{{ \Carbon\Carbon::parse($booking->start_time)->format('H:i') }} -
|
||||||
|
{{ \Carbon\Carbon::parse($booking->end_time)->format('H:i') }}</td>
|
||||||
|
<td class="px-4 py-2 capitalize">{{ $booking->status }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,34 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="p-4">
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Edit Meja: {{ $table->name }}</h1>
|
||||||
|
|
||||||
|
<form action="{{ route('admin.tables.update', $table->id) }}" method="POST" class="space-y-4">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700">Nama Meja</label>
|
||||||
|
<input type="text" name="name" value="{{ $table->name }}" class="w-full border border-gray-300 p-2 rounded">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700">Merek</label>
|
||||||
|
<input type="text" name="brand" value="{{ $table->brand }}"
|
||||||
|
class="w-full border border-gray-300 p-2 rounded">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700">Status</label>
|
||||||
|
<select name="status" class="w-full border border-gray-300 p-2 rounded">
|
||||||
|
<option value="Available" {{ $table->status === 'Available' ? 'selected' : '' }}>Available</option>
|
||||||
|
<option value="Booked" {{ $table->status === 'Booked' ? 'selected' : '' }}>Booked</option>
|
||||||
|
<option value="Unavailable" {{ $table->status === 'Unavailable' ? 'selected' : '' }}>Unavailable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded">Simpan</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,48 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="p-4">
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Kelola Meja</h1>
|
||||||
|
|
||||||
|
<div class="overflow-x-auto bg-white shadow rounded-lg">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200 text-sm">
|
||||||
|
<thead class="bg-gray-100">
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-2 text-left font-semibold text-gray-600">Nama Meja</th>
|
||||||
|
<th class="px-4 py-2 text-left font-semibold text-gray-600">Merek</th>
|
||||||
|
<th class="px-4 py-2 text-left font-semibold text-gray-600">Status</th>
|
||||||
|
<th class="px-4 py-2 text-left font-semibold text-gray-600">Aksi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-100">
|
||||||
|
@forelse ($tables as $table)
|
||||||
|
<tr class="hover:bg-gray-50">
|
||||||
|
<td class="px-4 py-2">{{ $table->name }}</td>
|
||||||
|
<td class="px-4 py-2">{{ $table->brand }}</td>
|
||||||
|
<td class="px-4 py-2">
|
||||||
|
<span class="px-2 py-1 rounded-full text-xs font-medium
|
||||||
|
{{ $table->status === 'Available' ? 'bg-green-100 text-green-800' :
|
||||||
|
($table->status === 'Booked' ? 'bg-yellow-100 text-yellow-800' :
|
||||||
|
'bg-red-100 text-red-800') }}">
|
||||||
|
{{ $table->status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-2">
|
||||||
|
<a href="{{ route('admin.tables.edit', $table->id) }}"
|
||||||
|
class="text-blue-600 hover:underline">Edit</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="px-4 py-4 text-center text-gray-500">Belum ada data meja.</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
{{ $tables->links() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,83 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Admin Panel - {{ config('app.name') }}</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body x-data="{ sidebarOpen: true }" class="flex">
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<div :class="sidebarOpen ? 'w-64' : 'w-16'" class="bg-white border-r h-screen transition-all duration-300">
|
||||||
|
<div class="flex justify-between items-center p-4">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<span class="font-bold text-lg" x-show="sidebarOpen">Admin Panel</span>
|
||||||
|
</div>
|
||||||
|
<button @click="sidebarOpen = !sidebarOpen" class="text-gray-600 focus:outline-none">
|
||||||
|
<svg x-show="sidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" 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>
|
||||||
|
<svg x-show="!sidebarOpen" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav class="flex flex-col justify-between h-full mt-4">
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{ route('admin.dashboard') }}" class="block px-4 py-2 hover:bg-gray-100">📊 <span
|
||||||
|
x-show="sidebarOpen">Dashboard</span></a></li>
|
||||||
|
<li><a href="{{ route('admin.tables.index') }}" class="block px-4 py-2 hover:bg-gray-100">🪑 <span
|
||||||
|
x-show="sidebarOpen">Kelola
|
||||||
|
Meja</span></a></li>
|
||||||
|
<li><a href="{{ route('admin.bookings.index') }}" class="block px-4 py-2 hover:bg-gray-100">📅 <span
|
||||||
|
x-show="sidebarOpen">Daftar
|
||||||
|
Booking</span></a></li>
|
||||||
|
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100">👥 <span x-show="sidebarOpen">Data
|
||||||
|
User</span></a></li>
|
||||||
|
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100">🔔 <span
|
||||||
|
x-show="sidebarOpen">Notifikasi</span></a></li>
|
||||||
|
<li><a href="#" class="block px-4 py-2 hover:bg-gray-100">⚙️ <span
|
||||||
|
x-show="sidebarOpen">Pengaturan</span></a></li>
|
||||||
|
<li>
|
||||||
|
<div class="relative mt-4 px-4" x-data="{ open: false }">
|
||||||
|
<button @click="open = !open" class="flex items-center w-full text-left">
|
||||||
|
<span class="truncate" x-show="sidebarOpen">{{ auth()->user()->name }}</span>
|
||||||
|
<svg x-show="sidebarOpen" class="ml-1 h-4 w-4" fill="none" stroke="currentColor"
|
||||||
|
stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div x-show="open" @click.outside="open = false"
|
||||||
|
class="absolute left-4 mt-2 w-48 bg-white border rounded shadow-md z-10" x-cloak>
|
||||||
|
<a href="#" class="block px-4 py-2 text-sm hover:bg-gray-100">Edit Profil</a>
|
||||||
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit"
|
||||||
|
class="block w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-gray-100">Logout</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- User Dropdown -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<div class="flex-1 p-6 bg-gray-50 min-h-screen">
|
||||||
|
@yield('content')
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -5,6 +5,7 @@
|
||||||
<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">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
@vite('resources/css/app.css')
|
@vite('resources/css/app.css')
|
||||||
{{-- Font | Google Fonts --}}
|
{{-- Font | Google Fonts --}}
|
||||||
|
@ -148,11 +149,38 @@ class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 rounded">Daftar</but
|
||||||
|
|
||||||
|
|
||||||
<main class="pt-20">
|
<main class="pt-20">
|
||||||
@if(Auth::check())
|
@if (session('success') || session('error'))
|
||||||
<p>Halo, {{ Auth::user()->name }}</p>
|
<div id="floating-alert" style="
|
||||||
@else
|
position: fixed;
|
||||||
<p>Kamu belum login</p>
|
top: 30px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: {{ session('success') ? '#d1e7dd' : '#f8d7da' }};
|
||||||
|
color: {{ session('success') ? '#0f5132' : '#842029' }};
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: 0 3px 10px rgba(0,0,0,0.15);
|
||||||
|
z-index: 9999;
|
||||||
|
max-width: 300px;
|
||||||
|
text-align: center;
|
||||||
|
">
|
||||||
|
{{ session('success') ?? session('error') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
setTimeout(() => {
|
||||||
|
const alert = document.getElementById('floating-alert');
|
||||||
|
if (alert) {
|
||||||
|
alert.style.transition = 'opacity 0.5s ease';
|
||||||
|
alert.style.opacity = '0';
|
||||||
|
setTimeout(() => alert.remove(), 500);
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@yield('content')
|
@yield('content')
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class="flex items-center bg-[url('/public/images/map.jpg')] bg-cover bg-center p
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@foreach ($venue['tables'] as $table)
|
@foreach ($venue['tables'] as $table)
|
||||||
<div x-data="{ open: false }" class="border rounded-lg shadow-md p-4 mb-4">
|
<div x-data="booking(@json(auth()->check()))" class="border rounded-lg shadow-md p-4 mb-4">
|
||||||
<div class="flex items-center justify-between cursor-pointer" @click="open = !open">
|
<div class="flex items-center justify-between cursor-pointer" @click="open = !open">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="{{ asset('images/meja.jpg') }}" class="w-24">
|
<img src="{{ asset('images/meja.jpg') }}" class="w-24">
|
||||||
|
@ -47,37 +47,130 @@ class="flex items-center bg-[url('/public/images/map.jpg')] bg-cover bg-center p
|
||||||
|
|
||||||
<div x-show="open" x-collapse class="mt-4 p-4 border-t bg-gray-100 rounded-lg">
|
<div x-show="open" x-collapse class="mt-4 p-4 border-t bg-gray-100 rounded-lg">
|
||||||
<h4 class="font-semibold mb-2">Pilih Jam Booking:</h4>
|
<h4 class="font-semibold mb-2">Pilih Jam Booking:</h4>
|
||||||
<select class="w-full border p-2 rounded-lg">
|
<select class="w-full border p-2 rounded-lg" x-model="selectedTime">
|
||||||
<option>10:00</option>
|
<option value="">-- Pilih Jam --</option>
|
||||||
<option>11:00</option>
|
<template x-for="hour in getHoursInRange(9, 22)" :key="hour">
|
||||||
<option>12:00</option>
|
<option :value="hour + ':00'" x-text="hour + ':00'"></option>
|
||||||
<option>13:00</option>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
<button class="mt-3 px-4 py-2 bg-green-500 text-white rounded-lg w-full">Confirm Booking</button>
|
|
||||||
|
<h4 class="font-semibold mb-2 mt-4">Pilih Durasi Main:</h4>
|
||||||
|
<select class="w-full border p-2 rounded-lg" x-model="selectedDuration">
|
||||||
|
<option value="">-- Pilih Durasi --</option>
|
||||||
|
<option value="1">1 Jam</option>
|
||||||
|
<option value="2">2 Jam</option>
|
||||||
|
<option value="3">3 Jam</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button class="mt-3 px-4 py-2 bg-green-500 text-white rounded-lg w-full" :disabled="!selectedTime || !selectedDuration || isLoading"
|
||||||
|
@click="submitBooking('{{ $table['id'] }}', '{{ addslashes($table['name']) }}')">
|
||||||
|
<template x-if="isLoading">
|
||||||
|
<span>Loading...</span>
|
||||||
|
</template>
|
||||||
|
<template x-if="!isLoading">
|
||||||
|
<span>Confirm Booking</span>
|
||||||
|
</template>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{-- {{ dd($venue['location']) }} --}}
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function updateClock() {
|
function updateClock() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
// Konversi ke WIB (GMT+7)
|
|
||||||
const options = { timeZone: 'Asia/Jakarta', hour12: false };
|
const options = { timeZone: 'Asia/Jakarta', hour12: false };
|
||||||
const timeFormatter = new Intl.DateTimeFormat('id-ID', { ...options, hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
const timeFormatter = new Intl.DateTimeFormat('id-ID', { ...options, hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||||
|
|
||||||
document.getElementById('realTimeClock').textContent = timeFormatter.format(now);
|
document.getElementById('realTimeClock').textContent = timeFormatter.format(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update setiap detik
|
|
||||||
setInterval(updateClock, 1000);
|
setInterval(updateClock, 1000);
|
||||||
updateClock(); // Panggil sekali untuk langsung tampil
|
updateClock();
|
||||||
|
|
||||||
|
document.addEventListener('alpine:init', () => {
|
||||||
|
Alpine.data('booking', (isLoggedIn) => ({
|
||||||
|
isLoggedIn,
|
||||||
|
open: false,
|
||||||
|
selectedTime: '',
|
||||||
|
selectedDuration: '',
|
||||||
|
isLoading: false,
|
||||||
|
|
||||||
|
getHoursInRange(startHour, endHour) {
|
||||||
|
let hours = [];
|
||||||
|
for (let i = startHour; i <= endHour; i++) {
|
||||||
|
hours.push(i);
|
||||||
|
}
|
||||||
|
return hours;
|
||||||
|
},
|
||||||
|
|
||||||
|
submitBooking(tableId, tableName) {
|
||||||
|
if (!this.isLoggedIn) {
|
||||||
|
alert('Silahkan login terlebih dahulu untuk melakukan booking.');
|
||||||
|
}
|
||||||
|
const selectedTime = this.selectedTime;
|
||||||
|
const selectedDuration = this.selectedDuration;
|
||||||
|
|
||||||
|
if (!selectedTime || !selectedDuration) {
|
||||||
|
alert('Please select both time and duration');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validasi jam
|
||||||
|
const now = new Date();
|
||||||
|
const selectedDateTime = new Date();
|
||||||
|
const [selectedHour, selectedMinute] = selectedTime.split(':').map(Number);
|
||||||
|
selectedDateTime.setHours(selectedHour, selectedMinute, 0, 0);
|
||||||
|
|
||||||
|
if (selectedDateTime <= now) {
|
||||||
|
alert('Jam yang dipilih sudah lewat. Silakan pilih jam yang masih tersedia.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
// Hitung end time
|
||||||
|
const bookingStart = new Date();
|
||||||
|
bookingStart.setHours(selectedHour, selectedMinute, 0, 0);
|
||||||
|
const bookingEnd = new Date(bookingStart);
|
||||||
|
bookingEnd.setHours(bookingEnd.getHours() + parseInt(selectedDuration));
|
||||||
|
|
||||||
|
const endTimeFormatted = ('0' + bookingEnd.getHours()).slice(-2) + ':' + ('0' + bookingEnd.getMinutes()).slice(-2);
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
const start_time = `${today} ${selectedTime}`;
|
||||||
|
const end_time = `${today} ${endTimeFormatted}`;
|
||||||
|
|
||||||
|
// Kirim ke backend
|
||||||
|
fetch('/booking', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
table_id: tableId,
|
||||||
|
start_time: start_time,
|
||||||
|
end_time: end_time,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 409) throw new Error('Meja sudah dibooking.');
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
alert(`Booking ${tableName} berhasil! Meja akan diblokir dari ${selectedTime} hingga ${endTimeFormatted}`);
|
||||||
|
location.reload(); // Reload untuk update status meja
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
alert('Gagal booking: ' + err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
||||||
@endsection
|
@endsection
|
|
@ -2,9 +2,23 @@
|
||||||
|
|
||||||
use App\Http\Controllers\pages\HomeController;
|
use App\Http\Controllers\pages\HomeController;
|
||||||
use App\Http\Controllers\pages\VenueController;
|
use App\Http\Controllers\pages\VenueController;
|
||||||
|
use App\Http\Controllers\pages\BookingController;
|
||||||
|
use App\Http\Controllers\admin\BookingsController;
|
||||||
|
use App\Http\Controllers\admin\TableController;
|
||||||
|
use App\Http\Controllers\admin\AdminController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
Auth::routes();
|
Auth::routes();
|
||||||
Route::get('/', [HomeController::class, "index"])->name('index');
|
Route::get('/home', [HomeController::class, "index"])->name('index');
|
||||||
Route::get('/venue/{venueName}', [VenueController::class, "venue"])->name('venue');
|
Route::get('/venue/{venueName}', [VenueController::class, "venue"])->name('venue');
|
||||||
|
Route::post('/booking', [BookingController::class, 'store'])->name('booking.store');
|
||||||
|
Route::middleware(['auth', 'is_admin'])->prefix('admin')->group(function () {
|
||||||
|
Route::get('/', [AdminController::class, 'index'])->name('admin.dashboard');
|
||||||
|
Route::get('/bookings', [BookingsController::class, 'index'])->name('admin.bookings.index');
|
||||||
|
Route::get('/tables', [TableController::class, 'kelolaMeja'])->name('admin.tables.index');
|
||||||
|
|
||||||
|
Route::get('/tables/{id}/edit', [TableController::class, 'editTable'])->name('admin.tables.edit');
|
||||||
|
Route::put('/tables/{id}', [TableController::class, 'updateTable'])->name('admin.tables.update');
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue