From bb62469dbfde997fe973cb6ab718830ee28f0621 Mon Sep 17 00:00:00 2001 From: mikrosmile Date: Wed, 23 Nov 2022 10:42:33 +0000 Subject: [PATCH 1/2] Update CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4fddf0..8882d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `Timex` will be documented in this file. +## 1.0.3 - 2022-11-23 + +### What's Changed + +- Translations, config, redirect to timex page by @mikrosmile in https://github.com/buildix/timex/pull/6 + +**Full Changelog**: https://github.com/buildix/timex/compare/1.0.2...1.0.3 + ## 1.0.2 - 2022-11-22 ### What's Changed From e7a3e7f86efd908589e452725f101317ebb1f5a9 Mon Sep 17 00:00:00 2001 From: mihailkarzanov Date: Tue, 29 Nov 2022 09:16:43 +0300 Subject: [PATCH 2/2] v. 1.0.4 Signed-off-by: mihailkarzanov --- README.md | 171 ++++++++++++++++-- config/timex.php | 63 ++++++- .../migrations/create_timex_tables.php.stub | 6 +- resources/dist/timex.css | 89 +++++++++ resources/lang/en/timex.php | 15 +- resources/lang/ru/timex.php | 17 +- resources/views/calendar/day.blade.php | 16 +- resources/views/calendar/event-list.blade.php | 3 + resources/views/calendar/event.blade.php | 22 ++- resources/views/calendar/month.blade.php | 2 +- resources/views/calendar/week.blade.php | 11 +- resources/views/layout/heading.blade.php | 2 +- resources/views/layout/page.blade.php | 4 + src/Calendar/Event.php | 1 + src/Calendar/EventList.php | 105 +++++++++++ src/Events/EventItem.php | 21 +++ src/Models/Event.php | 13 +- src/Pages/Timex.php | 35 ++-- src/Resources/EventResource.php | 112 +++++++++++- .../EventResource/Pages/CreateEvent.php | 92 +--------- .../EventResource/Pages/EditEvent.php | 72 +------- .../EventResource/Pages/ListEvents.php | 15 ++ src/TimexServiceProvider.php | 6 + src/Traits/TimexTrait.php | 51 +++++- src/Widgets/Mini/EventWidget.php | 22 +-- 25 files changed, 729 insertions(+), 237 deletions(-) create mode 100644 resources/dist/timex.css create mode 100644 resources/views/calendar/event-list.blade.php create mode 100644 src/Calendar/EventList.php diff --git a/README.md b/README.md index 4d81d05..c58e8a9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![Latest Version on Packagist](https://img.shields.io/packagist/v/buildix/timex.svg?style=flat-square)](https://packagist.org/packages/buildix/timex) [![Total Downloads](https://img.shields.io/packagist/dt/buildix/timex.svg?style=flat-square)](https://packagist.org/packages/buildix/timex) + timex-main @@ -24,13 +25,29 @@ php artisan vendor:publish --tag="timex-migrations" php artisan migrate ``` +**If you're upgrading from 1.0.3 > 1.0.4 make sure to alter your database table to include `participants` column:** +``` +php artisan make:migration add_participants_to_timex_table --table=timex-events +``` + +In your newly created migration file add the following: + +```php +Schema::create('timex-events', function ($table) { + $table->json("participants")->nullable; + }); +``` + You can publish the config file with: ```bash php artisan vendor:publish --tag="timex-config" ``` -This is the contents of the published config file: +
TiMEX Config +

+ +#### This is the contents of the published config file: ```php return [ @@ -49,7 +66,7 @@ return [ |-------------------------------------------------------------------------- | TIMEX Mini widget |-------------------------------------------------------------------------- - | * - Not available on the release. Subscribe for future updates + | | You can disable or enable individually widgets or entirely the whole view. | */ @@ -62,7 +79,7 @@ return [ /* |-------------------------------------------------------------------------- - | TIMEX Calendar start & end of week + | TIMEX Calendar configurations |-------------------------------------------------------------------------- | | Change according to your locale. @@ -70,10 +87,12 @@ return [ */ 'week' => [ - 'start' => \Carbon\Carbon::MONDAY, - 'end' => \Carbon\Carbon::SUNDAY + 'start' => Carbon::MONDAY, + 'end' => Carbon::SUNDAY ], + 'dayName' => 'minDayName', // minDayName or dayName or shortDayName + /* |-------------------------------------------------------------------------- | TIMEX Resources & Pages @@ -89,18 +108,32 @@ return [ 'slug' => 'timex', 'group' => 'timex', 'shouldRegisterNavigation' => true, + 'modalWidth' => 'xl', 'icon' => [ 'static' => true, 'timex' => 'timex-timex', - 'day' => 'timex-day-'.Carbon::today()->day + 'day' => 'timex-day-' ], 'label' => [ - 'navigation' => Carbon::today()->isoFormat('dddd, D MMM'), - 'breadcrumbs' => Carbon::today()->isoFormat('dddd, D MMM'), - 'title' => Carbon::today()->isoFormat('dddd, D MMM'), + 'navigation' => [ + 'static' => false, + 'format' => 'dddd, D MMM', + ], + 'breadcrumbs' => [ + 'static' => false, + 'format' => 'dddd, D MMM', + ], + 'title' => [ + 'static' => false, + 'format' => 'dddd, D MMM', + ], ], 'buttons' => [ - 'today' => \Carbon\Carbon::today()->format('d M'), + 'today' => [ + 'static' => false, + 'format' => 'D MMM' + ], + 'outlined' => true, 'icons' => [ 'previousMonth' => 'heroicon-o-chevron-left', 'nextMonth' => 'heroicon-o-chevron-right', @@ -117,8 +150,16 @@ return [ ], 'models' => [ 'event' => \Buildix\Timex\Models\Event::class, - 'label' => 'Event', - 'pluralLabel' => 'Events' + 'users' => [ + 'model' => \App\Models\User::class, + 'name' => 'name', + 'id' => 'id', + ], + ], + 'tables' => [ + 'event' => [ + 'name' => 'timex_events', + ], ], /* @@ -126,13 +167,37 @@ return [ | TIMEX Event categories |-------------------------------------------------------------------------- | - | Categories names are used to define color. + | Categories names are used to define colors & icons. | Each represents default tailwind colors. | You may change as you wish, just make sure your color have -500 / -600 and etc variants + | You may also go for a custom Category model to define your labels, colors and icons | */ 'categories' => [ + 'isModelEnabled' => true, + /* + |-------------------------------------------------------------------------- + | Category Model + |-------------------------------------------------------------------------- + | + | You can define your custom Category model. + | Minimum and default columns in your DB should be: id, value, icon, color. + | + | + */ + 'model' => [ + 'class' => \App\Models\Category::class, // \App\Models\Category::class + 'key' => 'id', // "id" is a DB column - you can change by any primary key + 'value' => 'value', // "value" is a DB column - it used for Select options and displays on Resource page + 'icon' => 'icon', // "icon" is a DB column - define here any heroicon- icon + 'color' => 'color', // "color" is a DB column - default tailwindcss colors names like: primary / secondary / danger + ], + /* + |-------------------------------------------------------------------------- + | Default TiMEX Categories + |-------------------------------------------------------------------------- + */ 'labels' => [ 'primary' => 'Primary category', 'secondary' => 'Secondary category', @@ -152,9 +217,13 @@ return [ 'success' => 'success', ], ], + ]; ``` +

