From ab744b411deaac0e3d1bc421fb76ce5cc66a65f7 Mon Sep 17 00:00:00 2001 From: Hafid Nur <73023445+hafidnrzs@users.noreply.github.com> Date: Tue, 25 Nov 2025 19:59:08 +0700 Subject: [PATCH] feat(hackathon): update landing page and auth page UI (#60) * feat: update landing page * feat: Add favicon and SEO (JSON-LD schema, meta tags) - Add favicon image - Add JSON-LD schema for Hackathon event - Add react-helmet-async for managing meta tags * chore: remove react-helmet-async * chore: update landing page * chore: update UI for signup and login - add back button for better UX --------- Co-authored-by: Maulana Sodiqin --- apps/hackathon/index.html | 3 - apps/hackathon/src/app/auth/callback/page.tsx | 80 ++-- .../src/app/auth/forgot-password/page.tsx | 24 +- apps/hackathon/src/app/auth/login/page.tsx | 61 ++- .../src/app/auth/reset-password/page.tsx | 18 +- apps/hackathon/src/app/auth/signup/page.tsx | 82 ++-- apps/hackathon/src/app/page.tsx | 367 +++++++++--------- 7 files changed, 364 insertions(+), 271 deletions(-) diff --git a/apps/hackathon/index.html b/apps/hackathon/index.html index 2baf72c..8a9b483 100644 --- a/apps/hackathon/index.html +++ b/apps/hackathon/index.html @@ -4,7 +4,6 @@ IMPHNEN x Kolosal.ai Hackathon 2025 - - @@ -28,7 +26,6 @@ property="og:description" content="Total hadiah Rp14.500.000! Daftar sekarang dan wujudkan inovasi AI-mu untuk membantu usaha lokal." /> - { useEffect(() => { const handleCallback = async () => { if (hasRunRef.current) { - console.log('[Callback] Already processed, skipping...'); + // console.log('[Callback] Already processed, skipping...'); return; } hasRunRef.current = true; try { - console.log('[Callback] Processing OAuth callback...'); - console.log('[Callback] Current URL:', globalThis.location.href); + // console.log('[Callback] Processing OAuth callback...'); + // console.log('[Callback] Current URL:', globalThis.location.href); // Supabase client is configured with detectSessionInUrl: true // This means Supabase automatically detects and processes OAuth tokens from the URL hash // We just need to wait a moment for it to complete, then check for the session - console.log('[Callback] Waiting for Supabase to process OAuth callback...'); - await new Promise(resolve => setTimeout(resolve, 1000)); + // console.log('[Callback] Waiting for Supabase to process OAuth callback...'); + await new Promise((resolve) => setTimeout(resolve, 1000)); // Get the session that Supabase automatically created from the URL hash - const { data: { session: sessionData }, error: sessionError } = await supabase.auth.getSession(); + const { + data: { session: sessionData }, + error: sessionError, + } = await supabase.auth.getSession(); if (sessionError) { - console.error('[Callback] Session error:', sessionError); + // console.error('[Callback] Session error:', sessionError); throw new Error(sessionError.message || 'Failed to get session'); } if (!sessionData || !sessionData.user) { - throw new Error('No session found after OAuth callback. Please try logging in again.'); + throw new Error( + 'No session found after OAuth callback. Please try logging in again.' + ); } - console.log('[Callback] Supabase session established:', { - userId: sessionData.user.id, - email: sessionData.user.email, - }); + // console.log('[Callback] Supabase session established:', { + // userId: sessionData.user.id, + // email: sessionData.user.email, + // }); // Create/update user in the users table (for foreign key constraints) - console.log('[Callback] Creating/updating user record...'); + // console.log('[Callback] Creating/updating user record...'); const { data: userData, error: upsertError } = await supabase .from('users') - .upsert({ - id: sessionData.user.id, - email: sessionData.user.email || '', - fullname: sessionData.user.user_metadata?.full_name || - sessionData.user.user_metadata?.name || - sessionData.user.email?.split('@')[0] || '', - avatar: sessionData.user.user_metadata?.avatar_url || '', - is_active: true, - updated_at: new Date().toISOString(), - }, { - onConflict: 'id', - }) + .upsert( + { + id: sessionData.user.id, + email: sessionData.user.email || '', + fullname: + sessionData.user.user_metadata?.full_name || + sessionData.user.user_metadata?.name || + sessionData.user.email?.split('@')[0] || + '', + avatar: sessionData.user.user_metadata?.avatar_url || '', + is_active: true, + updated_at: new Date().toISOString(), + }, + { + onConflict: 'id', + } + ) .select() .single(); if (upsertError) { - console.warn('[Callback] Failed to create user record:', upsertError); + // console.warn('[Callback] Failed to create user record:', upsertError); // Don't throw - continue with login even if user record creation fails } else { - console.log('[Callback] User record created/updated successfully'); + // console.log('[Callback] User record created/updated successfully'); } // Store user-friendly data in Zustand for UI purposes @@ -77,9 +87,11 @@ const CallbackPage: FC = (): ReactElement => { const userRecord = userData || { id: sessionData.user.id, email: sessionData.user.email || '', - fullname: sessionData.user.user_metadata?.full_name || - sessionData.user.user_metadata?.name || - sessionData.user.email?.split('@')[0] || '', + fullname: + sessionData.user.user_metadata?.full_name || + sessionData.user.user_metadata?.name || + sessionData.user.email?.split('@')[0] || + '', avatar: sessionData.user.user_metadata?.avatar_url || '', phone_number: '', birthdate: '', @@ -114,21 +126,21 @@ const CallbackPage: FC = (): ReactElement => { }, }); - console.log('[Callback] Session stored successfully'); + // console.log('[Callback] Session stored successfully'); toast.success('Login successful!'); setIsProcessing(false); // Check if user has completed onboarding (has location) // Use globalThis.location.replace for hard redirect to prevent history issues if (userRecord.location) { - console.log('[Callback] User has completed onboarding, redirecting to dashboard...'); + // console.log('[Callback] User has completed onboarding, redirecting to dashboard...'); globalThis.location.replace('/dashboard'); } else { - console.log('[Callback] User needs onboarding, redirecting...'); + // console.log('[Callback] User needs onboarding, redirecting...'); globalThis.location.replace('/onboarding/user'); } } catch (err) { - console.error('[Callback] Error:', err); + // console.error('[Callback] Error:', err); setError((err as Error).message); setIsProcessing(false); toast.error('An error occurred during login'); diff --git a/apps/hackathon/src/app/auth/forgot-password/page.tsx b/apps/hackathon/src/app/auth/forgot-password/page.tsx index 97ac36b..7f9fe22 100644 --- a/apps/hackathon/src/app/auth/forgot-password/page.tsx +++ b/apps/hackathon/src/app/auth/forgot-password/page.tsx @@ -1,12 +1,14 @@ import { useState } from 'react'; import { supabase } from '@imphnen-frontend-service/service'; -import { Link } from 'react-router'; +import { Link, useNavigate } from 'react-router'; import { toast } from 'sonner'; +import { Icon } from '@iconify/react'; export default function ForgotPasswordPage() { const [email, setEmail] = useState(''); const [isLoading, setIsLoading] = useState(false); const [emailSent, setEmailSent] = useState(false); + const navigate = useNavigate(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -30,7 +32,7 @@ export default function ForgotPasswordPage() { setEmailSent(true); toast.success('Password reset email sent! Check your inbox.'); } catch (err) { - console.error('Failed to send reset email:', err); + // console.error('Failed to send reset email:', err); toast.error((err as Error).message || 'Failed to send reset email'); } finally { setIsLoading(false); @@ -55,7 +57,8 @@ export default function ForgotPasswordPage() {

- Click the link in the email to reset your password. The link will expire in 1 hour. + Click the link in the email to reset your password. The link will + expire in 1 hour.

@@ -90,7 +93,10 @@ export default function ForgotPasswordPage() {
-