diff --git a/apps/backoffice/src/app/(public)/auth/login/page.tsx b/apps/backoffice/src/app/(public)/auth/login/page.tsx index 31e2e9a..3955cb3 100644 --- a/apps/backoffice/src/app/(public)/auth/login/page.tsx +++ b/apps/backoffice/src/app/(public)/auth/login/page.tsx @@ -1,55 +1,110 @@ -import { FC, ReactElement } from 'react'; -import { Button } from '@imphnen-frontend-service/ui/atoms'; -import { useLogin } from './_hooks/use-login'; -import { ControlledInputField } from '@imphnen-frontend-service/ui/organisms'; +import { useState } from 'react'; +import { useLogin } from '@imphnen-frontend-service/service'; +import { useNavigate } from 'react-router'; +import { toast } from 'sonner'; +import { Icon } from '@iconify/react'; -export const Components: FC = (): ReactElement => { - const { form, onSubmit, isLoading } = useLogin(); +export default function LoginPage() { + const navigate = useNavigate(); + const loginMutation = useLogin(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(null); + const [showPassword, setShowPassword] = useState(false); + + const handleEmailLogin = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + if (!email || !password) { + setError('Please enter both email and password'); + return; + } + try { + await loginMutation.mutateAsync({ email, password }); + toast.success('Login successful!'); + navigate('/'); + } catch (err) { + setError((err as Error).message || 'Login failed'); + } + }; return ( -
-
- -

- Welcome to IMPHNEN Backoffice -

-
- - - +
+
+ + + {loginMutation.isPending ? 'Signing in...' : 'Sign in'} + + +
+

+ By signing in, you agree to our Terms of Service and Privacy Policy +

+
); -}; - -export default Components; +} diff --git a/apps/dimentorin/src/app/auth/login/page.tsx b/apps/dimentorin/src/app/auth/login/page.tsx index f62e86c..97eaaaf 100644 --- a/apps/dimentorin/src/app/auth/login/page.tsx +++ b/apps/dimentorin/src/app/auth/login/page.tsx @@ -1,99 +1,191 @@ -import { FC, ReactElement } from 'react'; -import { ControlledInputField, LoginBanner } from '@imphnen-frontend-service/ui/organisms'; -import { Button } from '@imphnen-frontend-service/ui/atoms'; -import { useLogin } from '../../_hooks/use-login'; -import { useGoogleLogin } from '../../_hooks/use-google-login'; -import { ArrowLeftOutlined } from '@ant-design/icons'; +import { useState, useEffect } from 'react'; +import { + useGitHubAuth, + useLogin, +} from '@imphnen-frontend-service/service'; +import { GithubOutlined } from '@ant-design/icons'; +import { useNavigate, Link } from 'react-router'; +import { toast } from 'sonner'; +import { Icon } from '@iconify/react'; -export const Components: FC = (): ReactElement => { - const { form, onSubmit, isLoading } = useLogin(); - const { handleGoogleLogin } = useGoogleLogin(); +export default function LoginPage() { + const navigate = useNavigate(); + const { signInWithGitHub } = useGitHubAuth(); + const loginMutation = useLogin(); + const [isGithubLoading, setIsGithubLoading] = useState(false); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(null); + const [showPassword, setShowPassword] = useState(false); + + useEffect(() => { + const hashParams = new URLSearchParams(globalThis.location.hash.substring(1)); + const urlParams = new URLSearchParams(globalThis.location.search); + const accessToken = hashParams.get('access_token') || urlParams.get('access_token'); + const type = hashParams.get('type') || urlParams.get('type'); + if (accessToken) { + if (type === 'recovery' || type === 'magiclink' || !type) { + toast.info('Redirecting to password reset...'); + navigate('/auth/reset-password?access_token=' + accessToken); + } + } + }, [navigate]); + + const handleEmailLogin = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + if (!email || !password) { + setError('Please enter both email and password'); + return; + } + try { + await loginMutation.mutateAsync({ email, password }); + toast.success('Login successful!'); + navigate('/dashboard'); + } catch (err) { + setError((err as Error).message || 'Login failed'); + } + }; + + const handleGithubLogin = async () => { + try { + setIsGithubLoading(true); + const result = await signInWithGitHub(); + if (result?.url) { + globalThis.location.href = result.url; + } else { + setIsGithubLoading(false); + setError('Failed to get GitHub OAuth URL'); + } + } catch (err) { + setError((err as Error).message || 'GitHub login failed'); + setIsGithubLoading(false); + } + }; return ( -
-
- -
-
-

- Hallo Minna-san -

-
- Welcome to Dimentorin by IMPHNEN -
-
- - - - - +
+
+
+ +
-
-
Belum Punya akun ?
- - Daftar Disini - -
- -
-
- Or -
-
- - - +
+

+ Welcome Back +

+

+ Sign in to the mentoring platform +

+
+ + {error && ( +
+

{error}

+ )} + +
+
+ + setEmail(e.target.value)} + placeholder="your@email.com" + disabled={loginMutation.isPending} + className="w-full px-4 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder:text-gray-400 dark:placeholder:text-gray-500 disabled:bg-gray-100 dark:disabled:bg-gray-700 disabled:cursor-not-allowed" + required + /> +
+ +
+
+ + + Forgot password? + +
+
+ setPassword(e.target.value)} + placeholder="••••••••" + disabled={loginMutation.isPending} + className="w-full px-4 py-2.5 pr-12 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder:text-gray-400 dark:placeholder:text-gray-500 disabled:bg-gray-100 dark:disabled:bg-gray-700 disabled:cursor-not-allowed" + required + /> + +
+
+ + +
+ +
+
+ OR +
+
+ + + +

