Skip to content

Commit cfc9c00

Browse files
committed
first commit
0 parents  commit cfc9c00

File tree

14 files changed

+528
-0
lines changed

14 files changed

+528
-0
lines changed

config/permissions.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
return [
4+
[
5+
'name' => 'calendar.index',
6+
'flag' => 'calendar.index',
7+
'parent_flag' => 'core.admin',
8+
],
9+
[
10+
'name' => 'calendar.create',
11+
'flag' => 'calendar.create',
12+
'parent_flag' => 'calendar.index',
13+
],
14+
[
15+
'name' => 'calendar.edit',
16+
'flag' => 'calendar.edit',
17+
'parent_flag' => 'calendar.index',
18+
],
19+
[
20+
'name' => 'calendar.delete',
21+
'flag' => 'calendar.delete',
22+
'parent_flag' => 'calendar.index',
23+
],
24+
];
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
use Illuminate\Database\Migrations\Migration;
3+
use Illuminate\Database\Schema\Blueprint;
4+
use Illuminate\Support\Facades\Schema;
5+
6+
return new class extends Migration {
7+
public function up()
8+
{
9+
Schema::create('calendar_tasks', function (Blueprint $table) {
10+
$table->id();
11+
$table->string('task_type');
12+
$table->enum('repetition', ['one_time', 'monthly', 'every_6_months', 'yearly'])->default('one_time');
13+
$table->date('start_date');
14+
$table->date('end_date')->nullable();
15+
$table->string('task_name');
16+
$table->string('phone_number')->nullable();
17+
$table->boolean('reminder_sent')->default(false);
18+
$table->timestamps();
19+
});
20+
}
21+
22+
public function down()
23+
{
24+
Schema::dropIfExists('calendar_tasks');
25+
}
26+
};

plugin.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"id": "platform/calendar",
3+
"name": "Calendar",
4+
"namespace": "Platform\\Plugins\\Calendar\\",
5+
"provider": "Platform\\Plugins\\Calendar\\Providers\\CalendarServiceProvider",
6+
"author": "Tayyab Akmal",
7+
"url": "https://www.linkedin.com/in/tayyab-sqa-engineer/",
8+
"version": "1.0.0",
9+
"description": "Manage tasks efficiently with features like adding, editing, deleting, and repeating tasks, plus automated reminders.",
10+
"minimum_core_version": "7.3.0"
11+
}

