feat: update frontend for account-based subscriptions
Replace all team_id/team_admin references with account_id/owner across types, store, hooks, API clients, components, and pages. Add new AccountSettingsPage, UpgradePrompt, CheckoutButton, useSubscription hook, and accounts API client. AuthStore now parallel-fetches account and subscription data alongside user profile. Also fix folder sidebar not refreshing after tree deletion by dispatching the folder-changed event in handleDeleteTree. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
import type { User, Token, UserCreate, UserLogin } from '@/types'
|
||||
import type { User, Token, UserCreate, UserLogin, Account, SubscriptionDetails } from '@/types'
|
||||
import { authApi } from '@/api'
|
||||
import { apiClient } from '@/api'
|
||||
|
||||
interface AuthState {
|
||||
user: User | null
|
||||
token: Token | null
|
||||
account: Account | null
|
||||
subscription: SubscriptionDetails | null
|
||||
isAuthenticated: boolean
|
||||
isLoading: boolean
|
||||
error: string | null
|
||||
@@ -25,6 +28,8 @@ export const useAuthStore = create<AuthState>()(
|
||||
(set, get) => ({
|
||||
user: null,
|
||||
token: null,
|
||||
account: null,
|
||||
subscription: null,
|
||||
isAuthenticated: false,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
@@ -70,15 +75,30 @@ export const useAuthStore = create<AuthState>()(
|
||||
} finally {
|
||||
localStorage.removeItem('access_token')
|
||||
localStorage.removeItem('refresh_token')
|
||||
set({ user: null, token: null, isAuthenticated: false, error: null })
|
||||
set({ user: null, token: null, account: null, subscription: null, isAuthenticated: false, error: null })
|
||||
}
|
||||
},
|
||||
|
||||
fetchUser: async () => {
|
||||
set({ isLoading: true })
|
||||
try {
|
||||
const user = await authApi.me()
|
||||
set({ user, isLoading: false })
|
||||
const [userResult, accountResult, subscriptionResult] = await Promise.allSettled([
|
||||
authApi.me(),
|
||||
apiClient.get<Account>('/accounts/me').then(r => r.data),
|
||||
apiClient.get<SubscriptionDetails>('/accounts/me/subscription').then(r => r.data),
|
||||
])
|
||||
|
||||
const user = userResult.status === 'fulfilled' ? userResult.value : null
|
||||
const account = accountResult.status === 'fulfilled' ? accountResult.value : null
|
||||
const subscription = subscriptionResult.status === 'fulfilled' ? subscriptionResult.value : null
|
||||
|
||||
if (!user) {
|
||||
// User fetch failed — propagate the error
|
||||
const reason = userResult.status === 'rejected' ? userResult.reason : new Error('Failed to fetch user')
|
||||
throw reason
|
||||
}
|
||||
|
||||
set({ user, account, subscription, isLoading: false })
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to fetch user'
|
||||
set({ error: message, isLoading: false })
|
||||
@@ -95,6 +115,8 @@ export const useAuthStore = create<AuthState>()(
|
||||
partialize: (state) => ({
|
||||
token: state.token,
|
||||
isAuthenticated: state.isAuthenticated,
|
||||
account: state.account,
|
||||
subscription: state.subscription,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user