From adba211a049c73cc77cf5c405a698948cfe6815e Mon Sep 17 00:00:00 2001 From: Camillalalala Date: Mon, 20 Apr 2026 21:25:14 -0700 Subject: [PATCH 01/10] Add alert for sign up and sign in auth pages --- app/(auth)/sign-up/page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/(auth)/sign-up/page.tsx b/app/(auth)/sign-up/page.tsx index 55d69f0b..6be9db3e 100644 --- a/app/(auth)/sign-up/page.tsx +++ b/app/(auth)/sign-up/page.tsx @@ -43,7 +43,8 @@ export default function SignUpPage() { }); setIsLoading(false); if (error) { - console.error('Sign-up error:', error); + alert(error.message); + return; } router.push('/home'); }; From 4c1214f227797cce90edd268b8873ebb434d8f9d Mon Sep 17 00:00:00 2001 From: Camillalalala Date: Thu, 23 Apr 2026 21:12:59 -0700 Subject: [PATCH 02/10] Create error handling for sign-in, sign-up, forgot-password, and donation form --- app/(auth)/forgot-password/page.tsx | 128 ++++++++++-------- app/(auth)/sign-in/page.tsx | 10 +- app/(auth)/sign-up/page.tsx | 12 +- .../components/LightweightDonationForm.tsx | 62 ++++++--- 4 files changed, 131 insertions(+), 81 deletions(-) diff --git a/app/(auth)/forgot-password/page.tsx b/app/(auth)/forgot-password/page.tsx index ed0471f6..41529a87 100644 --- a/app/(auth)/forgot-password/page.tsx +++ b/app/(auth)/forgot-password/page.tsx @@ -1,59 +1,69 @@ -'use client'; -import { useForm } from 'react-hook-form'; -import { createClient } from '@/app/lib/supabase/browser-client'; - -type ForgotPasswordFormValues = { - email: string; -}; - -export default function ForgotPasswordPage() { - const supabase = createClient(); - - const { - register, - handleSubmit, - formState: { errors, isSubmitting }, - } = useForm({ - defaultValues: { email: '' }, - mode: 'onSubmit', - }); - - const onSubmit = async (values: ForgotPasswordFormValues) => { - const { error } = await supabase.auth.resetPasswordForEmail(values.email); - - if (error) { - alert(error.message); - return; - } - - alert('Instructions to reset your password have been sent to your email.'); - }; - - return ( -
-

Reset Password

- -
- - - - - {errors.email?.message ?

{errors.email.message}

: null} - - -
-
- ); -} +'use client'; +import { useForm } from 'react-hook-form'; +import { useState } from 'react'; +import { createClient } from '@/app/lib/supabase/browser-client'; + +type ForgotPasswordFormValues = { + email: string; +}; + +export default function ForgotPasswordPage() { + const supabase = createClient(); + const [errorMessage, setErrorMessage] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { email: '' }, + mode: 'onSubmit', + }); + + const onSubmit = async (values: ForgotPasswordFormValues) => { + setErrorMessage(''); + setSuccessMessage(''); + + const { error } = await supabase.auth.resetPasswordForEmail(values.email); + + if (error) { + setErrorMessage('Failed to send reset password email: ' + error.message); + return; + } + + setSuccessMessage( + 'Instructions to reset your password have been sent to your email.', + ); + }; + + return ( +
+

Reset Password

+ +
+ + + + + {errors.email?.message ?

{errors.email.message}

: null} + + + + {errorMessage &&

{errorMessage}

} + {successMessage &&

{successMessage}

} +
+
+ ); +} diff --git a/app/(auth)/sign-in/page.tsx b/app/(auth)/sign-in/page.tsx index e09aa9dd..7f23ef69 100644 --- a/app/(auth)/sign-in/page.tsx +++ b/app/(auth)/sign-in/page.tsx @@ -2,6 +2,7 @@ import { createClient } from '@/app/lib/supabase/browser-client'; import { useForm } from 'react-hook-form'; +import { useState } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; @@ -16,18 +17,23 @@ export default function SignInPage() { handleSubmit, formState: { errors }, } = useForm(); + const [errorMessage, setErrorMessage] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); const router = useRouter(); const supabase = createClient(); const onSubmit = async (formData: Inputs) => { + setErrorMessage(''); + setSuccessMessage(''); const { error } = await supabase.auth.signInWithPassword({ email: formData.email, password: formData.password, }); if (error) { - alert(error.message); + setErrorMessage('Failed to sign in: ' + error.message); return; } + setSuccessMessage('Signed in successfully! Redirecting...'); router.push('/home'); }; @@ -61,6 +67,8 @@ export default function SignInPage() { Forgot password?
Sign up + {errorMessage &&

{errorMessage}

} + {successMessage &&

{successMessage}

} ); } diff --git a/app/(auth)/sign-up/page.tsx b/app/(auth)/sign-up/page.tsx index 6be9db3e..10e0bf0d 100644 --- a/app/(auth)/sign-up/page.tsx +++ b/app/(auth)/sign-up/page.tsx @@ -22,6 +22,8 @@ export default function SignUpPage() { formState: { errors }, } = useForm(); const [isLoading, setIsLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); const supabase = createClient(); const router = useRouter(); const passwordValue = useWatch({ @@ -30,6 +32,8 @@ export default function SignUpPage() { }); const onSubmit: SubmitHandler = async (formData) => { + setErrorMessage(''); + setSuccessMessage(''); setIsLoading(true); const { error } = await supabase.auth.signUp({ email: formData.email, @@ -43,10 +47,12 @@ export default function SignUpPage() { }); setIsLoading(false); if (error) { - alert(error.message); + setErrorMessage('Failed to sign up: ' + error.message); return; } - router.push('/home'); + setSuccessMessage( + 'Account created successfully! Please check your email to confirm your account.', + ); }; return ( @@ -131,6 +137,8 @@ export default function SignUpPage() {
Sign in + {errorMessage &&

{errorMessage}

} + {successMessage &&

{successMessage}

} ); } diff --git a/app/(main)/home/donate/components/LightweightDonationForm.tsx b/app/(main)/home/donate/components/LightweightDonationForm.tsx index 3555dd0b..8131cf6a 100644 --- a/app/(main)/home/donate/components/LightweightDonationForm.tsx +++ b/app/(main)/home/donate/components/LightweightDonationForm.tsx @@ -4,6 +4,7 @@ import { DonationInsert } from '@/app/types/donation'; import { useForm, useWatch, Controller } from 'react-hook-form'; import { PatternFormat } from 'react-number-format'; import { createDonation } from '@/app/actions/donation'; +import { useState } from 'react'; type FormData = { donor_type?: 'individual' | 'business'; @@ -32,7 +33,7 @@ export default function LightweightDonationForm() { control, reset, clearErrors, - formState: { errors, isSubmitSuccessful }, + formState: { errors }, } = useForm({ defaultValues: { donor_type: undefined, @@ -40,6 +41,8 @@ export default function LightweightDonationForm() { estimated_value: '', }, }); + const [errorMessage, setErrorMessage] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); const donorType = useWatch({ control, @@ -47,6 +50,8 @@ export default function LightweightDonationForm() { }); const onSubmit = async (data: FormData) => { + setErrorMessage(''); + setSuccessMessage(''); const donation: DonationInsert = { donor_is_individual: data.donor_type === 'individual', @@ -79,9 +84,10 @@ export default function LightweightDonationForm() { }; const result = await createDonation(donation); - - // Reset all fields to empty/default values if (result.success) { + setSuccessMessage( + 'Donation submitted successfully! Thank you for your generosity.', + ); reset({ donor_type: undefined, individual_name: '', @@ -99,7 +105,9 @@ export default function LightweightDonationForm() { }); clearErrors(); } else { - console.error('Failed to create donation:', result.error); + setErrorMessage( + 'Failed to create donation: ' + (result.error || 'Unknown error'), + ); } }; @@ -126,6 +134,36 @@ export default function LightweightDonationForm() { >

Donation Form

+ {errorMessage && ( +
+ {errorMessage} +
+ )} + {successMessage && ( +
+ {successMessage} +
+ )}
- {isSubmitSuccessful && ( -
- Form submitted successfully! Thank you for your donation. -
- )} + {/* Success message now handled above form */}
); From ee3847d055088c13b313702b2ba1ac8d131dd1ee Mon Sep 17 00:00:00 2001 From: Camillalalala Date: Thu, 23 Apr 2026 21:39:41 -0700 Subject: [PATCH 03/10] Create error handling for instock and outofstock item cards, removeTicketItem button, add instock to cart form, and add outofstock to cart form --- .../components/InStockTicketItemCard.tsx | 9 ++- .../components/OutOfStockTicketItemCard.tsx | 78 ++++++++++++++++--- .../components/RemoveTicketItemButton.tsx | 21 +++-- .../components/AddInStockToCartForm.tsx | 43 +++++++++- .../components/AddOutOfStockToCartForm.tsx | 40 +++++++++- 5 files changed, 169 insertions(+), 22 deletions(-) diff --git a/app/(main)/components/InStockTicketItemCard.tsx b/app/(main)/components/InStockTicketItemCard.tsx index 3b1b5287..19659f9f 100644 --- a/app/(main)/components/InStockTicketItemCard.tsx +++ b/app/(main)/components/InStockTicketItemCard.tsx @@ -28,6 +28,7 @@ export default function InStockTicketItemCard({ const hasChanged = quantity !== savedQuantity; const handleSave = async () => { + setErrorMessage(''); if (quantity < 1) { setErrorMessage('Please input a number greater than 0.'); return; @@ -36,7 +37,7 @@ export default function InStockTicketItemCard({ const result = await updateTicketItemQuantity(ticketItemId, quantity); if (!result.success) { - console.error('Error changing ticket item quantity:', result.error); + setErrorMessage('Failed to update ticket item quantity.' + result.error); return; } @@ -68,7 +69,11 @@ export default function InStockTicketItemCard({ }} /> - {errorMessage &&

{errorMessage}

} + {errorMessage && ( +

+ {errorMessage} +

+ )} {hasChanged && ( <> diff --git a/app/(main)/components/OutOfStockTicketItemCard.tsx b/app/(main)/components/OutOfStockTicketItemCard.tsx index 330a77e3..be9c66f4 100644 --- a/app/(main)/components/OutOfStockTicketItemCard.tsx +++ b/app/(main)/components/OutOfStockTicketItemCard.tsx @@ -1,4 +1,5 @@ 'use client'; + import { updateTicketItemDescription } from '@/app/actions/ticket'; import { useState } from 'react'; @@ -9,33 +10,86 @@ interface OutOfStockTicketItemCardProps { export default function OutOfStockTicketItemCard({ ticketItemId, - freeTextDescription, + freeTextDescription: initialDescription, }: OutOfStockTicketItemCardProps) { - const [description, setDescription] = useState(freeTextDescription); + const [description, setDescription] = useState(initialDescription); const [isChanged, setIsChanged] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [isSaving, setIsSaving] = useState(false); const handleChange = (e: React.ChangeEvent) => { const newValue = e.target.value; setDescription(newValue); - setIsChanged(newValue !== freeTextDescription); + setIsChanged(newValue !== initialDescription); }; + const handleCancel = () => { - setDescription(freeTextDescription); + setDescription(initialDescription); setIsChanged(false); + setErrorMessage(''); }; + const handleSave = async () => { - await updateTicketItemDescription(ticketItemId, description); - setIsChanged(false); + setErrorMessage(''); + setIsSaving(true); + + try { + const { error } = await updateTicketItemDescription( + ticketItemId, + description, + ); + + if (error) { + setErrorMessage('Failed to update description: ' + error); + setIsSaving(false); + return; + } + + // Success Path + setIsChanged(false); + } catch (e) { + // Handle infrastructure/network errors + setErrorMessage('A critical connection error occurred.' + e); + return; + } finally { + setIsSaving(false); + } }; + return ( -
-