Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions app/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Image from "next/image"
import Link from "next/link"

const Layout = ({children} : {children:React.ReactNode} ) => {
return (
<main className="auth-layout">
<section className="auth-left-section scrollbar-hide-default">
<Link href='/' className="auth-logo">
<Image src="/assets/icons/logo.svg" alt="App-logo" width={140} height={32} className="h-8 w-auto" />
</Link>

<div className="pb-6 lg:pb-8 flex-1">
{children}
</div>
</section>

<section className="auth-right-section">
<div className="z-10 relative lg:mt-4 lg:mb-16">
<blockquote className="auth-blockquote">
"Be fearful when others are greedy, and greedy when others are fearful."

</blockquote>
<div className="flex items-center justify-between">
<div>
<cite className="auth-testimonial-author">— Warren Buffett</cite>
<p className="max-md:text-xs text-gray-500">Chairman and CEO of Berkshire Hathaway</p>
</div>
</div>
</div>

<div className="flex-1 relative">
<Image src="/assets/images/dashboard.png" alt="Dashboard" width={1440} height={1150} className="auth-dashboard-preview absolute top-0"/>
</div>
</section>
</main>
)
}
export default Layout
68 changes: 68 additions & 0 deletions app/(auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use client'
import React from 'react'
import InputField from '@/components/forms/InputField'
import FooterLink from '@/components/forms/FooterLink'
import { Button } from '@/components/ui/button'
import { SubmitHandler, useForm } from 'react-hook-form'

type SignInFormData = {
email: string
password: string
}
Comment on lines +8 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove duplicate type definition.

The SignInFormData type is already defined globally in types/global.d.ts (lines 2-5). This local redefinition is unnecessary and creates maintenance overhead.

Apply this diff to remove the duplicate type:

 'use client'
 import React from 'react'
 import InputField from '@/components/forms/InputField'
 import FooterLink from '@/components/forms/FooterLink'
 import { Button } from '@/components/ui/button'
 import { SubmitHandler, useForm } from 'react-hook-form'

-type SignInFormData = {
-  email: string
-  password: string
-}
-
 const SignIn = () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type SignInFormData = {
email: string
password: string
}
'use client'
import React from 'react'
import InputField from '@/components/forms/InputField'
import FooterLink from '@/components/forms/FooterLink'
import { Button } from '@/components/ui/button'
import { SubmitHandler, useForm } from 'react-hook-form'
const SignIn = () => {
// ... rest of component
🤖 Prompt for AI Agents
In app/(auth)/sign-in/page.tsx around lines 8 to 11 there is a local duplicate
type definition for SignInFormData; remove these lines so the file uses the
globally declared SignInFormData from types/global.d.ts, and update any
imports/usages if necessary to reference the global type (no new imports should
be required).


const SignIn = () => {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<SignInFormData>({
defaultValues: {
email: '',
password: '',
},
mode: 'onBlur'
})

const onSubmit: SubmitHandler<SignInFormData> = async (data) => {
try {
console.log(data)
} catch (e) {
console.error(e)
}
}

return (
<>
<h1 className='form-title'>Welcome Back</h1>

<form onSubmit={handleSubmit(onSubmit)} className='space-y-5'>
<InputField
name="email"
label="Email"
placeholder="contact@example.com"
register={register}
error={errors.email}
validation={{ required: 'Email is required', pattern: { value: /^\w+@\w+\.\w+$/, message: 'Invalid email format' } }}
/>

<InputField
name="password"
label="Password"
placeholder="Enter your password"
type="password"
register={register}
error={errors.password}
validation={{ required: 'Password is required' }}
/>

<Button type='submit' disabled={isSubmitting} className='yellow-btn w-full mt-5'>
{isSubmitting ? 'Signing In...' : 'Sign In'}
</Button>

<FooterLink text="Don't have an account?" linkText='Sign-up' href='/sign-up' />
</form>
</>
)
}

export default SignIn
123 changes: 123 additions & 0 deletions app/(auth)/sign-up/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use client'
import { CountrySelectField } from '@/components/forms/CountrySelectField';
import FooterLink from '@/components/forms/FooterLink';
import InputField from '@/components/forms/InputField';
import SelectField from '@/components/forms/SelectField';
import { Button } from '@/components/ui/button';
import { INVESTMENT_GOALS, PREFERRED_INDUSTRIES, RISK_TOLERANCE_OPTIONS } from '@/lib/constants';
import { SubmitHandler, useForm } from 'react-hook-form'

const SignUp = () => {
const {
register,
handleSubmit,
watch,
control,

formState: { errors, isSubmitting },
} = useForm<SignUpFormData>({

defaultValues: {
fullName: '',
email: '',
password: '',
country: 'INDIA',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Incorrect country default value format.

The default value 'INDIA' doesn't match ISO 3166-1 alpha-2 format expected by react-select-country-list. The library expects two-letter codes like 'IN' for India.

Apply this diff to fix the country code:

        defaultValues: {
            fullName: '',
            email: '',
            password: '',
-           country: 'INDIA',
+           country: 'IN',
            investmentGoals: 'Growth',
            riskTolerance: 'Medium',
            preferredIndustry: 'Technology'
        },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
country: 'INDIA',
defaultValues: {
fullName: '',
email: '',
password: '',
country: 'IN',
investmentGoals: 'Growth',
riskTolerance: 'Medium',
preferredIndustry: 'Technology'
},
🤖 Prompt for AI Agents
In app/(auth)/sign-up/page.tsx around line 24 the default country value is set
to 'INDIA' which is not the ISO 3166-1 alpha-2 format required by
react-select-country-list; change the value to the two-letter code 'IN' (and
update any related default/state typing or tests if they assume the long name)
so the country selector receives the expected 'IN' code.

investmentGoals: 'Growth',
riskTolerance: 'Medium',
preferredIndustry: 'Technology'
},
mode: 'onBlur'
}, );

const onSubmit = async(data: SignUpFormData) => {
try {
console.log(data);
}catch (e){
console.error(e);
}
}
return (
<>
<h1 className='form-title'>Sign Up & Personalize</h1>

<form onSubmit={handleSubmit(onSubmit)} className='space-y-5'>
{/* Input */}
<InputField
name="fullName"
label="Full Name"
placeholder="John Doe"
register={register}
error={errors.fullName}
validation={{ required: 'Full name is required', minLength: 2 }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add validation message for minLength.

The minLength validation is incomplete. React Hook Form expects either a number (for basic validation) or an object with value and message properties.

Apply this diff to add a validation message:

-           validation={{ required: 'Full name is required', minLength: 2 }}
+           validation={{ required: 'Full name is required', minLength: { value: 2, message: 'Full name must be at least 2 characters' } }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
validation={{ required: 'Full name is required', minLength: 2 }}
validation={{
required: 'Full name is required',
minLength: { value: 2, message: 'Full name must be at least 2 characters' }
}}
🤖 Prompt for AI Agents
In app/(auth)/sign-up/page.tsx around line 51 the validation prop uses
minLength: 2 without an accompanying message; update minLength to an object with
value and message (e.g., minLength: { value: 2, message: 'Full name must be at
least 2 characters' }) so React Hook Form receives both the numeric rule and a
user-facing error string.

/>

<InputField
name="email"
label="Email"
placeholder="contact@jsmastery.com"
register={register}
error={errors.email}
validation={{ required: 'Email name is required', pattern: /^\w+@\w+\.\w+$/, message: 'Email address is required' }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix malformed email validation pattern.

The validation object structure is incorrect. The pattern property should be an object containing value and message, but here message is at the same level as pattern.

Apply this diff to fix the validation:

-           validation={{ required: 'Email name is required', pattern: /^\w+@\w+\.\w+$/, message: 'Email address is required' }}
+           validation={{ required: 'Email is required', pattern: { value: /^\w+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email format' } }}

Note: Also improved the regex pattern to better match email formats and fixed the typo "Email name" → "Email".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
validation={{ required: 'Email name is required', pattern: /^\w+@\w+\.\w+$/, message: 'Email address is required' }}
validation={{
required: 'Email is required',
pattern: {
value: /^\w+@[^\s@]+\.[^\s@]+$/,
message: 'Invalid email format'
}
}}
🤖 Prompt for AI Agents
In app/(auth)/sign-up/page.tsx around line 60, the validation object is
malformed: `pattern` and its `message` are at the same level and the required
message text has a typo. Replace the current validation with a proper structure
where `pattern` is an object containing `value` (the regex) and `message` (error
text), update `required` to "Email is required", and use an improved email regex
(e.g. that allows common characters, dots and hyphens) with a corresponding
"Invalid email address" message.

/>

<InputField
name="password"
label="Password"
placeholder="Enter a strong password"
type="password"
register={register}
error={errors.password}
validation={{ required: 'Password is required', minLength: 8 }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add validation message for minLength.

Similar to the fullName field, the password minLength validation lacks a message.

Apply this diff to add a validation message:

-           validation={{ required: 'Password is required', minLength: 8 }}
+           validation={{ required: 'Password is required', minLength: { value: 8, message: 'Password must be at least 8 characters' } }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
validation={{ required: 'Password is required', minLength: 8 }}
validation={{
required: 'Password is required',
minLength: { value: 8, message: 'Password must be at least 8 characters' }
}}
🤖 Prompt for AI Agents
In app/(auth)/sign-up/page.tsx around line 70 the password field's validation
uses minLength: 8 without a validation message; update the validation to use an
object with value and message (e.g. minLength: { value: 8, message: 'Password
must be at least 8 characters' }) so the form shows a clear error like the
fullName field does.

/>

<CountrySelectField
name="country"
label="Country"
control={control}
error={errors.country}
required
/>
<SelectField
name="investmentGoals"
label="Investment Goals"
placeholder="Select your investment goal"
options={INVESTMENT_GOALS}
control={control}
error={errors.investmentGoals}
required

/>

<SelectField
name="riskTolerance"
label="Risk Tolerance"
placeholder="Select your risk level"
options={RISK_TOLERANCE_OPTIONS}
control={control}
error={errors.riskTolerance}
required

/>

<SelectField
name="preferredIndustry"
label="Preferred Industry"
placeholder="Select your preferred industry"
options={PREFERRED_INDUSTRIES}
control={control}
error={errors.preferredIndustry}
required

/>

<Button type='submit' disabled={isSubmitting} className='yellow-btn w-full mt-5'>
{isSubmitting ? 'Creating Account' : 'Start Your Investing Journey'}
</Button>

<FooterLink text='Already Have an Account ?' linkText='Sign-in' href='/sign-in' />
</form>
</>
)
}

export default SignUp
146 changes: 146 additions & 0 deletions components/forms/CountrySelectField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Avoid disabling TypeScript checks.

The @typescript-eslint/no-explicit-any rule is disabled, but the any types on lines 28 should be properly typed using React Hook Form's generic types.

Apply this diff to properly type the control:

-/* eslint-disable @typescript-eslint/no-explicit-any */
 'use client';

And update the type definition:

 type CountrySelectProps = {
     name: string;
     label: string;
-    control: Control<any>;
+    control: Control<SignUpFormData>; // or use a generic type parameter
     error?: FieldError;
     required?: boolean;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* eslint-disable @typescript-eslint/no-explicit-any */
// components/forms/CountrySelectField.tsx
// Remove the eslint-disable for `any` and ensure we opt into React’s “use client” mode
'use client';
import { Control, FieldError } from 'react-hook-form';
// (Make sure you have an import for SignUpFormData, e.g.)
// import { SignUpFormData } from '@/types/form';
// …
type CountrySelectProps = {
name: string;
label: string;
control: Control<SignUpFormData>; // tighten from `any` to your form’s data shape
error?: FieldError;
required?: boolean;
};
// …

'use client';

import { useState } from 'react';
import { Control, Controller, FieldError } from 'react-hook-form';
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover';
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/components/ui/command';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Check, ChevronsUpDown } from 'lucide-react';
import { cn } from '@/lib/utils';
import countryList from 'react-select-country-list';

type CountrySelectProps = {
name: string;
label: string;
control: Control<any>;
error?: FieldError;
required?: boolean;
};
Comment on lines +25 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove duplicate type definition.

The CountrySelectProps type is already defined globally in types/global.d.ts (lines 17-23). This local redefinition should be removed.

Apply this diff:

 import { cn } from '@/lib/utils';
 import countryList from 'react-select-country-list';

-type CountrySelectProps = {
-    name: string;
-    label: string;
-    control: Control<any>;
-    error?: FieldError;
-    required?: boolean;
-};
-
 const CountrySelect = ({
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type CountrySelectProps = {
name: string;
label: string;
control: Control<any>;
error?: FieldError;
required?: boolean;
};
import { cn } from '@/lib/utils';
import countryList from 'react-select-country-list';
const CountrySelect = ({
name,
label,
control,
error,
required,
}: CountrySelectProps) => {
// …rest of component implementation
};
🤖 Prompt for AI Agents
In components/forms/CountrySelectField.tsx around lines 25 to 31, remove the
local duplicate CountrySelectProps type declaration (since it’s already defined
in types/global.d.ts lines 17-23); delete the entire local type block and ensure
the component uses the existing global CountrySelectProps without re-declaring
it (also remove any now-unused imports or references introduced solely for the
deleted type).


const CountrySelect = ({
value,
onChange,
}: {
value: string;
onChange: (value: string) => void;
}) => {
const [open, setOpen] = useState(false);

// Get country options with flags
const countries = countryList().getData();

// Helper function to get flag emoji
const getFlagEmoji = (countryCode: string) => {
const codePoints = countryCode
.toUpperCase()
.split('')
.map((char) => 127397 + char.charCodeAt(0));
return String.fromCodePoint(...codePoints);
};

return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant='outline'
role='combobox'
aria-expanded={open}
className='country-select-trigger'
>
{value ? (
<span className='flex items-center gap-2'>
<span>{getFlagEmoji(value)}</span>
<span>{countries.find((c) => c.value === value)?.label}</span>
</span>
) : (
'Select your country...'
)}
<ChevronsUpDown className='ml-2 h-4 w-4 shrink-0 opacity-50' />
</Button>
</PopoverTrigger>
<PopoverContent
className='w-full p-0 bg-gray-800 border-gray-600'
align='start'
>
<Command className='bg-gray-800 border-gray-600'>
<CommandInput
placeholder='Search countries...'
className='country-select-input'
/>
<CommandEmpty className='country-select-empty'>
No country found.
</CommandEmpty>
<CommandList className='max-h-60 bg-gray-800 scrollbar-hide-default'>
<CommandGroup className='bg-gray-800'>
{countries.map((country) => (
<CommandItem
key={country.value}
value={`${country.label} ${country.value}`}
onSelect={() => {
onChange(country.value);
setOpen(false);
}}
className='country-select-item'
>
<Check
className={cn(
'mr-2 h-4 w-4 text-yellow-500',
value === country.value ? 'opacity-100' : 'opacity-0'
)}
/>
<span className='flex items-center gap-2'>
<span>{getFlagEmoji(country.value)}</span>
<span>{country.label}</span>
</span>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
};

export const CountrySelectField = ({
name,
label,
control,
error,
required = false,
}: CountrySelectProps) => {
return (
<div className='space-y-2'>
<Label htmlFor={name} className='form-label'>
{label}
</Label>
<Controller
name={name}
control={control}
rules={{
required: required ? `Please select ${label.toLowerCase()}` : false,
}}
render={({ field }) => (
<CountrySelect value={field.value} onChange={field.onChange} />
)}
/>
{error && <p className='text-sm text-red-500'>{error.message}</p>}
<p className='text-xs text-gray-500'>
Helps us show market data and news relevant to you.
</p>
</div>
);
};
16 changes: 16 additions & 0 deletions components/forms/FooterLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

import Link from 'next/link'
import React from 'react'

const FooterLink = ({text, linkText , href} : FooterLinkProps) => (
<div className='text-center pt-4'>
<p className='text-sm text-gray-500'>
{text}{` `}
<Link href={href} className='footer-link'>
{linkText}
</Link>
</p>
</div>
)

export default FooterLink
Loading