| name | frontend-review |
| description | Code review chuyên sâu cho frontend repo React. Stack: React 19, Vite 7, Redux Toolkit v2, TanStack Query v5, Ant Design v6, react-router-dom v7, TailwindCSS v4. Trigger khi review code frontend/React/TypeScript, hỏi "code này đúng không", "review giúp mình", hoặc muốn check component/hook/store. |
Frontend Code Review
Mục tiêu
Review code React/TypeScript theo đúng stack và domain của repo đang xét.
Bước 1: Xác định repo và domain
Áp dụng cho MỌI repo có vai trò frontend trong bảng Ecosystem (AGENTS.md) — các repo này cùng stack (React 19/Vite/RTK v2/TanStack v5/AntD v6) nhưng có thể khác domain/route hoàn toàn. Luôn xác nhận đang review đúng repo (đọc AGENTS.md) trước khi áp business logic.
Checklist Review
1. Domain Boundary (KIỂM TRA ĐẦU TIÊN)
2. State Management
const { data, isLoading, isError } = useQuery({
queryKey: ['orders', companyId, { page, status }],
queryFn: () => orderApi.getOrders(companyId, { page, status }),
staleTime: 5 * 60 * 1000,
});
const mutation = useMutation({
mutationFn: orderApi.createOrder,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['orders'] }),
onError: (error) => toast.error(error.message),
});
const { data } = useQuery(['orders'], () => fetchOrders());
const authSlice = createSlice({
name: 'auth',
initialState: { user: null as User | null },
reducers: { setUser: (state, action: PayloadAction<User | null>) => { state.user = action.payload; } },
});
dispatch(setOrders(await fetchOrders()));
3. Routing — react-router-dom v7
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [searchParams, setSearchParams] = useSearchParams();
const history = useHistory();
import { Switch, Route } from 'react-router-dom';
4. Ant Design v6
import { App } from 'antd';
const { message, modal } = App.useApp();
const columns: ColumnsType<OrderRecord> = [
{ title: 'ID', dataIndex: 'id', key: 'id', sorter: true },
{ title: 'Trạng thái', dataIndex: 'status', render: (s) => <OrderStatusTag status={s} /> },
];
<Form.Item name="companyCode" rules={[{ required: true }]}> {/* ❌ */}
5. Forms — react-hook-form v7 + yup
const schema = yup.object({
companyCode: yup.string().required('Vui lòng nhập mã công ty'),
quantity: yup.number().min(1).required(),
});
const { control, handleSubmit, formState: { errors } } = useForm<CreateOrderForm>({
resolver: yupResolver(schema),
defaultValues: { quantity: 1 },
});
<Controller
name="companyCode"
control={control}
render={({ field }) => <Input {...field} status={errors.companyCode ? 'error' : ''} />}
/>
6. Component Patterns
interface OrderCardProps { orderId: string; onStatusChange: (id: string) => void; }
export const OrderCard: React.FC<OrderCardProps> = ({ orderId, onStatusChange }) => { ... };
export default OrderCard;
class OrderCard extends React.Component { ... }
7. Hooks
useEffect(() => { fetchOrder(orderId); }, [orderId]);
useEffect(() => { fetchOrder(orderId); }, []);
useEffect(() => {
socket.on('order:update', handleUpdate);
return () => socket.off('order:update', handleUpdate);
}, []);
8. TailwindCSS v4
import { twMerge } from 'tailwind-merge';
className={twMerge('px-4 py-2', isActive && 'bg-blue-500')}
9. Security & Quality
Output Format
📋 FRONTEND REVIEW — [file/component]
Repo: <tên repo> | Domain: <domain>
🔴 Critical:
- [Line X] Vấn đề → Fix cụ thể
🟡 Warning:
- [Line X] Vấn đề → Đề xuất fix
🟢 OK:
- [Điểm tốt]
💡 Suggestions (optional):
- [Cải thiện không bắt buộc]
✅ Kết luận: Approve / Request Changes