diff --git a/app/Http/Controllers/Auth/LoginEmailController.php b/app/Http/Controllers/Auth/LoginEmailController.php index 2970618..92b8ed3 100644 --- a/app/Http/Controllers/Auth/LoginEmailController.php +++ b/app/Http/Controllers/Auth/LoginEmailController.php @@ -3,14 +3,135 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; +use App\Repositories\Member\Auth\MemberAuthRepository; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Log; class LoginEmailController extends Controller { + protected $memberAuthRepository; + + public function __construct(MemberAuthRepository $memberAuthRepository) + { + $this->memberAuthRepository = $memberAuthRepository; + } + public function index() { return view('account.signin',[ 'type' => 'email', ]); } + + public function otp(Request $request) + { + $validator = Validator::make($request->all(), [ + 'identity' => 'required|email', + ]); + + + $email = $request->identity; + + try { + // Find user by email + $user = $this->memberAuthRepository->check(['email' => $email]); + + if (!$user) { + return response()->json([ + 'success' => false, + 'message' => __('signin.user_not_found'), + ], 404); + } + + try { + + // Use MemberAuthRepository to generate OTP + $otp = $this->memberAuthRepository->emailOtp(['email' => $email]); + + // TODO: Integrate with WhatsApp API to send OTP + // For now, we'll just log it (remove in production) + Log::info("OTP for {$email}: {$otp->otp}"); + + return response()->json([ + 'success' => true, + 'message' => __('otp.sent'), + 'redirect' => route('login-email.otp.view', ['identity' => $email]), + ]); + } catch (\Exception $e) { + Log::error('OTP generation failed: '.$e->getMessage()); + + return response()->json([ + 'success' => false, + 'message' => __('otp.generate_failed'), + ], 500); + } + + } catch (\Exception $e) { + Log::error('Email login failed: ' . $e->getMessage()); + + return response()->json([ + 'success' => false, + 'message' => __('signin.login_failed') + ], 500); + } + } + + public function otpView($identity) + { + return view('account.otp', [ + 'identity' => $identity, + 'type' => 'email' + ]); + } + + public function verify(Request $request) + { + $validator = Validator::make($request->all(), [ + 'identity' => 'required|email', + 'otp' => 'required|string|size:6', + ]); + + if ($validator->fails()) { + return back() + ->withErrors($validator) + ->withInput(); + } + + $identity = $request->identity; + $otp = $request->otp; + + try { + // Use MemberAuthRepository to verify OTP for email + $result = $this->memberAuthRepository->emailOtpConfirm([ + 'email' => $identity, + 'otp' => $otp, + ]); + + $check = $this->memberAuthRepository->check(['email' => $identity]); + + $loginData = [ + 'fcm_token' => null, + 'device' => 'web', + ]; + $this->memberAuthRepository->getAuth([ + 'user_id' => $check->id, + 'device' => 'web', + ]); + + return redirect()->route('home')->with('success', __('otp.login_success')); + + } catch (\Illuminate\Validation\ValidationException $e) { + return back() + ->withErrors(['otp' => $e->getMessage()]) + ->withInput(); + } catch (\Exception $e) { + Log::error('Email OTP verification failed: '.$e->getMessage()); + + return back() + ->withErrors(['otp' => __('otp.verification_failed')]) + ->withInput(); + } + } } diff --git a/app/Http/Controllers/Auth/LoginWaController.php b/app/Http/Controllers/Auth/LoginWaController.php index 5dcbd68..e78a71a 100644 --- a/app/Http/Controllers/Auth/LoginWaController.php +++ b/app/Http/Controllers/Auth/LoginWaController.php @@ -41,7 +41,7 @@ class LoginWaController extends Controller $identity = $request->identity; - // check first if user exists + // Find or create user by phone number $user = $this->memberAuthRepository->check(['phone' => $identity]); if (! $user) { return response()->json([ @@ -106,8 +106,14 @@ class LoginWaController extends Controller $check = $this->memberAuthRepository->check(['phone' => $identity]); - - // Auth::guard('web')->attempt(['id' => $check->id]); + $loginData = [ + 'fcm_token' => null, + 'device' => 'web', + ]; + $this->memberAuthRepository->getAuth([ + 'user_id' => $check->id, + 'device' => 'web', + ]); return redirect()->route('home')->with('success', __('otp.login_success')); diff --git a/app/Repositories/Member/Auth/MemberAuthRepository.php b/app/Repositories/Member/Auth/MemberAuthRepository.php index 82c7af7..8d962dd 100644 --- a/app/Repositories/Member/Auth/MemberAuthRepository.php +++ b/app/Repositories/Member/Auth/MemberAuthRepository.php @@ -57,9 +57,8 @@ class MemberAuthRepository $phone = preg_replace("/[^0-9]/", "",$phone); $phone_with_zero = "0" . substr($phone,2,strlen($phone)); - $affliator = Affiliator::where('phone', $phone)->orWhere('phone', $phone_with_zero)->first(); $customer = Customer::where('phone', $phone)->orWhere('phone', $phone_with_zero)->first(); - $user = $affliator ? $affliator->user : @$customer->user; + $user = @$customer->user; return $user; } @@ -69,9 +68,8 @@ class MemberAuthRepository { $email = trim($email); - $affliator = Affiliator::where('email', $email)->first(); $customer = Customer::where('email', $email)->first(); - $user = $affliator ? $affliator->user : @$customer->user; + $user = @$customer->user; return $user; } diff --git a/lang/en/otp.php b/lang/en/otp.php index bbb4038..fa37267 100644 --- a/lang/en/otp.php +++ b/lang/en/otp.php @@ -13,7 +13,7 @@ return [ | */ - 'title' => 'Verify Your Phone', + 'title' => 'Verify Your :type', 'description' => 'We sent a 6-digit code to :phone', 'enter_code' => 'Enter verification code', 'invalid_code' => 'Please enter a valid 6-digit code', @@ -32,5 +32,6 @@ return [ 'resend_failed' => 'Failed to resend OTP. Please try again', 'generate_failed' => 'Failed to generate OTP. Please try again', 'verification_failed' => 'OTP verification failed. Please try again', + 'register_required' => 'Please register an account first', ]; diff --git a/lang/en/signin.php b/lang/en/signin.php index f33b53d..1ac0253 100644 --- a/lang/en/signin.php +++ b/lang/en/signin.php @@ -31,8 +31,13 @@ return [ 'facebook' => 'Facebook', 'apple' => 'Apple', 'need_help' => 'Need help?', - 'rights_reserved' => '© All rights reserved. Made by :company', - + 'rights_reserved' => ' All rights reserved. Made by :company', + 'company_name' => 'Coderthemes', 'sending' => 'Sending...', 'error' => 'An error occurred. Please try again.', + 'invalid_credentials' => 'Invalid email or password', + 'user_not_found' => 'User not found with this email', + 'login_success' => 'Login successful', + 'login_failed' => 'Login failed. Please try again.', + 'password_field_required' => 'Password field is required for email login', ]; diff --git a/lang/id/otp.php b/lang/id/otp.php index 8faee24..9822208 100644 --- a/lang/id/otp.php +++ b/lang/id/otp.php @@ -32,5 +32,6 @@ return [ 'resend_failed' => 'Gagal mengirim ulang OTP. Silakan coba lagi', 'generate_failed' => 'Gagal membuat OTP. Silakan coba lagi', 'verification_failed' => 'Verifikasi OTP gagal. Silakan coba lagi', + 'register_required' => 'Silakan daftar akun terlebih dahulu', ]; diff --git a/lang/id/signin.php b/lang/id/signin.php index 606b10f..9864256 100644 --- a/lang/id/signin.php +++ b/lang/id/signin.php @@ -31,7 +31,13 @@ return [ 'facebook' => 'Facebook', 'apple' => 'Apple', 'need_help' => 'Butuh bantuan?', - 'rights_reserved' => '© Semua hak dilindungi. Dibuat oleh :company', + 'rights_reserved' => ' Semua hak dilindungi. Dibuat oleh :company', + 'company_name' => 'Coderthemes', 'sending' => 'Mengirim...', 'error' => 'Terjadi kesalahan. Silakan coba lagi.', + 'invalid_credentials' => 'Email atau kata sandi salah', + 'user_not_found' => 'Pengguna tidak ditemukan dengan email ini', + 'login_success' => 'Login berhasil', + 'login_failed' => 'Login gagal. Silakan coba lagi.', + 'password_field_required' => 'Kolom kata sandi diperlukan untuk login email', ]; \ No newline at end of file diff --git a/resources/views/account/otp.blade.php b/resources/views/account/otp.blade.php index 1c67465..960cc32 100644 --- a/resources/views/account/otp.blade.php +++ b/resources/views/account/otp.blade.php @@ -9,40 +9,39 @@ -

{{ __('otp.title') }}

-

{{ __('otp.description', ['phone' => $identity]) }}

+

{{ __('otp.title', ['type' => $type == 'email' ? 'Email' : 'Phone']) }}

+ - - {{-- show message if error --}} - @if ($errors->has('otp')) + {{-- error message --}} + @if ($errors->any())
- {{ $errors->first('otp') }} + @foreach ($errors->all() as $error) +
{{ $error }}
+ @endforeach +
@endif - + -
+ + @csrf - +
- +
{{ __('otp.invalid_code') }}
- +
@@ -86,61 +87,64 @@ @endsection @section('scripts') - + @endsection diff --git a/resources/views/account/signin.blade.php b/resources/views/account/signin.blade.php index 8df06d3..3d6016b 100644 --- a/resources/views/account/signin.blade.php +++ b/resources/views/account/signin.blade.php @@ -9,16 +9,16 @@ -

{{ __('signin.title') }}

+

Welcome back

{{-- show error message --}} @@ -27,10 +27,14 @@
- -
{{ $type == 'email' ? __('signin.email_invalid') : __('signin.phone_invalid') }}
+ +
+ {{ $type == 'email' ? __('signin.email_invalid') : __('signin.phone_invalid') }}
- +
{{-- @@ -48,13 +53,15 @@
-
@@ -74,81 +81,130 @@ @endsection @section('scripts') - + + // Hide error message when password field is typed + if (passwordInput) { + passwordInput.addEventListener('input', function() { + const errorDiv = document.getElementById('error-message'); + errorDiv.classList.add('d-none'); + }); + } + + loginForm.addEventListener('submit', function(e) { + e.preventDefault(); + + // Hide error message when submitting + const errorDiv = document.getElementById('error-message'); + errorDiv.classList.add('d-none'); + + // Reset validation + loginForm.classList.remove('was-validated'); + + // Basic validation + if (!identityInput.value.trim()) { + loginForm.classList.add('was-validated'); + return; + } + + if (passwordInput && !passwordInput.value.trim()) { + loginForm.classList.add('was-validated'); + return; + } + + // Show loading state + submitBtn.disabled = true; + submitBtn.innerHTML = + '{{ __('signin.sending') }}'; + + // Determine form type based on current route + const isPhoneLogin = '{{ $type }}' === 'phone'; + + if (isPhoneLogin) { + // Send OTP request for phone login + fetch('{{ route('login-phone.otp') }}', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]') + .getAttribute('content') + }, + body: JSON.stringify({ + identity: identityInput.value.trim() + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Redirect to OTP verification page + window.location.href = data.redirect; + } else { + // Show error in error message div + const errorDiv = document.getElementById('error-message'); + errorDiv.textContent = data.message || '{{ __('signin.error') }}'; + errorDiv.classList.remove('d-none'); + } + }) + .catch(error => { + console.error('Error:', error); + const errorDiv = document.getElementById('error-message'); + errorDiv.textContent = '{{ __('signin.error') }}'; + errorDiv.classList.remove('d-none'); + }) + .finally(() => { + // Reset button state + submitBtn.disabled = false; + submitBtn.textContent = '{{ __('signin.sign_in') }}'; + }); + } else { + + fetch('{{ route('login-email.otp') }}', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]') + .getAttribute('content') + }, + body: JSON.stringify({ + identity: identityInput.value.trim(), + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Redirect to home page + window.location.href = data.redirect; + } else { + // Show error in error message div + const errorDiv = document.getElementById('error-message'); + errorDiv.textContent = data.message || '{{ __('signin.error') }}'; + errorDiv.classList.remove('d-none'); + } + }) + .catch(error => { + console.error('Error:', error); + const errorDiv = document.getElementById('error-message'); + errorDiv.textContent = '{{ __('signin.error') }}'; + errorDiv.classList.remove('d-none'); + }) + .finally(() => { + // Reset button state + submitBtn.disabled = false; + submitBtn.textContent = '{{ __('signin.sign_in') }}'; + }); + } + }); + }); + @endsection diff --git a/resources/views/account/signup.blade.php b/resources/views/account/signup.blade.php index 1aa79a2..4e888b0 100644 --- a/resources/views/account/signup.blade.php +++ b/resources/views/account/signup.blade.php @@ -120,14 +120,16 @@
-