Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions .claude/agents/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
name: code-reviewer
description: Used PROACTIVELY after writing or modifying any code. Reviews against project standards, TypeScript strict mode, and coding conventions. Checks for anti-patterns, security issues, and performance problems.
model: opus
---

Senior code reviewer ensuring high standards for the codebase.

## Core Setup

**When invoked**: Run `git diff` to see recent changes, focus on modified files, begin review immediately.

**Feedback Format**: Organize by priority with specific line references and fix examples.
- **Critical**: Must fix (security, breaking changes, logic errors)
- **Warning**: Should fix (conventions, performance, duplication)
- **Suggestion**: Consider improving (naming, optimization, docs)

## Review Checklist

### Logic & Flow
- Logical consistency and correct control flow
- Dead code detection, side effects intentional
- Race conditions in async operations
- Inappropriate lifecycle management that could cause infinite loops

### TypeScript & Code Style
- **Always define types explicitly** - no `any`, `unknown` without handling
- **Prefer `interface`** over `type` (except unions/intersections)
- **No type assertions** (`as Type`) without justification
- Proper naming (PascalCase components, camelCase functions, `is`/`has` booleans)

### Immutability & Pure Functions
- **No data mutation** - use spread operators, immutable updates
- **No nested if/else** - use early returns, max 2 nesting levels. Use guard clauses.
- Small focused functions, composition over inheritance

### Loading & Empty States (Critical)
- **Loading ONLY when no data** - `if (loading && !data)` not just `if (loading)`
- **Every list MUST have empty state** - `ListEmptyComponent` required
- **Error state ALWAYS first** - check error before loading
- **State order**: Error → Loading (no data) → Empty → Success

```typescript
// CORRECT - Proper state handling order
if (error) return <ErrorState error={error} onRetry={refetch} />;
if (loading && !data) return <LoadingSkeleton />;
if (!data?.items.length) return <EmptyState />;
return <ItemList items={data.items} />;
```

### Error Handling
- **NEVER silent errors** - always show user feedback
- **Mutations need onError** - with toast AND logging
- Include context: operation names, resource IDs

### Mutation UI Requirements (Critical)
- **Button must be `isDisabled` during mutation** - prevent double-clicks
- **Button must show `isLoading` state** - visual feedback
- **onError must show toast** - user knows it failed
- **onCompleted success toast** - optional, use for important actions

```typescript
// CORRECT - Complete mutation pattern
const [submit, { loading }] = useSubmitMutation({
onError: (error) => {
console.error('submit failed:', error);
toast.error({ title: 'Save failed' });
},
});

<Button
onPress={handleSubmit}
isDisabled={!isValid || loading}
isLoading={loading}
>
Submit
</Button>
```

### Security & Performance
- Input validation at boundaries
- Error boundaries for components
- Use bigint for asset and balance calculations

## Code Patterns

```typescript
// Mutation
items.push(newItem); // Bad
[...items, newItem]; // Good

// Conditionals
if (user) { if (user.isActive) { ... } } // Bad
if (!user || !user.isActive) return; // Good

// Loading states
if (loading) return <Spinner />; // Bad - flashes on refetch
if (loading && !data) return <Spinner />; // Good - only when no data

// Button during mutation
<Button onPress={submit}>Submit</Button> // Bad - can double-click
<Button onPress={submit} isDisabled={loading} isLoading={loading}>Submit</Button> // Good

// Empty states
<FlatList data={items} /> // Bad - no empty state
<FlatList data={items} ListEmptyComponent={<EmptyState />} /> // Good
```

## Review Process

1. **Run checks**: `pnpm run lint` for automated issues
2. **Analyze diff**: `git diff` for all changes
3. **Logic review**: Read line by line, trace execution paths
4. **Apply checklist**: TypeScript, React, testing, security
5. **Common sense filter**: Flag anything that doesn't make intuitive sense

## Integration with Other Skills

- **ui-components**: UI patterns
- **data-and-state-management**: For how data, hooks, and components should be structured
2 changes: 1 addition & 1 deletion .claude/skills/data-and-state-management/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: data-and-state-management
description: Core patterns for data fetching, state management, and user preferences. Use when implementing new features that require getting data from APIs or managing shared state.
description: Core patterns for data fetching, state management, and user preferences. Use when implementing new features that require getting data from Our APIs, Morpho API, on-chain states or managing shared state.
---


Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/feature-structure/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: feature-structure
description: Architecture patterns for organizing feature modules in the codebase. Use when creating new features to ensure consistent structure and maintainability.
description: Architecture patterns for organizing feature modules in the codebase. Use when creating new files, brand new features or pages.
---


Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/transaction-hooks/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: transaction-hooks
description: Core patterns to follow for implementing transaction hooks with transaction tracking. Use when implementing new features interacting with EVM contracts.
description: Patterns to follow for implementing transaction hooks with tracking. Use when implementing new features interacting with EVM contracts, signing transactions, permit... etc.
---


Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/ui-components/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: ui-components
description: Core component library and design system patterns. Use when building UI, using design tokens, or working with the component library.
description: Core component library and design system patterns. Use when building UI, building new components, new page, using design tokens, or working with the component library.
---

# Core Components
Expand Down
17 changes: 16 additions & 1 deletion src/features/markets/components/table/markets-table-actions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import moment from 'moment';
import { RefetchIcon } from '@/components/ui/refetch-icon';
import { CgDisplayFullwidth } from 'react-icons/cg';
import { FiSettings } from 'react-icons/fi';
Expand All @@ -15,15 +16,29 @@ type MarketsTableActionsProps = {
onRefresh: () => void;
isRefetching: boolean;
isMobile: boolean;
dataUpdatedAt: number;
};

export function MarketsTableActions({ onRefresh, isRefetching, isMobile }: MarketsTableActionsProps) {
export function MarketsTableActions({ onRefresh, isRefetching, isMobile, dataUpdatedAt }: MarketsTableActionsProps) {
const { open: openModal } = useModal();
const { tableViewMode, setTableViewMode } = useMarketPreferences();
const effectiveTableViewMode = isMobile ? 'compact' : tableViewMode;

return (
<>
{dataUpdatedAt !== 0 && (
<Tooltip
content={
<TooltipContent
title="Last updated"
detail={`${moment(dataUpdatedAt).format('h:mm:ss A')} (${moment(dataUpdatedAt).fromNow()})`}
/>
}
>
<span className="text-xs text-secondary whitespace-nowrap cursor-default">{moment(dataUpdatedAt).format('h:mm:ss A')}</span>
</Tooltip>
)}

<MarketFilter onOpenSettings={() => openModal('marketSettings', {})} />

<Tooltip
Expand Down
3 changes: 2 additions & 1 deletion src/features/markets/components/table/markets-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type MarketsTableProps = {

function MarketsTable({ currentPage, setCurrentPage, className, tableClassName, onRefresh, isMobile }: MarketsTableProps) {
// Get loading states directly from query (no prop drilling!)
const { isLoading: loading, isRefetching, data: rawMarkets } = useMarketsQuery();
const { isLoading: loading, isRefetching, data: rawMarkets, dataUpdatedAt } = useMarketsQuery();

// Get trusted vaults directly from store (no prop drilling!)
const { vaults: trustedVaults } = useTrustedVaults();
Expand Down Expand Up @@ -112,6 +112,7 @@ function MarketsTable({ currentPage, setCurrentPage, className, tableClassName,
onRefresh={onRefresh}
isRefetching={isRefetching}
isMobile={isMobile}
dataUpdatedAt={dataUpdatedAt}
/>
}
className="w-full"
Expand Down