batas waktu
This commit is contained in:
parent
4cd4abccd7
commit
f5f2056e86
|
@ -35,6 +35,7 @@
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Filament\Forms\Components\Modal;
|
use Filament\Forms\Components\Modal;
|
||||||
use Filament\Forms\Components\FileUpload;
|
use Filament\Forms\Components\FileUpload;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class ReservasiiResource extends Resource
|
class ReservasiiResource extends Resource
|
||||||
{
|
{
|
||||||
|
@ -97,6 +98,12 @@ public static function form(Form $form): Form
|
||||||
->imageCropAspectRatio('16:9')
|
->imageCropAspectRatio('16:9')
|
||||||
->imageResizeTargetWidth('1920')
|
->imageResizeTargetWidth('1920')
|
||||||
->imageResizeTargetHeight('1080')
|
->imageResizeTargetHeight('1080')
|
||||||
|
->preserveFilenames()
|
||||||
|
->downloadable()
|
||||||
|
->openable()
|
||||||
|
->deleteUploadedFileUsing(function ($file) {
|
||||||
|
Storage::disk('public')->delete($file);
|
||||||
|
})
|
||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
])
|
])
|
||||||
])->columnSpan(1),
|
])->columnSpan(1),
|
||||||
|
@ -216,8 +223,7 @@ public static function table(Table $table): Table
|
||||||
return $table
|
return $table
|
||||||
->columns([
|
->columns([
|
||||||
Tables\Columns\TextColumn::make('nama')
|
Tables\Columns\TextColumn::make('nama')
|
||||||
->label('Nama')
|
->label('Nama'),
|
||||||
->searchable(),
|
|
||||||
|
|
||||||
Tables\Columns\TextColumn::make('tanggal')
|
Tables\Columns\TextColumn::make('tanggal')
|
||||||
->date('d F Y')
|
->date('d F Y')
|
||||||
|
@ -229,8 +235,7 @@ public static function table(Table $table): Table
|
||||||
|
|
||||||
Tables\Columns\TextColumn::make('detail.paketFoto.nama_paket_foto')
|
Tables\Columns\TextColumn::make('detail.paketFoto.nama_paket_foto')
|
||||||
->label('Paket Foto')
|
->label('Paket Foto')
|
||||||
->listWithLineBreaks()
|
->listWithLineBreaks(),
|
||||||
->searchable(),
|
|
||||||
|
|
||||||
Tables\Columns\TextColumn::make('total')
|
Tables\Columns\TextColumn::make('total')
|
||||||
->money('IDR'),
|
->money('IDR'),
|
||||||
|
|
|
@ -27,12 +27,21 @@ protected function getHeaderActions(): array
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public function getTabs(): array{
|
public function getTabs(): array{
|
||||||
return[
|
$paketFotos = \App\Models\PaketFoto::orderBy('nama_paket_foto')->get();
|
||||||
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')),
|
$tabs = [
|
||||||
'Paket 5 orang' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Paket 5 Orang')),
|
null => \Filament\Resources\Components\Tab::make('Semua Paket')
|
||||||
'Widebox Couple' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Widebox Couple')),
|
->badge(fn () => \App\Models\Reservasii::count())
|
||||||
'Widebox Group' => \Filament\Resources\Components\Tab::make()->query(fn($query) => $query->whereRelation('detail.paketFoto', 'nama_paket_foto', 'Widebox Group')),
|
->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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,8 +118,9 @@ public function updateUnavailableTimes()
|
||||||
{
|
{
|
||||||
if ($this->tanggal) {
|
if ($this->tanggal) {
|
||||||
// Ambil waktu yang sudah dipesan dari database untuk tanggal yang dipilih
|
// 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)
|
$this->bookedTimes = Reservasii::where('tanggal', $this->tanggal)
|
||||||
|
->where('status_pembayaran', 'approved') // Hanya ambil yang sudah approved
|
||||||
->whereHas('detail', function($query) {
|
->whereHas('detail', function($query) {
|
||||||
$query->where('paket_foto_id', $this->paketfoto->id);
|
$query->where('paket_foto_id', $this->paketfoto->id);
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
use Livewire\Attributes\Title;
|
use Livewire\Attributes\Title;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
#[Title('Upload Bukti Pembayaran - SiKolaself')]
|
#[Title('Upload Bukti Pembayaran - SiKolaself')]
|
||||||
class UploadBuktiPembayaran extends Component
|
class UploadBuktiPembayaran extends Component
|
||||||
|
@ -15,6 +17,8 @@ class UploadBuktiPembayaran extends Component
|
||||||
public $booking;
|
public $booking;
|
||||||
public $bukti_pembayaran;
|
public $bukti_pembayaran;
|
||||||
public $bookingId;
|
public $bookingId;
|
||||||
|
public $timeLeft;
|
||||||
|
public $isExpired = false;
|
||||||
|
|
||||||
public function mount($id)
|
public function mount($id)
|
||||||
{
|
{
|
||||||
|
@ -32,10 +36,48 @@ public function mount($id)
|
||||||
if ($this->booking->status_pembayaran === 'approved') {
|
if ($this->booking->status_pembayaran === 'approved') {
|
||||||
return redirect()->route('booking.success', $this->booking->id);
|
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(5);
|
||||||
|
return max(0, Carbon::now()->diffInSeconds($expiryTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function uploadBuktiPembayaran()
|
public function uploadBuktiPembayaran()
|
||||||
{
|
{
|
||||||
|
if ($this->isExpired) {
|
||||||
|
session()->flash('error', 'Waktu upload bukti pembayaran telah habis.');
|
||||||
|
return redirect()->route('histori');
|
||||||
|
}
|
||||||
|
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'bukti_pembayaran' => 'required|image|max:2048', // max 2MB
|
'bukti_pembayaran' => 'required|image|max:2048', // max 2MB
|
||||||
], [
|
], [
|
||||||
|
|
|
@ -25,7 +25,8 @@ class Reservasii extends Model
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'tanggal' => 'date',
|
'tanggal' => 'date',
|
||||||
'waktu' => 'datetime',
|
'waktu' => 'datetime',
|
||||||
'total' => 'decimal:2'
|
'total' => 'decimal:2',
|
||||||
|
'bukti_pembayaran' => 'array'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
|
|
|
@ -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">
|
<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-11 font-poppins dark:bg-gray-800">
|
<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="max-w-6xl px-4 py-4 mx-auto lg:py-8 md:px-6">
|
||||||
|
<div class="flex flex-col md:flex-row -mx-4">
|
||||||
|
<!-- Bagian Gambar -->
|
||||||
<div class="flex flex-wrap -mx-4">
|
|
||||||
<div class="w-full mb-8 md:w-1/2 md:mb-0" x-data="{ mainImage: '{{ url('storage', $paketfoto->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="sticky top-0 z-50 overflow-hidden">
|
||||||
<div class="aspect-[4/3] ">
|
<div class="aspect-[4/3]">
|
||||||
<img x-bind:src="mainImage" alt="" class="object-cover w-full lg:h-full ">
|
<img x-bind:src="mainImage" alt="{{ $paketfoto->nama_paket_foto }}" class="object-cover w-full h-full rounded-lg shadow-lg">
|
||||||
</div>
|
</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'">
|
<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">
|
{{-- <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 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>--}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full px-4 md:w-1/2 ">
|
|
||||||
|
<!-- Bagian Informasi -->
|
||||||
|
<div class="w-full px-4 md:w-1/2">
|
||||||
<div class="lg:pl-20">
|
<div class="lg:pl-20">
|
||||||
<div class="mb-8 ">
|
<div class="mb-8">
|
||||||
<h2 class="max-w-xl mb-6 text-2xl font-bold dark:text-gray-400 md:text-4xl">
|
<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 }}
|
{{ $paketfoto->nama_paket_foto }}
|
||||||
</h2>
|
</h2>
|
||||||
<p class="inline-block mb-6 text-4xl font-bold text-gray-700 dark:text-gray-400 ">
|
<p class="inline-block mb-6 text-2xl sm:text-3xl md:text-4xl font-bold text-gray-700 dark:text-gray-400">
|
||||||
<span>
|
<span>{{ Number::currency($paketfoto->harga_paket_foto, 'IDR') }}</span>
|
||||||
{{ Number::currency($paketfoto->harga_paket_foto, 'IDR') }}
|
</p>
|
||||||
</span>
|
<p class="max-w-md text-sm sm:text-base text-gray-700 dark:text-gray-400">
|
||||||
{{-- <span class="text-base font-normal text-gray-500 line-through dark:text-gray-400">$1800.99</span> --}}
|
{{ $paketfoto->fasilitas }}
|
||||||
</p>
|
</p>
|
||||||
<p class="max-w-md text-gray-700 dark:text-gray-400">
|
|
||||||
{{ $paketfoto->fasilitas }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-32 mb-8 ">
|
<div class="w-full sm:w-32 mb-8">
|
||||||
<div class="flex flex-col items-start">
|
<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">
|
<a href="{{ route('booking', ['id' => $paketfoto->id]) }}"
|
||||||
Reservasi
|
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">
|
||||||
</a>
|
Reservasi
|
||||||
</div>
|
</a>
|
||||||
{{-- <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> --}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,9 +2,26 @@
|
||||||
<div class="flex items-center font-poppins">
|
<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 class="w-full px-4 py-4 mx-auto bg-white border rounded-lg shadow-sm">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="mb-6 text-xl font-semibold text-gray-700">
|
<div class="flex justify-between items-center mb-6">
|
||||||
Upload Bukti Pembayaran
|
<h1 class="text-xl font-semibold text-gray-700">
|
||||||
</h1>
|
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 -->
|
<!-- Informasi Pelanggan -->
|
||||||
<div class="mb-6 p-4 bg-gray-50 rounded-lg">
|
<div class="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||||
|
@ -61,8 +78,8 @@
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-gray-600">Jumlah yang Harus Dibayar</p>
|
<p class="text-sm text-gray-600">Jumlah yang Harus Dibayar</p>
|
||||||
<p class="font-medium">
|
<p class="font-medium">
|
||||||
@if($booking->tipe_pembayaran === 'dp')
|
@if(strtolower($booking->tipe_pembayaran) === 'dp')
|
||||||
Rp {{ number_format(max(20000, $booking->total * 0.3), 0, ',', '.') }}
|
Rp {{ number_format(20000, 0, ',', '.') }}
|
||||||
<span class="text-xs text-gray-500 block">(Minimal 30% atau Rp 20.000)</span>
|
<span class="text-xs text-gray-500 block">(Minimal 30% atau Rp 20.000)</span>
|
||||||
@else
|
@else
|
||||||
Rp {{ number_format($booking->total, 0, ',', '.') }}
|
Rp {{ number_format($booking->total, 0, ',', '.') }}
|
||||||
|
@ -73,8 +90,8 @@
|
||||||
@if($booking->metode_pembayaran === 'transfer')
|
@if($booking->metode_pembayaran === 'transfer')
|
||||||
<div class="md:col-span-2">
|
<div class="md:col-span-2">
|
||||||
<p class="text-sm text-gray-600">Nomor Rekening</p>
|
<p class="text-sm text-gray-600">Nomor Rekening</p>
|
||||||
<p class="font-medium">1234567890 (Bank BCA)</p>
|
<p class="font-medium">116101022592507 (Bank BRI)</p>
|
||||||
<p class="text-xs text-gray-500">a.n. Nama Studio Foto</p>
|
<p class="text-xs text-gray-500">a.n. Adella Novita</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
<td>{{ $index + 1 }}</td>
|
<td>{{ $index + 1 }}</td>
|
||||||
<td>{{ $reservasi->nama }}</td>
|
<td>{{ $reservasi->nama }}</td>
|
||||||
<td>{{ $reservasi->tanggal->format('d F Y') }}</td>
|
<td>{{ $reservasi->tanggal->format('d F Y') }}</td>
|
||||||
<td>{{ $reservasi->waktu }}</td>
|
<td>{{ \Carbon\Carbon::parse($reservasi->waktu)->format('H:i') }}</td>
|
||||||
<td>
|
<td>
|
||||||
@foreach($reservasi->detail as $detail)
|
@foreach($reservasi->detail as $detail)
|
||||||
{{ $detail->paketFoto->nama_paket_foto }}<br>
|
{{ $detail->paketFoto->nama_paket_foto }}<br>
|
||||||
|
|
Loading…
Reference in New Issue