diff --git a/app/Actions/PasswordReset/VerifyOTPAction.php b/app/Actions/PasswordReset/VerifyOTPAction.php index c9223c9..b0b0cb6 100644 --- a/app/Actions/PasswordReset/VerifyOTPAction.php +++ b/app/Actions/PasswordReset/VerifyOTPAction.php @@ -20,11 +20,6 @@ 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')); - $isVerified = $this->otpService->verify($user, $data['otp']); - if ($isVerified) { - \Session::forget('otp_user_id'); - } - - return $isVerified; + return $this->otpService->verify($user, $data['otp']); } } diff --git a/app/Http/Controllers/Auth/PasswordResetController.php b/app/Http/Controllers/Auth/PasswordResetController.php index 37f7f80..1d1fe1f 100644 --- a/app/Http/Controllers/Auth/PasswordResetController.php +++ b/app/Http/Controllers/Auth/PasswordResetController.php @@ -46,7 +46,7 @@ public function verify(Request $request, VerifyOTPAction $otpAction) $data = $request->validate(['otp' => 'required|string:min:5:max:6']); try { $isVerified = $otpAction->execute($data); - if (! $isVerified) { + if (!$isVerified) { return back()->with('error', 'Invalid OTP'); } @@ -66,12 +66,14 @@ public function update(Request $request) $data = $request->validate([ 'password' => 'required', 'confirmed', Password::min(8)->letters()->mixedCase()->numbers()->symbols(), ]); - $user = User::find(Session::get('user_id')); - if (! $user) { + $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'); } diff --git a/app/Http/Controllers/Broker/BrokerDashboardController.php b/app/Http/Controllers/Broker/BrokerDashboardController.php index 546326b..d193c09 100644 --- a/app/Http/Controllers/Broker/BrokerDashboardController.php +++ b/app/Http/Controllers/Broker/BrokerDashboardController.php @@ -33,7 +33,6 @@ protected function deals() ->WithLikePerDeal() ->WithRedirectionPerDeal() ->withViewPerDeal() - ->latest() - ->paginate(); + ->latest()->take(3)->get(); } } diff --git a/app/Http/Controllers/Broker/BrokerDealController.php b/app/Http/Controllers/Broker/BrokerDealController.php index f22e0ec..623551a 100644 --- a/app/Http/Controllers/Broker/BrokerDealController.php +++ b/app/Http/Controllers/Broker/BrokerDealController.php @@ -7,6 +7,7 @@ use App\Models\Deal; use App\Models\DealCategory; use App\Services\FileService; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; @@ -18,7 +19,8 @@ class BrokerDealController extends Controller */ 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::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) { 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) { 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); } } diff --git a/app/Http/Controllers/ContactController.php b/app/Http/Controllers/ContactController.php new file mode 100644 index 0000000..32939b4 --- /dev/null +++ b/app/Http/Controllers/ContactController.php @@ -0,0 +1,24 @@ +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.'); + } + } +} diff --git a/app/Http/Requests/ContactRequest.php b/app/Http/Requests/ContactRequest.php new file mode 100644 index 0000000..749558e --- /dev/null +++ b/app/Http/Requests/ContactRequest.php @@ -0,0 +1,34 @@ +|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'; + } +} diff --git a/app/Notifications/NewContactNotification.php b/app/Notifications/NewContactNotification.php new file mode 100644 index 0000000..78def0e --- /dev/null +++ b/app/Notifications/NewContactNotification.php @@ -0,0 +1,39 @@ +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);; + } + +} diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..6689503 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon-96x96.png b/public/favicon-96x96.png new file mode 100644 index 0000000..bdd0b53 Binary files /dev/null and b/public/favicon-96x96.png differ diff --git a/public/favicon.ico b/public/favicon.ico index e69de29..4852031 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..44e38ac --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 0000000..ccf313a --- /dev/null +++ b/public/site.webmanifest @@ -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" +} \ No newline at end of file diff --git a/public/web-app-manifest-192x192.png b/public/web-app-manifest-192x192.png new file mode 100644 index 0000000..2b59f16 Binary files /dev/null and b/public/web-app-manifest-192x192.png differ diff --git a/public/web-app-manifest-512x512.png b/public/web-app-manifest-512x512.png new file mode 100644 index 0000000..d77a219 Binary files /dev/null and b/public/web-app-manifest-512x512.png differ diff --git a/resources/js/deal-view-modal.js b/resources/js/deal-view-modal.js index 05868ea..b6e23df 100644 --- a/resources/js/deal-view-modal.js +++ b/resources/js/deal-view-modal.js @@ -13,13 +13,13 @@ export async function showDealModal(dealId) { showModal('deal-modal'); - toggleShimmer(true, dealModal); + toggleShimmer(false, dealModal); try { const response = await axios.get('/api/deals/' + dealId); setDealDetails(response.data); - toggleShimmer(false, dealModal); + toggleShimmer(true, dealModal); dealModal.dataset.dealId = dealId; await axios.post(`/api/view/${dealId}`); diff --git a/resources/views/components/dashboard/broker/listing.blade.php b/resources/views/components/dashboard/broker/listing.blade.php index 0730fac..aaf10d5 100644 --- a/resources/views/components/dashboard/broker/listing.blade.php +++ b/resources/views/components/dashboard/broker/listing.blade.php @@ -1,5 +1,5 @@ @props(['deals' => []]) -
+

