This commit is contained in:
salam committed 2026-02-05 18:48:51 +01:00
1 parent b0a002c7c1
commit 23cf804865
23 files changed
+283 -123

No files matched your search

@@ -7,6 +7,7 @@ use App\Console\Commands\Services\Tasks\DBMapper;
use App\Console\Commands\Services\Tasks\GenerateAlarms; use App\Console\Commands\Services\Tasks\GenerateAlarms;
use App\Console\Commands\Services\Tasks\GenerateSetting; use App\Console\Commands\Services\Tasks\GenerateSetting;
use App\Console\Commands\Services\Tasks\MarketsList; use App\Console\Commands\Services\Tasks\MarketsList;
use App\Console\Commands\Services\Tasks\NotifyAlarms;
use App\Console\Commands\Services\Tasks\TxoddsFlags; use App\Console\Commands\Services\Tasks\TxoddsFlags;
class Services class Services
@@ -29,6 +30,9 @@ class Services
case 'Generate Alarms': case 'Generate Alarms':
GenerateAlarms::run(); GenerateAlarms::run();
break; break;
case 'Notify Alarms':
NotifyAlarms::run();
break;
} }
} }
@@ -10,6 +10,7 @@ use App\Models\Client;
use App\Models\ComparingBookmaker; use App\Models\ComparingBookmaker;
use App\Models\MultilineClient; use App\Models\MultilineClient;
use App\Models\MultilineSetting; use App\Models\MultilineSetting;
use App\Models\PersonalNotification;
use App\Models\Sport; use App\Models\Sport;
use App\Models\User; use App\Models\User;
use App\Utilities\Notice; use App\Utilities\Notice;
@@ -178,5 +179,37 @@ class GenerateSetting
} }
} }
/**************************************************
* 5) ALARM NOTIFICATION SETTINGS FOR USERS
**************************************************/
if ($debug) {
Notice::note('5) ALARM NOTIFICATION SETTINGS FOR USERS', 'p');
}
$users = User::with('client')->get();
foreach ($users as $user) {
if (in_array($user->id, [1, 2])) {
$sports = Sport::where('is_active', 1)->pluck('id')->toArray();
} else {
$sports = Client::find($user->client_id)->value('sport');
}
foreach ($sports as $sport_id) {
foreach ([2, 3] as $alarm_level_id) {
PersonalNotification::firstOrCreate(
['sport_id' => $sport_id, 'user_id' => $user->id, 'bookmaker_id' => $user->bookmaker_id, 'alarm_level_id' => $alarm_level_id],
['notify_by_system' => 0, 'notify_by_email' => 0]
);
if ($user->partner_bookmaker_id) {
PersonalNotification::firstOrCreate(
['sport_id' => $sport_id, 'user_id' => $user->id, 'bookmaker_id' => $user->partner_bookmaker_id, 'alarm_level_id' => $alarm_level_id],
['notify_by_system' => 0, 'notify_by_email' => 0]
);
}
}
}
}
} }
} }
@@ -0,0 +1,28 @@
<?php
namespace App\Console\Commands\Services\Tasks;
use App\Console\Commands\Nuh;
use App\Models\User;
use App\Utilities\Notice;
class NotifyAlarms
{
public static function run()
{
$debug = Nuh::$options['d'] ?? 0;
if ($debug) {
Notice::note('Notify Alarms', 'b');
}
/**
* USER
*/
$users = User::all();
foreach ($users as $user) {
dd($user);
}
}
}
@@ -61,7 +61,6 @@ class EventResource extends Resource
->with('event_bookmaker') ->with('event_bookmaker')
->with('event_user_star') ->with('event_user_star')
->with('event_user_note') ->with('event_user_note')
->with('event_user_notification')
->where('sport_id', auth()->user()->sport_id) ->where('sport_id', auth()->user()->sport_id)
->where('starttime', '>=', now()); ->where('starttime', '>=', now());
@@ -16,7 +16,6 @@ use App\Models\Country;
use App\Models\Event; use App\Models\Event;
use App\Models\EventBookmaker; use App\Models\EventBookmaker;
use App\Models\EventUserNote; use App\Models\EventUserNote;
use App\Models\EventUserNotification;
use App\Models\EventUserStar; use App\Models\EventUserStar;
use App\Models\Group; use App\Models\Group;
use App\Models\OddsTable; use App\Models\OddsTable;
@@ -27,11 +26,9 @@ use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction; use Filament\Actions\DeleteBulkAction;
use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Radio;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea; use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Components\Utilities\Get;
use Filament\Support\Enums\FontWeight; use Filament\Support\Enums\FontWeight;
use Filament\Support\Enums\VerticalAlignment; use Filament\Support\Enums\VerticalAlignment;
@@ -416,11 +413,6 @@ class EventsTable
function (Builder $query, $filter_notes) { function (Builder $query, $filter_notes) {
$query->whereHas('event_user_note'); $query->whereHas('event_user_note');
} }
)->when(
$data['filter_notification'],
function (Builder $query, $filter_notification) {
$query->whereHas('event_user_notification');
}
)->when( )->when(
$data['favorit_threshold'], $data['favorit_threshold'],
function (Builder $query, $favorit_threshold) { function (Builder $query, $favorit_threshold) {
@@ -664,77 +656,6 @@ class EventsTable
} }
}) })
->color(fn ($record) => $record->event_user_note->isEmpty() ? 'gray' : 'info'), ->color(fn ($record) => $record->event_user_note->isEmpty() ? 'gray' : 'info'),
Action::make('event_notification')
->modalWidth(Width::Large)
->modalDescription('Monitoring favorit and if condition is matchted the system will emit a notification')
->modalSubmitActionLabel('Save')
->extraModalFooterActions(fn (Action $action, $record) => $record->event_user_notification->isEmpty() ? [] : [$action->makeModalSubmitAction('Delete', arguments: ['delete' => true])->color('danger')])
->modalIcon('phosphor-bell')
->fillForm(data: function ($record) {
foreach ($record->event_user_notification as $value) {
if ($value->user_id == auth()->user()->id && $value->bookmaker_id == auth()->user()->bookmaker_id) {
return [
'event_user_notification_id' => $value->id,
'odds_table_id' => $value->odds_table_id,
'alarm_level_id' => $value->alarm_level_id,
'is_notified' => $value->is_notified,
'notify_by_email' => $value->notify_by_email,
];
}
}
return ['event_user_notification_id' => ''];
})
->schema([
Hidden::make('event_user_notification_id'),
Toggle::make('is_notified')->label('On/Off')
->onColor('gray')
->offColor('info'),
Radio::make('odds_table_id')
->label('Bettype')
->columns(3)
->required()
->options(fn ($record) => OddsTable::options_sport()),
Radio::make('alarm_level_id')
->label('Alarm level')
->columns(3)
->required()
->options([
'1' => 'Level 1',
'2' => 'Level 2',
'3' => 'Level 3',
]),
Toggle::make('notify_by_email')->label('Send also E-Mail')
// ->belowContent('Notify me also by e-mail')
->onColor('info')
->offColor('gray'),
])
->icon('phosphor-bell')
->iconButton()
->color(fn ($record) => $record?->event_user_notification->isEmpty() ? 'gray' : 'info')
->action(function ($record, array $data, $arguments = []) {
if ($arguments) {
EventUserNotification::where('id', $data['event_user_notification_id'])->delete();
} elseif ($data['event_user_notification_id']) {
EventUserNotification::where('id', $data['event_user_notification_id'])->update([
'odds_table_id' => $data['odds_table_id'],
'alarm_level_id' => $data['alarm_level_id'],
'notify_by_email' => $data['notify_by_email'],
'is_notified' => $data['is_notified'],
]);
} else {
EventUserNotification::updateOrCreate([
'event_id' => $record->id,
'bookmaker_id' => auth()->user()->bookmaker_id,
'user_id' => auth()->user()->id,
], [
'odds_table_id' => $data['odds_table_id'],
'alarm_level_id' => $data['alarm_level_id'],
'notify_by_email' => $data['notify_by_email'],
'is_notified' => $data['is_notified'],
]);
}
}),
ActionGroup::make([ ActionGroup::make([
DeleteAction::make()->visible(fn () => auth()->user()->hasRole('super_admin')), DeleteAction::make()->visible(fn () => auth()->user()->hasRole('super_admin')),
Action::make('txodds_odds') Action::make('txodds_odds')
@@ -78,6 +78,7 @@ class SupervisorsTable
'DB Mapper' => 'DB Mapper', 'DB Mapper' => 'DB Mapper',
'Generate Setting' => 'Generate Setting', 'Generate Setting' => 'Generate Setting',
'Generate Alarms' => 'Generate Alarms', 'Generate Alarms' => 'Generate Alarms',
'Notify Alarms' => 'Notify Alarms',
]; ];
case 9: case 9:
case 10: case 10:
@@ -0,0 +1,44 @@
<?php
namespace App\Livewire;
use App\Filament\Tables\Columns\BookmakerIcon;
use App\Models\PersonalNotification;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Contracts\HasSchemas;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Livewire\Component;
class PersonalNotificationTable extends Component implements HasActions, HasSchemas, HasTable
{
use InteractsWithActions;
use InteractsWithSchemas;
use InteractsWithTable;
public function table(Table $table): Table
{
return $table
->query(PersonalNotification::query()->with('bookmaker')->where('user_id', auth()->user()->id))
->columns([
IconColumn::make('sport.icon')
->label('')
->icon(fn ($record) => $record->sport->icon)
->tooltip(fn ($record) => $record->id),
TextColumn::make('sport.name'),
BookmakerIcon::make('bookmaker.icon')->label('Icon')->size('lg'),
]);
}
public function render(): View
{
return view('livewire.personal-notification-table');
}
}
+20 -4
View File
@@ -3,6 +3,7 @@
namespace App\Livewire; namespace App\Livewire;
use App\Mail\UserNotification; use App\Mail\UserNotification;
use App\Models\PersonalNotification;
use App\Models\User; use App\Models\User;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions; use Filament\Actions\Concerns\InteractsWithActions;
@@ -13,6 +14,7 @@ use Filament\Notifications\Notification;
use Filament\Schemas\Concerns\InteractsWithSchemas; use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Contracts\HasSchemas; use Filament\Schemas\Contracts\HasSchemas;
use Filament\Support\Enums\Width; use Filament\Support\Enums\Width;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable; use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable; use Filament\Tables\Contracts\HasTable;
@@ -27,6 +29,8 @@ class UserNotifications extends Component implements HasActions, HasSchemas, Has
use InteractsWithSchemas; use InteractsWithSchemas;
use InteractsWithTable; use InteractsWithTable;
protected Table $table2;
public function table(Table $table): Table public function table(Table $table): Table
{ {
return $table return $table
@@ -48,12 +52,14 @@ class UserNotifications extends Component implements HasActions, HasSchemas, Has
->modalIcon('phosphor-envelope-duotone') ->modalIcon('phosphor-envelope-duotone')
->schema([ ->schema([
Textarea::make('message') Textarea::make('message')
->required()
->rows(4), ->rows(4),
Toggle::make('notify_by_email')->label('Send also as email') Toggle::make('notify_by_email')->label('Send also as email')
// ->belowContent('Notify me also by e-mail') // ->belowContent('Notify me also by e-mail')
->onColor('info') ->onColor('info')
->offColor('gray'), ->offColor('gray'),
])->action(function (array $data, $record) { ])->action(function (array $data, $record) {
if ($data['notify_by_email']) { if ($data['notify_by_email']) {
Mail::to($record) Mail::to($record)
->send(new UserNotification($data['message'])); ->send(new UserNotification($data['message']));
@@ -69,13 +75,23 @@ class UserNotifications extends Component implements HasActions, HasSchemas, Has
->success() ->success()
->send(); ->send();
}), }),
])
->toolbarActions([
// ...
]); ]);
} }
public function table2(Table $table): Table
{
return $table
->query(PersonalNotification::query()->where('user_id', auth()->user()->id))
->columns([
IconColumn::make('sport.icon')
->label('')
->icon(fn ($record) => $record->sport->icon)
->tooltip(fn ($record) => $record->id)
->visibleFrom('lg'),
]);
}
public function render(): View public function render(): View
{ {
return view('livewire.user-notifications'); return view('livewire.user-notifications');
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class AlarmLevel extends Model
{
//
}
-5
View File
@@ -148,11 +148,6 @@ class Event extends Model
return $this->hasMany(EventUserNote::class, 'event_id', 'id'); return $this->hasMany(EventUserNote::class, 'event_id', 'id');
} }
public function event_user_notification()
{
return $this->hasMany(EventUserNotification::class, 'event_id', 'id');
}
public function event_bookmaker() public function event_bookmaker()
{ {
return $this->hasOne(EventBookmaker::class, 'event_id', 'id')->where('bookmaker_id', auth()->user()->bookmaker_id); return $this->hasOne(EventBookmaker::class, 'event_id', 'id')->where('bookmaker_id', auth()->user()->bookmaker_id);
@@ -4,31 +4,24 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class EventUserNotification extends Model class PersonalNotification extends Model
{ {
protected $fillable = [ protected $fillable = [
'event_id',
'bookmaker_id',
'user_id', 'user_id',
'odds_table_id', 'sport_id',
'bookmaker_id',
'alarm_level_id', 'alarm_level_id',
'notify_by_system',
'notify_by_email', 'notify_by_email',
'is_notified',
'deleted',
]; ];
public function user() public function sport()
{ {
return $this->belongsTo(User::class); return $this->belongsTo(Sport::class);
} }
public function bookmaker() public function bookmaker()
{ {
return $this->belongsTo(Bookmaker::class); return $this->belongsTo(Bookmaker::class);
} }
public function odds_table()
{
return $this->belongsTo(OddsTable::class);
}
} }
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PersonalNotificationSend extends Model
{
//
}
@@ -45,6 +45,7 @@ class AdminPanelProvider extends PanelProvider
->emailVerification() ->emailVerification()
->emailChangeVerification() ->emailChangeVerification()
->databaseNotifications() ->databaseNotifications()
->sidebarCollapsibleOnDesktop()
// ->databaseNotificationsPolling('15s') default is 30 // ->databaseNotificationsPolling('15s') default is 30
->profile(isSimple: false) ->profile(isSimple: false)
->default() ->default()
@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_notifications', function (Blueprint $table) {
$table->id();
$table->integer('user_id')->index()->references('id')->on('users');
$table->integer('sport_id')->index()->references('id')->on('sports');
$table->integer('bookmaker_id')->index()->references('id')->on('bookmakers');
$table->integer('alarm_level_id')->default(0);
$table->boolean('notify_by_system')->default(false);
$table->boolean('notify_by_email')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_notifications');
}
};
@@ -11,16 +11,12 @@ return new class extends Migration
*/ */
public function up(): void public function up(): void
{ {
Schema::create('event_user_notifications', function (Blueprint $table) { Schema::create('personal_notification_sends', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignId('event_id')->index()->constrained()->cascadeOnDelete()->references('id')->on('events'); $table->foreignId('event_id')->index()->constrained()->cascadeOnDelete()->references('id')->on('events');
$table->integer('bookmaker_id')->default(0);
$table->integer('user_id')->index()->references('id')->on('users'); $table->integer('user_id')->index()->references('id')->on('users');
$table->integer('odds_table_id')->index()->references('id')->on('odds_tables'); $table->integer('bookmaker_id')->index()->references('id')->on('bookmakers');
$table->integer('alarm_level_id')->default(0); $table->integer('alarm_level_id')->default(0);
$table->boolean('notify_by_email')->default(false);
$table->boolean('deleted')->default(false);
$table->boolean('is_notified')->default(false);
$table->timestamps(); $table->timestamps();
}); });
} }
@@ -30,6 +26,6 @@ return new class extends Migration
*/ */
public function down(): void public function down(): void
{ {
Schema::dropIfExists('event_user_notifications'); Schema::dropIfExists('personal_notification_sends');
} }
}; };
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('alarm_levels', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('color');
$table->decimal('default_threshold', 3, 2)->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('alarm_levels');
}
};
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class AlarmLevelSeeder extends Seeder
{
public function run(): void
{
/**
* Clients
*/
$sql = "INSERT INTO `alarm_levels` (`id`, `name`, `color`, `default_threshold`, `created_at`, `updated_at`)
VALUES
(1, 'LEVEL 1', 'info', 0.01, NULL, NULL),
(2, 'LEVEL 2', 'warning', 0.20, NULL, NULL),
(3, 'LEVEL 3', 'danger', 0.30, NULL, NULL);
";
DB::unprepared($sql);
}
}
+1
View File
@@ -24,6 +24,7 @@ class DatabaseSeeder extends Seeder
TxoddsMarketsSeeder::class, TxoddsMarketsSeeder::class,
CountryItalianSeeder::class, CountryItalianSeeder::class,
OddsTableSeeder::class, OddsTableSeeder::class,
AlarmLevelSeeder::class,
]); ]);
} }
} }
+2 -2
View File
@@ -86,11 +86,11 @@ button[wire\:click="resetTableFiltersForm"] {
/* Styling Radio Lable */ /* Styling Radio Lable */
.fi-fo-radio { .fi-fo-radio {
@apply !grid grid-cols-2 gap-y-3 my-5 @apply !grid grid-cols-2 gap-y-4 my-2
} }
.fi-fo-radio-label { .fi-fo-radio-label {
@apply p-2 border border-gray-700 rounded-md cursor-pointer has-checked:bg-blue-50 has-checked:text-blue-900 has-checked:ring-blue-200 dark:has-checked:bg-blue-950 dark:has-checked:text-blue-200 dark:has-checked:ring-blue-900 @apply p-3 border border-gray-200 shadow rounded-md cursor-pointer has-checked:bg-blue-50 has-checked:text-blue-900 dark:has-checked:bg-blue-950 dark:has-checked:text-blue-200
} }
@@ -1,4 +1,4 @@
<div class="flex flex-1 gap-3 items-center my-5 drop-shadow "> <div class="flex flex-1 gap-3 items-center my-5">
@switch(auth()->user()->sport_id) @switch(auth()->user()->sport_id)
@case(1) @case(1)
<x-icon-soccerball class="h-6 text-blue-600" /> <x-icon-soccerball class="h-6 text-blue-600" />
@@ -0,0 +1,3 @@
<div>
{{ $this->table }}
</div>
@@ -60,20 +60,39 @@
</x-filament::dropdown.list> </x-filament::dropdown.list>
</x-filament::dropdown> </x-filament::dropdown>
{{-- Notifications --}} {{-- Notifications --}}
<x-filament::modal slide-over width="2xl" icon="phosphor-envelope-duotone" :close-by-clicking-away="true" :close-by-escaping="true" <x-filament::modal slide-over width="2xl" icon="phosphor-warning-duotone" :close-by-clicking-away="true" :close-by-escaping="true"
:close-button="true"> :close-button="true">
<x-slot name="trigger"> <x-slot name="trigger">
<x-filament::button outlined icon="phosphor-envelope-duotone" class="my-auto" color="gray" <x-filament::button outlined icon="phosphor-warning-duotone" class="my-auto" color="gray"
tooltip="Notifications"> tooltip="Notifications Settings">
</x-filament::button> </x-filament::button>
</x-slot> </x-slot>
<x-slot name="heading"> <x-slot name="heading">
Notifications Notifications Settings
</x-slot>
@livewire('personal-notification-table')
</x-filament::modal>
{{-- Send Message --}}
<x-filament::modal slide-over width="2xl" icon="phosphor-paper-plane-tilt-duotone" :close-by-clicking-away="true" :close-by-escaping="true"
:close-button="true">
<x-slot name="trigger">
<x-filament::button outlined icon="phosphor-paper-plane-tilt-duotone" class="my-auto" color="gray"
tooltip="Send Message">
</x-filament::button>
</x-slot>
<x-slot name="heading">
Send Message
</x-slot> </x-slot>
@livewire('user-notifications') @livewire('user-notifications')
</x-filament::modal> </x-filament::modal>
{{-- Event Mapper --}} {{-- Event Mapper --}}
@@ -86,7 +105,7 @@
</x-slot> </x-slot>
<x-slot name="heading"> <x-slot name="heading">
<div class="flex justify-between items-center w-screen pr-24"> <div class="flex justify-end items-center gap-20">
<x-sport-header> <x-sport-header>
Event Mapper {{ auth()->user()->sport->name }} Event Mapper {{ auth()->user()->sport->name }}
</x-sport-header> </x-sport-header>
@@ -198,12 +217,12 @@
:close-button="true"> :close-button="true">
<x-slot name="trigger"> <x-slot name="trigger">
<x-filament::button outlined icon="phosphor-siren-duotone" color="gray" class="my-auto" <x-filament::button outlined icon="phosphor-siren-duotone" color="gray" class="my-auto"
tooltip="Alarm Settings"> tooltip="Alarm Level Settings">
</x-filament::button> </x-filament::button>
</x-slot> </x-slot>
<x-slot name="heading"> <x-slot name="heading">
Alarm Settings Alarm Level Settings
</x-slot> </x-slot>
@livewire('alarm-bookmaker') @livewire('alarm-bookmaker')
+3 -3
View File
@@ -99,6 +99,7 @@ img {
.header { .header {
padding: 25px 0; padding: 25px 0;
text-align: center;
} }
.header div { .header div {
@@ -111,10 +112,9 @@ img {
/* Logo */ /* Logo */
.logo { .logo {
height: 35px; height: 40px;
margin-top: 15px; margin-top: 15px;
margin-bottom: 10px; max-height: 40px;
max-height: 35px;
width: auto; width: auto;
} }