feat: show my bookings on a month calendar
This commit is contained in:
1 parent
5a8227f4d9
commit
4517b84023
12 files changed
+891
-21
No files matched your search
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
/**
|
||||
* The six-week skeleton behind a month calendar: always whole weeks, always starting on a Monday.
|
||||
*
|
||||
* Six weeks rather than "as many as the month needs" so the grid never changes height as you page
|
||||
* through it -- a month can span six week rows (a 31-day month starting on a Sunday does), and a
|
||||
* calendar that grows and shrinks under the cursor is worse than one with a trailing empty row.
|
||||
*
|
||||
* This is only the skeleton. Both calendars in this app draw the same grid and then disagree
|
||||
* entirely about what goes in a cell: the board shows everybody's occupancy for one kind of
|
||||
* resource plus the day you picked, "Meine Buchungen" shows one person's own bookings across all
|
||||
* kinds and has no selected day at all. So the payload stays with the caller, which decorates
|
||||
* these days by MonthDay::key(). gridStart and gridEnd are public precisely so that decoration
|
||||
* can be one range query over the visible window instead of 42 per-day ones.
|
||||
*/
|
||||
final readonly class MonthGrid
|
||||
{
|
||||
private const WEEKS = 6;
|
||||
|
||||
/**
|
||||
* @param list<list<MonthDay>> $weeks
|
||||
*/
|
||||
private function __construct(
|
||||
public \DateTimeImmutable $monthStart,
|
||||
public \DateTimeImmutable $gridStart,
|
||||
public \DateTimeImmutable $gridEnd,
|
||||
public array $weeks,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The grid containing $date, with "today" injectable so the flags can be tested without
|
||||
* waiting for the calendar to roll over. BookingHorizon::latest() takes the same optional
|
||||
* argument for the same reason.
|
||||
*/
|
||||
public static function around(\DateTimeImmutable $date, ?\DateTimeImmutable $today = null): self
|
||||
{
|
||||
$today = ($today ?? new \DateTimeImmutable('today'))->setTime(0, 0);
|
||||
|
||||
$monthStart = $date->setTime(0, 0)->modify('first day of this month');
|
||||
// "monday this week" is a no-op when the month already starts on a Monday, so this is the
|
||||
// whole leading-days calculation -- no weekday arithmetic needed.
|
||||
$gridStart = $monthStart->modify('monday this week');
|
||||
|
||||
$weeks = [];
|
||||
$cursor = $gridStart;
|
||||
|
||||
for ($week = 0; $week < self::WEEKS; ++$week) {
|
||||
$days = [];
|
||||
|
||||
for ($weekday = 0; $weekday < 7; ++$weekday) {
|
||||
$days[] = new MonthDay(
|
||||
date: $cursor,
|
||||
inMonth: $cursor->format('Y-m') === $monthStart->format('Y-m'),
|
||||
isToday: $cursor == $today,
|
||||
isPast: $cursor < $today,
|
||||
isWeekend: (int) $cursor->format('N') >= 6,
|
||||
);
|
||||
|
||||
$cursor = $cursor->modify('+1 day');
|
||||
}
|
||||
|
||||
$weeks[] = $days;
|
||||
}
|
||||
|
||||
// The cursor has already stepped past the grid, hence the day back.
|
||||
return new self($monthStart, $gridStart, $cursor->modify('-1 day'), $weeks);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user