update collection adapter/queries for unified api
- add userId param to list methods - remove public collection methods (now unified) - update query keys to include userId
This commit is contained in:
parent
35b0560749
commit
b8a48771dd
2 changed files with 96 additions and 133 deletions
|
|
@ -19,8 +19,7 @@ import type {
|
|||
CollectionWeaponInput,
|
||||
CollectionSummonInput,
|
||||
CollectionJobAccessoryInput,
|
||||
CollectionFilters,
|
||||
CollectionResponse
|
||||
CollectionFilters
|
||||
} from '$lib/types/api/collection'
|
||||
|
||||
/**
|
||||
|
|
@ -57,15 +56,20 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
// ============================================
|
||||
|
||||
/**
|
||||
* Lists the current user's collection characters with optional filters
|
||||
* Lists a user's collection characters with optional filters
|
||||
* Works for any user - privacy is enforced server-side
|
||||
*/
|
||||
async listCharacters(
|
||||
userId: string,
|
||||
params: CollectionListParams = {}
|
||||
): Promise<PaginatedResponse<CollectionCharacter>> {
|
||||
const response = await this.request<CollectionCharacterListResponse>('/collection/characters', {
|
||||
method: 'GET',
|
||||
query: params
|
||||
})
|
||||
const response = await this.request<CollectionCharacterListResponse>(
|
||||
`/users/${userId}/collection/characters`,
|
||||
{
|
||||
method: 'GET',
|
||||
query: params
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
results: response.characters,
|
||||
|
|
@ -131,17 +135,17 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the IDs of all characters in the current user's collection
|
||||
* Gets the IDs of all characters in a user's collection
|
||||
* Useful for filtering out already-owned characters in the add modal
|
||||
*/
|
||||
async getCollectedCharacterIds(): Promise<string[]> {
|
||||
async getCollectedCharacterIds(userId: string): Promise<string[]> {
|
||||
// Fetch all pages to get complete list
|
||||
const allIds: string[] = []
|
||||
let page = 1
|
||||
let hasMore = true
|
||||
|
||||
while (hasMore) {
|
||||
const response = await this.listCharacters({ page, limit: 100 })
|
||||
const response = await this.listCharacters(userId, { page, limit: 100 })
|
||||
allIds.push(...response.results.map((c) => c.character.id))
|
||||
hasMore = page < response.totalPages
|
||||
page++
|
||||
|
|
@ -155,13 +159,17 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
// ============================================
|
||||
|
||||
/**
|
||||
* Lists the current user's collection weapons with optional filters
|
||||
* Lists a user's collection weapons with optional filters
|
||||
* Works for any user - privacy is enforced server-side
|
||||
*/
|
||||
async listWeapons(params: CollectionListParams = {}): Promise<PaginatedResponse<CollectionWeapon>> {
|
||||
async listWeapons(
|
||||
userId: string,
|
||||
params: CollectionListParams = {}
|
||||
): Promise<PaginatedResponse<CollectionWeapon>> {
|
||||
const response = await this.request<{
|
||||
weapons: CollectionWeapon[]
|
||||
meta: { count: number; totalPages: number; perPage: number; currentPage: number }
|
||||
}>('/collection/weapons', {
|
||||
}>(`/users/${userId}/collection/weapons`, {
|
||||
method: 'GET',
|
||||
query: params
|
||||
})
|
||||
|
|
@ -213,13 +221,17 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
// ============================================
|
||||
|
||||
/**
|
||||
* Lists the current user's collection summons with optional filters
|
||||
* Lists a user's collection summons with optional filters
|
||||
* Works for any user - privacy is enforced server-side
|
||||
*/
|
||||
async listSummons(params: CollectionListParams = {}): Promise<PaginatedResponse<CollectionSummon>> {
|
||||
async listSummons(
|
||||
userId: string,
|
||||
params: CollectionListParams = {}
|
||||
): Promise<PaginatedResponse<CollectionSummon>> {
|
||||
const response = await this.request<{
|
||||
summons: CollectionSummon[]
|
||||
meta: { count: number; totalPages: number; perPage: number; currentPage: number }
|
||||
}>('/collection/summons', {
|
||||
}>(`/users/${userId}/collection/summons`, {
|
||||
method: 'GET',
|
||||
query: params
|
||||
})
|
||||
|
|
@ -304,49 +316,6 @@ export class CollectionAdapter extends BaseAdapter {
|
|||
})
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Public Collection (viewing other users)
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Gets a user's public collection (respects privacy settings)
|
||||
* @param userId - The user's ID
|
||||
* @param type - Optional type filter: 'characters', 'weapons', 'summons', 'job_accessories'
|
||||
*/
|
||||
async getPublicCollection(
|
||||
userId: string,
|
||||
type?: 'characters' | 'weapons' | 'summons' | 'job_accessories'
|
||||
): Promise<CollectionResponse> {
|
||||
return this.request<CollectionResponse>(`/users/${userId}/collection`, {
|
||||
method: 'GET',
|
||||
query: type ? { type } : undefined
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a user's public character collection
|
||||
*/
|
||||
async getPublicCharacters(userId: string): Promise<CollectionCharacter[]> {
|
||||
const response = await this.getPublicCollection(userId, 'characters')
|
||||
return response.characters || []
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a user's public weapon collection
|
||||
*/
|
||||
async getPublicWeapons(userId: string): Promise<CollectionWeapon[]> {
|
||||
const response = await this.getPublicCollection(userId, 'weapons')
|
||||
return response.weapons || []
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a user's public summon collection
|
||||
*/
|
||||
async getPublicSummons(userId: string): Promise<CollectionSummon[]> {
|
||||
const response = await this.getPublicCollection(userId, 'summons')
|
||||
return response.summons || []
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Cache Management
|
||||
// ============================================
|
||||
|
|
|
|||
|
|
@ -27,6 +27,14 @@ export interface CollectionPageResult<T> {
|
|||
perPage: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial data structure for collection infinite queries
|
||||
*/
|
||||
export interface CollectionInitialData<T> {
|
||||
pages: CollectionPageResult<T>[]
|
||||
pageParams: number[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection query options factory
|
||||
*
|
||||
|
|
@ -35,25 +43,33 @@ export interface CollectionPageResult<T> {
|
|||
* import { createQuery, createInfiniteQuery } from '@tanstack/svelte-query'
|
||||
* import { collectionQueries } from '$lib/api/queries/collection.queries'
|
||||
*
|
||||
* // Own collection characters
|
||||
* const characters = createInfiniteQuery(() => collectionQueries.characters())
|
||||
*
|
||||
* // Public collection
|
||||
* const publicChars = createQuery(() => collectionQueries.publicCharacters(userId))
|
||||
* // Any user's collection characters (privacy enforced server-side)
|
||||
* const characters = createInfiniteQuery(() => collectionQueries.characters(userId))
|
||||
*
|
||||
* // Collected character IDs (for filtering add modal)
|
||||
* const ownedIds = createQuery(() => collectionQueries.collectedCharacterIds())
|
||||
* const ownedIds = createQuery(() => collectionQueries.collectedCharacterIds(userId))
|
||||
* ```
|
||||
*/
|
||||
export const collectionQueries = {
|
||||
/**
|
||||
* Current user's collection characters with infinite scroll
|
||||
* User's collection characters with infinite scroll
|
||||
* Works for any user - privacy is enforced server-side
|
||||
*
|
||||
* @param userId - The user whose collection to fetch
|
||||
* @param filters - Optional filters for element, rarity, etc.
|
||||
* @param enabled - Whether the query is enabled (default: true)
|
||||
* @param initialData - Optional initial data for SSR hydration
|
||||
*/
|
||||
characters: (filters?: CollectionFilters) =>
|
||||
characters: (
|
||||
userId: string,
|
||||
filters?: CollectionFilters,
|
||||
enabled: boolean = true,
|
||||
initialData?: CollectionInitialData<CollectionCharacter>
|
||||
) =>
|
||||
infiniteQueryOptions({
|
||||
queryKey: ['collection', 'characters', filters] as const,
|
||||
queryKey: ['collection', 'characters', userId, filters] as const,
|
||||
queryFn: async ({ pageParam }): Promise<CollectionPageResult<CollectionCharacter>> => {
|
||||
const response = await collectionAdapter.listCharacters({
|
||||
const response = await collectionAdapter.listCharacters(userId, {
|
||||
...filters,
|
||||
page: pageParam
|
||||
})
|
||||
|
|
@ -73,17 +89,20 @@ export const collectionQueries = {
|
|||
return undefined
|
||||
},
|
||||
staleTime: 1000 * 60 * 2, // 2 minutes
|
||||
gcTime: 1000 * 60 * 15 // 15 minutes
|
||||
gcTime: 1000 * 60 * 15, // 15 minutes
|
||||
enabled,
|
||||
initialData
|
||||
}),
|
||||
|
||||
/**
|
||||
* Current user's collection weapons with infinite scroll
|
||||
* User's collection weapons with infinite scroll
|
||||
* Works for any user - privacy is enforced server-side
|
||||
*/
|
||||
weapons: (filters?: CollectionFilters) =>
|
||||
weapons: (userId: string, filters?: CollectionFilters) =>
|
||||
infiniteQueryOptions({
|
||||
queryKey: ['collection', 'weapons', filters] as const,
|
||||
queryKey: ['collection', 'weapons', userId, filters] as const,
|
||||
queryFn: async ({ pageParam }): Promise<CollectionPageResult<CollectionWeapon>> => {
|
||||
const response = await collectionAdapter.listWeapons({
|
||||
const response = await collectionAdapter.listWeapons(userId, {
|
||||
...filters,
|
||||
page: pageParam
|
||||
})
|
||||
|
|
@ -107,13 +126,14 @@ export const collectionQueries = {
|
|||
}),
|
||||
|
||||
/**
|
||||
* Current user's collection summons with infinite scroll
|
||||
* User's collection summons with infinite scroll
|
||||
* Works for any user - privacy is enforced server-side
|
||||
*/
|
||||
summons: (filters?: CollectionFilters) =>
|
||||
summons: (userId: string, filters?: CollectionFilters) =>
|
||||
infiniteQueryOptions({
|
||||
queryKey: ['collection', 'summons', filters] as const,
|
||||
queryKey: ['collection', 'summons', userId, filters] as const,
|
||||
queryFn: async ({ pageParam }): Promise<CollectionPageResult<CollectionSummon>> => {
|
||||
const response = await collectionAdapter.listSummons({
|
||||
const response = await collectionAdapter.listSummons(userId, {
|
||||
...filters,
|
||||
page: pageParam
|
||||
})
|
||||
|
|
@ -137,13 +157,14 @@ export const collectionQueries = {
|
|||
}),
|
||||
|
||||
/**
|
||||
* Get IDs of characters already in the user's collection
|
||||
* Get IDs of characters already in a user's collection
|
||||
* Used to filter out owned characters in the add modal
|
||||
*/
|
||||
collectedCharacterIds: () =>
|
||||
collectedCharacterIds: (userId: string) =>
|
||||
queryOptions({
|
||||
queryKey: ['collection', 'characters', 'ids'] as const,
|
||||
queryFn: () => collectionAdapter.getCollectedCharacterIds(),
|
||||
queryKey: ['collection', 'characters', 'ids', userId] as const,
|
||||
queryFn: () => collectionAdapter.getCollectedCharacterIds(userId),
|
||||
enabled: !!userId,
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
gcTime: 1000 * 60 * 30 // 30 minutes
|
||||
}),
|
||||
|
|
@ -158,42 +179,6 @@ export const collectionQueries = {
|
|||
enabled: !!id,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
gcTime: 1000 * 60 * 30
|
||||
}),
|
||||
|
||||
/**
|
||||
* Public collection for a user (respects privacy)
|
||||
*/
|
||||
publicCharacters: (userId: string) =>
|
||||
queryOptions({
|
||||
queryKey: ['collection', 'public', userId, 'characters'] as const,
|
||||
queryFn: () => collectionAdapter.getPublicCharacters(userId),
|
||||
enabled: !!userId,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
gcTime: 1000 * 60 * 30
|
||||
}),
|
||||
|
||||
/**
|
||||
* Public weapon collection for a user
|
||||
*/
|
||||
publicWeapons: (userId: string) =>
|
||||
queryOptions({
|
||||
queryKey: ['collection', 'public', userId, 'weapons'] as const,
|
||||
queryFn: () => collectionAdapter.getPublicWeapons(userId),
|
||||
enabled: !!userId,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
gcTime: 1000 * 60 * 30
|
||||
}),
|
||||
|
||||
/**
|
||||
* Public summon collection for a user
|
||||
*/
|
||||
publicSummons: (userId: string) =>
|
||||
queryOptions({
|
||||
queryKey: ['collection', 'public', userId, 'summons'] as const,
|
||||
queryFn: () => collectionAdapter.getPublicSummons(userId),
|
||||
enabled: !!userId,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
gcTime: 1000 * 60 * 30
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -210,24 +195,33 @@ export const collectionQueries = {
|
|||
* // Invalidate all collection data
|
||||
* queryClient.invalidateQueries({ queryKey: collectionKeys.all })
|
||||
*
|
||||
* // Invalidate only characters
|
||||
* queryClient.invalidateQueries({ queryKey: collectionKeys.characters() })
|
||||
* // Invalidate only characters for a user
|
||||
* queryClient.invalidateQueries({ queryKey: collectionKeys.characters(userId) })
|
||||
* ```
|
||||
*/
|
||||
export const collectionKeys = {
|
||||
all: ['collection'] as const,
|
||||
characters: () => [...collectionKeys.all, 'characters'] as const,
|
||||
characterList: (filters?: CollectionFilters) =>
|
||||
[...collectionKeys.characters(), filters] as const,
|
||||
characters: (userId?: string) =>
|
||||
userId
|
||||
? ([...collectionKeys.all, 'characters', userId] as const)
|
||||
: ([...collectionKeys.all, 'characters'] as const),
|
||||
characterList: (userId: string, filters?: CollectionFilters) =>
|
||||
[...collectionKeys.characters(userId), filters] as const,
|
||||
character: (id: string) => [...collectionKeys.all, 'character', id] as const,
|
||||
characterIds: () => [...collectionKeys.characters(), 'ids'] as const,
|
||||
weapons: () => [...collectionKeys.all, 'weapons'] as const,
|
||||
weaponList: (filters?: CollectionFilters) => [...collectionKeys.weapons(), filters] as const,
|
||||
summons: () => [...collectionKeys.all, 'summons'] as const,
|
||||
summonList: (filters?: CollectionFilters) => [...collectionKeys.summons(), filters] as const,
|
||||
public: (userId: string) => [...collectionKeys.all, 'public', userId] as const,
|
||||
publicCharacters: (userId: string) =>
|
||||
[...collectionKeys.public(userId), 'characters'] as const,
|
||||
publicWeapons: (userId: string) => [...collectionKeys.public(userId), 'weapons'] as const,
|
||||
publicSummons: (userId: string) => [...collectionKeys.public(userId), 'summons'] as const
|
||||
characterIds: (userId?: string) =>
|
||||
userId
|
||||
? ([...collectionKeys.all, 'characters', 'ids', userId] as const)
|
||||
: ([...collectionKeys.all, 'characters', 'ids'] as const),
|
||||
weapons: (userId?: string) =>
|
||||
userId
|
||||
? ([...collectionKeys.all, 'weapons', userId] as const)
|
||||
: ([...collectionKeys.all, 'weapons'] as const),
|
||||
weaponList: (userId: string, filters?: CollectionFilters) =>
|
||||
[...collectionKeys.weapons(userId), filters] as const,
|
||||
summons: (userId?: string) =>
|
||||
userId
|
||||
? ([...collectionKeys.all, 'summons', userId] as const)
|
||||
: ([...collectionKeys.all, 'summons'] as const),
|
||||
summonList: (userId: string, filters?: CollectionFilters) =>
|
||||
[...collectionKeys.summons(userId), filters] as const
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue