Skip to content

Commit bf8ff4a

Browse files
committed
Initial commit
0 parents  commit bf8ff4a

File tree

128 files changed

+19555
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+19555
-0
lines changed

.editorconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_size = 4
7+
indent_style = space
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false
13+
14+
[*.{yml,yaml}]
15+
indent_size = 2
16+
17+
[docker-compose.yml]
18+
indent_size = 4

.env.example

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
APP_NAME=Laravel
2+
APP_ENV=local
3+
APP_KEY=
4+
APP_DEBUG=true
5+
APP_URL=http://localhost
6+
7+
APP_LOCALE=en
8+
APP_FALLBACK_LOCALE=en
9+
APP_FAKER_LOCALE=en_US
10+
11+
APP_MAINTENANCE_DRIVER=file
12+
# APP_MAINTENANCE_STORE=database
13+
14+
PHP_CLI_SERVER_WORKERS=4
15+
16+
BCRYPT_ROUNDS=12
17+
18+
LOG_CHANNEL=stack
19+
LOG_STACK=single
20+
LOG_DEPRECATIONS_CHANNEL=null
21+
LOG_LEVEL=debug
22+
23+
DB_CONNECTION=sqlite
24+
# DB_HOST=127.0.0.1
25+
# DB_PORT=3306
26+
# DB_DATABASE=laravel
27+
# DB_USERNAME=root
28+
# DB_PASSWORD=
29+
30+
SESSION_DRIVER=database
31+
SESSION_LIFETIME=120
32+
SESSION_ENCRYPT=false
33+
SESSION_PATH=/
34+
SESSION_DOMAIN=null
35+
36+
BROADCAST_CONNECTION=log
37+
FILESYSTEM_DISK=local
38+
QUEUE_CONNECTION=database
39+
40+
CACHE_STORE=database
41+
# CACHE_PREFIX=
42+
43+
MEMCACHED_HOST=127.0.0.1
44+
45+
REDIS_CLIENT=phpredis
46+
REDIS_HOST=127.0.0.1
47+
REDIS_PASSWORD=null
48+
REDIS_PORT=6379
49+
50+
MAIL_MAILER=log
51+
MAIL_SCHEME=null
52+
MAIL_HOST=127.0.0.1
53+
MAIL_PORT=2525
54+
MAIL_USERNAME=null
55+
MAIL_PASSWORD=null
56+
MAIL_FROM_ADDRESS="hello@example.com"
57+
MAIL_FROM_NAME="${APP_NAME}"
58+
59+
AWS_ACCESS_KEY_ID=
60+
AWS_SECRET_ACCESS_KEY=
61+
AWS_DEFAULT_REGION=us-east-1
62+
AWS_BUCKET=
63+
AWS_USE_PATH_STYLE_ENDPOINT=false
64+
65+
VITE_APP_NAME="${APP_NAME}"

.gitattributes

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
* text=auto eol=lf
2+
3+
*.blade.php diff=html
4+
*.css diff=css
5+
*.html diff=html
6+
*.md diff=markdown
7+
*.php diff=php
8+
9+
CHANGELOG.md export-ignore
10+
README.md export-ignore

.github/workflows/lint.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: linter
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
- main
8+
pull_request:
9+
branches:
10+
- develop
11+
- main
12+
13+
permissions:
14+
contents: write
15+
16+
jobs:
17+
quality:
18+
runs-on: ubuntu-latest
19+
environment: Testing
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Setup PHP
24+
uses: shivammathur/setup-php@v2
25+
with:
26+
php-version: '8.4'
27+
28+
- name: Add Flux Credentials Loaded From ENV
29+
run: composer config http-basic.composer.fluxui.dev "${{ secrets.FLUX_USERNAME }}" "${{ secrets.FLUX_LICENSE_KEY }}"
30+
31+
- name: Install Dependencies
32+
run: |
33+
composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
34+
npm install
35+
36+
- name: Run Pint
37+
run: vendor/bin/pint
38+
39+
# - name: Commit Changes
40+
# uses: stefanzweifel/git-auto-commit-action@v5
41+
# with:
42+
# commit_message: fix code style
43+
# commit_options: '--no-verify'
44+
# file_pattern: |
45+
# **/*
46+
# !.github/workflows/*

