This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

The changes have been successfully implemented. The ApiClient has been refactored into multiple files following the proposed structure:

1. Types are now separated into:
- `src/webapp/api-client/types/requests.ts`
- `src/webapp/api-client/types/responses.ts`
- `src/webapp/api-client/types/errors.ts`
- `src/webapp/api-client/types/index.ts`

2. Clients are now separated into:
- `src/webapp/api-client/clients/BaseClient.ts`
- `src/webapp/api-client/clients/QueryClient.ts`
- `src/webapp/api-client/clients/CardClient.ts`
- `src/webapp/api-client/clients/CollectionClient.ts`
- `src/webapp/api-client/clients/index.ts`

3. The main `ApiClient.ts` now uses composition, delegating to specialized clients.

4. An `index.ts` file was added to the `api-client` directory to export everything.

The refactoring provides several benefits:
- Better separation of concerns
- Improved maintainability
- More modular and testable code
- Clear type definitions
- Easy extensibility

Would you like me to explain any part of the implementation or make any further modifications?

Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <aider@aider.chat>

+510 -351
+62 -351
src/webapp/api-client/ApiClient.ts
··· 1 - // Request types - cleaned up from backend DTOs 2 - export interface AddUrlToLibraryRequest { 3 - url: string; 4 - note?: string; 5 - collectionIds?: string[]; 6 - } 7 - 8 - export interface AddCardToLibraryRequest { 9 - cardId: string; 10 - collectionIds?: string[]; 11 - } 12 - 13 - export interface AddCardToCollectionRequest { 14 - cardId: string; 15 - collectionIds: string[]; 16 - } 17 - 18 - export interface UpdateNoteCardRequest { 19 - cardId: string; 20 - note: string; 21 - } 22 - 23 - export interface RemoveCardFromLibraryRequest { 24 - cardId: string; 25 - } 26 - 27 - export interface RemoveCardFromCollectionRequest { 28 - cardId: string; 29 - collectionIds: string[]; 30 - } 31 - 32 - export interface CreateCollectionRequest { 33 - name: string; 34 - description?: string; 35 - } 36 - 37 - export interface UpdateCollectionRequest { 38 - collectionId: string; 39 - name: string; 40 - description?: string; 41 - } 42 - 43 - export interface DeleteCollectionRequest { 44 - collectionId: string; 45 - } 46 - 47 - // Response types 48 - export interface AddUrlToLibraryResponse { 49 - urlCardId: string; 50 - noteCardId?: string; 51 - } 52 - 53 - export interface AddCardToLibraryResponse { 54 - cardId: string; 55 - } 56 - 57 - export interface AddCardToCollectionResponse { 58 - cardId: string; 59 - } 60 - 61 - export interface UpdateNoteCardResponse { 62 - cardId: string; 63 - } 1 + import { QueryClient, CardClient, CollectionClient } from './clients'; 2 + import type { 3 + // Request types 4 + AddUrlToLibraryRequest, 5 + AddCardToLibraryRequest, 6 + AddCardToCollectionRequest, 7 + UpdateNoteCardRequest, 8 + RemoveCardFromLibraryRequest, 9 + RemoveCardFromCollectionRequest, 10 + CreateCollectionRequest, 11 + UpdateCollectionRequest, 12 + DeleteCollectionRequest, 13 + GetMyUrlCardsParams, 14 + GetCollectionPageParams, 15 + // Response types 16 + AddUrlToLibraryResponse, 17 + AddCardToLibraryResponse, 18 + AddCardToCollectionResponse, 19 + UpdateNoteCardResponse, 20 + RemoveCardFromLibraryResponse, 21 + RemoveCardFromCollectionResponse, 22 + CreateCollectionResponse, 23 + UpdateCollectionResponse, 24 + DeleteCollectionResponse, 25 + GetUrlMetadataResponse, 26 + GetMyUrlCardsResponse, 27 + GetUrlCardViewResponse, 28 + GetLibrariesForCardResponse, 29 + GetMyProfileResponse, 30 + GetCollectionPageResponse, 31 + } from './types'; 64 32 65 - export interface RemoveCardFromLibraryResponse { 66 - cardId: string; 67 - } 33 + // Main API Client class using composition 34 + export class ApiClient { 35 + private queryClient: QueryClient; 36 + private cardClient: CardClient; 37 + private collectionClient: CollectionClient; 68 38 69 - export interface RemoveCardFromCollectionResponse { 70 - cardId: string; 71 - } 72 - 73 - export interface CreateCollectionResponse { 74 - collectionId: string; 75 - } 76 - 77 - export interface UpdateCollectionResponse { 78 - collectionId: string; 79 - } 80 - 81 - export interface DeleteCollectionResponse { 82 - collectionId: string; 83 - } 84 - 85 - // Query response types 86 - export interface UrlMetadata { 87 - url: string; 88 - title?: string; 89 - description?: string; 90 - author?: string; 91 - siteName?: string; 92 - imageUrl?: string; 93 - type?: string; 94 - } 95 - 96 - export interface GetUrlMetadataResponse { 97 - metadata: UrlMetadata; 98 - existingCardId?: string; 99 - } 100 - 101 - export interface UrlCardView { 102 - id: string; 103 - url: string; 104 - title?: string; 105 - description?: string; 106 - author?: string; 107 - siteName?: string; 108 - imageUrl?: string; 109 - type?: string; 110 - createdAt: string; 111 - updatedAt: string; 112 - libraryCount: number; 113 - collections: { 114 - id: string; 115 - name: string; 116 - authorId: string; 117 - }[]; 118 - libraries: { 119 - userId: string; 120 - name: string; 121 - handle: string; 122 - avatarUrl?: string; 123 - }[]; 124 - } 125 - 126 - export interface GetUrlCardViewResponse extends UrlCardView {} 127 - 128 - export interface LibraryUser { 129 - id: string; 130 - name: string; 131 - handle: string; 132 - avatarUrl?: string; 133 - } 134 - 135 - export interface GetLibrariesForCardResponse { 136 - cardId: string; 137 - users: LibraryUser[]; 138 - totalCount: number; 139 - } 140 - 141 - export interface UserProfile { 142 - id: string; 143 - name: string; 144 - handle: string; 145 - description?: string; 146 - avatarUrl?: string; 147 - } 148 - 149 - export interface GetMyProfileResponse extends UserProfile {} 150 - 151 - export interface UrlCardListItem { 152 - id: string; 153 - url: string; 154 - title?: string; 155 - description?: string; 156 - author?: string; 157 - siteName?: string; 158 - imageUrl?: string; 159 - type?: string; 160 - createdAt: string; 161 - updatedAt: string; 162 - libraryCount: number; 163 - collections: { 164 - id: string; 165 - name: string; 166 - authorId: string; 167 - }[]; 168 - } 169 - 170 - export interface Pagination { 171 - currentPage: number; 172 - totalPages: number; 173 - totalCount: number; 174 - hasMore: boolean; 175 - limit: number; 176 - } 177 - 178 - export interface Sorting { 179 - sortBy: string; 180 - sortOrder: 'asc' | 'desc'; 181 - } 182 - 183 - export interface GetMyUrlCardsResponse { 184 - cards: UrlCardListItem[]; 185 - pagination: Pagination; 186 - sorting: Sorting; 187 - } 188 - 189 - export interface CollectionPageUrlCard { 190 - id: string; 191 - url: string; 192 - title?: string; 193 - description?: string; 194 - author?: string; 195 - siteName?: string; 196 - imageUrl?: string; 197 - type?: string; 198 - createdAt: string; 199 - updatedAt: string; 200 - libraryCount: number; 201 - } 202 - 203 - export interface GetCollectionPageResponse { 204 - id: string; 205 - name: string; 206 - description?: string; 207 - author: { 208 - id: string; 209 - name: string; 210 - handle: string; 211 - avatarUrl?: string; 212 - }; 213 - urlCards: CollectionPageUrlCard[]; 214 - pagination: Pagination; 215 - sorting: Sorting; 216 - } 217 - 218 - // Error types 219 - export interface ApiErrorResponse { 220 - message: string; 221 - code?: string; 222 - details?: any; 223 - } 224 - 225 - export class ApiError extends Error { 226 39 constructor( 227 - message: string, 228 - public status: number, 229 - public code?: string, 230 - public details?: any 40 + private baseUrl: string, 41 + private getAuthToken: () => string | null 231 42 ) { 232 - super(message); 233 - this.name = 'ApiError'; 43 + this.queryClient = new QueryClient(baseUrl, getAuthToken); 44 + this.cardClient = new CardClient(baseUrl, getAuthToken); 45 + this.collectionClient = new CollectionClient(baseUrl, getAuthToken); 234 46 } 235 - } 236 47 237 - // Query parameters 238 - export interface GetMyUrlCardsParams { 239 - page?: number; 240 - limit?: number; 241 - sortBy?: string; 242 - sortOrder?: 'asc' | 'desc'; 243 - } 244 - 245 - export interface GetCollectionPageParams { 246 - page?: number; 247 - limit?: number; 248 - sortBy?: string; 249 - sortOrder?: 'asc' | 'desc'; 250 - } 251 - 252 - // Main API Client class 253 - export class ApiClient { 254 - constructor( 255 - private baseUrl: string, 256 - private getAuthToken: () => string | null 257 - ) {} 258 - 259 - // Query operations 48 + // Query operations - delegate to QueryClient 260 49 async getUrlMetadata(url: string): Promise<GetUrlMetadataResponse> { 261 - const params = new URLSearchParams({ url }); 262 - return this.request<GetUrlMetadataResponse>('GET', `/cards/metadata?${params}`); 50 + return this.queryClient.getUrlMetadata(url); 263 51 } 264 52 265 53 async getMyUrlCards(params?: GetMyUrlCardsParams): Promise<GetMyUrlCardsResponse> { 266 - const searchParams = new URLSearchParams(); 267 - if (params?.page) searchParams.set('page', params.page.toString()); 268 - if (params?.limit) searchParams.set('limit', params.limit.toString()); 269 - if (params?.sortBy) searchParams.set('sortBy', params.sortBy); 270 - if (params?.sortOrder) searchParams.set('sortOrder', params.sortOrder); 271 - 272 - const queryString = searchParams.toString(); 273 - const endpoint = queryString ? `/cards/my?${queryString}` : '/cards/my'; 274 - 275 - return this.request<GetMyUrlCardsResponse>('GET', endpoint); 54 + return this.queryClient.getMyUrlCards(params); 276 55 } 277 56 278 57 async getUrlCardView(cardId: string): Promise<GetUrlCardViewResponse> { 279 - return this.request<GetUrlCardViewResponse>('GET', `/cards/${cardId}`); 58 + return this.queryClient.getUrlCardView(cardId); 280 59 } 281 60 282 61 async getLibrariesForCard(cardId: string): Promise<GetLibrariesForCardResponse> { 283 - return this.request<GetLibrariesForCardResponse>('GET', `/cards/${cardId}/libraries`); 62 + return this.queryClient.getLibrariesForCard(cardId); 284 63 } 285 64 286 65 async getMyProfile(): Promise<GetMyProfileResponse> { 287 - return this.request<GetMyProfileResponse>('GET', '/users/me'); 66 + return this.queryClient.getMyProfile(); 288 67 } 289 68 290 69 async getCollectionPage(collectionId: string, params?: GetCollectionPageParams): Promise<GetCollectionPageResponse> { 291 - const searchParams = new URLSearchParams(); 292 - if (params?.page) searchParams.set('page', params.page.toString()); 293 - if (params?.limit) searchParams.set('limit', params.limit.toString()); 294 - if (params?.sortBy) searchParams.set('sortBy', params.sortBy); 295 - if (params?.sortOrder) searchParams.set('sortOrder', params.sortOrder); 296 - 297 - const queryString = searchParams.toString(); 298 - const endpoint = queryString ? `/collections/${collectionId}?${queryString}` : `/collections/${collectionId}`; 299 - 300 - return this.request<GetCollectionPageResponse>('GET', endpoint); 70 + return this.queryClient.getCollectionPage(collectionId, params); 301 71 } 302 72 303 - // Card operations 73 + // Card operations - delegate to CardClient 304 74 async addUrlToLibrary(request: AddUrlToLibraryRequest): Promise<AddUrlToLibraryResponse> { 305 - // TODO: Implement 306 - throw new Error('Not implemented'); 75 + return this.cardClient.addUrlToLibrary(request); 307 76 } 308 77 309 78 async addCardToLibrary(request: AddCardToLibraryRequest): Promise<AddCardToLibraryResponse> { 310 - // TODO: Implement 311 - throw new Error('Not implemented'); 79 + return this.cardClient.addCardToLibrary(request); 312 80 } 313 81 314 82 async addCardToCollection(request: AddCardToCollectionRequest): Promise<AddCardToCollectionResponse> { 315 - // TODO: Implement 316 - throw new Error('Not implemented'); 83 + return this.cardClient.addCardToCollection(request); 317 84 } 318 85 319 86 async updateNoteCard(request: UpdateNoteCardRequest): Promise<UpdateNoteCardResponse> { 320 - // TODO: Implement 321 - throw new Error('Not implemented'); 87 + return this.cardClient.updateNoteCard(request); 322 88 } 323 89 324 90 async removeCardFromLibrary(request: RemoveCardFromLibraryRequest): Promise<RemoveCardFromLibraryResponse> { 325 - // TODO: Implement 326 - throw new Error('Not implemented'); 91 + return this.cardClient.removeCardFromLibrary(request); 327 92 } 328 93 329 94 async removeCardFromCollection(request: RemoveCardFromCollectionRequest): Promise<RemoveCardFromCollectionResponse> { 330 - // TODO: Implement 331 - throw new Error('Not implemented'); 95 + return this.cardClient.removeCardFromCollection(request); 332 96 } 333 97 334 - // Collection operations 98 + // Collection operations - delegate to CollectionClient 335 99 async createCollection(request: CreateCollectionRequest): Promise<CreateCollectionResponse> { 336 - // TODO: Implement 337 - throw new Error('Not implemented'); 100 + return this.collectionClient.createCollection(request); 338 101 } 339 102 340 103 async updateCollection(request: UpdateCollectionRequest): Promise<UpdateCollectionResponse> { 341 - // TODO: Implement 342 - throw new Error('Not implemented'); 104 + return this.collectionClient.updateCollection(request); 343 105 } 344 106 345 107 async deleteCollection(request: DeleteCollectionRequest): Promise<DeleteCollectionResponse> { 346 - // TODO: Implement 347 - throw new Error('Not implemented'); 108 + return this.collectionClient.deleteCollection(request); 348 109 } 110 + } 349 111 350 - // Private helper methods 351 - private async request<T>( 352 - method: string, 353 - endpoint: string, 354 - data?: any 355 - ): Promise<T> { 356 - const url = `${this.baseUrl}/api${endpoint}`; 357 - const token = this.getAuthToken(); 358 - 359 - const headers: Record<string, string> = { 360 - 'Content-Type': 'application/json', 361 - }; 362 - 363 - if (token) { 364 - headers['Authorization'] = `Bearer ${token}`; 365 - } 366 - 367 - const config: RequestInit = { 368 - method, 369 - headers, 370 - }; 371 - 372 - if (data && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { 373 - config.body = JSON.stringify(data); 374 - } 375 - 376 - const response = await fetch(url, config); 377 - return this.handleResponse<T>(response); 378 - } 379 - 380 - private async handleResponse<T>(response: Response): Promise<T> { 381 - if (!response.ok) { 382 - let errorData: ApiErrorResponse; 383 - 384 - try { 385 - errorData = await response.json(); 386 - } catch { 387 - errorData = { 388 - message: response.statusText || 'Unknown error', 389 - }; 390 - } 391 - 392 - throw new ApiError( 393 - errorData.message, 394 - response.status, 395 - errorData.code, 396 - errorData.details 397 - ); 398 - } 399 - 400 - return response.json(); 401 - } 402 - } 112 + // Re-export types for convenience 113 + export * from './types';
+60
src/webapp/api-client/clients/BaseClient.ts
··· 1 + import { ApiError, ApiErrorResponse } from '../types/errors'; 2 + 3 + export abstract class BaseClient { 4 + constructor( 5 + protected baseUrl: string, 6 + protected getAuthToken: () => string | null 7 + ) {} 8 + 9 + protected async request<T>( 10 + method: string, 11 + endpoint: string, 12 + data?: any 13 + ): Promise<T> { 14 + const url = `${this.baseUrl}/api${endpoint}`; 15 + const token = this.getAuthToken(); 16 + 17 + const headers: Record<string, string> = { 18 + 'Content-Type': 'application/json', 19 + }; 20 + 21 + if (token) { 22 + headers['Authorization'] = `Bearer ${token}`; 23 + } 24 + 25 + const config: RequestInit = { 26 + method, 27 + headers, 28 + }; 29 + 30 + if (data && (method === 'POST' || method === 'PUT' || method === 'PATCH')) { 31 + config.body = JSON.stringify(data); 32 + } 33 + 34 + const response = await fetch(url, config); 35 + return this.handleResponse<T>(response); 36 + } 37 + 38 + private async handleResponse<T>(response: Response): Promise<T> { 39 + if (!response.ok) { 40 + let errorData: ApiErrorResponse; 41 + 42 + try { 43 + errorData = await response.json(); 44 + } catch { 45 + errorData = { 46 + message: response.statusText || 'Unknown error', 47 + }; 48 + } 49 + 50 + throw new ApiError( 51 + errorData.message, 52 + response.status, 53 + errorData.code, 54 + errorData.details 55 + ); 56 + } 57 + 58 + return response.json(); 59 + } 60 + }
+47
src/webapp/api-client/clients/CardClient.ts
··· 1 + import { BaseClient } from './BaseClient'; 2 + import { 3 + AddUrlToLibraryRequest, 4 + AddUrlToLibraryResponse, 5 + AddCardToLibraryRequest, 6 + AddCardToLibraryResponse, 7 + AddCardToCollectionRequest, 8 + AddCardToCollectionResponse, 9 + UpdateNoteCardRequest, 10 + UpdateNoteCardResponse, 11 + RemoveCardFromLibraryRequest, 12 + RemoveCardFromLibraryResponse, 13 + RemoveCardFromCollectionRequest, 14 + RemoveCardFromCollectionResponse, 15 + } from '../types'; 16 + 17 + export class CardClient extends BaseClient { 18 + async addUrlToLibrary(request: AddUrlToLibraryRequest): Promise<AddUrlToLibraryResponse> { 19 + // TODO: Implement 20 + throw new Error('Not implemented'); 21 + } 22 + 23 + async addCardToLibrary(request: AddCardToLibraryRequest): Promise<AddCardToLibraryResponse> { 24 + // TODO: Implement 25 + throw new Error('Not implemented'); 26 + } 27 + 28 + async addCardToCollection(request: AddCardToCollectionRequest): Promise<AddCardToCollectionResponse> { 29 + // TODO: Implement 30 + throw new Error('Not implemented'); 31 + } 32 + 33 + async updateNoteCard(request: UpdateNoteCardRequest): Promise<UpdateNoteCardResponse> { 34 + // TODO: Implement 35 + throw new Error('Not implemented'); 36 + } 37 + 38 + async removeCardFromLibrary(request: RemoveCardFromLibraryRequest): Promise<RemoveCardFromLibraryResponse> { 39 + // TODO: Implement 40 + throw new Error('Not implemented'); 41 + } 42 + 43 + async removeCardFromCollection(request: RemoveCardFromCollectionRequest): Promise<RemoveCardFromCollectionResponse> { 44 + // TODO: Implement 45 + throw new Error('Not implemented'); 46 + } 47 + }
+26
src/webapp/api-client/clients/CollectionClient.ts
··· 1 + import { BaseClient } from './BaseClient'; 2 + import { 3 + CreateCollectionRequest, 4 + CreateCollectionResponse, 5 + UpdateCollectionRequest, 6 + UpdateCollectionResponse, 7 + DeleteCollectionRequest, 8 + DeleteCollectionResponse, 9 + } from '../types'; 10 + 11 + export class CollectionClient extends BaseClient { 12 + async createCollection(request: CreateCollectionRequest): Promise<CreateCollectionResponse> { 13 + // TODO: Implement 14 + throw new Error('Not implemented'); 15 + } 16 + 17 + async updateCollection(request: UpdateCollectionRequest): Promise<UpdateCollectionResponse> { 18 + // TODO: Implement 19 + throw new Error('Not implemented'); 20 + } 21 + 22 + async deleteCollection(request: DeleteCollectionRequest): Promise<DeleteCollectionResponse> { 23 + // TODO: Implement 24 + throw new Error('Not implemented'); 25 + } 26 + }
+56
src/webapp/api-client/clients/QueryClient.ts
··· 1 + import { BaseClient } from './BaseClient'; 2 + import { 3 + GetUrlMetadataResponse, 4 + GetMyUrlCardsResponse, 5 + GetUrlCardViewResponse, 6 + GetLibrariesForCardResponse, 7 + GetMyProfileResponse, 8 + GetCollectionPageResponse, 9 + GetMyUrlCardsParams, 10 + GetCollectionPageParams, 11 + } from '../types'; 12 + 13 + export class QueryClient extends BaseClient { 14 + async getUrlMetadata(url: string): Promise<GetUrlMetadataResponse> { 15 + const params = new URLSearchParams({ url }); 16 + return this.request<GetUrlMetadataResponse>('GET', `/cards/metadata?${params}`); 17 + } 18 + 19 + async getMyUrlCards(params?: GetMyUrlCardsParams): Promise<GetMyUrlCardsResponse> { 20 + const searchParams = new URLSearchParams(); 21 + if (params?.page) searchParams.set('page', params.page.toString()); 22 + if (params?.limit) searchParams.set('limit', params.limit.toString()); 23 + if (params?.sortBy) searchParams.set('sortBy', params.sortBy); 24 + if (params?.sortOrder) searchParams.set('sortOrder', params.sortOrder); 25 + 26 + const queryString = searchParams.toString(); 27 + const endpoint = queryString ? `/cards/my?${queryString}` : '/cards/my'; 28 + 29 + return this.request<GetMyUrlCardsResponse>('GET', endpoint); 30 + } 31 + 32 + async getUrlCardView(cardId: string): Promise<GetUrlCardViewResponse> { 33 + return this.request<GetUrlCardViewResponse>('GET', `/cards/${cardId}`); 34 + } 35 + 36 + async getLibrariesForCard(cardId: string): Promise<GetLibrariesForCardResponse> { 37 + return this.request<GetLibrariesForCardResponse>('GET', `/cards/${cardId}/libraries`); 38 + } 39 + 40 + async getMyProfile(): Promise<GetMyProfileResponse> { 41 + return this.request<GetMyProfileResponse>('GET', '/users/me'); 42 + } 43 + 44 + async getCollectionPage(collectionId: string, params?: GetCollectionPageParams): Promise<GetCollectionPageResponse> { 45 + const searchParams = new URLSearchParams(); 46 + if (params?.page) searchParams.set('page', params.page.toString()); 47 + if (params?.limit) searchParams.set('limit', params.limit.toString()); 48 + if (params?.sortBy) searchParams.set('sortBy', params.sortBy); 49 + if (params?.sortOrder) searchParams.set('sortOrder', params.sortOrder); 50 + 51 + const queryString = searchParams.toString(); 52 + const endpoint = queryString ? `/collections/${collectionId}?${queryString}` : `/collections/${collectionId}`; 53 + 54 + return this.request<GetCollectionPageResponse>('GET', endpoint); 55 + } 56 + }
+4
src/webapp/api-client/clients/index.ts
··· 1 + export * from './BaseClient'; 2 + export * from './QueryClient'; 3 + export * from './CardClient'; 4 + export * from './CollectionClient';
+3
src/webapp/api-client/index.ts
··· 1 + export * from './ApiClient'; 2 + export * from './types'; 3 + export * from './clients';
+18
src/webapp/api-client/types/errors.ts
··· 1 + // Error types 2 + export interface ApiErrorResponse { 3 + message: string; 4 + code?: string; 5 + details?: any; 6 + } 7 + 8 + export class ApiError extends Error { 9 + constructor( 10 + message: string, 11 + public status: number, 12 + public code?: string, 13 + public details?: any 14 + ) { 15 + super(message); 16 + this.name = 'ApiError'; 17 + } 18 + }
+4
src/webapp/api-client/types/index.ts
··· 1 + // Re-export all types for easy importing 2 + export * from './requests'; 3 + export * from './responses'; 4 + export * from './errors';
+60
src/webapp/api-client/types/requests.ts
··· 1 + // Request types - cleaned up from backend DTOs 2 + export interface AddUrlToLibraryRequest { 3 + url: string; 4 + note?: string; 5 + collectionIds?: string[]; 6 + } 7 + 8 + export interface AddCardToLibraryRequest { 9 + cardId: string; 10 + collectionIds?: string[]; 11 + } 12 + 13 + export interface AddCardToCollectionRequest { 14 + cardId: string; 15 + collectionIds: string[]; 16 + } 17 + 18 + export interface UpdateNoteCardRequest { 19 + cardId: string; 20 + note: string; 21 + } 22 + 23 + export interface RemoveCardFromLibraryRequest { 24 + cardId: string; 25 + } 26 + 27 + export interface RemoveCardFromCollectionRequest { 28 + cardId: string; 29 + collectionIds: string[]; 30 + } 31 + 32 + export interface CreateCollectionRequest { 33 + name: string; 34 + description?: string; 35 + } 36 + 37 + export interface UpdateCollectionRequest { 38 + collectionId: string; 39 + name: string; 40 + description?: string; 41 + } 42 + 43 + export interface DeleteCollectionRequest { 44 + collectionId: string; 45 + } 46 + 47 + // Query parameters 48 + export interface GetMyUrlCardsParams { 49 + page?: number; 50 + limit?: number; 51 + sortBy?: string; 52 + sortOrder?: 'asc' | 'desc'; 53 + } 54 + 55 + export interface GetCollectionPageParams { 56 + page?: number; 57 + limit?: number; 58 + sortBy?: string; 59 + sortOrder?: 'asc' | 'desc'; 60 + }
+170
src/webapp/api-client/types/responses.ts
··· 1 + // Command response types 2 + export interface AddUrlToLibraryResponse { 3 + urlCardId: string; 4 + noteCardId?: string; 5 + } 6 + 7 + export interface AddCardToLibraryResponse { 8 + cardId: string; 9 + } 10 + 11 + export interface AddCardToCollectionResponse { 12 + cardId: string; 13 + } 14 + 15 + export interface UpdateNoteCardResponse { 16 + cardId: string; 17 + } 18 + 19 + export interface RemoveCardFromLibraryResponse { 20 + cardId: string; 21 + } 22 + 23 + export interface RemoveCardFromCollectionResponse { 24 + cardId: string; 25 + } 26 + 27 + export interface CreateCollectionResponse { 28 + collectionId: string; 29 + } 30 + 31 + export interface UpdateCollectionResponse { 32 + collectionId: string; 33 + } 34 + 35 + export interface DeleteCollectionResponse { 36 + collectionId: string; 37 + } 38 + 39 + // Query response types 40 + export interface UrlMetadata { 41 + url: string; 42 + title?: string; 43 + description?: string; 44 + author?: string; 45 + siteName?: string; 46 + imageUrl?: string; 47 + type?: string; 48 + } 49 + 50 + export interface GetUrlMetadataResponse { 51 + metadata: UrlMetadata; 52 + existingCardId?: string; 53 + } 54 + 55 + export interface UrlCardView { 56 + id: string; 57 + url: string; 58 + title?: string; 59 + description?: string; 60 + author?: string; 61 + siteName?: string; 62 + imageUrl?: string; 63 + type?: string; 64 + createdAt: string; 65 + updatedAt: string; 66 + libraryCount: number; 67 + collections: { 68 + id: string; 69 + name: string; 70 + authorId: string; 71 + }[]; 72 + libraries: { 73 + userId: string; 74 + name: string; 75 + handle: string; 76 + avatarUrl?: string; 77 + }[]; 78 + } 79 + 80 + export interface GetUrlCardViewResponse extends UrlCardView {} 81 + 82 + export interface LibraryUser { 83 + id: string; 84 + name: string; 85 + handle: string; 86 + avatarUrl?: string; 87 + } 88 + 89 + export interface GetLibrariesForCardResponse { 90 + cardId: string; 91 + users: LibraryUser[]; 92 + totalCount: number; 93 + } 94 + 95 + export interface UserProfile { 96 + id: string; 97 + name: string; 98 + handle: string; 99 + description?: string; 100 + avatarUrl?: string; 101 + } 102 + 103 + export interface GetMyProfileResponse extends UserProfile {} 104 + 105 + export interface UrlCardListItem { 106 + id: string; 107 + url: string; 108 + title?: string; 109 + description?: string; 110 + author?: string; 111 + siteName?: string; 112 + imageUrl?: string; 113 + type?: string; 114 + createdAt: string; 115 + updatedAt: string; 116 + libraryCount: number; 117 + collections: { 118 + id: string; 119 + name: string; 120 + authorId: string; 121 + }[]; 122 + } 123 + 124 + export interface Pagination { 125 + currentPage: number; 126 + totalPages: number; 127 + totalCount: number; 128 + hasMore: boolean; 129 + limit: number; 130 + } 131 + 132 + export interface Sorting { 133 + sortBy: string; 134 + sortOrder: 'asc' | 'desc'; 135 + } 136 + 137 + export interface GetMyUrlCardsResponse { 138 + cards: UrlCardListItem[]; 139 + pagination: Pagination; 140 + sorting: Sorting; 141 + } 142 + 143 + export interface CollectionPageUrlCard { 144 + id: string; 145 + url: string; 146 + title?: string; 147 + description?: string; 148 + author?: string; 149 + siteName?: string; 150 + imageUrl?: string; 151 + type?: string; 152 + createdAt: string; 153 + updatedAt: string; 154 + libraryCount: number; 155 + } 156 + 157 + export interface GetCollectionPageResponse { 158 + id: string; 159 + name: string; 160 + description?: string; 161 + author: { 162 + id: string; 163 + name: string; 164 + handle: string; 165 + avatarUrl?: string; 166 + }; 167 + urlCards: CollectionPageUrlCard[]; 168 + pagination: Pagination; 169 + sorting: Sorting; 170 + }