resources/lang/en/calendar.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
return [
4+
'calendar' => 'Calendar',
5+
'add_task' => 'Add Task',
6+
'edit_task' => 'Edit Task',
7+
'task_name' => 'Task Name',
8+
'task_type' => 'Task Type',
9+
'repetition' => 'Repetition',
10+
'repetition_one_time' => 'One-time',
11+
'repetition_monthly' => 'Monthly',
12+
'repetition_every_6_months' => 'Every 6 Months',
13+
'repetition_yearly' => 'Yearly',
14+
'start_date' => 'Start Date',
15+
'end_date' => 'End Date',
16+
'phone_number' => 'Phone Number',
17+
'actions' => 'Actions',
18+
'edit' => 'Edit',
19+
'delete' => 'Delete',
20+
'update' => 'Update',
21+
'create' => 'Create',
22+
'cancel' => 'Cancel',
23+
'no_tasks' => 'No tasks found.',
24+
'task_created' => 'Task created successfully.',
25+
'task_updated' => 'Task updated successfully.',
26+
'task_deleted' => 'Task deleted successfully.',
27+
'confirm_delete' => 'Are you sure you want to delete this task?',
28+
'list_view' => 'List View',
29+
'calendar_view' => 'Calendar View',
30+
];
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
@extends('core/base::layouts.master')
2+
3+
@section('content')
4+
<div class="container">
5+
<h1>{{ __('calendar::calendar.calendar') }}</h1>
6+
<a href="{{ route('admin.calendar.index') }}" class="btn btn-secondary mb-3">{{ __('calendar::calendar.list_view') }}</a>
7+
<div id="calendar"></div>
8+
</div>
9+
10+
<!-- Modal -->
11+
<div class="modal fade" id="taskModal" tabindex="-1" aria-labelledby="taskModalLabel" aria-hidden="true">
12+
<div class="modal-dialog">
13+
<div class="modal-content">
14+
<div class="modal-header">
15+
<h5 class="modal-title" id="taskModalLabel">Task Details</h5>
16+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
17+
</div>
18+
<div class="modal-body" id="taskModalBody">
19+
<!-- Task details will be injected here -->
20+
</div>
21+
<div class="modal-footer">
22+
<a href="#" id="editTaskLink" class="btn btn-primary">Edit Task</a>
23+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
24+
</div>
25+
</div>
26+
</div>
27+
</div>
28+
@endsection
29+
30+
@push('header')
31+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.css" rel="stylesheet">
32+
@endpush
33+
34+
@push('footer')
35+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js"></script>
36+
<script>
37+
document.addEventListener('DOMContentLoaded', function() {
38+
var calendarEl = document.getElementById('calendar');
39+
var calendar = new FullCalendar.Calendar(calendarEl, {
40+
initialView: 'dayGridMonth',
41+
events: {
42+
url: '{{ route('admin.calendar.calendar.events') }}',
43+
method: 'GET',
44+
},
45+
headerToolbar: {
46+
left: 'prev,next today',
47+
center: 'title',
48+
right: 'dayGridMonth,dayGridWeek,dayGridDay'
49+
},
50+
eventClick: function(info) {
51+
info.jsEvent.preventDefault();
52+
// Show modal with task details
53+
var event = info.event;
54+
var modal = new bootstrap.Modal(document.getElementById('taskModal'));
55+
var body = document.getElementById('taskModalBody');
56+
var editLink = document.getElementById('editTaskLink');
57+
body.innerHTML = `
58+
<p><strong>Task Name:</strong> ${event.title}</p>
59+
<p><strong>Date:</strong> ${event.startStr}</p>
60+
`;
61+
// If the event id is in the format 'id-YYYYMMDD', extract the id
62+
var taskId = event.id.split('-')[0];
63+
editLink.href = '{{ url('admin/calendar') }}/' + taskId + '/edit';
64+
modal.show();
65+
}
66+
});
67+
calendar.render();
68+
});
69+
</script>
70+
@endpush
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
@extends('core/base::layouts.master')
2+
3+
@section('content')
4+
<div class="container">
5+
<h1>{{ isset($task) ? __('calendar::calendar.edit_task') : __('calendar::calendar.add_task') }}</h1>
6+
<form method="POST" action="{{ isset($task) ? route('admin.calendar.update', $task) : route('admin.calendar.store') }}">
7+
@csrf
8+
@if(isset($task))
9+
@method('PUT')
10+
@endif
11+
<div class="mb-3">
12+
<label for="task_name" class="form-label">{{ __('calendar::calendar.task_name') }}</label>
13+
<input type="text" class="form-control" id="task_name" name="task_name" value="{{ old('task_name', $task->task_name ?? '') }}" required>
14+
</div>
15+
<div class="mb-3">
16+
<label for="task_type" class="form-label">{{ __('calendar::calendar.task_type') }}</label>
17+
<input type="text" class="form-control" id="task_type" name="task_type" value="{{ old('task_type', $task->task_type ?? '') }}" required>
18+
</div>
19+
<div class="mb-3">
20+
<label for="repetition" class="form-label">{{ __('calendar::calendar.repetition') }}</label>
21+
<select class="form-control" id="repetition" name="repetition" required>
22+
<option value="one_time" {{ old('repetition', $task->repetition ?? '') == 'one_time' ? 'selected' : '' }}>{{ __('calendar::calendar.repetition_one_time') }}</option>
23+
<option value="monthly" {{ old('repetition', $task->repetition ?? '') == 'monthly' ? 'selected' : '' }}>{{ __('calendar::calendar.repetition_monthly') }}</option>
24+
<option value="every_6_months" {{ old('repetition', $task->repetition ?? '') == 'every_6_months' ? 'selected' : '' }}>{{ __('calendar::calendar.repetition_every_6_months') }}</option>
25+
<option value="yearly" {{ old('repetition', $task->repetition ?? '') == 'yearly' ? 'selected' : '' }}>{{ __('calendar::calendar.repetition_yearly') }}</option>
26+
</select>
27+
</div>
28+
<div class="mb-3">
29+
<label for="start_date" class="form-label">{{ __('calendar::calendar.start_date') }}</label>
30+
<input type="date" class="form-control" id="start_date" name="start_date" value="{{ old('start_date', isset($task) ? $task->start_date->format('Y-m-d') : '') }}" required>
31+
</div>
32+
<div class="mb-3">
33+
<label for="end_date" class="form-label">{{ __('calendar::calendar.end_date') }}</label>
34+
<input type="date" class="form-control" id="end_date" name="end_date" value="{{ old('end_date', isset($task) && $task->end_date ? $task->end_date->format('Y-m-d') : '') }}">
35+
</div>
36+
<div class="mb-3">
37+
<label for="phone_number" class="form-label">{{ __('calendar::calendar.phone_number') }}</label>
38+
<input type="text" class="form-control" id="phone_number" name="phone_number" value="{{ old('phone_number', $task->phone_number ?? '') }}">
39+
</div>
40+
<button type="submit" class="btn btn-success">{{ isset($task) ? __('calendar::calendar.update') : __('calendar::calendar.create') }}</button>
41+
<a href="{{ route('admin.calendar.index') }}" class="btn btn-secondary">{{ __('calendar::calendar.cancel') }}</a>
42+
</form>
43+
</div>
44+
@endsection
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@extends('core/base::layouts.master')
2+
3+
@section('content')
4+
<div class="container">
5+
<h1>{{ __('calendar::calendar.calendar') }}</h1>
6+
<a href="{{ route('admin.calendar.calendar') }}" class="btn btn-info mb-3">{{ __('calendar::calendar.calendar_view') }}</a>
7+
<a href="{{ route('admin.calendar.create') }}" class="btn btn-primary mb-3">{{ __('calendar::calendar.add_task') }}</a>
8+
@if(session('success'))
9+
<div class="alert alert-success">{{ session('success') }}</div>
10+
@endif
11+
<table class="table table-bordered">
12+
<thead>
13+
<tr>
14+
<th>{{ __('calendar::calendar.task_name') }}</th>
15+
<th>{{ __('calendar::calendar.task_type') }}</th>
16+
<th>{{ __('calendar::calendar.repetition') }}</th>
17+
<th>{{ __('calendar::calendar.start_date') }}</th>
18+
<th>{{ __('calendar::calendar.end_date') }}</th>
19+
<th>{{ __('calendar::calendar.phone_number') }}</th>
20+
<th>{{ __('calendar::calendar.actions') }}</th>
21+
</tr>
22+
</thead>
23+
<tbody>
24+
@forelse($tasks as $task)
25+
<tr>
26+
<td>{{ $task->task_name }}</td>
27+
<td>{{ $task->task_type }}</td>
28+
<td>{{ __('calendar::calendar.repetition_' . $task->repetition) }}</td>
29+
<td>{{ $task->start_date->format('Y-m-d') }}</td>
30+
<td>{{ $task->end_date ? $task->end_date->format('Y-m-d') : '-' }}</td>
31+
<td>{{ $task->phone_number }}</td>
32+
<td>
33+
<a href="{{ route('admin.calendar.edit', $task) }}" class="btn btn-sm btn-warning">{{ __('calendar::calendar.edit') }}</a>
34+
<form action="{{ route('admin.calendar.destroy', $task) }}" method="POST" style="display:inline-block;">
35+
@csrf
36+
@method('DELETE')
37+
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('{{ __('calendar::calendar.confirm_delete') }}')">{{ __('calendar::calendar.delete') }}</button>
38+
</form>
39+
</td>
40+
</tr>
41+
@empty
42+
<tr>
43+
<td colspan="7">{{ __('calendar::calendar.no_tasks') }}</td>
44+
</tr>
45+
@endforelse
46+
</tbody>
47+
</table>
48+
</div>
49+
@endsection
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<p>Hello,</p>
2+
<p>This is a reminder that the following task is due tomorrow:</p>
3+
<ul>
4+
<li><strong>Task Name:</strong> {{ $task->task_name }}</li>
5+
<li><strong>Task Type:</strong> {{ $task->task_type }}</li>
6+
<li><strong>Start Date:</strong> {{ $task->start_date->format('Y-m-d') }}</li>
7+
<li><strong>End Date:</strong> {{ $task->end_date ? $task->end_date->format('Y-m-d') : '-' }}</li>
8+
<li><strong>Repetition:</strong> {{ __('calendar::calendar.repetition_' . $task->repetition) }}</li>
9+
<li><strong>Phone Number:</strong> {{ $task->phone_number }}</li>
10+
</ul>
11+
<p>Please make sure to complete it on time.</p>
12+
<p>Thank you!</p>

