Первоначальная версия VidConf
This commit is contained in:
118
frontend/src/pages/LobbyPage.tsx
Normal file
118
frontend/src/pages/LobbyPage.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Calendar, Link2, User, Video } from 'lucide-react'
|
||||
import { ShellTopbar } from '@/components/layout/ShellTopbar'
|
||||
import { LogoMedallion } from '@/components/ui/LogoMark'
|
||||
import { createConference } from '@/api/conferences'
|
||||
import { useToast } from '@/components/ui/ToastProvider'
|
||||
import '@/styles/lobby.css'
|
||||
|
||||
/**
|
||||
* Лобби — «хаб действий» (см. design/mockups/lobby.html).
|
||||
*
|
||||
* Предустановленных переговорных комнат больше нет: конференции создаются
|
||||
* динамически. Мозаика из 4 плиток — единственный вход в остальные сценарии:
|
||||
* мгновенное создание, календарь плановых конференций, вход по ссылке/номеру,
|
||||
* «Мои конференции».
|
||||
*
|
||||
* Отклонение от макета: топбар здесь — переиспользуемый `ShellTopbar` (прямые
|
||||
* ссылки Лобби/Календарь/Админка + пилюля пользователя), а не бургер-меню из
|
||||
* lobby.html. `ShellTopbar` — общий компонент светлой оболочки (используется
|
||||
* также в календаре/админке), поэтому бургер-меню из макета здесь
|
||||
* сознательно не воспроизводится.
|
||||
*/
|
||||
export function LobbyPage() {
|
||||
const navigate = useNavigate()
|
||||
const toast = useToast()
|
||||
const [creating, setCreating] = useState(false)
|
||||
|
||||
async function handleCreate() {
|
||||
if (creating) return
|
||||
setCreating(true)
|
||||
try {
|
||||
const conference = await createConference({})
|
||||
if (!conference.join) {
|
||||
toast.show('Не удалось создать конференцию. Попробуйте ещё раз', 'error')
|
||||
return
|
||||
}
|
||||
navigate(`/room/${conference.slug}`, {
|
||||
state: {
|
||||
livekitUrl: conference.join.livekit_url,
|
||||
token: conference.join.token,
|
||||
roomName: conference.join.room_name,
|
||||
conferenceId: conference.join.conference_id,
|
||||
chatEnabled: conference.join.chat_enabled,
|
||||
number: conference.number,
|
||||
slug: conference.slug,
|
||||
},
|
||||
})
|
||||
} catch {
|
||||
toast.show('Не удалось создать конференцию. Попробуйте ещё раз', 'error')
|
||||
} finally {
|
||||
setCreating(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="lobby-shell">
|
||||
<ShellTopbar />
|
||||
<main className="hub-main">
|
||||
<div className="hub-wrap">
|
||||
<div className="hub-intro">
|
||||
<p className="eyebrow">[ ДОБРО ПОЖАЛОВАТЬ В VIDCONF ]</p>
|
||||
<h1>Что делаем сегодня?</h1>
|
||||
</div>
|
||||
|
||||
<div className="hub">
|
||||
<button
|
||||
type="button"
|
||||
className="action action--create"
|
||||
onClick={handleCreate}
|
||||
disabled={creating}
|
||||
aria-busy={creating}
|
||||
>
|
||||
<span className="action-icon" aria-hidden="true">
|
||||
<Video className="icon" aria-hidden="true" />
|
||||
</span>
|
||||
<h2 className="action-title">Создать</h2>
|
||||
<p className="action-object">конференцию</p>
|
||||
<p className="action-note">{creating ? 'Создаём…' : 'начнётся сразу — вы первый участник'}</p>
|
||||
</button>
|
||||
|
||||
<button type="button" className="action action--calendar" onClick={() => navigate('/calendar')}>
|
||||
<span className="action-icon" aria-hidden="true">
|
||||
<Calendar className="icon" aria-hidden="true" />
|
||||
</span>
|
||||
<h2 className="action-title">Календарь</h2>
|
||||
<p className="action-object">конференций</p>
|
||||
<p className="action-note">запланировать · закрепить · повторять</p>
|
||||
</button>
|
||||
|
||||
<button type="button" className="action action--join" onClick={() => navigate('/join')}>
|
||||
<span className="action-icon" aria-hidden="true">
|
||||
<Link2 className="icon" aria-hidden="true" />
|
||||
</span>
|
||||
<h2 className="action-title">Подключиться</h2>
|
||||
<p className="action-object">к конференции</p>
|
||||
<p className="action-note">по ссылке или номеру</p>
|
||||
</button>
|
||||
|
||||
<button type="button" className="action action--mine" onClick={() => navigate('/my-conferences')}>
|
||||
<span className="action-icon" aria-hidden="true">
|
||||
<User className="icon" aria-hidden="true" />
|
||||
</span>
|
||||
<h2 className="action-title">Мои</h2>
|
||||
<p className="action-object">конференции</p>
|
||||
<p className="action-note">закреплённые и предстоящие</p>
|
||||
</button>
|
||||
|
||||
<div className="hub-logo" aria-hidden="true">
|
||||
<LogoMedallion className="logo-mark" />
|
||||
<span className="logo-word">VidConf</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user