Skip to content

Commit

Permalink
Merge pull request #28 from KonferCA/feat/23/register-wallet
Browse files Browse the repository at this point in the history
Registration Page
  • Loading branch information
aidantrabs authored Nov 20, 2024
2 parents 57a547d + 4708ff0 commit a9c6864
Show file tree
Hide file tree
Showing 15 changed files with 585 additions and 50 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@eslint/js": "^9.13.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 0 additions & 10 deletions src/components/Dummy.test.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions src/components/Dummy.tsx

This file was deleted.

13 changes: 13 additions & 0 deletions src/components/FormContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ReactNode } from 'react';

const FormContainer = ({ children }: { children: ReactNode }) => {
return (
<div className="min-h-screen flex flex-col items-center px-4">
<div className="w-full max-w-xl p-8">
{children}
</div>
</div>
);
};

export { FormContainer };
73 changes: 73 additions & 0 deletions src/components/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { forwardRef } from 'react';
import { Field, Label, Textarea } from '@headlessui/react';

interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
label?: string;
error?: string;
description?: string;
value?: string;
required?: boolean;
onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
}

const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
({ label, error, description, className = '', value, required, onChange, ...props }, ref) => {
const inputProps = onChange
? { value, onChange }
: { defaultValue: value };

const sharedClassNames = `
w-full px-4 py-2
bg-white
border border-gray-300
rounded-md
focus:outline-none focus:ring-2 focus:ring-blue-500
data-[invalid]:border-red-500
min-h-[100px] resize-y
${className}
`;

return (
<div className="w-full">
<Field>
{label && (
<div className="flex justify-between items-center mb-1">
<Label className="block text-md font-normal">
{label}
</Label>
{required && (
<span className="text-sm text-gray-500">
Required
</span>
)}
</div>
)}

<Textarea
ref={ref}
className={sharedClassNames}
invalid={!!error}
required={required}
{...inputProps}
{...props}
/>

{description && (
<div className="mt-1 text-sm text-gray-500">
{description}
</div>
)}

{error && (
<div className="mt-1 text-sm text-red-500">
{error}
</div>
)}
</Field>
</div>
);
}
);

TextArea.displayName = 'TextArea';
export { TextArea };
45 changes: 29 additions & 16 deletions src/components/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,57 @@ interface TextInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
error?: string;
description?: string;
value?: string;
required?: boolean;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
}

const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
({ label, error, description, className = '', value, onChange, ...props }, ref) => {
({ label, error, description, className = '', value, required, onChange, ...props }, ref) => {
const inputProps = onChange
? { value, onChange }
: { defaultValue: value };

const sharedClassNames = `
w-full px-4 py-3
bg-white
border border-gray-300
rounded-md
focus:outline-none focus:ring-2 focus:ring-blue-500
data-[invalid]:border-red-500
${className}
`;

return (
<div className="max-w-[400px] w-full">
<div className="w-full">
<Field>
{label && (
<Label className="block text-2xl font-bold">
{label}
</Label>
<div className="flex justify-between items-center mb-1">
<Label className="block text-md font-normal">
{label}
</Label>
{required && (
<span className="text-sm text-gray-500">
Required
</span>
)}
</div>
)}

<Input
ref={ref}
className={`
w-full py-3 px-4
bg-white
border border-gray-300
rounded-md
focus:outline-none focus:ring-2 focus:ring-blue-500
data-[invalid]:border-red-500
${className}
`}
className={sharedClassNames}
invalid={!!error}
required={required}
{...inputProps}
{...props}
/>

{description && (
<div className="mt-1 text-sm text-gray-500">
{description}
</div>
)}

{error && (
<div className="mt-1 text-sm text-red-500">
{error}
Expand All @@ -55,5 +69,4 @@ const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
);

TextInput.displayName = 'TextInput';

export { TextInput };
export { TextInput };
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { TextInput } from './TextInput';
export { TextArea } from './TextArea';
export { Dropdown } from './Dropdown';
export { FileUpload } from './FileUpload';
export { InfoCard } from './InfoCard';
export { Button } from './Button';
export { FormContainer } from './FormContainer';
65 changes: 65 additions & 0 deletions src/components/tests/TextArea.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { TextArea } from '@components';

describe('TextArea', () => {
it('renders with basic props', () => {
render(<TextArea placeholder="Enter text" />);
expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument();
});

it('renders label when provided', () => {
render(<TextArea label="Description" />);
expect(screen.getByText('Description')).toBeInTheDocument();
});

it('shows required text when required prop is true', () => {
render(<TextArea label="Description" required />);
expect(screen.getByText('Required')).toBeInTheDocument();
});

it('displays error message', () => {
render(<TextArea error="This field is required" />);
expect(screen.getByText('This field is required')).toBeInTheDocument();
});

it('displays description text', () => {
render(<TextArea description="Enter detailed description" />);
expect(screen.getByText('Enter detailed description')).toBeInTheDocument();
});

it('handles onChange events', async () => {
const handleChange = vi.fn();
render(<TextArea onChange={handleChange} />);

const textarea = screen.getByRole('textbox');
await userEvent.type(textarea, 'test');

expect(handleChange).toHaveBeenCalled();
expect(textarea).toHaveValue('test');
});

it('forwards ref correctly', () => {
const ref = vi.fn();
render(<TextArea ref={ref} />);
expect(ref).toHaveBeenCalled();
});

it('applies custom className', () => {
render(<TextArea className="custom-class" />);
expect(screen.getByRole('textbox')).toHaveClass('custom-class');
});

it('allows resizing', () => {
render(<TextArea />);
const textarea = screen.getByRole('textbox');
expect(textarea).toHaveClass('resize-y');
});

it('has minimum height', () => {
render(<TextArea />);
const textarea = screen.getByRole('textbox');
expect(textarea).toHaveClass('min-h-[100px]');
});
});
53 changes: 53 additions & 0 deletions src/components/tests/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { TextInput } from '@components';

describe('TextInput', () => {
it('renders with basic props', () => {
render(<TextInput placeholder="Enter text" />);
expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument();
});

it('renders label when provided', () => {
render(<TextInput label="Name" />);
expect(screen.getByText('Name')).toBeInTheDocument();
});

it('shows required text when required prop is true', () => {
render(<TextInput label="Name" required />);
expect(screen.getByText('Required')).toBeInTheDocument();
});

it('displays error message', () => {
render(<TextInput error="This field is required" />);
expect(screen.getByText('This field is required')).toBeInTheDocument();
});

it('displays description text', () => {
render(<TextInput description="Enter your full name" />);
expect(screen.getByText('Enter your full name')).toBeInTheDocument();
});

it('handles onChange events', async () => {
const handleChange = vi.fn();
render(<TextInput onChange={handleChange} />);

const input = screen.getByRole('textbox');
await userEvent.type(input, 'test');

expect(handleChange).toHaveBeenCalled();
expect(input).toHaveValue('test');
});

it('forwards ref correctly', () => {
const ref = vi.fn();
render(<TextInput ref={ref} />);
expect(ref).toHaveBeenCalled();
});

it('applies custom className', () => {
render(<TextInput className="custom-class" />);
expect(screen.getByRole('textbox')).toHaveClass('custom-class');
});
});
6 changes: 6 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
@import url('https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap');

@tailwind base;
@tailwind components;
@tailwind utilities;

body {
font-family: 'Kanit', sans-serif;
}
Loading

0 comments on commit a9c6864

Please sign in to comment.