converting login reactjs codes to laravel php using livewire
This commit is contained in:
parent
deb9afe175
commit
041518c8cb
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class ChangePassword extends Component
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.change-password');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Services\ApiService;
|
||||
use App\Services\CookieService;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Login extends Component
|
||||
{
|
||||
public $username = '';
|
||||
public $password = '';
|
||||
public $isSubmitting = false;
|
||||
public $userVerified = false;
|
||||
public $isModalVisible = false;
|
||||
public $forgotUsername = false;
|
||||
public $userEmail = '';
|
||||
public $userLogo = '';
|
||||
public $mounted = false;
|
||||
public $role = null;
|
||||
public $errors = [];
|
||||
|
||||
protected $apiService;
|
||||
protected $cookieService;
|
||||
|
||||
public function boot(ApiService $apiService, CookieService $cookieService)
|
||||
{
|
||||
$this->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']);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Livewire;
|
||||
|
||||
use Livewire\Livewire;
|
||||
use Tests\TestCase;
|
||||
use App\Livewire\Login;
|
||||
|
||||
class LoginTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function it_renders_without_crashing()
|
||||
{
|
||||
Livewire::test(Login::class)
|
||||
->assertSee('Login'); // Check if "Login" text is rendered
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use Jenssegers\Agent\Agent;
|
||||
|
||||
class PublicTopErrorPage extends Component
|
||||
{
|
||||
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 render()
|
||||
{
|
||||
return view('livewire.public-top-error-page')->layout('layouts.app');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Services\ApiService;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Jenssegers\Agent\Agent;
|
||||
|
||||
class PublicTopSuccessPage extends Component
|
||||
{
|
||||
public $loading = false;
|
||||
public $status = '';
|
||||
public $userInfo = null;
|
||||
public $message = '';
|
||||
public $paymentId = '';
|
||||
public $token = '';
|
||||
public $payerId = '';
|
||||
|
||||
protected $apiService;
|
||||
|
||||
public function boot(ApiService $apiService)
|
||||
{
|
||||
$this->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');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Services\ApiService;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class Registration extends Component
|
||||
{
|
||||
public $email = '';
|
||||
public $password = '';
|
||||
public $confirm_password = '';
|
||||
public $first_name = '';
|
||||
public $middle_name = '';
|
||||
public $last_name = '';
|
||||
public $website = '';
|
||||
public $isSubmitting = false;
|
||||
public $status = '';
|
||||
public $errors = [];
|
||||
public $isRegistered = false;
|
||||
|
||||
protected $apiService;
|
||||
|
||||
public function boot(ApiService $apiService)
|
||||
{
|
||||
$this->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');
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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%;
|
||||
}
|
||||
}
|
|
@ -3,11 +3,16 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Laravel</title>
|
||||
<title>Unioil - @yield('title')</title>
|
||||
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
|
||||
@if(app()->environment('local'))
|
||||
<script>
|
||||
localStorage.setItem('debug', 'awesome-react-app:*');
|
||||
</script>
|
||||
@endif
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<div id="root" class="app-container h-100">
|
||||
@yield('content')
|
||||
</div>
|
||||
<script src="{{ asset('js/app.js') }}"></script>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
{{-- Close your eyes. Count to one. That is how long forever feels. --}}
|
||||
</div>
|
|
@ -0,0 +1,75 @@
|
|||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="text-center mt-5 mb-4">
|
||||
<img src="{{ asset('images/logo_unioil.png') }}" alt="Unioil Logo" style="max-width: 200px;">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<h1 class="mb-0">Welcome</h1>
|
||||
@if(!$userVerified)
|
||||
<span style="font-size: 12px;">Sign in to continue</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<form wire:submit.prevent="{{ $userVerified ? 'login' : 'checkUser' }}">
|
||||
<div class="mb-3 position-relative">
|
||||
@if(!$userVerified)
|
||||
<label class="form-label fw-medium" style="color: #005598;">Enter Username</label>
|
||||
<input type="text" class="form-control @error('username') is-invalid @enderror" wire:model="username" placeholder="User name" readonly="{{ $userVerified ? 'true' : 'false' }}">
|
||||
@error('username') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
@else
|
||||
<div class="d-flex align-items-center bg-light border rounded p-2 mb-3" style="border-color: #d9d9d9;">
|
||||
<span class="input-group-text bg-transparent border-0"><i class="bi bi-person"></i></span>
|
||||
<span class="flex-grow-1 text-muted">{{ $username }}</span>
|
||||
<button type="button" wire:click="backToLogin" class="btn btn-link p-0 text-muted"><i class="bi bi-x"></i></button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if($userVerified)
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium" style="color: #005598;">Enter Password</label>
|
||||
<input type="password" class="form-control @error('password') is-invalid @enderror" wire:model="password" placeholder="Password">
|
||||
@error('password') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-6">
|
||||
@if($userVerified)
|
||||
<a href="#" wire:click="showModalChangePassword" style="color: #005598;">Forgot Password</a>
|
||||
@else
|
||||
<a href="#" wire:click="showModalForgotUsername" style="color: #005598;">Forgot Username</a>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
<button type="submit" class="btn btn-primary w-100" wire:loading.attr="disabled" wire:target="{{ $userVerified ? 'login' : 'checkUser' }}" style="background-color: {{ $userVerified ? ($password ? '#E74610' : '#FCFCFC') : ($username ? '#E74610' : '#FCFCFC') }}; border-color: {{ $userVerified ? ($password ? '#E74610' : '#D9D9D9') : ($username ? '#E74610' : '#D9D9D9') }};" {{ $userVerified ? ($password ? '' : 'disabled') : ($username ? '' : 'disabled') }}>
|
||||
<span wire:loading wire:target="{{ $userVerified ? 'login' : 'checkUser' }}">Processing...</span>
|
||||
<span wire:loading.remove wire:target="{{ $userVerified ? 'login' : 'checkUser' }}">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Modal -->
|
||||
@if($isModalVisible)
|
||||
<div class="modal fade show d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
|
||||
<div class="modal-dialog modal-dialog-centered" style="max-width: 337px;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<h4>Forgot {{ $forgotUsername ? 'Username' : 'Password' }}</h4>
|
||||
<p>
|
||||
To have your {{ $forgotUsername ? 'username' : 'password' }} reset, please contact <br>
|
||||
Unioil's admin at <a href="mailto:{{ $userEmail }}" style="color: #005598;">{{ $userEmail }}</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer justify-content-end">
|
||||
<button wire:click="hideModal" class="btn btn-primary" style="background-color: #E74610; border-color: #E74610; width: 64px;">Ok</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,29 @@
|
|||
<div class="container position-relative" style="min-height: 100vh;">
|
||||
<div class="text-center position-absolute top-0 start-50 translate-middle-x mt-4">
|
||||
<img src="{{ asset('images/ic_error.svg') }}" alt="Error" style="width: 24vmin;">
|
||||
<p class="mt-3" style="line-height: 7vmin; font-size: 6vmin; font-weight: bold; color: #4D4D4D;">
|
||||
Transaction Failed.<br>
|
||||
Your purchase for top-up is not <br>successful. Please try again.
|
||||
</p>
|
||||
</div>
|
||||
<div class="position-absolute bottom-0 start-50 translate-middle-x mb-4" style="width: 100%; max-width: 300px;">
|
||||
<button wire:click="backHandler" class="btn btn-primary w-100" style="height: 11vmin; font-size: 5vmin; background-color: #e74610; border-color: #e74610;">
|
||||
Return to Top-Up Page
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- JavaScript for native app integration -->
|
||||
<script>
|
||||
window.addEventListener('ios-top-up-failed', function () {
|
||||
if (typeof window.iOStopUpFailed === 'function') {
|
||||
window.iOStopUpFailed();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('android-top-up-failed', function () {
|
||||
if (typeof window.AndroidTopUpFailed === 'function') {
|
||||
window.AndroidTopUpFailed();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
|
@ -0,0 +1,86 @@
|
|||
<div class="container position-relative" style="min-height: 100vh;">
|
||||
@if($loading)
|
||||
<div class="text-center position-absolute top-50 start-50 translate-middle" style="font-size: 6vmin;">
|
||||
<div class="spinner-border text-primary" role="status"></div>
|
||||
<span class="ms-2">Loading Top-Up Please wait...</span>
|
||||
</div>
|
||||
@else
|
||||
<div class="mt-5">
|
||||
@if($status == 200)
|
||||
<div class="text-center position-absolute top-0 start-50 translate-middle-x mt-4">
|
||||
<img src="{{ asset('images/ic_success.svg') }}" alt="Success" style="width: 18vmin;">
|
||||
<p class="mt-3" style="line-height: 7vmin; font-size: 6vmin; font-weight: bold;">
|
||||
Your purchase for top-up points <br> is successful!
|
||||
</p>
|
||||
<div style="font-size: 15px; font-weight: 400;">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<span style="font-size: 6vmin; font-weight: bold;">{{ $userInfo['date'] ?? '' }}</span>
|
||||
</div>
|
||||
<div class="col-12">Card Number: {{ $userInfo['card_number'] ?? '' }}</div>
|
||||
<div class="col-12">Sales Invoice Number: {{ $userInfo['invoice'] ?? '' }}</div>
|
||||
</div>
|
||||
<div class="mt-3" style="font-size: 3.5vmin;">
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-6 text-start">Top-up Points Value</div>
|
||||
<div class="col-6 text-end">{{ $userInfo['points'] ?? '' }}</div>
|
||||
</div>
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-6 text-start">Payment Value</div>
|
||||
<div class="col-6 text-end">Php {{ $userInfo['payment_val'] ?? '' }}</div>
|
||||
</div>
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-6 text-start">Paypal Fee</div>
|
||||
<div class="col-6 text-end">Php {{ $userInfo['paypal_fee'] ?? '' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="position-absolute bottom-0 start-50 translate-middle-x mb-4" style="width: 100%; max-width: 300px;">
|
||||
<button wire:click="backHandlerSuccess" class="btn btn-primary w-100" style="height: 11vmin; font-size: 5vmin; background-color: #e74610; border-color: #e74610;">
|
||||
Return to Home Page
|
||||
</button>
|
||||
</div>
|
||||
@else
|
||||
<div class="text-center position-absolute top-0 start-50 translate-middle-x mt-4">
|
||||
<img src="{{ asset('images/ic_error.svg') }}" alt="Error" style="width: 24vmin;">
|
||||
<p class="mt-3" style="line-height: 7vmin; font-size: 5vmin; font-weight: bold; color: #4D4D4D;">
|
||||
Transaction Failed.<br>{{ $message }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="position-absolute bottom-0 start-50 translate-middle-x mb-4" style="width: 100%; max-width: 300px;">
|
||||
<button wire:click="backHandler" class="btn btn-primary w-100" style="height: 11vmin; font-size: 5vmin; background-color: #e74610; border-color: #e74610;">
|
||||
Return to Top-Up Page
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- JavaScript for native app integration -->
|
||||
<script>
|
||||
window.addEventListener('ios-top-up-success', function () {
|
||||
if (typeof window.iOStopUpSuccess === 'function') {
|
||||
window.iOStopUpSuccess();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('ios-top-up-failed', function () {
|
||||
if (typeof window.iOStopUpFailed === 'function') {
|
||||
window.iOStopUpFailed();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('android-top-up-success', function () {
|
||||
if (typeof window.AndroidTopUpSuccess === 'function') {
|
||||
window.AndroidTopUpSuccess();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('android-top-up-failed', function () {
|
||||
if (typeof window.AndroidTopUpFailed === 'function') {
|
||||
window.AndroidTopUpFailed();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
|
@ -0,0 +1,106 @@
|
|||
<div class="row justify-content-center align-items-center">
|
||||
<div class="col-12 col-sm-12 col-lg-6 col-xl-6">
|
||||
<h1 class="text-center">Registration</h1>
|
||||
|
||||
@if($status === 'error' && session('error'))
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form wire:submit.prevent="register">
|
||||
<div class="mb-3 row">
|
||||
<label for="email" class="col-sm-4 col-form-label">E-mail</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="email" class="form-control @error('email') is-invalid @enderror" wire:model="email" id="email">
|
||||
@error('email') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label for="password" class="col-sm-4 col-form-label">Password</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="password" class="form-control @error('password') is-invalid @enderror" wire:model="password" id="password">
|
||||
@error('password') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label for="confirm_password" class="col-sm-4 col-form-label">Confirm Password</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="password" class="form-control @error('confirm_password') is-invalid @enderror" wire:model="confirm_password" id="confirm_password">
|
||||
@error('confirm_password') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label for="first_name" class="col-sm-4 col-form-label">First Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control @error('first_name') is-invalid @enderror" wire:model="first_name" id="first_name">
|
||||
@error('first_name') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label for="middle_name" class="col-sm-4 col-form-label">Middle Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control @error('middle_name') is-invalid @enderror" wire:model="middle_name" id="middle_name">
|
||||
@error('middle_name') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label for="last_name" class="col-sm-4 col-form-label">Last Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control @error('last_name') is-invalid @enderror" wire:model="last_name" id="last_name">
|
||||
@error('last_name') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label for="website" class="col-sm-4 col-form-label">Website</label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-select @error('website') is-invalid @enderror" wire:model="website" id="website">
|
||||
<option value="">Select Website</option>
|
||||
<option value="option1">Option 1</option>
|
||||
<option value="option2">Option 2</option>
|
||||
</select>
|
||||
@error('website') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-primary" wire:loading.attr="disabled" wire:target="register">
|
||||
<span wire:loading wire:target="register">Registering...</span>
|
||||
<span wire:loading.remove wire:target="register">Register</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
Back to <a href="{{ route('login') }}">Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script>
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Success',
|
||||
text: '{{ session('success') }}',
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script>
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: '{{ session('error') }}',
|
||||
});
|
||||
</script>
|
||||
@endif
|
|
@ -47,6 +47,12 @@ use App\Livewire\FetchData;
|
|||
use App\Livewire\Logout;
|
||||
use App\Livewire\ErrorHandler;
|
||||
|
||||
Route::get('/registration', \App\Livewire\Registration::class)->name('registration');
|
||||
Route::get('/topup-success-page', \App\Livewire\PublicTopSuccessPage::class)->name('topup-success');
|
||||
Route::get('/topup-error-page', \App\Livewire\PublicTopErrorPage::class)->name('topup-error');
|
||||
|
||||
Route::get('/login', \App\Livewire\Login::class)->name('login');
|
||||
Route::get('/change-password', \App\Livewire\ChangePassword::class)->name('change-password');
|
||||
|
||||
|
||||
Route::get('/fetch-data/{url}', FetchData::class)->name('fetch.data');
|
||||
|
|
Loading…
Reference in New Issue