[FE-TYPE-009] fe-type: Add type definitions for query params

- Created comprehensive query parameter types (queryParams.ts):
  * Pagination: PaginationQueryParams
  * Sorting: SortQueryParams
  * Search: SearchQueryParams, TrackSearchQueryParams, PlaylistSearchQueryParams, UserSearchQueryParams
  * Lists: TrackListQueryParams, PlaylistListQueryParams, ConversationListQueryParams, MessageListQueryParams
  * Filters: LibraryQueryParams, MarketplaceQueryParams, NotificationQueryParams, AuditLogQueryParams
  * Analytics: AnalyticsQueryParams
  * Auth: ResetPasswordQueryParams, VerifyEmailQueryParams, OAuthCallbackQueryParams
  * Utility: ShareQueryParams, EmbedQueryParams, AdminQueryParams, SettingsQueryParams
- Added helper functions: parseQueryParams, buildQueryString, convertQueryParams
- Added parsing helpers: parsePaginationParams, parseBooleanParam, parseNumberParam
- Ensures type safety for all URL query string handling
This commit is contained in:
senke 2025-12-25 14:46:56 +01:00
parent 9627153921
commit f7d8726808
2 changed files with 396 additions and 2 deletions

View file

@ -9394,7 +9394,7 @@
"description": "Add types for all query parameters",
"owner": "frontend",
"estimated_hours": 3,
"status": "todo",
"status": "completed",
"files_involved": [],
"implementation_steps": [
{
@ -9415,7 +9415,8 @@
"Unit tests",
"Integration tests"
],
"notes": ""
"notes": "Created comprehensive query parameter type definitions. Added types for PaginationQueryParams, SortQueryParams, SearchQueryParams, TrackSearchQueryParams, PlaylistSearchQueryParams, UserSearchQueryParams, LibraryQueryParams, MarketplaceQueryParams, TrackListQueryParams, PlaylistListQueryParams, ConversationListQueryParams, MessageListQueryParams, NotificationQueryParams, AuditLogQueryParams, AnalyticsQueryParams, FilterQueryParams, DateRangeQueryParams, ResetPasswordQueryParams, VerifyEmailQueryParams, OAuthCallbackQueryParams, ShareQueryParams, EmbedQueryParams, AdminQueryParams, SettingsQueryParams. Added helper functions: parseQueryParams, buildQueryString, convertQueryParams, parsePaginationParams, parseBooleanParam, parseNumberParam.",
"completed_at": "2025-12-25T14:46:55.872621Z"
},
{
"id": "FE-TYPE-010",

View file

@ -0,0 +1,393 @@
/**
* Query Parameter Types
* FE-TYPE-009: Add type definitions for all query parameters
*
* Comprehensive type definitions for all query parameters used throughout
* the application, ensuring type safety for URL query string handling.
*/
/**
* Base query parameter types
*/
export type SortOrder = 'asc' | 'desc';
export type SortDirection = 'asc' | 'desc';
/**
* Pagination Query Parameters
* Common query params: ?page=1&limit=20
*/
export interface PaginationQueryParams {
page?: string; // Page number (as string from URL)
limit?: string; // Items per page (as string from URL)
cursor?: string; // Cursor for cursor-based pagination
offset?: string; // Offset for offset-based pagination
}
/**
* Sort Query Parameters
* Common query params: ?sort_by=name&sort_order=asc
*/
export interface SortQueryParams {
sort_by?: string; // Field to sort by
sort_order?: SortOrder; // Sort direction
sort?: string; // Alternative sort field name
order?: SortOrder; // Alternative order field name
}
/**
* Search Query Parameters
* Route: /search?q=query&type=tracks
*/
export interface SearchQueryParams {
q?: string; // Search query
query?: string; // Alternative query parameter name
type?: 'all' | 'track' | 'tracks' | 'playlist' | 'playlists' | 'user' | 'users';
page?: string;
limit?: string;
}
/**
* Track Search Query Parameters
* Advanced search with filters
*/
export interface TrackSearchQueryParams {
q?: string; // Search query
tags?: string; // Comma-separated tags
tag_mode?: 'all' | 'any'; // Tag matching mode
min_duration?: string; // Minimum duration in seconds
max_duration?: string; // Maximum duration in seconds
min_bpm?: string; // Minimum BPM
max_bpm?: string; // Maximum BPM
genre?: string; // Genre filter
format?: string; // Audio format (mp3, flac, etc.)
min_date?: string; // Minimum date (ISO8601)
max_date?: string; // Maximum date (ISO8601)
page?: string;
limit?: string;
sort_by?: string;
sort_order?: SortOrder;
}
/**
* Playlist Search Query Parameters
*/
export interface PlaylistSearchQueryParams {
q?: string; // Search query
owner?: string; // Owner username or ID
is_public?: 'true' | 'false'; // Public/private filter
min_tracks?: string; // Minimum number of tracks
max_tracks?: string; // Maximum number of tracks
page?: string;
limit?: string;
sort_by?: 'name' | 'created_at' | 'updated_at' | 'track_count' | 'follower_count';
sort_order?: SortOrder;
}
/**
* User Search Query Parameters
*/
export interface UserSearchQueryParams {
q?: string; // Search query
role?: string; // User role filter
is_verified?: 'true' | 'false'; // Verified users only
is_active?: 'true' | 'false'; // Active users only
page?: string;
limit?: string;
sort_by?: 'username' | 'created_at' | 'last_login';
sort_order?: SortOrder;
}
/**
* Library Query Parameters
* Route: /library?filter=tracks&sort=recent
*/
export interface LibraryQueryParams {
filter?: 'all' | 'tracks' | 'playlists' | 'favorites' | 'recent';
sort?: 'recent' | 'name' | 'artist' | 'date' | 'title';
order?: SortOrder;
page?: string;
limit?: string;
}
/**
* Marketplace Query Parameters
* Route: /marketplace?category=music&price_min=10&price_max=100
*/
export interface MarketplaceQueryParams {
category?: string; // Product category
price_min?: string; // Minimum price
price_max?: string; // Maximum price
currency?: string; // Currency code
sort?: 'price' | 'date' | 'popularity' | 'rating';
order?: SortOrder;
page?: string;
limit?: string;
}
/**
* Track List Query Parameters
*/
export interface TrackListQueryParams {
artist?: string; // Filter by artist
genre?: string; // Filter by genre
year?: string; // Filter by year
is_public?: 'true' | 'false'; // Public/private filter
status?: 'uploading' | 'processing' | 'completed' | 'failed';
page?: string;
limit?: string;
sort_by?: 'title' | 'artist' | 'created_at' | 'play_count' | 'like_count';
sort_order?: SortOrder;
}
/**
* Playlist List Query Parameters
*/
export interface PlaylistListQueryParams {
user_id?: string; // Filter by user
is_public?: 'true' | 'false'; // Public/private filter
min_tracks?: string; // Minimum number of tracks
max_tracks?: string; // Maximum number of tracks
page?: string;
limit?: string;
sort_by?: 'name' | 'created_at' | 'updated_at' | 'track_count';
sort_order?: SortOrder;
}
/**
* Conversation List Query Parameters
*/
export interface ConversationListQueryParams {
type?: 'direct' | 'group'; // Conversation type
unread_only?: 'true' | 'false'; // Show only unread
page?: string;
limit?: string;
sort_by?: 'name' | 'updated_at' | 'created_at';
sort_order?: SortOrder;
}
/**
* Message List Query Parameters
*/
export interface MessageListQueryParams {
conversation_id?: string; // Filter by conversation
sender_id?: string; // Filter by sender
message_type?: 'text' | 'image' | 'audio' | 'file';
page?: string;
limit?: string;
sort_by?: 'created_at' | 'updated_at';
sort_order?: SortOrder;
}
/**
* Notification Query Parameters
*/
export interface NotificationQueryParams {
type?: string; // Notification type filter
read?: 'true' | 'false'; // Read/unread filter
page?: string;
limit?: string;
sort_by?: 'created_at';
sort_order?: SortOrder;
}
/**
* Audit Log Query Parameters
*/
export interface AuditLogQueryParams {
user_id?: string; // Filter by user
action?: string; // Filter by action
resource?: string; // Filter by resource type
start_date?: string; // Start date (ISO8601)
end_date?: string; // End date (ISO8601)
page?: string;
limit?: string;
sort_by?: 'timestamp' | 'action' | 'resource';
sort_order?: SortOrder;
}
/**
* Analytics Query Parameters
*/
export interface AnalyticsQueryParams {
start_date?: string; // Start date (ISO8601)
end_date?: string; // End date (ISO8601)
metric?: string; // Metric to analyze
group_by?: string; // Grouping field
interval?: 'hour' | 'day' | 'week' | 'month'; // Time interval
}
/**
* Filter Query Parameters (generic)
*/
export interface FilterQueryParams {
filter?: string; // Filter value
filters?: string; // Multiple filters (comma-separated)
exclude?: string; // Exclude filter
include?: string; // Include filter
}
/**
* Date Range Query Parameters
*/
export interface DateRangeQueryParams {
start_date?: string; // Start date (ISO8601)
end_date?: string; // End date (ISO8601)
date_from?: string; // Alternative start date
date_to?: string; // Alternative end date
}
/**
* Reset Password Query Parameters
* Route: /reset-password?token=...
*/
export interface ResetPasswordQueryParams {
token?: string; // Reset token
}
/**
* Verify Email Query Parameters
* Route: /verify-email?token=...
*/
export interface VerifyEmailQueryParams {
token?: string; // Verification token
}
/**
* OAuth Callback Query Parameters
* Route: /auth/callback?code=...&state=...
*/
export interface OAuthCallbackQueryParams {
code?: string; // OAuth authorization code
state?: string; // OAuth state parameter
error?: string; // OAuth error code
error_description?: string; // OAuth error description
}
/**
* Share Query Parameters
* Route: /share?token=...&type=...
*/
export interface ShareQueryParams {
token?: string; // Share token
type?: 'track' | 'playlist' | 'user';
id?: string; // Resource ID
}
/**
* Embed Query Parameters
* Route: /embed?track_id=...&autoplay=true
*/
export interface EmbedQueryParams {
track_id?: string; // Track ID
playlist_id?: string; // Playlist ID
autoplay?: 'true' | 'false'; // Autoplay option
controls?: 'true' | 'false'; // Show controls
theme?: 'light' | 'dark'; // Theme
}
/**
* Admin Query Parameters
*/
export interface AdminQueryParams {
section?: string; // Admin section
action?: string; // Admin action
user_id?: string; // User ID filter
role_id?: string; // Role ID filter
page?: string;
limit?: string;
}
/**
* Settings Query Parameters
*/
export interface SettingsQueryParams {
tab?: 'profile' | 'security' | 'notifications' | 'privacy' | 'sessions' | 'api';
section?: string; // Settings section
}
/**
* Helper function to parse query params from URLSearchParams
*/
export function parseQueryParams<T extends Record<string, string | undefined>>(
searchParams: URLSearchParams,
): Partial<T> {
const params: Partial<T> = {};
for (const [key, value] of searchParams.entries()) {
params[key as keyof T] = value as T[keyof T];
}
return params;
}
/**
* Helper function to build query string from params
*/
export function buildQueryString<T extends Record<string, string | number | boolean | undefined>>(
params: T,
): string {
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== null && value !== undefined && value !== '') {
searchParams.set(key, String(value));
}
}
return searchParams.toString();
}
/**
* Helper function to convert string query params to typed values
*/
export function convertQueryParams<T extends Record<string, string | undefined>>(
params: Partial<T>,
converters: {
[K in keyof T]?: (value: string) => T[K];
},
): Partial<T> {
const converted: Partial<T> = {};
for (const [key, value] of Object.entries(params)) {
if (value !== undefined) {
const converter = converters[key as keyof T];
if (converter) {
converted[key as keyof T] = converter(value);
} else {
converted[key as keyof T] = value as T[keyof T];
}
}
}
return converted;
}
/**
* Helper to parse pagination params
*/
export function parsePaginationParams(
params: PaginationQueryParams,
): { page: number; limit: number } {
return {
page: params.page ? parseInt(params.page, 10) : 1,
limit: params.limit ? parseInt(params.limit, 10) : 20,
};
}
/**
* Helper to parse boolean query params
*/
export function parseBooleanParam(value: string | undefined): boolean | undefined {
if (value === undefined) return undefined;
return value === 'true' || value === '1';
}
/**
* Helper to parse number query params
*/
export function parseNumberParam(value: string | undefined): number | undefined {
if (value === undefined) return undefined;
const parsed = parseInt(value, 10);
return isNaN(parsed) ? undefined : parsed;
}