Реалізація кімнати очікування (Waiting Room) для відеоконференцій на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація кімнати очікування (Waiting Room) для відеоконференцій на сайті
Проста
від 1 робочого дня до 3 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка комнати очікування для відеоконференцій

Комната очікування дозволяє ведучому контролювати, хто впадеть в конференцію. Учасник бачить екран очікування, ведучий отримує сповіщення та приймає рішення — впустити або відхилити.

Реалізація через LiveKit Permissions

LiveKit підтримує зміну прав учасника на льоту. Учасник з лобі отримує токен з canPublish: false, а ведучий повищує права через API.

function generateLobbyToken(roomName: string, userId: string, displayName: string): string {
  const at = new AccessToken(
    process.env.LIVEKIT_API_KEY!,
    process.env.LIVEKIT_API_SECRET!,
    { identity: `lobby-${userId}`, name: displayName }
  );

  at.addGrant({
    roomJoin: true,
    room: roomName,
    canPublish: false,
    canSubscribe: false,
    canPublishData: true,
  });

  return at.toJwt();
}

async function admitParticipant(roomName: string, lobbyIdentity: string): Promise<void> {
  await svc.updateParticipant(roomName, lobbyIdentity, undefined, {
    canPublish: true,
    canSubscribe: true,
  });

  await svc.sendData(
    roomName,
    Buffer.from(JSON.stringify({ type: 'admitted' })),
    DataPacket_Kind.RELIABLE,
    [lobbyIdentity]
  );
}

Екран очікування

function WaitingRoom({ roomName, userId, displayName, onAdmitted }) {
  const [waitTime, setWaitTime] = useState(0);

  useEffect(() => {
    const room = new Room();
    room.connect(process.env.NEXT_PUBLIC_LIVEKIT_URL, lobbyToken);

    room.on('connected', async () => {
      await room.localParticipant.publishData(
        new TextEncoder().encode(JSON.stringify({
          type: 'lobby_request',
          userId,
          displayName,
        })),
        { reliable: true }
      );
    });

    room.on('dataReceived', (payload) => {
      const msg = JSON.parse(new TextDecoder().decode(payload));
      if (msg.type === 'admitted') onAdmitted();
    });

    const timer = setInterval(() => setWaitTime(t => t + 1), 1000);
    return () => { clearInterval(timer); room.disconnect(); };
  }, []);

  return (
    <div className="min-h-screen bg-gray-900 flex items-center justify-center text-white">
      <div className="text-center max-w-md px-6">
        <h2 className="text-2xl font-semibold mb-2">Подождите...</h2>
        <p className="text-gray-400 mb-6">
          Ведущий скоро впустит вас. Время ожидания: {Math.floor(waitTime / 60)}:{String(waitTime % 60).padStart(2, '0')}
        </p>
      </div>
    </div>
  );
}

Панель управління ведучого

function HostLobbyPanel({ room }: { room: Room }) {
  const [lobbyRequests, setLobbyRequests] = useState<LobbyRequest[]>([]);

  useEffect(() => {
    room.on('dataReceived', (payload, participant) => {
      const msg = JSON.parse(new TextDecoder().decode(payload));
      if (msg.type === 'lobby_request') {
        setLobbyRequests(prev => [
          ...prev,
          { identity: participant?.identity ?? '', displayName: msg.displayName }
        ]);
      }
    });
  }, [room]);

  const admit = async (identity: string) => {
    await fetch(`/api/rooms/${room.name}/admit/${identity}`, { method: 'POST' });
    setLobbyRequests(prev => prev.filter(r => r.identity !== identity));
  };

  if (lobbyRequests.length === 0) return null;

  return (
    <div className="absolute top-4 right-4 w-72 bg-white rounded-xl shadow-lg p-4 z-50">
      <h3 className="font-semibold text-gray-800 mb-3">Ожидают входа ({lobbyRequests.length})</h3>
      <div className="space-y-3">
        {lobbyRequests.map(req => (
          <div key={req.identity} className="flex items-center gap-3">
            <span className="flex-1 text-sm text-gray-800">{req.displayName}</span>
            <button onClick={() => admit(req.identity)}
              className="text-xs px-2 py-1 bg-green-600 text-white rounded">
              Впустити
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

Терміни

Комната очікування з екраном учасника та панеллю ведучого — 1–2 дні.