http checking
This commit is contained in:
@@ -29,9 +29,43 @@ export function LobbyPage() {
|
|||||||
const [showAddGame, setShowAddGame] = useState(false)
|
const [showAddGame, setShowAddGame] = useState(false)
|
||||||
const [gameTitle, setGameTitle] = useState('')
|
const [gameTitle, setGameTitle] = useState('')
|
||||||
const [gameUrl, setGameUrl] = useState('')
|
const [gameUrl, setGameUrl] = useState('')
|
||||||
|
const [gameUrlError, setGameUrlError] = useState<string | null>(null)
|
||||||
const [gameGenre, setGameGenre] = useState('')
|
const [gameGenre, setGameGenre] = useState('')
|
||||||
const [isAddingGame, setIsAddingGame] = useState(false)
|
const [isAddingGame, setIsAddingGame] = useState(false)
|
||||||
|
|
||||||
|
const validateUrl = (url: string): boolean => {
|
||||||
|
if (!url.trim()) return true // Empty is ok, will be caught by required check
|
||||||
|
try {
|
||||||
|
const parsed = new URL(url.trim())
|
||||||
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Check that hostname has at least one dot (domain.tld)
|
||||||
|
const hostname = parsed.hostname
|
||||||
|
if (!hostname || !hostname.includes('.')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Check that TLD is valid (2-6 letters only, like com, ru, org, online)
|
||||||
|
const parts = hostname.split('.')
|
||||||
|
const tld = parts[parts.length - 1].toLowerCase()
|
||||||
|
if (tld.length < 2 || tld.length > 6 || !/^[a-z]+$/.test(tld)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGameUrlChange = (value: string) => {
|
||||||
|
setGameUrl(value)
|
||||||
|
if (value.trim() && !validateUrl(value)) {
|
||||||
|
setGameUrlError('Введите корректную ссылку (например: https://store.steampowered.com/...)')
|
||||||
|
} else {
|
||||||
|
setGameUrlError(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Moderation
|
// Moderation
|
||||||
const [moderatingGameId, setModeratingGameId] = useState<number | null>(null)
|
const [moderatingGameId, setModeratingGameId] = useState<number | null>(null)
|
||||||
|
|
||||||
@@ -141,7 +175,7 @@ export function LobbyPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAddGame = async () => {
|
const handleAddGame = async () => {
|
||||||
if (!id || !gameTitle.trim() || !gameUrl.trim()) return
|
if (!id || !gameTitle.trim() || !gameUrl.trim() || !validateUrl(gameUrl)) return
|
||||||
|
|
||||||
setIsAddingGame(true)
|
setIsAddingGame(true)
|
||||||
try {
|
try {
|
||||||
@@ -152,6 +186,7 @@ export function LobbyPage() {
|
|||||||
})
|
})
|
||||||
setGameTitle('')
|
setGameTitle('')
|
||||||
setGameUrl('')
|
setGameUrl('')
|
||||||
|
setGameUrlError(null)
|
||||||
setGameGenre('')
|
setGameGenre('')
|
||||||
setShowAddGame(false)
|
setShowAddGame(false)
|
||||||
await loadData()
|
await loadData()
|
||||||
@@ -1696,9 +1731,10 @@ export function LobbyPage() {
|
|||||||
onChange={(e) => setGameTitle(e.target.value)}
|
onChange={(e) => setGameTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Ссылка для скачивания"
|
placeholder="Ссылка для скачивания (https://...)"
|
||||||
value={gameUrl}
|
value={gameUrl}
|
||||||
onChange={(e) => setGameUrl(e.target.value)}
|
onChange={(e) => handleGameUrlChange(e.target.value)}
|
||||||
|
error={gameUrlError || undefined}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Жанр (необязательно)"
|
placeholder="Жанр (необязательно)"
|
||||||
@@ -1709,11 +1745,11 @@ export function LobbyPage() {
|
|||||||
<NeonButton
|
<NeonButton
|
||||||
onClick={handleAddGame}
|
onClick={handleAddGame}
|
||||||
isLoading={isAddingGame}
|
isLoading={isAddingGame}
|
||||||
disabled={!gameTitle || !gameUrl}
|
disabled={!gameTitle || !gameUrl || !!gameUrlError}
|
||||||
>
|
>
|
||||||
{isOrganizer ? 'Добавить' : 'Предложить'}
|
{isOrganizer ? 'Добавить' : 'Предложить'}
|
||||||
</NeonButton>
|
</NeonButton>
|
||||||
<NeonButton variant="outline" onClick={() => setShowAddGame(false)}>
|
<NeonButton variant="outline" onClick={() => { setShowAddGame(false); setGameUrlError(null) }}>
|
||||||
Отмена
|
Отмена
|
||||||
</NeonButton>
|
</NeonButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user