mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 09:51:13 -05:00
This commit introduces several improvements: - Enhances `RideModelCard` by safely accessing and displaying ride count and image data, preventing potential errors. - Refactors `useEntityVersions` and `useSearch` hooks to use `useCallback` and improve performance and prevent race conditions. - Introduces a `MAX_MAP_SIZE` and cleanup mechanism for the rate limiting map in `detect-location` Supabase function to prevent memory leaks. - Adds robust error handling and cleanup for image uploads in `uploadPendingImages`. - Modifies `ManufacturerModels` to correctly map and display ride counts. - Includes error handling for topological sort in `process-selective-approval` Supabase function. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 39bb006b-d046-477f-a1f9-b7821836f3a1 Replit-Commit-Checkpoint-Type: intermediate_checkpoint
80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import { supabase } from '@/integrations/supabase/client';
|
|
import { usernameSchema } from '@/lib/validation';
|
|
import { useDebounce } from './useDebounce';
|
|
|
|
export type UsernameValidationState = {
|
|
isValid: boolean;
|
|
isAvailable: boolean | null;
|
|
isChecking: boolean;
|
|
error: string | null;
|
|
};
|
|
|
|
export function useUsernameValidation(username: string, currentUsername?: string) {
|
|
const [state, setState] = useState<UsernameValidationState>({
|
|
isValid: false,
|
|
isAvailable: null,
|
|
isChecking: false,
|
|
error: null,
|
|
});
|
|
|
|
const debouncedUsername = useDebounce(username, 500);
|
|
|
|
const checkUsernameAvailability = useCallback(async (normalizedUsername: string) => {
|
|
try {
|
|
const { data, error } = await supabase
|
|
.from('profiles')
|
|
.select('username')
|
|
.eq('username', normalizedUsername)
|
|
.maybeSingle();
|
|
|
|
if (error) throw error;
|
|
|
|
const isAvailable = !data;
|
|
setState({
|
|
isValid: isAvailable,
|
|
isAvailable,
|
|
isChecking: false,
|
|
error: isAvailable ? null : 'Username is already taken',
|
|
});
|
|
} catch (error) {
|
|
setState({
|
|
isValid: false,
|
|
isAvailable: null,
|
|
isChecking: false,
|
|
error: 'Error checking username availability',
|
|
});
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!debouncedUsername || debouncedUsername === currentUsername) {
|
|
setState({
|
|
isValid: debouncedUsername === currentUsername,
|
|
isAvailable: null,
|
|
isChecking: false,
|
|
error: null,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Validate format first
|
|
const validation = usernameSchema.safeParse(debouncedUsername);
|
|
if (!validation.success) {
|
|
setState({
|
|
isValid: false,
|
|
isAvailable: null,
|
|
isChecking: false,
|
|
error: validation.error.issues[0].message,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Check availability
|
|
setState(prev => ({ ...prev, isChecking: true, error: null }));
|
|
|
|
checkUsernameAvailability(validation.data);
|
|
}, [debouncedUsername, currentUsername, checkUsernameAvailability]);
|
|
|
|
return state;
|
|
} |