My Listings

@@ -9,5 +9,10 @@

No Deals created

@endforelse
+
+ + See more + +
diff --git a/resources/views/components/dashboard/user/recent-search/recent-search-item.blade.php b/resources/views/components/dashboard/user/recent-search/recent-search-item.blade.php index f891fad..c5d6516 100644 --- a/resources/views/components/dashboard/user/recent-search/recent-search-item.blade.php +++ b/resources/views/components/dashboard/user/recent-search/recent-search-item.blade.php @@ -1,7 +1,7 @@ @props(['item'])
  • + href="{{route('explore', ['search' => $item->query])}}"> {{$item->query}} diff --git a/resources/views/components/footer.blade.php b/resources/views/components/footer.blade.php index 5df8f54..742977f 100644 --- a/resources/views/components/footer.blade.php +++ b/resources/views/components/footer.blade.php @@ -51,18 +51,18 @@ class="fill-[#BDC1D2]"/>

    For Brokers

    diff --git a/resources/views/components/get-in-touch.blade.php b/resources/views/components/get-in-touch.blade.php index 1d19df6..de6959b 100644 --- a/resources/views/components/get-in-touch.blade.php +++ b/resources/views/components/get-in-touch.blade.php @@ -1,15 +1,14 @@ -
    +

    Get In Touch

    Have questions? We'd love it hear from you. Send us a message and we'll respond
    as soon as possible.

    -
    -
    - + + @csrf diff --git a/resources/views/components/hero.blade.php b/resources/views/components/hero.blade.php index ab51f0b..1030592 100644 --- a/resources/views/components/hero.blade.php +++ b/resources/views/components/hero.blade.php @@ -1,4 +1,14 @@ -
    +
    + +
    + @session('success') + {{$value}} + @endsession + + @session('error') + {{$value}} + @endsession +
    diff --git a/resources/views/components/impersonate-alert.blade.php b/resources/views/components/impersonate-alert.blade.php index ce260e6..d52b76d 100644 --- a/resources/views/components/impersonate-alert.blade.php +++ b/resources/views/components/impersonate-alert.blade.php @@ -1,4 +1,4 @@ -
    +
    You are impersonating as {{session()->get('impersonate_name', 'a User')}} diff --git a/resources/views/components/layout.blade.php b/resources/views/components/layout.blade.php index ad58404..6412aa3 100644 --- a/resources/views/components/layout.blade.php +++ b/resources/views/components/layout.blade.php @@ -14,7 +14,12 @@ {{ $pageTitle }} - + + + + + + diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 0b7e21b..627fbcc 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -9,8 +9,8 @@
      - - + +
    diff --git a/resources/views/components/why-dealhub.blade.php b/resources/views/components/why-dealhub.blade.php index c578cf2..b42e9a3 100644 --- a/resources/views/components/why-dealhub.blade.php +++ b/resources/views/components/why-dealhub.blade.php @@ -1,4 +1,4 @@ -
    +

    Why Choose {{config('app.name')}}?

    A trusted platform connecting you with verified experts who share the best deals,
    diff --git a/resources/views/dashboards/broker/deals/index.blade.php b/resources/views/dashboards/broker/deals/index.blade.php new file mode 100644 index 0000000..43aecf8 --- /dev/null +++ b/resources/views/dashboards/broker/deals/index.blade.php @@ -0,0 +1,22 @@ + + + + +

    + +

    My Deals

    +
    + @forelse($deals as $deal) + + @empty +

    No Deals created

    + @endforelse +
    + {{ $deals->links() }} +
    +
    + + diff --git a/routes/web.php b/routes/web.php index 5322ea5..0fec1e6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,6 @@ name('home'); Route::get('/explore', ExplorePageController::class)->name('explore'); - +Route::post('/contact', ContactController::class)->name('contact'); /** * This routes are accessed by JS XHR requests, and is loaded here cause * we do not want to use sanctum for web requests diff --git a/routes/web/auth.php b/routes/web/auth.php index 0f60b23..d0f0498 100644 --- a/routes/web/auth.php +++ b/routes/web/auth.php @@ -13,7 +13,7 @@ ->only(['create', 'store']); Route::resource('/register', RegisteredUserController::class)->only(['create', 'store']); - Route::prefix('password/reset')->name('password.reset.')->middleware('throttle:20,1')->group(function () { + Route::prefix('password/reset')->name('password.reset.')->middleware('throttle:30,1')->group(function () { Route::controller(PasswordResetController::class)->group(function () { Route::get('/', 'show')->name('show');