From 4c985e51772502752b4526b18a1c4f4b4a109dd6 Mon Sep 17 00:00:00 2001
From: aryabenade
Date: Mon, 27 Apr 2026 14:57:51 +0530
Subject: [PATCH 1/6] remove ai word from magic itinerary from city home page
---
src/pages/MelbournePage.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pages/MelbournePage.tsx b/src/pages/MelbournePage.tsx
index 75ba85a..1f6410e 100644
--- a/src/pages/MelbournePage.tsx
+++ b/src/pages/MelbournePage.tsx
@@ -392,7 +392,7 @@ export function MelbournePage({
>
- AI-Powered Magic Itinerary
+ Magic Itinerary
-
+ {/*
Free to use • No credit card required
-
+
*/}
From e0c314d3afd7f70ee81ebadd6f14e6184f5b1263 Mon Sep 17 00:00:00 2001
From: aryabenade
Date: Mon, 27 Apr 2026 15:48:34 +0530
Subject: [PATCH 2/6] show validation errors below the fields instead of
toasters
---
src/components/RegisterPage.tsx | 219 ++++++++++++++++++++++---------
src/pages/PaymentDetailsPage.tsx | 166 ++++++++---------------
src/pages/ProfilePage.tsx | 162 ++++++++++++++++-------
3 files changed, 323 insertions(+), 224 deletions(-)
diff --git a/src/components/RegisterPage.tsx b/src/components/RegisterPage.tsx
index 8072f8d..0ced869 100644
--- a/src/components/RegisterPage.tsx
+++ b/src/components/RegisterPage.tsx
@@ -10,6 +10,7 @@ import { Footer } from './Footer';
import { useNavigate } from 'react-router-dom';
import { Label } from './ui/label';
import { useEffect } from 'react';
+import { AlertCircle } from 'lucide-react';
export default function RegisterPage() {
const { login, user } = useAuth();
@@ -30,6 +31,7 @@ export default function RegisterPage() {
const [helperText, setHelperText] = useState('');
const [isLoading, setIsLoading] = useState(false);
+ const [fieldErrors, setFieldErrors] = useState>({});
const navigate = useNavigate()
@@ -46,63 +48,120 @@ export default function RegisterPage() {
setFormData(prev => ({ ...prev, [field]: value }));
};
- const validateForm = () => {
- // First Name
- if (!formData.firstName.trim()) return toast.error('First name is required'), false;
- if (/\s/.test(formData.firstName)) return toast.error('First name must not contain spaces'), false;
- if (!/^[A-Za-z]+$/.test(formData.firstName)) return toast.error('First name must contain only letters (A–Z)'), false;
- if (formData.firstName.length < 2 || formData.firstName.length > 50) return toast.error('First name must be between 2 and 50 characters'), false;
+ // const validateForm = () => {
+ // // First Name
+ // if (!formData.firstName.trim()) return toast.error('First name is required'), false;
+ // if (/\s/.test(formData.firstName)) return toast.error('First name must not contain spaces'), false;
+ // if (!/^[A-Za-z]+$/.test(formData.firstName)) return toast.error('First name must contain only letters (A–Z)'), false;
+ // if (formData.firstName.length < 2 || formData.firstName.length > 50) return toast.error('First name must be between 2 and 50 characters'), false;
- // Last Name
- if (!formData.lastName.trim()) return toast.error('Last name is required'), false;
- if (/\s/.test(formData.lastName)) return toast.error('Last name must not contain spaces'), false;
- if (!/^[A-Za-z]+$/.test(formData.lastName)) return toast.error('Last name must contain only letters (A–Z)'), false;
- if (formData.lastName.length < 2 || formData.lastName.length > 50) return toast.error('Last name must be between 2 and 50 characters'), false;
+ // // Last Name
+ // if (!formData.lastName.trim()) return toast.error('Last name is required'), false;
+ // if (/\s/.test(formData.lastName)) return toast.error('Last name must not contain spaces'), false;
+ // if (!/^[A-Za-z]+$/.test(formData.lastName)) return toast.error('Last name must contain only letters (A–Z)'), false;
+ // if (formData.lastName.length < 2 || formData.lastName.length > 50) return toast.error('Last name must be between 2 and 50 characters'), false;
- // Email
- if (!formData.emailAddress.trim()) return toast.error('Email address is required'), false;
- if (!/\S+@\S+\.\S+/.test(formData.emailAddress)) return toast.error('Enter a valid email (e.g. name@example.com)'), false;
+ // // Email
+ // if (!formData.emailAddress.trim()) return toast.error('Email address is required'), false;
+ // if (!/\S+@\S+\.\S+/.test(formData.emailAddress)) return toast.error('Enter a valid email (e.g. name@example.com)'), false;
- // ISD
- if (!formData.isdCode.trim()) return toast.error('ISD code is required'), false;
- if (/\s/.test(formData.isdCode)) return toast.error('ISD code must not contain spaces'), false;
- if (!formData.isdCode.startsWith('+')) return toast.error("ISD code must start with '+' (e.g. +91)"), false;
- if (!/^\+\d+$/.test(formData.isdCode)) return toast.error("ISD code must contain only digits after '+'"), false;
+ // // ISD
+ // if (!formData.isdCode.trim()) return toast.error('ISD code is required'), false;
+ // if (/\s/.test(formData.isdCode)) return toast.error('ISD code must not contain spaces'), false;
+ // if (!formData.isdCode.startsWith('+')) return toast.error("ISD code must start with '+' (e.g. +91)"), false;
+ // if (!/^\+\d+$/.test(formData.isdCode)) return toast.error("ISD code must contain only digits after '+'"), false;
- // Phone
- if (!formData.mobileNumber.trim()) return toast.error('Mobile number is required'), false;
- if (/\s/.test(formData.mobileNumber)) return toast.error('Mobile number must not contain spaces'), false;
- if (!/^\d+$/.test(formData.mobileNumber)) return toast.error('Mobile number must contain only digits (0–9)'), false;
- if (formData.mobileNumber.length < 7 || formData.mobileNumber.length > 15) return toast.error('Mobile number must be between 7 and 15 digits'), false;
+ // // Phone
+ // if (!formData.mobileNumber.trim()) return toast.error('Mobile number is required'), false;
+ // if (/\s/.test(formData.mobileNumber)) return toast.error('Mobile number must not contain spaces'), false;
+ // if (!/^\d+$/.test(formData.mobileNumber)) return toast.error('Mobile number must contain only digits (0–9)'), false;
+ // if (formData.mobileNumber.length < 7 || formData.mobileNumber.length > 15) return toast.error('Mobile number must be between 7 and 15 digits'), false;
- // Address
- if (!formData.address1.trim()) return toast.error('Address is required'), false;
- if (!/^[A-Za-z0-9\s,\-.]+$/.test(formData.address1)) return toast.error('Address can only contain letters, numbers, spaces, commas, dots, and hyphens'), false;
- if (formData.address1.length < 5 || formData.address1.length > 100) return toast.error('Address must be between 5 and 100 characters'), false;
+ // // Address
+ // if (!formData.address1.trim()) return toast.error('Address is required'), false;
+ // if (!/^[A-Za-z0-9\s,\-.]+$/.test(formData.address1)) return toast.error('Address can only contain letters, numbers, spaces, commas, dots, and hyphens'), false;
+ // if (formData.address1.length < 5 || formData.address1.length > 100) return toast.error('Address must be between 5 and 100 characters'), false;
- // City
- if (!formData.city.trim()) return toast.error('City is required'), false;
- if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.city)) return toast.error('City can only contain letters and spaces'), false;
- if (/\s{2,}/.test(formData.city)) return toast.error('City must not contain multiple consecutive spaces'), false;
+ // // City
+ // if (!formData.city.trim()) return toast.error('City is required'), false;
+ // if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.city)) return toast.error('City can only contain letters and spaces'), false;
+ // if (/\s{2,}/.test(formData.city)) return toast.error('City must not contain multiple consecutive spaces'), false;
- // State
- if (!formData.state.trim()) return toast.error('State is required'), false;
- if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.state)) return toast.error('State can only contain letters and spaces'), false;
- if (/\s{2,}/.test(formData.state)) return toast.error('State must not contain multiple consecutive spaces'), false;
+ // // State
+ // if (!formData.state.trim()) return toast.error('State is required'), false;
+ // if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.state)) return toast.error('State can only contain letters and spaces'), false;
+ // if (/\s{2,}/.test(formData.state)) return toast.error('State must not contain multiple consecutive spaces'), false;
- // Country
- if (!formData.country.trim()) return toast.error('Country is required'), false;
- if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.country)) return toast.error('Country can only contain letters and spaces'), false;
+ // // Country
+ // if (!formData.country.trim()) return toast.error('Country is required'), false;
+ // if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.country)) return toast.error('Country can only contain letters and spaces'), false;
- // Postal Code
- if (!formData.postalCode.trim()) return toast.error('Postal code is required'), false;
- if (/\s/.test(formData.postalCode)) return toast.error('Postal code must not contain spaces'), false;
- if (!/^[A-Za-z0-9]+$/.test(formData.postalCode)) return toast.error('Postal code must contain only letters and numbers'), false;
- if (formData.postalCode.length < 4 || formData.postalCode.length > 10) return toast.error('Postal code must be between 4 and 10 characters'), false;
+ // // Postal Code
+ // if (!formData.postalCode.trim()) return toast.error('Postal code is required'), false;
+ // if (/\s/.test(formData.postalCode)) return toast.error('Postal code must not contain spaces'), false;
+ // if (!/^[A-Za-z0-9]+$/.test(formData.postalCode)) return toast.error('Postal code must contain only letters and numbers'), false;
+ // if (formData.postalCode.length < 4 || formData.postalCode.length > 10) return toast.error('Postal code must be between 4 and 10 characters'), false;
- return true;
-};
+ // return true;
+ // };
+ const validateForm = () => {
+ const e: Record = {};
+ if (!formData.firstName.trim()) e.firstName = 'First name is required';
+ else if (/\s/.test(formData.firstName)) e.firstName = 'First name must not contain spaces';
+ else if (!/^[A-Za-z]+$/.test(formData.firstName)) e.firstName = 'First name must contain only letters (A–Z)';
+ else if (formData.firstName.length < 2 || formData.firstName.length > 50) e.firstName = 'First name must be between 2 and 50 characters';
+
+ if (!formData.lastName.trim()) e.lastName = 'Last name is required';
+ else if (/\s/.test(formData.lastName)) e.lastName = 'Last name must not contain spaces';
+ else if (!/^[A-Za-z]+$/.test(formData.lastName)) e.lastName = 'Last name must contain only letters (A–Z)';
+ else if (formData.lastName.length < 2 || formData.lastName.length > 50) e.lastName = 'Last name must be between 2 and 50 characters';
+
+ if (!formData.emailAddress.trim()) e.emailAddress = 'Email address is required';
+ else if (!/\S+@\S+\.\S+/.test(formData.emailAddress)) e.emailAddress = 'Enter a valid email (e.g. name@example.com)';
+
+ if (!formData.isdCode.trim()) e.isdCode = 'ISD code is required';
+ else if (/\s/.test(formData.isdCode)) e.isdCode = 'ISD code must not contain spaces';
+ else if (!formData.isdCode.startsWith('+')) e.isdCode = "ISD code must start with '+' (e.g. +91)";
+ else if (!/^\+\d+$/.test(formData.isdCode)) e.isdCode = "ISD code must contain only digits after '+'";
+
+ if (!formData.mobileNumber.trim()) e.mobileNumber = 'Mobile number is required';
+ else if (/\s/.test(formData.mobileNumber)) e.mobileNumber = 'Mobile number must not contain spaces';
+ else if (!/^\d+$/.test(formData.mobileNumber)) e.mobileNumber = 'Mobile number must contain only digits (0–9)';
+ else if (formData.mobileNumber.length < 7 || formData.mobileNumber.length > 15) e.mobileNumber = 'Mobile number must be between 7 and 15 digits';
+
+ if (!formData.address1.trim()) e.address1 = 'Address is required';
+ else if (!/^[A-Za-z0-9\s,\-.]+$/.test(formData.address1)) e.address1 = 'Address can only contain letters, numbers, spaces, commas, dots, and hyphens';
+ else if (formData.address1.length < 5 || formData.address1.length > 100) e.address1 = 'Address must be between 5 and 100 characters';
+
+ if (!formData.city.trim()) e.city = 'City is required';
+ else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.city)) e.city = 'City can only contain letters and spaces';
+ else if (/\s{2,}/.test(formData.city)) e.city = 'City must not contain multiple consecutive spaces';
+
+ if (!formData.state.trim()) e.state = 'State is required';
+ else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.state)) e.state = 'State can only contain letters and spaces';
+ else if (/\s{2,}/.test(formData.state)) e.state = 'State must not contain multiple consecutive spaces';
+
+ if (!formData.country.trim()) e.country = 'Country is required';
+ else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(formData.country)) e.country = 'Country can only contain letters and spaces';
+ else if (formData.country.length < 2 || formData.country.length > 50) e.country = 'Country must be between 2 and 50 characters';
+
+ if (!formData.postalCode.trim()) e.postalCode = 'Postal code is required';
+ else if (/\s/.test(formData.postalCode)) e.postalCode = 'Postal code must not contain spaces';
+ else if (!/^[A-Za-z0-9]+$/.test(formData.postalCode)) e.postalCode = 'Postal code must contain only letters and numbers';
+ else if (formData.postalCode.length < 4 || formData.postalCode.length > 10) e.postalCode = 'Postal code must be between 4 and 10 characters';
+
+ setFieldErrors(e);
+ return Object.keys(e).length === 0;
+ };
+
+ // Helper to render inline error (add once near top of return or as a small component)
+ const FieldError = ({ name }: { name: string }) =>
+ fieldErrors[name] ? (
+
diff --git a/src/pages/PaymentDetailsPage.tsx b/src/pages/PaymentDetailsPage.tsx
index cc86e0a..24ef775 100644
--- a/src/pages/PaymentDetailsPage.tsx
+++ b/src/pages/PaymentDetailsPage.tsx
@@ -85,7 +85,7 @@ function Field({
prefilled,
disabled = false,
}: {
- label: string;
+ label: React.ReactNode;
value: string;
onChange: (v: string) => void;
placeholder?: string;
@@ -230,64 +230,64 @@ export function PaymentDetailsPage({
const [errors, setErrors] = useState>({});
-const validate = () => {
- const e: Record = {};
+ const validate = () => {
+ const e: Record = {};
- if (selectedTab === 'gift') {
- // First Name
- if (!giftFirstName.trim()) e.giftFirstName = 'First name is required';
- else if (/\s/.test(giftFirstName)) e.giftFirstName = 'First name must not contain spaces';
- else if (!/^[A-Za-z]+$/.test(giftFirstName)) e.giftFirstName = 'First name must contain only letters (A–Z)';
- else if (giftFirstName.length < 2 || giftFirstName.length > 50) e.giftFirstName = 'First name must be between 2 and 50 characters';
+ if (selectedTab === 'gift') {
+ // First Name
+ if (!giftFirstName.trim()) e.giftFirstName = 'First name is required';
+ else if (/\s/.test(giftFirstName)) e.giftFirstName = 'First name must not contain spaces';
+ else if (!/^[A-Za-z]+$/.test(giftFirstName)) e.giftFirstName = 'First name must contain only letters (A–Z)';
+ else if (giftFirstName.length < 2 || giftFirstName.length > 50) e.giftFirstName = 'First name must be between 2 and 50 characters';
- // Last Name
- if (!giftLastName.trim()) e.giftLastName = 'Last name is required';
- else if (/\s/.test(giftLastName)) e.giftLastName = 'Last name must not contain spaces';
- else if (!/^[A-Za-z]+$/.test(giftLastName)) e.giftLastName = 'Last name must contain only letters (A–Z)';
- else if (giftLastName.length < 2 || giftLastName.length > 50) e.giftLastName = 'Last name must be between 2 and 50 characters';
+ // Last Name
+ if (!giftLastName.trim()) e.giftLastName = 'Last name is required';
+ else if (/\s/.test(giftLastName)) e.giftLastName = 'Last name must not contain spaces';
+ else if (!/^[A-Za-z]+$/.test(giftLastName)) e.giftLastName = 'Last name must contain only letters (A–Z)';
+ else if (giftLastName.length < 2 || giftLastName.length > 50) e.giftLastName = 'Last name must be between 2 and 50 characters';
- // ISD Code
- if (!giftIsd.trim()) e.giftIsd = 'ISD code is required';
- else if (/\s/.test(giftIsd)) e.giftIsd = 'ISD code must not contain spaces';
- else if (!giftIsd.startsWith('+')) e.giftIsd = "ISD code must start with '+' (e.g. +91)";
- else if (!/^\+\d+$/.test(giftIsd)) e.giftIsd = "ISD code must contain only digits after '+'";
+ // ISD Code
+ if (!giftIsd.trim()) e.giftIsd = 'ISD code is required';
+ else if (/\s/.test(giftIsd)) e.giftIsd = 'ISD code must not contain spaces';
+ else if (!giftIsd.startsWith('+')) e.giftIsd = "ISD code must start with '+' (e.g. +91)";
+ else if (!/^\+\d+$/.test(giftIsd)) e.giftIsd = "ISD code must contain only digits after '+'";
- // Email
- if (!giftEmail.trim()) e.giftEmail = 'Email address is required';
- else if (!/\S+@\S+\.\S+/.test(giftEmail)) e.giftEmail = 'Enter a valid email (e.g. name@example.com)';
+ // Email
+ if (!giftEmail.trim()) e.giftEmail = 'Email address is required';
+ else if (!/\S+@\S+\.\S+/.test(giftEmail)) e.giftEmail = 'Enter a valid email (e.g. name@example.com)';
- // Phone
- if (!giftPhone.trim()) e.giftPhone = 'Phone number is required';
- else if (/\s/.test(giftPhone)) e.giftPhone = 'Phone number must not contain spaces';
- else if (!/^\d+$/.test(giftPhone)) e.giftPhone = 'Phone number must contain only digits (0–9)';
- else if (giftPhone.length < 7 || giftPhone.length > 15) e.giftPhone = 'Phone number must be between 7 and 15 digits';
+ // Phone
+ if (!giftPhone.trim()) e.giftPhone = 'Phone number is required';
+ else if (/\s/.test(giftPhone)) e.giftPhone = 'Phone number must not contain spaces';
+ else if (!/^\d+$/.test(giftPhone)) e.giftPhone = 'Phone number must contain only digits (0–9)';
+ else if (giftPhone.length < 7 || giftPhone.length > 15) e.giftPhone = 'Phone number must be between 7 and 15 digits';
- // Message
- if (!giftMessage.trim()) e.giftMessage = 'Message is required';
- else if (giftMessage.length < 5) e.giftMessage = 'Message must be at least 5 characters long';
- else if (giftMessage.length > 500) e.giftMessage = 'Message must not exceed 500 characters';
+ // Message
+ if (!giftMessage.trim()) e.giftMessage = 'Message is required';
+ else if (giftMessage.length < 5) e.giftMessage = 'Message must be at least 5 characters long';
+ else if (giftMessage.length > 500) e.giftMessage = 'Message must not exceed 500 characters';
- // City
- if (!giftCity.trim()) e.giftCity = 'City is required';
- else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(giftCity)) e.giftCity = 'City can only contain letters and spaces';
- else if (/\s{2,}/.test(giftCity)) e.giftCity = 'City must not contain multiple consecutive spaces';
- else if (giftCity.length < 2 || giftCity.length > 50) e.giftCity = 'City must be between 2 and 50 characters';
+ // City
+ if (!giftCity.trim()) e.giftCity = 'City is required';
+ else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(giftCity)) e.giftCity = 'City can only contain letters and spaces';
+ else if (/\s{2,}/.test(giftCity)) e.giftCity = 'City must not contain multiple consecutive spaces';
+ else if (giftCity.length < 2 || giftCity.length > 50) e.giftCity = 'City must be between 2 and 50 characters';
- // Country
- if (!giftCountry.trim()) e.giftCountry = 'Country is required';
- else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(giftCountry)) e.giftCountry = 'Country can only contain letters and spaces';
- else if (giftCountry.length < 2 || giftCountry.length > 50) e.giftCountry = 'Country must be between 2 and 50 characters';
- }
+ // Country
+ if (!giftCountry.trim()) e.giftCountry = 'Country is required';
+ else if (!/^[A-Za-z\s\-'À-ÿ]+$/.test(giftCountry)) e.giftCountry = 'Country can only contain letters and spaces';
+ else if (giftCountry.length < 2 || giftCountry.length > 50) e.giftCountry = 'Country must be between 2 and 50 characters';
+ }
- return e;
-};
+ return e;
+ };
const [isRedirecting, setIsRedirecting] = useState(false);
const handlePayment = async () => {
const validationErrors = validate();
setErrors(validationErrors);
if (Object.keys(validationErrors).length > 0) {
- toast.error('Please fill all required fields');
+ // toast.error('Please fill all required fields');
return;
}
@@ -413,8 +413,8 @@ const validate = () => {