.github/workflows/tests.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: tests
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
- main
8+
pull_request:
9+
branches:
10+
- develop
11+
- main
12+
13+
jobs:
14+
ci:
15+
runs-on: ubuntu-latest
16+
environment: Testing
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Setup PHP
23+
uses: shivammathur/setup-php@v2
24+
with:
25+
php-version: 8.4
26+
tools: composer:v2
27+
coverage: xdebug
28+
29+
- name: Setup Node
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: '22'
33+
cache: 'npm'
34+
35+
- name: Install Node Dependencies
36+
run: npm i
37+
38+
- name: Add Flux Credentials Loaded From ENV
39+
run: composer config http-basic.composer.fluxui.dev "${{ secrets.FLUX_USERNAME }}" "${{ secrets.FLUX_LICENSE_KEY }}"
40+
41+
- name: Install Dependencies
42+
run: composer install --no-interaction --prefer-dist --optimize-autoloader
43+
44+
- name: Copy Environment File
45+
run: cp .env.example .env
46+
47+
- name: Generate Application Key
48+
run: php artisan key:generate
49+
50+
- name: Build Assets
51+
run: npm run build
52+
53+
- name: Run Tests
54+
run: ./vendor/bin/pest

.gitignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/.phpunit.cache
2+
/node_modules
3+
/public/build
4+
/public/hot
5+
/public/storage
6+
/storage/*.key
7+
/storage/pail
8+
/vendor
9+
/EMAIL_SETUP.md
10+
/NOTIFICATIONS.md
11+
.env
12+
.env.backup
13+
.env.production
14+
.phpactor.json
15+
.phpunit.result.cache
16+
Homestead.json
17+
Homestead.yaml
18+
npm-debug.log
19+
yarn-error.log
20+
/auth.json
21+
/.fleet
22+
/.idea
23+
/.nova
24+
/.vscode
25+
/.zed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\Task;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Support\Facades\Log;
8+
use Illuminate\Notifications\Messages\MailMessage;
9+
use Illuminate\Support\Facades\Notification;
10+
11+
class SendDueSoonTaskNotifications extends Command
12+
{
13+
/**
14+
* The name and signature of the console command.
15+
*
16+
* @var string
17+
*/
18+
protected $signature = 'tasks:send-due-soon-notifications {--days=3 : Number of days ahead to check}';
19+
20+
/**
21+
* The console command description.
22+
*
23+
* @var string
24+
*/
25+
protected $description = 'Send due soon task notifications to users';
26+
27+
/**
28+
* Execute the console command.
29+
*/
30+
public function handle()
31+
{
32+
$days = (int) $this->option('days');
33+
34+
// Get tasks due within the specified days that haven't been completed
35+
$dueSoonTasks = Task::with(['assignedTo', 'assignedBy'])
36+
->where('status', '!=', 'completed')
37+
->where('deadline', '>=', now())
38+
->where('deadline', '<=', now()->addDays($days))
39+
->get();
40+
41+
$this->info("Found {$dueSoonTasks->count()} tasks due within {$days} days.");
42+
43+
$notifiedCount = 0;
44+
$errorCount = 0;
45+
46+
foreach ($dueSoonTasks as $task) {
47+
try {
48+
// Send custom due soon notification
49+
$task->assignedTo->notify(new class($task) extends \Illuminate\Notifications\Notification {
50+
use \Illuminate\Bus\Queueable;
51+
use \Illuminate\Contracts\Queue\ShouldQueue;
52+
53+
public function __construct(public $task) {}
54+
55+
public function via($notifiable): array
56+
{
57+
return ['mail'];
58+
}
59+
60+
public function toMail($notifiable): MailMessage
61+
{
62+
$daysUntilDue = now()->diffInDays($this->task->deadline, false);
63+
$dueText = $daysUntilDue === 0 ? 'today' : "in {$daysUntilDue} day" . ($daysUntilDue > 1 ? 's' : '');
64+
65+
return (new MailMessage)
66+
->subject('📅 Task Due Soon: ' . $this->task->title)
67+
->greeting('Hello ' . $notifiable->name . '!')
68+
->line('📅 **Reminder: You have a task due soon!**')
69+
->line('**Task Title:** ' . $this->task->title)
70+
->line('**Description:** ' . ($this->task->description ?: 'No description provided'))
71+
->line('**Due:** ' . $this->task->deadline->format('F j, Y \a\t g:i A') . " ({$dueText})")
72+
->line('**Current Status:** ' . ucfirst(str_replace('_', ' ', $this->task->status)))
73+
->action('Update Task Status', url('/dashboard'))
74+
->line('Please review and update the task status as needed.');
75+
}
76+
});
77+
78+
$notifiedCount++;
79+
$this->line("✓ Notified {$task->assignedTo->name} about task due soon: {$task->title}");
80+
} catch (\Exception $e) {
81+
$errorCount++;
82+
Log::error("Failed to send due soon notification for task {$task->id}: " . $e->getMessage());
83+
$this->error("✗ Failed to notify {$task->assignedTo->name} about task: {$task->title}");
84+
}
85+
}
86+
87+
$this->info("Notification summary:");
88+
$this->info("- Successfully sent: {$notifiedCount}");
89+
$this->info("- Errors: {$errorCount}");
90+
91+
return 0;
92+
}
93+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\Task;
6+
use App\Notifications\TaskOverdueNotification;
7+
use Illuminate\Console\Command;
8+
use Illuminate\Support\Facades\Log;
9+
10+
class SendOverdueTaskNotifications extends Command
11+
{
12+
/**
13+
* The name and signature of the console command.
14+
*
15+
* @var string
16+
*/
17+
protected $signature = 'tasks:send-overdue-notifications {--days=1 : Number of days to wait before sending notification}';
18+
19+
/**
20+
* The console command description.
21+
*
22+
* @var string
23+
*/
24+
protected $description = 'Send overdue task notifications to users';
25+
26+
/**
27+
* Execute the console command.
28+
*/
29+
public function handle()
30+
{
31+
$days = (int) $this->option('days');
32+
33+
// Get overdue tasks that haven't been completed
34+
$overdueTasks = Task::with(['assignedTo', 'assignedBy'])
35+
->where('status', '!=', 'completed')
36+
->where('deadline', '<', now()->subDays($days))
37+
->get();
38+
39+
$this->info("Found {$overdueTasks->count()} overdue tasks to notify about.");
40+
41+
$notifiedCount = 0;
42+
$errorCount = 0;
43+
44+
foreach ($overdueTasks as $task) {
45+
try {
46+
// Send notification to the assigned user
47+
$task->assignedTo->notify(new TaskOverdueNotification($task));
48+
$notifiedCount++;
49+
50+
$this->line("✓ Notified {$task->assignedTo->name} about overdue task: {$task->title}");
51+
} catch (\Exception $e) {
52+
$errorCount++;
53+
Log::error("Failed to send overdue notification for task {$task->id}: " . $e->getMessage());
54+
$this->error("✗ Failed to notify {$task->assignedTo->name} about task: {$task->title}");
55+
}
56+
}
57+
58+
$this->info("Notification summary:");
59+
$this->info("- Successfully sent: {$notifiedCount}");
60+
$this->info("- Errors: {$errorCount}");
61+
62+
return 0;
63+
}
64+
}

0 commit comments

Comments
 (0)