import React, { useState, useEffect, useMemo } from 'react'; import Joyride, { STATUS } from 'react-joyride'; const GuideTour = ({ darkMode, tourVersion, onTourEnd }) => { const steps = useMemo(() => [ { target: 'body', title: 'Xin chào, tôi là Pochi', content: 'Cùng bắt đầu khám phá không gian làm việc của bạn nhé!', placement: 'center', disableBeacon: true, }, { target: 'body', title: 'Thao tác nhanh', content: (
Sử dụng bàn phím để điều khiển linh hoạt:
: Điều hướng các bước.
Esc
: Bỏ qua hướng dẫn nhanh.
Enter
: Hoàn tất hướng dẫn.
), placement: 'center', disableBeacon: true, }, { target: '#tour-new-chat', title: 'Đoạn chat mới', content: 'Nơi bạn bắt đầu những cuộc trò chuyện mới với Pochi linh hoạt và nhanh chóng.', disableBeacon: true, }, { target: '#tour-chat-input-area', title: 'Khung gửi tin nhắn', content: 'Nhập nội dung câu hỏi, đính kèm hình ảnh để trò chuyện cùng Pochi.', disableBeacon: true, }, { target: '#tour-chat-interface', title: 'Giao diện trò chuyện', content: 'Khu vực hiển thị nội dung trao đổi giữa bạn và Pochi một cách trực quan.', disableBeacon: true, }, { target: '#tour-history-section', title: 'Lịch sử trò chuyện', content: 'Toàn bộ các cuộc trò chuyện của bạn đều được lưu trữ an toàn tại đây.', spotlightPadding: 5, disableBeacon: true, }, { target: '#tour-chat-features', title: 'Tính năng nâng cao', content: 'Bạn có thể ghim, đổi tên, lưu trữ hoặc xóa các cuộc trò chuyện thông qua menu này.', spotlightPadding: 5, disableBeacon: true, }, { target: '#tour-profile-header-avatar', title: 'Cài đặt cá nhân (Header)', content: 'Bạn có thể truy cập cài đặt, quản lý tài khoản hoặc đăng xuất nhanh tại logo góc trên này.', spotlightPadding: 5, disableBeacon: true, }, { target: '#tour-profile-sidebar-avatar', title: 'Cài đặt cá nhân (Sidebar)', content: 'Hoặc bạn cũng có thể thay đổi chế độ tối / sáng và xem tin nhắn lưu trữ tại logo phía dưới này.', spotlightPadding: 5, disableBeacon: true, }, { target: '#tour-search', title: 'Tìm kiếm đoạn chat', content: 'Giúp bạn tìm lại những thông tin cũ trong lịch sử trò chuyện chỉ với vài phím gõ.', spotlightPadding: 5, disableBeacon: true, }, { target: '#tour-toggle-sidebar', title: 'Thu gọn thanh bên', content: 'Tối ưu không gian làm việc bằng cách thu gọn thanh bên khi cần thiết.', spotlightPadding: 5, disableBeacon: true, }, { target: '#tour-help-btn', title: 'Trợ giúp & Hướng dẫn', content: 'Bất cứ lúc nào bạn cần, hãy nhấn vào đây để xem lại hướng dẫn sử dụng nhé!', disableBeacon: true, }, { target: 'body', title: 'Tổng hợp phím tắt', content: (
Làm chủ ứng dụng qua các phím tắt nhanh:
{navigator.platform.toUpperCase().indexOf('MAC') >= 0 ? '⌘' : 'Ctrl'} F
: Tìm kiếm trò chuyện.
{navigator.platform.toUpperCase().indexOf('MAC') >= 0 ? '⌘' : 'Ctrl'} E
: Tạo đoạn chat mới.
{navigator.platform.toUpperCase().indexOf('MAC') >= 0 ? '⌘' : 'Ctrl'} K
: Bật/tắt chế độ tối.
{navigator.platform.toUpperCase().indexOf('MAC') >= 0 ? '⌘' : 'Ctrl'} X
: Mở cài đặt chung.
{navigator.platform.toUpperCase().indexOf('MAC') >= 0 ? '⌘' : 'Ctrl'} I
: Thông tin tài khoản.
Ấn phím tắt Enter để hoàn tất hướng dẫn.
), placement: 'center', disableBeacon: true, } ], [darkMode]); const [run, setRun] = useState(false); const [stepIndex, setStepIndex] = useState(() => { const savedIndex = localStorage.getItem('tourStepIndex'); return (savedIndex && savedIndex !== '-1') ? parseInt(savedIndex, 10) : 0; }); const finalizeTour = () => { setRun(false); setStepIndex(0); localStorage.setItem('hasSeenTour', 'true'); localStorage.setItem('tourStepIndex', '-1'); if (onTourEnd) onTourEnd(); // Remove focus from whatever triggered the end/skip to prevent persistent focus outlines if (document.activeElement && typeof document.activeElement.blur === 'function') { document.activeElement.blur(); } }; const handleJoyrideCallback = (data) => { const { action, index, status, type, size } = data; if (type === 'step:after' || type === 'target:not_found') { const isLastStep = index === size - 1; if (isLastStep && action === 'next') { finalizeTour(); return; } const nextIndex = index + (action === 'next' ? 1 : -1); if (nextIndex >= 0 && nextIndex < size) { setStepIndex(nextIndex); localStorage.setItem('tourStepIndex', nextIndex.toString()); } } const finishedStatuses = [STATUS.FINISHED, STATUS.SKIPPED]; if (finishedStatuses.includes(status)) { finalizeTour(); } }; useEffect(() => { const hasSeenTour = localStorage.getItem('hasSeenTour'); const savedIndex = localStorage.getItem('tourStepIndex'); if (tourVersion > 0) { setStepIndex(0); localStorage.setItem('tourStepIndex', '0'); setRun(true); } else if (tourVersion === -1) { setRun(false); } else if (!hasSeenTour || (savedIndex !== null && savedIndex !== '-1')) { setRun(true); } else { setRun(false); } }, [tourVersion]); useEffect(() => { if (!run) return; const handleKeyDown = (e) => { const isLastStep = stepIndex === steps.length - 1; const isFirstStep = stepIndex === 0; switch (e.key) { case 'ArrowRight': if (!isLastStep) { e.preventDefault(); const nextIndex = stepIndex + 1; setStepIndex(nextIndex); localStorage.setItem('tourStepIndex', nextIndex.toString()); } break; case 'ArrowLeft': if (!isFirstStep) { e.preventDefault(); const prevIndex = stepIndex - 1; setStepIndex(prevIndex); localStorage.setItem('tourStepIndex', prevIndex.toString()); } break; case 'Enter': e.preventDefault(); if (isLastStep) { finalizeTour(); } break; case 'Escape': e.preventDefault(); finalizeTour(); break; default: break; } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [run, stepIndex, steps]); const CustomTooltip = ({ index, step, size, backProps, primaryProps, skipProps, tooltipProps, arrowProps, isLastStep }) => { const safeTooltipProps = tooltipProps || {}; const placement = safeTooltipProps['data-placement'] || step?.placement || 'bottom'; return (
{index + 1} / {size}
{index > 0 && ( )}
{step?.title &&

{step.title}

}
{step?.content}
{!isLastStep && ( )}