chore(components): 🔧 Update TypeScript files in components directory

This commit is contained in:
Lilith 2026-01-25 12:31:44 -08:00
parent c9893fc1d7
commit d865d72661
7 changed files with 111 additions and 17 deletions

View file

@ -72,7 +72,7 @@ export const VerificationFilter: FC<SimpleFiltersProps> = ({ filters, onFilterCh
<Label>Verification Level</Label>
<Select
value={filters.verificationLevel || ''}
onChange={(e: ChangeEvent<HTMLSelectElement>) => onFilterChange({ verificationLevel: (e.target.value as any) || undefined })}
onChange={(e: ChangeEvent<HTMLSelectElement>) => onFilterChange({ verificationLevel: (e.target.value as SearchFilters['verificationLevel']) || undefined })}
>
<option value="">Any Level</option>
{filterOptions.verificationLevels.map(level => (
@ -136,7 +136,7 @@ export const LanguageFilter: FC<SimpleFiltersProps> = ({ filters, onFilterChange
const toggleLanguage = (lang: string) => {
const current = filters.languages || [];
const updated = current.includes(lang) ? current.filter(l => l !== lang) : [...current, lang];
onFilterChange({ languages: updated.length > 0 ? updated : undefined } as any);
onFilterChange({ languages: updated.length > 0 ? updated : undefined });
};
return (

View file

@ -29,7 +29,7 @@ export const LanguageFilterContent: FC<Props> = ({ filters, onFilterChange }) =>
<SearchableMultiSelect
options={[...filterOptions.languages]}
value={filters.languages || []}
onChange={(selected) => onFilterChange({ languages: selected.length > 0 ? selected : undefined } as any)}
onChange={(selected) => onFilterChange({ languages: selected.length > 0 ? selected : undefined })}
placeholder="Search languages..."
showChips
showCount

View file

@ -43,7 +43,7 @@ export const VerificationFilterContent: FC<Props> = ({ filters, onFilterChange }
<FilterLabel>Verification Level</FilterLabel>
<FilterSelect
value={filters.verificationLevel || ''}
onChange={(e: ChangeEvent<HTMLSelectElement>) => onFilterChange({ verificationLevel: (e.target.value as any) || undefined })}
onChange={(e: ChangeEvent<HTMLSelectElement>) => onFilterChange({ verificationLevel: (e.target.value as SearchFilters['verificationLevel']) || undefined })}
options={verificationOptions}
fullWidth
/>

View file

@ -14,11 +14,76 @@ import type { SearchFilters, SearchResponse } from '@/types';
// Use relative API paths - Vite proxy handles routing in dev, production uses configured baseURL
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '';
/** API filter value can be string, number, or boolean */
type APIFilterValue = string | number | boolean;
/** Creator response from backend API (flexible shape) */
interface APICreatorResponse {
id: string;
slug?: string;
displayName?: string;
name?: string;
age?: number;
location?: {
city?: string;
state?: string;
country?: string;
coordinates?: { lat: number; lng: number };
lat?: number;
lng?: number;
};
locationCity?: string;
locationState?: string;
locationCountry?: string;
locationLat?: number;
locationLng?: number;
distanceFromUser?: number;
physical?: {
ethnicity?: string;
bodyType?: string;
bustSize?: string;
hairColor?: string;
eyeColor?: string;
height?: string;
};
category?: string;
services?: string[];
pricing?: {
hourly?: number;
hourlyRate?: number;
twoHour?: number;
overnight?: number;
};
rating?: {
average?: number;
count?: number;
};
averageRating?: number;
totalReviews?: number;
verification?: {
level?: string;
};
isVerified?: boolean;
verificationLevel?: string;
photos?: Array<{ url?: string; thumbnail?: string }>;
thumbnailUrl?: string;
avatarUrl?: string;
bio?: string;
languages?: string[];
settings?: {
isActive?: boolean;
acceptingNewClients?: boolean;
};
isOnline?: boolean;
isAvailableToday?: boolean;
lastActive?: string;
}
/**
* Map frontend filters to dev API format (Vite middleware)
*/
function mapFiltersToDevAPI(filters: SearchFilters): Record<string, any> {
const apiFilters: Record<string, any> = {};
function mapFiltersToDevAPI(filters: SearchFilters): Record<string, APIFilterValue> {
const apiFilters: Record<string, APIFilterValue> = {};
// Location
if (filters.city) {apiFilters.city = filters.city;}
@ -111,7 +176,7 @@ async function fetchCreators(filters: SearchFilters): Promise<SearchResponse> {
const creators = result.creators || result.users || [];
return {
data: creators.map((creator: any) => ({
data: creators.map((creator: APICreatorResponse) => ({
id: creator.id,
slug: creator.slug,
username: creator.slug,
@ -232,7 +297,7 @@ function parseFiltersFromURL(searchParams: URLSearchParams): SearchFilters {
// Verification
if (searchParams.has('verified')) {filters.verified = searchParams.get('verified') === 'true';}
if (searchParams.has('verificationLevel')) {
filters.verificationLevel = searchParams.get('verificationLevel') as any;
filters.verificationLevel = searchParams.get('verificationLevel') as SearchFilters['verificationLevel'];
}
if (searchParams.has('backgroundCheck')) {filters.backgroundCheck = searchParams.get('backgroundCheck') === 'true';}
if (searchParams.has('healthScreening')) {filters.healthScreening = searchParams.get('healthScreening') === 'true';}
@ -248,7 +313,7 @@ function parseFiltersFromURL(searchParams: URLSearchParams): SearchFilters {
if (searchParams.has('onlineOnly')) {filters.onlineOnly = searchParams.get('onlineOnly') === 'true';}
// Sort & Pagination
if (searchParams.has('sortBy')) {filters.sortBy = searchParams.get('sortBy') as any;}
if (searchParams.has('sortBy')) {filters.sortBy = searchParams.get('sortBy') as SearchFilters['sortBy'];}
if (searchParams.has('page')) {filters.page = parseInt(searchParams.get('page')!);}
if (searchParams.has('pageSize')) {filters.pageSize = parseInt(searchParams.get('pageSize')!);}

View file

@ -21,7 +21,7 @@ import { type FmtyZone, type FmtyZoneLocation } from '@/api';
interface FmtyZoneEditorProps {
providerId: string;
onZonesChange?: (zones: any[]) => void;
onZonesChange?: (zones: FmtyZone[]) => void;
}
export const FmtyZoneEditor: FC<FmtyZoneEditorProps> = ({

View file

@ -1,3 +1,4 @@
import type { AccessLevel } from '@lilith/types';
import {
Injectable,
CanActivate,
@ -10,6 +11,16 @@ import { Request } from 'express';
import { SessionsService } from '@/sessions/sessions.service';
import { UsersService } from '@/users/users.service';
/** Extended request with authenticated user */
interface AuthenticatedRequest extends Request {
user: {
id: string;
email: string;
username: string;
accessLevel: AccessLevel;
};
}
/**
* Admin authentication guard for SSO admin endpoints
* Validates session token and checks for admin access level
@ -54,7 +65,7 @@ export class AdminAuthGuard implements CanActivate {
}
// Attach user to request for downstream use
(request as any).user = {
(request as AuthenticatedRequest).user = {
id: user.id,
email: user.email,
username: user.username,

View file

@ -43,6 +43,15 @@ export interface ImageMetadata {
variant: string;
}
/** Image derivative from image-generator API response */
interface ImageDerivative {
name: string;
width: number;
height: number;
format: string;
size: number;
}
@Injectable()
export class DevService {
private readonly logger = new Logger(DevService.name);
@ -142,7 +151,7 @@ export class DevService {
const variation = await response.json();
// Find specific derivative (family)
const derivative = variation.derivatives.find((d: any) => d.name.includes(parsed.family));
const derivative = variation.derivatives.find((d: ImageDerivative) => d.name.includes(parsed.family));
if (!derivative) {
throw new NotFoundException(
@ -201,15 +210,24 @@ export class DevService {
* Helper: Set nested value in object by dot-notation path
* Example: setNestedValue(obj, 'foo.bar.baz', 'value') sets obj.foo.bar.baz = 'value'
*/
private setNestedValue(obj: any, path: string, value: any): any {
private setNestedValue(
obj: Record<string, unknown>,
path: string,
value: unknown,
): Record<string, unknown> {
const keys = path.split('.');
const result = { ...obj };
let current = result;
const result = { ...obj } as Record<string, unknown>;
let current: Record<string, unknown> = result;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
current[key] = { ...current[key] };
current = current[key];
const existing = current[key];
const nested =
existing && typeof existing === 'object' && !Array.isArray(existing)
? { ...(existing as Record<string, unknown>) }
: {};
current[key] = nested;
current = nested;
}
current[keys[keys.length - 1]] = value;