diff --git a/composer.json b/composer.json index 970b30e..5c48046 100644 --- a/composer.json +++ b/composer.json @@ -48,6 +48,7 @@ "nunomaduro/collision": "^6.0 || ^7.0", "phpunit/phpunit": "^9.0 || ^10.0", "orchestra/testbench": "^7.0 || ^8.0", + "spatie/laravel-ray": "^1.35", "spatie/test-time": "^1.2" }, "config": { diff --git a/src/EventFactory.php b/src/EventFactory.php index e24ad98..24b4ae0 100644 --- a/src/EventFactory.php +++ b/src/EventFactory.php @@ -17,7 +17,7 @@ public static function createFromEntry(Entry $event, bool $collapseMultiDays = f } // this has to be `->value` because `recurrence` returns a `LabeledValue`. - if ($event->recurrence->value()) { + if (in_array($event->recurrence->value(), ['daily', 'weekly', 'monthly', 'every'])) { return new RecurringEvent($event); } diff --git a/src/Events.php b/src/Events.php index 00322ad..e69cc05 100644 --- a/src/Events.php +++ b/src/Events.php @@ -3,6 +3,7 @@ namespace TransformStudios\Events; use Carbon\CarbonInterface; +use Exception; use Illuminate\Support\Traits\Conditionable; use Statamic\Entries\Entry; use Statamic\Entries\EntryCollection; @@ -165,7 +166,8 @@ private function entries(): self private function occurrences(callable $generator): EntryCollection { return $this->entries - // take each event and generate the occurences + ->filter(fn (Entry $occurrence) => $this->hasStartDate($occurrence)) + // take each event and generate the occurrences ->flatMap(callback: $generator) ->reject(fn (Entry $occurrence) => collect($occurrence->exclude_dates) ->filter(fn (Values $dateRow) => $dateRow->date) @@ -174,6 +176,21 @@ private function occurrences(callable $generator): EntryCollection ->values(); } + private function hasStartDate(Entry $occurrence): bool + { + if ($occurrence->multi_day || $occurrence->get('recurrence') === 'multi_day') { + try { + $days = collect($occurrence->days); + + return $days->isNotEmpty() && $days->every(fn (Values $day) => $day->date); + } catch (Exception $e) { + return false; + } + } + + return $occurrence->has('start_date'); + } + private function paginate(EntryCollection $occurrences): LengthAwarePaginator { return new LengthAwarePaginator( diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 2d473a2..09bbbb4 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -67,6 +67,14 @@ private function bootCarbon(): self private function bootFields(): self { + Collection::computed('events', 'recurrence', function ($entry, $value) { + if ($value) { + return $value; + } + + return $entry->multi_day ? 'multi_day' : 'none'; + }); + Collection::computed('events', 'timezone', function ($entry, $value) { if ($value) { return $value; diff --git a/tests/Unit/EventsTest.php b/tests/Unit/EventsTest.php index 5e75537..c927612 100755 --- a/tests/Unit/EventsTest.php +++ b/tests/Unit/EventsTest.php @@ -376,4 +376,41 @@ public function canHandleEmptyExcludeDates() $this->assertCount(4, $occurrences); } + + /** @test */ + public function canFilterOurEventsWithNoStartDate() + { + Carbon::setTestNow(now()->setTimeFromTimeString('10:00')); + + Entry::make() + ->collection('events') + ->slug('single-event') + ->data([ + 'title' => 'Single Event', + 'start_time' => '11:00', + 'end_time' => '12:00', + ])->save(); + Entry::make() + ->collection('events') + ->slug('legacy-multi-day-event') + ->data([ + 'title' => 'Legacy Multi-day Event', + 'multi_day' => true, + 'days' => [ + ['date' => 'bad-date'], + ], + ])->save(); + Entry::make() + ->collection('events') + ->slug('legacy-multi-day-event-2') + ->data([ + 'title' => 'Legacy Multi-day Event', + 'multi_day' => true, + ])->save(); + + $occurrences = Events::fromCollection(handle: 'events') + ->upcoming(5); + + $this->assertEmpty($occurrences); + } }