From 02f5286ede456880a29c65664d3d885dc4a8c336 Mon Sep 17 00:00:00 2001 From: ajikamaludin Date: Tue, 20 Sep 2022 21:40:19 +0700 Subject: [PATCH] done --- .env.example | 11 ++-- app/Console/Kernel.php | 2 + app/Http/Controllers/DocumentController.php | 6 ++- app/Jobs/DocumentReminder.php | 50 +++++++++++++++++++ app/Mail/DocumentNotification.php | 38 ++++++++++++++ app/Mail/DocumentShare.php | 38 ++++++++++++++ app/Models/Document.php | 6 +-- .../2022_09_20_135018_create_jobs_table.php | 36 +++++++++++++ package-lock.json | 14 ++++++ package.json | 1 + resources/js/Pages/Dashboard.jsx | 20 ++++++-- resources/js/Pages/Document/Detail.jsx | 34 ++++++++++--- resources/js/Pages/Document/Index.jsx | 3 +- resources/js/Pages/Document/ModalShare.jsx | 2 +- resources/js/utils.js | 8 ++- .../emails/document/notification.blade.php | 12 +++++ .../views/emails/document/share.blade.php | 12 +++++ 17 files changed, 265 insertions(+), 28 deletions(-) create mode 100644 app/Jobs/DocumentReminder.php create mode 100644 app/Mail/DocumentNotification.php create mode 100644 app/Mail/DocumentShare.php create mode 100644 database/migrations/2022_09_20_135018_create_jobs_table.php create mode 100644 resources/views/emails/document/notification.blade.php create mode 100644 resources/views/emails/document/share.blade.php diff --git a/.env.example b/.env.example index aa94780..2fc2c5e 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -APP_NAME=Laravel +APP_NAME=MonitorDoc APP_ENV=local APP_KEY= APP_DEBUG=true @@ -8,17 +8,12 @@ LOG_CHANNEL=stack LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=monitor_doc -DB_USERNAME=root -DB_PASSWORD= +DB_CONNECTION=sqlite BROADCAST_DRIVER=log CACHE_DRIVER=file FILESYSTEM_DISK=local -QUEUE_CONNECTION=sync +QUEUE_CONNECTION=database SESSION_DRIVER=file SESSION_LIFETIME=120 diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index d8bc1d2..d4c3243 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,7 @@ namespace App\Console; +use App\Jobs\DocumentReminder; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -16,6 +17,7 @@ class Kernel extends ConsoleKernel protected function schedule(Schedule $schedule) { // $schedule->command('inspire')->hourly(); + $schedule->job(new DocumentReminder)->daily(); } /** diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index 081c7fe..5376069 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -2,12 +2,14 @@ namespace App\Http\Controllers; +use App\Mail\DocumentShare; use App\Models\Department; use App\Models\Document; use App\Models\TypeDoc; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Mail; use OpenSpout\Writer\Common\Creator\Style\StyleBuilder; use Rap2hpoutre\FastExcel\FastExcel; @@ -182,7 +184,7 @@ class DocumentController extends Controller public function show(Document $doc) { return inertia('Document/Detail', [ - 'doc' => $doc->load(['department', 'type', 'creator', 'reminders']), + 'doc' => $doc->load(['department', 'type', 'creator', 'reminders', 'shares']), 'doc_url' => asset('document/'.$doc->document), ]); } @@ -257,7 +259,7 @@ class DocumentController extends Controller } else { $doc->shares()->updateOrCreate(['share_to' => $share['share_to']]); } - // TODO: plase send email here + Mail::to($share['share_to'])->queue(new DocumentShare($doc)); } DB::commit(); diff --git a/app/Jobs/DocumentReminder.php b/app/Jobs/DocumentReminder.php new file mode 100644 index 0000000..bd0ca58 --- /dev/null +++ b/app/Jobs/DocumentReminder.php @@ -0,0 +1,50 @@ +pluck('document_id'); + $documents = Document::whereIn('id', $documentIds)->get(); + + foreach ($documents as $doc) { + Mail::to($doc->email)->queue(new DocumentNotification($doc)); + if ($doc->shares()->count() > 0) { + foreach ($doc->shares as $share) { + Mail::to($share->share_to)->queue(new DocumentNotification($doc)); + } + } + } + } +} diff --git a/app/Mail/DocumentNotification.php b/app/Mail/DocumentNotification.php new file mode 100644 index 0000000..bbd6163 --- /dev/null +++ b/app/Mail/DocumentNotification.php @@ -0,0 +1,38 @@ +markdown('emails.document.notification', [ + 'no_doc' => $this->doc->no_doc, + 'end_date' => $this->doc->end_date->format('d-m-Y'), + 'url' => route('docs.show', $this->doc) + ]); + } +} diff --git a/app/Mail/DocumentShare.php b/app/Mail/DocumentShare.php new file mode 100644 index 0000000..7baa8cd --- /dev/null +++ b/app/Mail/DocumentShare.php @@ -0,0 +1,38 @@ +markdown('emails.document.share', [ + 'no_doc' => $this->doc->no_doc, + 'end_date' => $this->doc->end_date->format('d-m-Y'), + 'url' => route('docs.show', $this->doc) + ]); + } +} diff --git a/app/Models/Document.php b/app/Models/Document.php index 164b31d..3162cf2 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -27,9 +27,9 @@ class Document extends Model 'user_id', ]; - protected $cast = [ - 'start_date' => 'date', - 'end_date' => 'date' + protected $casts = [ + 'start_date' => 'datetime:Y-m-d', + 'end_date' => 'datetime:Y-m-d' ]; public const ACTIVE = 0; diff --git a/database/migrations/2022_09_20_135018_create_jobs_table.php b/database/migrations/2022_09_20_135018_create_jobs_table.php new file mode 100644 index 0000000..a786a89 --- /dev/null +++ b/database/migrations/2022_09_20_135018_create_jobs_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('jobs'); + } +}; diff --git a/package-lock.json b/package-lock.json index 5d1d2f0..de14783 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "@fullcalendar/interaction": "^5.11.3", "@fullcalendar/react": "^5.11.2", "daisyui": "^2.28.0", + "moment": "^2.29.4", "react-toastify": "^9.0.8", "react-use": "^17.4.0" }, @@ -1973,6 +1974,14 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4116,6 +4125,11 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index 536c427..465e19a 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@fullcalendar/interaction": "^5.11.3", "@fullcalendar/react": "^5.11.2", "daisyui": "^2.28.0", + "moment": "^2.29.4", "react-toastify": "^9.0.8", "react-use": "^17.4.0" } diff --git a/resources/js/Pages/Dashboard.jsx b/resources/js/Pages/Dashboard.jsx index f0d4e2c..cd53f3f 100644 --- a/resources/js/Pages/Dashboard.jsx +++ b/resources/js/Pages/Dashboard.jsx @@ -6,17 +6,29 @@ import interactionPlugin from "@fullcalendar/interaction" // needed for dayClick import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head } from '@inertiajs/inertia-react'; +import { Inertia } from '@inertiajs/inertia'; export default function Dashboard(props) { const { count_active, count_update, count_expired, count_total, events } = props - console.log(events) - const calenderEvents = events.map(e => { return {title: `${e.document.no_doc} - ${e.document.pic_name}`, date: e.date} }) + + const calenderEvents = events.map(e => { + return { + title: `${e.document.no_doc} - ${e.document.pic_name}`, + date: e.date, + id : e.id, + url: route('docs.show', e.document) + } + }) + + const handleEventClick = (arg) => { + // console.log(arg.event) + } const handleDateClick = (arg) => { // bind with an arrow function // apa yang harus di handle: tampilkan saja modal yang ada event pada date ini kemudian bisa tambah reminder atau hapus reminder pada data ini, // untuk tambah reminder pilih form doc id saja kemudian tambah , untuk delete cukup confirm kemudian hilang alert(arg.dateStr) - } + } return ( console.log(arg)} + eventClick={handleEventClick} events={calenderEvents} /> diff --git a/resources/js/Pages/Document/Detail.jsx b/resources/js/Pages/Document/Detail.jsx index 0cc3c56..f5ebc10 100644 --- a/resources/js/Pages/Document/Detail.jsx +++ b/resources/js/Pages/Document/Detail.jsx @@ -5,11 +5,20 @@ import DocStatusItem from './DocStatusItem' import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import InputLabel from '@/Components/InputLabel' import TextInput from '@/Components/TextInput' +import { formatDate } from '@/utils' +import ModalShare from './ModalShare' +import { useModalState } from '@/Hooks' export default function FormDocument(props) { const { doc, doc_url }= props + const shareModal = useModalState(false) + const handleShare = (doc) => { + shareModal.setData(doc) + shareModal.toggle() + } + return (
- - Edit - +
+ + Edit + +
handleShare(doc)}> + Share +
+
Kembali @@ -180,7 +194,11 @@ export default function FormDocument(props) {
- +
) diff --git a/resources/js/Pages/Document/Index.jsx b/resources/js/Pages/Document/Index.jsx index f95d849..ea3c50f 100644 --- a/resources/js/Pages/Document/Index.jsx +++ b/resources/js/Pages/Document/Index.jsx @@ -12,6 +12,7 @@ import ModalFilter from './ModalFilter' import ModalShare from './ModalShare' import DocStatusItem from './DocStatusItem' import { IconFilter, IconMenu } from '@/Icons' +import { formatDate } from '@/utils' export default function Document(props) { const { types, departments } = props @@ -122,7 +123,7 @@ export default function Document(props) { {doc.type.name} {doc.pic_name} - {doc.end_date} + {formatDate(doc.end_date)}
diff --git a/resources/js/Pages/Document/ModalShare.jsx b/resources/js/Pages/Document/ModalShare.jsx index 9cffe9c..e23ea70 100644 --- a/resources/js/Pages/Document/ModalShare.jsx +++ b/resources/js/Pages/Document/ModalShare.jsx @@ -71,7 +71,7 @@ export default function ModalShare(props) {
{shares.map((share, index) => ( -
+

{share.share_to} diff --git a/resources/js/utils.js b/resources/js/utils.js index 5ae9c01..c2c60db 100644 --- a/resources/js/utils.js +++ b/resources/js/utils.js @@ -1,3 +1,5 @@ +import moment from "moment"; + export const statuses = [ { key: 0, @@ -22,4 +24,8 @@ export const validateEmail = (email) => { .match( /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ ); -}; \ No newline at end of file +}; + +export const formatDate = (stringDate) => { + return moment(stringDate).format('DD-MM-yyyy') +} \ No newline at end of file diff --git a/resources/views/emails/document/notification.blade.php b/resources/views/emails/document/notification.blade.php new file mode 100644 index 0000000..85f0740 --- /dev/null +++ b/resources/views/emails/document/notification.blade.php @@ -0,0 +1,12 @@ +@component('mail::message') +# Dokumen Notifikasi + +Reminder, untuk dokument {{ $no_doc }} akan berakhir pada {{ $end_date }} mohon untuk segera melakukan tindakan + +@component('mail::button', ['url' => $url]) +Detail Dokumen +@endcomponent + +Terima kasih ,
+{{ config('app.name') }} +@endcomponent diff --git a/resources/views/emails/document/share.blade.php b/resources/views/emails/document/share.blade.php new file mode 100644 index 0000000..f0cb55d --- /dev/null +++ b/resources/views/emails/document/share.blade.php @@ -0,0 +1,12 @@ +@component('mail::message') +# Berbagi Dokumen + +Saya membagikan dokumen dengan anda, untuk dokument {{ $no_doc }} akan berakhir pada {{ $end_date }} mohon untuk segera melakukan tindakan + +@component('mail::button', ['url' => $url]) +Detail Dokumen +@endcomponent + +Terima kasih ,
+{{ config('app.name') }} +@endcomponent