| name | frontend |
| description | React frontend development patterns. Use when creating pages, components, API integration, or UI features. |
| tools | ["read","write","bash"] |
| metadata | {"version":"1.0","category":"development","framework":"react"} |
Frontend Development Skill
This skill provides patterns and guidance for developing the React frontend.
Page Component Pattern
When creating a new page:
1. Create Page Component
import { useState, useEffect } from 'react';
import { exampleAPI } from '../services/api';
import { useAuth } from '../contexts/AuthContext';
export default function Example() {
const { user } = useAuth();
const [items, setItems] = useState([]);
const [filters, setFilters] = useState({ search: '', status: '' });
const [modalOpen, setModalOpen] = useState(false);
const [editItem, setEditItem] = useState(null);
const [formData, setFormData] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => { loadData(); }, [filters]);
const loadData = async () => {
try {
const res = await exampleAPI.getAll(filters);
setItems(res.data.items || []);
} catch (error) {
console.error('Failed to load:', error);
} finally {
setLoading(false);
}
};
const openModal = (item = null) => {
setEditItem(item);
setFormData(item || { name: '', amount: 0, status: 'active' });
setModalOpen(true);
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
if (editItem) {
await exampleAPI.update(editItem.id, formData);
} else {
await exampleAPI.create(formData);
}
setModalOpen(false);
loadData();
} catch (error) {
alert(error.response?.data?.detail || 'Failed to save');
}
};
const handleDelete = async (id) => {
if (!window.confirm('Delete this item?')) return;
try {
await exampleAPI.delete(id);
loadData();
} catch (error) {
alert('Failed to delete');
}
};
if (loading) return <div className="text-center text-muted">Loading...</div>;
return (
<>
{/* Toolbar */}
<div className="toolbar">
<input
type="text"
className="form-input"
placeholder="Search..."
value={filters.search}
onChange={(e) => setFilters({ ...filters, search: e.target.value })}
/>
<select
className="form-select"
value={filters.status}
onChange={(e) => setFilters({ ...filters, status: e.target.value })}
>
<option value="">All Status</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
{user?.role === 'admin' && (
<button className="btn btn-primary" onClick={() => openModal()}>
+ New Item
</button>
)}
</div>
{/* Data Table */}
Name
Amount
Status
Actions
{items.length === 0 ? (
No items found
) : items.map(item => (
{item.name}
${item.amount}
{item.status}
openModal(item)}>
Edit
{user?.role === 'admin' && (
handleDelete(item.id)}>
Delete
)}
))}
{/* Modal */}
{modalOpen && (
setModalOpen(false)}>
e.stopPropagation()}>
{editItem ? 'Edit Item' : 'New Item'}
setModalOpen(false)}>
Name *
setFormData({ ...formData, name: e.target.value })}
required
/>
Amount
setFormData({ ...formData, amount: parseFloat(e.target.value) || 0 })}
/>
setModalOpen(false)}>
Cancel
Save
)}
);
}
2. Add API Service
export const exampleAPI = {
getAll: (params) => api.get('/example', { params }),
getById: (id) => api.get(`/example/${id}`),
create: (data) => api.post('/example', data),
update: (id, data) => api.put(`/example/${id}`, data),
delete: (id) => api.delete(`/example/${id}`)
};
3. Add Route
import Example from './pages/Example';
<Route path="/example" element={
<PrivateRoute allowedRoles={['admin', 'supplier']}>
<Layout><Example /></Layout>
</PrivateRoute>
} />
Component Patterns
Stats Card
<div className="stat-card">
<span className="stat-icon">📊</span>
<div className="stat-content">
<div className="stat-label">Total Items</div>
<div className="stat-value success">{count}</div>
</div>
</div>
Badge
<span className={`badge badge-${status}`}>{label}</span>
Grid Layout
<div className="grid-2">
<div className="form-group">...</div>
<div className="form-group">...</div>
</div>
<div className="stats-grid">
<div className="stat-card">...</div>
<div className="stat-card">...</div>
</div>
Chart.js Integration
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';
import { Bar } from 'react-chartjs-2';
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);
const chartData = {
labels: data.map(d => d.label),
datasets: [{
label: 'Values',
data: data.map(d => d.value),
backgroundColor: '#667eea'
}]
};
<div className="chart-container">
<Bar data={chartData} options={{ responsive: true, maintainAspectRatio: false }} />
Auth Context Usage
import { useAuth } from '../contexts/AuthContext';
function MyComponent() {
const { user, logout } = useAuth();
if (user?.role === 'admin') {
}
const handleLogout = () => logout();
}
API Error Handling
try {
const res = await api.get('/endpoint');
setData(res.data);
} catch (error) {
if (error.response?.status === 401) {
} else if (error.response?.status === 403) {
alert('Permission denied');
} else {
alert(error.response?.data?.detail || 'An error occurred');
}
}
CSS Classes Reference
.toolbar
.section
.grid-2
.stats-grid
.form-group
.form-label
.form-input
.form-select
.form-textarea
.btn
.btn-primary
.btn-success
.btn-danger
.btn-secondary
.btn-sm
.table-container
.data-table
.empty-row
.modal-overlay
.modal
.modal-header