Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
fa3389c
Reorganize the fields
edalzell Mar 16, 2026
e364116
wip
edalzell Mar 18, 2026
55aa50e
Add passing and failing test
marcorieser Mar 20, 2026
62cdfe6
better test, pass test
edalzell Mar 20, 2026
74d4dd8
small tidy
edalzell Mar 20, 2026
052971e
Tidy
edalzell Mar 20, 2026
1ac50fa
Tests
edalzell Mar 20, 2026
bea9656
could be usefule on the front end
edalzell Mar 20, 2026
38bccf6
fix properly
edalzell Mar 23, 2026
68af710
can list weekdays
edalzell Mar 23, 2026
bbdcef1
use site locale
edalzell Mar 25, 2026
e2dccc2
fix test
edalzell Mar 25, 2026
449cf5c
move the creation to setup
edalzell Mar 25, 2026
f60ef12
Set and restore locale for calendar generation
marcorieser Mar 26, 2026
62fc8f1
add `event with timezone offset appears on the correct UTC date` test
marcorieser Mar 26, 2026
329ac2a
don’t shift tz when querying between
edalzell Mar 26, 2026
4779f99
get all tests passing
edalzell Mar 27, 2026
d1e25ed
group occurrences by utc date and time
marcorieser Mar 27, 2026
fac9f8f
use timezones dictionary for settings
marcorieser Mar 27, 2026
bc96e26
use display_timezone as fallback before app timezone
marcorieser Mar 27, 2026
53460fc
group occurrences based on the default timezone
marcorieser Mar 27, 2026
508c957
use period to match all spanning days
marcorieser Mar 27, 2026
4313438
Rename
edalzell Apr 10, 2026
245ed77
Not used
edalzell Apr 10, 2026
c23a7a1
test defaultTimezone
edalzell Apr 10, 2026
8aec565
tidy
edalzell Apr 10, 2026
e72836f
use tag param to set timezone
edalzell Apr 13, 2026
53574ad
Add spansday
edalzell Apr 13, 2026
1c8792a
refactor to use new computed defaults
edalzell Apr 13, 2026
d8338b6
handle missing collection
edalzell Apr 13, 2026
7261661
simpler
edalzell Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 8 additions & 20 deletions resources/blueprints/settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,17 @@ tabs:
-
handle: collections
field:
type: grid
type: collections
display: Collections
sortable: false
add_row: 'Add Collection'
full_width_setting: true
fields:
-
handle: collection
field:
type: collections
display: Collection
width: 50
mode: select
max_items: 1
default:
-
collection: events
width: 50
mode: select
default: events
-
handle: timezone
field:
mode: select
dictionary: timezones
max_items: 1
type: timezones
type: dictionary
display: Timezone
full_width_setting: true
default: 'UTC'
default: computed:default-events-timezone
width: 50
76 changes: 45 additions & 31 deletions resources/fieldsets/event.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,18 @@ fields:
monthly: Monthly
every: Every
multi_day: Multi-Day
width: 33
width: 50
display: Recurrence
default: none
-
handle: timezone
field:
dictionary: timezones
max_items: 1
default: UTC
type: dictionary
display: Timezone
-
handle: all_day
field:
type: toggle
width: 33
display: 'All Day?'
unless:
recurrence: 'equals multi_day'
default: computed:default-event-timezone
width: 50
-
handle: specific_days
field:
Expand Down Expand Up @@ -75,6 +68,13 @@ fields:
multi_day: 'equals true'
recurrence: 'equals multi_day'
format: Y-m-d
-
handle: end_date_spacer
field:
type: spacer
width: 33
if:
recurrence: 'equals none'
-
handle: end_date
field:
Expand All @@ -91,11 +91,44 @@ fields:
if:
recurrence: 'contains_any daily, weekly, monthly, every'
format: Y-m-d
-
handle: exclude_dates
field:
type: grid
fullscreen: false
display: 'Exclude Days'
add_row: 'Add Day'
if_any:
recurrence: 'contains_any monthly, daily, weekly, every'
fields:
-
handle: date
field:
type: date
allow_blank: false
allow_time: false
require_time: false
input_format: YYYY/M/D/YYYY
display: Date
format: Y-m-d
-
handle: times_sections
field:
type: section
display: Times
-
handle: all_day
field:
type: toggle
width: 33
display: 'All Day?'
unless:
recurrence: 'equals multi_day'
-
handle: start_time
field:
type: time
width: 25
width: 33
display: 'Start Time'
instructions: 'Input in [24-hour format](https://en.wikipedia.org/wiki/24-hour_clock)'
unless_any:
Expand All @@ -106,7 +139,7 @@ fields:
handle: end_time
field:
type: time
width: 25
width: 33
display: 'End Time'
instructions: 'Input in [24-hour format](https://en.wikipedia.org/wiki/24-hour_clock)'
unless_any:
Expand Down Expand Up @@ -170,22 +203,3 @@ fields:
field: 'events::event.all_day'
config:
width: 25
-
handle: exclude_dates
field:
type: grid
display: 'Exclude Days'
add_row: 'Add Day'
if_any:
recurrence: 'contains_any monthly, daily, weekly, every'
fields:
-
handle: date
field:
type: date
allow_blank: false
allow_time: false
require_time: false
input_format: YYYY/M/D/YYYY
display: Date
format: Y-m-d
40 changes: 28 additions & 12 deletions src/Events.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Carbon\CarbonInterface;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Traits\Conditionable;
use Statamic\Entries\Entry;
use Statamic\Entries\EntryCollection;
Expand Down Expand Up @@ -45,6 +44,14 @@ class Events

private array $terms = [];

private ?string $timezone = null;

