Issues (62)

src/Filament/Pages/NotificationPreferences.php (7 issues)

1
<?php
2
3
namespace Usamamuneerchaudhary\Notifier\Filament\Pages;
4
5
use Filament\Forms;
6
use Filament\Forms\Components\Checkbox;
7
use Filament\Forms\Concerns\InteractsWithForms;
8
use Filament\Forms\Contracts\HasForms;
9
use Filament\Notifications\Notification;
10
use Filament\Pages\Page;
11
use Filament\Schemas\Components\Grid;
12
use Filament\Schemas\Components\Section;
13
use Illuminate\Support\Facades\Auth;
14
use Usamamuneerchaudhary\Notifier\Models\NotificationChannel;
15
use Usamamuneerchaudhary\Notifier\Models\NotificationEvent;
16
use Usamamuneerchaudhary\Notifier\Models\NotificationPreference;
17
use Usamamuneerchaudhary\Notifier\Models\NotificationSetting;
18
19
class NotificationPreferences extends Page implements HasForms
20
{
21
    use InteractsWithForms;
0 ignored issues
show
The trait Filament\Forms\Concerns\InteractsWithForms requires some properties which are not provided by Usamamuneerchaudhary\Not...NotificationPreferences: $timestamp, $map
Loading history...
22
23
    protected static string|null|\BackedEnum $navigationIcon = 'heroicon-o-bell';
0 ignored issues
show
The type BackedEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
    protected static ?string $navigationLabel = 'Notification Preferences';
25
    protected static ?string $title = 'Notification Preferences';
26
    protected static string|null|\UnitEnum $navigationGroup = 'Notifier';
0 ignored issues
show
The type UnitEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
    protected static ?int $navigationSort = 6;
28
    protected string $view = 'notifier::filament.pages.notification-preferences';
29
30
    public ?array $data = [];
31
32
    public function mount(): void
33
    {
34
        $user = Auth::user();
35
        $events = NotificationEvent::where('is_active', true)
36
            ->orderBy('group')
37
            ->orderBy('name')
38
            ->get();
39
40
        $activeChannels = NotificationChannel::where('is_active', true)
41
            ->orderBy('title')
42
            ->get();
43
44
        $groupedEvents = $events->groupBy('group');
45
46
        $formData = [];
47
48
        foreach ($groupedEvents as $group => $groupEvents) {
49
            foreach ($groupEvents as $event) {
50
                $preference = NotificationPreference::where('user_id', $user->id)
0 ignored issues
show
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
51
                    ->where('notification_event_id', $event->id)
52
                    ->first();
53
54
                $defaultChannels = $this->getDefaultChannelsForEvent($event);
55
56
                $channelData = [];
57
                foreach ($activeChannels as $channel) {
58
                    if ($preference && isset($preference->channels[$channel->type])) {
59
                        $channelData[$channel->type] = (bool) $preference->channels[$channel->type];
60
                    } else {
61
                        $channelData[$channel->type] = in_array($channel->type, $defaultChannels);
62
                    }
63
                }
64
65
                $formData["event_{$event->id}"] = $channelData;
66
            }
67
        }
68
69
        $this->form->fill($formData);
0 ignored issues
show
Bug Best Practice introduced by
The property form does not exist on Usamamuneerchaudhary\Not...NotificationPreferences. Since you implemented __get, consider adding a @property annotation.
Loading history...
70
    }
71
72
    protected function getFormSchema(): array
73
    {
74
        $events = NotificationEvent::where('is_active', true)
75
            ->orderBy('group')
76
            ->orderBy('name')
77
            ->get();
78
79
        $activeChannels = NotificationChannel::where('is_active', true)
80
            ->orderBy('title')
81
            ->get();
82
83
        $groupedEvents = $events->groupBy('group');
84
85
        $sections = [];
86
87
        foreach ($groupedEvents as $group => $groupEvents) {
88
            $fields = [];
89
90
            foreach ($groupEvents as $event) {
91
                $channelCheckboxes = [];
92
93
                foreach ($activeChannels as $channel) {
94
                    $channelCheckboxes[] = Checkbox::make("event_{$event->id}.{$channel->type}")
95
                        ->label('')
96
                        ->inline(false);
97
                }
98
99
                $fields[] = Grid::make([
100
                    'default' => 1,
101
                    'md' => $activeChannels->count() + 1,
102
                ])
103
                    ->schema([
104
                        Forms\Components\Placeholder::make("event_label_{$event->id}")
105
                            ->label($event->name)
106
                            ->content($event->description ?: '')
107
                            ->extraAttributes([
108
                                'class' => 'font-medium text-gray-900'
109
                            ]),
110
                        ...$channelCheckboxes,
111
                    ])
112
                    ->extraAttributes([
113
                        'class' => 'border-b border-gray-200 py-4 first:pt-0 last:border-b-0 last:pb-0'
114
                    ]);
115
            }
116
117
            $sections[] = Section::make($group ?: 'General')
118
                ->schema([
119
                    Grid::make([
120
                        'default' => 1,
121
                        'md' => $activeChannels->count() + 1,
122
                    ])
123
                        ->schema([
124
                            Forms\Components\Placeholder::make('header_label')
125
                                ->label('')
126
                                ->content(''),
127
                            ...array_map(function ($channel) {
128
                                return Forms\Components\Placeholder::make("header_{$channel->type}")
129
                                    ->label($channel->title)
130
                                    ->content('')
131
                                    ->extraAttributes([
132
                                        'class' => 'font-semibold text-gray-700 text-sm'
133
                                    ]);
134
                            }, $activeChannels->all()),
135
                        ])
136
                        ->extraAttributes([
137
                            'class' => 'border-b-2 border-gray-300 pb-3 mb-2'
138
                        ]),
139
                    ...$fields,
140
                ])
141
                ->collapsible()
142
                ->collapsed(false);
143
        }
144
145
        return $sections;
146
    }
147
148
    public function save(): void
149
    {
150
        $preferences = NotificationSetting::getPreferences();
151
        if (!($preferences['allow_override'] ?? config('notifier.settings.preferences.allow_override', true))) {
152
            Notification::make()
153
                ->title('Preferences Disabled')
154
                ->body('User preference override is disabled by administrator.')
155
                ->danger()
156
                ->send();
157
158
            return;
159
        }
160
161
        $data = $this->form->getState();
0 ignored issues
show
Bug Best Practice introduced by
The property form does not exist on Usamamuneerchaudhary\Not...NotificationPreferences. Since you implemented __get, consider adding a @property annotation.
Loading history...
162
        $user = Auth::user();
163
        $activeChannels = NotificationChannel::where('is_active', true)
164
            ->pluck('type')
165
            ->toArray();
166
167
        $updated = 0;
168
169
        foreach ($data as $key => $channels) {
170
            if (!str_starts_with($key, 'event_')) {
171
                continue;
172
            }
173
174
            $eventId = (int) str_replace('event_', '', $key);
175
            $event = NotificationEvent::find($eventId);
176
177
            if (!$event) {
178
                continue;
179
            }
180
181
            $validatedChannels = [];
182
            foreach ($channels as $channelType => $enabled) {
183
                if (in_array($channelType, $activeChannels)) {
184
                    $validatedChannels[$channelType] = (bool) $enabled;
185
                }
186
            }
187
188
            NotificationPreference::updateOrCreate(
189
                [
190
                    'user_id' => $user->id,
0 ignored issues
show
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
191
                    'notification_event_id' => $eventId,
192
                ],
193
                [
194
                    'channels' => $validatedChannels,
195
                ]
196
            );
197
198
            $updated++;
199
        }
200
201
        Notification::make()
202
            ->title('Preferences Saved')
203
            ->body("Successfully updated {$updated} notification preference(s).")
204
            ->success()
205
            ->send();
206
    }
207
208
    protected function getDefaultChannelsForEvent(NotificationEvent $event): array
209
    {
210
        if (isset($event->settings['channels']) && is_array($event->settings['channels'])) {
211
            return $event->settings['channels'];
212
        }
213
214
        $defaultChannels = NotificationSetting::get('preferences.default_channels', config('notifier.settings.preferences.default_channels', ['email']));
215
        return is_array($defaultChannels) ? $defaultChannels : ['email'];
216
    }
217
}
218
219