|
|
@ -1,8 +1,9 @@ |
|
|
|
import { useState } from 'react'; |
|
|
|
import { useEffect, useState } from 'react'; |
|
|
|
import type { AllowedProfileVisibility } from '../../api/user'; |
|
|
|
import type { AllowedProfileVisibility } from '../../api/user'; |
|
|
|
import { httpGet, httpPost } from '../../lib/http'; |
|
|
|
import { httpGet, httpPost } from '../../lib/http'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { CheckIcon, Loader2, X, XCircle } from 'lucide-react'; |
|
|
|
import { CheckIcon, Loader2, X, XCircle } from 'lucide-react'; |
|
|
|
|
|
|
|
import { useDebounceValue } from '../../hooks/use-debounce.ts'; |
|
|
|
|
|
|
|
|
|
|
|
type ProfileUsernameProps = { |
|
|
|
type ProfileUsernameProps = { |
|
|
|
username: string; |
|
|
|
username: string; |
|
|
@ -17,6 +18,11 @@ export function ProfileUsername(props: ProfileUsernameProps) { |
|
|
|
const toast = useToast(); |
|
|
|
const toast = useToast(); |
|
|
|
const [isLoading, setIsLoading] = useState(false); |
|
|
|
const [isLoading, setIsLoading] = useState(false); |
|
|
|
const [isUnique, setIsUnique] = useState<boolean | null>(null); |
|
|
|
const [isUnique, setIsUnique] = useState<boolean | null>(null); |
|
|
|
|
|
|
|
const debouncedUsername = useDebounceValue(username, 500); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
checkIsUnique(debouncedUsername).then(); |
|
|
|
|
|
|
|
}, [debouncedUsername]); |
|
|
|
|
|
|
|
|
|
|
|
const checkIsUnique = async (username: string) => { |
|
|
|
const checkIsUnique = async (username: string) => { |
|
|
|
if (isLoading || username.length < 3) { |
|
|
|
if (isLoading || username.length < 3) { |
|
|
@ -66,7 +72,22 @@ export function ProfileUsername(props: ProfileUsernameProps) { |
|
|
|
spellCheck={false} |
|
|
|
spellCheck={false} |
|
|
|
value={username} |
|
|
|
value={username} |
|
|
|
title="Username must be at least 3 characters long and can only contain letters, numbers, and underscores" |
|
|
|
title="Username must be at least 3 characters long and can only contain letters, numbers, and underscores" |
|
|
|
onChange={(e) => setUsername((e.target as HTMLInputElement).value)} |
|
|
|
onKeyDown={(e) => { |
|
|
|
|
|
|
|
// only allow letters, numbers
|
|
|
|
|
|
|
|
const keyCode = e.key; |
|
|
|
|
|
|
|
const validKey = /^[a-zA-Z0-9]*$/.test(keyCode); |
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
!validKey && |
|
|
|
|
|
|
|
!['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight'].includes( |
|
|
|
|
|
|
|
keyCode, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
onChange={(e) => { |
|
|
|
|
|
|
|
setUsername((e.target as HTMLInputElement).value.toLowerCase()); |
|
|
|
|
|
|
|
}} |
|
|
|
onBlur={(e) => checkIsUnique((e.target as HTMLInputElement).value)} |
|
|
|
onBlur={(e) => checkIsUnique((e.target as HTMLInputElement).value)} |
|
|
|
required={profileVisibility === 'public'} |
|
|
|
required={profileVisibility === 'public'} |
|
|
|
/> |
|
|
|
/> |
|
|
|