+ Make sure your GitHub email is{' '} + + set to public + {' '} + for GitHub sign in to work. +

+ +
+

+ Don't have an account?{' '} + + Sign up + +

+
+ +
+

+ By signing in, you agree to our Terms of Service and Privacy Policy +

); -}; - -export default Components; +} diff --git a/apps/qrcampaign/src/app/auth/login/page.tsx b/apps/qrcampaign/src/app/auth/login/page.tsx index 46102f4..fc7c521 100644 --- a/apps/qrcampaign/src/app/auth/login/page.tsx +++ b/apps/qrcampaign/src/app/auth/login/page.tsx @@ -24,20 +24,11 @@ export default function LoginPage() { }, [isAuthenticated, navigate]); useEffect(() => { - const hashParams = new URLSearchParams( - globalThis.location.hash.substring(1) - ); + const hashParams = new URLSearchParams(globalThis.location.hash.substring(1)); const urlParams = new URLSearchParams(globalThis.location.search); - - const accessToken = - hashParams.get('access_token') || urlParams.get('access_token'); + const accessToken = hashParams.get('access_token') || urlParams.get('access_token'); const type = hashParams.get('type') || urlParams.get('type'); - if (accessToken) { - console.log( - '[Login] Detected access_token, redirecting to reset-password page' - ); - if (type === 'recovery' || type === 'magiclink' || !type) { toast.info('Redirecting to password reset...'); navigate('/auth/reset-password?access_token=' + accessToken); @@ -48,16 +39,13 @@ export default function LoginPage() { const handleEmailLogin = async (e: React.FormEvent) => { e.preventDefault(); setError(null); - if (!email || !password) { setError('Please enter both email and password'); return; } - setIsSubmitting(true); try { const success = await login(email, password); - if (success) { toast.success('Login successful!'); navigate('/'); @@ -65,7 +53,6 @@ export default function LoginPage() { setError('Login failed. Please check your credentials.'); } } catch (err) { - console.error('[Login] Email login failed:', err); setError('Login failed. Please try again.'); } finally { setIsSubmitting(false); @@ -77,30 +64,26 @@ export default function LoginPage() { }; return ( -
-
- { -} - +
+
-

+

Welcome Back

-

Sign in to continue to IMPHNEN

+

+ Sign in to QR Campaign Manager +

{error && ( -
-

{error}

+
+

{error}

)} -
+
-
-
@@ -138,18 +115,15 @@ export default function LoginPage() { onChange={(e) => setPassword(e.target.value)} placeholder="••••••••" disabled={isSubmitting} - className="w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white text-gray-900 placeholder:text-gray-400 disabled:bg-gray-100 disabled:cursor-not-allowed pr-10" + className="w-full px-4 py-2.5 pr-12 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder:text-gray-400 dark:placeholder:text-gray-500 disabled:bg-gray-100 dark:disabled:bg-gray-700 disabled:cursor-not-allowed" required />
@@ -157,62 +131,47 @@ export default function LoginPage() { -
-
-
-
-
- - Or continue with - -
+
+
+ OR +
-

+

Make sure your GitHub email is{' '} - + set to public {' '} for GitHub sign in to work.

-

+

Don't have an account?{' '} - + Sign up

-

+

By signing in, you agree to our Terms of Service and Privacy Policy