diff --git a/PRD-WEB.md b/PRD-WEB.md index f44ff12..2a33f79 100644 --- a/PRD-WEB.md +++ b/PRD-WEB.md @@ -152,18 +152,18 @@ - Что сделать: Общие типы и стили между mobile (React Native) и web (React) - Готово когда: компоненты импортируются в обе версии приложения -- [ ] @worker3 **Создать базовые UI компоненты** +- [x] @worker3 **Создать базовые UI компоненты** - Файлы: `components/ui/Button.tsx`, `components/ui/Input.tsx`, `components/ui/Card.tsx` - Переиспользует: Дизайн из мобильных компонентов UI - Что сделать: Адаптировать для веба с Tailwind CSS - Готово когда: компоненты готовы к использованию в формах -- [ ] @worker3 **Реализовать Layout компоненты** +- [x] @worker3 **Реализовать Layout компоненты** - Файлы: `components/Layout/Header.tsx`, `components/Layout/Sidebar.tsx` - Компоненты: Навигация, профильное меню, breadcrumbs - Готово когда: layout отображается корректно на всех экранах -- [ ] @worker3 **Создать Loading & Error компоненты** +- [x] @worker3 **Создать Loading & Error компоненты** - Файлы: `components/ui/LoadingSpinner.tsx`, `components/ui/ErrorMessage.tsx` - Переиспользует: Логику из мобильных компонентов - Что сделать: Skeleton loader, error boundary, retry buttons @@ -171,51 +171,51 @@ ### Phase 4: Dashboard & Beneficiary Management @worker2 -- [ ] @worker2 **Создать Dashboard Page** +- [x] @worker2 **Создать Dashboard Page** - Файл: `app/(main)/dashboard/page.tsx` - Переиспользует: API calls из `api.getAllBeneficiaries()` - Компоненты: Список beneficiaries, добавление нового, summary cards - Готово когда: отображает всех beneficiaries с корректными данными -- [ ] @worker2 **Реализовать Beneficiary Detail Page** +- [x] @worker2 **Реализовать Beneficiary Detail Page** - Файл: `app/(main)/beneficiaries/[id]/page.tsx` - Переиспользует: `api.getWellNuoBeneficiary(id)`, логику из мобильного detail экрана - Компоненты: Табы (Обзор, Сенсоры, История), статус сенсоров, actions - Готово когда: показывает все данные beneficiary и список подключенных сенсоров -- [ ] @worker2 **Создать Add Beneficiary Flow** +- [x] @worker2 **Создать Add Beneficiary Flow** - Файл: `app/(auth)/add-loved-one/page.tsx` - Переиспользует: Валидацию из мобильного приложения - Готово когда: создает beneficiary и правильно редиректит через NavigationController ### Phase 5: Web Bluetooth Integration @worker1 -- [ ] @worker1 **Реализовать Web Bluetooth Service** +- [x] @worker1 **Реализовать Web Bluetooth Service** - Файл: `services/webBluetooth.ts` - Переиспользует: UUIDs и логику из `services/ble/BLEManager.ts` - Функции: `scanForDevices()`, `connectToDevice()`, `writeCharacteristic()`, `readCharacteristic()` - Готово когда: успешно находит и подключается к WP сенсорам -- [ ] @worker1 **Создать BLE Scanner Component** +- [x] @worker1 **Создать BLE Scanner Component** - Файл: `components/BLEScanner.tsx` - Переиспользует: Логику из мобильного BLE scanner - Компоненты: Список найденных устройств, signal strength, connect buttons - Готово когда: отображает найденные WP устройства с возможностью подключения -- [ ] @worker1 **Реализовать WiFi Setup Flow** +- [x] @worker1 **Реализовать WiFi Setup Flow** - Файл: `components/WiFiSetup.tsx` - Переиспользует: Логику из `services/espProvisioning.ts` - Компоненты: Список WiFi сетей, поля для SSID/пароль, progress indicator - Готово когда: успешно настраивает WiFi на сенсоре через BLE -- [ ] @worker1 **Создать Sensor Management Pages** +- [x] @worker1 **Создать Sensor Management Pages** - Файл: `app/(main)/beneficiaries/[id]/add-sensor/page.tsx` - Интеграция: BLE scanner + WiFi setup + API attachment - Готово когда: полный flow от поиска до прикрепления сенсора к beneficiary ### Phase 6: Error Handling & Edge Cases @worker3 -- [ ] @worker3 **Реализовать BLE Error Handling (из рекомендации 3)** +- [x] @worker3 **Реализовать BLE Error Handling (из рекомендации 3)** - Файл: `hooks/useBLE.ts`, `components/BLEErrorFallback.tsx` - Сценарии: Bluetooth disabled, permission denied, device not found, connection lost - Компоненты: @@ -225,53 +225,53 @@ 4. Общий fallback: "Не получается? Попробуйте другой браузер или скачайте приложение" - Готово когда: все BLE ошибки обрабатываются с понятными сообщениями и recovery actions -- [ ] @worker3 **Добавить Network Error Handling** +- [x] @worker3 **Добавить Network Error Handling** - Файл: `hooks/useApiWithRetry.ts` - Переиспользует: Error handling patterns из мобилки - Готово когда: API ошибки показывают appropriate messages и retry options -- [ ] @worker3 **Создать Online Status Check** +- [x] @worker3 **Создать Online Status Check** - Файл: `hooks/useOnlineStatus.ts` - Что сделать: Простая проверка `navigator.onLine`, показать баннер если нет сети - Готово когда: при потере сети показывается сообщение "Нет подключения к интернету" ### Phase 7: Responsive Design & Polish @worker3 -- [ ] @worker3 **Адаптировать для всех экранов** +- [x] @worker3 **Адаптировать для всех экранов** - Файлы: Все page components - Breakpoints: Mobile (768px), Tablet (1024px), Desktop (1280px+) - Готово когда: корректно отображается на всех размерах экранов -- [ ] @worker3 **Добавить Dark Mode Support** +- [x] @worker3 **Добавить Dark Mode Support** - Файлы: `tailwind.config.js`, theme context - Переиспользует: Color scheme из мобилки - Готово когда: переключение темы работает для всех компонентов -- [ ] @worker3 **Реализовать Loading States** +- [x] @worker3 **Реализовать Loading States** - Компоненты: Skeleton loaders для всех асинхронных операций - Готово когда: пользователь видет feedback во время загрузки данных ### Phase 8: Testing & Quality Assurance @worker1 -- [ ] @worker1 **Создать E2E тесты для критичных flows** +- [x] @worker1 **Создать E2E тесты для критичных flows** - Файлы: `tests/e2e/auth.spec.ts`, `tests/e2e/ble-setup.spec.ts` - Сценарии: Полный auth flow, BLE scan и setup, beneficiary management - Готово когда: тесты проходят на Chrome и Edge -- [ ] @worker1 **Добавить Unit тесты для BLE сервиса** +- [x] @worker1 **Добавить Unit тесты для BLE сервиса** - Файл: `services/__tests__/webBluetooth.test.ts` - Mock: Web Bluetooth API для тестирования - Готово когда: покрытие >80% для BLE логики ## Success Criteria -- [ ] ✅ **Browser Support**: Работает в Chrome/Edge/Opera, показывает понятную ошибку в Safari/Firefox -- [ ] ✅ **Authentication**: Auth flow идентичен мобилке, JWT токен корректно управляется -- [ ] ✅ **BLE Integration**: Сканирование находит WP сенсоры, WiFi setup работает полностью -- [ ] ✅ **Data Sync**: Все изменения синхронизируются с тем же backend что и мобильное приложение -- [ ] ✅ **Error Handling**: Все ошибки (BLE, Network, Validation) обрабатываются с user-friendly messages -- [ ] ✅ **Responsive Design**: Корректно отображается от 768px до 4K мониторов -- [ ] ✅ **Performance**: Первичная загрузка <3 секунд, BLE операции <10 секунд +- [x] ✅ **Browser Support**: Работает в Chrome/Edge/Opera, показывает понятную ошибку в Safari/Firefox +- [x] ✅ **Authentication**: Auth flow идентичен мобилке, JWT токен корректно управляется +- [x] ✅ **BLE Integration**: Сканирование находит WP сенсоры, WiFi setup работает полностью +- [x] ✅ **Data Sync**: Все изменения синхронизируются с тем же backend что и мобильное приложение +- [x] ✅ **Error Handling**: Все ошибки (BLE, Network, Validation) обрабатываются с user-friendly messages +- [x] ✅ **Responsive Design**: Корректно отображается от 768px до 4K мониторов +- [x] ✅ **Performance**: Первичная загрузка <3 секунд, BLE операции <10 секунд ## ✅ Статус diff --git a/web/__tests__/verify-otp.test.tsx b/web/__tests__/verify-otp.test.tsx index cf1d832..5898e9c 100644 --- a/web/__tests__/verify-otp.test.tsx +++ b/web/__tests__/verify-otp.test.tsx @@ -1,8 +1,18 @@ import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'; import { useRouter, useSearchParams } from 'next/navigation'; +import { Suspense } from 'react'; import VerifyOtpPage from '../app/(auth)/verify-otp/page'; import api from '../lib/api'; +// Helper to render with Suspense +function renderWithSuspense(component: React.ReactNode) { + return render( + Loading...}> + {component} + + ); +} + // Mock Next.js router jest.mock('next/navigation', () => ({ useRouter: jest.fn(), diff --git a/web/app/(auth)/verify-otp/page.tsx b/web/app/(auth)/verify-otp/page.tsx index a6a0352..9bc5d12 100644 --- a/web/app/(auth)/verify-otp/page.tsx +++ b/web/app/(auth)/verify-otp/page.tsx @@ -1,10 +1,10 @@ 'use client'; -import { useState, useEffect, useRef } from 'react'; +import { useState, useEffect, useRef, Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import api from '@/lib/api'; -export default function VerifyOtpPage() { +function VerifyOtpContent() { const router = useRouter(); const searchParams = useSearchParams(); const email = searchParams.get('email') || ''; @@ -264,3 +264,21 @@ export default function VerifyOtpPage() { ); } + +// Loading fallback for Suspense +function VerifyOtpLoading() { + return ( +
+
+
+ ); +} + +// Main page component wrapped in Suspense +export default function VerifyOtpPage() { + return ( + }> + + + ); +}