import React, { useState, useEffect } from 'react'; import { ClipboardList, Eye, Key, Users, Building2, Copy, CheckCircle2, Play, Pause, X } from 'lucide-react'; import { apiClient } from '../../services/apiClient'; import { NPSSurvey, NPSSurveyStats, Building } from '../../types'; export const NPSSurveysManager: React.FC = () => { const [surveys, setSurveys] = useState([]); const [buildings, setBuildings] = useState([]); const [isLoading, setIsLoading] = useState(true); const [showAccessKeyModal, setShowAccessKeyModal] = useState(false); const [selectedSurvey, setSelectedSurvey] = useState(null); const [stats, setStats] = useState>({}); const [filterBuilding, setFilterBuilding] = useState(''); const [filterStatus, setFilterStatus] = useState(''); const [selectedMonth, setSelectedMonth] = useState<{ month: number; year: number }>(() => { const now = new Date(); return { month: now.getMonth() + 1, year: now.getFullYear() }; }); useEffect(() => { loadSurveys(); loadBuildings(); }, [filterBuilding, filterStatus]); useEffect(() => { // Перезагружаем статистику при изменении месяца surveys.forEach(survey => { loadStats(survey.id, selectedMonth.month, selectedMonth.year); }); }, [selectedMonth]); const loadSurveys = async () => { try { setIsLoading(true); const params: any = {}; if (filterBuilding) params.building_id = filterBuilding; if (filterStatus) params.status = filterStatus; const queryString = new URLSearchParams(params).toString(); const data = await apiClient.get(`/pr/nps-surveys${queryString ? `?${queryString}` : ''}`); setSurveys(data); // Загружаем статистику для всех опросов с учетом выбранного месяца data.forEach((survey: NPSSurvey) => { loadStats(survey.id, selectedMonth.month, selectedMonth.year); }); } catch (err) { console.error('Error loading surveys:', err); } finally { setIsLoading(false); } }; const loadBuildings = async () => { try { const data = await apiClient.get('/buildings'); setBuildings(data); } catch (err) { console.error('Error loading buildings:', err); } }; const loadStats = async (surveyId: number, month?: number, year?: number) => { try { const params = new URLSearchParams(); if (month) params.append('month', month.toString()); if (year) params.append('year', year.toString()); const queryString = params.toString(); const data = await apiClient.get(`/pr/nps-surveys/${surveyId}/stats${queryString ? `?${queryString}` : ''}`); setStats(prev => ({ ...prev, [surveyId]: data })); } catch (err) { console.error('Error loading stats:', err); } }; const handleUpdateStatus = async (survey: NPSSurvey, newStatus: 'draft' | 'active' | 'closed') => { try { const updated = await apiClient.put(`/pr/nps-surveys/${survey.id}`, { status: newStatus }); setSurveys(surveys.map(s => s.id === survey.id ? updated : s)); } catch (err: any) { alert(`Ошибка обновления статуса: ${err.message || 'Неизвестная ошибка'}`); } }; const getSurveyLink = (survey: NPSSurvey, apartment?: string) => { const baseUrl = `${window.location.origin}/nps/${survey.id}?key=${survey.accessKey}`; if (apartment) { return `${baseUrl}&apartment=${encodeURIComponent(apartment)}`; } return baseUrl; }; const [copiedSurveyId, setCopiedSurveyId] = useState(null); const [showApartmentInput, setShowApartmentInput] = useState(null); const [apartmentForLink, setApartmentForLink] = useState(''); const handleCopyLink = (survey: NPSSurvey, apartment?: string) => { const link = getSurveyLink(survey, apartment); navigator.clipboard.writeText(link); setCopiedSurveyId(survey.id); setTimeout(() => setCopiedSurveyId(null), 2000); }; const getNPSColor = (nps: number) => { if (nps >= 50) return 'text-emerald-600'; if (nps >= 0) return 'text-amber-600'; return 'text-red-600'; }; const getStatusColor = (status: string) => { switch (status) { case 'active': return 'bg-emerald-100 text-emerald-700'; case 'closed': return 'bg-slate-100 text-slate-700'; default: return 'bg-amber-100 text-amber-700'; } }; const getStatusLabel = (status: string) => { switch (status) { case 'active': return 'Активен'; case 'closed': return 'Закрыт'; default: return 'Черновик'; } }; return (
{/* Заголовок и фильтры */}

Опросы NPS

Опросы создаются автоматически для каждого дома

{/* Выбор месяца для статистики */}
{/* Список опросов */} {isLoading ? (

Загрузка опросов...

) : surveys.length === 0 ? (

Нет опросов

Опросы создаются автоматически для каждого дома 1 числа каждого месяца

) : (
{surveys.map(survey => { const surveyStats = stats[survey.id]; return (
{/* Заголовок */}

{survey.title}

{survey.address && (

{survey.address}

)}
{getStatusLabel(survey.status)}
{/* Статистика */} {surveyStats && surveyStats.totalResponses > 0 ? (

NPS

{surveyStats.nps > 0 ? '+' : ''}{surveyStats.nps}

Средняя оценка

{surveyStats.avgScore.toFixed(1)}

Промоутеры

{surveyStats.promoters}

Нейтральные

{surveyStats.passives}

Критики

{surveyStats.detractors}

Ответов за {new Date(selectedMonth.year, selectedMonth.month - 1).toLocaleDateString('ru-RU', { month: 'long', year: 'numeric' })}: {surveyStats.totalResponses}

) : (

Нет ответов за {new Date(selectedMonth.year, selectedMonth.month - 1).toLocaleDateString('ru-RU', { month: 'long', year: 'numeric' })}

)} {/* Действия */}
{survey.status === 'draft' && ( )} {survey.status === 'active' && ( )} {/* Модальное окно для ввода номера квартиры */} {showApartmentInput === survey.id && (

Ссылка для отправки в чат

setApartmentForLink(e.target.value)} placeholder="Например: 45" className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" autoFocus />
{apartmentForLink.trim() && (

Ссылка будет содержать:

{getSurveyLink(survey, apartmentForLink.trim())}

)}
)}
); })}
)} {/* Модальное окно с ключом доступа */} {showAccessKeyModal && selectedSurvey && (

Ссылка на опрос

💬 Для отправки в чат:

Добавьте параметр ?apartment=XX к ссылке, чтобы автоматически указать номер квартиры жителя.

Пример: {getSurveyLink(selectedSurvey)}&apartment=45

Важно: Ссылка содержит ключ доступа. Отправляйте её только жителям выбранного дома.

)}
); };