ویزارد کار (JobWizard)
wizard چندمرحلهای canonical برای راهاندازی کارهای async — تحلیل، کمپین، ارزیابی، ایمپورت — با per-step validation، draft persistence، و finish state (submitting/success/error).
معرفی
JobWizard canonical برای ساختن فرمهای چندمرحلهای است که در پایان یک کار async را شروع میکنند — تحلیل کامنتها، راهاندازی کمپین Booster، یا ارزیابی پورتفوی. ترکیب:
useJobWizard(هوک) — مغز state: قدم فعلی، دادهها، اعتبارسنجی per-step، navigation، draft، finish lifecycle.<JobWizard>composition — لایهی presentation با stepper (StatusFlow) + header + body + footer + success panel.
چه زمانی استفاده کنیم:
- ایجاد تحلیل جدید (کامنتسنج: منبع → پیکربندی → بازبینی)
- راهاندازی کمپین Booster (پست هدف → worker → scheduling)
- افزودن پیج به پورتفوی ارزیابی (جستجو → دسته → اهداف)
- هر فرمی که state بین چند صفحه حفظ شود و در انتها یک job با احتمال خطا/تأخیر شروع کند
چه زمانی استفاده نکنیم:
- فرمهای تکمرحلهای (از
Formساده استفاده کنید) - فلوی navigation محور کاربر بدون ورودی form (از
Stepperساده استفاده کنید — JobWizard فرم میخواهد) - نمایش وضعیت یک job که از قبل شروع شده (از
StatusFlow+JobCardاستفاده کنید)
ایجاد تحلیل جدید
با این wizard یک تحلیل کامنت جدید ایجاد کنید
- منبع داده
پست اینستاگرام یا فایل اکسل
- پیکربندی تحلیل
ماژولهای فعال
- بازبینی و شروع
تأیید نهایی و ایجاد جاب
زمین بازی
با تغییر تنظیمات زیر، پیشنمایش زنده را مشاهده کنید.
منبع
انتخاب پلتفرم و بازه
- منبع
انتخاب پلتفرم و بازه
- فیلترها
هشتگ، زبان، منطقه
- تحلیل
انتخاب مدل و کیفیت
- مرور
بررسی نهایی و ارسال
الگوی مصرف
'use client'
import {
useJobWizard,
JobWizard,
JobWizardHeader,
JobWizardStepper,
JobWizardBody,
JobWizardError,
JobWizardFooter,
JobWizardBack,
JobWizardNext,
JobWizardCancel,
JobWizardSpacer,
JobWizardSuccess,
} from '@parto-system-design/ui'
interface FormData extends Record<string, unknown> {
source: 'instagram' | 'excel'
postUrl?: string
name: string
}
export function NewAnalysisWizard({ onClose }: { onClose: () => void }) {
const wizard = useJobWizard<FormData>({
steps: [
{ id: 'source', title: 'منبع', description: 'پست یا فایل' },
{ id: 'config', title: 'پیکربندی' },
{ id: 'review', title: 'بازبینی' },
],
initialData: { source: 'instagram', name: '' },
validateStep: (stepId, data) => {
if (stepId === 'source' && data.source === 'instagram' && !data.postUrl?.trim())
return { postUrl: 'URL پست الزامی است' } as Record<string, string>
if (stepId === 'review' && !data.name?.trim()) return 'نام تحلیل الزامی است'
return null
},
onSubmit: async (data) => {
const job = await fetch('/api/analyses', { method: 'POST', body: JSON.stringify(data) }).then((r) => r.json())
return job
},
onCancel: onClose,
draftKey: 'analyses:new', // persist draft
})
return (
<JobWizard wizard={wizard}>
<JobWizardHeader title="ایجاد تحلیل جدید" description="یک تحلیل کامنت جدید بسازید" />
<JobWizardStepper size="sm" />
{wizard.submitState === 'success' ? (
<JobWizardSuccess title="تحلیل شروع شد" description={`شناسه: ${wizard.submitResult?.id}`} />
) : (
<>
<JobWizardBody>{/* step content */}</JobWizardBody>
<JobWizardError />
<JobWizardFooter>
<JobWizardBack />
<JobWizardSpacer />
<JobWizardCancel />
<JobWizardNext submitLabel="شروع تحلیل" />
</JobWizardFooter>
</>
)}
</JobWizard>
)
}Layout عمودی (sidebar stepper)
پلتفرم
محتوای مرحلهی «پلتفرم»
برای wizardهای طولانی یا صفحات اختصاصی، از stepper عمودی در sidebar استفاده کنید. کافی است <JobWizardStepper orientation="vertical" /> را در یک <aside> و بقیه را در ستون کنارش بگذارید.
چرخه finish — idle / submitting / success / error
wizard.submitState چهار حالت دارد:
- idle — حالت پیشفرض. کاربر در حال پر کردن.
- submitting —
onSubmitدر حال اجراست. دکمه Next disabled + spinner. - success —
onSubmitبا موفقیت resolve شد.<JobWizardSuccess>بهصورت خودکار نمایش داده میشود. - error —
onSubmitthrow کرد.<JobWizardError>پیام خطایwizard.submitError.messageرا نشان میدهد. کاربر میتواند دوباره Next بزند.
Validation
validateStep(stepId, data) دو نوع خروجی میتواند برگرداند:
string— خطای سطح-مرحله (step-level).<JobWizardError>آن را در قالب یک بنر قرمز نشان میدهد.Record<string, string>— map از field → error. مصرفکننده خودش ارور هر field را زیرش میچسباند (wizard.errorرا object کنترل میکند).
اگر null برگردد، navigation رد میشود. validator میتواند async باشد (Promise برگرداند).
Draft persistence
- با ست کردن
draftKey، محتوایdataبهlocalStorageذخیره میشود (debounce پیشفرض 300ms). - در mount بعدی، اگر draft باشد، جایگزین
initialDataمیشود. - پس از
submitموفق، draft خودکار پاک میشود. - با
wizard.clearDraft()یاwizard.reset()هم قابل پاک کردن است.
Props و APIs
useJobWizard (هوک)
JobWizardApi (return value)
مهمترین فیلدها:
type JobWizardApi<TData> = {
currentStep: WizardStep
currentIndex: number
isFirst: boolean
isLast: boolean
steps: WizardStep[]
data: TData
setData: (data: TData) => void
update: (patch: Partial<TData>) => void
error: string | Record<string, string> | null
clearError: () => void
submitState: 'idle' | 'submitting' | 'success' | 'error'
submitResult: unknown
submitError: unknown
next: () => void
back: () => void
goToStep: (id: string) => void
submit: () => void
cancel: () => void
reset: () => void
clearDraft: () => void
isStepVisited: (id: string) => boolean
stageStatus: (step: WizardStep, index: number) => StageStatusKey
}JobWizard (component)
دکمههای نویگیشن
هر چهار دکمه (JobWizardBack, JobWizardNext, JobWizardCancel, JobWizardSkip) از variant/size/className همان Button پایه پشتیبانی میکنند:
JobWizardBack—wizard.back(). در اولین مرحله disabled.JobWizardNext—wizard.next()یا در آخرین مرحلهwizard.submit().submitLabelبرای متن سفارشی دکمهی finish. هنگامsubmittingspinner میشود.JobWizardCancel—wizard.cancel().JobWizardSkip— فقط در stepهایی کهoptional: trueدارند ظاهر میشود؛ بدون validation به مرحلهی بعد میپرد.JobWizardSpacer— div transparent باflex: 1برای push کردن گروه بعدی به end.
راهنمای استفاده
بکنید
- برای برنچینگ (مثلاً skipping یک مرحله بر اساس داده)، یک
stepsarray محاسبهشده ازReact.useMemoپاس دهید و با تغییر data تغییرش دهید — wizard خودکار سازگار میشود draftKeyرا برای wizardهای long-running حتماً ست کنید تا کاربر با reload صفحه progress از دست ندهد- در
<JobWizardSuccess>حداقل یک action primary («مشاهده وضعیت» / «رفتن به داشبورد») بدهید تا کاربر در بنبست نماند - برای خطای فیلد،
wizard.errorرا بهصورت object بازگردانید و زیر هر Input مقدار مناسب را نمایش دهید +aria-invalid
نکنید
- از
wizard.next()به صورت مستقیم همراه باwizard.submit()در یک handler استفاده نکنید —<JobWizardNext>خودش بر اساسisLastسوئیچ میکند - برای فرمهای یکمرحلهای از JobWizard استفاده نکنید — overkill است
- در
onSubmitاز دست دادنdataاصلی را در state والد قبول نکنید — wizard حق ensure میدهد ولی برای منطق رفتاری (مثل «continue in background»)، داده را خودتان cache کنید validateStepرا async بدون loading state نگذارید — کاربر کلیک میکند و نمیفهمد چرا چیزی نمیشود. حداقل در هنگام validation خیلی سریع باشید یا ازsubmittingاستفاده کنید
دسترسیپذیری
- Stepper از
StatusFlowمیآید: root<ol>باaria-current="step"روی مرحلهی فعال + aria-label ترکیبی"{title} — {status}"روی هر مرحله - مراحل بازدیدشده (با
allowJump) به<button>تبدیل میشوند؛ مراحل بعدی کلیکپذیر نیستند <JobWizardError>باrole="alert"— screen reader بلافاصله announce میکند<JobWizardSuccess>باrole="status"— screen reader موفقیت را همزمان با focus trap میشنود- دکمه Next در
submittingspinner دارد باmotion-safe:animate-spin(reduced-motion safe) - هنگام
submitting/success، دکمههای Back/Cancel disabled میشوند تا کاربر عقبگرد نکند - flow کاملاً keyboard-accessible — Tab بین فیلدها + دکمههای نویگیشن
کامپوننتهای مرتبط
- StatusFlow — زیرین برای stepper؛ JobWizard فقط یک integration است
- JobCard — بعد از submit موفق، نمایش job ایجادشده در لیست «کارهای من»
- Stepper — برای wizardهای بدون ایجاد job (مثل onboarding سبک) — state کمتر، بدون submit
- Form — برای فرمهای تکمرحلهای
- FilterPanel — الگوی مشابه composition-based root
فید فعالیت (ActionTimeline)
فید زمانی رویدادها و اقدامات — عملیات Booster، رویدادهای چرخهعمر تحلیل، لاگ audit — با markerهای وضعیتی، متادیتای نسبی/مطلق، گروهبندی روزانه، و پشتیبانی از پیشنمایش و اکشنهای inline.
کارت پست (PostCard)
نمایش یکپارچه پست از تمام پلتفرمهای سوشاللیسنینگ — اینستاگرام، توییتر، تلگرام، یوتیوب، تیکتاک، لینکدین، ترِدز — با دو چگالی فشرده و راحت، handling خودکار نسبتهای ابعادی، و اکشنهای آیکنی روی هاور.