+
+ ## Usage After your fresh installation, TIMEX calendar is working out of the box (make sure to run migration) and start managing your time. @@ -195,6 +264,43 @@ Also, you can change slug, icon, and the Filament resource itself 'shouldRegisterNavigation' => false, ], ``` +#### Event custom table name + +You may change from default `timex_events` table name by changing config: + +```php +'tables' => [ + 'event' => [ + 'name' => 'your_custom_table_name', +], +``` + +#### Event category model + +You may create a custom category model, and define the class and main key table values in config with `isModelEnabled` set to `true`: + +```php +'model' => [ + 'class' => '', // \App\Models\Category::class + 'key' => 'id', // "id" is a DB column - you can change by any primary key + 'value' => 'value', // "value" is a DB column - it used for Select options and displays on Resource page + 'icon' => 'icon', // "icon" is a DB column - define here any heroicon- icon + 'color' => 'color', // "color" is a DB column - default tailwindcss colors names like: primary / secondary / danger +], +``` +#### User model + +TiMEX uses default User model `\App\Models\User::class` + +You may change the class to your preferences and define which columns will be used for ID and name: + +```php +'users' => [ + 'model' => \App\Models\User::class, + 'name' => 'name', + 'id' => 'id', + ], +``` ### TiMEX Page @@ -206,7 +312,7 @@ If you need to change label naming, slug, navigation group, etc, go ahead to TiM timex-dark -### Dynamic icon set +### Dynamic icon set & labels timex-icons @@ -223,6 +329,43 @@ You may change navigation icon from static to dynamic, simply changing TiMEX con ], ``` +You may change navigation label, title, breadcrumbs from dynamic to static string, which you can translate to any language you want by changing config properties: + +```php +// timex.php + +'label' => [ + 'navigation' => [ + 'static' => true, + // + ], + 'breadcrumbs' => [ + 'static' => true, + // + ], + 'title' => [ + 'static' => true, + // + ], +], +'buttons' => [ + 'today' => [ + 'static' => true, + // + ], +], + +// resources/lang/en/timex.php + +'labels' => [ + 'navigation' => 'TiMEX', + 'breadcrumbs' => 'TiMEX', + 'title' => 'TiMEX', + 'today' => 'Today', +], + +``` + ### Start & End of week You may change how the calendar renders your week according to your locale. In order to make week start on Sunday, change TiMEX config accordingly: diff --git a/config/timex.php b/config/timex.php index 472670f..4462257 100644 --- a/config/timex.php +++ b/config/timex.php @@ -27,7 +27,6 @@ 'isMiniCalendarEnabled' => true, 'isDayViewHidden' => false, 'isNextMeetingViewHidden' => false, - 'noEventsTitle' => 'No upcoming events' ], /* @@ -40,8 +39,8 @@ */ 'week' => [ - 'start' => \Carbon\Carbon::MONDAY, - 'end' => \Carbon\Carbon::SUNDAY + 'start' => Carbon::MONDAY, + 'end' => Carbon::SUNDAY ], 'dayName' => 'minDayName', // minDayName or dayName or shortDayName @@ -68,12 +67,24 @@ 'day' => 'timex-day-' ], 'label' => [ - 'navigation' => 'dddd, D MMM', - 'breadcrumbs' => 'dddd, D MMM', - 'title' => 'dddd, D MMM' + 'navigation' => [ + 'static' => false, + 'format' => 'dddd, D MMM', + ], + 'breadcrumbs' => [ + 'static' => false, + 'format' => 'dddd, D MMM', + ], + 'title' => [ + 'static' => false, + 'format' => 'dddd, D MMM', + ], ], 'buttons' => [ - 'today' => 'D MMM', + 'today' => [ + 'static' => false, + 'format' => 'D MMM' + ], 'outlined' => true, 'icons' => [ 'previousMonth' => 'heroicon-o-chevron-left', @@ -91,8 +102,16 @@ ], 'models' => [ 'event' => \Buildix\Timex\Models\Event::class, - 'label' => 'Event', - 'pluralLabel' => 'Events' + 'users' => [ + 'model' => \App\Models\User::class, + 'name' => 'name', + 'id' => 'id', + ], + ], + 'tables' => [ + 'event' => [ + 'name' => 'timex_events', + ], ], /* @@ -100,13 +119,37 @@ | TIMEX Event categories |-------------------------------------------------------------------------- | - | Categories names are used to define color. + | Categories names are used to define colors & icons. | Each represents default tailwind colors. | You may change as you wish, just make sure your color have -500 / -600 and etc variants + | You may also go for a custom Category model to define your labels, colors and icons | */ 'categories' => [ + 'isModelEnabled' => false, + /* + |-------------------------------------------------------------------------- + | Category Model + |-------------------------------------------------------------------------- + | + | You can define your custom Category model. + | Minimum and default columns in your DB should be: id, value, icon, color. + | + | + */ + 'model' => [ + 'class' => \App\Models\Category::class, // \App\Models\Category::class + 'key' => 'id', // "id" is a DB column - you can change by any primary key + 'value' => 'value', // "value" is a DB column - it used for Select options and displays on Resource page + 'icon' => 'icon', // "icon" is a DB column - define here any heroicon- icon + 'color' => 'color', // "color" is a DB column - default tailwindcss colors names like: primary / secondary / danger + ], + /* + |-------------------------------------------------------------------------- + | Default TiMEX Categories + |-------------------------------------------------------------------------- + */ 'labels' => [ 'primary' => 'Primary category', 'secondary' => 'Secondary category', diff --git a/database/migrations/create_timex_tables.php.stub b/database/migrations/create_timex_tables.php.stub index 8ad3805..56ea15c 100644 --- a/database/migrations/create_timex_tables.php.stub +++ b/database/migrations/create_timex_tables.php.stub @@ -8,7 +8,7 @@ return new class extends Migration { public function up() { - Schema::create('timex_events', function (Blueprint $table) { + Schema::create(config('timex.tables.event.name'), function (Blueprint $table) { $table->uuid('id')->primary(); $table->longText('body')->nullable(); $table->string('category')->nullable(); @@ -16,12 +16,14 @@ return new class extends Migration $table->time('endTime'); $table->boolean('isAllDay')->default(false); $table->foreignUuid('organizer'); + $table->json('participants')->nullable(); $table->longText('subject'); $table->date('start'); $table->time('startTime'); $table->timestamps(); }); + } /** @@ -31,6 +33,6 @@ return new class extends Migration */ public function down() { - Schema::dropIfExists('timex_events'); + Schema::dropIfExists(config('timex.tables.event.name')); } }; diff --git a/resources/dist/timex.css b/resources/dist/timex.css new file mode 100644 index 0000000..6627c5c --- /dev/null +++ b/resources/dist/timex.css @@ -0,0 +1,89 @@ +.timex-month { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + text-align: center; + background: white; + border-radius: 0.75rem; + border-width: 1px; +} + +.timex-week-name { + font-weight: 500; + padding: 0.5rem; + height: 2.5rem; + +} + +.timex-week{ + grid-auto-flow: column; +} + +.timex-week-last { + border-bottom-right-radius: 0.75rem; +} + +.timex-day { + align-items: center; + text-align: left; + height: 65px; +} +.timex-event { + visibility: hidden; +} + +@media (min-width: 640px) { + .timex-day { + align-items: center; + text-align: left; + height: 65px; + } + .timex-event { + visibility: hidden; + } +} + +@media (min-width: 768px) { + .timex-day { + align-items: center; + text-align: left; + height: 65px; + } + .timex-event { + visibility: hidden; + } +} + +@media (min-width: 1024px) { + .timex-day { + align-items: center; + text-align: left; + height: 130px; + } + .timex-event { + visibility: visible; + height: 88px; + } +} + +@media (min-width: 1280px) { + .timex-day { + align-items: center; + text-align: left; + height: 130px; + } + .timex-event { + visibility: visible; + height: 88px; + } +} + +@media (min-width: 1536px) { + .timex-day { + align-items: center; + text-align: left; + height: 130px; + } + .timex-event { + height: 88px; + } +} diff --git a/resources/lang/en/timex.php b/resources/lang/en/timex.php index 474b350..0a7e9d3 100644 --- a/resources/lang/en/timex.php +++ b/resources/lang/en/timex.php @@ -17,6 +17,19 @@ 'category' => 'Category', 'allDay' => 'All day', 'start' => 'Start', - 'end' => 'End' + 'end' => 'End', + 'participants' => 'Participants' + + ], + 'event-list' => [ + 'author' => 'Author: :name', + 'start' => 'Start: :start', + 'end' => 'End: :end' + ], + 'labels' => [ + 'navigation' => 'TiMEX', + 'breadcrumbs' => 'TiMEX', + 'title' => 'TiMEX', + 'today' => 'Today', ], ]; diff --git a/resources/lang/ru/timex.php b/resources/lang/ru/timex.php index 672d7c6..eaa4295 100644 --- a/resources/lang/ru/timex.php +++ b/resources/lang/ru/timex.php @@ -9,7 +9,7 @@ 'delete' => 'Удалить', ], 'events' => [ - 'empty' => 'Нет предстоящих событий' + 'empty' => 'Нет событий' ], 'event' => [ 'subject' => 'Тема', @@ -17,6 +17,19 @@ 'category' => 'Категория', 'allDay' => 'Целый день', 'start' => 'Начало', - 'end' => 'Окончание' + 'end' => 'Окончание', + 'participants' => 'Участники' ], + 'event-list' => [ + 'author' => 'Автор: :name', + 'start' => 'Начало: :start', + 'end' => 'Окончание: :end' + ], + 'labels' => [ + 'navigation' => 'TiMEX', + 'breadcrumbs' => 'TiMEX', + 'title' => 'TiMEX', + 'today' => 'Сегодня', + ], + ]; diff --git a/resources/views/calendar/day.blade.php b/resources/views/calendar/day.blade.php index b8ed947..203e09c 100644 --- a/resources/views/calendar/day.blade.php +++ b/resources/views/calendar/day.blade.php @@ -7,8 +7,8 @@ @endphp
-
+
@@ -49,14 +49,16 @@ class="group items-center text-left"
+ :subject="$event->getSubject()" + />
@endforeach
diff --git a/resources/views/calendar/event-list.blade.php b/resources/views/calendar/event-list.blade.php new file mode 100644 index 0000000..c3fedc4 --- /dev/null +++ b/resources/views/calendar/event-list.blade.php @@ -0,0 +1,3 @@ +
+ {{ $this->table }} +
diff --git a/resources/views/calendar/event.blade.php b/resources/views/calendar/event.blade.php index ba68cc6..39d3cbf 100644 --- a/resources/views/calendar/event.blade.php +++ b/resources/views/calendar/event.blade.php @@ -1,6 +1,17 @@ @php - $icon = config('timex.categories.icons.'.$category); - $color = config('timex.categories.colors.'.$color); + $isMyEvent = $organizer == Auth::id(); + $isModelEnabled = \Buildix\Timex\Traits\TimexTrait::isCategoryModelEnabled() && Str::isUuid($category); + if ($isModelEnabled){ + $model = \Buildix\Timex\Traits\TimexTrait::getCategoryModel()::query()->find($category)->getAttributes(); + $icon = $model[\Buildix\Timex\Traits\TimexTrait::getCategoryModelColumn('icon')]; + $color = $model[\Buildix\Timex\Traits\TimexTrait::getCategoryModelColumn('color')]; + }elseif (Str::isUuid($category) && !$isModelEnabled){ + $icon = ""; + $color = "primary"; + }else{ + $icon = config('timex.categories.icons.'.$category); + $color = config('timex.categories.colors.'.$color); + } $eventStart = \Carbon\Carbon::createFromTimestamp($start)->setHours(23); $isInPast = $eventStart->isPast(); @endphp @@ -13,18 +24,19 @@ 'h-full ml-1 rounded-md', 'bg-'.$color.'-600' => $color != 'secondary', 'bg-gray-600' => $color == 'secondary', - 'hidden' => $isWidgetEvent + 'hidden' => $isWidgetEvent, ])>
!$isMyEvent && !$isWidgetEvent, 'grid grid-cols-7 items-center text-left text-xs font-light cursor-pointer', 'w-full rounded ml-1 mr-1', 'hover:bg-'.$color.'-600/20' => $color !== 'secondary' && !$isWidgetEvent, 'hover:bg-gray-600/20' => $color == 'secondary' && !$isWidgetEvent, - 'text-white hover:text-'.$color.'-500 bg-'.$color.'-500' => $color != 'secondary' && !$isInPast && !$isWidgetEvent, - 'text-white hover:text-gray-500 bg-gray-500' => $color == 'secondary' && !$isInPast && !$isWidgetEvent, + 'text-white hover:text-'.$color.'-500 bg-'.$color.'-500' => $color != 'secondary' && !$isInPast && !$isWidgetEvent && $isMyEvent, + 'text-white hover:text-gray-500 bg-gray-500' => $color == 'secondary' && !$isInPast && !$isWidgetEvent && $isMyEvent, ]) > diff --git a/resources/views/calendar/month.blade.php b/resources/views/calendar/month.blade.php index 2590d5a..8802676 100644 --- a/resources/views/calendar/month.blade.php +++ b/resources/views/calendar/month.blade.php @@ -5,7 +5,7 @@
+ wire:init="loaded" class="timex-month dark:bg-gray-800 dark:border-gray-600"> @foreach(collect($this->getDays())['weekDays'] as $dayOfWeek)
-
+
{{$name}}
$last, 'border-r dark:border-gray-600' => !$last, 'bg-gray-50 dark:bg-gray-700' => in_array($dayOfWeek,\Carbon\Carbon::getWeekendDays()), ] ) - @if($last) - style="border-bottom-right-radius: 0.75rem;" - @endif +{{-- @if($last)--}} +{{-- style="border-bottom-right-radius: 0.75rem;"--}} +{{-- @endif--}} > @foreach($days as $day) $isEventViewHidden, 'relative group max-w-md rounded-lg bg-gray-400/10 dark:bg-gray-700', ]) - style="width: 16rem;"> + style="min-width: 12rem; max-width: 12rem;">
diff --git a/resources/views/layout/page.blade.php b/resources/views/layout/page.blade.php index ca28b0d..cdb4cff 100644 --- a/resources/views/layout/page.blade.php +++ b/resources/views/layout/page.blade.php @@ -2,4 +2,8 @@
+{{-- WIP +
--}} +{{-- --}} +{{--
--}} diff --git a/src/Calendar/Event.php b/src/Calendar/Event.php index 8044446..37cf960 100644 --- a/src/Calendar/Event.php +++ b/src/Calendar/Event.php @@ -14,6 +14,7 @@ class Event extends Component public $color; public $icon; public $category; + public $organizer; public $isWidgetEvent = false; public function render() diff --git a/src/Calendar/EventList.php b/src/Calendar/EventList.php new file mode 100644 index 0000000..8fae67f --- /dev/null +++ b/src/Calendar/EventList.php @@ -0,0 +1,105 @@ + 'onTodayClick', +// 'onPrevClick' => 'onPrevClick', +// 'onNextClick' => 'onNextClick' +// ]; + + public function boot() + { + $this->start = Carbon::create($this->today); + $this->end = Carbon::create($this->today)->endOfMonth(); + } + + public function onTodayClick() + { + $this->today = Carbon::today(); + $this->start = Carbon::create($this->today); + $this->end = Carbon::create($this->today)->endOfMonth(); + } + + public function onPrevClick() + { + $this->today = $this->today->subMonth(); + $this->start = Carbon::create($this->today)->firstOfMonth(); + $this->end = Carbon::create($this->today)->endOfMonth(); + } + + public function onNextClick() + { + $this->today = $this->today->addMonth(); + $this->start = Carbon::create($this->today)->firstOfMonth(); + $this->end = Carbon::create($this->today)->endOfMonth(); + } + + protected static function getEventModel(): string + { + return static::$model = config('timex.models.event'); + } + + protected static function getEventResource(): string + { + return static::$recource = config('timex.resources.event'); + } + + protected function getTableQuery(): Builder|Relation + { + return self::getEventModel()::whereBetween('start', [$this->start, $this->end]); + } + + public function render() + { + return view('timex::calendar.event-list'); + } + + protected function getTableColumns(): array + { + return [ + TextColumn::make('subject')->label(__('timex::timex.event.subject')) + ->description(function ($record){ + return __('timex::timex.event-list.author',['name' => self::getUserModel()::find($record->organizer)->getAttribute(self::getUserModelColumn('name'))]); + })->wrap(), + TextColumn::make('start')->date()->description(function ($record){ + return __('timex::timex.event-list.start',['start' => Carbon::create($record->startTime)->format('G:i')]); + })->label(__('timex::timex.event.start')), + TextColumn::make('end')->date()->description(function ($record){ + return __('timex::timex.event-list.end',['end' => Carbon::create($record->endTime)->format('G:i')]); + })->label(__('timex::timex.event.end')), + ]; + } + + protected function getTableRecordUrlUsing(): ?Closure + { + return fn (Model $record): string => $this->getEventResource()::getUrl('edit', ['record' => $record]); + } + + +} diff --git a/src/Events/EventItem.php b/src/Events/EventItem.php index fbc6fa9..b8fd3a6 100644 --- a/src/Events/EventItem.php +++ b/src/Events/EventItem.php @@ -18,6 +18,8 @@ class EventItem protected $type; protected ?string $icon = null; protected ?string $category = null; + public $organizer; + public $participants = []; final public function __construct($eventID) @@ -97,6 +99,20 @@ public function color(?string $color): static } + public function organizer(string $organizer) + { + $this->organizer = $organizer; + + return $this; + } + + public function participants(?array $participants) + { + $this->participants = $participants; + + return $this; + } + public function getColor(): ?string { @@ -113,6 +129,11 @@ public function getBody(): ?string return $this->body; } + public function getOrganizer() + { + return $this->organizer; + } + public function getStart() { return $this->start; diff --git a/src/Models/Event.php b/src/Models/Event.php index 8d23930..9daf468 100644 --- a/src/Models/Event.php +++ b/src/Models/Event.php @@ -2,12 +2,17 @@ namespace Buildix\Timex\Models; +use App\Models\User; +use Buildix\Timex\Traits\TimexTrait; use Buildix\Timex\Traits\Uuids; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Spatie\Permission\PermissionRegistrar; class Event extends Model { use Uuids; + use TimexTrait; protected $guarded = []; @@ -15,11 +20,12 @@ class Event extends Model 'start' => 'date', 'end' => 'date', 'isAllDay' => 'boolean', + 'participants' => 'array' ]; public function getTable() { - return 'timex_events'; + return config('timex.tables.event.name', parent::getTable()); } public function __construct(array $attributes = []) @@ -29,7 +35,10 @@ public function __construct(array $attributes = []) parent::__construct($attributes); } - + public function category() + { + return $this->hasOne(self::getCategoryModel()); + } } diff --git a/src/Pages/Timex.php b/src/Pages/Timex.php index b5908c9..2efa25a 100644 --- a/src/Pages/Timex.php +++ b/src/Pages/Timex.php @@ -21,6 +21,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Support\Fluent; use Illuminate\Support\Str; +use mysql_xdevapi\Collection; use function Filament\Support\get_model_label; class Timex extends Page @@ -36,18 +37,18 @@ class Timex extends Page protected static function getNavigationLabel(): string { - return Carbon::today()->isoFormat(config('timex.pages.label.navigation')); + return config('timex.pages.label.navigation.static') ? __('timex::timex.labels.navigation') : self::getDynamicLabel('navigation'); } protected function getTitle(): string { - return Carbon::today()->isoFormat(config('timex.pages.label.title')); + return config('timex.pages.label.title.static') ? __('timex::timex.labels.title') : self::getDynamicLabel('title'); } protected function getBreadcrumbs(): array { return [ - Carbon::today()->isoFormat(config('timex.pages.label.breadcrumbs')) + config('timex.pages.label.breadcrumbs.static') ? __('timex::timex.labels.breadcrumbs') : self::getDynamicLabel('breadcrumbs') ]; } @@ -108,7 +109,6 @@ protected function getActions(): array ->slideOver() ->extraAttributes(['class' => '-mr-2']) ->form($this->getResourceForm(2)->getSchema()) - ->mountUsing(fn (Forms\ComponentContainer $form) => $form->fill(self::$eventData)) ->modalHeading(__('timex::timex.model.label')) ->modalWidth(config('timex.pages.modalWidth')) ->action(fn(array $data) => $this->updateOrCreate($data)) @@ -117,6 +117,9 @@ protected function getActions(): array ->label(__('timex::timex.modal.delete')) ->color('danger') ->action('deleteEvent') + ->visible(function (){ + return $this->mountedActionData['organizer'] == \Auth::id() ? true : ($this->mountedActionData['organizer'] != \Auth::id() ? false : true); + }) ->cancel() ]), Action::make('prev') @@ -130,7 +133,7 @@ protected function getActions(): array ->size('sm') ->outlined(config('timex.pages.buttons.outlined')) ->extraAttributes(['class' => '-ml-1 -mr-1']) - ->label(Carbon::today()->isoFormat(config('timex.pages.buttons.today'))) + ->label(config('timex.pages.buttons.today.static') ? __('timex::timex.labels.today') : self::getDynamicLabel('today')) ->action(fn() => $this->emit('onTodayClick')), Action::make('next') ->size('sm') @@ -144,7 +147,7 @@ protected function getActions(): array public static function getEvents(): array { - return self::getModel()::orderBy('startTime')->get() + $events = self::getModel()::orderBy('startTime')->get() ->map(function ($event){ return EventItem::make($event->id) ->subject($event->subject) @@ -153,14 +156,14 @@ public static function getEvents(): array ->category($event->category) ->start(Carbon::create($event->start)) ->startTime($event->startTime) - ->end(Carbon::create($event->end)); + ->end(Carbon::create($event->end)) + ->organizer($event->organizer) + ->participants($event?->participants); })->toArray(); - } - - public function setNullRecord() - { - $this->record = null; + return collect($events)->filter(function ($event){ + return $event->organizer == \Auth::id() || in_array(\Auth::id(), $event?->participants ?? []); + })->toArray(); } public function updateOrCreate($data) @@ -183,15 +186,17 @@ public function dispatEventUpdates(): void { $this->emit('modelUpdated',['id' => $this->id]); $this->emit('updateWidget',['id' => $this->id]); - $this->record = null; } public function onEventClick($eventID) { $this->record = $eventID; $event = $this->getFormModel()->getAttributes(); - self::$eventData = $event; $this->mountAction('openCreateModal'); + $this->getMountedActionForm() + ->fill([ + ...$event, + 'participants' => self::getFormModel()?->participants + ]); } - } diff --git a/src/Resources/EventResource.php b/src/Resources/EventResource.php index 0e3a586..68836bd 100644 --- a/src/Resources/EventResource.php +++ b/src/Resources/EventResource.php @@ -2,6 +2,7 @@ namespace Buildix\Timex\Resources; +use Buildix\Timex\Traits\TimexTrait; use Carbon\Carbon; use Filament\Forms\Components\Card; use Filament\Forms\Components\DatePicker; @@ -26,6 +27,7 @@ class EventResource extends Resource { + use TimexTrait; protected static ?string $recordTitleAttribute = 'subject'; protected $chosenStartTime; @@ -76,12 +78,23 @@ public static function form(Form $form): Form RichEditor::make('body') ->label(__('timex::timex.event.body')) ->columnSpanFull(), + Select::make('participants') + ->label(__('timex::timex.event.participants')) + ->options(function (){ + return self::getUserModel()::all() + ->pluck(self::getUserModelColumn('name'),self::getUserModelColumn('id')); + }) + ->multiple()->columnSpanFull()->hidden(!in_array('participants',\Schema::getColumnListing(self::getEventTableName()))), Select::make('category') ->label(__('timex::timex.event.category')) ->columnSpanFull() ->searchable() ->preload() - ->options(config('timex.categories.labels')) + ->options(function (){ + return self::isCategoryModelEnabled() ? self::getCategoryModel()::all() + ->pluck(self::getCategoryModelColumn('value'),self::getCategoryModelColumn('key')) + : config('timex.categories.labels'); + }) ->columnSpanFull(), Grid::make(3)->schema([ Toggle::make('isAllDay') @@ -157,6 +170,87 @@ public static function form(Form $form): Form ]); } + public static function getCreateEditForm(): array + { + return [ + Grid::make(3)->schema([ + Card::make([ + TextInput::make('subject') + ->label(__('timex::timex.event.subject')) + ->required(), + RichEditor::make('body') + ->label(__('timex::timex.event.body')), + ])->columnSpan(2), + Card::make([ + Grid::make(3)->schema([ + Toggle::make('isAllDay') + ->label(__('timex::timex.event.allDay')) + ->columnSpanFull() + ->reactive() + ->afterStateUpdated(function ($set, callable $get, $state){ + $start = today()->setHours(0)->setMinutes(0); + $end = today()->setHours(23)->setMinutes(59); + if ($state == true){ + $set('startTime',$start); + $set('endTime',$end); + }else{ + $set('startTime',now()->setMinutes(0)->addHour()); + $set('endTime',now()->setMinutes(0)->addHour()->addMinutes(30)); + } + }), + DatePicker::make('start') + ->label(__('timex::timex.event.start')) + ->inlineLabel() + ->columnSpan(2) + ->default(today()) + ->minDate(today()) + ->firstDayOfWeek(config('timex.week.start')), + TimePicker::make('startTime') + ->withoutSeconds() + ->disableLabel() + ->default(now()->setMinutes(0)->addHour()) + ->reactive() + ->afterStateUpdated(function ($set,$state){ + $set('endTime',Carbon::parse($state)->addMinutes(30)); + }) + ->disabled(function ($get){ + return $get('isAllDay'); + }), + DatePicker::make('end') + ->label(__('timex::timex.event.end')) + ->inlineLabel() + ->columnSpan(2) + ->default(today()) + ->minDate(today()) + ->firstDayOfWeek(config('timex.week.start')), + TimePicker::make('endTime') + ->withoutSeconds() + ->disableLabel() + ->reactive() + ->default(now()->setMinutes(0)->addHour()->addMinutes(30)) + ->disabled(function ($get){ + return $get('isAllDay'); + }), + Select::make('participants') + ->options(function (){ + return self::getUserModel()::all() + ->pluck(self::getUserModelColumn('name'),self::getUserModelColumn('id')); + }) + ->multiple()->columnSpanFull()->hidden(!in_array('participants',\Schema::getColumnListing(self::getEventTableName()))), + Select::make('category') + ->label(__('timex::timex.event.category')) + ->columnSpanFull() + ->options(function (){ + return self::isCategoryModelEnabled() ? self::getCategoryModel()::all() + ->pluck(self::getCategoryModelColumn('value'),self::getCategoryModelColumn('key')) + : config('timex.categories.labels'); + }) + ]) + ])->columnSpan(1) + ]), + ]; + } + public static function table(Table $table): Table { return $table @@ -178,11 +272,23 @@ public static function table(Table $table): Table BadgeColumn::make('category') ->label(__('timex::timex.event.category')) ->enum(config('timex.categories.labels')) - ->colors(config('timex.categories.colors')) + ->formatStateUsing(function ($record){ + if (\Str::isUuid($record->category)){ + return self::getCategoryModel() == null ? "" : self::getCategoryModel()::findOrFail($record->category)->getAttributes()[self::getCategoryModelColumn('value')]; + }else{ + return config('timex.categories.labels')[$record->category] ?? ""; + } + }) + ->color(function ($record){ + if (\Str::isUuid($record->category)){ + return self::getCategoryModel() == null ? "primary" :self::getCategoryModel()::findOrFail($record->category)->getAttributes()[self::getCategoryModelColumn('color')]; + }else{ + return config('timex.categories.colors')[$record->category] ?? "primary"; + } + }) ])->defaultSort('start'); } - public static function getPages(): array { return [ diff --git a/src/Resources/EventResource/Pages/CreateEvent.php b/src/Resources/EventResource/Pages/CreateEvent.php index 3491679..afdbf68 100644 --- a/src/Resources/EventResource/Pages/CreateEvent.php +++ b/src/Resources/EventResource/Pages/CreateEvent.php @@ -2,6 +2,8 @@ namespace Buildix\Timex\Resources\EventResource\Pages; +use App\Models\User; +use Buildix\Timex\Traits\TimexTrait; use Carbon\Carbon; use Filament\Forms\Components\Card; use Filament\Forms\Components\DatePicker; @@ -17,98 +19,12 @@ class CreateEvent extends CreateRecord { + use TimexTrait; protected static string $resource = EventResource::class; public function form(Form $form): Form { - return $form - ->schema([ - Grid::make(3)->schema([ - Card::make([ - TextInput::make('subject') - ->label(__('timex::timex.event.subject')) - ->required(), - RichEditor::make('body') - ->label(__('timex::timex.event.body')) - ])->columnSpan(2), - Card::make([ - Grid::make(3)->schema([ - Toggle::make('isAllDay') - ->label(__('timex::timex.event.allDay')) - ->columnSpanFull() - ->reactive() - ->afterStateUpdated(function ($set, callable $get, $state){ - $start = today()->setHours(0)->setMinutes(0); - $end = today()->setHours(23)->setMinutes(59); - if ($state == true){ - $set('startTime',$start); - $set('endTime',$end); - }else{ - $set('startTime',now()->setMinutes(0)->addHour()); - $set('endTime',now()->setMinutes(0)->addHour()->addMinutes(30)); - } - }), - DatePicker::make('start') - ->label(__('timex::timex.event.start')) - ->required() - ->inlineLabel() - ->columnSpan(2) - ->default(today()) - ->minDate(today()) - ->extraAttributes([ - 'class' => '-ml-2' - ]) - ->firstDayOfWeek(config('timex.week.start')), - TimePicker::make('startTime') - ->withoutSeconds() - ->disableLabel() - ->default(now()->setMinutes(0)->addHour()) - ->reactive() - ->extraAttributes([ - 'class' => '-ml-2' - ]) - ->afterStateUpdated(function ($set,$state){ - $set('endTime',Carbon::parse($state)->addMinutes(30)); - }) - ->disabled(function ($get){ - return $get('isAllDay'); - }), - DatePicker::make('end') - ->label(__('timex::timex.event.end')) - ->inlineLabel() - ->columnSpan(2) - ->default(today()) - ->minDate(today()) - ->extraAttributes([ - 'class' => '-ml-2' - ]) - ->firstDayOfWeek(config('timex.week.start')), - TimePicker::make('endTime') - ->withoutSeconds() - ->disableLabel() - ->reactive() - ->extraAttributes([ - 'class' => '-ml-2' - ]) - ->default(now()->setMinutes(0)->addHour()->addMinutes(30)) - ->disabled(function ($get){ - return $get('isAllDay'); - }), - Select::make('category') - ->label(__('timex::timex.event.category')) - ->columnSpanFull() - ->options(config('timex.categories.labels')) - ]) - ])->columnSpan(1) - ]), - ]); + return $form->schema(self::getResource()::getCreateEditForm()); } -// protected function mutateFormDataBeforeCreate(array $data): array -// { -//// $data['startTime'] = Carbon::create($data['start'])->isoFormat("H:mm"); -//// $data['endTime'] = Carbon::create($data['end'])->isoFormat('H:mm'); -// -// return $data; -// } } diff --git a/src/Resources/EventResource/Pages/EditEvent.php b/src/Resources/EventResource/Pages/EditEvent.php index 0854c4a..61f8653 100644 --- a/src/Resources/EventResource/Pages/EditEvent.php +++ b/src/Resources/EventResource/Pages/EditEvent.php @@ -2,6 +2,8 @@ namespace Buildix\Timex\Resources\EventResource\Pages; +use App\Models\User; +use Buildix\Timex\Traits\TimexTrait; use Carbon\Carbon; use Filament\Forms\Components\Card; use Filament\Forms\Components\DatePicker; @@ -18,78 +20,12 @@ class EditEvent extends EditRecord { + use TimexTrait; protected static string $resource = EventResource::class; public function form(Form $form): Form { - return $form - ->schema([ - Grid::make(3)->schema([ - Card::make([ - TextInput::make('subject') - ->label(__('timex::timex.event.subject')) - ->required(), - RichEditor::make('body') - ->label(__('timex::timex.event.body')) - ])->columnSpan(2), - Card::make([ - Grid::make(3)->schema([ - Toggle::make('isAllDay') - ->label(__('timex::timex.event.allDay')) - ->columnSpanFull() - ->reactive() - ->afterStateUpdated(function ($set, callable $get, $state){ - $start = today()->setHours(0)->setMinutes(0); - $end = today()->setHours(23)->setMinutes(59); - if ($state == true){ - $set('startTime',$start); - $set('endTime',$end); - }else{ - $set('startTime',now()->setMinutes(0)->addHour()); - $set('endTime',now()->setMinutes(0)->addHour()->addMinutes(30)); - } - }), - DatePicker::make('start') - ->label(__('timex::timex.event.start')) - ->inlineLabel() - ->columnSpan(2) - ->default(today()) - ->minDate(today()) - ->firstDayOfWeek(config('timex.week.start')), - TimePicker::make('startTime') - ->withoutSeconds() - ->disableLabel() - ->default(now()->setMinutes(0)->addHour()) - ->reactive() - ->afterStateUpdated(function ($set,$state){ - $set('endTime',Carbon::parse($state)->addMinutes(30)); - }) - ->disabled(function ($get){ - return $get('isAllDay'); - }), - DatePicker::make('end') - ->label(__('timex::timex.event.end')) - ->inlineLabel() - ->columnSpan(2) - ->default(today()) - ->minDate(today()) - ->firstDayOfWeek(config('timex.week.start')), - TimePicker::make('endTime') - ->withoutSeconds() - ->disableLabel() - ->reactive() - ->default(now()->setMinutes(0)->addHour()->addMinutes(30)) - ->disabled(function ($get){ - return $get('isAllDay'); - }), - Select::make('category') - ->label(__('timex::timex.event.category')) - ->columnSpanFull() - ->options(config('timex.categories.labels')) - ]) - ])->columnSpan(1) - ]), - ]); + return $form->schema(self::getResource()::getCreateEditForm()); } protected function getActions(): array diff --git a/src/Resources/EventResource/Pages/ListEvents.php b/src/Resources/EventResource/Pages/ListEvents.php index 4af316d..d2c1108 100644 --- a/src/Resources/EventResource/Pages/ListEvents.php +++ b/src/Resources/EventResource/Pages/ListEvents.php @@ -2,14 +2,18 @@ namespace Buildix\Timex\Resources\EventResource\Pages; +use Buildix\Timex\Events\InteractWithEvents; +use Buildix\Timex\Traits\TimexTrait; use Closure; use Filament\Pages\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Buildix\Timex\Resources\EventResource; class ListEvents extends ListRecords { + use TimexTrait; protected static string $resource = EventResource::class; protected function getActions(): array @@ -18,4 +22,15 @@ protected function getActions(): array CreateAction::make(), ]; } + + protected function getTableQuery(): Builder + { + if (in_array('participants',\Schema::getColumnListing(self::getEventTableName()))){ + return parent::getTableQuery() + ->where('organizer','=',\Auth::id()) + ->orWhereJsonContains('participants', \Auth::id()); + }else{ + return parent::getTableQuery(); + } + } } diff --git a/src/TimexServiceProvider.php b/src/TimexServiceProvider.php index 230ccdd..e99b29c 100644 --- a/src/TimexServiceProvider.php +++ b/src/TimexServiceProvider.php @@ -5,6 +5,7 @@ use BladeUI\Icons\Factory; use Buildix\Timex\Calendar\Day; use Buildix\Timex\Calendar\Event; +use Buildix\Timex\Calendar\EventList; use Buildix\Timex\Calendar\Month; use Buildix\Timex\Calendar\Week; use Buildix\Timex\Widgets\Mini\DayWidget; @@ -24,6 +25,10 @@ class TimexServiceProvider extends PluginServiceProvider 'timex' => __DIR__.'/../resources/dist/timex.js' ]; + protected array $styles = [ + 'timex' => __DIR__.'/../resources/dist/timex.css' + ]; + public function configurePackage(Package $package): void { /* @@ -48,6 +53,7 @@ public function boot() Livewire::component('timex-event',Event::class); Livewire::component('timex-event-widget',EventWidget::class); Livewire::component('timex-day-widget',DayWidget::class); + Livewire::component('timex-event-list',EventList::class); $this->registerConfig(); diff --git a/src/Traits/TimexTrait.php b/src/Traits/TimexTrait.php index 401b44e..1265c13 100644 --- a/src/Traits/TimexTrait.php +++ b/src/Traits/TimexTrait.php @@ -40,10 +40,59 @@ public function getEndOfWeek() return $this->endOfWeek = config('timex.week.end');; } - public function getPageClass() + public static function getPageClass() { return config('timex.pages.timex'); } + public static function getUserModel() + { + return config('timex.models.users.model'); + } + + public static function getEventTableName() + { + return config('timex.tables.event.name'); + } + + public static function getUserModelColumn($column) + { + return match ($column){ + 'name' => config('timex.models.users.name'), + 'id' => config('timex.models.users.id') + }; + } + + public static function getDynamicLabel(string $label) + { + $format = match ($label){ + 'navigation' => config('timex.pages.label.navigation.format'), + 'breadcrumbs' => config('timex.pages.label.breadcrumbs.format'), + 'title' => config('timex.pages.label.title.format'), + 'today' => config('timex.pages.buttons.today.format'), + }; + + return Carbon::today()->isoFormat($format); + } + + public static function getCategoryModel() + { + return config('timex.categories.model.class'); + } + + public static function getCategoryModelColumn(string $column) + { + return match ($column){ + 'key' => config('timex.categories.model.key'), + 'value' => config('timex.categories.model.value'), + 'icon' => config('timex.categories.model.icon'), + 'color' => config('timex.categories.model.color') + }; + } + + public static function isCategoryModelEnabled(): bool + { + return config('timex.categories.isModelEnabled'); + } } diff --git a/src/Widgets/Mini/EventWidget.php b/src/Widgets/Mini/EventWidget.php index 20a8563..dd70825 100644 --- a/src/Widgets/Mini/EventWidget.php +++ b/src/Widgets/Mini/EventWidget.php @@ -5,6 +5,7 @@ use Buildix\Timex\Events\EventItem; use Buildix\Timex\Events\InteractWithEvents; use Buildix\Timex\Pages\Timex; +use Buildix\Timex\Traits\TimexTrait; use Carbon\Carbon; use Livewire\Component; use Illuminate\Support\Collection; @@ -12,8 +13,10 @@ class EventWidget extends Component { use InteractWithEvents; + use TimexTrait; public $events; + public $now; protected $listeners = [ 'updateWidget' => 'updateWidget' @@ -25,6 +28,11 @@ public function updateWidget() $this->events = self::getEvents(); } + public function boot() + { + $this->now = Carbon::today()->timestamp; + } + public function mount() { $this->events = self::getEvents(); @@ -32,20 +40,10 @@ public function mount() public static function getEvents(): Collection { - $events = self::getModel()::orderBy('startTime')->get() - ->map(function ($event){ - return EventItem::make($event->id) - ->subject($event->subject) - ->body($event->body) - ->color($event->category) - ->category($event->category) - ->start(Carbon::create($event->start)) - ->startTime($event->startTime) - ->end(Carbon::create($event->end)); - })->toArray(); + $events = self::getPageClass()::getEvents(); return collect($events)->filter(function ($event){ - return Carbon::createFromTimestamp($event->start) == today() && $event->startTime > now()->isoFormat('H:mm:ss'); + return $event->start == today()->timestamp && Carbon::createFromTimeString($event->startTime) >= now(); }); }