270 lines
8.2 KiB
PHP
270 lines
8.2 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Forms\Studio\Master;
|
|
|
|
use App\Enums\Day;
|
|
use App\Enums\OutletStatus;
|
|
use App\Models\OpeningHour;
|
|
use App\Models\Outlet;
|
|
use App\Models\User;
|
|
use App\Rules\PhoneNumber;
|
|
use App\Traits\Media\WithMediaHandler;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
use Livewire\Form;
|
|
|
|
class OutletForm extends Form
|
|
{
|
|
use WithMediaHandler;
|
|
|
|
public ?Outlet $outlet = null;
|
|
|
|
public string $name = '';
|
|
|
|
public string $phone_number = '';
|
|
|
|
public string $address = '';
|
|
|
|
public ?string $landmark = null;
|
|
|
|
public ?string $maps_url = null;
|
|
|
|
public array $opening_hours = [];
|
|
|
|
public array $facilities = ['Parkir'];
|
|
|
|
public string $opened_date = '';
|
|
|
|
public int $status = OutletStatus::OPERATIONAL->value;
|
|
|
|
public array $featured_image = [];
|
|
|
|
public array $images = [];
|
|
|
|
public function rules(): array
|
|
{
|
|
return array_merge($this->getBasicRules(), $this->getOpeningHoursRules());
|
|
}
|
|
|
|
private function getBasicRules(): array
|
|
{
|
|
return [
|
|
'name' => ['required', 'string', 'max:100'],
|
|
'phone_number' => ['required', 'string', new PhoneNumber],
|
|
'address' => ['required', 'string'],
|
|
'landmark' => ['required', 'string', 'max:30'],
|
|
'maps_url' => [
|
|
'nullable',
|
|
'string',
|
|
'regex:/^(https?:\/\/)?(www\.)?(google\.[a-z.]+\/maps\/.+|goo\.gl\/maps\/.+|maps\.app\.goo\.gl\/.+)$/i',
|
|
],
|
|
'opening_hours' => ['required', 'array'],
|
|
'facilities' => ['required', 'array', 'min:1'],
|
|
'facilities.*' => ['required', 'string', 'max:20'],
|
|
'opened_date' => ['required', 'date'],
|
|
'status' => ['required', Rule::in(OutletStatus::cases())],
|
|
'featured_image' => ['required', 'array', 'max:1'],
|
|
'images' => ['required', 'array', 'max:5'],
|
|
];
|
|
}
|
|
|
|
private function getOpeningHoursRules(): array
|
|
{
|
|
$rules = [];
|
|
|
|
foreach (Day::cases() as $day) {
|
|
$rules["opening_hours.{$day->value}"] = ['required', 'array'];
|
|
$rules["opening_hours.{$day->value}.open_time"] = ['nullable', 'date_format:H:i'];
|
|
$rules["opening_hours.{$day->value}.close_time"] = ['nullable', 'date_format:H:i'];
|
|
}
|
|
|
|
return $rules;
|
|
}
|
|
|
|
public function validationAttributes(): array
|
|
{
|
|
return [
|
|
'name' => 'nama',
|
|
'phone_number' => 'nomor telepon',
|
|
'address' => 'alamat',
|
|
'landmark' => 'patokan',
|
|
'maps_url' => 'tautan google maps',
|
|
'opening_hours' => 'jam beroperasi',
|
|
'opening_hours.*' => 'jam beroperasi',
|
|
'facilities' => 'fasilitas',
|
|
'facilities.*' => 'fasilitas',
|
|
'opened_date' => 'tanggal buka',
|
|
'featured_image' => 'gambar utama',
|
|
'images' => 'gambar',
|
|
];
|
|
}
|
|
|
|
public function setOutlet(Outlet $outlet): void
|
|
{
|
|
$outlet->load(['openingHours', 'facilities']);
|
|
|
|
$this->outlet = $outlet;
|
|
|
|
$this->fillBasicAttributes($outlet);
|
|
$this->opening_hours = $this->formatOpeningHoursForForm($outlet);
|
|
$this->facilities = $outlet->facilities->pluck('name')->toArray();
|
|
$this->featured_image = $this->mapMediaCollection($outlet->getMedia('featured_image'));
|
|
$this->images = $this->mapMediaCollection($outlet->getMedia('images'));
|
|
}
|
|
|
|
private function fillBasicAttributes(Outlet $outlet): void
|
|
{
|
|
$this->name = $outlet->name;
|
|
$this->phone_number = $outlet->phone_number;
|
|
$this->address = $outlet->address;
|
|
$this->landmark = $outlet->landmark;
|
|
$this->maps_url = $outlet->maps_url;
|
|
$this->opened_date = $outlet->opened_date;
|
|
$this->status = $outlet->status->value;
|
|
}
|
|
|
|
private function formatOpeningHoursForForm(Outlet $outlet): array
|
|
{
|
|
return $outlet->openingHours
|
|
->mapWithKeys(fn ($item) => [
|
|
$item->day->value => [
|
|
'open_time' => $item->open_time ? formatTime($item->open_time) : null,
|
|
'close_time' => $item->close_time ? formatTime($item->close_time) : null,
|
|
],
|
|
])
|
|
->toArray();
|
|
}
|
|
|
|
public function store(): void
|
|
{
|
|
$this->validate();
|
|
|
|
$data = $this->prepareDataForSave();
|
|
|
|
DB::transaction(function () use ($data) {
|
|
$outlet = Outlet::create($data);
|
|
|
|
$this->createOpeningHours($outlet, $data['opening_hours']);
|
|
$this->createFacilities($outlet, $data['facilities']);
|
|
$this->handleMediaUpload($outlet);
|
|
|
|
// Auto-assign users with Developer, Owner, and Leader roles to the new outlet
|
|
$this->assignUsersToOutlet($outlet);
|
|
});
|
|
}
|
|
|
|
private function prepareDataForSave(): array
|
|
{
|
|
$data = $this->all();
|
|
|
|
$data['closed_date'] = $data['status'] == OutletStatus::TERMINATED->value
|
|
? now()
|
|
: null;
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function createOpeningHours(Outlet $outlet, array $openingHours): void
|
|
{
|
|
$hoursData = collect($openingHours)
|
|
->map(fn ($time, $day) => [
|
|
'outlet_id' => $outlet->id,
|
|
'day' => $day,
|
|
'open_time' => $time['open_time'],
|
|
'close_time' => $time['close_time'],
|
|
])
|
|
->values()
|
|
->toArray();
|
|
|
|
OpeningHour::insert($hoursData);
|
|
}
|
|
|
|
private function createFacilities(Outlet $outlet, array $facilities): void
|
|
{
|
|
$facilitiesData = collect($facilities)
|
|
->map(fn ($facility) => ['name' => $facility])
|
|
->toArray();
|
|
|
|
$outlet->facilities()->createMany($facilitiesData);
|
|
}
|
|
|
|
private function handleMediaUpload(Outlet $outlet): void
|
|
{
|
|
$this->uploadMedia($this->featured_image, $outlet, 'featured_image');
|
|
$this->uploadMedia($this->images, $outlet, 'images');
|
|
}
|
|
|
|
private function assignUsersToOutlet(Outlet $outlet): void
|
|
{
|
|
// Get users with Developer, Owner, and Leader roles
|
|
$users = User::whereHas('roles', function ($query) {
|
|
$query->whereIn('name', ['Developer', 'Owner', 'Leader']);
|
|
})->get();
|
|
|
|
// Assign users to the outlet
|
|
if ($users->isNotEmpty()) {
|
|
$outlet->users()->attach($users->pluck('id'));
|
|
}
|
|
}
|
|
|
|
public function update(): void
|
|
{
|
|
$this->validate();
|
|
|
|
$data = $this->prepareDataForSave();
|
|
|
|
DB::transaction(function () use ($data) {
|
|
$this->outlet->update($data);
|
|
|
|
$this->updateOpeningHours($data['opening_hours']);
|
|
$this->updateFacilities($data['facilities']);
|
|
$this->handleMediaSync($data);
|
|
$this->handleMediaUpload($this->outlet);
|
|
});
|
|
}
|
|
|
|
private function updateOpeningHours(array $openingHours): void
|
|
{
|
|
// Delete opening hours for days that are not in the new data
|
|
$this->outlet->openingHours()
|
|
->whereNotIn('day', array_keys($openingHours))
|
|
->delete();
|
|
|
|
// Add or update opening hours
|
|
foreach ($openingHours as $day => $hours) {
|
|
OpeningHour::updateOrCreate(
|
|
[
|
|
'outlet_id' => $this->outlet->id,
|
|
'day' => $day,
|
|
],
|
|
[
|
|
'open_time' => $hours['open_time'] ?? null,
|
|
'close_time' => $hours['close_time'] ?? null,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
private function updateFacilities(array $facilities): void
|
|
{
|
|
// Delete facilities that are not in the new list
|
|
$this->outlet->facilities()
|
|
->whereNotIn('name', $facilities)
|
|
->delete();
|
|
|
|
// Add or update facilities
|
|
foreach ($facilities as $facilityName) {
|
|
$this->outlet->facilities()->updateOrCreate(
|
|
['name' => $facilityName],
|
|
['name' => $facilityName]
|
|
);
|
|
}
|
|
}
|
|
|
|
private function handleMediaSync(array $data): void
|
|
{
|
|
$this->syncMedia($data['featured_image'], $this->outlet, 'featured_image');
|
|
$this->syncMedia($data['images'], $this->outlet, 'images');
|
|
}
|
|
}
|