Compare commits
27 Commits
feature/ad
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2132f8c02 | ||
|
|
44b13a5ebf | ||
|
|
964d7a8936 | ||
|
|
12726c93b5 | ||
|
|
82d61e757f | ||
|
|
59b74a6905 | ||
|
|
a853b58f48 | ||
|
|
587893511c | ||
|
|
976ea01c89 | ||
|
|
2f566cc4d8 | ||
|
|
0d0818baf3 | ||
|
|
82715973dc | ||
|
|
5cae04884a | ||
|
|
a06fac4fef | ||
|
|
aa7e2f245f | ||
|
|
2fecd52d7e | ||
|
|
d7c06c38a6 | ||
|
|
1edfd7b9d4 | ||
|
|
aa8ad6b84b | ||
|
|
d03aa31f30 | ||
|
|
0b631f6049 | ||
|
|
039f8f5568 | ||
|
|
38d429e5d5 | ||
|
|
450c8b4dce | ||
|
|
a8be44553e | ||
|
|
2590ebc0ab | ||
|
|
298d73791f |
25
.env.example
@ -63,3 +63,28 @@ AWS_BUCKET=
|
|||||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
TWILIO_SID=
|
||||||
|
TWILIO_AUTH_TOKEN=
|
||||||
|
TWILIO_NUMBER=
|
||||||
|
|
||||||
|
# OTP valid time in minutes
|
||||||
|
OTP_LIFESPAN=10
|
||||||
|
|
||||||
|
VAPID_PUBLIC_KEY=
|
||||||
|
VAPID_PRIVATE_KEY=
|
||||||
|
|
||||||
|
# Same as the VAPID_PUBLIC_KEY
|
||||||
|
VITE_VAPID_PUBLIC_KEY="${VAPID_PUBLIC_KEY}"
|
||||||
|
|
||||||
|
REVERB_APP_ID=
|
||||||
|
REVERB_APP_KEY=
|
||||||
|
REVERB_APP_SECRET=
|
||||||
|
REVERB_HOST=
|
||||||
|
REVERB_PORT=
|
||||||
|
REVERB_SCHEME=
|
||||||
|
|
||||||
|
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
||||||
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
||||||
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
||||||
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
||||||
|
|||||||
2371
.phpstorm.meta.php
Normal file
11
README.md
@ -79,11 +79,22 @@ ## ⚙️ Installation
|
|||||||
```bash
|
```bash
|
||||||
git clone https://git.sentientgeeks.us/joydip.manna/dealhub.git
|
git clone https://git.sentientgeeks.us/joydip.manna/dealhub.git
|
||||||
cd dealhub
|
cd dealhub
|
||||||
|
# Install dependencies
|
||||||
composer install
|
composer install
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
|
# Set VAPID for webpush
|
||||||
|
php artisan webpush:vapid
|
||||||
|
|
||||||
|
# Install Reverb
|
||||||
|
php artisan install:broadcasting
|
||||||
|
|
||||||
npm run dev
|
npm run dev
|
||||||
php artisan migrate
|
php artisan migrate
|
||||||
php artisan serve
|
php artisan serve
|
||||||
|
|
||||||
|
# Start Reverb Server ( Another terminal )
|
||||||
|
php artisan reverb:start
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
4
TODO.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- [ ] Live Support.
|
||||||
|
- [ ] Add an Audit Log table to save all actions.
|
||||||
|
- [ ] Link foreign keys properly with related tables in the database.
|
||||||
|
- [ ] Add debouncing to the search feature and create proper database indexes to improve search performance.
|
||||||
28340
_ide_helper.php
Normal file
31
app/Actions/CreateOrGetInboxAction.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Models\Inbox;
|
||||||
|
use App\Models\User;
|
||||||
|
use DB;
|
||||||
|
|
||||||
|
final readonly class CreateOrGetInboxAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(User $recipient, User $sender): Inbox
|
||||||
|
{
|
||||||
|
$existingInbox = Inbox::whereHas('users', fn ($q) => $q->where('users.id', $sender->id))
|
||||||
|
->whereHas('users', fn ($q) => $q->where('users.id', $recipient->id))
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($existingInbox) {
|
||||||
|
return $existingInbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DB::transaction(function () use ($sender, $recipient) {
|
||||||
|
$inbox = Inbox::create();
|
||||||
|
$inbox->users()->attach([$sender->id, $recipient->id]);
|
||||||
|
|
||||||
|
return $inbox;
|
||||||
|
}, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Actions/PasswordReset/ResendOTPAction.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\PasswordReset;
|
||||||
|
|
||||||
|
use App\Exceptions\UserNotFoundException;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\OTPService;
|
||||||
|
|
||||||
|
final readonly class ResendOTPAction
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private OTPService $otpService,
|
||||||
|
private SendOTPToUserAction $otpToUserAction
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(): void
|
||||||
|
{
|
||||||
|
$user = \Session::get('otp_user_id') ? User::find(\Session::get('otp_user_id')) : null;
|
||||||
|
throw_if(! $user, new UserNotFoundException('User not found'));
|
||||||
|
|
||||||
|
$otp = $this->otpService->generate($user);
|
||||||
|
|
||||||
|
$this->otpToUserAction->execute(['user' => $user, 'otp' => $otp]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Actions/PasswordReset/SendOTPAction.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\PasswordReset;
|
||||||
|
|
||||||
|
use App\Exceptions\UserNotFoundException;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\OTPService;
|
||||||
|
|
||||||
|
final readonly class SendOTPAction
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private OTPService $otpService,
|
||||||
|
private SendOTPToUserAction $otpToUserAction
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(array $data): void
|
||||||
|
{
|
||||||
|
$user = User::where('email', $data['email'])->first();
|
||||||
|
throw_if(! $user, new UserNotFoundException('User not found'));
|
||||||
|
|
||||||
|
\Session::put('otp_user_id', $user->id);
|
||||||
|
$otp = $this->otpService->generate($user);
|
||||||
|
|
||||||
|
$this->otpToUserAction->execute(['user' => $user, 'otp' => $otp]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Actions/PasswordReset/SendOTPToUserAction.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\PasswordReset;
|
||||||
|
|
||||||
|
use App\Actions\SendPasswordResetMailAction;
|
||||||
|
use App\Services\TwilioService;
|
||||||
|
use Twilio\Exceptions\TwilioException;
|
||||||
|
|
||||||
|
final readonly class SendOTPToUserAction
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private SendPasswordResetMailAction $mailAction,
|
||||||
|
private TwilioService $twilioService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $data
|
||||||
|
*
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(array $data): void
|
||||||
|
{
|
||||||
|
['user' => $user,'otp' => $otp] = $data;
|
||||||
|
|
||||||
|
$this->mailAction->execute($user->email, $otp);
|
||||||
|
|
||||||
|
if ($user?->type->phone !== null) {
|
||||||
|
try {
|
||||||
|
$this->twilioService->sendSms($user->type->phone, "Your OTP is $otp");
|
||||||
|
} catch (TwilioException $e) {
|
||||||
|
\Log::error('SMS send failed', [$e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
app/Actions/PasswordReset/VerifyOTPAction.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\PasswordReset;
|
||||||
|
|
||||||
|
use App\Exceptions\UserNotFoundException;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\OTPService;
|
||||||
|
|
||||||
|
final readonly class VerifyOTPAction
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private OTPService $otpService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(array $data): bool
|
||||||
|
{
|
||||||
|
$user = \Session::get('otp_user_id') ? User::find(\Session::get('otp_user_id')) : null;
|
||||||
|
throw_if(! $user, new UserNotFoundException('User not found'));
|
||||||
|
|
||||||
|
return $this->otpService->verify($user, $data['otp']);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
app/Actions/RecordUserPageVisitAction.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Models\PageVisit;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
final readonly class RecordUserPageVisitAction
|
||||||
|
{
|
||||||
|
public function execute(?User $user, string $page): void
|
||||||
|
{
|
||||||
|
PageVisit::create(['user_id' => $user?->id, 'page' => $page, 'user_type' => $user?->role ?? null, 'created_at' => now()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/Actions/SendDealCreatedNotificationCustomerAction.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Models\Broker;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use App\Models\Deal;
|
||||||
|
use App\Notifications\NewDealNotification;
|
||||||
|
|
||||||
|
final readonly class SendDealCreatedNotificationCustomerAction
|
||||||
|
{
|
||||||
|
public function execute(Deal $deal): void
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Broker $broker
|
||||||
|
*/
|
||||||
|
$broker = $deal->broker->type;
|
||||||
|
$followers = $broker->followers()->with('user')->get();
|
||||||
|
$followers->map(function (Customer $follower) use ($deal) {
|
||||||
|
$user = $follower->user;
|
||||||
|
|
||||||
|
\Log::info("Sending notification to {$follower->user->name}", [$deal, $follower->user]);
|
||||||
|
|
||||||
|
$user->notifyNow(new NewDealNotification($deal));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
45
app/Actions/SendMessageAction.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Events\MessageSent;
|
||||||
|
use App\Exceptions\MessageNotSendException;
|
||||||
|
use App\Models\User;
|
||||||
|
use DB;
|
||||||
|
|
||||||
|
final readonly class SendMessageAction
|
||||||
|
{
|
||||||
|
public function __construct(private CreateOrGetInboxAction $inboxAction) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(User $sender, User $recipient, array $data): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
// find the inbox between the two users
|
||||||
|
DB::beginTransaction();
|
||||||
|
$inbox = $this->inboxAction->execute($recipient, $sender);
|
||||||
|
|
||||||
|
// update the inbox with the last message and last user as current user
|
||||||
|
$inbox->last_message = $data['message'];
|
||||||
|
$inbox->last_user_id = $sender->id;
|
||||||
|
$inbox->save();
|
||||||
|
|
||||||
|
// create a new message in the inbox
|
||||||
|
$message = $inbox->messages()->create([
|
||||||
|
'message' => $data['message'],
|
||||||
|
'user_id' => $sender->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Send the message to all other users in the inbox
|
||||||
|
broadcast(new MessageSent($message))->toOthers();
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw new MessageNotSendException('Message not sent.', previous: $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
app/Actions/SendPasswordResetMailAction.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Mail\PasswordResetMail;
|
||||||
|
|
||||||
|
final readonly class SendPasswordResetMailAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function execute(string $email, string $otp): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$message = \Mail::to($email)->send(new PasswordResetMail($otp));
|
||||||
|
\Log::info('Mail sent successfully', ['message' => $message]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
\Log::info('Mail send failed', ['message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Events/MessageSent.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events;
|
||||||
|
|
||||||
|
use App\Models\Message;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class MessageSent implements ShouldBroadcastNow
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*/
|
||||||
|
public function __construct(public Message $message)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the channels the event should broadcast on.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||||
|
*/
|
||||||
|
public function broadcastOn(): array
|
||||||
|
{
|
||||||
|
$users = $this->message->inbox->users->pluck('id')->toArray();
|
||||||
|
sort($users);
|
||||||
|
|
||||||
|
return [
|
||||||
|
new PrivateChannel("chat.{$users[0]}.{$users[1]}"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Exceptions/MessageNotSendException.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class MessageNotSendException extends Exception {}
|
||||||
7
app/Exceptions/UserNotFoundException.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class UserNotFoundException extends Exception {}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Actions\SendDealCreatedNotificationCustomerAction;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Deal;
|
use App\Models\Deal;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -11,16 +12,18 @@ class DealController extends Controller
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('dashboards.admin.deals.index')
|
return view('dashboards.admin.deals.index')
|
||||||
->with('deals', $this->deals());
|
->with('pendingDeals', $this->pendingDeals())
|
||||||
|
->with('activeDeals', $this->activeDeals());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function approve(Deal $deal)
|
public function approve(Deal $deal, SendDealCreatedNotificationCustomerAction $notificationCustomerAction)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
\DB::transaction(function () use ($deal) {
|
\DB::transaction(function () use ($deal) {
|
||||||
$deal->active = true;
|
$deal->active = true;
|
||||||
$deal->save();
|
$deal->save();
|
||||||
});
|
});
|
||||||
|
$notificationCustomerAction->execute($deal);
|
||||||
|
|
||||||
return back()->with('success', 'Deal activated successfully.');
|
return back()->with('success', 'Deal activated successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@ -30,7 +33,8 @@ public function approve(Deal $deal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reject(Deal $deal){
|
public function reject(Deal $deal)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$deal->delete();
|
$deal->delete();
|
||||||
|
|
||||||
@ -42,8 +46,13 @@ public function reject(Deal $deal){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function deals()
|
private function pendingDeals()
|
||||||
{
|
{
|
||||||
return Deal::where('active', false)->get();
|
return Deal::where('active', false)->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function activeDeals()
|
||||||
|
{
|
||||||
|
return Deal::where('active', true)->get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
use App\Enums\ReportStatus;
|
use App\Enums\ReportStatus;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Report;
|
use App\Models\Report;
|
||||||
|
use App\Notifications\ReportRejectedNotificationToUser;
|
||||||
|
use App\Notifications\ReportResolvedNotificationToBroker;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class ReportController extends Controller
|
class ReportController extends Controller
|
||||||
@ -27,9 +29,13 @@ public function resolve(Report $report)
|
|||||||
$report->status = ReportStatus::Resolved;
|
$report->status = ReportStatus::Resolved;
|
||||||
$report->save();
|
$report->save();
|
||||||
|
|
||||||
|
$report->user->notify(new ReportRejectedNotificationToUser($report->deals()->first()->title, false));
|
||||||
|
$report->deals()->first()->broker->notify(new ReportResolvedNotificationToBroker($report->deals()->first()->title,
|
||||||
|
false));
|
||||||
|
|
||||||
return back()->with('success', 'Report resolved successfully.');
|
return back()->with('success', 'Report resolved successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
\Log::error('Error resolving report', [$report->id, $e->getMessage(), $e->getTraceAsString()]);
|
\Log::error('Error resolving report', [$report->id, $e->getMessage()]);
|
||||||
|
|
||||||
return back()->with('error', 'Something went wrong.');
|
return back()->with('error', 'Something went wrong.');
|
||||||
}
|
}
|
||||||
@ -41,9 +47,11 @@ public function reject(Report $report)
|
|||||||
$report->status = ReportStatus::Rejected;
|
$report->status = ReportStatus::Rejected;
|
||||||
$report->save();
|
$report->save();
|
||||||
|
|
||||||
|
$report->user->notify(new ReportRejectedNotificationToUser($report->deals()->first()->title));
|
||||||
|
|
||||||
return back()->with('success', 'Report Rejected successfully.');
|
return back()->with('success', 'Report Rejected successfully.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
\Log::error('Error rejecting report', [$report->id, $e->getMessage(), $e->getTraceAsString()]);
|
\Log::error('Error rejecting report', [$report->id, $e->getMessage()]);
|
||||||
|
|
||||||
return back()->with('error', 'Something went wrong.');
|
return back()->with('error', 'Something went wrong.');
|
||||||
}
|
}
|
||||||
@ -56,6 +64,11 @@ public function removeContent(Report $report)
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
DB::transaction(function () use ($report) {
|
DB::transaction(function () use ($report) {
|
||||||
|
|
||||||
|
$report->user->notify(new ReportRejectedNotificationToUser($report->deals()->first()->title, true));
|
||||||
|
$report->deals()->first()->broker->notify(new ReportResolvedNotificationToBroker($report->deals()->first()->title,
|
||||||
|
true));
|
||||||
|
|
||||||
$deal = $report->deals()->first();
|
$deal = $report->deals()->first();
|
||||||
$deal->active = false;
|
$deal->active = false;
|
||||||
$report->status = ReportStatus::Resolved;
|
$report->status = ReportStatus::Resolved;
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Actions\RecordUserPageVisitAction;
|
||||||
use App\Enums\UserStatus;
|
use App\Enums\UserStatus;
|
||||||
use App\Enums\UserTypes;
|
use App\Enums\UserTypes;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
@ -16,7 +17,7 @@ public function create()
|
|||||||
return view('auth.login');
|
return view('auth.login');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(AuthenticateUserRequest $request)
|
public function store(AuthenticateUserRequest $request, RecordUserPageVisitAction $action)
|
||||||
{
|
{
|
||||||
$data = $request->validated();
|
$data = $request->validated();
|
||||||
if (Auth::attempt($data, $data['remember_me'] ?? false)) {
|
if (Auth::attempt($data, $data['remember_me'] ?? false)) {
|
||||||
@ -35,6 +36,12 @@ public function store(AuthenticateUserRequest $request)
|
|||||||
UserTypes::Broker->value, UserTypes::User->value => 'explore',
|
UserTypes::Broker->value, UserTypes::User->value => 'explore',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
$action->execute($user, $route);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
\Log::error('Error recording user page visit', [$e->getMessage()]);
|
||||||
|
}
|
||||||
|
|
||||||
return to_route($route);
|
return to_route($route);
|
||||||
} else {
|
} else {
|
||||||
return back()
|
return back()
|
||||||
|
|||||||
91
app/Http/Controllers/Auth/PasswordResetController.php
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Actions\PasswordReset\ResendOTPAction;
|
||||||
|
use App\Actions\PasswordReset\SendOTPAction;
|
||||||
|
use App\Actions\PasswordReset\VerifyOTPAction;
|
||||||
|
use App\Exceptions\UserNotFoundException;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
|
|
||||||
|
class PasswordResetController extends Controller
|
||||||
|
{
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
return view('auth.passwords.reset');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendCode(Request $request, SendOTPAction $action)
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'email' => 'required|email',
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$action->execute($data);
|
||||||
|
|
||||||
|
return to_route('password.reset.show.verify')
|
||||||
|
->with('success', 'Password reset code is sent');
|
||||||
|
} catch (UserNotFoundException $e) {
|
||||||
|
return to_route('password.reset.show.verify')->with('success', 'Password reset code is sent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showVerify()
|
||||||
|
{
|
||||||
|
return view('auth.passwords.verify')
|
||||||
|
->with('expiryMinutes', 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(Request $request, VerifyOTPAction $otpAction)
|
||||||
|
{
|
||||||
|
$data = $request->validate(['otp' => 'required|string:min:5:max:6']);
|
||||||
|
try {
|
||||||
|
$isVerified = $otpAction->execute($data);
|
||||||
|
if (! $isVerified) {
|
||||||
|
return back()->with('error', 'Invalid OTP');
|
||||||
|
}
|
||||||
|
|
||||||
|
return to_route('password.reset.show.update')->with('success', 'OTP Verified');
|
||||||
|
} catch (UserNotFoundException $e) {
|
||||||
|
return back()->with('error', 'Session Expired');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showUpdate()
|
||||||
|
{
|
||||||
|
return view('auth.passwords.update');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'password' => 'required', 'confirmed', Password::min(8)->letters()->mixedCase()->numbers()->symbols(),
|
||||||
|
]);
|
||||||
|
$user = User::find(Session::get('otp_user_id'));
|
||||||
|
if (! $user) {
|
||||||
|
return back()->with('error', 'Session Expired');
|
||||||
|
}
|
||||||
|
$user->update(['password' => $data['password']]);
|
||||||
|
|
||||||
|
\Session::forget('otp_user_id');
|
||||||
|
|
||||||
|
return to_route('login.create')->with('success', 'Password updated successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resend(ResendOTPAction $otpAction)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$otpAction->execute();
|
||||||
|
|
||||||
|
return to_route('password.reset.show.verify')
|
||||||
|
->with('success', 'Password reset code is sent');
|
||||||
|
} catch (UserNotFoundException $e) {
|
||||||
|
return to_route('password.reset.show.verify')->with('success', 'Password reset code is sent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -45,7 +45,7 @@ public function store(StoreRegisterdUser $request)
|
|||||||
});
|
});
|
||||||
|
|
||||||
return to_route('login.create')
|
return to_route('login.create')
|
||||||
->with('userRegistered', 'User registered successfully.');
|
->with('success', 'User registered successfully.');
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Registration Failed: '.$e->getMessage());
|
Log::error('Registration Failed: '.$e->getMessage());
|
||||||
|
|||||||
@ -33,7 +33,6 @@ protected function deals()
|
|||||||
->WithLikePerDeal()
|
->WithLikePerDeal()
|
||||||
->WithRedirectionPerDeal()
|
->WithRedirectionPerDeal()
|
||||||
->withViewPerDeal()
|
->withViewPerDeal()
|
||||||
->latest()
|
->latest()->take(3)->get();
|
||||||
->paginate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
use App\Models\Deal;
|
use App\Models\Deal;
|
||||||
use App\Models\DealCategory;
|
use App\Models\DealCategory;
|
||||||
use App\Services\FileService;
|
use App\Services\FileService;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
@ -18,7 +19,8 @@ class BrokerDealController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
//
|
return view('dashboards.broker.deals.index')
|
||||||
|
->with('deals', $this->deals());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,7 +51,7 @@ public function store(StoreBrokerDeal $request, FileService $fileService)
|
|||||||
Deal::create($data);
|
Deal::create($data);
|
||||||
Deal::reguard();
|
Deal::reguard();
|
||||||
|
|
||||||
return to_route('broker.dashboard')->with('success', 'Deal has been created.');
|
return to_route('broker.deals.index')->with('success', 'Deal has been created.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,10 +91,10 @@ public function update(StoreBrokerDeal $request, Deal $deal, FileService $fileSe
|
|||||||
} catch (\Throwable $exception) {
|
} catch (\Throwable $exception) {
|
||||||
Log::error($exception->getMessage(), $exception->getTrace());
|
Log::error($exception->getMessage(), $exception->getTrace());
|
||||||
|
|
||||||
return to_route('broker.dashboard')->with('error', 'Something gone wrong.');
|
return back()->with('error', 'Something gone wrong.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return to_route('broker.dashboard')->with('success', 'Deal has been updated.');
|
return back()->with('success', 'Deal has been updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,9 +114,31 @@ public function destroy(Deal $deal, FileService $fileService)
|
|||||||
} catch (\Throwable $exception) {
|
} catch (\Throwable $exception) {
|
||||||
Log::error($exception->getMessage(), $exception->getTrace());
|
Log::error($exception->getMessage(), $exception->getTrace());
|
||||||
|
|
||||||
return to_route('broker.dashboard')->with('error', 'Something gone wrong.');
|
return back()->with('error', 'Something gone wrong.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return to_route('broker.dashboard')->with('success', 'Deal has been deleted.');
|
return back()->with('success', 'Deal has been deleted.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function deals()
|
||||||
|
{
|
||||||
|
return Auth::user()
|
||||||
|
->deals()
|
||||||
|
->select([
|
||||||
|
'id',
|
||||||
|
'title',
|
||||||
|
'description',
|
||||||
|
'image',
|
||||||
|
'active',
|
||||||
|
'slug',
|
||||||
|
'link',
|
||||||
|
'deal_category_id',
|
||||||
|
])
|
||||||
|
->with('category:id,name')
|
||||||
|
->WithLikePerDeal()
|
||||||
|
->WithRedirectionPerDeal()
|
||||||
|
->withViewPerDeal()
|
||||||
|
->latest()
|
||||||
|
->paginate(15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
app/Http/Controllers/ChatController.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\CreateOrGetInboxAction;
|
||||||
|
use App\Actions\SendMessageAction;
|
||||||
|
use App\Exceptions\MessageNotSendException;
|
||||||
|
use App\Http\Requests\SendMessageRequest;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Container\Attributes\CurrentUser;
|
||||||
|
use Log;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ChatController extends Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
public function index(#[CurrentUser] User $user)
|
||||||
|
{
|
||||||
|
return view('dashboards.user.chat')
|
||||||
|
->with('inboxes', $user->inboxes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(#[CurrentUser] User $sender, User $recipient, CreateOrGetInboxAction $action)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$inbox = $action->execute($recipient, $sender);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Log::error('Inbox instantiation Failed: ', [$e->getMessage()]);
|
||||||
|
abort(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('dashboards.user.chat')
|
||||||
|
->with('recipient', $recipient)
|
||||||
|
->with('inboxes', $sender->inboxes)
|
||||||
|
->with('messages', $inbox->messages()->latest()->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function store(
|
||||||
|
#[CurrentUser] User $sender,
|
||||||
|
User $recipient,
|
||||||
|
SendMessageRequest $request,
|
||||||
|
SendMessageAction $action
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
$action->execute($sender, $recipient, $request->validated());
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Message sent successfully.']);
|
||||||
|
|
||||||
|
} catch (MessageNotSendException $e) {
|
||||||
|
|
||||||
|
Log::error('Message send failed', [$e->getMessage()]);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Message sent failed.'], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Http/Controllers/CommentController.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\CommentRequest;
|
||||||
|
use App\Models\Comment;
|
||||||
|
use App\Models\Deal;
|
||||||
|
|
||||||
|
class CommentController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Deal $deal)
|
||||||
|
{
|
||||||
|
$comments = $deal->comments()->with('user')->latest()->get();
|
||||||
|
$html = view('components.dashboard.user.deal-comment.index', compact('comments'))->render();
|
||||||
|
|
||||||
|
return response()->json(['html' => $html]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Deal $deal, CommentRequest $request)
|
||||||
|
{
|
||||||
|
$data = $request->validated();
|
||||||
|
$data['user_id'] = $request->user()->id;
|
||||||
|
$data['deal_id'] = $deal->id;
|
||||||
|
|
||||||
|
Comment::create($data);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Comment created successfully.'], 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Comment $comment) {}
|
||||||
|
|
||||||
|
public function update(CommentRequest $request, Comment $comment)
|
||||||
|
{
|
||||||
|
$comment->update($request->validated());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Comment $comment)
|
||||||
|
{
|
||||||
|
$comment->delete();
|
||||||
|
|
||||||
|
return response()->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Http/Controllers/ContactController.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\ContactRequest;
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Notifications\NewContactNotification;
|
||||||
|
|
||||||
|
class ContactController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(ContactRequest $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
$data = $request->validated();
|
||||||
|
$admin = Admin::first();
|
||||||
|
$admin->user->notify(new NewContactNotification($data['name'], $data['email'], $data['message']));
|
||||||
|
|
||||||
|
return back()->with('success', 'Your message has been sent successfully.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
\Log::error('Error sending contact message', [$e->getMessage()]);
|
||||||
|
|
||||||
|
return back()->with('error', 'Something went wrong.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
app/Http/Controllers/FollowController.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Broker;
|
||||||
|
use App\Models\Follow;
|
||||||
|
|
||||||
|
class FollowController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Broker $broker)
|
||||||
|
{
|
||||||
|
$follow = $this->checkFollow($broker);
|
||||||
|
if ($follow === null) {
|
||||||
|
return $this->store($broker);
|
||||||
|
} else {
|
||||||
|
return $this->destroy($follow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Broker $broker)
|
||||||
|
{
|
||||||
|
Follow::create([
|
||||||
|
'broker_id' => $broker->id,
|
||||||
|
'customer_id' => auth()->id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Followed successfully.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Follow $follow)
|
||||||
|
{
|
||||||
|
$follow->delete();
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Unfollowed successfully.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkFollow(Broker $broker)
|
||||||
|
{
|
||||||
|
return Follow::where('broker_id', $broker->id)
|
||||||
|
->where('customer_id', auth()->id())
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Http/Controllers/PushSubscriptionController.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\PushSubscriptionRequest;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Container\Attributes\CurrentUser;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class PushSubscriptionController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(#[CurrentUser] User $user, PushSubscriptionRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->validated();
|
||||||
|
$user->updatePushSubscription($data['endpoint'], $data['keys']['p256dh'], $data['keys']['auth']);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Push subscription updated successfully.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
app/Http/Controllers/StatsController.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Enums\UserTypes;
|
||||||
|
use App\Http\Resources\ActiveUsersStatsCollection;
|
||||||
|
use App\Http\Resources\DealsCountByCategoryCollection;
|
||||||
|
use App\Models\DealCategory;
|
||||||
|
use App\Queries\PageVisitStatsQuery;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class StatsController extends Controller
|
||||||
|
{
|
||||||
|
public function getActiveUsers(Request $request, PageVisitStatsQuery $baseQuery)
|
||||||
|
{
|
||||||
|
$startDay = $request->from ?? now()->subDays(30);
|
||||||
|
$endDay = $request->to ?? now();
|
||||||
|
|
||||||
|
$activeCustomers = $baseQuery->builder(UserTypes::User, $startDay, $endDay)->get();
|
||||||
|
$activeBrokers = $baseQuery->builder(UserTypes::Broker, $startDay, $endDay)->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'activeCustomers' => new ActiveUsersStatsCollection($activeCustomers),
|
||||||
|
'activeBrokers' => new ActiveUsersStatsCollection($activeBrokers),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDealsByCategory()
|
||||||
|
{
|
||||||
|
return new DealsCountByCategoryCollection(
|
||||||
|
DealCategory::select(['id', 'name'])
|
||||||
|
->withCount('deals')
|
||||||
|
->get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Http/Middleware/EnsureUserFollowedBroker.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class EnsureUserFollowedBroker
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
$sender = \Auth::user();
|
||||||
|
if ($sender->isBroker()) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$recipientUser = $request->route('recipient');
|
||||||
|
if ($recipientUser->isBroker()) {
|
||||||
|
$recipient = $recipientUser->type;
|
||||||
|
|
||||||
|
$isFollowing = $recipient->followers->contains($sender->id);
|
||||||
|
|
||||||
|
if ($isFollowing) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403, 'You are not following this broker.');
|
||||||
|
}
|
||||||
|
|
||||||
|
abort('404', 'Broker not found.');
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Http/Requests/CommentRequest.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class CommentRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'text' => ['required', 'string', 'max:255'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Http/Requests/ContactRequest.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class ContactRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|min:3|max:255',
|
||||||
|
'email' => 'required|email|max:255',
|
||||||
|
'message' => 'required|string|min:10|max:255',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRedirectUrl(): string
|
||||||
|
{
|
||||||
|
return parent::getRedirectUrl().'#contact';
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Http/Requests/PushSubscriptionRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class PushSubscriptionRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'endpoint' => 'required|string|max:500',
|
||||||
|
'keys.auth' => 'required|string|max:255',
|
||||||
|
'keys.p256dh' => 'required|string|max:255',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Http/Requests/SendMessageRequest.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class SendMessageRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'message' => 'required|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
app/Http/Resources/ActiveUsersStatsCollection.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class ActiveUsersStatsCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Http/Resources/ActiveUsersStatsResource.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class ActiveUsersStatsResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array{data: string, userCount: int}
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'date' => $this->date,
|
||||||
|
'userCount' => (int) $this->user_count,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -27,6 +27,7 @@ public function toArray(Request $request): array
|
|||||||
'totalRedirection' => $this->total_redirection,
|
'totalRedirection' => $this->total_redirection,
|
||||||
'isLiked' => $this->is_liked,
|
'isLiked' => $this->is_liked,
|
||||||
'isFavorite' => $this->is_favorite,
|
'isFavorite' => $this->is_favorite,
|
||||||
|
'isFollowed' => $this->is_followed,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
app/Http/Resources/DealsCountByCategoryCollection.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class DealsCountByCategoryCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Http/Resources/DealsCountByCategoryResource.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class DealsCountByCategoryResource extends JsonResource
|
||||||
|
{
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $this->name,
|
||||||
|
'dealsCount' => $this->deals_count,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Mail/PasswordResetMail.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Address;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class PasswordResetMail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(private readonly string $otp) {}
|
||||||
|
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
from: new Address(config('mail.from.address'), config('mail.from.name')),
|
||||||
|
subject: 'Password Reset',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.password-reset',
|
||||||
|
with: ['otp' => $this->otp]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,21 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Admin newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Admin newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Admin query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Admin whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Admin whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Admin whereUpdatedAt($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class Admin extends Model
|
class Admin extends Model
|
||||||
{
|
{
|
||||||
public function user(): MorphOne
|
public function user(): MorphOne
|
||||||
|
|||||||
@ -3,8 +3,35 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string|null $bio
|
||||||
|
* @property string|null $location
|
||||||
|
* @property string|null $phone
|
||||||
|
* @property bool $verified
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Follow|null $pivot
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Customer> $followers
|
||||||
|
* @property-read int|null $followers_count
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker whereBio($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker whereLocation($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker wherePhone($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Broker whereVerified($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class Broker extends Model
|
class Broker extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['bio', 'location', 'phone'];
|
protected $fillable = ['bio', 'location', 'phone'];
|
||||||
@ -20,4 +47,14 @@ public function user(): MorphOne
|
|||||||
{
|
{
|
||||||
return $this->morphOne(User::class, 'role');
|
return $this->morphOne(User::class, 'role');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function followers(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(
|
||||||
|
Customer::class,
|
||||||
|
'follows',
|
||||||
|
'broker_id',
|
||||||
|
'customer_id'
|
||||||
|
)->using(Follow::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
app/Models/Comment.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $text
|
||||||
|
* @property int $deal_id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Deal|null $deal
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment whereDealId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment whereText($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Comment whereUserId($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Comment extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'text',
|
||||||
|
'deal_id',
|
||||||
|
'user_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function deal(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Deal::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,8 +3,32 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string|null $bio
|
||||||
|
* @property string|null $location
|
||||||
|
* @property string|null $phone
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Follow> $followings
|
||||||
|
* @property-read int|null $followings_count
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer whereBio($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer whereLocation($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer wherePhone($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Customer whereUpdatedAt($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class Customer extends Model
|
class Customer extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['bio', 'location', 'phone'];
|
protected $fillable = ['bio', 'location', 'phone'];
|
||||||
@ -13,4 +37,9 @@ public function user(): MorphOne
|
|||||||
{
|
{
|
||||||
return $this->morphOne(User::class, 'role');
|
return $this->morphOne(User::class, 'role');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function followings(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Follow::class, 'customer_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,52 @@
|
|||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $title
|
||||||
|
* @property string $slug
|
||||||
|
* @property string $description
|
||||||
|
* @property string|null $image
|
||||||
|
* @property string|null $link
|
||||||
|
* @property int $active
|
||||||
|
* @property int $deal_category_id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\User|null $broker
|
||||||
|
* @property-read \App\Models\DealCategory|null $category
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Comment> $comments
|
||||||
|
* @property-read int|null $comments_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Interaction> $interactions
|
||||||
|
* @property-read int|null $interactions_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Report> $reports
|
||||||
|
* @property-read int|null $reports_count
|
||||||
|
*
|
||||||
|
* @method static Builder<static>|Deal WithActiveDeals()
|
||||||
|
* @method static Builder<static>|Deal WithCurrentUserInteractions()
|
||||||
|
* @method static Builder<static>|Deal WithLikePerDeal()
|
||||||
|
* @method static Builder<static>|Deal WithRedirectionPerDeal()
|
||||||
|
* @method static Builder<static>|Deal filterByCategory(string $category)
|
||||||
|
* @method static Builder<static>|Deal newModelQuery()
|
||||||
|
* @method static Builder<static>|Deal newQuery()
|
||||||
|
* @method static Builder<static>|Deal query()
|
||||||
|
* @method static Builder<static>|Deal search(string $search)
|
||||||
|
* @method static Builder<static>|Deal whereActive($value)
|
||||||
|
* @method static Builder<static>|Deal whereCreatedAt($value)
|
||||||
|
* @method static Builder<static>|Deal whereDealCategoryId($value)
|
||||||
|
* @method static Builder<static>|Deal whereDescription($value)
|
||||||
|
* @method static Builder<static>|Deal whereId($value)
|
||||||
|
* @method static Builder<static>|Deal whereImage($value)
|
||||||
|
* @method static Builder<static>|Deal whereLink($value)
|
||||||
|
* @method static Builder<static>|Deal whereSlug($value)
|
||||||
|
* @method static Builder<static>|Deal whereTitle($value)
|
||||||
|
* @method static Builder<static>|Deal whereUpdatedAt($value)
|
||||||
|
* @method static Builder<static>|Deal whereUserId($value)
|
||||||
|
* @method static Builder<static>|Deal withIsFollowedByCurrentUser()
|
||||||
|
* @method static Builder<static>|Deal withViewPerDeal()
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class Deal extends Model
|
class Deal extends Model
|
||||||
{
|
{
|
||||||
public function broker(): BelongsTo
|
public function broker(): BelongsTo
|
||||||
@ -33,6 +79,11 @@ public function reports(): BelongsToMany
|
|||||||
return $this->belongsToMany(Report::class);
|
return $this->belongsToMany(Report::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function comments(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Comment::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scope a query to only include active deals
|
* Scope a query to only include active deals
|
||||||
*/
|
*/
|
||||||
@ -119,4 +170,30 @@ public function filterByCategory(Builder $query, string $category): Builder
|
|||||||
{
|
{
|
||||||
return $query->where('deal_category_id', $category);
|
return $query->where('deal_category_id', $category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add this to App\Models\Deal.php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope a query to check if the current user follows the deal's broker
|
||||||
|
*/
|
||||||
|
#[Scope]
|
||||||
|
public function withIsFollowedByCurrentUser(Builder $query): Builder
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if (! $user || $user->role_type !== \App\Models\Customer::class) {
|
||||||
|
return $query->withExists(['broker as is_followed' => fn ($q) => $q->whereRaw('1 = 0')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->withExists([
|
||||||
|
'broker as is_followed' => function ($query) use ($user) {
|
||||||
|
$query->where('role_type', \App\Models\Broker::class)
|
||||||
|
->whereHasMorph('type', [\App\Models\Broker::class], function ($query) use ($user) {
|
||||||
|
$query->whereHas('followers', function ($query) use ($user) {
|
||||||
|
$query->where('customer_id', $user->id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,36 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string|null $description
|
||||||
|
* @property string $slug
|
||||||
|
* @property int $active
|
||||||
|
* @property int $order
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Deal> $deals
|
||||||
|
* @property-read int|null $deals_count
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereActive($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereDescription($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereOrder($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereSlug($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DealCategory whereUpdatedAt($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class DealCategory extends Model
|
class DealCategory extends Model
|
||||||
{
|
{
|
||||||
|
protected $fillable = ['name', 'description', 'slug', 'active', 'order'];
|
||||||
|
|
||||||
public function deals(): HasMany
|
public function deals(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Deal::class);
|
return $this->hasMany(Deal::class);
|
||||||
|
|||||||
46
app/Models/Follow.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $customer_id
|
||||||
|
* @property int $broker_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Broker|null $broker
|
||||||
|
* @property-read \App\Models\Customer|null $customer
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow whereBrokerId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow whereCustomerId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Follow whereUpdatedAt($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Follow extends Pivot
|
||||||
|
{
|
||||||
|
protected $table = 'follows';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'customer_id',
|
||||||
|
'broker_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function customer(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function broker(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Broker::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
55
app/Models/Inbox.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string|null $last_message
|
||||||
|
* @property int|null $last_user_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\User|null $lastUser
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||||
|
* @property-read int|null $users_count
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox whereLastMessage($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox whereLastUserId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Inbox whereUpdatedAt($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Inbox extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['last_user_id', 'last_message'];
|
||||||
|
|
||||||
|
public function users(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastUser(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'id', 'last_user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Message::class, 'inbox_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRecipientAttribute(): User
|
||||||
|
{
|
||||||
|
// first user in the relationship that is NOT the authenticated user
|
||||||
|
return $this->users->where('id', '!=', auth()->id())->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,30 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property int $deal_id
|
||||||
|
* @property InteractionType $type
|
||||||
|
* @property int $count
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Deal|null $deal
|
||||||
|
* @property-read \App\Models\Deal|null $user
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereCount($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereDealId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereType($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Interaction whereUserId($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class Interaction extends Model
|
class Interaction extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
|||||||
62
app/Models/Message.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Eloquent;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property int $inbox_id
|
||||||
|
* @property string $message
|
||||||
|
* @property string|null $read_at
|
||||||
|
* @property string|null $delivered_at
|
||||||
|
* @property string|null $deleted_at
|
||||||
|
* @property string|null $failed_at
|
||||||
|
* @property Carbon $created_at
|
||||||
|
* @property-read Inbox|null $inbox
|
||||||
|
* @property-read User|null $user
|
||||||
|
*
|
||||||
|
* @method static Builder<static>|Message newModelQuery()
|
||||||
|
* @method static Builder<static>|Message newQuery()
|
||||||
|
* @method static Builder<static>|Message query()
|
||||||
|
* @method static Builder<static>|Message whereCreatedAt($value)
|
||||||
|
* @method static Builder<static>|Message whereDeletedAt($value)
|
||||||
|
* @method static Builder<static>|Message whereDeliveredAt($value)
|
||||||
|
* @method static Builder<static>|Message whereFailedAt($value)
|
||||||
|
* @method static Builder<static>|Message whereId($value)
|
||||||
|
* @method static Builder<static>|Message whereInboxId($value)
|
||||||
|
* @method static Builder<static>|Message whereMessage($value)
|
||||||
|
* @method static Builder<static>|Message whereReadAt($value)
|
||||||
|
* @method static Builder<static>|Message whereUserId($value)
|
||||||
|
*
|
||||||
|
* @mixin Eloquent
|
||||||
|
*/
|
||||||
|
class Message extends Model
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'inbox_id', 'user_id', 'message',
|
||||||
|
'read_at', 'deleted_at', 'failed_at',
|
||||||
|
'created_at', 'delivered_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function inbox(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Inbox::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/Models/PageVisit.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\UserTypes;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int|null $user_id
|
||||||
|
* @property string $page
|
||||||
|
* @property UserTypes|null $user_type
|
||||||
|
* @property string $created_at
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit wherePage($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit whereUserId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PageVisit whereUserType($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class PageVisit extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id', 'page', 'user_type',
|
||||||
|
'created_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'user_type' => UserTypes::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,25 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property string $query
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
*
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch whereQuery($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|RecentSearch whereUserId($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class RecentSearch extends Model
|
class RecentSearch extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['query'];
|
protected $fillable = ['query'];
|
||||||
|
|||||||
@ -10,6 +10,32 @@
|
|||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property ReportType $type
|
||||||
|
* @property ReportStatus $status
|
||||||
|
* @property string $description
|
||||||
|
* @property int $user_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Deal> $deals
|
||||||
|
* @property-read int|null $deals_count
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
*
|
||||||
|
* @method static Builder<static>|Report newModelQuery()
|
||||||
|
* @method static Builder<static>|Report newQuery()
|
||||||
|
* @method static Builder<static>|Report orderByStatus(array $statusOrder)
|
||||||
|
* @method static Builder<static>|Report query()
|
||||||
|
* @method static Builder<static>|Report whereCreatedAt($value)
|
||||||
|
* @method static Builder<static>|Report whereDescription($value)
|
||||||
|
* @method static Builder<static>|Report whereId($value)
|
||||||
|
* @method static Builder<static>|Report whereStatus($value)
|
||||||
|
* @method static Builder<static>|Report whereType($value)
|
||||||
|
* @method static Builder<static>|Report whereUpdatedAt($value)
|
||||||
|
* @method static Builder<static>|Report whereUserId($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class Report extends Model
|
class Report extends Model
|
||||||
{
|
{
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
|
|||||||
@ -5,16 +5,74 @@
|
|||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use NotificationChannels\WebPush\HasPushSubscriptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $email
|
||||||
|
* @property \Illuminate\Support\Carbon|null $email_verified_at
|
||||||
|
* @property string $password
|
||||||
|
* @property string|null $remember_token
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property string $status
|
||||||
|
* @property string $role
|
||||||
|
* @property string|null $role_type
|
||||||
|
* @property int|null $role_id
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Comment> $comments
|
||||||
|
* @property-read int|null $comments_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Deal> $deals
|
||||||
|
* @property-read int|null $deals_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Interaction> $dealsInteractions
|
||||||
|
* @property-read int|null $deals_interactions_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Inbox> $inboxes
|
||||||
|
* @property-read int|null $inboxes_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Deal> $interactedDeals
|
||||||
|
* @property-read int|null $interacted_deals_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, User> $interactions
|
||||||
|
* @property-read int|null $interactions_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Message> $messages
|
||||||
|
* @property-read int|null $messages_count
|
||||||
|
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||||
|
* @property-read int|null $notifications_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \NotificationChannels\WebPush\PushSubscription> $pushSubscriptions
|
||||||
|
* @property-read int|null $push_subscriptions_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecentSearch> $recentSearches
|
||||||
|
* @property-read int|null $recent_searches_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Report> $reports
|
||||||
|
* @property-read int|null $reports_count
|
||||||
|
* @property-read Model|\Eloquent|null $type
|
||||||
|
*
|
||||||
|
* @method static \Database\Factories\UserFactory factory($count = null, $state = [])
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmail($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmailVerifiedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User wherePassword($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRememberToken($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRole($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRoleId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRoleType($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereStatus($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereUpdatedAt($value)
|
||||||
|
*
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||||
use HasFactory, Notifiable;
|
use HasFactory, HasPushSubscriptions, Notifiable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
@ -104,4 +162,19 @@ public function reports(): HasMany
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Report::class);
|
return $this->hasMany(Report::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function comments(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Comment::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inboxes(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Inbox::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Message::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
app/Notifications/NewContactNotification.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class NewContactNotification extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly string $customerName,
|
||||||
|
private readonly string $customerEmail,
|
||||||
|
private readonly string $customerMessage
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function via($notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail($notifiable): MailMessage
|
||||||
|
{
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject('New Contact Submission: '.$this->customerName)
|
||||||
|
->greeting('Hello Admin,') // Or keep it empty if you prefer
|
||||||
|
->line('You have received a new message from your contact form:')
|
||||||
|
->line("**Name:** {$this->customerName}")
|
||||||
|
->line("**Email:** {$this->customerEmail}")
|
||||||
|
->line('**Message:**')
|
||||||
|
->line($this->customerMessage)
|
||||||
|
->action('Reply via Email', 'mailto:'.$this->customerEmail);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Notifications/NewDealNotification.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Models\Deal;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use NotificationChannels\WebPush\WebPushChannel;
|
||||||
|
use NotificationChannels\WebPush\WebPushMessage;
|
||||||
|
|
||||||
|
class NewDealNotification extends Notification
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*/
|
||||||
|
public function __construct(private readonly Deal $deal)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
return [WebPushChannel::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toWebPush($notifiable, $notification): WebPushMessage
|
||||||
|
{
|
||||||
|
\Log::info('Building WebPush for user: '.$notifiable->id);
|
||||||
|
|
||||||
|
return (new WebPushMessage)
|
||||||
|
->title("New deal from {$this->deal->broker->name}")
|
||||||
|
->body('Check out this deal:'.Str::limit($this->deal->title, 30, '...'))
|
||||||
|
->action('View deal', route('explore', ['show' => $this->deal->id]));
|
||||||
|
}
|
||||||
|
}
|
||||||
43
app/Notifications/ReportRejectedNotificationToUser.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class ReportRejectedNotificationToUser extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly string $dealTitle,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function via($notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail($notifiable): MailMessage
|
||||||
|
{
|
||||||
|
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject('Update on Your Recent Report: '.$this->dealTitle)
|
||||||
|
->greeting('Hello!')
|
||||||
|
->line('Thank you for helping us maintain the integrity of our marketplace.')
|
||||||
|
->line("We have completed our review of the deal you reported: **{$this->dealTitle}**.")
|
||||||
|
->line('Based on our moderation policy, we have rejected your report.')
|
||||||
|
->action('View Marketplace', route('explore'))
|
||||||
|
->line('Your feedback helps make our community a safer place for everyone.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray($notifiable): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'report_outcome' => $this->isContentRemoved ? 'violation_confirmed' : 'no_violation_found',
|
||||||
|
'deal_title' => $this->dealTitle,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
46
app/Notifications/ReportResolvedNotificationToBroker.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class ReportResolvedNotificationToBroker extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly string $dealTitle,
|
||||||
|
private readonly bool $isContentRemoved
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function via($notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail($notifiable): MailMessage
|
||||||
|
{
|
||||||
|
$status = $this->isContentRemoved
|
||||||
|
? 'has been removed following a policy review.'
|
||||||
|
: 'has been reviewed and remains active.';
|
||||||
|
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject('Update Regarding Your Reported Deal: '.$this->dealTitle)
|
||||||
|
->greeting('Hello!')
|
||||||
|
->line("We are writing to inform you that the report regarding your deal, **{$this->dealTitle}**, has been resolved.")
|
||||||
|
->line("Our moderation team has completed their review, and the content {$status}")
|
||||||
|
->action('View My Deals', route('broker.dashboard')) // Adjusted for your UMS/Project structure
|
||||||
|
->line('Thank you for being a part of our marketplace.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray($notifiable): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'deal_title' => $this->dealTitle,
|
||||||
|
'action_taken' => $this->isContentRemoved ? 'removed' : 'kept',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/Notifications/ReportResolvedNotificationToUser.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class ReportResolvedNotificationToUser extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly string $dealTitle,
|
||||||
|
private readonly bool $isContentRemoved
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function via($notifiable): array
|
||||||
|
{
|
||||||
|
return ['mail'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail($notifiable): MailMessage
|
||||||
|
{
|
||||||
|
$outcome = $this->isContentRemoved
|
||||||
|
? 'has been removed following our investigation.'
|
||||||
|
: 'will remain active as it was found to be in compliance with our guidelines.';
|
||||||
|
|
||||||
|
return (new MailMessage)
|
||||||
|
->subject('Update on Your Recent Report: '.$this->dealTitle)
|
||||||
|
->greeting('Hello!')
|
||||||
|
->line('Thank you for helping us maintain the integrity of our marketplace.')
|
||||||
|
->line("We have completed our review of the deal you reported: **{$this->dealTitle}**.")
|
||||||
|
->line("Based on our moderation policy, the content {$outcome}")
|
||||||
|
->action('View Marketplace', route('explore'))
|
||||||
|
->line('Your feedback helps make our community a safer place for everyone.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray($notifiable): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'report_outcome' => $this->isContentRemoved ? 'violation_confirmed' : 'no_violation_found',
|
||||||
|
'deal_title' => $this->dealTitle,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -29,6 +29,7 @@ public function builder(): Builder
|
|||||||
// Check if the current user interacted with the deal
|
// Check if the current user interacted with the deal
|
||||||
->tap(fn ($q) => (new Deal)->withCurrentUserInteractions($q))
|
->tap(fn ($q) => (new Deal)->withCurrentUserInteractions($q))
|
||||||
->tap(fn ($q) => (new Deal)->withLikePerDeal($q))
|
->tap(fn ($q) => (new Deal)->withLikePerDeal($q))
|
||||||
|
->tap(fn ($q) => (new Deal)->withIsFollowedByCurrentUser($q))
|
||||||
->tap(fn ($q) => (new Deal)->withRedirectionPerDeal($q));
|
->tap(fn ($q) => (new Deal)->withRedirectionPerDeal($q));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
app/Queries/PageVisitStatsQuery.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Queries;
|
||||||
|
|
||||||
|
use App\Enums\UserTypes;
|
||||||
|
use App\Models\PageVisit;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
final readonly class PageVisitStatsQuery
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return Builder<PageVisit>
|
||||||
|
*/
|
||||||
|
public function builder(UserTypes $userType, string $startDay, string $endDay): Builder
|
||||||
|
{
|
||||||
|
return PageVisit::query()
|
||||||
|
->selectRaw('count(distinct user_id) as user_count, created_at as date')
|
||||||
|
->where('user_type', $userType)
|
||||||
|
->whereBetween('created_at', [$startDay.' 00:00:00', $endDay.' 23:59:59'])
|
||||||
|
->groupBy('date');
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Services/OTPService.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class OTPService
|
||||||
|
{
|
||||||
|
public function generate(User $user, int $length = 6): string
|
||||||
|
{
|
||||||
|
$code = \Str::random($length);
|
||||||
|
Cache::put("otp_$user->id", $code, now()->addMinutes((int) config('auth.otp_lifespan', '10')));
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(User $user, string $otp): bool
|
||||||
|
{
|
||||||
|
$code = Cache::get("otp_$user->id");
|
||||||
|
if ($code === $otp) {
|
||||||
|
Cache::forget("otp_$user->id");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Services/TwilioService.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Twilio\Exceptions\TwilioException;
|
||||||
|
use Twilio\Rest\Client;
|
||||||
|
|
||||||
|
class TwilioService
|
||||||
|
{
|
||||||
|
private Client $client;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->client = new Client(config('services.twilio.sid'), config('services.twilio.token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws TwilioException
|
||||||
|
*/
|
||||||
|
public function sendSms(string $to, string $message): void
|
||||||
|
{
|
||||||
|
$this->client->messages->create($to, ['from' => config('services.twilio.from'), 'body' => $message]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@
|
|||||||
->withRouting(
|
->withRouting(
|
||||||
web: __DIR__.'/../routes/web.php',
|
web: __DIR__.'/../routes/web.php',
|
||||||
commands: __DIR__.'/../routes/console.php',
|
commands: __DIR__.'/../routes/console.php',
|
||||||
|
channels: __DIR__.'/../routes/channels.php',
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
|
|||||||
2
bootstrap/cache/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
105
bootstrap/cache/packages.php
vendored
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
<?php return array (
|
||||||
|
'barryvdh/laravel-ide-helper' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'blade-ui-kit/blade-heroicons' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'BladeUI\\Heroicons\\BladeHeroiconsServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'blade-ui-kit/blade-icons' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'BladeUI\\Icons\\BladeIconsServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laradumps/laradumps' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'LaraDumps\\LaraDumps\\LaraDumpsServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel-notification-channels/webpush' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'NotificationChannels\\WebPush\\WebPushServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/pail' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Pail\\PailServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/reverb' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Reverb\\ApplicationManagerServiceProvider',
|
||||||
|
1 => 'Laravel\\Reverb\\ReverbServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/sail' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/tinker' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nesbot/carbon' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nunomaduro/collision' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nunomaduro/termwind' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'opcodesio/log-viewer' =>
|
||||||
|
array (
|
||||||
|
'aliases' =>
|
||||||
|
array (
|
||||||
|
'LogViewer' => 'Opcodes\\LogViewer\\Facades\\LogViewer',
|
||||||
|
),
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Opcodes\\LogViewer\\LogViewerServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'pestphp/pest-plugin-laravel' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Pest\\Laravel\\PestServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
289
bootstrap/cache/services.php
vendored
Executable file
@ -0,0 +1,289 @@
|
|||||||
|
<?php return array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Illuminate\\Auth\\AuthServiceProvider',
|
||||||
|
1 => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
2 => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
3 => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
4 => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
5 => 'Illuminate\\Concurrency\\ConcurrencyServiceProvider',
|
||||||
|
6 => 'Illuminate\\Cookie\\CookieServiceProvider',
|
||||||
|
7 => 'Illuminate\\Database\\DatabaseServiceProvider',
|
||||||
|
8 => 'Illuminate\\Encryption\\EncryptionServiceProvider',
|
||||||
|
9 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',
|
||||||
|
10 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',
|
||||||
|
11 => 'Illuminate\\Hashing\\HashServiceProvider',
|
||||||
|
12 => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
13 => 'Illuminate\\Notifications\\NotificationServiceProvider',
|
||||||
|
14 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
||||||
|
15 => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
||||||
|
16 => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
||||||
|
17 => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
18 => 'Illuminate\\Redis\\RedisServiceProvider',
|
||||||
|
19 => 'Illuminate\\Session\\SessionServiceProvider',
|
||||||
|
20 => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
|
21 => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
22 => 'Illuminate\\View\\ViewServiceProvider',
|
||||||
|
23 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
24 => 'BladeUI\\Heroicons\\BladeHeroiconsServiceProvider',
|
||||||
|
25 => 'BladeUI\\Icons\\BladeIconsServiceProvider',
|
||||||
|
26 => 'LaraDumps\\LaraDumps\\LaraDumpsServiceProvider',
|
||||||
|
27 => 'NotificationChannels\\WebPush\\WebPushServiceProvider',
|
||||||
|
28 => 'Laravel\\Pail\\PailServiceProvider',
|
||||||
|
29 => 'Laravel\\Reverb\\ApplicationManagerServiceProvider',
|
||||||
|
30 => 'Laravel\\Reverb\\ReverbServiceProvider',
|
||||||
|
31 => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
32 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
|
33 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
|
34 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
|
35 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
|
36 => 'Opcodes\\LogViewer\\LogViewerServiceProvider',
|
||||||
|
37 => 'Pest\\Laravel\\PestServiceProvider',
|
||||||
|
38 => 'App\\Providers\\AppServiceProvider',
|
||||||
|
),
|
||||||
|
'eager' =>
|
||||||
|
array (
|
||||||
|
0 => 'Illuminate\\Auth\\AuthServiceProvider',
|
||||||
|
1 => 'Illuminate\\Cookie\\CookieServiceProvider',
|
||||||
|
2 => 'Illuminate\\Database\\DatabaseServiceProvider',
|
||||||
|
3 => 'Illuminate\\Encryption\\EncryptionServiceProvider',
|
||||||
|
4 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',
|
||||||
|
5 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',
|
||||||
|
6 => 'Illuminate\\Notifications\\NotificationServiceProvider',
|
||||||
|
7 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
||||||
|
8 => 'Illuminate\\Session\\SessionServiceProvider',
|
||||||
|
9 => 'Illuminate\\View\\ViewServiceProvider',
|
||||||
|
10 => 'BladeUI\\Heroicons\\BladeHeroiconsServiceProvider',
|
||||||
|
11 => 'BladeUI\\Icons\\BladeIconsServiceProvider',
|
||||||
|
12 => 'LaraDumps\\LaraDumps\\LaraDumpsServiceProvider',
|
||||||
|
13 => 'NotificationChannels\\WebPush\\WebPushServiceProvider',
|
||||||
|
14 => 'Laravel\\Pail\\PailServiceProvider',
|
||||||
|
15 => 'Laravel\\Reverb\\ReverbServiceProvider',
|
||||||
|
16 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
|
17 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
|
18 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
|
19 => 'Opcodes\\LogViewer\\LogViewerServiceProvider',
|
||||||
|
20 => 'Pest\\Laravel\\PestServiceProvider',
|
||||||
|
21 => 'App\\Providers\\AppServiceProvider',
|
||||||
|
),
|
||||||
|
'deferred' =>
|
||||||
|
array (
|
||||||
|
'Illuminate\\Broadcasting\\BroadcastManager' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Broadcasting\\Factory' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Broadcasting\\Broadcaster' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
'Illuminate\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Bus\\QueueingDispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Bus\\BatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Bus\\DatabaseBatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'cache' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'cache.store' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'cache.psr6' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'memcached.connector' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'Illuminate\\Cache\\RateLimiter' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\AboutCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\ClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\ForgetCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ClearCompiledCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Auth\\Console\\ClearResetsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigShowCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\DbCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\MonitorCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\PruneCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\ShowCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\TableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\WipeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\DownCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnvironmentCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnvironmentDecryptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnvironmentEncryptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Concurrency\\Console\\InvokeSerializedClosureCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\KeyGenerateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\OptimizeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\OptimizeClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\PackageDiscoverCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\PruneStaleTagsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ListFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\FlushFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ForgetFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ListenCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\MonitorCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\PauseCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\PruneBatchesCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\PruneFailedJobsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\RestartCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ResumeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\RetryCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\RetryBatchCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\WorkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ReloadCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RouteCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RouteClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RouteListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\DumpCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Seeds\\SeedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleFinishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleRunCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleClearCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleTestCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleWorkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleInterruptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\ShowModelCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\StorageLinkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\StorageUnlinkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\UpCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ViewCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ViewClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ApiInstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\BroadcastingInstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\CacheTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\CastMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ChannelListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ChannelMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ClassMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ComponentMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConsoleMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Routing\\Console\\ControllerMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\DocsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnumMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventGenerateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ExceptionMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Factories\\FactoryMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\InterfaceMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\JobMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\JobMiddlewareMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\LangPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ListenerMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\MailMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Routing\\Console\\MiddlewareMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ModelMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\NotificationMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Notifications\\Console\\NotificationTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ObserverMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\PolicyMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ProviderMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\FailedTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\TableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\BatchesTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RequestMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ResourceMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RuleMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ScopeMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Seeds\\SeederMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Session\\Console\\SessionTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ServeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\StubPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\TestMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\TraitMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\VendorPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ViewMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'migrator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'migration.repository' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'migration.creator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Migrations\\Migrator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\MigrateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\FreshCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\InstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\RefreshCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\ResetCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\RollbackCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\StatusCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\MigrateMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'composer' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Concurrency\\ConcurrencyManager' => 'Illuminate\\Concurrency\\ConcurrencyServiceProvider',
|
||||||
|
'hash' => 'Illuminate\\Hashing\\HashServiceProvider',
|
||||||
|
'hash.driver' => 'Illuminate\\Hashing\\HashServiceProvider',
|
||||||
|
'mail.manager' => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
'mailer' => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
'Illuminate\\Mail\\Markdown' => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
'auth.password' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
||||||
|
'auth.password.broker' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Pipeline\\Hub' => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
||||||
|
'pipeline' => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
||||||
|
'queue' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.connection' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.failer' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.listener' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.worker' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'redis' => 'Illuminate\\Redis\\RedisServiceProvider',
|
||||||
|
'redis.connection' => 'Illuminate\\Redis\\RedisServiceProvider',
|
||||||
|
'translator' => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
|
'translation.loader' => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
|
'validator' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
'validation.presence' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Validation\\UncompromisedVerifier' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\GeneratorCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\ModelsCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\MetaCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\EloquentCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Laravel\\Reverb\\ApplicationManager' => 'Laravel\\Reverb\\ApplicationManagerServiceProvider',
|
||||||
|
'Laravel\\Reverb\\Contracts\\ApplicationProvider' => 'Laravel\\Reverb\\ApplicationManagerServiceProvider',
|
||||||
|
'Laravel\\Sail\\Console\\InstallCommand' => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
'Laravel\\Sail\\Console\\PublishCommand' => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
'command.tinker' => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
|
),
|
||||||
|
'when' =>
|
||||||
|
array (
|
||||||
|
'Illuminate\\Broadcasting\\BroadcastServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Bus\\BusServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Cache\\CacheServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Concurrency\\ConcurrencyServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Hashing\\HashServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Mail\\MailServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Pipeline\\PipelineServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Queue\\QueueServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Redis\\RedisServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Translation\\TranslationServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Validation\\ValidationServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Laravel\\Reverb\\ApplicationManagerServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Laravel\\Sail\\SailServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Laravel\\Tinker\\TinkerServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
@ -11,16 +11,22 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"blade-ui-kit/blade-heroicons": "^2.6",
|
"blade-ui-kit/blade-heroicons": "^2.6",
|
||||||
|
"laravel-notification-channels/webpush": "^10.4",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/tinker": "^2.10.1"
|
"laravel/reverb": "^1.0",
|
||||||
|
"laravel/tinker": "^2.10.1",
|
||||||
|
"twilio/sdk": "^8.10"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"barryvdh/laravel-ide-helper": "^3.6",
|
||||||
"fakerphp/faker": "^1.23",
|
"fakerphp/faker": "^1.23",
|
||||||
|
"laradumps/laradumps": "^5.0",
|
||||||
"laravel/pail": "^1.2.2",
|
"laravel/pail": "^1.2.2",
|
||||||
"laravel/pint": "^1.24",
|
"laravel/pint": "^1.24",
|
||||||
"laravel/sail": "^1.41",
|
"laravel/sail": "^1.41",
|
||||||
"mockery/mockery": "^1.6",
|
"mockery/mockery": "^1.6",
|
||||||
"nunomaduro/collision": "^8.6",
|
"nunomaduro/collision": "^8.6",
|
||||||
|
"opcodesio/log-viewer": "^3.21",
|
||||||
"pestphp/pest": "^4.3",
|
"pestphp/pest": "^4.3",
|
||||||
"pestphp/pest-plugin-laravel": "^4.0"
|
"pestphp/pest-plugin-laravel": "^4.0"
|
||||||
},
|
},
|
||||||
|
|||||||
2398
composer.lock
generated
@ -111,5 +111,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
||||||
|
'otp_lifespan' => env('OTP_LIFESPAN', 10),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
82
config/broadcasting.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Broadcaster
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default broadcaster that will be used by the
|
||||||
|
| framework when an event needs to be broadcast. You may set this to
|
||||||
|
| any of the connections defined in the "connections" array below.
|
||||||
|
|
|
||||||
|
| Supported: "reverb", "pusher", "ably", "redis", "log", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('BROADCAST_CONNECTION', 'null'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Broadcast Connections
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define all of the broadcast connections that will be used
|
||||||
|
| to broadcast events to other systems or over WebSockets. Samples of
|
||||||
|
| each available type of connection are provided inside this array.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'connections' => [
|
||||||
|
|
||||||
|
'reverb' => [
|
||||||
|
'driver' => 'reverb',
|
||||||
|
'key' => env('REVERB_APP_KEY'),
|
||||||
|
'secret' => env('REVERB_APP_SECRET'),
|
||||||
|
'app_id' => env('REVERB_APP_ID'),
|
||||||
|
'options' => [
|
||||||
|
'host' => env('REVERB_HOST'),
|
||||||
|
'port' => env('REVERB_PORT', 443),
|
||||||
|
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||||
|
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||||
|
],
|
||||||
|
'client_options' => [
|
||||||
|
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'pusher' => [
|
||||||
|
'driver' => 'pusher',
|
||||||
|
'key' => env('PUSHER_APP_KEY'),
|
||||||
|
'secret' => env('PUSHER_APP_SECRET'),
|
||||||
|
'app_id' => env('PUSHER_APP_ID'),
|
||||||
|
'options' => [
|
||||||
|
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||||
|
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
||||||
|
'port' => env('PUSHER_PORT', 443),
|
||||||
|
'scheme' => env('PUSHER_SCHEME', 'https'),
|
||||||
|
'encrypted' => true,
|
||||||
|
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||||
|
],
|
||||||
|
'client_options' => [
|
||||||
|
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'ably' => [
|
||||||
|
'driver' => 'ably',
|
||||||
|
'key' => env('ABLY_KEY'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'log' => [
|
||||||
|
'driver' => 'log',
|
||||||
|
],
|
||||||
|
|
||||||
|
'null' => [
|
||||||
|
'driver' => 'null',
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
95
config/reverb.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Reverb Server
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default server used by Reverb to handle
|
||||||
|
| incoming messages as well as broadcasting message to all your
|
||||||
|
| connected clients. At this time only "reverb" is supported.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('REVERB_SERVER', 'reverb'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Reverb Servers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define details for each of the supported Reverb servers.
|
||||||
|
| Each server has its own configuration options that are defined in
|
||||||
|
| the array below. You should ensure all the options are present.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'servers' => [
|
||||||
|
|
||||||
|
'reverb' => [
|
||||||
|
'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
|
||||||
|
'port' => env('REVERB_SERVER_PORT', 8080),
|
||||||
|
'path' => env('REVERB_SERVER_PATH', ''),
|
||||||
|
'hostname' => env('REVERB_HOST'),
|
||||||
|
'options' => [
|
||||||
|
'tls' => [],
|
||||||
|
],
|
||||||
|
'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
|
||||||
|
'scaling' => [
|
||||||
|
'enabled' => env('REVERB_SCALING_ENABLED', false),
|
||||||
|
'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
|
||||||
|
'server' => [
|
||||||
|
'url' => env('REDIS_URL'),
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
|
'username' => env('REDIS_USERNAME'),
|
||||||
|
'password' => env('REDIS_PASSWORD'),
|
||||||
|
'database' => env('REDIS_DB', '0'),
|
||||||
|
'timeout' => env('REDIS_TIMEOUT', 60),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
|
||||||
|
'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Reverb Applications
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define how Reverb applications are managed. If you choose
|
||||||
|
| to use the "config" provider, you may define an array of apps which
|
||||||
|
| your server will support, including their connection credentials.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'apps' => [
|
||||||
|
|
||||||
|
'provider' => 'config',
|
||||||
|
|
||||||
|
'apps' => [
|
||||||
|
[
|
||||||
|
'key' => env('REVERB_APP_KEY'),
|
||||||
|
'secret' => env('REVERB_APP_SECRET'),
|
||||||
|
'app_id' => env('REVERB_APP_ID'),
|
||||||
|
'options' => [
|
||||||
|
'host' => env('REVERB_HOST'),
|
||||||
|
'port' => env('REVERB_PORT', 443),
|
||||||
|
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||||
|
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||||
|
],
|
||||||
|
'allowed_origins' => ['*'],
|
||||||
|
'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
|
||||||
|
'activity_timeout' => env('REVERB_APP_ACTIVITY_TIMEOUT', 30),
|
||||||
|
'max_connections' => env('REVERB_APP_MAX_CONNECTIONS'),
|
||||||
|
'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
@ -35,4 +35,10 @@
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'twilio' => [
|
||||||
|
'sid' => env('TWILIO_SID'),
|
||||||
|
'token' => env('TWILIO_AUTH_TOKEN'),
|
||||||
|
'from' => env('TWILIO_NUMBER'),
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
44
config/webpush.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are the keys for authentication (VAPID).
|
||||||
|
* These keys must be safely stored and should not change.
|
||||||
|
*/
|
||||||
|
'vapid' => [
|
||||||
|
'subject' => env('VAPID_SUBJECT'),
|
||||||
|
'public_key' => env('VAPID_PUBLIC_KEY'),
|
||||||
|
'private_key' => env('VAPID_PRIVATE_KEY'),
|
||||||
|
'pem_file' => env('VAPID_PEM_FILE'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is model that will be used to for push subscriptions.
|
||||||
|
*/
|
||||||
|
'model' => \NotificationChannels\WebPush\PushSubscription::class,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the name of the table that will be created by the migration and
|
||||||
|
* used by the PushSubscription model shipped with this package.
|
||||||
|
*/
|
||||||
|
'table_name' => env('WEBPUSH_DB_TABLE', 'push_subscriptions'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the database connection that will be used by the migration and
|
||||||
|
* the PushSubscription model shipped with this package.
|
||||||
|
*/
|
||||||
|
'database_connection' => env('WEBPUSH_DB_CONNECTION', env('DB_CONNECTION', 'mysql')),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Guzzle client options used by Minishlink\WebPush.
|
||||||
|
*/
|
||||||
|
'client_options' => [],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The automatic padding in bytes used by Minishlink\WebPush.
|
||||||
|
* Set to false to support Firefox Android with v1 endpoint.
|
||||||
|
*/
|
||||||
|
'automatic_padding' => env('WEBPUSH_AUTOMATIC_PADDING', true),
|
||||||
|
|
||||||
|
];
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Enums\UserTypes;
|
||||||
|
use App\Models\User;
|
||||||
|
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('page_visits', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignIdFor(User::class)->nullable();
|
||||||
|
$table->string('page');
|
||||||
|
$table->enum('user_type', UserTypes::values())->nullable();
|
||||||
|
$table->date('created_at')->useCurrent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('page_visits');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Deal;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('comments', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('text');
|
||||||
|
$table->foreignIdFor(Deal::class);
|
||||||
|
$table->foreignIdFor(User::class);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('comments');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Broker;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('follows', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignIdFor(Customer::class);
|
||||||
|
$table->foreignIdFor(Broker::class);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('follows');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::connection(config('webpush.database_connection'))->create(config('webpush.table_name'), function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->morphs('subscribable', 'push_subscriptions_subscribable_morph_idx');
|
||||||
|
$table->string('endpoint', 500)->unique();
|
||||||
|
$table->string('public_key')->nullable();
|
||||||
|
$table->string('auth_token')->nullable();
|
||||||
|
$table->string('content_encoding')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::connection(config('webpush.database_connection'))->dropIfExists(config('webpush.table_name'));
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
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('inboxes', function (Blueprint $table) {
|
||||||
|
$table->id()->index();
|
||||||
|
$table->text('last_message')->nullable();
|
||||||
|
$table->foreignIdFor(User::class, 'last_user_id')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->index(['last_user_id', 'created_at']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('inboxes');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Inbox;
|
||||||
|
use App\Models\User;
|
||||||
|
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('messages', function (Blueprint $table) {
|
||||||
|
$table->id()->index();
|
||||||
|
$table->foreignIdFor(User::class)->index();
|
||||||
|
$table->foreignIdFor(Inbox::class)->index();
|
||||||
|
$table->text('message');
|
||||||
|
$table->time('read_at')->nullable();
|
||||||
|
$table->time('delivered_at')->nullable();
|
||||||
|
$table->time('deleted_at')->nullable();
|
||||||
|
$table->time('failed_at')->nullable();
|
||||||
|
$table->timestamp('created_at')->useCurrent()->index();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('messages');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Inbox;
|
||||||
|
use App\Models\User;
|
||||||
|
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('inbox_user', function (Blueprint $table) {
|
||||||
|
$table->id()->index();
|
||||||
|
$table->foreignIdFor(Inbox::class)->index();
|
||||||
|
$table->foreignIdFor(User::class)->index();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('inbox_user');
|
||||||
|
}
|
||||||
|
};
|
||||||
22
database/seeders/CategorySeeder.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\DealCategory;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class CategorySeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<int, array{name: string, description: string, slug:string, active:bool, order:int}> $categories
|
||||||
|
*/
|
||||||
|
$categories = [
|
||||||
|
['name' => 'Food', 'description' => 'Share Food related deals', 'slug' => 'food', 'active' => true, 'order' => 1],
|
||||||
|
['name' => 'Real Estate', 'description' => 'Share Real Estate related deals', 'slug' => 'real-estate', 'active' => true, 'order' => 2],
|
||||||
|
['name' => 'Sell & Deal', 'description' => 'Sell your services', 'slug' => 'sell-and-deal', 'active' => true, 'order' => 3],
|
||||||
|
];
|
||||||
|
DealCategory::insert($categories);
|
||||||
|
}
|
||||||
|
}
|
||||||
182
package-lock.json
generated
@ -1,14 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "DealHub",
|
"name": "dealhub",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"chart.js": "^4.5.1"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
|
"laravel-echo": "^2.3.0",
|
||||||
"laravel-vite-plugin": "^2.0.0",
|
"laravel-vite-plugin": "^2.0.0",
|
||||||
|
"pusher-js": "^8.4.0",
|
||||||
"tailwindcss": "^4.0.0",
|
"tailwindcss": "^4.0.0",
|
||||||
"vite": "^7.0.7"
|
"vite": "^7.0.7"
|
||||||
}
|
}
|
||||||
@ -505,6 +510,12 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||||
|
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.55.1",
|
"version": "4.55.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz",
|
||||||
@ -855,6 +866,14 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@socket.io/component-emitter": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/node": {
|
"node_modules/@tailwindcss/node": {
|
||||||
"version": "4.1.18",
|
"version": "4.1.18",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
|
||||||
@ -1223,6 +1242,18 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
||||||
|
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cliui": {
|
"node_modules/cliui": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||||
@ -1296,6 +1327,25 @@
|
|||||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@ -1338,6 +1388,32 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/engine.io-client": {
|
||||||
|
"version": "6.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz",
|
||||||
|
"integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.4.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.18.3",
|
||||||
|
"xmlhttprequest-ssl": "~2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-parser": {
|
||||||
|
"version": "5.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||||
|
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.18.4",
|
"version": "5.18.4",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
|
||||||
@ -1675,6 +1751,20 @@
|
|||||||
"jiti": "lib/jiti-cli.mjs"
|
"jiti": "lib/jiti-cli.mjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/laravel-echo": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-wgHPnnBvfHmu2I58xJ4asZH37Nu6P0472ku6zuoGRLc3zEWwIbpovDLYTiOshDH1SM7rA6AjZTKuu+jYoM1tpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"pusher-js": "*",
|
||||||
|
"socket.io-client": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/laravel-vite-plugin": {
|
"node_modules/laravel-vite-plugin": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.1.tgz",
|
||||||
@ -1999,6 +2089,14 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.11",
|
"version": "3.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||||
@ -2074,6 +2172,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/pusher-js": {
|
||||||
|
"version": "8.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0.tgz",
|
||||||
|
"integrity": "sha512-wp3HqIIUc1GRyu1XrP6m2dgyE9MoCsXVsWNlohj0rjSkLf+a0jLvEyVubdg58oMk7bhjBWnFClgp8jfAa6Ak4Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": "^1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/require-directory": {
|
"node_modules/require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
@ -2152,6 +2260,38 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/socket.io-client": {
|
||||||
|
"version": "4.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz",
|
||||||
|
"integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.4.1",
|
||||||
|
"engine.io-client": "~6.6.1",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socket.io-parser": {
|
||||||
|
"version": "4.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
|
||||||
|
"integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
@ -2261,6 +2401,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "7.3.1",
|
"version": "7.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||||
@ -2378,6 +2525,39 @@
|
|||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.18.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||||
|
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xmlhttprequest-ssl": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||||
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|||||||
@ -10,8 +10,13 @@
|
|||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
|
"laravel-echo": "^2.3.0",
|
||||||
"laravel-vite-plugin": "^2.0.0",
|
"laravel-vite-plugin": "^2.0.0",
|
||||||
|
"pusher-js": "^8.4.0",
|
||||||
"tailwindcss": "^4.0.0",
|
"tailwindcss": "^4.0.0",
|
||||||
"vite": "^7.0.7"
|
"vite": "^7.0.7"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chart.js": "^4.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
public/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 15 KiB |
1
public/favicon.svg
Normal file
|
After Width: | Height: | Size: 45 KiB |
20
public/service-worker.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
self.addEventListener('push', function (e) {
|
||||||
|
if (!(self.Notification && self.Notification.permission === 'granted')) {
|
||||||
|
//notifications aren't supported or permission not granted!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.data) {
|
||||||
|
let msg = '';
|
||||||
|
try {
|
||||||
|
msg = e.data.json();
|
||||||
|
}catch (e){
|
||||||
|
msg = e.data;
|
||||||
|
}
|
||||||
|
console.log(msg)
|
||||||
|
e.waitUntil(self.registration.showNotification(msg.title, {
|
||||||
|
body: msg.body,
|
||||||
|
actions: msg.actions
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
21
public/site.webmanifest
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "MyWebSite",
|
||||||
|
"short_name": "MySite",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
1
public/vendor/log-viewer/app.css
vendored
Normal file
2
public/vendor/log-viewer/app.js
vendored
Normal file
33
public/vendor/log-viewer/app.js.LICENSE.txt
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*!
|
||||||
|
* The buffer module from node.js, for the browser.
|
||||||
|
*
|
||||||
|
* @author Feross Aboukhadijeh <http://feross.org>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* pinia v2.2.2
|
||||||
|
* (c) 2024 Eduardo San Martin Morote
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
|
|
||||||
|
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||||
|
|
||||||
|
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Lodash <https://lodash.com/>
|
||||||
|
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
|
||||||
|
* Released under MIT license <https://lodash.com/license>
|
||||||
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||||
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @vue/shared v3.4.38
|
||||||
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||||
|
* @license MIT
|
||||||
|
**/
|
||||||
BIN
public/vendor/log-viewer/img/log-viewer-128.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/vendor/log-viewer/img/log-viewer-32.png
vendored
Normal file
|
After Width: | Height: | Size: 526 B |
BIN
public/vendor/log-viewer/img/log-viewer-64.png
vendored
Normal file
|
After Width: | Height: | Size: 970 B |
7
public/vendor/log-viewer/mix-manifest.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"/app.js": "/app.js?id=b5eb6497b80ecd00237a857b35fcc1d6",
|
||||||
|
"/app.css": "/app.css?id=bf9e77abce3da8caacd004d57e4e8429",
|
||||||
|
"/img/log-viewer-128.png": "/img/log-viewer-128.png?id=d576c6d2e16074d3f064e60fe4f35166",
|
||||||
|
"/img/log-viewer-32.png": "/img/log-viewer-32.png?id=f8ec67d10f996aa8baf00df3b61eea6d",
|
||||||
|
"/img/log-viewer-64.png": "/img/log-viewer-64.png?id=8902d596fc883ca9eb8105bb683568c6"
|
||||||
|
}
|
||||||
BIN
public/web-app-manifest-192x192.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/web-app-manifest-512x512.png
Normal file
|
After Width: | Height: | Size: 91 KiB |