Add waiting queue for guest join with sound
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m26s
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m26s
This commit is contained in:
@@ -31,6 +31,8 @@ export default function RoomDetail() {
|
||||
const [shareSearch, setShareSearch] = useState('');
|
||||
const [shareResults, setShareResults] = useState([]);
|
||||
const [shareSearching, setShareSearching] = useState(false);
|
||||
const [waitingToJoin, setWaitingToJoin] = useState(false);
|
||||
const prevRunningRef = useRef(false);
|
||||
|
||||
// Federation invite state
|
||||
const [showFedInvite, setShowFedInvite] = useState(false);
|
||||
@@ -87,6 +89,21 @@ export default function RoomDetail() {
|
||||
return () => clearInterval(interval);
|
||||
}, [uid]);
|
||||
|
||||
// Auto-join when meeting starts while waiting
|
||||
useEffect(() => {
|
||||
if (!prevRunningRef.current && status.running && waitingToJoin) {
|
||||
new Audio('/sounds/meeting-started.mp3').play().catch(() => {});
|
||||
toast.success(t('room.meetingStarted'));
|
||||
setWaitingToJoin(false);
|
||||
setActionLoading('join');
|
||||
api.post(`/rooms/${uid}/join`, {})
|
||||
.then(res => { if (res.data.joinUrl) window.open(res.data.joinUrl, '_blank'); })
|
||||
.catch(err => toast.error(err.response?.data?.error || t('room.joinFailed')))
|
||||
.finally(() => setActionLoading(null));
|
||||
}
|
||||
prevRunningRef.current = status.running;
|
||||
}, [status.running]);
|
||||
|
||||
const handleStart = async () => {
|
||||
setActionLoading('start');
|
||||
try {
|
||||
@@ -104,6 +121,12 @@ export default function RoomDetail() {
|
||||
};
|
||||
|
||||
const handleJoin = async () => {
|
||||
if (!status.running) {
|
||||
setWaitingToJoin(true);
|
||||
toast(t('room.guestWaitingTitle'), { icon: '🕐' });
|
||||
return;
|
||||
}
|
||||
setWaitingToJoin(false);
|
||||
setActionLoading('join');
|
||||
try {
|
||||
const data = room.access_code ? { access_code: prompt(t('room.enterAccessCode')) } : {};
|
||||
@@ -351,18 +374,21 @@ export default function RoomDetail() {
|
||||
<span className="hidden sm:inline">{t('federation.inviteRemote')}</span>
|
||||
</button>
|
||||
)}
|
||||
{canManage && !status.running && (
|
||||
{canManage && !status.running && !waitingToJoin && (
|
||||
<button onClick={handleStart} disabled={actionLoading === 'start'} className="btn-primary">
|
||||
{actionLoading === 'start' ? <Loader2 size={16} className="animate-spin" /> : <Play size={16} />}
|
||||
{t('room.start')}
|
||||
</button>
|
||||
)}
|
||||
{status.running && (
|
||||
<button onClick={handleJoin} disabled={actionLoading === 'join'} className="btn-primary">
|
||||
{actionLoading === 'join' ? <Loader2 size={16} className="animate-spin" /> : <ExternalLink size={16} />}
|
||||
{t('room.join')}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={waitingToJoin ? () => setWaitingToJoin(false) : handleJoin}
|
||||
disabled={actionLoading === 'join'}
|
||||
className={waitingToJoin ? 'btn-ghost' : 'btn-primary'}
|
||||
title={waitingToJoin ? t('room.guestCancelWaiting') : undefined}
|
||||
>
|
||||
{(actionLoading === 'join' || waitingToJoin) ? <Loader2 size={16} className="animate-spin" /> : <ExternalLink size={16} />}
|
||||
{waitingToJoin ? t('room.waitingToJoin') : t('room.join')}
|
||||
</button>
|
||||
{canManage && status.running && (
|
||||
<button onClick={handleEnd} disabled={actionLoading === 'end'} className="btn-danger">
|
||||
{actionLoading === 'end' ? <Loader2 size={16} className="animate-spin" /> : <Square size={16} />}
|
||||
|
||||
Reference in New Issue
Block a user