Выбор времени для собеседования

Выбор времени для собеседования

Ниже отображаются свободные интервалы в рабочее время с 09:00 до 13:00 на ближайшие 3 недели (будни, без выходных). Шаг слотов — 15 минут.

${interviewInfo}
Если вам нужно изменить время, пожалуйста, свяжитесь с нами — мы перенесём встречу.
`; alreadyContainer.innerHTML = ''; alreadyContainer.appendChild(card); const cancelBtn = card.querySelector('#cancel-interview-btn'); if (cancelBtn) { cancelBtn.addEventListener('click', onCancelInterviewClick); } console.log('Отрисован блок "Собеседование уже назначено"', { interviewInfo }); } // ================== Обработка кликов ================== function onSlotClick(slot) { currentSelectedSlot = slot; renderCurrentPage(); } async function bookSlot(slot) { if (!currentCandidateId) { showError('Не найден идентификатор кандидата. Ссылка некорректна.'); return; } const sectionId = await getInvitationsSectionId(); const intervalText = formatHumanInterval(slot.start, slot.end); const dateFromStr = slot.start.toLocaleString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(',', ''); const dateToStr = slot.end.toLocaleString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(',', ''); const candidateLink = getCandidateCardUrl(); const displayName = candidateName || `кандидатом #${currentCandidateId}`; let eventDescription = `Интервью с ${displayName}.\n` + `Карточка кандидата: ${candidateLink || ''}`; if (candidateLink) { eventDescription += `\n\nОткрыть карточку кандидата`; } const eventResult = await callBitrix('calendar.event.add', { type: 'user', ownerId: USER_ID, section: sectionId, name: `Собеседование с ${displayName}`, from: dateFromStr, to: dateToStr, skipTime: 'N', timezone: 'Europe/Moscow', description: eventDescription }); const eventId = typeof eventResult === 'object' && eventResult !== null && eventResult.ID ? parseInt(eventResult.ID, 10) : parseInt(eventResult, 10); if (!eventId || isNaN(eventId)) { console.warn('calendar.event.add вернул странный результат', eventResult); } else { currentEventId = eventId; } const interviewInfoValue = `Собеседование назначено: ${intervalText}`; const dtForField = toBitrixDateTimeWithOffset(slot.start); const fieldsPayload = { entityTypeId: ENTITY_TYPE_ID, id: currentCandidateId, [`fields[${FIELD_INTERVIEW_INFO_UPDATE}]`]: interviewInfoValue, [`fields[${FIELD_INTERVIEW_FLAG_UPDATE}]`]: 'Да', [`fields[${FIELD_EVENT_ID_UPDATE}]`]: eventId ? String(eventId) : '', [`fields[${FIELD_INTERVIEW_DATETIME_UPDATE}]`]: dtForField }; await callBitrix('crm.item.update', fieldsPayload); showResult(`Вы успешно записаны на собеседование. ${interviewInfoValue}`); updateTitleAndSubtitle(true); renderAlreadyBooked(interviewInfoValue); } async function onCancelInterviewClick() { if (!currentCandidateId) { showError('Не найден идентификатор кандидата. Ссылка некорректна.'); return; } const btn = document.getElementById('cancel-interview-btn'); if (btn) { btn.disabled = true; btn.textContent = 'Отменяем...'; } console.log('Отмена собеседования: старт', { candidateId: currentCandidateId, currentEventId }); if (currentEventId) { try { await callBitrix('calendar.event.delete', { id: currentEventId }); console.log('Событие календаря удалено', currentEventId); } catch (e) { console.error('Не удалось удалить событие календаря', e); } } const fieldsPayload = { entityTypeId: ENTITY_TYPE_ID, id: currentCandidateId, [`fields[${FIELD_INTERVIEW_INFO_UPDATE}]`]: '', [`fields[${FIELD_INTERVIEW_FLAG_UPDATE}]`]: 'Собеседование отменено', [`fields[${FIELD_EVENT_ID_UPDATE}]`]: '', [`fields[${FIELD_INTERVIEW_DATETIME_UPDATE}]`]: '' }; try { await callBitrix('crm.item.update', fieldsPayload); console.log('Отмена собеседования: crm.item.update успешен', fieldsPayload); currentEventId = null; showResult('Собеседование отменено. При необходимости выберите новое время для собеседования.'); const selector = document.getElementById('slot-selector'); const alreadyContainer = document.getElementById('already-booked'); if (alreadyContainer) alreadyContainer.innerHTML = ''; if (selector) selector.style.display = 'block'; updateTitleAndSubtitle(false); await loadFreeSlots(); } catch (e) { console.error('Ошибка при отмене собеседования', e); showError('Не удалось отменить собеседование. Пожалуйста, попробуйте ещё раз.'); if (btn) { btn.disabled = false; btn.textContent = 'Отменить собеседование'; } } } // ================== Навигация по карусели ================== function setupNavButtons() { const prevBtn = document.getElementById('prev-page-btn'); const nextBtn = document.getElementById('next-page-btn'); if (!prevBtn || !nextBtn) return; prevBtn.addEventListener('click', () => { if (currentPage > 0) { currentPage -= 1; renderCurrentPage(); } }); nextBtn.addEventListener('click', () => { const maxPage = Math.floor((allDaysWithSlots.length - 1) / DAYS_PER_PAGE); if (currentPage { setupNavButtons(); initPage().catch((e) => { console.error(e); showError('Произошла ошибка при инициализации страницы.'); }); });