From 854d9db22e5da214713f47bd2be3c7b776b08166 Mon Sep 17 00:00:00 2001 From: ajikamaludin Date: Tue, 18 Oct 2022 08:47:43 +0700 Subject: [PATCH] update notification --- app/Http/Controllers/DocumentController.php | 8 +-- .../Controllers/NotificationController.php | 21 ++++++++ app/Http/Middleware/HandleInertiaRequests.php | 27 ++++++++++ app/Models/Notification.php | 22 +++++++++ ...0_17_115058_create_notifications_table.php | 35 +++++++++++++ resources/css/app.css | 20 ++++++++ resources/js/Components/Dropdown.jsx | 17 ++++--- resources/js/Icons.jsx | 16 ++++++ resources/js/Layouts/AuthenticatedLayout.jsx | 49 ++++++++++++++++++- resources/js/Pages/Dashboard.jsx | 1 + resources/js/Pages/Document/Detail.jsx | 1 + resources/js/Pages/Document/Form.jsx | 5 +- resources/js/Pages/Document/Index.jsx | 1 + resources/js/Pages/User/Index.jsx | 1 + routes/web.php | 3 ++ 15 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 app/Http/Controllers/NotificationController.php create mode 100644 app/Models/Notification.php create mode 100644 database/migrations/2022_10_17_115058_create_notifications_table.php diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index 0a11dc9..c138a35 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -70,7 +70,7 @@ class DocumentController extends Controller 'first_person_name' => 'required|string', 'second_person_name' => 'required|string', 'start_date' => 'required|date', - 'end_date' => 'required|date', + 'end_date' => 'required|date|after_or_equal:'.$request->start_date, 'type_doc_id' => 'required|exists:type_docs,id', 'department_id' => 'required|exists:departments,id', 'pic_name' => 'required|string', @@ -98,7 +98,7 @@ class DocumentController extends Controller 'note' => $request->note, 'type_doc_id' => $request->type_doc_id, 'department_id' => $request->department_id, - 'status' => $request->status, + 'status' => Document::ACTIVE, //DOCUMENT CREATED ALWAYS ACTIVE 'user_id' => auth()->user()->id, ]); @@ -137,7 +137,7 @@ class DocumentController extends Controller 'first_person_name' => 'required|string', 'second_person_name' => 'required|string', 'start_date' => 'required|date', - 'end_date' => 'required|date', + 'end_date' => 'required|date|after_or_equal:'.$request->start_date, 'type_doc_id' => 'required|exists:type_docs,id', 'department_id' => 'required|exists:departments,id', 'pic_name' => 'required|string', @@ -162,7 +162,7 @@ class DocumentController extends Controller 'note' => $request->note, 'type_doc_id' => $request->type_doc_id, 'department_id' => $request->department_id, - 'status' => $request->status, + 'status' => Document::UPDATE // DOCUEMENT UPDATED IS ALWAYS UPDATE ]); $file = $request->file('document'); diff --git a/app/Http/Controllers/NotificationController.php b/app/Http/Controllers/NotificationController.php new file mode 100644 index 0000000..747f727 --- /dev/null +++ b/app/Http/Controllers/NotificationController.php @@ -0,0 +1,21 @@ + redirect to page with related page with status read + $notification->update(['status' => Notification::STATUS_READ]); + + if ($notification->model_related == Document::class) { + return redirect()->route('docs.show', $notification->model_id); + } + return redirect()->route('dashboard'); + } +} diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index b0cb9ab..c94a6c1 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -2,6 +2,9 @@ namespace App\Http\Middleware; +use App\Models\Document; +use App\Models\DocumentReminder as ModelsDocumentReminder; +use App\Models\Notification; use Illuminate\Http\Request; use Inertia\Middleware; use Tightenco\Ziggy\Ziggy; @@ -34,6 +37,26 @@ class HandleInertiaRequests extends Middleware */ public function share(Request $request) { + $now = now(); + // Do Something here to check document expired -> than create notification + $documentIds = ModelsDocumentReminder::whereDate('date', $now)->pluck('document_id'); + + $documents = Document::whereIn('id', $documentIds)->whereIn('status', [Document::ACTIVE, Document::UPDATE])->get(); + foreach ($documents as $doc) { + // only set expired when enddate is set + if ($doc->end_date->format('d-m-Y') >= $now->format('d-m-Y')) { + $doc->update(['status' => Document::EXPIRED]); + } + // create notification + Notification::create([ + 'content' => $doc->type->name.' - '.$doc->name. ' akan berakhir pada '. $doc->end_date->format('d-m-Y'), + 'date' => $now, + 'model_related' => Document::class, + 'model_id' => $doc->id, + 'status' => Notification::STATUS_UNREAD + ]); + } + return array_merge(parent::share($request), [ 'auth' => [ 'user' => $request->user(), @@ -46,6 +69,10 @@ class HandleInertiaRequests extends Middleware 'flash' => [ 'message' => fn () => $request->session()->get('message') ], + 'notify' => [ + 'notifications' => Notification::orderBy('created_at', 'desc')->get(), + 'notification_has_unread' => Notification::where('status', Notification::STATUS_UNREAD)->count() + ] ]); } } diff --git a/app/Models/Notification.php b/app/Models/Notification.php new file mode 100644 index 0000000..2dccf8a --- /dev/null +++ b/app/Models/Notification.php @@ -0,0 +1,22 @@ +id(); + $table->timestamps(); + $table->text('content')->nullable(); + $table->date('date')->nullable(); + $table->string('model_related')->nullable(); + $table->string('model_id')->nullable(); + $table->smallInteger('status')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('notifications'); + } +}; diff --git a/resources/css/app.css b/resources/css/app.css index b5c61c9..f26cddf 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,3 +1,23 @@ @tailwind base; @tailwind components; @tailwind utilities; + +/* width */ +::-webkit-scrollbar { + width: 5px; + } + + /* Track */ + ::-webkit-scrollbar-track { + background: #f1f1f1; + } + + /* Handle */ + ::-webkit-scrollbar-thumb { + background: #888; + } + + /* Handle on hover */ + ::-webkit-scrollbar-thumb:hover { + background: #555; + } \ No newline at end of file diff --git a/resources/js/Components/Dropdown.jsx b/resources/js/Components/Dropdown.jsx index 3f02d42..a4cdfc7 100644 --- a/resources/js/Components/Dropdown.jsx +++ b/resources/js/Components/Dropdown.jsx @@ -30,7 +30,7 @@ const Trigger = ({ children }) => { ); }; -const Content = ({ align = 'right', width = '48', contentClasses = 'py-1 bg-base-100', children }) => { +const Content = ({ align = 'right', width = 'w-48', contentClasses = 'py-1 bg-base-100', maxHeight = '100px', children }) => { const { open, setOpen } = useContext(DropDownContext); let alignmentClasses = 'origin-top'; @@ -41,10 +41,10 @@ const Content = ({ align = 'right', width = '48', contentClasses = 'py-1 bg-base alignmentClasses = 'origin-top-right right-0'; } - let widthClasses = ''; - - if (width === '48') { - widthClasses = 'w-48'; + let widthClasses = width; + let overflwoAuto = false; + if(maxHeight !== '100px') { + overflwoAuto = true; } return ( @@ -60,10 +60,13 @@ const Content = ({ align = 'right', width = '48', contentClasses = 'py-1 bg-base leaveTo="transform opacity-0 scale-95" >
setOpen(false)} > -
{children}
+
+ {children} +
diff --git a/resources/js/Icons.jsx b/resources/js/Icons.jsx index 697964a..e283d11 100644 --- a/resources/js/Icons.jsx +++ b/resources/js/Icons.jsx @@ -18,4 +18,20 @@ export const IconCross = () => { return ( ) +} + +export const IconBell = () => { + return ( + + + + ) +} + +export const IconBellRing = ({ color = "none" }) => { + return ( + + + + ) } \ No newline at end of file diff --git a/resources/js/Layouts/AuthenticatedLayout.jsx b/resources/js/Layouts/AuthenticatedLayout.jsx index cff6b4b..7cbf332 100644 --- a/resources/js/Layouts/AuthenticatedLayout.jsx +++ b/resources/js/Layouts/AuthenticatedLayout.jsx @@ -5,8 +5,41 @@ import { ToastContainer, toast } from 'react-toastify' import ResponsiveNavLink from '@/Components/ResponsiveNavLink'; import { Link } from '@inertiajs/inertia-react'; import MenuItem from '@/Components/SidebarMenuItem'; +import { IconBell, IconBellRing } from '@/Icons'; +import { Inertia } from '@inertiajs/inertia'; -export default function Authenticated({ auth, children, flash }) { +const Notification = ({ notifications, hasUnread }) => { + const redirect = (item) => { + Inertia.get(route('notification.redirect', item)) + } + + return ( + + + {hasUnread ? ( + + ) : ( + + )} + + + {notifications.map(item => ( +
redirect(item)}> +
{item.content}
+
• {item.date}
+
+ ))} + {+notifications.length === 0 && ( +
+
No Notification Found
+
+ )} +
+
+ ) +} + +export default function Authenticated({ auth, children, flash, notify }) { const [showingNavigationDropdown, setShowingNavigationDropdown] = useState(false); useEffect(() => { @@ -35,6 +68,12 @@ export default function Authenticated({ auth, children, flash }) {
+
+ 0 ? true : false} + /> +
@@ -61,7 +100,7 @@ export default function Authenticated({ auth, children, flash }) { - + Log Out @@ -70,6 +109,12 @@ export default function Authenticated({ auth, children, flash }) {
+
+ 0 ? true : false} + /> +
-
+ {/*