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
+10 -5
View File
@@ -19,6 +19,8 @@ import ServiceSlotPicker from '../components/appointments/ServiceSlotPicker';
import SlotPicker, { type PickedSlot } from '../components/appointments/SlotPicker';
import { tehranWallClockToUnix, rialToToman, tomanToRial } from '../lib/utils';
import BackButton from '../components/ui/BackButton';
import TourButton from '../components/ui/TourButton';
import { useTour } from '../hooks/useTour';
import { digitsOnly, todayIso, formatNumber } from '../lib/utils';
import Switch from '../components/ui/Switch';
@@ -266,6 +268,8 @@ export default function AppointmentCreatePage() {
onError: (e: any) => toast.error(e.message || 'خطا در ثبت نوبت'),
});
useTour('appointment-create', { ready: true });
return (
<div style={{ padding: '20px 24px', maxWidth: 1080, margin: '0 auto' }}>
{/* بردکرامب */}
@@ -273,7 +277,8 @@ export default function AppointmentCreatePage() {
<BackButton fallback="/admin/appointments" />
<span style={{ fontSize: 13, color: 'var(--text-3)' }}>نوبت ها</span>
<span style={{ color: 'var(--text-3)' }}></span>
<span style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)' }}>ثبت نوبت جدید</span>
<span style={{ fontSize: 15, fontWeight: 700, color: 'var(--text)' }} data-tour="page-title">ثبت نوبت جدید</span>
<TourButton tourId="appointment-create" />
</div>
{/* فرم باید صریح بگوید این نوبت برای کدام دوره است؛ بیمارِ چنددوره‌ای بدون این،
@@ -313,7 +318,7 @@ export default function AppointmentCreatePage() {
{!isDoctor && (
<>
<div style={{ ...sectionTitle, marginTop: 0 }}>پزشک:</div>
<label style={label}>انتخاب پزشک</label>
<label style={label} data-tour="create-doctor">انتخاب پزشک</label>
<div style={{ margin: '6px 0 4px', maxWidth: 400 }}>
<SearchableSelect
options={doctorOptions}
@@ -386,7 +391,7 @@ export default function AppointmentCreatePage() {
{/* حالت جستجوی مراجعه‌کنندهٔ موجود */}
{!newPatient && (
<>
<label style={label}>انتخاب مراجعه کننده</label>
<label style={label} data-tour="create-patient">انتخاب مراجعه کننده</label>
<div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 12, margin: '6px 0 8px' }}>
<div className="field" style={{ width: 400, maxWidth: '100%' }}>
<MagnifyingGlassIcon style={{ width: 18, height: 18, color: 'var(--text-3)', flexShrink: 0 }} />
@@ -487,7 +492,7 @@ export default function AppointmentCreatePage() {
<>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 16, marginBottom: 10 }}>
<div>
<label style={label}>بخش</label>
<label style={label} data-tour="create-service">بخش</label>
<div style={{ marginTop: 6 }}>
<SearchableSelect
inputId="appt-section-select"
@@ -702,7 +707,7 @@ export default function AppointmentCreatePage() {
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end', paddingTop: 4 }}>
<button className="btn primary lg" disabled={!valid || create.isPending} onClick={() => create.mutate()}>
<button className="btn primary lg" data-tour="create-submit" disabled={!valid || create.isPending} onClick={() => create.mutate()}>
{create.isPending ? '...' : 'ثبت اطلاعات'}
</button>
</div>