created admin panel with some of its content

This commit is contained in:
ghassan committed 2026-01-26 00:50:43 +03:00
1 parent 2ee4b76599
commit b16351c416
52 files changed
+5690 -203

No files matched your search

+72
View File
@@ -0,0 +1,72 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class ClubActivity extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_activities';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'name',
'duration_minutes',
'frequency_per_week',
'facility_id',
'schedule',
'description',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'duration_minutes' => 'integer',
'frequency_per_week' => 'integer',
'schedule' => 'array',
];
/**
* Get the club that owns the activity.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the facility where the activity takes place.
*/
public function facility(): BelongsTo
{
return $this->belongsTo(ClubFacility::class, 'facility_id');
}
/**
* Get the packages that include this activity.
*/
public function packages(): BelongsToMany
{
return $this->belongsToMany(ClubPackage::class, 'club_package_activities', 'activity_id', 'package_id')
->withPivot('instructor_id')
->withTimestamps();
}
}
+104
View File
@@ -0,0 +1,104 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Support\Facades\Crypt;
class ClubBankAccount extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_bank_accounts';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'bank_name',
'account_name',
'account_number',
'iban',
'swift_code',
'is_primary',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'is_primary' => 'boolean',
];
/**
* Get the club that owns the bank account.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Encrypt and decrypt account_number.
*/
protected function accountNumber(): Attribute
{
return Attribute::make(
get: fn ($value) => $value ? Crypt::decryptString($value) : null,
set: fn ($value) => $value ? Crypt::encryptString($value) : null,
);
}
/**
* Encrypt and decrypt iban.
*/
protected function iban(): Attribute
{
return Attribute::make(
get: fn ($value) => $value ? Crypt::decryptString($value) : null,
set: fn ($value) => $value ? Crypt::encryptString($value) : null,
);
}
/**
* Encrypt and decrypt swift_code.
*/
protected function swiftCode(): Attribute
{
return Attribute::make(
get: fn ($value) => $value ? Crypt::decryptString($value) : null,
set: fn ($value) => $value ? Crypt::encryptString($value) : null,
);
}
/**
* Get masked account number for display.
*/
public function getMaskedAccountNumber(): string
{
$accountNumber = $this->account_number;
if (!$accountNumber) {
return 'N/A';
}
$length = strlen($accountNumber);
if ($length <= 4) {
return str_repeat('*', $length);
}
return str_repeat('*', $length - 4) . substr($accountNumber, -4);
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class ClubFacility extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_facilities';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'name',
'photo',
'address',
'gps_lat',
'gps_long',
'is_available',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'gps_lat' => 'decimal:7',
'gps_long' => 'decimal:7',
'is_available' => 'boolean',
];
/**
* Get the club that owns the facility.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the activities for the facility.
*/
public function activities(): HasMany
{
return $this->hasMany(ClubActivity::class, 'facility_id');
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ClubGalleryImage extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_gallery_images';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'image_path',
'caption',
'uploaded_by',
'display_order',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'display_order' => 'integer',
];
/**
* Get the club that owns the image.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the user who uploaded the image.
*/
public function uploader(): BelongsTo
{
return $this->belongsTo(User::class, 'uploaded_by');
}
}
+71
View File
@@ -0,0 +1,71 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class ClubInstructor extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_instructors';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'user_id',
'role',
'experience_years',
'rating',
'skills',
'bio',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'experience_years' => 'integer',
'rating' => 'decimal:2',
'skills' => 'array',
];
/**
* Get the club that owns the instructor.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the user associated with the instructor.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the packages that include this instructor.
*/
public function packages(): BelongsToMany
{
return $this->belongsToMany(ClubPackage::class, 'club_package_activities', 'instructor_id', 'package_id')
->withTimestamps();
}
}
+112
View File
@@ -0,0 +1,112 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Carbon\Carbon;
class ClubMemberSubscription extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_member_subscriptions';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'user_id',
'package_id',
'start_date',
'end_date',
'status',
'payment_status',
'amount_paid',
'amount_due',
'notes',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'start_date' => 'date',
'end_date' => 'date',
'amount_paid' => 'decimal:2',
'amount_due' => 'decimal:2',
];
/**
* Get the club that owns the subscription.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the member associated with the subscription.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the package associated with the subscription.
*/
public function package(): BelongsTo
{
return $this->belongsTo(ClubPackage::class, 'package_id');
}
/**
* Get the transactions for the subscription.
*/
public function transactions(): HasMany
{
return $this->hasMany(ClubTransaction::class, 'subscription_id');
}
/**
* Check if subscription is expiring soon (within 3 days).
*/
public function isExpiringSoon(): bool
{
if ($this->status !== 'active') {
return false;
}
$daysUntilExpiry = Carbon::now()->diffInDays($this->end_date, false);
return $daysUntilExpiry >= 0 && $daysUntilExpiry <= 3;
}
/**
* Check if subscription is expired.
*/
public function isExpired(): bool
{
return $this->end_date < Carbon::now();
}
/**
* Get days until expiry.
*/
public function daysUntilExpiry(): int
{
return Carbon::now()->diffInDays($this->end_date, false);
}
}
+95
View File
@@ -0,0 +1,95 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ClubMessage extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_messages';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'sender_id',
'recipient_id',
'subject',
'message',
'is_read',
'read_at',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'is_read' => 'boolean',
'read_at' => 'datetime',
];
/**
* Get the club that owns the message.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the sender of the message.
*/
public function sender(): BelongsTo
{
return $this->belongsTo(User::class, 'sender_id');
}
/**
* Get the recipient of the message.
*/
public function recipient(): BelongsTo
{
return $this->belongsTo(User::class, 'recipient_id');
}
/**
* Mark message as read.
*/
public function markAsRead(): void
{
$this->update([
'is_read' => true,
'read_at' => now(),
]);
}
/**
* Scope a query to only include unread messages.
*/
public function scopeUnread($query)
{
return $query->where('is_read', false);
}
/**
* Scope a query to only include read messages.
*/
public function scopeRead($query)
{
return $query->where('is_read', true);
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
class ClubPackage extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_packages';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'name',
'cover_image',
'type',
'age_min',
'age_max',
'gender',
'price',
'duration_months',
'session_count',
'description',
'is_active',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'age_min' => 'integer',
'age_max' => 'integer',
'price' => 'decimal:2',
'duration_months' => 'integer',
'session_count' => 'integer',
'is_active' => 'boolean',
];
/**
* Get the club that owns the package.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the activities included in the package.
*/
public function activities(): BelongsToMany
{
return $this->belongsToMany(ClubActivity::class, 'club_package_activities', 'package_id', 'activity_id')
->withPivot('instructor_id')
->withTimestamps();
}
/**
* Get the subscriptions for the package.
*/
public function subscriptions(): HasMany
{
return $this->hasMany(ClubMemberSubscription::class, 'package_id');
}
/**
* Get active subscriptions for the package.
*/
public function activeSubscriptions(): HasMany
{
return $this->hasMany(ClubMemberSubscription::class, 'package_id')
->where('status', 'active');
}
}
+74
View File
@@ -0,0 +1,74 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ClubReview extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_reviews';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'user_id',
'rating',
'comment',
'is_approved',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'rating' => 'integer',
'is_approved' => 'boolean',
];
/**
* Get the club that owns the review.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the user who wrote the review.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Scope a query to only include approved reviews.
*/
public function scopeApproved($query)
{
return $query->where('is_approved', true);
}
/**
* Scope a query to only include pending reviews.
*/
public function scopePending($query)
{
return $query->where('is_approved', false);
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ClubSocialLink extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_social_links';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'platform',
'url',
'icon',
'display_order',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'display_order' => 'integer',
];
/**
* Get the club that owns the social link.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
}
+95
View File
@@ -0,0 +1,95 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ClubTransaction extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'club_transactions';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'tenant_id',
'user_id',
'type',
'category',
'amount',
'payment_method',
'description',
'transaction_date',
'reference_number',
'subscription_id',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'amount' => 'decimal:2',
'transaction_date' => 'date',
];
/**
* Get the club that owns the transaction.
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* Get the user associated with the transaction.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the subscription associated with the transaction.
*/
public function subscription(): BelongsTo
{
return $this->belongsTo(ClubMemberSubscription::class, 'subscription_id');
}
/**
* Scope a query to only include income transactions.
*/
public function scopeIncome($query)
{
return $query->where('type', 'income');
}
/**
* Scope a query to only include expense transactions.
*/
public function scopeExpense($query)
{
return $query->where('type', 'expense');
}
/**
* Scope a query to only include refund transactions.
*/
public function scopeRefund($query)
{
return $query->where('type', 'refund');
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Permission extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'slug',
'description',
];
/**
* Get the roles for the permission.
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class, 'role_permission')
->withTimestamps();
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Role extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'slug',
'description',
];
/**
* Get the permissions for the role.
*/
public function permissions(): BelongsToMany
{
return $this->belongsToMany(Permission::class, 'role_permission')
->withTimestamps();
}
/**
* Get the users for the role.
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class, 'user_roles')
->withPivot('tenant_id')
->withTimestamps();
}
/**
* Check if role has a specific permission.
*/
public function hasPermission(string $permissionSlug): bool
{
return $this->permissions()->where('slug', $permissionSlug)->exists();
}
}
+143 -1
View File
@@ -7,10 +7,11 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Tenant extends Model
{
use HasFactory;
use HasFactory, SoftDeletes;
/**
* The attributes that are mass assignable.
@@ -22,8 +23,25 @@ class Tenant extends Model
'club_name',
'slug',
'logo',
'slogan',
'description',
'enrollment_fee',
'commercial_reg_number',
'vat_reg_number',
'vat_percentage',
'email',
'phone',
'currency',
'timezone',
'country',
'address',
'favicon',
'cover_image',
'owner_name',
'owner_email',
'gps_lat',
'gps_long',
'settings',
];
/**
@@ -34,6 +52,10 @@ class Tenant extends Model
protected $casts = [
'gps_lat' => 'decimal:7',
'gps_long' => 'decimal:7',
'enrollment_fee' => 'decimal:2',
'vat_percentage' => 'decimal:2',
'phone' => 'array',
'settings' => 'array',
];
/**
@@ -61,4 +83,124 @@ class Tenant extends Model
{
return $this->hasMany(Invoice::class);
}
/**
* Get the facilities for the club.
*/
public function facilities(): HasMany
{
return $this->hasMany(ClubFacility::class);
}
/**
* Get the instructors for the club.
*/
public function instructors(): HasMany
{
return $this->hasMany(ClubInstructor::class);
}
/**
* Get the activities for the club.
*/
public function activities(): HasMany
{
return $this->hasMany(ClubActivity::class);
}
/**
* Get the packages for the club.
*/
public function packages(): HasMany
{
return $this->hasMany(ClubPackage::class);
}
/**
* Get the subscriptions for the club.
*/
public function subscriptions(): HasMany
{
return $this->hasMany(ClubMemberSubscription::class);
}
/**
* Get the transactions for the club.
*/
public function transactions(): HasMany
{
return $this->hasMany(ClubTransaction::class);
}
/**
* Get the gallery images for the club.
*/
public function galleryImages(): HasMany
{
return $this->hasMany(ClubGalleryImage::class);
}
/**
* Get the social links for the club.
*/
public function socialLinks(): HasMany
{
return $this->hasMany(ClubSocialLink::class);
}
/**
* Get the bank accounts for the club.
*/
public function bankAccounts(): HasMany
{
return $this->hasMany(ClubBankAccount::class);
}
/**
* Get the messages for the club.
*/
public function messages(): HasMany
{
return $this->hasMany(ClubMessage::class);
}
/**
* Get the reviews for the club.
*/
public function reviews(): HasMany
{
return $this->hasMany(ClubReview::class);
}
/**
* Get approved reviews for the club.
*/
public function approvedReviews(): HasMany
{
return $this->hasMany(ClubReview::class)->where('is_approved', true);
}
/**
* Get the average rating for the club.
*/
public function getAverageRatingAttribute(): float
{
return $this->approvedReviews()->avg('rating') ?? 0;
}
/**
* Get active members count.
*/
public function getActiveMembersCountAttribute(): int
{
return $this->subscriptions()->where('status', 'active')->distinct('user_id')->count('user_id');
}
/**
* Get the club URL.
*/
public function getUrlAttribute(): string
{
return url("/club/{$this->slug}");
}
}
+148
View File
@@ -258,6 +258,154 @@ class User extends Authenticatable
return $this->hasMany(ClubAffiliation::class, 'member_id');
}
/**
* Get the roles for the user.
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class, 'user_roles')
->withPivot('tenant_id')
->withTimestamps();
}
/**
* Get the subscriptions for the user.
*/
public function subscriptions(): HasMany
{
return $this->hasMany(ClubMemberSubscription::class);
}
/**
* Get the transactions for the user.
*/
public function transactions(): HasMany
{
return $this->hasMany(ClubTransaction::class);
}
/**
* Get the sent messages for the user.
*/
public function sentMessages(): HasMany
{
return $this->hasMany(ClubMessage::class, 'sender_id');
}
/**
* Get the received messages for the user.
*/
public function receivedMessages(): HasMany
{
return $this->hasMany(ClubMessage::class, 'recipient_id');
}
/**
* Get the reviews written by the user.
*/
public function reviews(): HasMany
{
return $this->hasMany(ClubReview::class);
}
/**
* Check if user has a specific role.
*/
public function hasRole(string $roleSlug, ?int $tenantId = null): bool
{
$query = $this->roles()->where('slug', $roleSlug);
if ($tenantId !== null) {
$query->wherePivot('tenant_id', $tenantId);
}
return $query->exists();
}
/**
* Check if user has any of the given roles.
*/
public function hasAnyRole(array $roleSlugs, ?int $tenantId = null): bool
{
$query = $this->roles()->whereIn('slug', $roleSlugs);
if ($tenantId !== null) {
$query->wherePivot('tenant_id', $tenantId);
}
return $query->exists();
}
/**
* Check if user has a specific permission.
*/
public function hasPermission(string $permissionSlug, ?int $tenantId = null): bool
{
$roles = $tenantId !== null
? $this->roles()->wherePivot('tenant_id', $tenantId)->get()
: $this->roles;
foreach ($roles as $role) {
if ($role->hasPermission($permissionSlug)) {
return true;
}
}
return false;
}
/**
* Check if user is super admin.
*/
public function isSuperAdmin(): bool
{
return $this->hasRole('super-admin');
}
/**
* Check if user is club admin for a specific club.
*/
public function isClubAdmin(?int $tenantId = null): bool
{
return $this->hasRole('club-admin', $tenantId);
}
/**
* Check if user is instructor for a specific club.
*/
public function isInstructor(?int $tenantId = null): bool
{
return $this->hasRole('instructor', $tenantId);
}
/**
* Assign a role to the user.
*/
public function assignRole(string $roleSlug, ?int $tenantId = null): void
{
$role = Role::where('slug', $roleSlug)->firstOrFail();
$this->roles()->attach($role->id, ['tenant_id' => $tenantId]);
}
/**
* Remove a role from the user.
*/
public function removeRole(string $roleSlug, ?int $tenantId = null): void
{
$role = Role::where('slug', $roleSlug)->first();
if (!$role) {
return;
}
if ($tenantId !== null) {
$this->roles()->wherePivot('tenant_id', $tenantId)->detach($role->id);
} else {
$this->roles()->detach($role->id);
}
}
/**
* Send the email verification notification.
* Override to prevent sending the default Laravel notification.