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}
+ />
+
diff --git a/resources/js/Pages/Document/Detail.jsx b/resources/js/Pages/Document/Detail.jsx
index f5ebc10..a79b76b 100644
--- a/resources/js/Pages/Document/Detail.jsx
+++ b/resources/js/Pages/Document/Detail.jsx
@@ -24,6 +24,7 @@ export default function FormDocument(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
+ notify={props.notify}
>
diff --git a/resources/js/Pages/Document/Form.jsx b/resources/js/Pages/Document/Form.jsx
index 2318ba5..02156fe 100644
--- a/resources/js/Pages/Document/Form.jsx
+++ b/resources/js/Pages/Document/Form.jsx
@@ -96,6 +96,7 @@ export default function FormDocument(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
+ notify={props.notify}
>
@@ -276,7 +277,7 @@ export default function FormDocument(props) {
file saved is found, reupload to replace
)}
- */}
diff --git a/resources/js/Pages/Document/Index.jsx b/resources/js/Pages/Document/Index.jsx
index 63a99e4..86362c4 100644
--- a/resources/js/Pages/Document/Index.jsx
+++ b/resources/js/Pages/Document/Index.jsx
@@ -76,6 +76,7 @@ export default function Document(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
+ notify={props.notify}
>
diff --git a/resources/js/Pages/User/Index.jsx b/resources/js/Pages/User/Index.jsx
index 782e034..6d50e05 100644
--- a/resources/js/Pages/User/Index.jsx
+++ b/resources/js/Pages/User/Index.jsx
@@ -56,6 +56,7 @@ export default function Users(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
+ notify={props.notify}
>
diff --git a/routes/web.php b/routes/web.php
index 6dd488a..94ee4a4 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -2,6 +2,7 @@
use App\Http\Controllers\DocumentController;
use App\Http\Controllers\GeneralController;
+use App\Http\Controllers\NotificationController;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
@@ -39,6 +40,8 @@ Route::middleware(['auth'])->group(function () {
Route::post('/docs/{doc}', [DocumentController::class, 'update'])->name('docs.update');
Route::get('/docs/{doc}/show', [DocumentController::class, 'show'])->name('docs.show');
Route::post('/docs/{doc}/share', [DocumentController::class, 'share'])->name('docs.share');
+
+ Route::get('/notification/{notification}', [NotificationController::class, 'redirect'])->name('notification.redirect');
});
require __DIR__.'/auth.php';