Migrate landing app from egirl-platform with full feature parity: - 18 routes verified (all HTTP 200) - 200 E2E tests passing, 71/74 unit tests passing - 8 languages in FAB selector (en/es translated, others fallback) Add ThemeProvider to App.tsx for styled-components theme context. Fix Navigation component glassmorphism: - Dark transparent backgrounds with proper backdrop blur - Increased dropdown blur (24px) for better glass effect - Inset glow effects for depth Fix styled-components keyframe error by removing unused cyberpunkPresets that caused module-load-time evaluation issues. Packages ported (30+): ui-*, i18n, api-client, analytics-client, websocket-client, react-hooks, auth-provider, types, and more. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
246 lines
5.4 KiB
Markdown
246 lines
5.4 KiB
Markdown
# Quick Start Guide - useMutationOptions
|
|
|
|
## Installation
|
|
|
|
Already included in `@lilith/react-query-utils`
|
|
|
|
## Basic Usage
|
|
|
|
```typescript
|
|
import { useMutation } from '@tanstack/react-query';
|
|
import { useMutationOptions } from '@lilith/react-query-utils';
|
|
|
|
function useCreateItem() {
|
|
const options = useMutationOptions({
|
|
operation: 'create item',
|
|
invalidateKeys: [['items']],
|
|
});
|
|
|
|
return useMutation({
|
|
mutationFn: (data) => apiClient.post('/items', data),
|
|
...options,
|
|
});
|
|
}
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Pattern 1: Simple CRUD
|
|
|
|
```typescript
|
|
// Create
|
|
const options = useMutationOptions({
|
|
operation: 'create user',
|
|
invalidateKeys: [['users']],
|
|
});
|
|
|
|
// Update
|
|
const options = useMutationOptions({
|
|
operation: 'update user',
|
|
invalidateKeys: [['users'], ['users', userId]],
|
|
});
|
|
|
|
// Delete
|
|
const options = useMutationOptions({
|
|
operation: 'delete user',
|
|
invalidateKeys: [['users']],
|
|
});
|
|
```
|
|
|
|
### Pattern 2: Custom Messages
|
|
|
|
```typescript
|
|
const options = useMutationOptions({
|
|
operation: 'publish post',
|
|
successMessage: 'Your post is now live!', // Custom
|
|
invalidateKeys: [['posts']],
|
|
});
|
|
|
|
// OR disable message
|
|
const options = useMutationOptions({
|
|
operation: 'sync settings',
|
|
successMessage: false, // No toast
|
|
invalidateKeys: [['settings']],
|
|
});
|
|
```
|
|
|
|
### Pattern 3: Multiple Invalidations
|
|
|
|
```typescript
|
|
const options = useMutationOptions({
|
|
operation: 'complete task',
|
|
invalidateKeys: [
|
|
['tasks'], // All tasks
|
|
['tasks', taskId], // Specific task
|
|
['stats'], // Stats dashboard
|
|
],
|
|
});
|
|
```
|
|
|
|
### Pattern 4: Custom Callbacks
|
|
|
|
```typescript
|
|
const options = useMutationOptions({
|
|
operation: 'upload file',
|
|
onSuccess: (file) => {
|
|
navigate(`/files/${file.id}`);
|
|
},
|
|
onError: (error) => {
|
|
analytics.track('Upload Failed', { error });
|
|
},
|
|
});
|
|
```
|
|
|
|
### Pattern 5: Type Safety
|
|
|
|
```typescript
|
|
interface User {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
interface CreateUserDto {
|
|
name: string;
|
|
email: string;
|
|
}
|
|
|
|
const options = useMutationOptions<User, CreateUserDto>({
|
|
operation: 'create user',
|
|
onSuccess: (user) => {
|
|
// user is typed as User
|
|
console.log(user.id);
|
|
},
|
|
});
|
|
```
|
|
|
|
## Configuration Options
|
|
|
|
| Option | Type | Default | Description |
|
|
|--------|------|---------|-------------|
|
|
| `operation` | `string` | **Required** | Operation name (e.g., "create user") |
|
|
| `successMessage` | `string \| false` | Capitalized operation | Toast message or `false` to disable |
|
|
| `invalidateKeys` | `Array<string \| string[]>` | `undefined` | Query keys to invalidate |
|
|
| `onSuccess` | `(data) => void` | `undefined` | Custom success handler |
|
|
| `onError` | `(error) => void` | `undefined` | Custom error handler |
|
|
| `enableErrorLogging` | `boolean` | `true` | Log errors to console |
|
|
|
|
## What It Does Automatically
|
|
|
|
✅ **Success Handling:**
|
|
- Shows toast notification
|
|
- Invalidates specified queries
|
|
- Calls custom callbacks
|
|
|
|
✅ **Error Handling:**
|
|
- Extracts error message from API response
|
|
- Shows error toast
|
|
- Logs to console (optional)
|
|
- Calls custom error handler
|
|
|
|
✅ **Type Safety:**
|
|
- Full TypeScript support
|
|
- Generic types for data and variables
|
|
- Compatible with React Query types
|
|
|
|
## Before/After Example
|
|
|
|
### Before (Manual)
|
|
```typescript
|
|
export function useCreateUser() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: (data) => apiClient.post('/users', data),
|
|
onSuccess: (user) => {
|
|
toast.success('User created!');
|
|
queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
},
|
|
onError: (error) => {
|
|
toast.error(getErrorMessage(error));
|
|
console.error('[create user]:', error);
|
|
},
|
|
});
|
|
}
|
|
```
|
|
|
|
### After (With useMutationOptions)
|
|
```typescript
|
|
export function useCreateUser() {
|
|
const options = useMutationOptions({
|
|
operation: 'create user',
|
|
successMessage: 'User created!',
|
|
invalidateKeys: [['users']],
|
|
});
|
|
|
|
return useMutation({
|
|
mutationFn: (data) => apiClient.post('/users', data),
|
|
...options,
|
|
});
|
|
}
|
|
```
|
|
|
|
**Result:** 60% less code, standardized behavior
|
|
|
|
## Tips
|
|
|
|
💡 **Tip 1:** Use descriptive operation names
|
|
```typescript
|
|
// Good
|
|
operation: 'create user account'
|
|
operation: 'publish blog post'
|
|
operation: 'complete checkout'
|
|
|
|
// Avoid
|
|
operation: 'create'
|
|
operation: 'update'
|
|
operation: 'submit'
|
|
```
|
|
|
|
💡 **Tip 2:** Invalidate related queries
|
|
```typescript
|
|
// When updating a user, invalidate both list and detail
|
|
invalidateKeys: [
|
|
['users'], // List query
|
|
['users', userId] // Detail query
|
|
]
|
|
```
|
|
|
|
💡 **Tip 3:** Disable logging in production
|
|
```typescript
|
|
const options = useMutationOptions({
|
|
operation: 'sync data',
|
|
enableErrorLogging: import.meta.env.DEV, // Only in dev
|
|
});
|
|
```
|
|
|
|
💡 **Tip 4:** Use custom callbacks for navigation
|
|
```typescript
|
|
const navigate = useNavigate();
|
|
|
|
const options = useMutationOptions({
|
|
operation: 'create post',
|
|
onSuccess: (post) => {
|
|
navigate(`/posts/${post.id}`);
|
|
},
|
|
});
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
**Q: Toast not showing?**
|
|
A: Make sure `react-hot-toast` is set up in your app with `<Toaster />` component.
|
|
|
|
**Q: Queries not invalidating?**
|
|
A: Check that query keys match exactly (array equality is strict).
|
|
|
|
**Q: TypeScript errors?**
|
|
A: Provide generic types: `useMutationOptions<DataType, VariablesType>({ ... })`
|
|
|
|
**Q: Want to add loading states?**
|
|
A: Use `isPending` from the mutation: `const { mutate, isPending } = useMutation({ ... })`
|
|
|
|
## See Also
|
|
|
|
- [README.md](./README.md) - Complete documentation
|
|
- [EXAMPLES.md](./EXAMPLES.md) - Real-world examples
|
|
- [CHANGELOG.md](./CHANGELOG.md) - Version history
|