diff --git a/app/Livewire/ChangePassword.php b/app/Livewire/ChangePassword.php new file mode 100644 index 0000000..7db783b --- /dev/null +++ b/app/Livewire/ChangePassword.php @@ -0,0 +1,13 @@ +apiService = $apiService; + $this->cookieService = $cookieService; + } + + public function mount() + { + if (Session::get('isAuthenticated')) { + return redirect('/my-profile'); // Adjust based on role if needed + } + + try { + $contactResponse = $this->apiService->get('systemPreference/contact_details'); + $logoResponse = $this->apiService->get('systemPreference/logo'); + + $this->userEmail = $contactResponse['data']['value'] ?? ''; + $this->userLogo = $logoResponse['data']['value'] ?? ''; + $this->mounted = true; + } catch (\Exception $e) { + Log::error('Failed to load system preferences', ['error' => $e->getMessage(), 'source' => 'LoginComponent']); + } + } + + public function checkUser() + { + $this->isSubmitting = true; + $this->errors = []; + + try { + $this->validate([ + 'username' => ['required', 'regex:/^[A-Za-z0-9_@. ]+$/'], + ], [ + 'username.required' => 'Username is required!', + 'username.regex' => 'Invalid username.', + ]); + + $response = $this->apiService->post('/login_username', ['username' => $this->username]); + $this->userVerified = $response['data']['is_verified'] ?? false; + $this->role = $response['data']['role'] ?? null; + } catch (\Illuminate\Validation\ValidationException $e) { + $this->errors = $e->errors(); + } catch (\Exception $e) { + $this->errors['username'] = [$e->getMessage()]; + Log::error('Username check failed', ['error' => $e->getMessage(), 'source' => 'LoginComponent']); + } finally { + $this->isSubmitting = false; + } + } + + public function login() + { + $this->isSubmitting = true; + $this->errors = []; + + try { + $this->validate([ + 'password' => ['required'], + ], [ + 'password.required' => 'Password is required!', + ]); + + $response = $this->apiService->post('/login_password', [ + 'username' => $this->username, + 'password' => $this->password, + ]); + + if (isset($response['data']['prompt_password']) && $response['data']['prompt_password']) { + return redirect()->route('change-password', [ + 'username' => $this->username, + 'admin_uuid' => $response['data']['admin_uuid'], + 'password' => $this->password, + ]); + } + + if (isset($response['data']['token'])) { + $token = $response['data']['token']; + $this->cookieService->setCookie(['token' => $token], 'TOKEN'); + Session::put('isAuthenticated', true); + + $profileResponse = $this->apiService->post('adminProfile'); + $userInfo = $profileResponse['data']; + Session::put('userInfo', $userInfo); + + Log::info('Login successful', ['source' => 'LoginComponent']); + return redirect('/my-profile'); // Adjust based on role if needed + } + } catch (\Illuminate\Validation\ValidationException $e) { + $this->errors = $e->errors(); + } catch (\Exception $e) { + $this->errors['password'] = [$e->getMessage()]; + Log::error('Login failed', ['error' => $e->getMessage(), 'source' => 'LoginComponent']); + } finally { + $this->isSubmitting = false; + } + } + + public function showModalForgotUsername() + { + $this->isModalVisible = true; + $this->forgotUsername = true; + } + + public function showModalChangePassword() + { + $this->isModalVisible = true; + $this->forgotUsername = false; + } + + public function hideModal() + { + $this->isModalVisible = false; + } + + public function backToLogin() + { + $this->username = ''; + $this->password = ''; + $this->userVerified = false; + } + + public function render() + { + if (!$this->mounted) { + return null; + } + + return view('livewire.login')->layout('layouts.app', ['title' => 'Login Page']); + } +} \ No newline at end of file diff --git a/app/Livewire/LoginTest.php b/app/Livewire/LoginTest.php new file mode 100644 index 0000000..6e6bc2e --- /dev/null +++ b/app/Livewire/LoginTest.php @@ -0,0 +1,17 @@ +assertSee('Login'); // Check if "Login" text is rendered + } +} \ No newline at end of file diff --git a/app/Livewire/PublicTopErrorPage.php b/app/Livewire/PublicTopErrorPage.php new file mode 100644 index 0000000..2be7e87 --- /dev/null +++ b/app/Livewire/PublicTopErrorPage.php @@ -0,0 +1,27 @@ +is('iOS')) { + // Trigger iOS native handler + $this->dispatchBrowserEvent('ios-top-up-failed'); + } elseif ($agent->is('Android')) { + // Trigger Android native handler + $this->dispatchBrowserEvent('android-top-up-failed'); + } + } + + public function render() + { + return view('livewire.public-top-error-page')->layout('layouts.app'); + } +} \ No newline at end of file diff --git a/app/Livewire/PublicTopSuccessPage.php b/app/Livewire/PublicTopSuccessPage.php new file mode 100644 index 0000000..8da55f4 --- /dev/null +++ b/app/Livewire/PublicTopSuccessPage.php @@ -0,0 +1,90 @@ +apiService = $apiService; + } + + public function mount() + { + $this->loading = true; + + // Get query parameters from the request + $this->paymentId = request()->query('paymentId'); + $this->token = request()->query('token'); + $this->payerId = request()->query('PayerID'); + + $payload = [ + 'paymentId' => $this->paymentId, + 'token' => $this->token, + 'PayerID' => $this->payerId, + ]; + + try { + $response = $this->apiService->post('paypalExecute', $payload); + + if ($response && isset($response['status']) && $response['status'] === 200) { + $this->status = 200; + $this->userInfo = $response['data']; + Log::info('Top-up success', ['source' => 'PublicTopSuccessPage']); + } + } catch (\Exception $e) { + $this->status = $e->getCode() ?: 500; + $this->message = $e->getMessage(); + Log::error('Top-up failed', ['error' => $e->getMessage(), 'source' => 'PublicTopSuccessPage']); + } finally { + $this->loading = false; + } + } + + public function backHandler() + { + $agent = new Agent(); + + if ($agent->is('iOS')) { + // Trigger iOS native handler + $this->dispatchBrowserEvent('ios-top-up-failed'); + } elseif ($agent->is('Android')) { + // Trigger Android native handler + $this->dispatchBrowserEvent('android-top-up-failed'); + } + } + + public function backHandlerSuccess() + { + $agent = new Agent(); + + if ($agent->is('iOS')) { + // Trigger iOS native handler + $this->dispatchBrowserEvent('ios-top-up-success'); + } elseif ($agent->is('Android')) { + // Trigger Android native handler (corrected from Failed to Success) + $this->dispatchBrowserEvent('android-top-up-success'); + } + } + + public function render() + { + return view('livewire.public-top-success-page')->layout('layouts.app'); + } +} \ No newline at end of file diff --git a/app/Livewire/Registration.php b/app/Livewire/Registration.php new file mode 100644 index 0000000..abc481d --- /dev/null +++ b/app/Livewire/Registration.php @@ -0,0 +1,101 @@ +apiService = $apiService; + } + + public function mount() + { + if (Session::get('isRegistered')) { + return redirect()->route('login'); + } + } + + public function register() + { + $this->isSubmitting = true; + $this->status = 'loading'; + $this->errors = []; + + try { + $this->validate([ + 'email' => ['required', 'email'], + 'password' => ['required'], + 'confirm_password' => ['required', Rule::in([$this->password])], + 'first_name' => ['required'], + 'middle_name' => ['required'], + 'last_name' => ['required'], + 'website' => ['required'], + ], [ + 'email.required' => 'Email is required.', + 'email.email' => 'Invalid Email address.', + 'password.required' => 'Password is required.', + 'confirm_password.required' => 'Confirm password is required.', + 'confirm_password.in' => 'Passwords do not match.', + 'first_name.required' => 'First name is required.', + 'middle_name.required' => 'Middle name is required.', + 'last_name.required' => 'Last name is required.', + 'website.required' => 'Website is required.', + ]); + + $data = [ + 'email' => $this->email, + 'password' => $this->password, + 'first_name' => $this->first_name, + 'middle_name' => $this->middle_name, + 'last_name' => $this->last_name, + 'website' => $this->website, + ]; + + $response = $this->apiService->post('/register', $data); + + if ($response && isset($response['status']) && $response['status'] === 201) { + $this->status = 'success'; + $this->isRegistered = true; + Session::put('isRegistered', true); + Session::flash('success', 'Registration successful.'); + return redirect()->route('login'); + } + } catch (\Illuminate\Validation\ValidationException $e) { + $this->status = 'error'; + $this->errors = $e->errors(); + Log::error('Registration validation failed', ['errors' => $this->errors, 'source' => 'RegistrationComponent']); + } catch (\Exception $e) { + $this->status = 'error'; + Session::flash('error', 'Something went wrong: ' . $e->getMessage()); + Log::error('Registration failed', ['error' => $e->getMessage(), 'source' => 'RegistrationComponent']); + } finally { + $this->isSubmitting = false; + } + } + + public function render() + { + return view('livewire.registration')->layout('layouts.app'); + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 192f45c..d80d8cc 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "require": { "php": "^8.2", "guzzlehttp/guzzle": "^7.9", + "jenssegers/agent": "^2.6", "laravel/framework": "^11.31", "laravel/tinker": "^2.9", "laravel/ui": "^4.6", diff --git a/composer.lock b/composer.lock index bfce4c2..51cf3e6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "76604e550276fef9afccacf4143ff3aa", + "content-hash": "a76eb60c479c8d60dd14c1dc914f137b", "packages": [ { "name": "brick/math", @@ -1054,6 +1054,141 @@ ], "time": "2025-02-03T10:55:03+00:00" }, + { + "name": "jaybizzle/crawler-detect", + "version": "v1.3.4", + "source": { + "type": "git", + "url": "https://github.com/JayBizzle/Crawler-Detect.git", + "reference": "d3b7ff28994e1b0de764ab7412fa269a79634ff3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/d3b7ff28994e1b0de764ab7412fa269a79634ff3", + "reference": "d3b7ff28994e1b0de764ab7412fa269a79634ff3", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.5|^6.5|^9.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jaybizzle\\CrawlerDetect\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Beech", + "email": "m@rkbee.ch", + "role": "Developer" + } + ], + "description": "CrawlerDetect is a PHP class for detecting bots/crawlers/spiders via the user agent", + "homepage": "https://github.com/JayBizzle/Crawler-Detect/", + "keywords": [ + "crawler", + "crawler detect", + "crawler detector", + "crawlerdetect", + "php crawler detect" + ], + "support": { + "issues": "https://github.com/JayBizzle/Crawler-Detect/issues", + "source": "https://github.com/JayBizzle/Crawler-Detect/tree/v1.3.4" + }, + "time": "2025-03-05T23:12:10+00:00" + }, + { + "name": "jenssegers/agent", + "version": "v2.6.4", + "source": { + "type": "git", + "url": "https://github.com/jenssegers/agent.git", + "reference": "daa11c43729510b3700bc34d414664966b03bffe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jenssegers/agent/zipball/daa11c43729510b3700bc34d414664966b03bffe", + "reference": "daa11c43729510b3700bc34d414664966b03bffe", + "shasum": "" + }, + "require": { + "jaybizzle/crawler-detect": "^1.2", + "mobiledetect/mobiledetectlib": "^2.7.6", + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5.0|^6.0|^7.0" + }, + "suggest": { + "illuminate/support": "Required for laravel service providers" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Agent": "Jenssegers\\Agent\\Facades\\Agent" + }, + "providers": [ + "Jenssegers\\Agent\\AgentServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Jenssegers\\Agent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jens Segers", + "homepage": "https://jenssegers.com" + } + ], + "description": "Desktop/mobile user agent parser with support for Laravel, based on Mobiledetect", + "homepage": "https://github.com/jenssegers/agent", + "keywords": [ + "Agent", + "browser", + "desktop", + "laravel", + "mobile", + "platform", + "user agent", + "useragent" + ], + "support": { + "issues": "https://github.com/jenssegers/agent/issues", + "source": "https://github.com/jenssegers/agent/tree/v2.6.4" + }, + "funding": [ + { + "url": "https://github.com/jenssegers", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/jenssegers/agent", + "type": "tidelift" + } + ], + "time": "2020-06-13T08:05:20+00:00" + }, { "name": "laravel/framework", "version": "v11.44.2", @@ -2145,6 +2280,68 @@ ], "time": "2025-03-12T20:24:15+00:00" }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.45", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "reference": "96aaebcf4f50d3d2692ab81d2c5132e425bca266", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.36" + }, + "type": "library", + "autoload": { + "psr-0": { + "Detection": "namespaced/" + }, + "classmap": [ + "Mobile_Detect.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "support": { + "issues": "https://github.com/serbanghita/Mobile-Detect/issues", + "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.45" + }, + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "time": "2023-11-07T21:57:25+00:00" + }, { "name": "monolog/monolog", "version": "3.9.0", diff --git a/resources/css/app.css b/resources/css/app.css index 32d4f96..426aeea 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,4 +1,101 @@ @tailwind base; @tailwind components; @tailwind utilities; +/* Import Bootstrap */ @import 'bootstrap/dist/css/bootstrap.min.css'; + +/* General styles */ +#root { + height: 100%; + overflow: hidden; +} + +/* Custom colors and hover effects */ +:root { + --primary-color: #e74610; /* Replace Ant Design's orange */ + --hover-bg: rgba(231, 70, 16, 0.1); +} + +/* Menu styles (adapt for Bootstrap navbar or custom sidebar) */ +.nav-link:hover, +.nav-link.active { + color: var(--primary-color) !important; +} + +.nav-item:hover { + background-color: var(--hover-bg) !important; +} + +/* Scrollbar styles */ +::-webkit-scrollbar { + width: 12px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar-track { + border-radius: 10px; + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + background-color: #f5f5f5; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + background-color: #b8bbc9; +} + +/* Form and button styles */ +.form-control:disabled { + cursor: text !important; +} + +.btn-sm { + padding: 0 20px !important; + height: 27px !important; +} + +/* Breadcrumb (Bootstrap equivalent) */ +.breadcrumb-item a:hover { + color: var(--primary-color) !important; +} + +.breadcrumb-item:last-child a { + color: #4d4d4d; + font-weight: 500; + opacity: 0.85; +} + +/* Custom terms management (adapt for your UI) */ +.terms-management { + position: absolute; + left: -42px; +} + +.terms-management-parent { + position: relative; + left: -30px; +} + +.terms-management-parent .terms-management { + position: relative; + left: 37px; + border-color: var(--primary-color) !important; + background: var(--primary-color); + width: 100px; + color: #fff; + text-align: right; +} + +.terms-management-parent .btn:hover, +.terms-management-parent .btn:focus { + background: var(--primary-color); + color: #fff; +} + +/* Responsive design */ +@media only screen and (max-width: 480px) { + .app-container { + position: fixed; + width: 100%; + } +} \ No newline at end of file diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index e8e2ec0..721de20 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -3,11 +3,16 @@
-
+ Transaction Failed.
+ Your purchase for top-up is not
successful. Please try again.
+
+ Your purchase for top-up points
is successful!
+
+ Transaction Failed.
{{ $message }}
+