diff --git a/.claude/skills/livewire-development/SKILL.md b/.claude/skills/livewire-development/SKILL.md deleted file mode 100644 index c009dae..0000000 --- a/.claude/skills/livewire-development/SKILL.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -name: livewire-development -description: "Use for any task or question involving Livewire. Activate if user mentions Livewire, wire: directives, or Livewire-specific concepts like wire:model, wire:click, wire:sort, or islands, invoke this skill. Covers building new components, debugging reactivity issues, real-time form validation, drag-and-drop, loading states, migrating from Livewire 3 to 4, converting component formats (SFC/MFC/class-based), and performance optimization. Do not use for non-Livewire reactive UI (React, Vue, Alpine-only, Inertia.js) or standard Laravel forms without Livewire." -license: MIT -metadata: - author: laravel ---- - -# Livewire Development - -## Documentation - -Use `search-docs` for detailed Livewire 4 patterns and documentation. - -## Basic Usage - -### Creating Components - -```bash - -# Single-file component (default in v4) - -php artisan make:livewire create-post - -# Multi-file component - -php artisan make:livewire create-post --mfc - -# Class-based component (v3 style) - -php artisan make:livewire create-post --class - -# With namespace - -php artisan make:livewire Posts/CreatePost -``` - -### Converting Between Formats - -Use `php artisan livewire:convert create-post` to convert between single-file, multi-file, and class-based formats. - -### Choosing a Component Format - -Before creating a component, check `config/livewire.php` for directory overrides, which change where files are stored. Then, look at existing files in those directories (defaulting to `app/Livewire/` and `resources/views/livewire/`) to match the established convention. - -### Component Format Reference - -| Format | Flag | Class Path | View Path | -|--------|------|------------|-----------| -| Single-file (SFC) | default | — | `resources/views/livewire/create-post.blade.php` (PHP + Blade in one file) | -| Multi-file (MFC) | `--mfc` | `app/Livewire/CreatePost.php` | `resources/views/livewire/create-post.blade.php` | -| Class-based | `--class` | `app/Livewire/CreatePost.php` | `resources/views/livewire/create-post.blade.php` | -| View-based | ⚡ prefix | — | `resources/views/livewire/create-post.blade.php` (Blade-only with functional state) | - -Namespaced components map to subdirectories: `make:livewire Posts/CreatePost` creates files at `app/Livewire/Posts/CreatePost.php` and `resources/views/livewire/posts/create-post.blade.php`. - -### Single-File Component Example - - -```php -count++; - } -} -?> - -
- -
-``` - -## Livewire 4 Specifics - -### Key Changes From Livewire 3 - -These things changed in Livewire 4, but may not have been updated in this application. Verify this application's setup to ensure you follow existing conventions. - -- Use `Route::livewire()` for full-page components (e.g., `Route::livewire('/posts/create', CreatePost::class)`); config keys renamed: `layout` → `component_layout`, `lazy_placeholder` → `component_placeholder`. -- `wire:model` now ignores child events by default (use `wire:model.deep` for old behavior); `wire:scroll` renamed to `wire:navigate:scroll`. -- Component tags must be properly closed; `wire:transition` now uses View Transitions API (modifiers removed). -- JavaScript: `$wire.$js('name', fn)` → `$wire.$js.name = fn`; `commit`/`request` hooks → `interceptMessage()`/`interceptRequest()`. - -### New Features - -- Component formats: single-file (SFC), multi-file (MFC), view-based components. -- Islands (`@island`) for isolated updates; async actions (`wire:click.async`, `#[Async]`) for parallel execution. -- Deferred/bundled loading: `defer`, `lazy.bundle` for optimized component loading. - -| Feature | Usage | Purpose | -|---------|-------|---------| -| Islands | `@island(name: 'stats')` | Isolated update regions | -| Async | `wire:click.async` or `#[Async]` | Non-blocking actions | -| Deferred | `defer` attribute | Load after page render | -| Bundled | `lazy.bundle` | Load multiple together | - -### New Directives - -- `wire:sort`, `wire:intersect`, `wire:ref`, `.renderless`, `.preserve-scroll` are available for use. -- `data-loading` attribute automatically added to elements triggering network requests. - -| Directive | Purpose | -|-----------|---------| -| `wire:sort` | Drag-and-drop sorting | -| `wire:intersect` | Viewport intersection detection | -| `wire:ref` | Element references for JS | -| `.renderless` | Component without rendering | -| `.preserve-scroll` | Preserve scroll position | - -## Best Practices - -- Always use `wire:key` in loops -- Use `wire:loading` for loading states -- Use `wire:model.live` for instant updates (default is debounced) -- Validate and authorize in actions (treat like HTTP requests) - -## Configuration - -- `smart_wire_keys` defaults to `true`; new configs: `component_locations`, `component_namespaces`, `make_command`, `csp_safe`. - -## Alpine & JavaScript - -- `wire:transition` uses browser View Transitions API; `$errors` and `$intercept` magic properties available. -- Non-blocking `wire:poll` and parallel `wire:model.live` updates improve performance. - -For interceptors and hooks, see [reference/javascript-hooks.md](reference/javascript-hooks.md). - -## Testing - - -```php -Livewire::test(Counter::class) - ->assertSet('count', 0) - ->call('increment') - ->assertSet('count', 1); -``` - -## Verification - -1. Browser console: Check for JS errors -2. Network tab: Verify Livewire requests return 200 -3. Ensure `wire:key` on all `@foreach` loops - -## Common Pitfalls - -- Missing `wire:key` in loops → unexpected re-rendering -- Expecting `wire:model` real-time → use `wire:model.live` -- Unclosed component tags → syntax errors in v4 -- Using deprecated config keys or JS hooks -- Including Alpine.js separately (already bundled in Livewire 4) \ No newline at end of file diff --git a/.claude/skills/livewire-development/reference/javascript-hooks.md b/.claude/skills/livewire-development/reference/javascript-hooks.md deleted file mode 100644 index d6a4417..0000000 --- a/.claude/skills/livewire-development/reference/javascript-hooks.md +++ /dev/null @@ -1,39 +0,0 @@ -# Livewire 4 JavaScript Integration - -## Interceptor System (v4) - -### Intercept Messages - -```js -Livewire.interceptMessage(({ component, message, onFinish, onSuccess, onError }) => { - onFinish(() => { /* After response, before processing */ }); - onSuccess(({ payload }) => { /* payload.snapshot, payload.effects */ }); - onError(() => { /* Server errors */ }); -}); -``` - -### Intercept Requests - -```js -Livewire.interceptRequest(({ request, onResponse, onSuccess, onError, onFailure }) => { - onResponse(({ response }) => { /* When received */ }); - onSuccess(({ response, responseJson }) => { /* Success */ }); - onError(({ response, responseBody, preventDefault }) => { /* 4xx/5xx */ }); - onFailure(({ error }) => { /* Network failures */ }); -}); -``` - -### Component-Scoped Interceptors - -```blade - -``` - -## Magic Properties - -- `$errors` - Access validation errors from JavaScript -- `$intercept` - Component-scoped interceptors \ No newline at end of file diff --git a/resources/js/composables/useAuth.js b/resources/js/composables/useAuth.js index e8849f9..d4c3cd3 100644 --- a/resources/js/composables/useAuth.js +++ b/resources/js/composables/useAuth.js @@ -40,5 +40,39 @@ export function useAuth() { fetched.value = false } - return { user, loading, isAuthenticated, userTier, isPaidTier, fetchUser, clearUser } + async function logout() { + try { + await api.post('/auth/logout') + } finally { + clearUser() + } + } + + async function updateProfile(data) { + const response = await api.put('/user/profile', data) + user.value = response.data + } + + async function updatePassword(data) { + await api.put('/user/password', data) + } + + async function deleteAccount(password) { + await api.delete('/user', { data: { password } }) + clearUser() + } + + return { + user, + loading, + isAuthenticated, + userTier, + isPaidTier, + fetchUser, + clearUser, + logout, + updateProfile, + updatePassword, + deleteAccount, + } }