433 lines
13 KiB
PHP
433 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Schedule;
|
|
|
|
use App\Models\Dish;
|
|
use App\Models\Schedule;
|
|
use App\Models\ScheduledUserDish;
|
|
use App\Models\User;
|
|
use App\Models\UserDish;
|
|
use Carbon\Carbon;
|
|
use DishPlanner\Schedule\Services\ScheduleCalendarService;
|
|
use DishPlanner\ScheduledUserDish\Actions\DeleteScheduledUserDishForDateAction;
|
|
use DishPlanner\ScheduledUserDish\Actions\SkipScheduledUserDishForDateAction;
|
|
use Exception;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Livewire\Component;
|
|
|
|
class ScheduleCalendar extends Component
|
|
{
|
|
public $currentMonth;
|
|
public $currentYear;
|
|
public $calendarDays = [];
|
|
public $showRegenerateModal = false;
|
|
public $regenerateDate = null;
|
|
public $regenerateUserId = null;
|
|
|
|
// Edit dish modal
|
|
public $showEditDishModal = false;
|
|
public $editDate = null;
|
|
public $editUserId = null;
|
|
public $selectedDishId = null;
|
|
public $availableDishes = [];
|
|
|
|
// Add dish modal
|
|
public $showAddDishModal = false;
|
|
public $addDate = null;
|
|
public $addUserIds = [];
|
|
public $addSelectedDishId = null;
|
|
public $addAvailableUsers = [];
|
|
public $addAvailableDishes = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->currentMonth = now()->month;
|
|
$this->currentYear = now()->year;
|
|
$this->loadCalendar();
|
|
}
|
|
|
|
protected $listeners = ['schedule-generated' => 'refreshCalendar'];
|
|
|
|
public function render(): View
|
|
{
|
|
return view('livewire.schedule.schedule-calendar');
|
|
}
|
|
|
|
public function refreshCalendar(): void
|
|
{
|
|
$this->loadCalendar();
|
|
}
|
|
|
|
public function loadCalendar(): void
|
|
{
|
|
$service = new ScheduleCalendarService();
|
|
$this->calendarDays = $service->getCalendarDays(
|
|
auth()->user(),
|
|
$this->currentMonth,
|
|
$this->currentYear
|
|
);
|
|
}
|
|
|
|
public function previousMonth(): void
|
|
{
|
|
if ($this->currentMonth === 1) {
|
|
$this->currentMonth = 12;
|
|
$this->currentYear--;
|
|
} else {
|
|
$this->currentMonth--;
|
|
}
|
|
$this->loadCalendar();
|
|
}
|
|
|
|
public function nextMonth(): void
|
|
{
|
|
if ($this->currentMonth === 12) {
|
|
$this->currentMonth = 1;
|
|
$this->currentYear++;
|
|
} else {
|
|
$this->currentMonth++;
|
|
}
|
|
$this->loadCalendar();
|
|
}
|
|
|
|
public function regenerateForUserDate($date, $userId): void
|
|
{
|
|
if (!$this->authorizeUser($userId)) {
|
|
session()->flash('error', 'Unauthorized action.');
|
|
return;
|
|
}
|
|
|
|
$this->regenerateDate = $date;
|
|
$this->regenerateUserId = $userId;
|
|
$this->showRegenerateModal = true;
|
|
}
|
|
|
|
public function confirmRegenerate(): void
|
|
{
|
|
try {
|
|
if (!$this->authorizeUser($this->regenerateUserId)) {
|
|
session()->flash('error', 'Unauthorized action.');
|
|
return;
|
|
}
|
|
|
|
$action = new DeleteScheduledUserDishForDateAction();
|
|
$action->execute(
|
|
auth()->user(),
|
|
Carbon::parse($this->regenerateDate),
|
|
$this->regenerateUserId
|
|
);
|
|
|
|
$this->showRegenerateModal = false;
|
|
$this->loadCalendar();
|
|
|
|
session()->flash('success', 'Schedule regenerated for the selected date!');
|
|
} catch (Exception $e) {
|
|
Log::error('Schedule regeneration failed', ['exception' => $e, 'date' => $this->regenerateDate]);
|
|
session()->flash('error', 'Unable to regenerate schedule. Please try again.');
|
|
}
|
|
}
|
|
|
|
public function skipDay($date, $userId): void
|
|
{
|
|
try {
|
|
if (!$this->authorizeUser($userId)) {
|
|
session()->flash('error', 'Unauthorized action.');
|
|
return;
|
|
}
|
|
|
|
$action = new SkipScheduledUserDishForDateAction();
|
|
$action->execute(
|
|
auth()->user(),
|
|
Carbon::parse($date),
|
|
$userId
|
|
);
|
|
|
|
$this->loadCalendar();
|
|
|
|
session()->flash('success', 'Day skipped successfully!');
|
|
} catch (Exception $e) {
|
|
Log::error('Skip day failed', ['exception' => $e, 'date' => $date, 'userId' => $userId]);
|
|
session()->flash('error', 'Unable to skip day. Please try again.');
|
|
}
|
|
}
|
|
|
|
private function authorizeUser(int $userId): bool
|
|
{
|
|
$user = User::find($userId);
|
|
return $user && $user->planner_id === auth()->id();
|
|
}
|
|
|
|
public function cancel(): void
|
|
{
|
|
$this->showRegenerateModal = false;
|
|
$this->regenerateDate = null;
|
|
$this->regenerateUserId = null;
|
|
$this->showEditDishModal = false;
|
|
$this->editDate = null;
|
|
$this->editUserId = null;
|
|
$this->selectedDishId = null;
|
|
$this->availableDishes = [];
|
|
$this->showAddDishModal = false;
|
|
$this->addDate = null;
|
|
$this->addUserIds = [];
|
|
$this->addSelectedDishId = null;
|
|
$this->addAvailableUsers = [];
|
|
$this->addAvailableDishes = [];
|
|
}
|
|
|
|
public function removeDish($date, $userId): void
|
|
{
|
|
try {
|
|
if (!$this->authorizeUser($userId)) {
|
|
session()->flash('error', 'Unauthorized action.');
|
|
return;
|
|
}
|
|
|
|
$schedule = Schedule::where('planner_id', auth()->id())
|
|
->where('date', $date)
|
|
->first();
|
|
|
|
if ($schedule) {
|
|
ScheduledUserDish::where('schedule_id', $schedule->id)
|
|
->where('user_id', $userId)
|
|
->delete();
|
|
}
|
|
|
|
$this->loadCalendar();
|
|
session()->flash('success', 'Dish removed successfully!');
|
|
} catch (Exception $e) {
|
|
Log::error('Remove dish failed', ['exception' => $e, 'date' => $date, 'userId' => $userId]);
|
|
session()->flash('error', 'Unable to remove dish. Please try again.');
|
|
}
|
|
}
|
|
|
|
public function openAddDishModal($date): void
|
|
{
|
|
$this->addDate = $date;
|
|
|
|
// Load all users for this planner
|
|
$this->addAvailableUsers = User::where('planner_id', auth()->id())
|
|
->orderBy('name')
|
|
->get();
|
|
|
|
$this->addAvailableDishes = [];
|
|
$this->addUserIds = [];
|
|
$this->addSelectedDishId = null;
|
|
|
|
$this->showAddDishModal = true;
|
|
}
|
|
|
|
public function toggleAllUsers(): void
|
|
{
|
|
if (count($this->addUserIds) === count($this->addAvailableUsers)) {
|
|
$this->addUserIds = [];
|
|
} else {
|
|
$this->addUserIds = $this->addAvailableUsers->pluck('id')->map(fn($id) => (string) $id)->toArray();
|
|
}
|
|
$this->updateAvailableDishes();
|
|
}
|
|
|
|
public function updatedAddUserIds(): void
|
|
{
|
|
$this->updateAvailableDishes();
|
|
}
|
|
|
|
private function updateAvailableDishes(): void
|
|
{
|
|
if (empty($this->addUserIds)) {
|
|
$this->addAvailableDishes = [];
|
|
} else {
|
|
// Load dishes that ALL selected users have in common
|
|
$selectedCount = count($this->addUserIds);
|
|
$this->addAvailableDishes = Dish::whereHas('users', function ($query) {
|
|
$query->whereIn('users.id', $this->addUserIds);
|
|
}, '=', $selectedCount)->orderBy('name')->get();
|
|
}
|
|
$this->addSelectedDishId = null;
|
|
}
|
|
|
|
public function saveAddDish(): void
|
|
{
|
|
try {
|
|
if (empty($this->addUserIds)) {
|
|
session()->flash('error', 'Please select at least one user.');
|
|
return;
|
|
}
|
|
|
|
if (!$this->addSelectedDishId) {
|
|
session()->flash('error', 'Please select a dish.');
|
|
return;
|
|
}
|
|
|
|
// Find or create the schedule for this date
|
|
$schedule = Schedule::firstOrCreate(
|
|
[
|
|
'planner_id' => auth()->id(),
|
|
'date' => $this->addDate,
|
|
],
|
|
['is_skipped' => false]
|
|
);
|
|
|
|
$addedCount = 0;
|
|
$skippedCount = 0;
|
|
|
|
foreach ($this->addUserIds as $userId) {
|
|
if (!$this->authorizeUser((int) $userId)) {
|
|
$skippedCount++;
|
|
continue;
|
|
}
|
|
|
|
// Check if user already has a dish scheduled for this date
|
|
$existing = ScheduledUserDish::where('schedule_id', $schedule->id)
|
|
->where('user_id', $userId)
|
|
->first();
|
|
|
|
if ($existing) {
|
|
$skippedCount++;
|
|
continue;
|
|
}
|
|
|
|
// Find the UserDish for this user and dish
|
|
$userDish = UserDish::where('user_id', $userId)
|
|
->where('dish_id', $this->addSelectedDishId)
|
|
->first();
|
|
|
|
if (!$userDish) {
|
|
$skippedCount++;
|
|
continue;
|
|
}
|
|
|
|
// Create the scheduled user dish
|
|
ScheduledUserDish::create([
|
|
'schedule_id' => $schedule->id,
|
|
'user_id' => $userId,
|
|
'user_dish_id' => $userDish->id,
|
|
'is_skipped' => false,
|
|
]);
|
|
$addedCount++;
|
|
}
|
|
|
|
$this->closeAddDishModal();
|
|
$this->loadCalendar();
|
|
|
|
if ($addedCount > 0 && $skippedCount > 0) {
|
|
session()->flash('success', "Dish added for {$addedCount} user(s). {$skippedCount} user(s) skipped (already scheduled).");
|
|
} elseif ($addedCount > 0) {
|
|
session()->flash('success', "Dish added for {$addedCount} user(s)!");
|
|
} else {
|
|
session()->flash('error', 'No users could be scheduled. They may already have dishes for this date.');
|
|
}
|
|
} catch (Exception $e) {
|
|
Log::error('Add dish failed', ['exception' => $e]);
|
|
session()->flash('error', 'Unable to add dish. Please try again.');
|
|
}
|
|
}
|
|
|
|
private function closeAddDishModal(): void
|
|
{
|
|
$this->showAddDishModal = false;
|
|
$this->addDate = null;
|
|
$this->addUserIds = [];
|
|
$this->addSelectedDishId = null;
|
|
$this->addAvailableUsers = [];
|
|
$this->addAvailableDishes = [];
|
|
}
|
|
|
|
public function editDish($date, $userId): void
|
|
{
|
|
if (!$this->authorizeUser($userId)) {
|
|
session()->flash('error', 'Unauthorized action.');
|
|
return;
|
|
}
|
|
|
|
$this->editDate = $date;
|
|
$this->editUserId = $userId;
|
|
|
|
// Load dishes available for this user (via UserDish pivot)
|
|
$this->availableDishes = Dish::whereHas('users', function ($query) use ($userId) {
|
|
$query->where('users.id', $userId);
|
|
})->orderBy('name')->get();
|
|
|
|
// Get currently selected dish for this date/user if exists
|
|
$schedule = Schedule::where('planner_id', auth()->id())
|
|
->where('date', $date)
|
|
->first();
|
|
|
|
if ($schedule) {
|
|
$scheduledUserDish = ScheduledUserDish::where('schedule_id', $schedule->id)
|
|
->where('user_id', $userId)
|
|
->first();
|
|
|
|
if ($scheduledUserDish && $scheduledUserDish->userDish) {
|
|
$this->selectedDishId = $scheduledUserDish->userDish->dish_id;
|
|
}
|
|
}
|
|
|
|
$this->showEditDishModal = true;
|
|
}
|
|
|
|
public function saveDish(): void
|
|
{
|
|
try {
|
|
if (!$this->authorizeUser($this->editUserId)) {
|
|
session()->flash('error', 'Unauthorized action.');
|
|
return;
|
|
}
|
|
|
|
if (!$this->selectedDishId) {
|
|
session()->flash('error', 'Please select a dish.');
|
|
return;
|
|
}
|
|
|
|
// Find or create the schedule for this date
|
|
$schedule = Schedule::firstOrCreate(
|
|
[
|
|
'planner_id' => auth()->id(),
|
|
'date' => $this->editDate,
|
|
],
|
|
['is_skipped' => false]
|
|
);
|
|
|
|
// Find the UserDish for this user and dish
|
|
$userDish = UserDish::where('user_id', $this->editUserId)
|
|
->where('dish_id', $this->selectedDishId)
|
|
->first();
|
|
|
|
if (!$userDish) {
|
|
session()->flash('error', 'This dish is not assigned to this user.');
|
|
return;
|
|
}
|
|
|
|
// Update or create the scheduled user dish
|
|
ScheduledUserDish::updateOrCreate(
|
|
[
|
|
'schedule_id' => $schedule->id,
|
|
'user_id' => $this->editUserId,
|
|
],
|
|
[
|
|
'user_dish_id' => $userDish->id,
|
|
'is_skipped' => false,
|
|
]
|
|
);
|
|
|
|
$this->showEditDishModal = false;
|
|
$this->editDate = null;
|
|
$this->editUserId = null;
|
|
$this->selectedDishId = null;
|
|
$this->availableDishes = [];
|
|
|
|
$this->loadCalendar();
|
|
session()->flash('success', 'Dish updated successfully!');
|
|
} catch (Exception $e) {
|
|
Log::error('Save dish failed', ['exception' => $e]);
|
|
session()->flash('error', 'Unable to save dish. Please try again.');
|
|
}
|
|
}
|
|
|
|
public function getMonthNameProperty(): string
|
|
{
|
|
$service = new ScheduleCalendarService();
|
|
return $service->getMonthName($this->currentMonth, $this->currentYear);
|
|
}
|
|
}
|