157 lines
4.4 KiB
React
157 lines
4.4 KiB
React
|
|
import React, { useState, useEffect } from 'react'
|
||
|
|
import { useAuth } from './auth/AuthContext'
|
||
|
|
import './BoardJoinPreview.css'
|
||
|
|
|
||
|
|
function BoardJoinPreview({ inviteToken, onNavigate }) {
|
||
|
|
const { authFetch, user } = useAuth()
|
||
|
|
const [board, setBoard] = useState(null)
|
||
|
|
const [loading, setLoading] = useState(true)
|
||
|
|
const [joining, setJoining] = useState(false)
|
||
|
|
const [error, setError] = useState('')
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (inviteToken) {
|
||
|
|
fetchBoardInfo()
|
||
|
|
}
|
||
|
|
}, [inviteToken])
|
||
|
|
|
||
|
|
const fetchBoardInfo = async () => {
|
||
|
|
try {
|
||
|
|
const res = await authFetch(`/api/wishlist/invite/${inviteToken}`)
|
||
|
|
|
||
|
|
if (res.ok) {
|
||
|
|
setBoard(await res.json())
|
||
|
|
} else {
|
||
|
|
const err = await res.json()
|
||
|
|
setError(err.error || 'Ссылка недействительна или устарела')
|
||
|
|
}
|
||
|
|
} catch (err) {
|
||
|
|
setError('Ошибка загрузки')
|
||
|
|
} finally {
|
||
|
|
setLoading(false)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleJoin = async () => {
|
||
|
|
if (!user) {
|
||
|
|
// Сохраняем токен для возврата после логина
|
||
|
|
sessionStorage.setItem('pendingInviteToken', inviteToken)
|
||
|
|
onNavigate('login')
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
setJoining(true)
|
||
|
|
setError('')
|
||
|
|
|
||
|
|
try {
|
||
|
|
const res = await authFetch(`/api/wishlist/invite/${inviteToken}/join`, {
|
||
|
|
method: 'POST'
|
||
|
|
})
|
||
|
|
|
||
|
|
if (res.ok) {
|
||
|
|
const data = await res.json()
|
||
|
|
// Переходим на доску
|
||
|
|
onNavigate('wishlist', { boardId: data.board.id })
|
||
|
|
} else {
|
||
|
|
const err = await res.json()
|
||
|
|
setError(err.error || 'Ошибка при присоединении')
|
||
|
|
}
|
||
|
|
} catch (err) {
|
||
|
|
setError('Ошибка при присоединении')
|
||
|
|
} finally {
|
||
|
|
setJoining(false)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleGoBack = () => {
|
||
|
|
onNavigate('wishlist')
|
||
|
|
}
|
||
|
|
|
||
|
|
if (loading) {
|
||
|
|
return (
|
||
|
|
<div className="board-join-preview">
|
||
|
|
<div className="preview-loading">
|
||
|
|
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin"></div>
|
||
|
|
<p>Загрузка...</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (error && !board) {
|
||
|
|
return (
|
||
|
|
<div className="board-join-preview">
|
||
|
|
<div className="preview-card error-card">
|
||
|
|
<div className="error-icon">❌</div>
|
||
|
|
<h2>Ошибка</h2>
|
||
|
|
<p className="error-text">{error}</p>
|
||
|
|
<button className="back-btn" onClick={handleGoBack}>
|
||
|
|
Вернуться к желаниям
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="board-join-preview">
|
||
|
|
<div className="preview-card">
|
||
|
|
<div className="invite-icon">✨</div>
|
||
|
|
<h2>Приглашение на доску</h2>
|
||
|
|
|
||
|
|
<div className="board-info">
|
||
|
|
<div className="board-name">{board.name}</div>
|
||
|
|
<div className="board-owner">
|
||
|
|
<span className="label">Владелец:</span>
|
||
|
|
<span className="value">{board.owner_name}</span>
|
||
|
|
</div>
|
||
|
|
{board.member_count > 0 && (
|
||
|
|
<div className="board-members">
|
||
|
|
<span className="label">Участников:</span>
|
||
|
|
<span className="value">{board.member_count}</span>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{error && (
|
||
|
|
<div className="join-error">{error}</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{user ? (
|
||
|
|
<button
|
||
|
|
className="join-btn"
|
||
|
|
onClick={handleJoin}
|
||
|
|
disabled={joining}
|
||
|
|
>
|
||
|
|
{joining ? (
|
||
|
|
<>
|
||
|
|
<span className="spinner-small"></span>
|
||
|
|
<span>Присоединение...</span>
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
<span>🎉</span>
|
||
|
|
<span>Присоединиться</span>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</button>
|
||
|
|
) : (
|
||
|
|
<div className="login-prompt">
|
||
|
|
<p>Для присоединения необходимо войти в аккаунт</p>
|
||
|
|
<button className="login-btn" onClick={() => onNavigate('login')}>
|
||
|
|
Войти
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
<button className="cancel-link" onClick={handleGoBack}>
|
||
|
|
Отмена
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export default BoardJoinPreview
|
||
|
|
|