public static function defaultTimezone(): string
{
// return static::setting('timezone', config('statamic.system.display_timezone') ?? config('app.timezone', 'UTC'));
return static::setting('timezone');
}

public static function fromCollection(string $handle): self
{
return tap(new static)->collection($handle);
Expand All @@ -55,21 +62,11 @@ public static function fromEntry(string $id): self
return tap(new static)->event($id);
}

public static function collectionHandles(): Collection
{
return collect(static::setting('collections', ['events']))->keys();
}

public static function setting(string $key, $default = null): mixed
{
return Addon::get('transformstudios/events')->settings()->get($key, $default);
}

public static function timezone(): string
{
return static::setting('timezone', config('app.timezone'));
}

private function __construct() {}

public function collapseMultiDays(): self
Expand Down Expand Up @@ -145,6 +142,13 @@ public function terms(string|array $terms): self
return $this;
}

public function timezone(string $timezone): self
{
$this->timezone = $timezone;

return $this;
}

public function between(string|CarbonInterface $from, string|CarbonInterface $to): EntryCollection|LengthAwarePaginator
{
return $this->output(
Expand All @@ -163,6 +167,18 @@ private function output(callable $type): EntryCollection|LengthAwarePaginator
{
$occurrences = $this->entries()->occurrences(generator: $type);

if (! is_null($this->timezone)) {
$occurrences->transform(function (Entry $occurrence) {
$start = $occurrence->start->setTimezone($this->timezone);
$end = $occurrence->end->setTimezone($this->timezone);

return $occurrence
->setSupplement('start', $start)
->setSupplement('end', $end)
->setSupplement('spansDay', ! $start->isSameDay($end));
});
}

if ($this->offset) {
$occurrences = $occurrences->slice(offset: $this->offset);
}
Expand Down Expand Up @@ -200,7 +216,7 @@ private function isMultiDay(Entry $occurrence): bool
private function occurrences(callable $generator): EntryCollection
{
return $this->entries
->filter(fn (Entry $occurrence) => $this->hasStartDate($occurrence))
->filter(fn (Entry $event) => $this->hasStartDate($event))
// take each event and generate the occurrences
->flatMap(callback: $generator)
->reject(fn (Entry $occurrence) => collect($occurrence->exclude_dates)
Expand Down
14 changes: 12 additions & 2 deletions src/Modifiers/IsEndOfWeek.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@
namespace TransformStudios\Events\Modifiers;

use Carbon\CarbonImmutable;
use Statamic\Facades\Site;
use Statamic\Modifiers\Modifier;

class IsEndOfWeek extends Modifier
{
public function index($value, $params, $context)
{
/*
have to do this because Statamic sets the Carbon locale
to the `lang` of the site, instead of the `locale`
*/
$currentLocale = CarbonImmutable::getLocale();
CarbonImmutable::setLocale(Site::current()->locale());

$date = CarbonImmutable::parse($value);

$date->isSameDay($date->locale(CarbonImmutable::getLocale())->startOfWeek());
$isStartOfWeek = $date->dayOfWeek == now()->endOfWeek()->dayOfWeek;

CarbonImmutable::setLocale($currentLocale);

return $date->dayOfWeek == now()->endOfWeek()->dayOfWeek;
return $isStartOfWeek;
}
}
14 changes: 12 additions & 2 deletions src/Modifiers/IsStartOfWeek.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@
namespace TransformStudios\Events\Modifiers;

use Carbon\CarbonImmutable;
use Statamic\Facades\Site;
use Statamic\Modifiers\Modifier;

class IsStartOfWeek extends Modifier
{
public function index($value, $params, $context)
{
/*
have to do this because Statamic sets the Carbon locale
to the `lang` of the site, instead of the `locale`
*/
$currentLocale = CarbonImmutable::getLocale();
CarbonImmutable::setLocale(Site::current()->locale());

$date = CarbonImmutable::parse($value);

$date->isSameDay($date->locale(CarbonImmutable::getLocale())->startOfWeek());
$isStartOfWeek = $date->dayOfWeek == now()->startOfWeek()->dayOfWeek;

CarbonImmutable::setLocale($currentLocale);

return $date->dayOfWeek == now()->startOfWeek()->dayOfWeek;
return $isStartOfWeek;
}
}
39 changes: 15 additions & 24 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,28 @@

namespace TransformStudios\Events;

use Statamic\Entries\Entry;
use Statamic\Facades\Collection;
use Statamic\Fields\Field;
use Statamic\Fields\Value;
use Statamic\Fieldtypes\Dictionary;
use Statamic\Facades\Field;
use Statamic\Providers\AddonServiceProvider;
use Statamic\Statamic;

class ServiceProvider extends AddonServiceProvider
{
public function bootAddon()
{
collect(Events::setting('collections', [['collection' => 'events']]))
->each(fn (array $collection) => Collection::computed(
$collection['collection'],
'timezone',
$this->timezone(...)
));
}

private function timezone(Entry $entry, $value): string|Value
{
$value ??= Events::timezone();

if ($entry->blueprint()->fields()->get('timezone')?->fieldtype() instanceof Dictionary) {
return $value;
}
Field::computedDefault('default-events-timezone', fn () => Statamic::displayTimezone());
Field::computedDefault('default-event-timezone', fn () => Events::defaultTimezone());

return (new Field('timezone', ['type' => 'timezones', 'max_items' => 1]))
->setValue($value)
->setParent($entry)
->augment()
->value();
collect(Events::setting('collections', ['events']))
->each(function (string $collection) {
Collection::findByHandle($collection)?->entryBlueprint()->ensureField(
'timezone',
[
'dictionary' => 'timezones',
'max_items' => '1',
'type' => 'dictionary',
'default' => 'computed:default-event-timezone',
]);
});
}
}
Loading
Loading