Skip to content

Commit 07e3ec6

Browse files
authored
Merge pull request #6 from flavorly/feat/notification
2 parents 905fe89 + f6479b6 commit 07e3ec6

37 files changed

+3331
-227
lines changed

.github/workflows/pest.yml

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ on:
44
push:
55
branches:
66
- main
7-
87
jobs:
98
ci:
109
runs-on: ubuntu-latest

README.md

+201-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ return [
8282
];
8383
```
8484

85-
## Usage
85+
## 1) Inertia Share
8686

8787
You can use the Inertia Flash helper anywhere from your code and share your variables directly to InertiaJS.
8888
Keep in the mind that the values will only be kept on the current or next request lifecycle, they will be flushed once shared to Inertia
@@ -136,6 +136,206 @@ inertia_flash()->append('foo', 'bar');
136136
inertia_flash()->forUser($user)->append('foo', 'bar');
137137
```
138138

139+
## 2) Notifications
140+
141+
This package also provide a nice way to build a agnostic notification system that can be shared to Inertia or Other Frameworks
142+
143+
Here is a basic example of usage:
144+
145+
```php
146+
notification()
147+
->message('Thanks for your order! Your welcome on Site! ')
148+
->viaInertia()
149+
->dispatch();
150+
```
151+
152+
### 2.1) Notifications Channels
153+
154+
The Package provides 4 different ways to forward notifications, here is a quick breakdown:
155+
156+
- Via Inertia - This will share the notification to frontend, resulting in a property being injected on the shared data, by default it goes into "notifications", this can be changed, it will contain an array of notifications there.
157+
- Via Database - This will use Laravel Notifications system to persist the notification on the database
158+
- Via Broadcast - this will use Laravel Echo to broadcast the notification to the frontend
159+
- Via Mail - this will use Laravel Mail to send the notification to the user
160+
161+
Keep in mind that you can always override all this channels & the notification yourself by extending the original notification class or providing one on the configuration, Please do check the `config.php` for more information
162+
163+
### 2.2) Notifications Content Blocks
164+
165+
Usually notifications contain a title, message & icon, but there is some cases where you want more, we provide a simple abstraction for simple content blocks
166+
This is useful for Dialogs, where you want to show more information, keep in mind this is really simple, anything more complex should be taken care on the frontend
167+
168+
Here is a quick example
169+
170+
```php
171+
notification()
172+
->dialog()
173+
->title('Thanks for your order!')
174+
->message('Thanks for your order! Your welcome on Site! ')
175+
->icon('🎉')
176+
->block(fn (NotificationContentBlock $block) => $block->icon('🎉'))
177+
->block(fn (NotificationContentBlock $block) => $block->title('Thanks for your order!'))
178+
->block(fn (NotificationContentBlock $block) => $block->text('Your welcome on Site!'))
179+
->block(fn (NotificationContentBlock $block) => $block->image('https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExeXRmMHp4N2o1bjQ2ajg0bXEyMmt5OXJrdW8zcmxqbHJ1MTNjZmdxbyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Cm9wKmKMUlRPvdoHgU/giphy-downsized-large.gif'))
180+
->viaInertia()
181+
->dispatch();
182+
```
183+
184+
### 2.3) Notifications Icon
185+
186+
By default the notification doesnt contain any icon, we send a "level" back, so you can decide on the frontend how you will handle the icon based on the level
187+
But you can also pass in more complex icons or raw icons ( say emojis ) for the notification icon.
188+
189+
```php
190+
notification()
191+
->message('Thanks for your order! Your welcome on Site! ')
192+
->icon('🎉')
193+
->dispatch();
194+
```
195+
196+
### 2.4) Notifications Levels & Types
197+
198+
By default a level `info` and type `flash` is set, you can change this by calling fluent methods.
199+
Different types of notifications can usefull across the app, while Flash notifications are more useful to show quick messages, dialogs can be also useful to show more detailed information.
200+
201+
202+
```php
203+
notification()
204+
->message('Thanks for your order! Your welcome on Site!')
205+
->success()
206+
->dialog()
207+
->dispatch();
208+
209+
notification()
210+
->message('Thanks for your order! Your welcome on Site!')
211+
->error()
212+
->toast()
213+
->dispatch();
214+
215+
notification()
216+
->message('Thanks for your order! Your welcome on Site!')
217+
->warning()
218+
->flash()
219+
->dispatch();
220+
```
221+
222+
223+
### 2.5) Notifications Advanced
224+
225+
There is a lot more to explore on the notifications advanced options, so im going to highlight some of them here:
226+
227+
- Calling `dispatch()` will usually "queue" the notification sending depending on your driver, call `dispatchNow()` to send it immediately
228+
- Queues & Connections can be configured in the config file, same structure as Laravel.
229+
- By default no channels are enabled, you can chain `viaInertia()`, `viaDatabase()`, `viaBroadcast()`, `viaMail()` to enable them, or use the configuration to set a default channel.
230+
- By default, when using Broadcast or Database, we will try to resolve the notified to the current logged user, but you can always use `toUser()` or `to($notifiable)` to send it to a specific user/model.
231+
- When using Database Notifications a URL for `readable` is generated, you can override this by calling `readable($url)` on the notification.
232+
- You can also use `readable()` to generate a URL based on the current request.
233+
- There is a current issue that when sharing with Inertia & Database Notifications, the notification will be shared to the frontend, the ID of the inertia notification is a auto-generated one since the record is only created later. Use a Listener to update or just use Broadcast
234+
235+
### 2.6) Notifications Frontend Implementation
236+
237+
Here is an example of a component using Shadcn for Flash notifications, supporting emojis, icons and iconify for icons.
238+
239+
```php
240+
notification()
241+
->title('Thanks for your order!'.time())
242+
->message('Thanks for your order! Your welcome on site! '.time())
243+
->icon('majesticons:add-column')
244+
->dispatch();
245+
```
246+
React Example:
247+
248+
```tsx
249+
import { useContext } from 'react'
250+
import axios from 'axios'
251+
import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'
252+
import { each } from 'lodash-es'
253+
import { AlertFlash } from '@ui/alert-flash'
254+
import { NotificationsFlashContext } from './notifications-context'
255+
import type { AlertProps } from '@ui/design/alert'
256+
257+
export function NotificationsFlash(){
258+
const { state, api } = useContext(NotificationsFlashContext)
259+
260+
if(!state || !api) {
261+
throw new Error('NotificationsFlash must be used within a provider')
262+
}
263+
264+
const { notifications } = usePage<{ notifications: Notification.FlashNotification[] }>().props
265+
useEffect(
266+
() => {
267+
each(notifications, (notification: Notification.FlashNotification) => {
268+
api.push(notification)
269+
})
270+
},
271+
[notifications]
272+
)
273+
274+
const onClose = (item: Notification.FlashNotification) => {
275+
if(item.readable?.enable && item.readable.url) {
276+
axios({
277+
method: item.readable.method,
278+
url: item.readable.url,
279+
}).then(() => {
280+
api.pull(item)
281+
})
282+
return
283+
}
284+
api.pull(item)
285+
}
286+
287+
const convertLevelToVariant = (level: Notification.Enums.NotificationLevelEnum): AlertProps['variant'] => {
288+
switch(level) {
289+
case 'success':
290+
return 'green'
291+
case 'info':
292+
return 'blue'
293+
case 'warning':
294+
return 'warning'
295+
case 'error':
296+
return 'destructive'
297+
default:
298+
return 'blue'
299+
}
300+
}
301+
302+
if(!state.items.length) {
303+
return null
304+
}
305+
306+
return (
307+
<LayoutGroup>
308+
<div className="grid grid-cols-1 gap-y-2">
309+
<AnimatePresence>
310+
{state.items.map((item) => (
311+
<motion.div
312+
animate={{ opacity: 1, scale: 1 }}
313+
exit={{ opacity: 0, scale: 0.9 }}
314+
initial={{ opacity: 0, scale: 0.9 }}
315+
key={item.id}
316+
transition={{ duration: 0.3, easing: 'ease-in-out' }}
317+
>
318+
{ item.shown ? (
319+
<AlertFlash
320+
closable
321+
icon={item.icon?.content}
322+
iconProps={item.icon?.props as any}
323+
text={item.message}
324+
title={item.title}
325+
variant={convertLevelToVariant(item.level)}
326+
onClose={() => { onClose(item) }}
327+
/>
328+
) : null }
329+
</motion.div>
330+
))}
331+
</AnimatePresence>
332+
</div>
333+
</LayoutGroup>
334+
)
335+
}
336+
````
337+
338+
139339
# Why Inertia Flash?
140340

141341
This package is intended to be used with the [InertiaJS](https://inertiajs.com/) framework.

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"php": "^8.3",
2020
"laravel/framework": "^v11.0.0",
2121
"illuminate/contracts": "^11.8.0",
22+
"spatie/laravel-data": "^4.5",
2223
"spatie/laravel-package-tools": "^1.16"
2324
},
2425
"suggest": {

0 commit comments

Comments
 (0)