routes/web.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
use Illuminate\Support\Facades\Route;
4+
use Platform\Plugins\Calendar\Http\Controllers\TaskController;
5+
6+
Route::group([
7+
'prefix' => 'admin/calendar',
8+
'as' => 'admin.calendar.',
9+
'middleware' => ['web', 'auth'],
10+
], function () {
11+
Route::get('/', [TaskController::class, 'index'])->name('index');
12+
Route::get('/create', [TaskController::class, 'create'])->name('create');
13+
Route::post('/store', [TaskController::class, 'store'])->name('store');
14+
Route::get('/{task}/edit', [TaskController::class, 'edit'])->name('edit');
15+
Route::put('/{task}', [TaskController::class, 'update'])->name('update');
16+
Route::delete('/{task}', [TaskController::class, 'destroy'])->name('destroy');
17+
Route::get('/calendar-view', [TaskController::class, 'calendar'])->name('calendar');
18+
Route::get('/calendar-events', [TaskController::class, 'calendarEvents'])->name('calendar.events');
19+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Platform\Plugins\Calendar\Console\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use Platform\Plugins\Calendar\Models\Task;
7+
use Illuminate\Support\Facades\Mail;
8+
use Carbon\Carbon;
9+
10+
class SendTaskReminders extends Command
11+
{
12+
protected $signature = 'calendar:send-reminders';
13+
protected $description = 'Send reminder emails for tasks due tomorrow.';
14+
15+
public function handle()
16+
{
17+
$tomorrow = Carbon::tomorrow();
18+
$tasks = Task::where('reminder_sent', false)
19+
->whereDate('start_date', $tomorrow)
20+
->get();
21+
22+
foreach ($tasks as $task) {
23+
// Send email (implement your mail logic here)
24+
Mail::send('calendar::emails.reminder', ['task' => $task], function ($message) use ($task) {
25+
$message->to(config('mail.from.address'));
26+
$message->subject('Task Reminder: ' . $task->task_name);
27+
});
28+
$task->reminder_sent = true;
29+
$task->save();
30+
}
31+
32+
$this->info('Reminders sent for ' . $tasks->count() . ' tasks.');
33+
}
34+
}

0 commit comments

Comments
 (0)