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
Navigation Component
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`
`}
${props => props.variant === 'secondary' && css`
`}
`;
Best Practices
Component Development
- Component composition
- Props validation
- Error boundaries
- Performance optimization
State Management
- Local state usage
- Context API
- Redux patterns
- Data fetching
Testing
- Component testing
- Integration testing
- Visual regression
- Accessibility testing
Performance
- Code splitting
- Lazy loading
- Memoization
- Bundle optimization