Compare commits
10 Commits
0bb466573d
...
877162ea46
Author | SHA1 | Date |
---|---|---|
|
877162ea46 | |
|
f1761af8b5 | |
|
1e5e982a5f | |
|
d550527c36 | |
|
0657270b87 | |
|
f5f2056e86 | |
|
4cd4abccd7 | |
|
bbec273eea | |
|
3f5133a285 | |
|
cda7716cfa |
|
@ -59,7 +59,15 @@ public static function form(Form $form): Form
|
|||
MarkdownEditor::make('fasilitas')
|
||||
])->columnSpan(2),
|
||||
Section::make()->schema([
|
||||
FileUpload::make('gambar'),
|
||||
FileUpload::make('gambar')
|
||||
->acceptedFileTypes(['image/jpeg', 'image/png', 'image/jpg', 'image/webp'])
|
||||
->label('Gambar')
|
||||
->required()
|
||||
->helperText('Hanya file JPG, JPEG, PNG, atau WEBP yang diperbolehkan.')
|
||||
->validationMessages([
|
||||
'mimes' => 'Format file tidak didukung. Hanya JPG, JPEG, PNG, atau WEBP.',
|
||||
'mimetypes' => 'Format file tidak didukung. Hanya JPG, JPEG, PNG, atau WEBP.',
|
||||
]),
|
||||
Toggle::make('status')
|
||||
->required()
|
||||
->default(true),
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
use Filament\Forms\Components\BelongsToSelect;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Filament\Forms\Components\Modal;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ReservasiiResource extends Resource
|
||||
{
|
||||
|
@ -69,7 +71,6 @@ public static function form(Form $form): Form
|
|||
->options([
|
||||
'tunai' => 'Tunai',
|
||||
'transfer' => 'Transfer Bank',
|
||||
'wallet' => 'E-Wallet',
|
||||
])
|
||||
->required(),
|
||||
Radio::make('tipe_pembayaran')
|
||||
|
@ -78,7 +79,35 @@ public static function form(Form $form): Form
|
|||
'full' => 'Full',
|
||||
'dp' => 'DP',
|
||||
])
|
||||
->required(),
|
||||
->required()
|
||||
->default('full')
|
||||
->inline(),
|
||||
Select::make('status_pembayaran')
|
||||
->label('Status Pembayaran')
|
||||
->options([
|
||||
'pending' => 'Pending',
|
||||
'approved' => 'Approved',
|
||||
'rejected' => 'Rejected',
|
||||
])
|
||||
->required()
|
||||
->default('pending'),
|
||||
FileUpload::make('bukti_pembayaran')
|
||||
->label('Bukti Pembayaran')
|
||||
->image()
|
||||
->directory('bukti-pembayaran')
|
||||
->acceptedFileTypes(['image/jpeg', 'image/png', 'image/jpg', 'image/webp'])
|
||||
->helperText('Hanya file JPG, JPEG, PNG, atau WEBP yang diperbolehkan.')
|
||||
->validationMessages([
|
||||
'mimes' => 'Format file tidak didukung. Hanya JPG, JPEG, PNG, atau WEBP.',
|
||||
'mimetypes' => 'Format file tidak didukung. Hanya JPG, JPEG, PNG, atau WEBP.'])
|
||||
->visibility('public')
|
||||
->preserveFilenames()
|
||||
->downloadable()
|
||||
->openable()
|
||||
->deleteUploadedFileUsing(function ($file) {
|
||||
Storage::disk('public')->delete($file);
|
||||
})
|
||||
->columnSpanFull(),
|
||||
])
|
||||
])->columnSpan(1),
|
||||
|
||||
|
@ -100,7 +129,7 @@ public static function form(Form $form): Form
|
|||
DatePicker::make('tanggal')
|
||||
->label('Tanggal')
|
||||
->required(),
|
||||
Select::make('waktu')
|
||||
Select::make('waktu')
|
||||
->label('Pilih Jam')
|
||||
->options(
|
||||
collect(range(8, 23))->mapWithKeys(function ($hour) {
|
||||
|
@ -109,6 +138,9 @@ public static function form(Form $form): Form
|
|||
})->toArray()
|
||||
)
|
||||
->required()
|
||||
->disabled()
|
||||
->dehydrated()
|
||||
->default(fn ($record) => $record?->waktu),
|
||||
]),
|
||||
])->columnSpan(1),
|
||||
|
||||
|
@ -142,7 +174,7 @@ public static function form(Form $form): Form
|
|||
'cream' => 'Cream',
|
||||
'spotlight' => 'Spotlight'
|
||||
])
|
||||
->columnSpan(2), // Lebih kecil karena opsinya sedikit
|
||||
->columnSpan(2),
|
||||
|
||||
TextInput::make('jumlah')
|
||||
->numeric()
|
||||
|
@ -179,11 +211,33 @@ public static function form(Form $form): Form
|
|||
foreach ($repeaters as $key => $repeater){
|
||||
$total += $get("detail.{$key}.total_harga");
|
||||
}
|
||||
|
||||
// Hitung diskon jika ada promo
|
||||
$diskon = 0;
|
||||
if ($promoId = $get('promo_id')) {
|
||||
$promo = \App\Models\Promo::find($promoId);
|
||||
if ($promo && $promo->aktif) {
|
||||
if ($promo->tipe === 'fix') {
|
||||
$diskon = $promo->diskon;
|
||||
} else if ($promo->tipe === 'persen') {
|
||||
$diskon = ($total * $promo->diskon) / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$totalSetelahDiskon = $total - $diskon;
|
||||
$set('total', $total);
|
||||
return 'Rp ' . number_format($total, 0, ',', '.');
|
||||
$set('diskon', $diskon);
|
||||
$set('total_setelah_diskon', $totalSetelahDiskon);
|
||||
|
||||
return 'Rp ' . number_format($totalSetelahDiskon, 0, ',', '.');
|
||||
}),
|
||||
Hidden::make('total')
|
||||
->default(0)
|
||||
->default(0),
|
||||
Hidden::make('diskon')
|
||||
->default(0),
|
||||
Hidden::make('total_setelah_diskon')
|
||||
->default(0),
|
||||
])->columnSpanFull(),
|
||||
])
|
||||
]);
|
||||
|
@ -192,10 +246,10 @@ public static function form(Form $form): Form
|
|||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->defaultSort('created_at', 'desc')
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('nama')
|
||||
->label('Nama')
|
||||
->searchable(),
|
||||
->label('Nama'),
|
||||
|
||||
Tables\Columns\TextColumn::make('tanggal')
|
||||
->date('d F Y')
|
||||
|
@ -207,8 +261,7 @@ public static function table(Table $table): Table
|
|||
|
||||
Tables\Columns\TextColumn::make('detail.paketFoto.nama_paket_foto')
|
||||
->label('Paket Foto')
|
||||
->listWithLineBreaks()
|
||||
->searchable(),
|
||||
->listWithLineBreaks(),
|
||||
|
||||
Tables\Columns\TextColumn::make('total')
|
||||
->money('IDR'),
|
||||
|
@ -220,8 +273,19 @@ public static function table(Table $table): Table
|
|||
'dp' => 'danger',
|
||||
}),
|
||||
|
||||
Tables\Columns\TextColumn::make('metode_pembayaran')
|
||||
->badge(),
|
||||
Tables\Columns\TextColumn::make('status_pembayaran')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(fn (string $state): string => match (strtolower($state)) {
|
||||
'pending' => 'warning',
|
||||
'approved' => 'success',
|
||||
'rejected' => 'danger',
|
||||
}),
|
||||
|
||||
Tables\Columns\ImageColumn::make('bukti_pembayaran')
|
||||
->label('Bukti Pembayaran')
|
||||
->size(100),
|
||||
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\Filter::make('tanggal')
|
||||
|
@ -234,6 +298,13 @@ public static function table(Table $table): Table
|
|||
fn (Builder $query, $date): Builder => $query->whereDate('tanggal', $date),
|
||||
);
|
||||
}),
|
||||
Tables\Filters\SelectFilter::make('status_pembayaran')
|
||||
->options([
|
||||
'pending' => 'Pending',
|
||||
'approved' => 'Approved',
|
||||
'rejected' => 'Rejected',
|
||||
])
|
||||
->label('Status Pembayaran'),
|
||||
])
|
||||
->actions([
|
||||
ActionGroup::make([
|
||||
|
@ -281,20 +352,20 @@ public static function getRelations(): array
|
|||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
// Hitung jumlah reservasi dengan tipe pembayaran 'dp'
|
||||
$dpCount = static::getModel()::where('tipe_pembayaran', 'dp')->count();
|
||||
// Hitung jumlah reservasi dengan status pending
|
||||
$pendingCount = static::getModel()::where('status_pembayaran', 'pending')->count();
|
||||
|
||||
// Kembalikan jumlah jika ada, null jika tidak ada
|
||||
return $dpCount > 0 ? (string) $dpCount : null;
|
||||
return $pendingCount > 0 ? (string) $pendingCount : null;
|
||||
}
|
||||
|
||||
public static function getNavigationBadgeColor(): ?string
|
||||
{
|
||||
// Hitung jumlah reservasi dengan tipe pembayaran 'dp'
|
||||
$dpCount = static::getModel()::where('tipe_pembayaran', 'dp')->count();
|
||||
// Hitung jumlah reservasi dengan status pending
|
||||
$pendingCount = static::getModel()::where('status_pembayaran', 'pending')->count();
|
||||
|
||||
// Kembalikan warna merah jika ada reservasi DP
|
||||
return $dpCount > 0 ? 'danger' : null;
|
||||
// Kembalikan warna warning jika ada reservasi pending
|
||||
return $pendingCount > 0 ? 'warning' : null;
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
|
|
|
@ -27,12 +27,21 @@ protected function getHeaderActions(): array
|
|||
//}
|
||||
|
||||
public function getTabs(): array{
|
||||
return[
|
||||
null => \Filament\Resources\Components\Tab::make('Semua'),
|
||||
'Paket Pasangan' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Paket Pasangan')),
|
||||
'Paket 5 orang' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Paket 5 Orang')),
|
||||
'Widebox Couple' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Widebox Couple')),
|
||||
'Widebox Group' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Widebox Group')),
|
||||
$paketFotos = \App\Models\PaketFoto::orderBy('nama_paket_foto')->get();
|
||||
|
||||
$tabs = [
|
||||
null => \Filament\Resources\Components\Tab::make('Semua Paket')
|
||||
->badge(fn () => \App\Models\Reservasii::count())
|
||||
->icon('heroicon-o-photo'),
|
||||
];
|
||||
|
||||
foreach ($paketFotos as $paketFoto) {
|
||||
$tabs[$paketFoto->id] = \Filament\Resources\Components\Tab::make($paketFoto->nama_paket_foto)
|
||||
->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', $paketFoto->nama_paket_foto))
|
||||
->badge(fn () => \App\Models\Reservasii::whereRelation('detail.paketFoto', 'nama_paket_foto', $paketFoto->nama_paket_foto)->count())
|
||||
->icon('heroicon-o-camera');
|
||||
}
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,6 @@ public function table(Table $table): Table
|
|||
'full' => 'succes',
|
||||
'DP' => 'danger'
|
||||
}),
|
||||
TextColumn::make('metode_pembayaran')
|
||||
->label('Metode Pembayaran')
|
||||
->badge(),
|
||||
TextColumn::make('created_at')
|
||||
->label('Waktu Reservasi')
|
||||
])
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\PaketFoto;
|
||||
use Livewire\Component;
|
||||
|
||||
class AddPaketModal extends Component
|
||||
{
|
||||
public $search = '';
|
||||
public $pakets;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadPakets();
|
||||
}
|
||||
|
||||
public function loadPakets()
|
||||
{
|
||||
$this->pakets = PaketFoto::where('nama_paket_foto', 'like', '%' . $this->search . '%')
|
||||
->get();
|
||||
}
|
||||
|
||||
public function updatedSearch()
|
||||
{
|
||||
$this->loadPakets();
|
||||
}
|
||||
|
||||
public function addPaket($paketId)
|
||||
{
|
||||
$this->dispatch('paket-added', paketId: $paketId);
|
||||
$this->dispatch('close-modal');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.add-paket-modal');
|
||||
}
|
||||
}
|
|
@ -23,18 +23,17 @@ public function save(){
|
|||
]);
|
||||
|
||||
// save to database
|
||||
$user = User::create([
|
||||
User::create([
|
||||
'name' => $this->name,
|
||||
'email' => $this->email,
|
||||
'password' => Hash::make($this->password)
|
||||
]);
|
||||
|
||||
// login user
|
||||
auth()->login($user);
|
||||
|
||||
// redirect to home page
|
||||
return redirect()->intended();
|
||||
// set success message
|
||||
session()->flash('success', 'Registrasi berhasil! Silakan login untuk melanjutkan.');
|
||||
|
||||
// redirect to login page
|
||||
return redirect()->route('login');
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
|
|
|
@ -3,9 +3,58 @@
|
|||
namespace App\Livewire\Auth;
|
||||
|
||||
use Livewire\Component;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\User;
|
||||
|
||||
class ResetPasswordPage extends Component
|
||||
{
|
||||
public $token;
|
||||
#[Url]
|
||||
public $email;
|
||||
public $password;
|
||||
public $password_confirmation;
|
||||
|
||||
public function mount($token = null)
|
||||
{
|
||||
$this->token = $token ?? request()->route('token');
|
||||
$this->email = request()->query('email');
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$this->validate([
|
||||
'email' => 'required|email|exists:users,email',
|
||||
'password' => 'required|min:6|confirmed',
|
||||
]);
|
||||
|
||||
$status = Password::reset(
|
||||
[
|
||||
'email' => $this->email,
|
||||
'password' => $this->password,
|
||||
'password_confirmation' => $this->password_confirmation,
|
||||
'token' => $this->token,
|
||||
],
|
||||
function (User $user, string $password) {
|
||||
$password = $this->password;
|
||||
$user->forceFill([
|
||||
'password' => Hash::make($password)
|
||||
])->setRememberToken(Str::random(60));
|
||||
$user->save();
|
||||
event(new PasswordReset($user));
|
||||
}
|
||||
);
|
||||
|
||||
if ($status == Password::PASSWORD_RESET) {
|
||||
session()->flash('success', 'Password berhasil diubah!');
|
||||
return redirect('/login');
|
||||
} else {
|
||||
session()->flash('error', 'Terjadi kesalahan. Silakan coba lagi.');
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.auth.reset-password-page');
|
||||
|
|
|
@ -6,11 +6,16 @@
|
|||
use App\Models\Reservasii;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Livewire\Attributes\On;
|
||||
|
||||
#[Title('Booking - SiKolaself')]
|
||||
class BookingPage extends Component
|
||||
{
|
||||
public $paketfoto;
|
||||
public $selectedPakets = [];
|
||||
public $showModal = false;
|
||||
public $search = '';
|
||||
public $pakets;
|
||||
public $nama = '';
|
||||
public $tanggal = '';
|
||||
public $waktu = '';
|
||||
|
@ -27,13 +32,80 @@ public function mount($id = null)
|
|||
{
|
||||
if ($id) {
|
||||
$this->paketfoto = PaketFoto::findOrFail($id);
|
||||
$this->selectedPakets[] = [
|
||||
'id' => $this->paketfoto->id,
|
||||
'nama' => $this->paketfoto->nama_paket_foto,
|
||||
'harga' => $this->paketfoto->harga_paket_foto,
|
||||
'gambar' => $this->paketfoto->gambar,
|
||||
'warna' => ''
|
||||
];
|
||||
} else {
|
||||
$this->paketfoto = PaketFoto::first();
|
||||
}
|
||||
|
||||
// Set tanggal default ke hari ini
|
||||
$this->tanggal = now()->format('Y-m-d');
|
||||
$this->updateUnavailableTimes();
|
||||
$this->loadPakets();
|
||||
}
|
||||
|
||||
public function loadPakets()
|
||||
{
|
||||
$this->pakets = PaketFoto::where('nama_paket_foto', 'like', '%' . $this->search . '%')
|
||||
->get();
|
||||
}
|
||||
|
||||
public function updatedSearch()
|
||||
{
|
||||
$this->loadPakets();
|
||||
}
|
||||
|
||||
#[On('paket-added')]
|
||||
public function handlePaketAdded($paketId)
|
||||
{
|
||||
$paket = PaketFoto::find($paketId);
|
||||
if ($paket) {
|
||||
// Cek apakah paket sudah ada di selectedPakets
|
||||
$exists = collect($this->selectedPakets)->contains('id', $paket->id);
|
||||
if (!$exists) {
|
||||
$this->selectedPakets[] = [
|
||||
'id' => $paket->id,
|
||||
'nama' => $paket->nama_paket_foto,
|
||||
'harga' => $paket->harga_paket_foto,
|
||||
'gambar' => $paket->gambar,
|
||||
'warna' => ''
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addPaket($paketId)
|
||||
{
|
||||
$paket = PaketFoto::find($paketId);
|
||||
if ($paket) {
|
||||
// Cek apakah paket sudah ada di selectedPakets
|
||||
$exists = collect($this->selectedPakets)->contains('id', $paket->id);
|
||||
if (!$exists) {
|
||||
$this->selectedPakets[] = [
|
||||
'id' => $paket->id,
|
||||
'nama' => $paket->nama_paket_foto,
|
||||
'harga' => $paket->harga_paket_foto,
|
||||
'gambar' => $paket->gambar,
|
||||
'warna' => ''
|
||||
];
|
||||
}
|
||||
}
|
||||
$this->showModal = false;
|
||||
}
|
||||
|
||||
public function removePaket($index)
|
||||
{
|
||||
unset($this->selectedPakets[$index]);
|
||||
$this->selectedPakets = array_values($this->selectedPakets);
|
||||
}
|
||||
|
||||
public function updatePaketWarna($index, $warna)
|
||||
{
|
||||
$this->selectedPakets[$index]['warna'] = $warna;
|
||||
}
|
||||
|
||||
public function updatedTanggal()
|
||||
|
@ -46,8 +118,9 @@ public function updateUnavailableTimes()
|
|||
{
|
||||
if ($this->tanggal) {
|
||||
// Ambil waktu yang sudah dipesan dari database untuk tanggal yang dipilih
|
||||
// dan paket foto yang sama
|
||||
// dan paket foto yang sama, hanya yang statusnya approved
|
||||
$this->bookedTimes = Reservasii::where('tanggal', $this->tanggal)
|
||||
->where('status_pembayaran', 'approved') // Hanya ambil yang sudah approved
|
||||
->whereHas('detail', function($query) {
|
||||
$query->where('paket_foto_id', $this->paketfoto->id);
|
||||
})
|
||||
|
@ -117,11 +190,11 @@ public function applyPromo()
|
|||
|
||||
public function getTotalPriceProperty()
|
||||
{
|
||||
$total = $this->paketfoto->harga_paket_foto;
|
||||
$total = collect($this->selectedPakets)->sum('harga');
|
||||
if ($this->promoApplied) {
|
||||
$total -= $this->promoDiscount;
|
||||
}
|
||||
return max(0, $total); // Pastikan total tidak negatif
|
||||
return max(0, $total);
|
||||
}
|
||||
|
||||
public function placeOrder()
|
||||
|
@ -133,6 +206,7 @@ public function placeOrder()
|
|||
'warna' => 'required',
|
||||
'promo' => '',
|
||||
'tipe_pembayaran' => 'required',
|
||||
'selectedPakets' => 'required|array|min:1',
|
||||
], [
|
||||
'nama.required' => 'Nama lengkap harus diisi',
|
||||
'nama.min' => 'Nama lengkap minimal 3 karakter',
|
||||
|
@ -141,15 +215,15 @@ public function placeOrder()
|
|||
'waktu.required' => 'Waktu booking harus dipilih',
|
||||
'warna.required' => 'Background harus dipilih',
|
||||
'tipe_pembayaran.required' => 'Tipe pembayaran harus dipilih',
|
||||
'selectedPakets.required' => 'Pilih minimal satu paket foto',
|
||||
'selectedPakets.min' => 'Pilih minimal satu paket foto',
|
||||
]);
|
||||
|
||||
// Validasi waktu yang dipilih
|
||||
if (in_array($this->waktu, $this->unavailableTimes)) {
|
||||
$this->addError('waktu', 'Waktu yang dipilih tidak tersedia');
|
||||
return;
|
||||
}
|
||||
|
||||
// Membuat reservasi baru
|
||||
$reservasi = Reservasii::create([
|
||||
'user_id' => auth()->id(),
|
||||
'nama' => $this->nama,
|
||||
|
@ -158,22 +232,22 @@ public function placeOrder()
|
|||
'promo_id' => $this->promoData ? $this->promoData->id : null,
|
||||
'total' => $this->totalPrice,
|
||||
'tipe_pembayaran' => $this->tipe_pembayaran,
|
||||
'metode_pembayaran' => 'transfer', // Default transfer, bisa diubah sesuai pilihan
|
||||
'metode_pembayaran' => 'transfer',
|
||||
'status_pembayaran' => 'pending'
|
||||
]);
|
||||
|
||||
// Membuat detail reservasi
|
||||
$reservasi->detail()->create([
|
||||
'paket_foto_id' => $this->paketfoto->id,
|
||||
'warna' => $this->warna,
|
||||
'jumlah' => 1,
|
||||
'harga' => $this->paketfoto->harga_paket_foto,
|
||||
'total_harga' => $this->totalPrice,
|
||||
]);
|
||||
foreach ($this->selectedPakets as $paket) {
|
||||
$reservasi->detail()->create([
|
||||
'paket_foto_id' => $paket['id'],
|
||||
'warna' => $this->warna,
|
||||
'jumlah' => 1,
|
||||
'harga' => $paket['harga'],
|
||||
'total_harga' => $paket['harga'],
|
||||
]);
|
||||
}
|
||||
|
||||
// Tampilkan pesan sukses dan redirect
|
||||
session()->flash('message', 'Booking berhasil dibuat! Silahkan lakukan pembayaran sesuai metode yang dipilih.');
|
||||
session()->flash('booking_name', $this->nama);
|
||||
return redirect()->route('booking.success');
|
||||
session()->flash('message', 'Booking berhasil dibuat! Silahkan upload bukti pembayaran.');
|
||||
return redirect()->route('upload.bukti.pembayaran', $reservasi->id);
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
|
|
@ -12,7 +12,7 @@ class HomePage extends Component
|
|||
{
|
||||
public function render()
|
||||
{
|
||||
$paketfoto = PaketFoto::where('status', 1)->get();
|
||||
$paketfoto = PaketFoto::where('status', 1)->take(4)->get();
|
||||
return view('livewire.home-page', [
|
||||
'paketfoto' => $paketfoto
|
||||
]);
|
||||
|
|
|
@ -16,7 +16,7 @@ class PaketFotoPage extends Component
|
|||
use WithPagination;
|
||||
|
||||
#[Url]
|
||||
public $sort = 'latest';
|
||||
public $sort = 'oldest';
|
||||
|
||||
// tambah
|
||||
//public function addToCart($paketfoto_id){
|
||||
|
@ -27,18 +27,19 @@ class PaketFotoPage extends Component
|
|||
|
||||
public function render()
|
||||
{
|
||||
$paketfotoQuery = PaketFoto::query()->where('status', 1);
|
||||
|
||||
if($this->sort == 'latest') {
|
||||
$paketfotoQuery->latest();
|
||||
}
|
||||
|
||||
if($this->sort == 'price') {
|
||||
$paketfotoQuery->orderBy('harga_paket_foto');
|
||||
}
|
||||
$paketfoto = PaketFoto::when($this->sort === 'price', function($query) {
|
||||
return $query->orderBy('harga_paket_foto', 'asc');
|
||||
})
|
||||
->when($this->sort === 'latest', function($query) {
|
||||
return $query->latest();
|
||||
})
|
||||
->when($this->sort === 'oldest', function($query) {
|
||||
return $query->oldest();
|
||||
})
|
||||
->paginate(6);
|
||||
|
||||
return view('livewire.paket-foto-page', [
|
||||
'paketfoto' => $paketfotoQuery->paginate(6),
|
||||
'paketfoto' => $paketfoto
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,11 @@ public function mount($id = null)
|
|||
return redirect()->route('home');
|
||||
}
|
||||
|
||||
// Jika status pending dan belum ada bukti pembayaran, redirect ke halaman upload
|
||||
if ($this->booking->status_pembayaran === 'pending' && !$this->booking->bukti_pembayaran) {
|
||||
return redirect()->route('upload.bukti.pembayaran', $this->booking->id);
|
||||
}
|
||||
|
||||
// Ambil nama dari session
|
||||
$this->bookingName = session('booking_name');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Reservasii;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
use Livewire\Attributes\Title;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
#[Title('Upload Bukti Pembayaran - SiKolaself')]
|
||||
class UploadBuktiPembayaran extends Component
|
||||
{
|
||||
use WithFileUploads;
|
||||
|
||||
public $booking;
|
||||
public $bukti_pembayaran;
|
||||
public $bookingId;
|
||||
public $timeLeft;
|
||||
public $isExpired = false;
|
||||
|
||||
public function mount($id)
|
||||
{
|
||||
$this->bookingId = $id;
|
||||
$this->booking = Reservasii::with(['user', 'detail.paketFoto', 'promo'])
|
||||
->where('user_id', auth()->id())
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (!$this->booking) {
|
||||
session()->flash('error', 'Data booking tidak ditemukan');
|
||||
return redirect()->route('histori');
|
||||
}
|
||||
|
||||
if ($this->booking->status_pembayaran === 'approved') {
|
||||
return redirect()->route('booking.success', $this->booking->id);
|
||||
}
|
||||
|
||||
// Check if booking is expired
|
||||
$createdAt = Carbon::parse($this->booking->created_at);
|
||||
$expiryTime = $createdAt->addMinutes(5);
|
||||
|
||||
if (Carbon::now()->gt($expiryTime)) {
|
||||
// Update status pembayaran menjadi rejected
|
||||
$this->booking->update(['status_pembayaran' => 'rejected']);
|
||||
|
||||
// Hapus reservasi ini dari daftar waktu yang tidak tersedia
|
||||
DB::table('unavailable_times')
|
||||
->where('tanggal', $this->booking->tanggal)
|
||||
->where('waktu', $this->booking->waktu)
|
||||
->where('reservasii_id', $this->booking->id)
|
||||
->delete();
|
||||
|
||||
$this->isExpired = true;
|
||||
session()->flash('error', 'Waktu upload bukti pembayaran telah habis. Reservasi ditolak.');
|
||||
return redirect()->route('histori');
|
||||
}
|
||||
|
||||
$this->timeLeft = Carbon::now()->diffInSeconds($expiryTime);
|
||||
}
|
||||
|
||||
public function getTimeLeftProperty()
|
||||
{
|
||||
if ($this->isExpired) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$createdAt = Carbon::parse($this->booking->created_at);
|
||||
$expiryTime = $createdAt->addMinutes(1);
|
||||
return max(0, Carbon::now()->diffInSeconds($expiryTime));
|
||||
}
|
||||
|
||||
public function uploadBuktiPembayaran()
|
||||
{
|
||||
if (
|
||||
$this->isExpired
|
||||
) {
|
||||
session()->flash('error', 'Waktu upload bukti pembayaran telah habis.');
|
||||
return redirect()->route('histori');
|
||||
}
|
||||
|
||||
$this->validate([
|
||||
'bukti_pembayaran' => 'required|mimes:jpg,jpeg,png,webp|max:2048', // max 2MB, hanya gambar tertentu
|
||||
], [
|
||||
'bukti_pembayaran.required' => 'Bukti pembayaran harus diupload',
|
||||
'bukti_pembayaran.mimes' => 'File harus berupa gambar dengan format JPG, JPEG, PNG, atau WEBP. Dokumen tidak diperbolehkan.',
|
||||
'bukti_pembayaran.max' => 'Ukuran file maksimal 2MB',
|
||||
]);
|
||||
|
||||
$path = $this->bukti_pembayaran->store('bukti-pembayaran', 'public');
|
||||
|
||||
$this->booking->update([
|
||||
'bukti_pembayaran' => $path,
|
||||
'status_pembayaran' => 'pending'
|
||||
]);
|
||||
|
||||
session()->flash('message', 'Bukti pembayaran berhasil diupload. Silahkan tunggu konfirmasi dari admin.');
|
||||
return redirect()->route('histori');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.upload-bukti-pembayaran');
|
||||
}
|
||||
}
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use App\Notifications\ReservasiApproved;
|
||||
use App\Notifications\ReservasiRejected;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Reservasii extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
|
@ -17,7 +21,9 @@ class Reservasii extends Model
|
|||
'promo_id',
|
||||
'total',
|
||||
'tipe_pembayaran',
|
||||
'metode_pembayaran'
|
||||
'metode_pembayaran',
|
||||
'bukti_pembayaran',
|
||||
'status_pembayaran'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
@ -42,6 +48,52 @@ public function paketFoto()
|
|||
{
|
||||
return $this->belongsTo(PaketFoto::class);
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::updated(function ($reservasi) {
|
||||
// Cek apakah status pembayaran berubah
|
||||
if ($reservasi->isDirty('status_pembayaran')) {
|
||||
// Jika status menjadi 'approved'
|
||||
if ($reservasi->status_pembayaran === 'approved') {
|
||||
// Kirim notifikasi 'approved' ke user
|
||||
try {
|
||||
$reservasi->user->notify(new ReservasiApproved($reservasi));
|
||||
Log::info('Notifikasi email [approved] berhasil dikirim untuk reservasi ID: ' . $reservasi->id);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Gagal mengirim notifikasi email [approved]: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
// Otomatis reject reservasi lain yang bentrok
|
||||
$paketFotoIds = $reservasi->detail()->pluck('paket_foto_id')->toArray();
|
||||
$reservasiBentrok = self::where('id', '!=', $reservasi->id)
|
||||
->where('tanggal', $reservasi->tanggal)
|
||||
->where('waktu', $reservasi->waktu)
|
||||
->where('status_pembayaran', 'pending')
|
||||
->whereHas('detail', function($q) use ($paketFotoIds) {
|
||||
$q->whereIn('paket_foto_id', $paketFotoIds);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($reservasiBentrok as $r) {
|
||||
// Update ini akan memicu event 'updated' lagi untuk reservasi yang ditolak,
|
||||
// sehingga notifikasi 'rejected' akan terkirim secara otomatis.
|
||||
$r->update(['status_pembayaran' => 'rejected']);
|
||||
}
|
||||
}
|
||||
// Jika status menjadi 'rejected'
|
||||
elseif ($reservasi->status_pembayaran === 'rejected') {
|
||||
// Kirim notifikasi 'rejected' ke user
|
||||
try {
|
||||
$reservasi->user->notify(new ReservasiRejected($reservasi));
|
||||
Log::info('Notifikasi email [rejected] berhasil dikirim untuk reservasi ID: ' . $reservasi->id);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Gagal mengirim notifikasi email [rejected]: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,4 +54,9 @@ public function canAccessPanel(Panel $panel): bool
|
|||
{
|
||||
return $this->email == 'admin@gmail.com';
|
||||
}
|
||||
|
||||
public function routeNotificationForMail()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use App\Models\Reservasii;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ReservasiApproved extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
protected $reservasi;
|
||||
|
||||
public function __construct(Reservasii $reservasi)
|
||||
{
|
||||
$this->reservasi = $reservasi;
|
||||
Log::info('Notifikasi ReservasiApproved dibuat untuk reservasi ID: ' . $reservasi->id);
|
||||
}
|
||||
|
||||
public function via($notifiable)
|
||||
{
|
||||
Log::info('Mengirim notifikasi via email untuk reservasi ID: ' . $this->reservasi->id);
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
Log::info('Menyiapkan email untuk reservasi ID: ' . $this->reservasi->id);
|
||||
return (new MailMessage)
|
||||
->subject('Reservasi Anda Telah Disetujui')
|
||||
->greeting('Halo Sobat Minko!')
|
||||
->line('Reservasi Anda dengan nama : ' . $this->reservasi->nama . ' telah disetujui.')
|
||||
->line('Detail Reservasi')
|
||||
->line('Tanggal : ' . $this->reservasi->tanggal->format('d F Y'))
|
||||
->line('Waktu : ' . $this->reservasi->waktu)
|
||||
->line('Total Pembayaran : Rp ' . number_format($this->reservasi->total, 0, ',', '.'))
|
||||
->line('Silahkan datang sesuai dengan jadwal yang telah ditentukan.')
|
||||
->line('Terima kasih telah memilih layanan kami!')
|
||||
->salutation('Salam dari Minko');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use App\Models\Reservasii;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class ReservasiRejected extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
protected $reservasi;
|
||||
|
||||
public function __construct(Reservasii $reservasi)
|
||||
{
|
||||
$this->reservasi = $reservasi;
|
||||
}
|
||||
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('Reservasi Anda Ditolak')
|
||||
->greeting('Halo Sobat Minko!')
|
||||
->line('Mohon maaf, reservasi Anda dengan nama : ' . $this->reservasi->nama . ' telah ditolak.')
|
||||
->line('Tanggal : ' . Carbon::parse($this->reservasi->tanggal)->format('d F Y'))
|
||||
->line('Waktu : ' . $this->reservasi->waktu)
|
||||
->line('Hal ini terjadi karena jadwal sudah penuh atau ada masalah dengan pembayaran.')
|
||||
->line('Jika Anda merasa ini adalah sebuah kesalahan, silakan hubungi kami pada nomor dibawah ini.')
|
||||
->line('WA : 082131919312')
|
||||
->line('Terima kasih atas pengertian Anda.')
|
||||
->salutation('Salam dari Minko');
|
||||
}
|
||||
}
|
|
@ -65,7 +65,8 @@ public function panel(Panel $panel): Panel
|
|||
])
|
||||
->authMiddleware([
|
||||
Authenticate::class,
|
||||
]);
|
||||
])
|
||||
->sidebarCollapsibleOnDesktop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ public function up(): void
|
|||
$table->decimal('total',10 , 2);
|
||||
$table->enum('tipe_pembayaran',['full','DP']);
|
||||
$table->string('metode_pembayaran');
|
||||
$table->string('bukti_pembayaran')->nullable();
|
||||
$table->enum('status_pembayaran', ['pending', 'approved', 'rejected'])->default('pending');
|
||||
$table->decimal('diskon', 10, 2)->default(0);
|
||||
$table->decimal('total_setelah_diskon', 10, 2)->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,43 +17,93 @@ public function run(): void
|
|||
DB::table('paket_fotos')->insert([
|
||||
[
|
||||
'kode_paket_foto' => 101,
|
||||
'nama_paket_foto' => 'Paket Pasangan',
|
||||
'nama_paket_foto' => 'Self Basic',
|
||||
'harga_paket_foto' => '75000',
|
||||
'fasilitas' => '20 menit foto, 1x cetak foto single frame',
|
||||
'gambar' => '.jpg',
|
||||
'fasilitas' => '1. Harga 2 orang, lebih dari 2 orang dikenakan biaya tambahan 25k 2. Foto sepuasanya 20 menit, bebas jepret sebanyaknya 3. Print 1x Single Frame',
|
||||
'gambar' => 'self_basic.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now()
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 102,
|
||||
'nama_paket_foto' => 'Paket 5 Orang',
|
||||
'nama_paket_foto' => 'Basic Group',
|
||||
'harga_paket_foto' => '150000',
|
||||
'fasilitas' => '25 menit foto, 5x cetak foto single frame',
|
||||
'gambar' => 'gold.jpg',
|
||||
'fasilitas' => '1. Lebih dari 5 orang dikenakan biaya 25k/orang 2. Foto 25 menit bebas jepret sebanyaknya 3. Print 5x Single Frame',
|
||||
'gambar' => 'basic_group.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now()
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 103,
|
||||
'nama_paket_foto' => 'Widebox Couple',
|
||||
'nama_paket_foto' => 'Widebox',
|
||||
'harga_paket_foto' => '50000',
|
||||
'fasilitas' => '10 menit foto, 1x cetak foto 4R',
|
||||
'fasilitas' => '1. Maksimal 2 orang, lebih dari 2 orang dikenakan biaya tambahan 2. Foto 10 menit, bebas jepret sebanyaknya 3. Print 1x foto 4R',
|
||||
'gambar' => 'pasangan.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now()
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 103,
|
||||
'kode_paket_foto' => 104,
|
||||
'nama_paket_foto' => 'Widebox Group',
|
||||
'harga_paket_foto' => '110000',
|
||||
'fasilitas' => '10 menit foto, 5x cetak foto 4R',
|
||||
'gambar' => 'platinum.jpg',
|
||||
'harga_paket_foto' => '125000',
|
||||
'fasilitas' => '1. Maksimal 6 orang dalam 1 sesi 2. Foto 15 menit, bebas jepret sebanyaknya 3. Print 4x Single Frame 4R',
|
||||
'gambar' => 'widebox_group.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now()
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 105,
|
||||
'nama_paket_foto' => 'Self Neo',
|
||||
'harga_paket_foto' => '75000',
|
||||
'fasilitas' => '1. Konsep self studio ala di rumah biru yang harga bikin fotomu otentik dan lucu 2. Harga untuk 2 orang',
|
||||
'gambar' => 'self_neo.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 106,
|
||||
'nama_paket_foto' => 'Foto w/ Anabul',
|
||||
'harga_paket_foto' => '15000',
|
||||
'fasilitas' => '1. Bebas hewan apa saja, asal tidak membahayakan 2. Popok hewan disarankan',
|
||||
'gambar' => 'foto_anabul.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 107,
|
||||
'nama_paket_foto' => 'Tambah Orang',
|
||||
'harga_paket_foto' => '25000',
|
||||
'fasilitas' => '1. Berlaku untuk semua paket jika menambah orang 2. Print 1x single frame 4R',
|
||||
'gambar' => 'tambah_orang.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 108,
|
||||
'nama_paket_foto' => 'Tambah Waktu',
|
||||
'harga_paket_foto' => '10000',
|
||||
'fasilitas' => '1. Dihitung per 5 menit 2. Bebas menambah waktu hingga 20 menit',
|
||||
'gambar' => 'tambah_waktu.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'kode_paket_foto' => 109,
|
||||
'nama_paket_foto' => 'Semua File Foto',
|
||||
'harga_paket_foto' => '10000',
|
||||
'fasilitas' => '1. Dapat semua foto 2. Disarankan bawa flashdisk 3. Bisa kirim via Google Drive(masa aktif 4 hari) 4. Bisa kirim via Airdrop (IOS)',
|
||||
'gambar' => 'semua_file_foto.jpg',
|
||||
'status' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@livewireStyles
|
||||
@stack('scripts')
|
||||
</head>
|
||||
<body>
|
||||
<!-- ... existing content ... -->
|
||||
|
||||
@livewireScripts
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
@if($showModal)
|
||||
<div class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div class="mt-3 text-center sm:mt-0 sm:text-left w-full">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
||||
Tambah
|
||||
</h3>
|
||||
<div class="mt-4">
|
||||
<input type="text" wire:model.live="search" placeholder="Cari paket foto..." class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none">
|
||||
</div>
|
||||
<div class="mt-4 max-h-96 overflow-y-auto">
|
||||
<ul class="divide-y divide-gray-200">
|
||||
@forelse($pakets as $paket)
|
||||
<li class="py-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<img src="{{ url('storage', $paket->gambar) }}" alt="{{ $paket->nama_paket_foto }}" class="w-12 h-12 rounded-full">
|
||||
<div class="ml-4">
|
||||
<p class="text-sm font-medium text-gray-900">{{ $paket->nama_paket_foto }}</p>
|
||||
<p class="text-sm text-gray-500">{{ Number::currency($paket->harga_paket_foto, 'IDR') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button wire:click="addPaket({{ $paket->id }})" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600">
|
||||
Pilih
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
@empty
|
||||
<li class="py-3 text-center text-gray-500">
|
||||
Tidak ada paket ditemukan
|
||||
</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button type="button" wire:click="$set('showModal', false)" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
Tutup
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
|
@ -29,7 +29,7 @@
|
|||
<div class="grid gap-y-4">
|
||||
<!-- Form Group -->
|
||||
<div>
|
||||
<label for="email" class="block text-sm mb-2 dark:text-white">Email address</label>
|
||||
<label for="email" class="block text-sm mb-2 dark:text-white">Alamat Email</label>
|
||||
<div class="relative">
|
||||
<input type="email" id="email" wire:model="email" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500
|
||||
disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600" aria-describedby="email-error">
|
||||
|
@ -46,7 +46,7 @@
|
|||
@enderror
|
||||
</div>
|
||||
<!-- End Form Group -->
|
||||
<button type="submit" class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">Reset password</button>
|
||||
<button type="submit" class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-gray-600 text-white hover:bg-gray-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">Reset password</button>
|
||||
</div>
|
||||
</form>
|
||||
<!-- End Form -->
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
<h1 class="text-2xl font-bold text-center text-gray-800 mb-6">Login</h1>
|
||||
<form wire:submit.prevent="save" class="space-y-6">
|
||||
|
||||
@if (session('success'))
|
||||
<div class="bg-green-500 text-white p-4 rounded-lg text-sm mb-4" role="alert">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session('error'))
|
||||
<div class="bg-red-500 text-white p-4 rounded-lg text-sm mb-4" role="alert">
|
||||
{{ session('error') }}
|
||||
|
@ -21,7 +27,7 @@
|
|||
|
||||
<!-- Email -->
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-1 dark:text-white">Email address</label>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-1 dark:text-white">Alamat Email</label>
|
||||
<input type="email" id="email" wire:model="email" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600">
|
||||
@error('email')
|
||||
<p class="text-xs text-red-600 mt-2" id="email-error">{{ $message }}</p>
|
||||
|
@ -32,7 +38,7 @@
|
|||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<label for="password" class="block text-sm font-medium text-gray-700 dark:text-white">Password</label>
|
||||
{{--<a href="/forgot" class="text-sm text-blue-600 hover:underline">Lupa password?</a>--}}
|
||||
<a href="/forgot" class="text-sm text-blue-600 hover:underline">Lupa password?</a>
|
||||
</div>
|
||||
<input type="password" id="password" wire:model="password" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600">
|
||||
@error('password')
|
||||
|
@ -45,6 +51,5 @@
|
|||
|
||||
<p class="text-sm text-center text-gray-600">Belum punya akun? <a href="/register" class="text-blue-600 hover:underline">Daftar</a></p>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
<div class="w-full border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="p-4 sm:p-7">
|
||||
<div class="text-center">
|
||||
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Sign In</h1>
|
||||
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Daftar</h1>
|
||||
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
Sudah punya akun?
|
||||
<a wire:navigate class="text-blue-600 decoration-2 hover:underline font-medium dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="/login">
|
||||
Log in disini
|
||||
Login
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -46,7 +46,7 @@
|
|||
|
||||
<!-- Field Email -->
|
||||
<div>
|
||||
<label for="email" class="block text-sm mb-2 dark:text-white">Email address</label>
|
||||
<label for="email" class="block text-sm mb-2 dark:text-white">Alamat Email</label>
|
||||
<div class="relative">
|
||||
<input type="email" id="email" wire:model="email" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600" aria-describedby="email-error">
|
||||
@error('email')
|
||||
|
@ -82,7 +82,7 @@
|
|||
|
||||
<!-- Tombol -->
|
||||
<button type="submit" class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-gray-600 text-white hover:bg-gray-700 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
|
||||
Sign Up
|
||||
Daftar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,46 +4,67 @@
|
|||
<div class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="p-4 sm:p-7">
|
||||
<div class="text-center">
|
||||
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Reset password</h1>
|
||||
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Reset Password</h1>
|
||||
</div>
|
||||
|
||||
@if (session()->has('error'))
|
||||
<div class="mt-4 p-4 text-sm text-red-800 border border-red-300 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400 dark:border-red-800" role="alert">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session()->has('success'))
|
||||
<div class="mt-4 p-4 text-sm text-green-800 border border-green-300 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400 dark:border-green-800" role="alert">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="mt-5">
|
||||
<!-- Form -->
|
||||
<form wire:submit.prevent="save">
|
||||
<div class="grid gap-y-4">
|
||||
<!-- Form Group -->
|
||||
<div>
|
||||
<label for="password" class="block text-sm mb-2 dark:text-white">Password</label>
|
||||
<label for="password" class="block text-sm mb-2 dark:text-white">Password Baru</label>
|
||||
<div class="relative">
|
||||
<input type="password" id="password" wire:model="password" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm
|
||||
focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600" aria-describedby="email-error">
|
||||
<div class=" absolute inset-y-0 end-0 flex items-center pointer-events-none pe-3">
|
||||
<svg class="h-5 w-5 text-red-500" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input type="password" id="password" wire:model.live="password" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm
|
||||
focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600 @error('password') border-red-500 @enderror" aria-describedby="password-error">
|
||||
@error('password')
|
||||
<div class="absolute inset-y-0 end-0 flex items-center pointer-events-none pe-3">
|
||||
<svg class="h-5 w-5 text-red-500" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
@enderror
|
||||
</div>
|
||||
<p class="text-red-600 mt-2" id="password-error">Password error message</p>
|
||||
@error('password')
|
||||
<p class="text-red-600 text-xs mt-2" id="password-error">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<!-- End Form Group -->
|
||||
|
||||
<div>
|
||||
<label for="password_confirmation" class="block text-sm mb-2 dark:text-white">Confirm Password</label>
|
||||
<label for="password_confirmation" class="block text-sm mb-2 dark:text-white">Konfirmasi Password</label>
|
||||
<div class="relative">
|
||||
<input type="password" id="password_confirmation" wire:model="password_confirmation" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600" required aria-describedby="email-error">
|
||||
<input type="password" id="password_confirmation" wire:model.live="password_confirmation" class="py-3 px-4 block w-full border border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-gray-600 @error('password_confirmation') border-red-500 @enderror" required aria-describedby="password_confirmation-error">
|
||||
|
||||
<div class="hidden inset-y-0 end-0 flex items-center pointer-events-none pe-3">
|
||||
<svg class="h-5 w-5 text-red-500" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
@error('password_confirmation')
|
||||
<div class="absolute inset-y-0 end-0 flex items-center pointer-events-none pe-3">
|
||||
<svg class="h-5 w-5 text-red-500" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
@enderror
|
||||
|
||||
</div>
|
||||
<p class="text-xs text-red-600 mt-2" id="password_confirmation-error">Confirm Password Error</p>
|
||||
@error('password_confirmation')
|
||||
<p class="text-xs text-red-600 mt-2" id="password_confirmation-error">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
|
||||
Save password
|
||||
<button type="submit" class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-gray-600 text-white hover:bg-gray-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
|
||||
<span wire:loading.remove>Simpan Password</span>
|
||||
<span wire:loading>Simpan Password</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,229 +1,289 @@
|
|||
<div class="w-full max-w-[85rem] py-10 px-4 sm:px-6 lg:px-8 mx-auto">
|
||||
<h1 class="text-2xl font-bold text-gray-800 dark:text-white mb-4">
|
||||
Booking
|
||||
</h1>
|
||||
<form wire:submit.prevent="placeOrder">
|
||||
<div class="grid grid-cols-12 gap-4">
|
||||
<div class="md:col-span-12 lg:col-span-8 col-span-12">
|
||||
<!-- Card -->
|
||||
<div class="bg-white rounded-xl shadow p-4 sm:p-7 dark:bg-slate-900">
|
||||
<!-- Shipping Address -->
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold underline text-gray-700 dark:text-white mb-2">
|
||||
Formulir Reservasi
|
||||
</h2>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="nama">
|
||||
Nama Lengkap
|
||||
</label>
|
||||
<input wire:model="nama" class="w-full rounded-lg border py-2 px-3
|
||||
dark:bg-gray-700 dark:text-white dark:border-none @error('nama') border-red-500 @enderror " id="nama" type="text">
|
||||
@error('nama')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div>
|
||||
<div class="w-full max-w-[85rem] py-10 px-4 sm:px-6 lg:px-8 mx-auto">
|
||||
<h1 class="text-2xl font-bold text-gray-800 dark:text-white mb-4">
|
||||
Reservasi
|
||||
</h1>
|
||||
<form wire:submit.prevent="placeOrder">
|
||||
<div class="grid grid-cols-12 gap-4">
|
||||
<div class="md:col-span-12 lg:col-span-8 col-span-12">
|
||||
<!-- Card -->
|
||||
<div class="bg-white rounded-xl shadow p-4 sm:p-7 dark:bg-slate-900">
|
||||
<!-- Shipping Address -->
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold underline text-gray-700 dark:text-white mb-2">
|
||||
Formulir Reservasi
|
||||
</h2>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="nama">
|
||||
Nama
|
||||
</label>
|
||||
<input wire:model="nama" class="w-full rounded-lg border py-2 px-3
|
||||
dark:bg-gray-700 dark:text-white dark:border-none @error('nama') border-red-500 @enderror " id="nama" type="text">
|
||||
@error('nama')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="tanggal">
|
||||
Tanggal
|
||||
</label>
|
||||
<input wire:model="tanggal" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('tanggal') border-red-500 @enderror" id="tanggal" type="date" min="{{ date('Y-m-d') }}">
|
||||
@error('tanggal')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="tanggal">
|
||||
Tanggal
|
||||
</label>
|
||||
<input wire:model="tanggal" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('tanggal') border-red-500 @enderror" id="tanggal" type="date" min="{{ date('Y-m-d') }}">
|
||||
@error('tanggal')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="waktu">
|
||||
Waktu
|
||||
</label>
|
||||
<select wire:model="waktu" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('waktu') border-red-500 @enderror" id="waktu">
|
||||
<option value="">Pilih waktu</option>
|
||||
@php
|
||||
$timeLabels = collect(range(8, 20))->mapWithKeys(function ($hour) {
|
||||
$formatted = str_pad($hour, 2, '0', STR_PAD_LEFT) . ':00';
|
||||
return [$formatted => $formatted];
|
||||
})->toArray();
|
||||
@endphp
|
||||
@foreach($timeLabels as $time => $label)
|
||||
@php
|
||||
$isUnavailable = in_array($time, $this->unavailableTimes);
|
||||
$isBooked = in_array($time, $this->bookedTimes);
|
||||
$isPast = $this->tanggal == now()->format('Y-m-d') && $time <= now()->format('H:i');
|
||||
@endphp
|
||||
<option value="{{ $time }}"
|
||||
{{ $isUnavailable ? 'disabled' : '' }}
|
||||
class="{{ $isUnavailable ? 'text-gray-400 bg-gray-100' : '' }}"
|
||||
style="{{ $isUnavailable ? 'background-color: #f3f4f6; color: #9ca3af;' : '' }}">
|
||||
{{ $label }}
|
||||
@if($isBooked)
|
||||
(Sudah dipesan)
|
||||
@elseif($isPast)
|
||||
(Sudah lewat)
|
||||
@endif
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('waktu')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="warna">
|
||||
Background
|
||||
</label>
|
||||
<select wire:model="warna" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('warna') border-red-500 @enderror" id="warna">
|
||||
<option value="">Pilih warna</option>
|
||||
<option value="putih">White</option>
|
||||
<option value="abu">Grey</option>
|
||||
<option value="cream">Cream</option>
|
||||
<option value="spotlight">Spotlight</option>
|
||||
</select>
|
||||
@error('warna')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="waktu">
|
||||
Waktu
|
||||
</label>
|
||||
<select wire:model="waktu" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('waktu') border-red-500 @enderror" id="waktu">
|
||||
<option value="">Pilih waktu</option>
|
||||
@php
|
||||
$timeLabels = collect(range(8, 20))->mapWithKeys(function ($hour) {
|
||||
$formatted = str_pad($hour, 2, '0', STR_PAD_LEFT) . ':00';
|
||||
return [$formatted => $formatted];
|
||||
})->toArray();
|
||||
@endphp
|
||||
@foreach($timeLabels as $time => $label)
|
||||
@php
|
||||
$isUnavailable = in_array($time, $this->unavailableTimes);
|
||||
$isBooked = in_array($time, $this->bookedTimes);
|
||||
$isPast = $this->tanggal == now()->format('Y-m-d') && $time <= now()->format('H:i');
|
||||
@endphp
|
||||
<option value="{{ $time }}"
|
||||
{{ $isUnavailable ? 'disabled' : '' }}
|
||||
class="{{ $isUnavailable ? 'text-gray-400 bg-gray-100' : '' }}"
|
||||
style="{{ $isUnavailable ? 'background-color: #f3f4f6; color: #9ca3af;' : '' }}">
|
||||
{{ $label }}
|
||||
@if($isBooked)
|
||||
(Sudah dipesan)
|
||||
@elseif($isPast)
|
||||
(Sudah lewat)
|
||||
@endif
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('waktu')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="warna">
|
||||
Background
|
||||
</label>
|
||||
<select wire:model="warna" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('warna') border-red-500 @enderror" id="warna">
|
||||
<option value="">Pilih warna</option>
|
||||
<option value="putih">White</option>
|
||||
<option value="abu">Grey</option>
|
||||
<option value="cream">Cream</option>
|
||||
<option value="spotlight">Spotlight</option>
|
||||
</select>
|
||||
@error('warna')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="promo">
|
||||
Kode Promo (jika ada)
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input wire:model="promo" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('promo') border-red-500 @enderror" id="promo" type="text" placeholder="Masukkan kode promo">
|
||||
<button type="button" wire:click="applyPromo" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600">Terapkan</button>
|
||||
</div>
|
||||
@error('promo')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
@if($promoApplied)
|
||||
<div class="text-green-500 text-sm mt-1">Promo berhasil diterapkan!</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1" for="promo">
|
||||
Kode Promo (jika ada)
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<input wire:model="promo" class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none @error('promo') border-red-500 @enderror" id="promo" type="text" placeholder="Masukkan kode promo">
|
||||
<button type="button" wire:click="applyPromo" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600">Terapkan</button>
|
||||
</div>
|
||||
@error('promo')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
@if($promoApplied)
|
||||
<div class="text-green-500 text-sm mt-1">Promo berhasil diterapkan!</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<!-- Tipe Pembayaran - Muncul ketika Transfer Bank dipilih -->
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<!-- Transfer Bank via Midtrans -->
|
||||
<div class="mt-6">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Card -->
|
||||
</div>
|
||||
<div class="md:col-span-12 lg:col-span-4 col-span-12">
|
||||
<div class="bg-white rounded-xl shadow p-4 sm:p-7 dark:bg-slate-900">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold underline text-gray-700 dark:text-white mb-4">
|
||||
Metode Pembayaran
|
||||
</h2>
|
||||
<!-- Pilih Tipe Pembayaran -->
|
||||
<div class="mt-4">
|
||||
<label class="block text-gray-700 dark:text-white mb-1">Tipe Pembayaran</label>
|
||||
<ul class="grid w-full gap-4 md:grid-cols-2">
|
||||
<li>
|
||||
<input wire:model="tipe_pembayaran" class="hidden peer" id="payment-dp" name="payment_type" type="radio" value="dp" required />
|
||||
<label for="payment-dp" class="inline-flex items-center justify-between w-full p-5 bg-white border border-gray-200 rounded-lg cursor-pointer
|
||||
hover:bg-gray-100 peer-checked:border-blue-600 peer-checked:text-blue-600 dark:bg-gray-800 dark:text-gray-400 dark:peer-checked:text-blue-500 dark:border-gray-700 dark:hover:bg-gray-700">
|
||||
<div class="block">
|
||||
<div class="text-lg font-semibold">Down Payment</div>
|
||||
<div class="text-sm">Bayar DP terlebih dahulu</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input wire:model="tipe_pembayaran" class="hidden peer" id="payment-full" name="payment_type" type="radio" value="full" />
|
||||
<label for="payment-full" class="inline-flex items-center justify-between w-full p-5 bg-white border border-gray-200 rounded-lg cursor-pointer hover:bg-gray-100 peer-checked:border-blue-600 peer-checked:text-blue-600 dark:bg-gray-800 dark:text-gray-400 dark:peer-checked:text-blue-500 dark:border-gray-700 dark:hover:bg-gray-700">
|
||||
<div class="block">
|
||||
<div class="text-lg font-semibold">Full Payment</div>
|
||||
<div class="text-sm">Bayar lunas sekarang</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
@error('tipe_pembayaran')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<!-- Tipe Pembayaran - Muncul ketika Transfer Bank dipilih -->
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<!-- Transfer Bank via Midtrans -->
|
||||
<div class="mt-6">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Card -->
|
||||
</div>
|
||||
<div class="md:col-span-12 lg:col-span-4 col-span-12">
|
||||
<div class="bg-white rounded-xl shadow p-4 sm:p-7 dark:bg-slate-900">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold underline text-gray-700 dark:text-white mb-4">
|
||||
Metode Pembayaran
|
||||
</h2>
|
||||
<!-- Pilih Tipe Pembayaran -->
|
||||
<div class="mt-4">
|
||||
<ul class="grid w-full gap-4 md:grid-cols-2">
|
||||
<li>
|
||||
<input wire:model="tipe_pembayaran" class="hidden peer" id="payment-dp" name="payment_type" type="radio" value="dp" required />
|
||||
<label for="payment-dp" class="inline-flex items-center justify-between w-full p-5 bg-white border border-gray-200 rounded-lg cursor-pointer
|
||||
hover:bg-gray-100 peer-checked:border-blue-600 peer-checked:text-blue-600 dark:bg-gray-800 dark:text-gray-400 dark:peer-checked:text-blue-500 dark:border-gray-700 dark:hover:bg-gray-700">
|
||||
<div class="block">
|
||||
<div class="text-lg font-semibold">Down Payment</div>
|
||||
<div class="text-sm">DP min. Rp 20.000</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input wire:model="tipe_pembayaran" class="hidden peer" id="payment-full" name="payment_type" type="radio" value="full" />
|
||||
<label for="payment-full" class="inline-flex items-center justify-between w-full p-5 bg-white border border-gray-200 rounded-lg cursor-pointer hover:bg-gray-100 peer-checked:border-blue-600 peer-checked:text-blue-600 dark:bg-gray-800 dark:text-gray-400 dark:peer-checked:text-blue-500 dark:border-gray-700 dark:hover:bg-gray-700">
|
||||
<div class="block">
|
||||
<div class="text-lg font-semibold">Full Payment</div>
|
||||
<div class="text-sm">Bayar lunas sekarang</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
@error('tipe_pembayaran')
|
||||
<div class="text-red-500 text-sm">{{ $message }}</div>
|
||||
@enderror
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Transfer Bank via Midtrans -->
|
||||
<div class="mt-6">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Transfer Bank via Midtrans -->
|
||||
<div class="mt-6">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-xl font-bold underline text-gray-700 dark:text-white mb-2">
|
||||
Rincian Reservasi
|
||||
</div>
|
||||
<div class="flex justify-between mb-2 font-bold">
|
||||
<span>
|
||||
Subtotal
|
||||
</span>
|
||||
<span>
|
||||
@if($paketfoto)
|
||||
{{ Number::currency($paketfoto->harga_paket_foto, 'IDR') }}
|
||||
@else
|
||||
{{ Number::currency(0, 'IDR') }}
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
@if($promoApplied)
|
||||
<div class="flex justify-between mb-2">
|
||||
<span>
|
||||
Potongan Promo
|
||||
</span>
|
||||
<span class="text-green-500">
|
||||
- {{ Number::currency($promoDiscount, 'IDR') }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
<hr class="bg-slate-400 my-4 h-1 rounded">
|
||||
<div class="flex justify-between mb-2 font-bold">
|
||||
<span>
|
||||
Grand Total
|
||||
</span>
|
||||
<span>
|
||||
{{ Number::currency($this->totalPrice, 'IDR') }}
|
||||
</span>
|
||||
</div>
|
||||
</hr>
|
||||
</div>
|
||||
<button type="submit" class="bg-gray-500 mt-4 w-full p-3 rounded-lg text-lg text-white hover:bg-gray-600">
|
||||
Booking Sekarang
|
||||
</button>
|
||||
<div class="bg-white mt-4 rounded-xl shadow p-4 sm:p-7 dark:bg-slate-900">
|
||||
<div class="text-xl font-bold underline text-gray-700 dark:text-white mb-2">
|
||||
Paket Foto
|
||||
</div>
|
||||
<ul class="divide-y divide-gray-200 dark:divide-gray-700" role="list">
|
||||
@if($paketfoto)
|
||||
<li class="py-3 sm:py-4" wire:key="{{ $paketfoto->id }}">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<img alt="{{ $paketfoto->nama_paket_foto }}" class="w-12 h-12 rounded-full" src="{{ url('storage', $paketfoto->gambar) }}"> </img>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 ms-4">
|
||||
<p class="text-sm font-medium text-gray-900 truncate dark:text-white">
|
||||
{{ $paketfoto->nama_paket_foto }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="inline-flex items-center text-base font-semibold text-gray-900 dark:text-white">
|
||||
{{ Number::currency($paketfoto->harga_paket_foto, 'IDR') }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@else
|
||||
<li class="py-3 sm:py-4">
|
||||
<div class="flex items-center justify-center">
|
||||
<p class="text-sm text-gray-500">No package selected</p>
|
||||
</div>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="text-xl font-bold underline text-gray-700 dark:text-white mb-2">
|
||||
Rincian Reservasi
|
||||
</div>
|
||||
<div class="flex justify-between mb-2 font-bold">
|
||||
<span>
|
||||
Subtotal
|
||||
</span>
|
||||
<span>
|
||||
{{ Number::currency(collect($selectedPakets)->sum('harga'), 'IDR') }}
|
||||
</span>
|
||||
</div>
|
||||
@if($promoApplied)
|
||||
<div class="flex justify-between mb-2">
|
||||
<span>
|
||||
Potongan Promo
|
||||
</span>
|
||||
<span class="text-green-500">
|
||||
- {{ Number::currency($promoDiscount, 'IDR') }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
<hr class="bg-slate-400 my-4 h-1 rounded">
|
||||
<div class="flex justify-between mb-2 font-bold">
|
||||
<span>
|
||||
Total Harga
|
||||
</span>
|
||||
<span>
|
||||
{{ Number::currency($this->totalPrice, 'IDR') }}
|
||||
</span>
|
||||
</div>
|
||||
</hr>
|
||||
</div>
|
||||
<button type="submit" class="bg-gray-500 mt-4 w-full p-3 rounded-lg text-lg text-white hover:bg-gray-600">
|
||||
Reservasi Sekarang
|
||||
</button>
|
||||
<div class="bg-white mt-4 rounded-xl shadow p-4 sm:p-7 dark:bg-slate-900">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="text-xl font-bold underline text-gray-700 dark:text-white">
|
||||
Paket Foto
|
||||
</div>
|
||||
<button type="button" wire:click="$set('showModal', true)" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600">
|
||||
Tambah Paket
|
||||
</button>
|
||||
</div>
|
||||
<ul class="divide-y divide-gray-200 dark:divide-gray-700" role="list">
|
||||
@forelse($selectedPakets as $index => $paket)
|
||||
<li class="py-3 sm:py-4" wire:key="{{ $paket['id'] }}">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<img alt="{{ $paket['nama'] }}" class="w-12 h-12 rounded-full" src="{{ url('storage', $paket['gambar']) }}">
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 ms-4">
|
||||
<p class="text-sm font-medium text-gray-900 truncate dark:text-white">
|
||||
{{ $paket['nama'] }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="text-base font-semibold text-gray-900 dark:text-white">
|
||||
{{ Number::currency($paket['harga'], 'IDR') }}
|
||||
</div>
|
||||
<button type="button" wire:click="removePaket({{ $index }})" class="text-red-500 hover:text-red-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@empty
|
||||
<li class="py-3 sm:py-4">
|
||||
<div class="flex items-center justify-center">
|
||||
<p class="text-sm text-gray-500">Belum ada paket dipilih</p>
|
||||
</div>
|
||||
</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@if($showModal)
|
||||
<div class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div class="mt-3 text-center sm:mt-0 sm:text-left w-full">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
||||
Tambah Paket Foto
|
||||
</h3>
|
||||
<div class="mt-4">
|
||||
<input type="text" wire:model.live="search" placeholder="Cari paket foto..." class="w-full rounded-lg border py-2 px-3 dark:bg-gray-700 dark:text-white dark:border-none">
|
||||
</div>
|
||||
<div class="mt-4 max-h-96 overflow-y-auto">
|
||||
<ul class="divide-y divide-gray-200">
|
||||
@forelse($pakets as $paket)
|
||||
<li class="py-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<img src="{{ url('storage', $paket->gambar) }}" alt="{{ $paket->nama_paket_foto }}" class="w-12 h-12 rounded-full">
|
||||
<div class="ml-4">
|
||||
<p class="text-sm font-medium text-gray-900">{{ $paket->nama_paket_foto }}</p>
|
||||
<p class="text-sm text-gray-500">{{ Number::currency($paket->harga_paket_foto, 'IDR') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button wire:click="addPaket({{ $paket->id }})" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600">
|
||||
Pilih
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
@empty
|
||||
<li class="py-3 text-center text-gray-500">
|
||||
Tidak ada paket ditemukan
|
||||
</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button type="button" wire:click="$set('showModal', false)" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
Tutup
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
|
@ -1,65 +1,41 @@
|
|||
<div class="w-full max-w-[85rem] max-h-screen py-10 px-4 sm:px-6 lg:px-8 mx-auto">
|
||||
<section class="overflow-hidden bg-white py-11 font-poppins dark:bg-gray-800">
|
||||
<div class="w-full max-w-[85rem] py-10 px-4 sm:px-6 lg:px-8 mx-auto">
|
||||
<section class="overflow-hidden bg-white py-6 sm:py-11 font-poppins dark:bg-gray-800">
|
||||
<div class="max-w-6xl px-4 py-4 mx-auto lg:py-8 md:px-6">
|
||||
|
||||
|
||||
<div class="flex flex-wrap -mx-4">
|
||||
<div class="flex flex-col md:flex-row -mx-4">
|
||||
<!-- Bagian Gambar -->
|
||||
<div class="w-full mb-8 md:w-1/2 md:mb-0" x-data="{ mainImage: '{{ url('storage', $paketfoto->gambar) }}' }">
|
||||
<div class="sticky top-0 z-50 overflow-hidden ">
|
||||
<div class="aspect-[4/3] ">
|
||||
<img x-bind:src="mainImage" alt="" class="object-cover w-full lg:h-full ">
|
||||
<div class="sticky top-0 z-50 overflow-hidden">
|
||||
<div class="aspect-[4/3]">
|
||||
<img x-bind:src="mainImage" alt="{{ $paketfoto->nama_paket_foto }}" class="object-cover w-full h-full rounded-lg shadow-lg">
|
||||
</div>
|
||||
<div class="flex-wrap hidden md:flex ">
|
||||
<div class="flex-wrap hidden md:flex mt-4">
|
||||
<div class="w-1/2 p-2 sm:w-1/4" x-on:click="mainImage='https://m.media-amazon.com/images/I/71f5Eu5lJSL._SX679_.jpg'">
|
||||
<alt="" class="object-cover w-full lg:h-20 cursor-pointer hover:border hover:border-blue-500">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="px-6 pb-6 mt-6 border-t border-gray-300 dark:border-gray-400 ">
|
||||
<div class="flex flex-wrap items-center mt-6">
|
||||
{{-- <span class="mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="w-4 h-4 text-gray-700 dark:text-gray-400 bi bi-truck" viewBox="0 0 16 16">
|
||||
<path d="M0 3.5A1.5 1.5 0 0 1 1.5 2h9A1.5 1.5 0 0 1 12 3.5V5h1.02a1.5 1.5 0 0 1 1.17.563l1.481 1.85a1.5 1.5 0 0 1 .329.938V10.5a1.5 1.5 0 0 1-1.5 1.5H14a2 2 0 1 1-4 0H5a2 2 0 1 1-3.998-.085A1.5 1.5 0 0 1 0 10.5v-7zm1.294 7.456A1.999 1.999 0 0 1 4.732 11h5.536a2.01 2.01 0 0 1 .732-.732V3.5a.5.5 0 0 0-.5-.5h-9a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 .294.456zM12 10a2 2 0 0 1 1.732 1h.768a.5.5 0 0 0 .5-.5V8.35a.5.5 0 0 0-.11-.312l-1.48-1.85A.5.5 0 0 0 13.02 6H12v4zm-9 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2zm9 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2z">
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<h2 class="text-lg font-bold text-gray-700 dark:text-gray-400">Free Shipping</h2>--}}
|
||||
{{-- <img src="https://m.media-amazon.com/images/I/71f5Eu5lJSL._SX679_.jpg" alt="Thumbnail" class="object-cover w-full h-20 rounded cursor-pointer hover:border-2 hover:border-blue-500">--}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full px-4 md:w-1/2 ">
|
||||
<div class="lg:pl-20">
|
||||
<div class="mb-8 ">
|
||||
<h2 class="max-w-xl mb-6 text-2xl font-bold dark:text-gray-400 md:text-4xl">
|
||||
{{ $paketfoto->nama_paket_foto }}
|
||||
</h2>
|
||||
<p class="inline-block mb-6 text-4xl font-bold text-gray-700 dark:text-gray-400 ">
|
||||
<span>
|
||||
{{ Number::currency($paketfoto->harga_paket_foto, 'IDR') }}
|
||||
</span>
|
||||
{{-- <span class="text-base font-normal text-gray-500 line-through dark:text-gray-400">$1800.99</span> --}}
|
||||
</p>
|
||||
<p class="max-w-md text-gray-700 dark:text-gray-400">
|
||||
{{ $paketfoto->fasilitas }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-32 mb-8 ">
|
||||
<div class="flex flex-col items-start">
|
||||
<a href="{{ route('booking', ['id' => $paketfoto->id]) }}" class="px-6 py-3 bg-blue-500 rounded-md text-white hover:bg-blue-600 dark:bg-blue-500 dark:hover:bg-blue-700">
|
||||
Booking
|
||||
</a>
|
||||
</div>
|
||||
{{-- <label for="" class="w-full pb-1 text-xl font-semibold text-gray-700 border-b border-blue-300 dark:border-gray-600 dark:text-gray-400">Quantity</label>
|
||||
<div class="relative flex flex-row w-full h-10 mt-6 bg-transparent rounded-lg"> --}}
|
||||
|
||||
{{-- <button class="w-20 h-full text-gray-600 bg-gray-300 rounded-l outline-none cursor-pointer dark:hover:bg-gray-700 dark:text-gray-400 hover:text-gray-700 dark:bg-gray-900 hover:bg-gray-400">
|
||||
<span class="m-auto text-2xl font-thin">-</span>
|
||||
</button>
|
||||
<input type="number" readonly class="flex items-center w-full font-semibold text-center text-gray-700 placeholder-gray-700 bg-gray-300 outline-none dark:text-gray-400 dark:placeholder-gray-400 dark:bg-gray-900 focus:outline-none text-md hover:text-black" placeholder="1">
|
||||
<button class="w-20 h-full text-gray-600 bg-gray-300 rounded-r outline-none cursor-pointer dark:hover:bg-gray-700 dark:text-gray-400 dark:bg-gray-900 hover:text-gray-700 hover:bg-gray-400">
|
||||
<span class="m-auto text-2xl font-thin">+</span>
|
||||
</button> --}}
|
||||
<!-- Bagian Informasi -->
|
||||
<div class="w-full px-4 md:w-1/2">
|
||||
<div class="lg:pl-20">
|
||||
<div class="mb-8">
|
||||
<h2 class="max-w-xl mb-4 text-xl sm:text-2xl md:text-4xl font-bold dark:text-gray-400">
|
||||
{{ $paketfoto->nama_paket_foto }}
|
||||
</h2>
|
||||
<p class="inline-block mb-6 text-2xl sm:text-3xl md:text-4xl font-bold text-gray-700 dark:text-gray-400">
|
||||
<span>{{ Number::currency($paketfoto->harga_paket_foto, 'IDR') }}</span>
|
||||
</p>
|
||||
<p class="max-w-md text-sm sm:text-base text-gray-700 dark:text-gray-400">
|
||||
{{ $paketfoto->fasilitas }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-full sm:w-32 mb-8">
|
||||
<div class="flex flex-col items-start">
|
||||
<a href="{{ route('booking', ['id' => $paketfoto->id]) }}"
|
||||
class="w-full sm:w-auto px-6 py-3 text-center bg-blue-500 rounded-md text-white hover:bg-blue-600 dark:bg-blue-500 dark:hover:bg-blue-700 transition duration-300">
|
||||
Reservasi
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase">Tanggal</th>
|
||||
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase">Waktu</th>
|
||||
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase">Paket Foto</th>
|
||||
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase">Tipe Pembayaran</th>
|
||||
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase">Total</th>
|
||||
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase">Status</th>
|
||||
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -27,19 +27,30 @@
|
|||
<div>{{ $detail->paketFoto->nama_paket_foto }}</div>
|
||||
@endforeach
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-200">
|
||||
<span class="bg-{{ $booking->tipe_pembayaran == 'full' ? 'green' : 'orange' }}-500 py-1 px-3 rounded text-white shadow">
|
||||
{{ ucfirst($booking->tipe_pembayaran) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-200">Rp {{ number_format($booking->total, 0, ',', '.') }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-200">
|
||||
@if($booking->status_pembayaran === 'pending')
|
||||
<span class="bg-yellow-500 py-1 px-3 rounded text-white shadow">Menunggu</span>
|
||||
@elseif($booking->status_pembayaran === 'approved')
|
||||
<span class="bg-green-500 py-1 px-3 rounded text-white shadow">Disetujui</span>
|
||||
@elseif($booking->status_pembayaran === 'rejected')
|
||||
<span class="bg-red-500 py-1 px-3 rounded text-white shadow">Ditolak</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-end text-sm font-medium">
|
||||
<a href="{{ route('booking.success', $booking->id) }}" class="bg-slate-600 text-white py-2 px-4 rounded-md hover:bg-slate-500">View Details</a>
|
||||
@if($booking->status_pembayaran === 'pending' && !$booking->bukti_pembayaran)
|
||||
<a href="{{ route('upload.bukti.pembayaran', $booking->id) }}" class="bg-blue-500 text-white py-2 px-4 rounded-md hover:bg-blue-600">Upload Bukti</a>
|
||||
@elseif($booking->status_pembayaran === 'approved')
|
||||
<a href="{{ route('booking.success', $booking->id) }}" class="bg-slate-600 text-white py-2 px-4 rounded-md hover:bg-slate-500">Lihat Details</a>
|
||||
@else
|
||||
<a href="{{ route('booking.success', $booking->id) }}" class="bg-slate-600 text-white py-2 px-4 rounded-md hover:bg-slate-500">Lihat Details</a>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="px-6 py-4 text-center text-sm text-gray-500">Tidak ada data reservasi</td>
|
||||
<td colspan="8" class="px-6 py-4 text-center text-sm text-gray-500">Tidak ada data reservasi</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
<div class="max-w-xl mx-auto">
|
||||
<div class="text-center ">
|
||||
<div class="relative flex flex-col items-center">
|
||||
<h1 class="text-5xl font-bold dark:text-gray-200"> Paket Foto<span class="text-gray-500"> Populer
|
||||
<h1 class="text-5xl font-bold dark:text-gray-200"> Paket Foto<span class="text-gray-500"> Kami
|
||||
</span> </h1>
|
||||
<div class="flex w-40 mt-2 mb-6 overflow-hidden rounded">
|
||||
<div class="flex-1 h-2 bg-gray-300">
|
||||
|
@ -134,9 +134,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<p class="mb-12 text-base text-center text-gray-500">
|
||||
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Delectus magni eius eaque?
|
||||
Pariatur
|
||||
numquam, odio quod nobis ipsum ex cupiditate?
|
||||
Siap mengabadikan momen anda dengan berbagai
|
||||
Pilihan Paket Foto Terbaik
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<div class="items-center justify-between hidden px-3 py-2 bg-gray-100 md:flex dark:bg-gray-900 ">
|
||||
<div class="flex items-center justify-between">
|
||||
<select wire:model.live="sort" id="" class="block w-40 text-base bg-gray-100 cursor-pointer dark:text-gray-400 dark:bg-gray-900">
|
||||
<option value="oldest">Terlama</option>
|
||||
<option value="latest">Terbaru</option>
|
||||
<option value="price">Harga</option>
|
||||
</select>
|
||||
|
@ -48,7 +49,7 @@
|
|||
|
||||
</div>
|
||||
<!-- pagination start -->
|
||||
<div class="flex justify-end mt-6">
|
||||
<div class="flex justify-end mt-8 mb-4 px-4">
|
||||
{{ $paketfoto->links() }}
|
||||
</div>
|
||||
<!-- pagination end -->
|
||||
|
|
|
@ -7,44 +7,13 @@
|
|||
</div>
|
||||
<!-- End Col -->
|
||||
|
||||
<div class="col-span-1">
|
||||
<h4 class="font-semibold text-gray-900">Product</h4>
|
||||
|
||||
<div class="mt-3 grid space-y-3">
|
||||
<p><a class="inline-flex gap-x-2 text-gray-600 hover:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="/categories">Categories</a></p>
|
||||
<p><a class="inline-flex gap-x-2 text-gray-600 hover:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="/products">All Products</a></p>
|
||||
<p><a class="inline-flex gap-x-2 text-gray-600 hover:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="/products">Featured Products</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Col -->
|
||||
|
||||
<div class="col-span-1">
|
||||
<h4 class="font-semibold text-gray-900">Company</h4>
|
||||
|
||||
<div class="mt-3 grid space-y-3">
|
||||
<p><a class="inline-flex gap-x-2 text-gray-600 hover:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="#">About us</a></p>
|
||||
<p><a class="inline-flex gap-x-2 text-gray-600 hover:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="#">Blog</a></p>
|
||||
|
||||
<p><a class="inline-flex gap-x-2 text-gray-600 hover:text-gray-400 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="#">Customers</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Col -->
|
||||
|
||||
<div class="col-span-2">
|
||||
<h4 class="font-semibold text-gray-900">Stay up to date</h4>
|
||||
|
||||
<form>
|
||||
<div class="mt-4 flex flex-col items-center gap-2 sm:flex-row sm:gap-3 bg-gray-400 rounded-lg p-2 dark:bg-gray-800">
|
||||
<div class="w-full">
|
||||
<input type="text" id="hero-input" name="hero-input" class="py-3 px-4 block w-full border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-transparent dark:text-gray-400 dark:focus:ring-gray-600" placeholder="Enter your email">
|
||||
</div>
|
||||
<a class="w-full sm:w-auto whitespace-nowrap p-3 inline-flex justify-center items-center gap-x-2 text-sm font-semibold rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600" href="#">
|
||||
Subscribe
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<!-- End Col -->
|
||||
</div>
|
||||
<!-- End Grid -->
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
<div class="justify-center flex-1 max-w-6xl px-4 py-4 mx-auto bg-white border rounded-md dark:border-gray-900 dark:bg-gray-900 md:py-10 md:px-10">
|
||||
<div>
|
||||
<h1 class="px-4 mb-8 text-2xl font-semibold tracking-wide text-gray-700 dark:text-gray-300 ">
|
||||
Terimakasih. Reservasi Berhasil. </h1>
|
||||
@if($booking->status_pembayaran === 'approved')
|
||||
Terimakasih. Reservasi Berhasil.
|
||||
@elseif($booking->status_pembayaran === 'pending')
|
||||
Menunggu Konfirmasi Pembayaran.
|
||||
@elseif($booking->status_pembayaran === 'rejected')
|
||||
Reservasi Ditolak.
|
||||
@endif
|
||||
</h1>
|
||||
<div class="flex border-b border-gray-200 dark:border-gray-700 items-stretch justify-start w-full h-full px-4 mb-8 md:flex-row xl:flex-col md:space-x-6 lg:space-x-8 xl:space-x-0">
|
||||
<div class="flex items-start justify-start flex-shrink-0">
|
||||
<div class="flex items-center justify-center w-full pb-6 space-x-4 md:justify-start">
|
||||
|
@ -51,7 +58,7 @@
|
|||
<div class="px-4 mb-10">
|
||||
<div class="flex flex-col items-stretch justify-center w-full space-y-4 md:flex-row md:space-y-0 md:space-x-8">
|
||||
<div class="flex flex-col w-full space-y-6 ">
|
||||
<h2 class="mb-2 text-xl font-semibold text-gray-700 dark:text-gray-400">Order details</h2>
|
||||
<h2 class="mb-2 text-xl font-semibold text-gray-700 dark:text-gray-400">Detail Reservasi</h2>
|
||||
<div class="flex flex-col items-center justify-center w-full pb-4 space-y-4 border-b border-gray-200 dark:border-gray-700">
|
||||
@foreach($booking->detail as $detail)
|
||||
<div class="flex justify-between w-full">
|
||||
|
@ -76,6 +83,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($booking->bukti_pembayaran)
|
||||
<div class="mt-8 px-4">
|
||||
<h2 class="mb-4 text-xl font-semibold text-gray-700 dark:text-gray-400">Bukti Pembayaran</h2>
|
||||
<img src="{{ asset('storage/' . $booking->bukti_pembayaran) }}" alt="Bukti Pembayaran" class="max-w-md rounded-lg shadow-lg">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center justify-start gap-4 px-4 mt-6 ">
|
||||
<a href="/paketfoto" class="w-full text-center px-4 py-2 text-blue-500 border border-blue-500 rounded-md md:w-auto hover:text-white hover:bg-blue-600 dark:border-gray-700 dark:hover:bg-gray-700 dark:text-gray-300">
|
||||
Kembali
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
<div class="w-full max-w-4xl py-6 px-4 sm:px-6 lg:px-8 mx-auto">
|
||||
<div class="flex items-center font-poppins">
|
||||
<div class="w-full px-4 py-4 mx-auto bg-white border rounded-lg shadow-sm">
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-xl font-semibold text-gray-700">
|
||||
Upload Bukti Pembayaran
|
||||
</h1>
|
||||
<div class="text-right">
|
||||
<p class="text-sm text-gray-600">Sisa Waktu</p>
|
||||
<p class="font-medium text-red-600"
|
||||
x-data="{
|
||||
timeLeft: {{ $this->timeLeft }},
|
||||
formatTime(seconds) {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = Math.floor(seconds % 60);
|
||||
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
|
||||
}
|
||||
}"
|
||||
x-init="setInterval(() => { if(timeLeft > 0) timeLeft--; }, 1000)"
|
||||
x-text="formatTime(timeLeft)">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Informasi Pelanggan -->
|
||||
<div class="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||
<div class="flex items-center space-x-4">
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Nama</p>
|
||||
<p class="font-medium">{{ $booking->nama }}</p>
|
||||
</div>
|
||||
@if($booking && $booking->user)
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Email</p>
|
||||
<p class="font-medium">{{ $booking->user->email }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Informasi Booking -->
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Order Number</p>
|
||||
<p class="font-medium">{{ $booking->id }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Tanggal</p>
|
||||
<p class="font-medium">{{ \Carbon\Carbon::parse($booking->tanggal)->format('d-m-Y') }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Waktu</p>
|
||||
<p class="font-medium">{{ \Carbon\Carbon::parse($booking->waktu)->format('H:i') }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Total</p>
|
||||
<p class="font-medium text-blue-600">Rp {{ number_format($booking->total, 0, ',', '.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detail Pembayaran -->
|
||||
<div class="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||
<h2 class="text-lg font-semibold mb-3">Detail Pembayaran</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Metode Pembayaran</p>
|
||||
<p class="font-medium">{{ ucfirst($booking->metode_pembayaran) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Tipe Pembayaran</p>
|
||||
<p class="font-medium">{{ strtoupper($booking->tipe_pembayaran) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Total Harga</p>
|
||||
<p class="font-medium">Rp {{ number_format($booking->total, 0, ',', '.') }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600">Jumlah yang Harus Dibayar</p>
|
||||
<p class="font-medium">
|
||||
@if(strtolower($booking->tipe_pembayaran) === 'dp')
|
||||
Rp {{ number_format(20000, 0, ',', '.') }}
|
||||
<span class="text-xs text-gray-500 block">(Minimal 30% atau Rp 20.000)</span>
|
||||
@else
|
||||
Rp {{ number_format($booking->total, 0, ',', '.') }}
|
||||
<span class="text-xs text-gray-500 block">(Pembayaran Penuh)</span>
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
@if($booking->metode_pembayaran === 'transfer')
|
||||
<div class="md:col-span-2">
|
||||
<p class="text-sm text-gray-600">Nomor Rekening</p>
|
||||
<p class="font-medium">116101022592507 (Bank BRI)</p>
|
||||
<p class="text-xs text-gray-500">a.n. Adella Novita</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form Upload -->
|
||||
<form wire:submit="uploadBuktiPembayaran">
|
||||
<div class="flex items-start space-x-4">
|
||||
<div class="flex-1">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Upload Bukti Pembayaran</label>
|
||||
<input type="file" wire:model="bukti_pembayaran" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
@error('bukti_pembayaran')
|
||||
<span class="text-sm text-red-500">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="flex items-end space-x-4 pt-6">
|
||||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||
Upload Bukti Pembayaran
|
||||
</button>
|
||||
<a href="{{ route('histori') }}" class="px-4 py-2 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||
Kembali
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -71,7 +71,7 @@
|
|||
<td>{{ $index + 1 }}</td>
|
||||
<td>{{ $reservasi->nama }}</td>
|
||||
<td>{{ $reservasi->tanggal->format('d F Y') }}</td>
|
||||
<td>{{ $reservasi->waktu }}</td>
|
||||
<td>{{ \Carbon\Carbon::parse($reservasi->waktu)->format('H:i') }}</td>
|
||||
<td>
|
||||
@foreach($reservasi->detail as $detail)
|
||||
{{ $detail->paketFoto->nama_paket_foto }}<br>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
use App\Livewire\HomePage;
|
||||
use App\Livewire\PaketFotoPage;
|
||||
use App\Livewire\SuccesPage;
|
||||
use App\Livewire\UploadBuktiPembayaran;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', HomePage::class)->name('home');
|
||||
|
@ -39,8 +40,9 @@
|
|||
});
|
||||
Route::get('/booking', BookingPage::class);
|
||||
Route::get('/booking/{id}', BookingPage::class)->name('booking');
|
||||
Route::get('/histori', Histori::class);
|
||||
Route::get('/histori', Histori::class)->name('histori');
|
||||
Route::get('/cart', CartPage::class);
|
||||
Route::get('/success/{id?}', SuccesPage::class)->name('booking.success');
|
||||
Route::get('/cancel', CancelPage::class);
|
||||
Route::get('/upload-bukti-pembayaran/{id}', UploadBuktiPembayaran::class)->name('upload.bukti.pembayaran');
|
||||
});
|
Loading…
Reference in New Issue