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:
@@ -63,9 +63,11 @@ export default function DataTable<T extends object>({
|
||||
<div>
|
||||
{/* Toolbar row */}
|
||||
{(onSearchChange !== undefined || headerExtra) && (
|
||||
<div className="toolbar">
|
||||
// لنگرهای data-tour اینجا تعریف میشوند تا هر صفحهای که DataTable دارد
|
||||
// بدون تغییر کد خودش، در تور راهنما قابل اشاره باشد.
|
||||
<div className="toolbar" data-tour="page-toolbar">
|
||||
{onSearchChange !== undefined && (
|
||||
<div className="field" style={{ flex: '0 0 auto', minWidth: 240 }}>
|
||||
<div className="field" data-tour="page-search" style={{ flex: '0 0 auto', minWidth: 240 }}>
|
||||
<MagnifyingGlassIcon style={{ width: 16, height: 16, flexShrink: 0 }} />
|
||||
<input
|
||||
type="text"
|
||||
@@ -79,7 +81,7 @@ export default function DataTable<T extends object>({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="table-wrap">
|
||||
<div className="table-wrap" data-tour="page-table">
|
||||
<table className="t">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -21,9 +21,14 @@ interface Props {
|
||||
backTo?: string;
|
||||
/** شناسهٔ تور راهنمای این صفحه؛ اگر در registry ثبت نشده باشد دکمهای نمیآید. */
|
||||
tourId?: string;
|
||||
/**
|
||||
* محتوای صفحه نشسته است و تورِ بار اول میتواند خودکار اجرا شود.
|
||||
* صفحهای که دادهاش دیر میآید، `!isLoading` بدهد تا تور روی صفحهٔ نیمهساخته نیفتد.
|
||||
*/
|
||||
tourReady?: boolean;
|
||||
}
|
||||
|
||||
export default function PageHeader({ title, breadcrumbs, action, description, backTo, tourId }: Props) {
|
||||
export default function PageHeader({ title, breadcrumbs, action, description, backTo, tourId, tourReady = true }: Props) {
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, marginBottom: 24 }}>
|
||||
<div style={{ minWidth: 0 }}>
|
||||
@@ -51,15 +56,15 @@ export default function PageHeader({ title, breadcrumbs, action, description, ba
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }} data-tour="page-title">
|
||||
<h1 className="section-title">{title}</h1>
|
||||
<TourButton tourId={tourId} />
|
||||
<TourButton tourId={tourId} ready={tourReady} />
|
||||
</div>
|
||||
{description && (
|
||||
<p style={{ fontSize: 13, color: 'var(--text-3)', marginTop: 4 }}>{description}</p>
|
||||
)}
|
||||
</div>
|
||||
{action && <div style={{ flexShrink: 0 }}>{action}</div>}
|
||||
{action && <div style={{ flexShrink: 0 }} data-tour="page-action">{action}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function Pagination({ page, total, limit, onPageChange }: Props)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pagination">
|
||||
<div className="pagination" data-tour="page-pagination">
|
||||
<span style={{ fontSize: 12.5, color: 'var(--text-3)' }}>
|
||||
نمایش {formatNumber(from)}–{formatNumber(to)} از {formatNumber(total)} مورد
|
||||
</span>
|
||||
|
||||
@@ -8,17 +8,21 @@ import { getTour } from '../../lib/tour/registry';
|
||||
* وجود تور قبل از هر هوکی بررسی میشود تا صفحهای که راهنما ندارد — یعنی بیشتر
|
||||
* صفحات پنل — هیچ درخواستی برای وضعیت تورها نفرستد.
|
||||
*/
|
||||
export default function TourButton({ tourId }: { tourId?: string }) {
|
||||
export default function TourButton({ tourId, ready = false }: { tourId?: string; ready?: boolean }) {
|
||||
const tour = getTour(tourId);
|
||||
|
||||
if (!tour) return null;
|
||||
|
||||
return <TourLauncher tourId={tour.id} />;
|
||||
return <TourLauncher tourId={tour.id} ready={ready} />;
|
||||
}
|
||||
|
||||
/** اجرای خودکار وظیفهٔ خود صفحه است؛ این دکمه فقط دستی اجرا میکند. */
|
||||
function TourLauncher({ tourId }: { tourId: string }) {
|
||||
const { start } = useTour(tourId);
|
||||
/**
|
||||
* `ready` یعنی محتوای صفحه نشسته است و اجرای خودکارِ بار اول مجاز است.
|
||||
* صفحهای که دکمه را مستقیم میگذارد و آمادهبودنش را نمیداند، آن را false میگذارد
|
||||
* و تور فقط با کلیک اجرا میشود.
|
||||
*/
|
||||
function TourLauncher({ tourId, ready }: { tourId: string; ready: boolean }) {
|
||||
const { start } = useTour(tourId, { ready });
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user