update notification

original
ajikamaludin 2 years ago
parent 782e90ea46
commit 854d9db22e
Signed by: ajikamaludin
GPG Key ID: 476C9A2B4B794EBB

@ -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');

@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers;
use App\Models\Document;
use App\Models\Notification;
use Illuminate\Http\Request;
class NotificationController extends Controller
{
public function redirect(Notification $notification)
{
// todo: here you will receive notification id -> 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');
}
}

@ -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()
]
]);
}
}

@ -0,0 +1,22 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Notification extends Model
{
use HasFactory;
const STATUS_UNREAD = 0;
const STATUS_READ = 1;
protected $fillable = [
'content',
'date',
'model_related',
'model_id',
'status'
];
}

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('notifications', function (Blueprint $table) {
$table->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');
}
};

@ -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;
}

@ -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"
>
<div
className={`absolute z-50 mt-2 rounded-md shadow-lg ${alignmentClasses} ${widthClasses}`}
className={`absolute z-50 mt-2 rounded-md shadow-lg ${overflwoAuto ? 'overflow-auto' : ''} ${alignmentClasses} ${widthClasses}`}
style={{maxHeight: maxHeight}}
onClick={() => setOpen(false)}
>
<div className={`rounded-md ring-1 ring-black ring-opacity-5 ` + contentClasses}>{children}</div>
<div className={`rounded-md ring-1 ring-gray-300 ring-opacity-5` + contentClasses}>
{children}
</div>
</div>
</Transition>
</>

@ -18,4 +18,20 @@ export const IconCross = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>
)
}
export const IconBell = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
</svg>
)
}
export const IconBellRing = ({ color = "none" }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" fill={color} viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5" />
</svg>
)
}

@ -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 (
<Dropdown>
<Dropdown.Trigger>
{hasUnread ? (
<IconBellRing color="#37cdbe" />
) : (
<IconBell/>
)}
</Dropdown.Trigger>
<Dropdown.Content contentClasses='p-1 bg-base-100' width='w-60' maxHeight='600px'>
{notifications.map(item => (
<div className='pl-2 py-2 hover:bg-base-200' key={item.id} onClick={() => redirect(item)}>
<div className={`text-sm ${item.status == 0 ? 'font-bold' : ''}`}>{item.content}</div>
<div className='text-xs font-light'> {item.date}</div>
</div>
))}
{+notifications.length === 0 && (
<div className='pl-2 py-2 hover:bg-base-200'>
<div className={`text-sm`}>No Notification Found</div>
</div>
)}
</Dropdown.Content>
</Dropdown>
)
}
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 }) {
</div>
<div className="hidden sm:flex sm:items-center sm:ml-6">
<div className="ml-3 relative">
<Notification
notifications={notify.notifications}
hasUnread={+notify.notification_has_unread > 0 ? true : false}
/>
</div>
<div className="ml-3 relative">
<Dropdown>
<Dropdown.Trigger>
@ -61,7 +100,7 @@ export default function Authenticated({ auth, children, flash }) {
</span>
</Dropdown.Trigger>
<Dropdown.Content>
<Dropdown.Content width='w-42'>
<Dropdown.Link href={route('logout')} method="post" as="button">
Log Out
</Dropdown.Link>
@ -70,6 +109,12 @@ export default function Authenticated({ auth, children, flash }) {
</div>
</div>
<div className="-mr-20 flex items-center sm:hidden">
<Notification
notifications={notify.notifications}
hasUnread={+notify.notification_has_unread > 0 ? true : false}
/>
</div>
<div className="-mr-2 flex items-center sm:hidden">
<button
onClick={() => setShowingNavigationDropdown((previousState) => !previousState)}

@ -35,6 +35,7 @@ export default function Dashboard(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
notify={props.notify}
>
<Head title="Dashboard" />

@ -24,6 +24,7 @@ export default function FormDocument(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
notify={props.notify}
>
<Head title="Document - Form" />

@ -96,6 +96,7 @@ export default function FormDocument(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
notify={props.notify}
>
<Head title="Document - Form" />
@ -276,7 +277,7 @@ export default function FormDocument(props) {
<p className='text-sm'>file saved is found, reupload to replace</p>
)}
</div>
<div className='mt-4'>
{/* <div className='mt-4'>
<InputLabel forInput="status" value="Status" />
<select
className="mt-1 select select-bordered w-full"
@ -289,7 +290,7 @@ export default function FormDocument(props) {
))}
</select>
<InputError message={errors.status}/>
</div>
</div> */}
<div className='mt-4'>
<div className='flex flex-row space-x-5 items-center'>
<InputLabel forInput="reminder" value="Reminder" />

@ -76,6 +76,7 @@ export default function Document(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
notify={props.notify}
>
<Head title="Document" />
<div className="flex flex-col w-full sm:px-6 lg:px-8 space-y-2">

@ -56,6 +56,7 @@ export default function Users(props) {
auth={props.auth}
errors={props.errors}
flash={props.flash}
notify={props.notify}
>
<Head title="Users" />
<div className="flex flex-col w-full sm:px-6 lg:px-8 space-y-2">

@ -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';

Loading…
Cancel
Save