@patricio0312rev/skillset 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/bin/cli.js +37 -0
- package/package.json +55 -0
- package/src/commands/init.js +301 -0
- package/src/index.js +168 -0
- package/src/lib/config.js +200 -0
- package/src/lib/generator.js +166 -0
- package/src/utils/display.js +95 -0
- package/src/utils/readme.js +196 -0
- package/src/utils/tool-specific.js +233 -0
- package/templates/ai-engineering/agent-orchestration-planner/ SKILL.md +266 -0
- package/templates/ai-engineering/cost-latency-optimizer/ SKILL.md +270 -0
- package/templates/ai-engineering/doc-to-vector-dataset-generator/ SKILL.md +239 -0
- package/templates/ai-engineering/evaluation-harness/ SKILL.md +219 -0
- package/templates/ai-engineering/guardrails-safety-filter-builder/ SKILL.md +226 -0
- package/templates/ai-engineering/llm-debugger/ SKILL.md +283 -0
- package/templates/ai-engineering/prompt-regression-tester/ SKILL.md +216 -0
- package/templates/ai-engineering/prompt-template-builder/ SKILL.md +393 -0
- package/templates/ai-engineering/rag-pipeline-builder/ SKILL.md +244 -0
- package/templates/ai-engineering/tool-function-schema-designer/ SKILL.md +219 -0
- package/templates/architecture/adr-writer/ SKILL.md +250 -0
- package/templates/architecture/api-versioning-deprecation-planner/ SKILL.md +331 -0
- package/templates/architecture/domain-model-boundaries-mapper/ SKILL.md +300 -0
- package/templates/architecture/migration-planner/ SKILL.md +376 -0
- package/templates/architecture/performance-budget-setter/ SKILL.md +318 -0
- package/templates/architecture/reliability-strategy-builder/ SKILL.md +286 -0
- package/templates/architecture/rfc-generator/ SKILL.md +362 -0
- package/templates/architecture/scalability-playbook/ SKILL.md +279 -0
- package/templates/architecture/system-design-generator/ SKILL.md +339 -0
- package/templates/architecture/tech-debt-prioritizer/ SKILL.md +329 -0
- package/templates/backend/api-contract-normalizer/ SKILL.md +487 -0
- package/templates/backend/api-endpoint-generator/ SKILL.md +415 -0
- package/templates/backend/auth-module-builder/ SKILL.md +99 -0
- package/templates/backend/background-jobs-designer/ SKILL.md +166 -0
- package/templates/backend/caching-strategist/ SKILL.md +190 -0
- package/templates/backend/error-handling-standardizer/ SKILL.md +174 -0
- package/templates/backend/rate-limiting-abuse-protection/ SKILL.md +147 -0
- package/templates/backend/rbac-permissions-builder/ SKILL.md +158 -0
- package/templates/backend/service-layer-extractor/ SKILL.md +269 -0
- package/templates/backend/webhook-receiver-hardener/ SKILL.md +211 -0
- package/templates/ci-cd/artifact-sbom-publisher/ SKILL.md +236 -0
- package/templates/ci-cd/caching-strategy-optimizer/ SKILL.md +195 -0
- package/templates/ci-cd/deployment-checklist-generator/ SKILL.md +381 -0
- package/templates/ci-cd/github-actions-pipeline-creator/ SKILL.md +348 -0
- package/templates/ci-cd/monorepo-ci-optimizer/ SKILL.md +298 -0
- package/templates/ci-cd/preview-environments-builder/ SKILL.md +187 -0
- package/templates/ci-cd/quality-gates-enforcer/ SKILL.md +342 -0
- package/templates/ci-cd/release-automation-builder/ SKILL.md +281 -0
- package/templates/ci-cd/rollback-workflow-builder/ SKILL.md +372 -0
- package/templates/ci-cd/secrets-env-manager/ SKILL.md +242 -0
- package/templates/db-management/backup-restore-runbook-generator/ SKILL.md +505 -0
- package/templates/db-management/data-integrity-auditor/ SKILL.md +505 -0
- package/templates/db-management/data-retention-archiving-planner/ SKILL.md +430 -0
- package/templates/db-management/data-seeding-fixtures-builder/ SKILL.md +375 -0
- package/templates/db-management/db-performance-watchlist/ SKILL.md +425 -0
- package/templates/db-management/etl-sync-job-builder/ SKILL.md +457 -0
- package/templates/db-management/multi-tenant-safety-checker/ SKILL.md +398 -0
- package/templates/db-management/prisma-migration-assistant/ SKILL.md +379 -0
- package/templates/db-management/schema-consistency-checker/ SKILL.md +440 -0
- package/templates/db-management/sql-query-optimizer/ SKILL.md +324 -0
- package/templates/foundation/changelog-writer/ SKILL.md +431 -0
- package/templates/foundation/code-formatter-installer/ SKILL.md +320 -0
- package/templates/foundation/codebase-summarizer/ SKILL.md +360 -0
- package/templates/foundation/dependency-doctor/ SKILL.md +163 -0
- package/templates/foundation/dev-environment-bootstrapper/ SKILL.md +259 -0
- package/templates/foundation/dev-onboarding-builder/ SKILL.md +556 -0
- package/templates/foundation/docs-starter-kit/ SKILL.md +574 -0
- package/templates/foundation/explaining-code/SKILL.md +13 -0
- package/templates/foundation/git-hygiene-enforcer/ SKILL.md +455 -0
- package/templates/foundation/project-scaffolder/ SKILL.md +65 -0
- package/templates/foundation/project-scaffolder/references/templates.md +126 -0
- package/templates/foundation/repo-structure-linter/ SKILL.md +0 -0
- package/templates/foundation/repo-structure-linter/references/conventions.md +98 -0
- package/templates/frontend/animation-micro-interaction-pack/ SKILL.md +41 -0
- package/templates/frontend/component-scaffold-generator/ SKILL.md +562 -0
- package/templates/frontend/design-to-component-translator/ SKILL.md +547 -0
- package/templates/frontend/form-wizard-builder/ SKILL.md +553 -0
- package/templates/frontend/frontend-refactor-planner/ SKILL.md +37 -0
- package/templates/frontend/i18n-frontend-implementer/ SKILL.md +44 -0
- package/templates/frontend/modal-drawer-system/ SKILL.md +377 -0
- package/templates/frontend/page-layout-builder/ SKILL.md +630 -0
- package/templates/frontend/state-ux-flow-builder/ SKILL.md +23 -0
- package/templates/frontend/table-builder/ SKILL.md +350 -0
- package/templates/performance/alerting-dashboard-builder/ SKILL.md +162 -0
- package/templates/performance/backend-latency-profiler-helper/ SKILL.md +108 -0
- package/templates/performance/caching-cdn-strategy-planner/ SKILL.md +150 -0
- package/templates/performance/capacity-planning-helper/ SKILL.md +242 -0
- package/templates/performance/core-web-vitals-tuner/ SKILL.md +126 -0
- package/templates/performance/incident-runbook-generator/ SKILL.md +162 -0
- package/templates/performance/load-test-scenario-builder/ SKILL.md +256 -0
- package/templates/performance/observability-setup/ SKILL.md +232 -0
- package/templates/performance/postmortem-writer/ SKILL.md +203 -0
- package/templates/performance/structured-logging-standardizer/ SKILL.md +122 -0
- package/templates/security/auth-security-reviewer/ SKILL.md +428 -0
- package/templates/security/dependency-vulnerability-triage/ SKILL.md +495 -0
- package/templates/security/input-validation-sanitization-auditor/ SKILL.md +76 -0
- package/templates/security/pii-redaction-logging-policy-builder/ SKILL.md +65 -0
- package/templates/security/rbac-policy-tester/ SKILL.md +80 -0
- package/templates/security/secrets-scanner/ SKILL.md +462 -0
- package/templates/security/secure-headers-csp-builder/ SKILL.md +404 -0
- package/templates/security/security-incident-playbook-generator/ SKILL.md +76 -0
- package/templates/security/security-pr-checklist-skill/ SKILL.md +62 -0
- package/templates/security/threat-model-generator/ SKILL.md +394 -0
- package/templates/testing/contract-testing-builder/ SKILL.md +492 -0
- package/templates/testing/coverage-strategist/ SKILL.md +436 -0
- package/templates/testing/e2e-test-builder/ SKILL.md +382 -0
- package/templates/testing/flaky-test-detective/ SKILL.md +416 -0
- package/templates/testing/integration-test-builder/ SKILL.md +525 -0
- package/templates/testing/mocking-assistant/ SKILL.md +383 -0
- package/templates/testing/snapshot-test-refactorer/ SKILL.md +375 -0
- package/templates/testing/test-data-factory-builder/ SKILL.md +449 -0
- package/templates/testing/test-reporting-triage-skill/ SKILL.md +469 -0
- package/templates/testing/unit-test-generator/ SKILL.md +548 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: form-wizard-builder
|
|
3
|
+
description: Builds multi-step forms with validation schemas (Zod/Yup), step components, shared state management, progress indicators, review steps, and error handling. Use when creating "multi-step forms", "wizard flows", "onboarding forms", or "checkout processes".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Form Wizard Builder
|
|
7
|
+
|
|
8
|
+
Create multi-step form experiences with validation, state persistence, and review steps.
|
|
9
|
+
|
|
10
|
+
## Core Workflow
|
|
11
|
+
|
|
12
|
+
1. **Define steps**: Break form into logical sections
|
|
13
|
+
2. **Create schema**: Zod/Yup validation for each step
|
|
14
|
+
3. **Build step components**: Individual form sections
|
|
15
|
+
4. **State management**: Shared state across steps (Zustand/Context)
|
|
16
|
+
5. **Navigation**: Next/Back/Skip logic
|
|
17
|
+
6. **Progress indicator**: Visual step tracker
|
|
18
|
+
7. **Review step**: Summary before submission
|
|
19
|
+
8. **Error handling**: Per-step and final validation
|
|
20
|
+
|
|
21
|
+
## Basic Wizard Structure
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// types/wizard.ts
|
|
25
|
+
export type WizardStep = {
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
component: React.ComponentType<StepProps>;
|
|
30
|
+
schema: z.ZodSchema;
|
|
31
|
+
isOptional?: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type WizardData = {
|
|
35
|
+
personal: PersonalInfoData;
|
|
36
|
+
contact: ContactData;
|
|
37
|
+
preferences: PreferencesData;
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Validation Schemas (Zod)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// schemas/wizard.schema.ts
|
|
45
|
+
import { z } from "zod";
|
|
46
|
+
|
|
47
|
+
export const personalInfoSchema = z.object({
|
|
48
|
+
firstName: z.string().min(2, "First name must be at least 2 characters"),
|
|
49
|
+
lastName: z.string().min(2, "Last name must be at least 2 characters"),
|
|
50
|
+
dateOfBirth: z.string().refine((date) => {
|
|
51
|
+
const age = new Date().getFullYear() - new Date(date).getFullYear();
|
|
52
|
+
return age >= 18;
|
|
53
|
+
}, "Must be at least 18 years old"),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const contactSchema = z.object({
|
|
57
|
+
email: z.string().email("Invalid email address"),
|
|
58
|
+
phone: z.string().regex(/^\+?[\d\s-()]+$/, "Invalid phone number"),
|
|
59
|
+
address: z.object({
|
|
60
|
+
street: z.string().min(1, "Street is required"),
|
|
61
|
+
city: z.string().min(1, "City is required"),
|
|
62
|
+
zipCode: z.string().regex(/^\d{5}(-\d{4})?$/, "Invalid ZIP code"),
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export const preferencesSchema = z.object({
|
|
67
|
+
notifications: z.object({
|
|
68
|
+
email: z.boolean(),
|
|
69
|
+
sms: z.boolean(),
|
|
70
|
+
push: z.boolean(),
|
|
71
|
+
}),
|
|
72
|
+
interests: z.array(z.string()).min(1, "Select at least one interest"),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Complete wizard schema
|
|
76
|
+
export const wizardSchema = z.object({
|
|
77
|
+
personal: personalInfoSchema,
|
|
78
|
+
contact: contactSchema,
|
|
79
|
+
preferences: preferencesSchema,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export type WizardFormData = z.infer<typeof wizardSchema>;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## State Management (Zustand)
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// stores/wizard.store.ts
|
|
89
|
+
import { create } from "zustand";
|
|
90
|
+
import { persist } from "zustand/middleware";
|
|
91
|
+
|
|
92
|
+
interface WizardState {
|
|
93
|
+
currentStep: number;
|
|
94
|
+
data: Partial<WizardFormData>;
|
|
95
|
+
completedSteps: number[];
|
|
96
|
+
isSubmitting: boolean;
|
|
97
|
+
|
|
98
|
+
setCurrentStep: (step: number) => void;
|
|
99
|
+
updateStepData: (step: string, data: any) => void;
|
|
100
|
+
markStepComplete: (step: number) => void;
|
|
101
|
+
nextStep: () => void;
|
|
102
|
+
prevStep: () => void;
|
|
103
|
+
resetWizard: () => void;
|
|
104
|
+
submitWizard: () => Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const useWizardStore = create<WizardState>()(
|
|
108
|
+
persist(
|
|
109
|
+
(set, get) => ({
|
|
110
|
+
currentStep: 0,
|
|
111
|
+
data: {},
|
|
112
|
+
completedSteps: [],
|
|
113
|
+
isSubmitting: false,
|
|
114
|
+
|
|
115
|
+
setCurrentStep: (step) => set({ currentStep: step }),
|
|
116
|
+
|
|
117
|
+
updateStepData: (step, newData) =>
|
|
118
|
+
set((state) => ({
|
|
119
|
+
data: {
|
|
120
|
+
...state.data,
|
|
121
|
+
[step]: { ...state.data[step], ...newData },
|
|
122
|
+
},
|
|
123
|
+
})),
|
|
124
|
+
|
|
125
|
+
markStepComplete: (step) =>
|
|
126
|
+
set((state) => ({
|
|
127
|
+
completedSteps: Array.from(new Set([...state.completedSteps, step])),
|
|
128
|
+
})),
|
|
129
|
+
|
|
130
|
+
nextStep: () =>
|
|
131
|
+
set((state) => ({
|
|
132
|
+
currentStep: Math.min(state.currentStep + 1, steps.length - 1),
|
|
133
|
+
})),
|
|
134
|
+
|
|
135
|
+
prevStep: () =>
|
|
136
|
+
set((state) => ({
|
|
137
|
+
currentStep: Math.max(state.currentStep - 1, 0),
|
|
138
|
+
})),
|
|
139
|
+
|
|
140
|
+
resetWizard: () =>
|
|
141
|
+
set({
|
|
142
|
+
currentStep: 0,
|
|
143
|
+
data: {},
|
|
144
|
+
completedSteps: [],
|
|
145
|
+
isSubmitting: false,
|
|
146
|
+
}),
|
|
147
|
+
|
|
148
|
+
submitWizard: async () => {
|
|
149
|
+
set({ isSubmitting: true });
|
|
150
|
+
try {
|
|
151
|
+
// Submit to API
|
|
152
|
+
await fetch("/api/wizard", {
|
|
153
|
+
method: "POST",
|
|
154
|
+
body: JSON.stringify(get().data),
|
|
155
|
+
});
|
|
156
|
+
get().resetWizard();
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error("Submission failed:", error);
|
|
159
|
+
} finally {
|
|
160
|
+
set({ isSubmitting: false });
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
164
|
+
{
|
|
165
|
+
name: "wizard-storage",
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Main Wizard Component
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// components/Wizard.tsx
|
|
175
|
+
"use client";
|
|
176
|
+
|
|
177
|
+
import { useState } from "react";
|
|
178
|
+
import { useWizardStore } from "@/stores/wizard.store";
|
|
179
|
+
import { ProgressIndicator } from "./ProgressIndicator";
|
|
180
|
+
import { PersonalInfoStep } from "./steps/PersonalInfoStep";
|
|
181
|
+
import { ContactStep } from "./steps/ContactStep";
|
|
182
|
+
import { PreferencesStep } from "./steps/PreferencesStep";
|
|
183
|
+
import { ReviewStep } from "./steps/ReviewStep";
|
|
184
|
+
|
|
185
|
+
const steps = [
|
|
186
|
+
{
|
|
187
|
+
id: "personal",
|
|
188
|
+
title: "Personal Information",
|
|
189
|
+
component: PersonalInfoStep,
|
|
190
|
+
schema: personalInfoSchema,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: "contact",
|
|
194
|
+
title: "Contact Details",
|
|
195
|
+
component: ContactStep,
|
|
196
|
+
schema: contactSchema,
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: "preferences",
|
|
200
|
+
title: "Preferences",
|
|
201
|
+
component: PreferencesStep,
|
|
202
|
+
schema: preferencesSchema,
|
|
203
|
+
isOptional: true,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: "review",
|
|
207
|
+
title: "Review",
|
|
208
|
+
component: ReviewStep,
|
|
209
|
+
schema: z.any(),
|
|
210
|
+
},
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
export function Wizard() {
|
|
214
|
+
const { currentStep } = useWizardStore();
|
|
215
|
+
const CurrentStepComponent = steps[currentStep].component;
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<div className="mx-auto max-w-2xl space-y-8 p-6">
|
|
219
|
+
<ProgressIndicator steps={steps} currentStep={currentStep} />
|
|
220
|
+
|
|
221
|
+
<div className="rounded-lg border bg-white p-8 shadow-sm">
|
|
222
|
+
<div className="mb-6">
|
|
223
|
+
<h2 className="text-2xl font-bold">{steps[currentStep].title}</h2>
|
|
224
|
+
{steps[currentStep].description && (
|
|
225
|
+
<p className="text-gray-600">{steps[currentStep].description}</p>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
<CurrentStepComponent />
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Progress Indicator
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// components/ProgressIndicator.tsx
|
|
240
|
+
import { cn } from "@/lib/utils";
|
|
241
|
+
import { CheckIcon } from "@/components/icons";
|
|
242
|
+
|
|
243
|
+
interface ProgressIndicatorProps {
|
|
244
|
+
steps: Array<{ id: string; title: string }>;
|
|
245
|
+
currentStep: number;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function ProgressIndicator({
|
|
249
|
+
steps,
|
|
250
|
+
currentStep,
|
|
251
|
+
}: ProgressIndicatorProps) {
|
|
252
|
+
return (
|
|
253
|
+
<nav aria-label="Progress">
|
|
254
|
+
<ol className="flex items-center justify-between">
|
|
255
|
+
{steps.map((step, index) => {
|
|
256
|
+
const isComplete = index < currentStep;
|
|
257
|
+
const isCurrent = index === currentStep;
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
<li key={step.id} className="flex flex-1 items-center">
|
|
261
|
+
<div className="flex flex-col items-center">
|
|
262
|
+
<div
|
|
263
|
+
className={cn(
|
|
264
|
+
"flex h-10 w-10 items-center justify-center rounded-full border-2",
|
|
265
|
+
isComplete && "border-primary-500 bg-primary-500",
|
|
266
|
+
isCurrent && "border-primary-500 bg-white",
|
|
267
|
+
!isComplete && !isCurrent && "border-gray-300 bg-white"
|
|
268
|
+
)}
|
|
269
|
+
>
|
|
270
|
+
{isComplete ? (
|
|
271
|
+
<CheckIcon className="h-5 w-5 text-white" />
|
|
272
|
+
) : (
|
|
273
|
+
<span
|
|
274
|
+
className={cn(
|
|
275
|
+
"text-sm font-medium",
|
|
276
|
+
isCurrent ? "text-primary-500" : "text-gray-500"
|
|
277
|
+
)}
|
|
278
|
+
>
|
|
279
|
+
{index + 1}
|
|
280
|
+
</span>
|
|
281
|
+
)}
|
|
282
|
+
</div>
|
|
283
|
+
<span
|
|
284
|
+
className={cn(
|
|
285
|
+
"mt-2 text-sm font-medium",
|
|
286
|
+
isCurrent ? "text-primary-500" : "text-gray-500"
|
|
287
|
+
)}
|
|
288
|
+
>
|
|
289
|
+
{step.title}
|
|
290
|
+
</span>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
{index < steps.length - 1 && (
|
|
294
|
+
<div
|
|
295
|
+
className={cn(
|
|
296
|
+
"mx-4 h-0.5 flex-1",
|
|
297
|
+
isComplete ? "bg-primary-500" : "bg-gray-300"
|
|
298
|
+
)}
|
|
299
|
+
/>
|
|
300
|
+
)}
|
|
301
|
+
</li>
|
|
302
|
+
);
|
|
303
|
+
})}
|
|
304
|
+
</ol>
|
|
305
|
+
</nav>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Step Component Example
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// components/steps/PersonalInfoStep.tsx
|
|
314
|
+
"use client";
|
|
315
|
+
|
|
316
|
+
import { useForm } from "react-hook-form";
|
|
317
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
318
|
+
import { useWizardStore } from "@/stores/wizard.store";
|
|
319
|
+
import { personalInfoSchema } from "@/schemas/wizard.schema";
|
|
320
|
+
import { Button } from "@/components/ui/button";
|
|
321
|
+
import { Input } from "@/components/ui/input";
|
|
322
|
+
import { Label } from "@/components/ui/label";
|
|
323
|
+
|
|
324
|
+
export function PersonalInfoStep() {
|
|
325
|
+
const { data, updateStepData, markStepComplete, nextStep } = useWizardStore();
|
|
326
|
+
|
|
327
|
+
const {
|
|
328
|
+
register,
|
|
329
|
+
handleSubmit,
|
|
330
|
+
formState: { errors },
|
|
331
|
+
} = useForm({
|
|
332
|
+
resolver: zodResolver(personalInfoSchema),
|
|
333
|
+
defaultValues: data.personal || {},
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const onSubmit = (formData: any) => {
|
|
337
|
+
updateStepData("personal", formData);
|
|
338
|
+
markStepComplete(0);
|
|
339
|
+
nextStep();
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
|
344
|
+
<div className="space-y-4">
|
|
345
|
+
<div className="grid gap-4 sm:grid-cols-2">
|
|
346
|
+
<div className="space-y-2">
|
|
347
|
+
<Label htmlFor="firstName">First Name</Label>
|
|
348
|
+
<Input
|
|
349
|
+
id="firstName"
|
|
350
|
+
{...register("firstName")}
|
|
351
|
+
error={errors.firstName?.message}
|
|
352
|
+
/>
|
|
353
|
+
</div>
|
|
354
|
+
|
|
355
|
+
<div className="space-y-2">
|
|
356
|
+
<Label htmlFor="lastName">Last Name</Label>
|
|
357
|
+
<Input
|
|
358
|
+
id="lastName"
|
|
359
|
+
{...register("lastName")}
|
|
360
|
+
error={errors.lastName?.message}
|
|
361
|
+
/>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
|
|
365
|
+
<div className="space-y-2">
|
|
366
|
+
<Label htmlFor="dateOfBirth">Date of Birth</Label>
|
|
367
|
+
<Input
|
|
368
|
+
id="dateOfBirth"
|
|
369
|
+
type="date"
|
|
370
|
+
{...register("dateOfBirth")}
|
|
371
|
+
error={errors.dateOfBirth?.message}
|
|
372
|
+
/>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<div className="flex justify-end">
|
|
377
|
+
<Button type="submit">Next Step</Button>
|
|
378
|
+
</div>
|
|
379
|
+
</form>
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Review Step
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
// components/steps/ReviewStep.tsx
|
|
388
|
+
"use client";
|
|
389
|
+
|
|
390
|
+
import { useWizardStore } from "@/stores/wizard.store";
|
|
391
|
+
import { Button } from "@/components/ui/button";
|
|
392
|
+
import { Card } from "@/components/ui/card";
|
|
393
|
+
|
|
394
|
+
export function ReviewStep() {
|
|
395
|
+
const { data, isSubmitting, submitWizard, setCurrentStep } = useWizardStore();
|
|
396
|
+
|
|
397
|
+
return (
|
|
398
|
+
<div className="space-y-6">
|
|
399
|
+
<Card className="p-6">
|
|
400
|
+
<div className="mb-4 flex items-center justify-between">
|
|
401
|
+
<h3 className="text-lg font-semibold">Personal Information</h3>
|
|
402
|
+
<Button variant="ghost" size="sm" onClick={() => setCurrentStep(0)}>
|
|
403
|
+
Edit
|
|
404
|
+
</Button>
|
|
405
|
+
</div>
|
|
406
|
+
<dl className="space-y-2">
|
|
407
|
+
<div className="flex justify-between">
|
|
408
|
+
<dt className="text-gray-600">Name:</dt>
|
|
409
|
+
<dd className="font-medium">
|
|
410
|
+
{data.personal?.firstName} {data.personal?.lastName}
|
|
411
|
+
</dd>
|
|
412
|
+
</div>
|
|
413
|
+
<div className="flex justify-between">
|
|
414
|
+
<dt className="text-gray-600">Date of Birth:</dt>
|
|
415
|
+
<dd className="font-medium">{data.personal?.dateOfBirth}</dd>
|
|
416
|
+
</div>
|
|
417
|
+
</dl>
|
|
418
|
+
</Card>
|
|
419
|
+
|
|
420
|
+
<Card className="p-6">
|
|
421
|
+
<div className="mb-4 flex items-center justify-between">
|
|
422
|
+
<h3 className="text-lg font-semibold">Contact Details</h3>
|
|
423
|
+
<Button variant="ghost" size="sm" onClick={() => setCurrentStep(1)}>
|
|
424
|
+
Edit
|
|
425
|
+
</Button>
|
|
426
|
+
</div>
|
|
427
|
+
<dl className="space-y-2">
|
|
428
|
+
<div className="flex justify-between">
|
|
429
|
+
<dt className="text-gray-600">Email:</dt>
|
|
430
|
+
<dd className="font-medium">{data.contact?.email}</dd>
|
|
431
|
+
</div>
|
|
432
|
+
<div className="flex justify-between">
|
|
433
|
+
<dt className="text-gray-600">Phone:</dt>
|
|
434
|
+
<dd className="font-medium">{data.contact?.phone}</dd>
|
|
435
|
+
</div>
|
|
436
|
+
</dl>
|
|
437
|
+
</Card>
|
|
438
|
+
|
|
439
|
+
<div className="flex justify-between">
|
|
440
|
+
<Button
|
|
441
|
+
variant="outline"
|
|
442
|
+
onClick={() => setCurrentStep((prev) => prev - 1)}
|
|
443
|
+
>
|
|
444
|
+
Back
|
|
445
|
+
</Button>
|
|
446
|
+
<Button onClick={submitWizard} isLoading={isSubmitting}>
|
|
447
|
+
Submit Application
|
|
448
|
+
</Button>
|
|
449
|
+
</div>
|
|
450
|
+
</div>
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## Navigation Controls
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// components/WizardNavigation.tsx
|
|
459
|
+
interface WizardNavigationProps {
|
|
460
|
+
onNext?: () => void;
|
|
461
|
+
onPrev?: () => void;
|
|
462
|
+
onSkip?: () => void;
|
|
463
|
+
isFirstStep: boolean;
|
|
464
|
+
isLastStep: boolean;
|
|
465
|
+
isOptional?: boolean;
|
|
466
|
+
nextLabel?: string;
|
|
467
|
+
prevLabel?: string;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export function WizardNavigation({
|
|
471
|
+
onNext,
|
|
472
|
+
onPrev,
|
|
473
|
+
onSkip,
|
|
474
|
+
isFirstStep,
|
|
475
|
+
isLastStep,
|
|
476
|
+
isOptional,
|
|
477
|
+
nextLabel = "Next",
|
|
478
|
+
prevLabel = "Back",
|
|
479
|
+
}: WizardNavigationProps) {
|
|
480
|
+
return (
|
|
481
|
+
<div className="flex items-center justify-between">
|
|
482
|
+
<div>
|
|
483
|
+
{!isFirstStep && (
|
|
484
|
+
<Button variant="outline" onClick={onPrev}>
|
|
485
|
+
{prevLabel}
|
|
486
|
+
</Button>
|
|
487
|
+
)}
|
|
488
|
+
</div>
|
|
489
|
+
|
|
490
|
+
<div className="flex gap-2">
|
|
491
|
+
{isOptional && (
|
|
492
|
+
<Button variant="ghost" onClick={onSkip}>
|
|
493
|
+
Skip
|
|
494
|
+
</Button>
|
|
495
|
+
)}
|
|
496
|
+
<Button onClick={onNext}>{isLastStep ? "Submit" : nextLabel}</Button>
|
|
497
|
+
</div>
|
|
498
|
+
</div>
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## Persistence (LocalStorage)
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
// hooks/useWizardPersistence.ts
|
|
507
|
+
import { useEffect } from "react";
|
|
508
|
+
import { useWizardStore } from "@/stores/wizard.store";
|
|
509
|
+
|
|
510
|
+
export function useWizardPersistence() {
|
|
511
|
+
const { data, currentStep } = useWizardStore();
|
|
512
|
+
|
|
513
|
+
// Auto-save to localStorage
|
|
514
|
+
useEffect(() => {
|
|
515
|
+
localStorage.setItem("wizard-data", JSON.stringify(data));
|
|
516
|
+
localStorage.setItem("wizard-step", String(currentStep));
|
|
517
|
+
}, [data, currentStep]);
|
|
518
|
+
|
|
519
|
+
// Load on mount
|
|
520
|
+
useEffect(() => {
|
|
521
|
+
const savedData = localStorage.getItem("wizard-data");
|
|
522
|
+
const savedStep = localStorage.getItem("wizard-step");
|
|
523
|
+
|
|
524
|
+
if (savedData) {
|
|
525
|
+
// Restore state
|
|
526
|
+
}
|
|
527
|
+
}, []);
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## Best Practices
|
|
532
|
+
|
|
533
|
+
1. **Validate per step**: Don't wait until end
|
|
534
|
+
2. **Save progress**: Persist to localStorage/server
|
|
535
|
+
3. **Allow navigation**: Let users go back and edit
|
|
536
|
+
4. **Show progress**: Clear visual indicator
|
|
537
|
+
5. **Review before submit**: Summary step is crucial
|
|
538
|
+
6. **Handle errors gracefully**: Show which step has errors
|
|
539
|
+
7. **Mobile responsive**: Stack progress on mobile
|
|
540
|
+
8. **Accessibility**: Keyboard navigation, ARIA labels
|
|
541
|
+
|
|
542
|
+
## Output Checklist
|
|
543
|
+
|
|
544
|
+
- [ ] Step definitions with schemas
|
|
545
|
+
- [ ] Validation with Zod/Yup
|
|
546
|
+
- [ ] State management (Zustand/Context)
|
|
547
|
+
- [ ] Progress indicator component
|
|
548
|
+
- [ ] Individual step components
|
|
549
|
+
- [ ] Navigation controls (Next/Back/Skip)
|
|
550
|
+
- [ ] Review/summary step
|
|
551
|
+
- [ ] Error handling per step
|
|
552
|
+
- [ ] Persistence mechanism
|
|
553
|
+
- [ ] Mobile-responsive design
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-refactor-planner
|
|
3
|
+
description: Creates safe refactor plans for messy UI code including component splitting strategies, state simplification, performance optimizations, and accessibility improvements. Provides phased approach, risk assessment, and "done" criteria. Use when refactoring "legacy code", "messy components", "performance issues", or "large files".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Frontend Refactor Planner
|
|
7
|
+
|
|
8
|
+
Create safe, phased refactor plans for complex frontend code.
|
|
9
|
+
|
|
10
|
+
## Refactor Assessment
|
|
11
|
+
|
|
12
|
+
**Identify Issues**: Large components (>300 lines), prop drilling, duplicate logic, poor performance, accessibility gaps, tight coupling, untested code
|
|
13
|
+
**Prioritize**: By risk (high-traffic pages first) and impact (user-facing bugs prioritized)
|
|
14
|
+
**Plan Phases**: Break into small, testable increments
|
|
15
|
+
|
|
16
|
+
## Common Refactor Patterns
|
|
17
|
+
|
|
18
|
+
**Component Splitting**: Extract sub-components, create compound components, separate logic from presentation
|
|
19
|
+
**State Management**: Lift state up, move to Context/Zustand, remove unnecessary state
|
|
20
|
+
**Performance**: Memoization (useMemo/useCallback), code splitting, lazy loading, virtualization
|
|
21
|
+
**Accessibility**: Add ARIA labels, keyboard navigation, focus management, semantic HTML
|
|
22
|
+
**Testing**: Add tests before refactoring, test after each change
|
|
23
|
+
|
|
24
|
+
## Phased Approach
|
|
25
|
+
|
|
26
|
+
**Phase 1 - Stabilize**: Add tests, fix critical bugs, document current behavior
|
|
27
|
+
**Phase 2 - Extract**: Pull out utilities, create smaller components, reduce complexity
|
|
28
|
+
**Phase 3 - Simplify**: Remove dead code, consolidate duplicates, optimize state
|
|
29
|
+
**Phase 4 - Polish**: Performance optimization, accessibility audit, documentation
|
|
30
|
+
|
|
31
|
+
## Risk Mitigation
|
|
32
|
+
|
|
33
|
+
Feature flags for gradual rollout, A/B testing refactored vs original, monitor error rates, have rollback plan, peer review all changes, incremental deployment.
|
|
34
|
+
|
|
35
|
+
## Done Criteria
|
|
36
|
+
|
|
37
|
+
Code coverage >80%, performance metrics improved, accessibility score 95+, no regressions in tests, code review approved, documentation updated.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: i18n-frontend-implementer
|
|
3
|
+
description: Adds internationalization (i18n) infrastructure with translation plumbing, scalable key strategy, formatters for dates/numbers/currency, plural rules, and language switching. Use when implementing "internationalization", "translations", "multi-language support", or "i18n".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# i18n Frontend Implementer
|
|
7
|
+
|
|
8
|
+
Implement internationalization with next-intl, react-i18next, or similar libraries.
|
|
9
|
+
|
|
10
|
+
## Core Setup
|
|
11
|
+
|
|
12
|
+
**1. Install**: `npm install next-intl` or `react-i18next`
|
|
13
|
+
**2. Create dictionaries**: `locales/en.json`, `locales/es.json`
|
|
14
|
+
**3. Provider setup**: Wrap app with IntlProvider
|
|
15
|
+
**4. Translation keys**: Hierarchical namespace structure
|
|
16
|
+
**5. Formatters**: Date, number, currency formatting
|
|
17
|
+
**6. Language switcher**: Dropdown or flags UI
|
|
18
|
+
|
|
19
|
+
## Translation Structure
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"common": { "nav": { "home": "Home", "about": "About" } },
|
|
24
|
+
"auth": { "login": "Sign In", "logout": "Sign Out" },
|
|
25
|
+
"errors": { "required": "{field} is required" }
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage Examples
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
const t = useTranslations('common');
|
|
33
|
+
<h1>{t('nav.home')}</h1>
|
|
34
|
+
|
|
35
|
+
// With plurals
|
|
36
|
+
t('items', { count: 5 }) // "5 items"
|
|
37
|
+
|
|
38
|
+
// With formatting
|
|
39
|
+
<p>{formatDate(date, { dateStyle: 'long' })}</p>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Best Practices
|
|
43
|
+
|
|
44
|
+
Use namespaces for organization, extract all text to translations, handle plurals properly, format dates/numbers per locale, provide language switcher, support RTL languages, lazy-load translations.
|