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:
@@ -59,4 +59,50 @@ describe('registry', () => {
|
||||
expect(new Set(anchors).size).toBe(anchors.length);
|
||||
}
|
||||
});
|
||||
|
||||
it('متن هر استپ فارسی و غیرخالی است', () => {
|
||||
for (const tour of Object.values(TOURS)) {
|
||||
for (const step of tour.steps) {
|
||||
expect(step.title.trim().length).toBeGreaterThan(2);
|
||||
expect(step.body.trim().length).toBeGreaterThan(10);
|
||||
// متن راهنما برای کاربر فارسیزبان است؛ استپِ انگلیسیمانده یعنی جا افتاده.
|
||||
expect(step.title).toMatch(/[-ۿ]/);
|
||||
expect(step.body).toMatch(/[-ۿ]/);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* لنگرِ بیالمان بیصدا حذف میشود، پس تورِ خراب هیچ خطایی نمیدهد و فقط استپش را
|
||||
* از دست میدهد. این تست همان سکوت را میشکند: هر anchor باید در کدِ صفحات وجود
|
||||
* داشته باشد.
|
||||
*/
|
||||
describe('انطباق لنگرها با کد صفحات', () => {
|
||||
it('هیچ استپی به data-tour ناموجود اشاره نمیکند', async () => {
|
||||
// خواندن مستقیم فایلها، نه import.meta.glob: آن فقط زیر Vite کار میکند و
|
||||
// ts-loaderِ Encore همین فایل را هم type-check میکند و build را قرمز میکرد.
|
||||
const { readdirSync, readFileSync } = await import('node:fs');
|
||||
const { join } = await import('node:path');
|
||||
|
||||
const walk = (dir: string): string[] =>
|
||||
readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
||||
const path = join(dir, entry.name);
|
||||
if (entry.isDirectory()) return walk(path);
|
||||
return entry.name.endsWith('.tsx') && !entry.name.includes('.test.') ? [path] : [];
|
||||
});
|
||||
|
||||
const sources = walk('assets/admin').map((path) => readFileSync(path, 'utf8'));
|
||||
const declared = new Set(
|
||||
sources.flatMap((src) => [...src.matchAll(/data-tour="([a-z0-9-]+)"/g)].map((m) => m[1])),
|
||||
);
|
||||
|
||||
expect(declared.size).toBeGreaterThan(0);
|
||||
|
||||
const orphans = Object.values(TOURS).flatMap((tour) =>
|
||||
tour.steps.filter((s) => !declared.has(s.anchor)).map((s) => `${tour.id}:${s.anchor}`),
|
||||
);
|
||||
|
||||
expect(orphans).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user