feat(tour): add onboarding tours for various admin pages

- Integrated TourButton component into SettingsMenuPage, SkillsPage, SmsWalletPage, StaffPage, StaffSessionDetailPage, StaffTreatmentSessionsPage, SubscriptionPage, TagsSettingsPage, TreatmentCasesPage to enhance user onboarding experience.
- Created new tour definitions for appointments, clinics, staff management, financial management, and patient management, ensuring comprehensive guidance for users navigating the admin panel.
- Updated documentation to reflect the addition of tours and their implementation details.
This commit is contained in:
hamed
2026-08-10 10:10:20 +03:30
parent 20c8eaaad9
commit ecdefa3c24
73 changed files with 1008 additions and 76 deletions
+11 -4
View File
@@ -17,6 +17,8 @@ import SearchableSelect from '../components/ui/SearchableSelect';
import Pagination from '../components/ui/Pagination';
import NewAppointmentDrawer from '../components/NewAppointmentDrawer';
import BackButton from '../components/ui/BackButton';
import TourButton from '../components/ui/TourButton';
import { useTour } from '../hooks/useTour';
import { AppointmentInfoModal, TransferReserveModal } from '../components/AppointmentActions';
const LIMIT = 20;
@@ -119,16 +121,21 @@ export default function ReserveAppointmentsPage() {
const th: React.CSSProperties = { padding: '10px 14px', textAlign: 'right', fontWeight: 600, color: 'var(--text-2)', whiteSpace: 'nowrap' };
const td: React.CSSProperties = { padding: '10px 14px', textAlign: 'right', color: 'var(--text)', verticalAlign: 'middle' };
useTour('appointments-reserve', { ready: !isLoading });
return (
<div className="fade-in" style={{ padding: '20px 24px' }}>
<div style={{ marginBottom: 14 }}>
<BackButton fallback="/admin/appointments" />
</div>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 10, marginBottom: 16 }}>
<h1 style={{ fontSize: 17, fontWeight: 800 }}>نوبت های رزرو شده</h1>
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }} data-tour="page-title">
<h1 style={{ fontSize: 17, fontWeight: 800 }}>نوبت های رزرو شده</h1>
<TourButton tourId="appointments-reserve" />
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
{isClinic && (
<div style={{ minWidth: 180 }}>
<div style={{ minWidth: 180 }} data-tour="reserve-doctor">
<SearchableSelect
options={clinicDoctors.map(d => ({ value: d.uuid, label: d.name }))}
value={doctorUuid || null}
@@ -140,7 +147,7 @@ export default function ReserveAppointmentsPage() {
</div>
)}
{primaryRole !== 'representation' && (
<button className="btn primary sm" disabled={!doctorUuid}
<button className="btn primary sm" data-tour="reserve-new" disabled={!doctorUuid}
onClick={() => setDrawerOpen(true)} style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
<PlusIcon style={{ width: 15 }} /> نوبت رزرو
</button>
@@ -148,7 +155,7 @@ export default function ReserveAppointmentsPage() {
</div>
</div>
<div style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r)', overflow: 'hidden' }}>
<div data-tour="reserve-list" style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r)', overflow: 'hidden' }}>
{isLoading ? (
<div style={{ padding: 40, textAlign: 'center', color: 'var(--text-3)' }}>در حال بارگذاری...</div>
) : items.length === 0 ? (