Skip to main content

Frontend Components

Component Architecture

Shared Components

Form Components

// FormInput Component
interface FormInputProps {
label: string;
name: string;
type: 'text' | 'number' | 'email' | 'password';
value: string | number;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
error?: string;
required?: boolean;
}

const FormInput: React.FC<FormInputProps> = ({
label,
name,
type,
value,
onChange,
error,
required
}) => (
<div className="form-field">
<label htmlFor={name}>
{label} {required && <span className="required">*</span>}
</label>
<input
id={name}
name={name}
type={type}
value={value}
onChange={onChange}
className={error ? 'error' : ''}
/>
{error && <span className="error-message">{error}</span>}
</div>
);

Table Components

// DataTable Component
interface TableColumn<T> {
key: keyof T;
title: string;
render?: (value: T[keyof T], item: T) => ReactNode;
}

interface DataTableProps<T> {
data: T[];
columns: TableColumn<T>[];
loading?: boolean;
onRowClick?: (item: T) => void;
}

const DataTable = <T extends {}>({
data,
columns,
loading,
onRowClick
}: DataTableProps<T>) => (
<div className="table-container">
{loading ? (
<LoadingSpinner />
) : (
<table>
<thead>
<tr>
{columns.map(col => (
<th key={col.key as string}>{col.title}</th>
))}
</tr>
</thead>
<tbody>
{data.map((item, index) => (
<tr
key={index}
onClick={() => onRowClick?.(item)}
>
{columns.map(col => (
<td key={col.key as string}>
{col.render
? col.render(item[col.key], item)
: item[col.key]}
</td>
))}
</tr>
))}
</tbody>
</table>
)}
</div>
);

Business Components

Loan Application Form

interface LoanApplicationData {
amount: number;
term: number;
purpose: string;
businessInfo: {
name: string;
registrationNumber: string;
industry: string;
};
}

const LoanApplicationForm: React.FC = () => {
const [data, setData] = useState<LoanApplicationData>({
amount: 0,
term: 12,
purpose: '',
businessInfo: {
name: '',
registrationNumber: '',
industry: ''
}
});

const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
// Form submission logic
};

return (
<form onSubmit={handleSubmit}>
<FormSection title="Loan Details">
<FormInput
label="Loan Amount"
name="amount"
type="number"
value={data.amount}
onChange={handleAmountChange}
required
/>
<FormInput
label="Loan Term (months)"
name="term"
type="number"
value={data.term}
onChange={handleTermChange}
required
/>
</FormSection>

<FormSection title="Business Information">
<FormInput
label="Business Name"
name="businessName"
type="text"
value={data.businessInfo.name}
onChange={handleBusinessInfoChange}
required
/>
</FormSection>

<SubmitButton>Apply for Loan</SubmitButton>
</form>
);
};

Payment Schedule Component

interface PaymentSchedule {
dueDate: Date;
amount: number;
principal: number;
interest: number;
status: 'pending' | 'paid' | 'overdue';
}

const PaymentScheduleTable: React.FC<{ schedules: PaymentSchedule[] }> = ({
schedules
}) => {
const columns: TableColumn<PaymentSchedule>[] = [
{
key: 'dueDate',
title: 'Due Date',
render: (value) => formatDate(value as Date)
},
{
key: 'amount',
title: 'Amount',
render: (value) => formatCurrency(value as number)
},
{
key: 'status',
title: 'Status',
render: (value) => (
<StatusBadge status={value as string} />
)
}
];

return <DataTable data={schedules} columns={columns} />;
};

Layout Components

const Navigation: React.FC = () => {
const { user } = useAuth();
const location = useLocation();

return (
<nav className="main-nav">
<Logo />
<MenuItems>
<MenuItem
to="/dashboard"
active={location.pathname === '/dashboard'}
>
Dashboard
</MenuItem>
<MenuItem
to="/loans"
active={location.pathname.startsWith('/loans')}
>
Loans
</MenuItem>
<MenuItem
to="/payments"
active={location.pathname.startsWith('/payments')}
>
Payments
</MenuItem>
</MenuItems>
<UserMenu user={user} />
</nav>
);
};

Styling Guidelines

Theme Configuration

export const theme = {
colors: {
primary: '#007AFF',
secondary: '#5856D6',
success: '#34C759',
warning: '#FF9500',
error: '#FF3B30',
text: {
primary: '#000000',
secondary: '#8E8E93',
},
background: {
primary: '#FFFFFF',
secondary: '#F2F2F7',
}
},
typography: {
fontFamily: 'Arial, sans-serif',
fontSize: {
small: '12px',
medium: '14px',
large: '16px',
xlarge: '20px',
}
},
spacing: {
small: '8px',
medium: '16px',
large: '24px',
xlarge: '32px',
}
};

Component Styling

// Styled Components Example
const Button = styled.button<{ variant: 'primary' | 'secondary' }>`
padding: ${props => props.theme.spacing.medium};
border-radius: 4px;
font-size: ${props => props.theme.typography.fontSize.medium};
font-weight: 600;
border: none;
cursor: pointer;

${props => props.variant === 'primary' && css`
background-color: ${props.theme.colors.primary};
color: white;

&:hover {
background-color: ${darken(0.1, props.theme.colors.primary)};
}
`}

${props => props.variant === 'secondary' && css`
background-color: transparent;
color: ${props.theme.colors.primary};
border: 1px solid ${props.theme.colors.primary};

&:hover {
background-color: ${rgba(props.theme.colors.primary, 0.1)};
}
`}
`;

Best Practices

Component Development

  1. Component composition
  2. Props validation
  3. Error boundaries
  4. Performance optimization

State Management

  1. Local state usage
  2. Context API
  3. Redux patterns
  4. Data fetching

Testing

  1. Component testing
  2. Integration testing
  3. Visual regression
  4. Accessibility testing

Performance

  1. Code splitting
  2. Lazy loading
  3. Memoization
  4. Bundle optimization