> For the complete documentation index, see [llms.txt](https://optim-finance.gitbook.io/optim-finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://optim-finance.gitbook.io/optim-finance/oada-ui/tutorials/working-with-components.md).

# Working with Components

This tutorial will guide you through working with components in the OADA UI project. You'll learn how to create, customize, and compose components effectively, following the project's best practices and design patterns.

### Component Basics

#### 1. Component Structure

Every component in the project follows a consistent structure:

```typescript
import React from 'react';
import { useStyles } from './styles';

interface ComponentProps {
  // Component props
}

export const Component: React.FC<ComponentProps> = ({
  // Destructured props
}) => {
  const styles = useStyles();

  return (
    // Component JSX
  );
};
```

#### 2. Component Types

The project uses several types of components:

1. **Presentational Components**
   * Focus on how things look
   * Receive data via props
   * Rarely have their own state
   * Example: `Button`, `Card`, `Input`
2. **Container Components**
   * Focus on how things work
   * Manage state and data
   * Connect to Redux store
3. **Layout Components**
   * Define page structure
   * Handle responsive design

### Creating Components

#### 1. Basic Component

Let's create a simple `Card` component:

```typescript
// src/components/common/Card.tsx
import React from "react";
import { useStyles } from "./styles";

interface CardProps {
  title?: string;
  children: React.ReactNode;
  className?: string;
}

export const Card: React.FC<CardProps> = ({ title, children, className }) => {
  const styles = useStyles();

  return (
    <div className={`${styles.card} ${className || ""}`}>
      {title && <h3 className={styles.title}>{title}</h3>}
      <div className={styles.content}>{children}</div>
    </div>
  );
};
```

#### 2. Form Components

Creating a reusable form input:

```typescript
// src/components/forms/Input.tsx
import React from "react";
import { useStyles } from "./styles";

interface InputProps {
  label?: string;
  name: string;
  type?: "text" | "password" | "email";
  value: string;
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
  error?: string;
  required?: boolean;
}

export const Input: React.FC<InputProps> = ({
  label,
  name,
  type = "text",
  value,
  onChange,
  error,
  required = false,
}) => {
  const styles = useStyles();

  return (
    <div className={styles.container}>
      {label && (
        <label htmlFor={name} className={styles.label}>
          {label}
          {required && <span className={styles.required}>*</span>}
        </label>
      )}
      <input
        id={name}
        name={name}
        type={type}
        value={value}
        onChange={onChange}
        className={`${styles.input} ${error ? styles.error : ""}`}
      />
      {error && <span className={styles.errorMessage}>{error}</span>}
    </div>
  );
};
```

#### 3. Composite Components

Creating a form using composition:

```typescript
// src/components/forms/LoginForm.tsx
import React from "react";
import { useStyles } from "./styles";
import { Input } from "./Input";
import { Button } from "../common/Button";

interface LoginFormProps {
  onSubmit: (data: { email: string; password: string }) => void;
}

export const LoginForm: React.FC<LoginFormProps> = ({ onSubmit }) => {
  const styles = useStyles();
  const [formData, setFormData] = React.useState({
    email: "",
    password: "",
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    onSubmit(formData);
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData((prev) => ({ ...prev, [name]: value }));
  };

  return (
    <form onSubmit={handleSubmit} className={styles.form}>
      <Input
        label="Email"
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
        required
      />
      <Input
        label="Password"
        name="password"
        type="password"
        value={formData.password}
        onChange={handleChange}
        required
      />
      <Button type="submit" variant="primary">
        Login
      </Button>
    </form>
  );
};
```

### Component Styling

#### 1. Using Tailwind CSS

```typescript
// src/components/common/Button.tsx
interface ButtonProps {
  variant?: "primary" | "secondary" | "outline";
  size?: "sm" | "md" | "lg";
  children: React.ReactNode;
}

export const Button: React.FC<ButtonProps> = ({
  variant = "primary",
  size = "md",
  children,
}) => {
  const baseStyles = "rounded-md font-medium transition-colors";
  const variantStyles = {
    primary: "bg-primary-500 text-white hover:bg-primary-600",
    secondary: "bg-secondary-500 text-white hover:bg-secondary-600",
    outline: "border border-gray-300 hover:bg-gray-50",
  };
  const sizeStyles = {
    sm: "px-3 py-1.5 text-sm",
    md: "px-4 py-2 text-base",
    lg: "px-6 py-3 text-lg",
  };

  return (
    <button
      className={`${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]}`}
    >
      {children}
    </button>
  );
};
```

#### 2. CSS Modules

```typescript
// src/components/common/Card/styles.module.css
.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  padding: 1.5rem;
}

.title {
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 1rem;
}

.content {
  color: #4a5568;
}
```

### Component Testing

#### 1. Unit Testing

```typescript
// src/components/common/Button.test.tsx
import React from "react";
import { render, screen } from "@testing-library/react";
import { Button } from "./Button";

describe("Button", () => {
  it("renders with default props", () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText("Click me")).toBeInTheDocument();
  });

  it("applies variant styles", () => {
    render(<Button variant="primary">Primary</Button>);
    expect(screen.getByText("Primary")).toHaveClass("bg-primary-500");
  });

  it("applies size styles", () => {
    render(<Button size="lg">Large</Button>);
    expect(screen.getByText("Large")).toHaveClass("px-6 py-3");
  });
});
```

#### 2. Storybook

```typescript
// src/components/common/Button.stories.tsx
import React from "react";
import { Button } from "./Button";

export default {
  title: "Components/Button",
  component: Button,
};

export const Primary = () => <Button variant="primary">Primary Button</Button>;
export const Secondary = () => (
  <Button variant="secondary">Secondary Button</Button>
);
export const Outline = () => <Button variant="outline">Outline Button</Button>;
```

### Best Practices

1. **Component Design**
   * Keep components small and focused
   * Use composition over inheritance
   * Follow single responsibility principle
   * Make components reusable
2. **Props Management**
   * Use TypeScript interfaces for props
   * Provide default values where appropriate
   * Document prop types and usage
   * Use prop spreading carefully
3. **State Management**
   * Use local state for UI-only state
   * Lift state up when needed
   * Use context for theme/language
   * Connect to Redux for global state
4. **Performance**
   * Use React.memo for pure components
   * Implement proper key props
   * Avoid unnecessary re-renders
   * Use useCallback and useMemo

### Next Steps

Now that you understand how to work with components, you can proceed to:

1. State Management and Data Flow
2. Authentication and Authorization

### Additional Resources

* [React Component Documentation](https://reactjs.org/docs/components-and-props.html)
* [TypeScript React Documentation](https://www.typescriptlang.org/docs/handbook/react.html)
* [Tailwind CSS Documentation](https://tailwindcss.com/docs)
* [Testing Library Documentation](https://testing-library.com/docs/react-testing-library/intro/)
