@umituz/web-dashboard 2.0.6 → 2.0.8
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/package.json +35 -77
- package/src/domains/layouts/components/BrandLogo.tsx +83 -0
- package/src/domains/layouts/components/DashboardHeader.tsx +240 -0
- package/src/domains/layouts/components/DashboardLayout.tsx +155 -0
- package/src/domains/layouts/components/DashboardSidebar.tsx +152 -0
- package/src/domains/layouts/components/index.ts +8 -0
- package/src/domains/layouts/hooks/dashboard.ts +81 -0
- package/src/domains/layouts/hooks/index.ts +8 -0
- package/src/domains/layouts/index.ts +11 -0
- package/{dist/layouts/theme/default.js → src/domains/layouts/theme/default.ts} +18 -11
- package/src/domains/layouts/theme/index.ts +18 -0
- package/src/domains/layouts/theme/presets.ts +96 -0
- package/src/domains/layouts/theme/utils.ts +67 -0
- package/src/domains/layouts/types/index.ts +9 -0
- package/src/domains/layouts/types/layout.ts +43 -0
- package/src/domains/layouts/types/notification.ts +19 -0
- package/src/domains/layouts/types/sidebar.ts +35 -0
- package/src/domains/layouts/types/theme.ts +64 -0
- package/src/domains/layouts/types/user.ts +35 -0
- package/src/domains/layouts/utils/dashboard.ts +96 -0
- package/src/domains/layouts/utils/index.ts +11 -0
- package/src/domains/onboarding/components/AppFocusStep.tsx +113 -0
- package/src/domains/onboarding/components/OnboardingWizard.tsx +262 -0
- package/src/domains/onboarding/components/PlanStep.tsx +208 -0
- package/src/domains/onboarding/components/PlatformsStep.tsx +109 -0
- package/src/domains/onboarding/components/UserTypeStep.tsx +135 -0
- package/src/domains/onboarding/components/index.ts +9 -0
- package/src/domains/onboarding/hooks/index.ts +5 -0
- package/{dist/onboarding/hooks/index.js → src/domains/onboarding/hooks/useOnboarding.ts} +65 -19
- package/src/domains/onboarding/index.ts +35 -0
- package/src/domains/onboarding/types/index.ts +16 -0
- package/src/domains/onboarding/types/onboarding.ts +214 -0
- package/src/domains/onboarding/utils/index.ts +15 -0
- package/src/domains/onboarding/utils/onboarding.ts +166 -0
- package/src/domains/settings/components/SettingsLayout.tsx +144 -0
- package/src/domains/settings/components/SettingsSection.tsx +106 -0
- package/src/domains/settings/components/index.ts +6 -0
- package/src/domains/settings/hooks/index.ts +7 -0
- package/src/domains/settings/hooks/useSettings.ts +80 -0
- package/src/domains/settings/index.ts +22 -0
- package/src/domains/settings/types/index.ts +11 -0
- package/src/domains/settings/types/settings.ts +81 -0
- package/src/domains/settings/utils/index.ts +11 -0
- package/src/domains/settings/utils/settings.ts +80 -0
- package/dist/layouts/components/BrandLogo.d.ts +0 -18
- package/dist/layouts/components/BrandLogo.js +0 -88
- package/dist/layouts/components/BrandLogo.js.map +0 -1
- package/dist/layouts/components/DashboardHeader.d.ts +0 -36
- package/dist/layouts/components/DashboardHeader.js +0 -225
- package/dist/layouts/components/DashboardHeader.js.map +0 -1
- package/dist/layouts/components/DashboardLayout.d.ts +0 -45
- package/dist/layouts/components/DashboardLayout.js +0 -501
- package/dist/layouts/components/DashboardLayout.js.map +0 -1
- package/dist/layouts/components/DashboardSidebar.d.ts +0 -29
- package/dist/layouts/components/DashboardSidebar.js +0 -189
- package/dist/layouts/components/DashboardSidebar.js.map +0 -1
- package/dist/layouts/components/index.d.ts +0 -10
- package/dist/layouts/components/index.js +0 -502
- package/dist/layouts/components/index.js.map +0 -1
- package/dist/layouts/hooks/dashboard.d.ts +0 -35
- package/dist/layouts/hooks/dashboard.js +0 -57
- package/dist/layouts/hooks/dashboard.js.map +0 -1
- package/dist/layouts/hooks/index.d.ts +0 -3
- package/dist/layouts/hooks/index.js +0 -57
- package/dist/layouts/hooks/index.js.map +0 -1
- package/dist/layouts/index.d.ts +0 -17
- package/dist/layouts/index.js +0 -756
- package/dist/layouts/index.js.map +0 -1
- package/dist/layouts/theme/default.d.ts +0 -18
- package/dist/layouts/theme/default.js.map +0 -1
- package/dist/layouts/theme/index.d.ts +0 -4
- package/dist/layouts/theme/index.js +0 -184
- package/dist/layouts/theme/index.js.map +0 -1
- package/dist/layouts/theme/presets.d.ts +0 -14
- package/dist/layouts/theme/presets.js +0 -137
- package/dist/layouts/theme/presets.js.map +0 -1
- package/dist/layouts/theme/utils.d.ts +0 -22
- package/dist/layouts/theme/utils.js +0 -181
- package/dist/layouts/theme/utils.js.map +0 -1
- package/dist/layouts/types/index.d.ts +0 -6
- package/dist/layouts/types/index.js +0 -2
- package/dist/layouts/types/index.js.map +0 -1
- package/dist/layouts/types/layout.d.ts +0 -45
- package/dist/layouts/types/layout.js +0 -2
- package/dist/layouts/types/layout.js.map +0 -1
- package/dist/layouts/types/notification.d.ts +0 -20
- package/dist/layouts/types/notification.js +0 -2
- package/dist/layouts/types/notification.js.map +0 -1
- package/dist/layouts/types/sidebar.d.ts +0 -36
- package/dist/layouts/types/sidebar.js +0 -2
- package/dist/layouts/types/sidebar.js.map +0 -1
- package/dist/layouts/types/theme.d.ts +0 -64
- package/dist/layouts/types/theme.js +0 -2
- package/dist/layouts/types/theme.js.map +0 -1
- package/dist/layouts/types/user.d.ts +0 -37
- package/dist/layouts/types/user.js +0 -2
- package/dist/layouts/types/user.js.map +0 -1
- package/dist/layouts/utils/dashboard.d.ts +0 -57
- package/dist/layouts/utils/dashboard.js +0 -44
- package/dist/layouts/utils/dashboard.js.map +0 -1
- package/dist/layouts/utils/index.d.ts +0 -1
- package/dist/layouts/utils/index.js +0 -44
- package/dist/layouts/utils/index.js.map +0 -1
- package/dist/onboarding/components/AppFocusStep.d.ts +0 -26
- package/dist/onboarding/components/AppFocusStep.js +0 -86
- package/dist/onboarding/components/AppFocusStep.js.map +0 -1
- package/dist/onboarding/components/OnboardingWizard.d.ts +0 -13
- package/dist/onboarding/components/OnboardingWizard.js +0 -332
- package/dist/onboarding/components/OnboardingWizard.js.map +0 -1
- package/dist/onboarding/components/PlanStep.d.ts +0 -21
- package/dist/onboarding/components/PlanStep.js +0 -167
- package/dist/onboarding/components/PlanStep.js.map +0 -1
- package/dist/onboarding/components/PlatformsStep.d.ts +0 -26
- package/dist/onboarding/components/PlatformsStep.js +0 -86
- package/dist/onboarding/components/PlatformsStep.js.map +0 -1
- package/dist/onboarding/components/UserTypeStep.d.ts +0 -30
- package/dist/onboarding/components/UserTypeStep.js +0 -93
- package/dist/onboarding/components/UserTypeStep.js.map +0 -1
- package/dist/onboarding/components/index.d.ts +0 -9
- package/dist/onboarding/components/index.js +0 -738
- package/dist/onboarding/components/index.js.map +0 -1
- package/dist/onboarding/hooks/index.d.ts +0 -4
- package/dist/onboarding/hooks/index.js.map +0 -1
- package/dist/onboarding/hooks/useOnboarding.d.ts +0 -50
- package/dist/onboarding/hooks/useOnboarding.js +0 -100
- package/dist/onboarding/hooks/useOnboarding.js.map +0 -1
- package/dist/onboarding/index.d.ts +0 -11
- package/dist/onboarding/index.js +0 -913
- package/dist/onboarding/index.js.map +0 -1
- package/dist/onboarding/types/index.d.ts +0 -3
- package/dist/onboarding/types/index.js +0 -2
- package/dist/onboarding/types/index.js.map +0 -1
- package/dist/onboarding/types/onboarding.d.ts +0 -209
- package/dist/onboarding/types/onboarding.js +0 -2
- package/dist/onboarding/types/onboarding.js.map +0 -1
- package/dist/onboarding/utils/index.d.ts +0 -4
- package/dist/onboarding/utils/index.js +0 -83
- package/dist/onboarding/utils/index.js.map +0 -1
- package/dist/onboarding/utils/onboarding.d.ts +0 -106
- package/dist/onboarding/utils/onboarding.js +0 -83
- package/dist/onboarding/utils/onboarding.js.map +0 -1
- package/dist/settings/components/SettingsLayout.d.ts +0 -19
- package/dist/settings/components/SettingsLayout.js +0 -170
- package/dist/settings/components/SettingsLayout.js.map +0 -1
- package/dist/settings/components/SettingsSection.d.ts +0 -24
- package/dist/settings/components/SettingsSection.js +0 -73
- package/dist/settings/components/SettingsSection.js.map +0 -1
- package/dist/settings/components/index.d.ts +0 -5
- package/dist/settings/components/index.js +0 -169
- package/dist/settings/components/index.js.map +0 -1
- package/dist/settings/hooks/index.d.ts +0 -3
- package/dist/settings/hooks/index.js +0 -59
- package/dist/settings/hooks/index.js.map +0 -1
- package/dist/settings/hooks/useSettings.d.ts +0 -25
- package/dist/settings/hooks/useSettings.js +0 -59
- package/dist/settings/hooks/useSettings.js.map +0 -1
- package/dist/settings/index.d.ts +0 -7
- package/dist/settings/index.js +0 -259
- package/dist/settings/index.js.map +0 -1
- package/dist/settings/types/index.d.ts +0 -2
- package/dist/settings/types/index.js +0 -2
- package/dist/settings/types/index.js.map +0 -1
- package/dist/settings/types/settings.d.ts +0 -79
- package/dist/settings/types/settings.js +0 -2
- package/dist/settings/types/settings.js.map +0 -1
- package/dist/settings/utils/index.d.ts +0 -3
- package/dist/settings/utils/index.js +0 -39
- package/dist/settings/utils/index.js.map +0 -1
- package/dist/settings/utils/settings.d.ts +0 -50
- package/dist/settings/utils/settings.js +0 -39
- package/dist/settings/utils/settings.js.map +0 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Check } from "lucide-react";
|
|
2
|
+
import { cn } from "@umituz/web-design-system/utils";
|
|
3
|
+
import type { OnboardingState, PlanOption } from "../types/onboarding";
|
|
4
|
+
|
|
5
|
+
interface PlanStepProps {
|
|
6
|
+
/** Current onboarding state */
|
|
7
|
+
state: OnboardingState;
|
|
8
|
+
/** Update state function */
|
|
9
|
+
updateState: (updates: Partial<OnboardingState>) => void;
|
|
10
|
+
/** Plan options */
|
|
11
|
+
plans?: PlanOption[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Plan Selection Step
|
|
16
|
+
*
|
|
17
|
+
* Fourth step - select subscription plan
|
|
18
|
+
*/
|
|
19
|
+
export const PlanStep = ({
|
|
20
|
+
state,
|
|
21
|
+
updateState,
|
|
22
|
+
plans,
|
|
23
|
+
}: PlanStepProps) => {
|
|
24
|
+
// Default plans
|
|
25
|
+
const defaultPlans: PlanOption[] = [
|
|
26
|
+
{
|
|
27
|
+
id: "standard",
|
|
28
|
+
name: "Standard",
|
|
29
|
+
badge: "Most Popular",
|
|
30
|
+
badgeColor: "bg-muted text-muted-foreground",
|
|
31
|
+
description: "Perfect for individuals and small businesses",
|
|
32
|
+
price: 12,
|
|
33
|
+
features: [
|
|
34
|
+
{ text: "3 Social Accounts", bold: true },
|
|
35
|
+
"100 posts per month",
|
|
36
|
+
"Basic Analytics",
|
|
37
|
+
"Email Support",
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "pro",
|
|
42
|
+
name: "Pro",
|
|
43
|
+
badge: "Best Value",
|
|
44
|
+
badgeColor: "bg-primary text-primary-foreground",
|
|
45
|
+
description: "For growing businesses and teams",
|
|
46
|
+
price: 29,
|
|
47
|
+
features: [
|
|
48
|
+
{ text: "15 Social Accounts", bold: true },
|
|
49
|
+
"Unlimited posts",
|
|
50
|
+
"Advanced Analytics",
|
|
51
|
+
"AI Caption Suggestions",
|
|
52
|
+
{ text: "5 Team Members", bold: true },
|
|
53
|
+
"Priority Support",
|
|
54
|
+
],
|
|
55
|
+
highlight: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "enterprise",
|
|
59
|
+
name: "Enterprise",
|
|
60
|
+
badge: "Custom",
|
|
61
|
+
badgeColor: "bg-purple-600 text-white",
|
|
62
|
+
description: "For large organizations with custom needs",
|
|
63
|
+
price: 99,
|
|
64
|
+
features: [
|
|
65
|
+
{ text: "Unlimited Accounts", bold: true },
|
|
66
|
+
"Unlimited everything",
|
|
67
|
+
"Custom Integrations",
|
|
68
|
+
"Dedicated Account Manager",
|
|
69
|
+
"24/7 Phone Support",
|
|
70
|
+
"SLA Guarantee",
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const planOptions = plans || defaultPlans;
|
|
76
|
+
|
|
77
|
+
// Calculate price with billing cycle discount
|
|
78
|
+
const getPlanPrice = (plan: PlanOption) => {
|
|
79
|
+
const basePrice = plan.price;
|
|
80
|
+
return state.billingCycle === "yearly" ? basePrice * 12 * 0.8 : basePrice; // 20% discount
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div className="w-full max-w-5xl">
|
|
85
|
+
<div className="text-center mb-8">
|
|
86
|
+
<h1 className="text-3xl md:text-4xl font-extrabold text-foreground mb-3">
|
|
87
|
+
Choose your plan
|
|
88
|
+
</h1>
|
|
89
|
+
<p className="text-muted-foreground text-lg">
|
|
90
|
+
Start with a 14-day free trial - no credit card required
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Billing Cycle Toggle */}
|
|
95
|
+
<div className="flex items-center justify-center gap-2 mb-12">
|
|
96
|
+
<div className="flex bg-muted rounded-full p-1.5 border border-border">
|
|
97
|
+
<button
|
|
98
|
+
onClick={() => updateState({ billingCycle: "monthly" })}
|
|
99
|
+
className={cn(
|
|
100
|
+
"px-6 py-2 rounded-full text-sm font-bold transition-all",
|
|
101
|
+
state.billingCycle === "monthly"
|
|
102
|
+
? "bg-primary text-primary-foreground shadow-lg shadow-primary/20"
|
|
103
|
+
: "text-muted-foreground hover:text-foreground"
|
|
104
|
+
)}
|
|
105
|
+
>
|
|
106
|
+
Monthly
|
|
107
|
+
</button>
|
|
108
|
+
<button
|
|
109
|
+
onClick={() => updateState({ billingCycle: "yearly" })}
|
|
110
|
+
className={cn(
|
|
111
|
+
"px-6 py-2 rounded-full text-sm font-bold transition-all flex items-center gap-2",
|
|
112
|
+
state.billingCycle === "yearly"
|
|
113
|
+
? "bg-primary text-primary-foreground shadow-lg shadow-primary/20"
|
|
114
|
+
: "text-muted-foreground hover:text-foreground"
|
|
115
|
+
)}
|
|
116
|
+
>
|
|
117
|
+
Yearly
|
|
118
|
+
<span
|
|
119
|
+
className={cn(
|
|
120
|
+
"text-[10px] px-1.5 py-0.5 rounded-full transition-colors",
|
|
121
|
+
state.billingCycle === "yearly" ? "bg-white/20 text-white" : "bg-green-500/10 text-green-600"
|
|
122
|
+
)}
|
|
123
|
+
>
|
|
124
|
+
Save 20%
|
|
125
|
+
</span>
|
|
126
|
+
</button>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{/* Plans Grid */}
|
|
131
|
+
<div className="grid md:grid-cols-3 gap-8">
|
|
132
|
+
{planOptions.map((plan) => {
|
|
133
|
+
const isSelected = state.selectedPlan === plan.id;
|
|
134
|
+
const planPrice = getPlanPrice(plan);
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<button
|
|
138
|
+
key={plan.id}
|
|
139
|
+
onClick={() => updateState({ selectedPlan: plan.id })}
|
|
140
|
+
className={cn(
|
|
141
|
+
"bg-background border-2 rounded-[32px] p-8 text-left transition-all hover:translate-y-[-4px] relative",
|
|
142
|
+
isSelected
|
|
143
|
+
? "border-primary ring-4 ring-primary/10"
|
|
144
|
+
: "border-border hover:border-primary/40",
|
|
145
|
+
plan.highlight && "shadow-xl"
|
|
146
|
+
)}
|
|
147
|
+
>
|
|
148
|
+
{plan.highlight && (
|
|
149
|
+
<div className="absolute -top-3 left-1/2 -translate-x-1/2 bg-gradient-to-r from-primary to-purple-600 text-white text-[10px] font-black uppercase tracking-widest px-4 py-1 rounded-full">
|
|
150
|
+
Recommended
|
|
151
|
+
</div>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
<div className="flex items-center justify-between mb-4">
|
|
155
|
+
<h3 className="text-2xl font-black text-foreground">{plan.name}</h3>
|
|
156
|
+
{plan.badge && (
|
|
157
|
+
<div
|
|
158
|
+
className={cn(
|
|
159
|
+
"text-[10px] font-black uppercase tracking-widest px-3 py-1 rounded-full",
|
|
160
|
+
plan.badgeColor
|
|
161
|
+
)}
|
|
162
|
+
>
|
|
163
|
+
{plan.badge}
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<p className="text-muted-foreground mb-8 font-medium">{plan.description}</p>
|
|
169
|
+
|
|
170
|
+
<div className="flex items-baseline gap-1 mb-8">
|
|
171
|
+
<span className="text-5xl font-black text-foreground">
|
|
172
|
+
${Math.round(planPrice)}
|
|
173
|
+
</span>
|
|
174
|
+
<span className="text-lg font-bold text-muted-foreground">/mo</span>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<ul className="space-y-4">
|
|
178
|
+
{plan.features.map((feature, i) => {
|
|
179
|
+
const text = typeof feature === "string" ? feature : feature.text;
|
|
180
|
+
const bold = typeof feature !== "string" && feature.bold;
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<li key={i} className="flex items-start gap-3 text-sm font-medium">
|
|
184
|
+
<div className="w-5 h-5 rounded-full bg-primary/10 flex items-center justify-center shrink-0 mt-0.5">
|
|
185
|
+
<Check className="h-3 w-3 text-primary" />
|
|
186
|
+
</div>
|
|
187
|
+
<span className={cn("text-foreground/90", bold && "font-black")}>
|
|
188
|
+
{text}
|
|
189
|
+
</span>
|
|
190
|
+
</li>
|
|
191
|
+
);
|
|
192
|
+
})}
|
|
193
|
+
</ul>
|
|
194
|
+
</button>
|
|
195
|
+
);
|
|
196
|
+
})}
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
{state.selectedPlan && (
|
|
200
|
+
<p className="mt-8 text-center text-sm text-muted-foreground animate-in fade-in">
|
|
201
|
+
✨ Great choice! You selected the {planOptions.find((p) => p.id === state.selectedPlan)?.name} plan
|
|
202
|
+
</p>
|
|
203
|
+
)}
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export default PlanStep;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { cn } from "@umituz/web-design-system/utils";
|
|
2
|
+
import type { OnboardingState } from "../types/onboarding";
|
|
3
|
+
|
|
4
|
+
interface PlatformsStepProps {
|
|
5
|
+
/** Current onboarding state */
|
|
6
|
+
state: OnboardingState;
|
|
7
|
+
/** Update state function */
|
|
8
|
+
updateState: (updates: Partial<OnboardingState>) => void;
|
|
9
|
+
/** Platform options */
|
|
10
|
+
platforms?: Array<{
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
color?: string;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Platform Selection Step
|
|
20
|
+
*
|
|
21
|
+
* Third step - select social media platforms to connect
|
|
22
|
+
*/
|
|
23
|
+
export const PlatformsStep = ({
|
|
24
|
+
state,
|
|
25
|
+
updateState,
|
|
26
|
+
platforms,
|
|
27
|
+
}: PlatformsStepProps) => {
|
|
28
|
+
// Default platforms
|
|
29
|
+
const defaultPlatforms = [
|
|
30
|
+
{ id: "instagram", name: "Instagram", icon: "📸", color: "bg-gradient-to-br from-purple-500 to-pink-500" },
|
|
31
|
+
{ id: "twitter", name: "Twitter / X", icon: "🐦", color: "bg-black" },
|
|
32
|
+
{ id: "facebook", name: "Facebook", icon: "👍", color: "bg-blue-600" },
|
|
33
|
+
{ id: "linkedin", name: "LinkedIn", icon: "💼", color: "bg-blue-700" },
|
|
34
|
+
{ id: "tiktok", name: "TikTok", icon: "🎵", color: "bg-black" },
|
|
35
|
+
{ id: "youtube", name: "YouTube", icon: "📺", color: "bg-red-600" },
|
|
36
|
+
{ id: "pinterest", name: "Pinterest", icon: "📌", color: "bg-red-700" },
|
|
37
|
+
{ id: "threads", name: "Threads", icon: "🧵", color: "bg-black" },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const platformOptions = platforms || defaultPlatforms;
|
|
41
|
+
|
|
42
|
+
const togglePlatform = (id: string) => {
|
|
43
|
+
const isConnected = state.connectedPlatforms.includes(id);
|
|
44
|
+
updateState({
|
|
45
|
+
connectedPlatforms: isConnected
|
|
46
|
+
? state.connectedPlatforms.filter((p) => p !== id)
|
|
47
|
+
: [...state.connectedPlatforms, id],
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className="w-full max-w-4xl">
|
|
53
|
+
<div className="text-center mb-10">
|
|
54
|
+
<h1 className="text-3xl md:text-4xl font-extrabold text-foreground mb-3">
|
|
55
|
+
Connect your platforms
|
|
56
|
+
</h1>
|
|
57
|
+
<p className="text-muted-foreground">
|
|
58
|
+
Select the platforms you want to manage - you can add more later
|
|
59
|
+
</p>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
|
|
63
|
+
{platformOptions.map((platform) => {
|
|
64
|
+
const isConnected = state.connectedPlatforms.includes(platform.id);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<button
|
|
68
|
+
key={platform.id}
|
|
69
|
+
onClick={() => togglePlatform(platform.id)}
|
|
70
|
+
className={cn(
|
|
71
|
+
"group bg-background border rounded-2xl p-6 flex flex-col items-center gap-4 transition-all hover:scale-[1.02]",
|
|
72
|
+
isConnected ? "border-primary ring-2 ring-primary/20 bg-primary/5" : "border-border hover:border-primary/40"
|
|
73
|
+
)}
|
|
74
|
+
>
|
|
75
|
+
<div
|
|
76
|
+
className={cn(
|
|
77
|
+
"w-12 h-12 rounded-2xl bg-muted flex items-center justify-center text-2xl group-hover:scale-110 transition-transform",
|
|
78
|
+
platform.color
|
|
79
|
+
)}
|
|
80
|
+
>
|
|
81
|
+
{platform.icon}
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div className="flex flex-col items-center">
|
|
85
|
+
<span className="font-bold text-foreground text-sm">{platform.name}</span>
|
|
86
|
+
<span
|
|
87
|
+
className={cn(
|
|
88
|
+
"text-[10px] font-bold uppercase tracking-wider mt-1 transition-colors",
|
|
89
|
+
isConnected ? "text-primary" : "text-muted-foreground"
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
{isConnected ? "Connected" : "Connect"}
|
|
93
|
+
</span>
|
|
94
|
+
</div>
|
|
95
|
+
</button>
|
|
96
|
+
);
|
|
97
|
+
})}
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
{state.connectedPlatforms.length > 0 && (
|
|
101
|
+
<p className="mt-8 text-center text-sm text-muted-foreground animate-in fade-in">
|
|
102
|
+
✨ {state.connectedPlatforms.length} platform{state.connectedPlatforms.length > 1 ? "s" : ""} selected
|
|
103
|
+
</p>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export default PlatformsStep;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Check } from "lucide-react";
|
|
2
|
+
import { cn } from "@umituz/web-design-system/utils";
|
|
3
|
+
import type { OnboardingState } from "../types/onboarding";
|
|
4
|
+
import type { ComponentType } from "react";
|
|
5
|
+
|
|
6
|
+
interface UserTypeOption {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
description: string;
|
|
10
|
+
icon?: ComponentType<{ className?: string }>;
|
|
11
|
+
badge?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface UserTypeStepProps {
|
|
15
|
+
/** Current onboarding state */
|
|
16
|
+
state: OnboardingState;
|
|
17
|
+
/** Update state function */
|
|
18
|
+
updateState: (updates: Partial<OnboardingState>) => void;
|
|
19
|
+
/** User type options */
|
|
20
|
+
options?: UserTypeOption[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* User Type Selection Step
|
|
25
|
+
*
|
|
26
|
+
* First step of onboarding - select user type/category
|
|
27
|
+
*/
|
|
28
|
+
export const UserTypeStep = ({
|
|
29
|
+
state,
|
|
30
|
+
updateState,
|
|
31
|
+
options = [],
|
|
32
|
+
}: UserTypeStepProps) => {
|
|
33
|
+
// Default options if not provided
|
|
34
|
+
const defaultOptions: UserTypeOption[] = [
|
|
35
|
+
{
|
|
36
|
+
id: "founder",
|
|
37
|
+
label: "Founder",
|
|
38
|
+
description: "Building your own startup or business",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "creator",
|
|
42
|
+
label: "Content Creator",
|
|
43
|
+
description: "Creating content for social media and platforms",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "agency",
|
|
47
|
+
label: "Agency",
|
|
48
|
+
description: "Managing multiple client accounts",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "enterprise",
|
|
52
|
+
label: "Enterprise",
|
|
53
|
+
description: "Large scale organization with teams",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "small-business",
|
|
57
|
+
label: "Small Business",
|
|
58
|
+
description: "Local or niche business owner",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "personal",
|
|
62
|
+
label: "Personal",
|
|
63
|
+
description: "Individual looking to grow personal brand",
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const userTypeOptions = options.length > 0 ? options : defaultOptions;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className="w-full max-w-xl">
|
|
71
|
+
<div className="text-center mb-10">
|
|
72
|
+
<h1 className="text-3xl md:text-4xl font-extrabold text-foreground mb-3">
|
|
73
|
+
What describes you best?
|
|
74
|
+
</h1>
|
|
75
|
+
<p className="text-muted-foreground">
|
|
76
|
+
Select the option that best describes your situation
|
|
77
|
+
</p>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div className="grid grid-cols-1 gap-3">
|
|
81
|
+
{userTypeOptions.map((option) => {
|
|
82
|
+
const isSelected = state.selectedUserType === option.id;
|
|
83
|
+
const hasBadge = option.badge != null;
|
|
84
|
+
const hasIcon = option.icon != null;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<button
|
|
88
|
+
key={option.id}
|
|
89
|
+
onClick={() => updateState({ selectedUserType: option.id })}
|
|
90
|
+
className={cn(
|
|
91
|
+
"w-full flex items-center gap-4 p-5 rounded-2xl border bg-background text-left transition-all group",
|
|
92
|
+
isSelected
|
|
93
|
+
? "border-primary ring-2 ring-primary/20 bg-primary/5"
|
|
94
|
+
: "border-border hover:border-primary/40 hover:bg-muted/50"
|
|
95
|
+
)}
|
|
96
|
+
>
|
|
97
|
+
<div
|
|
98
|
+
className={cn(
|
|
99
|
+
"w-6 h-6 rounded-full border-2 flex items-center justify-center shrink-0 transition-colors",
|
|
100
|
+
isSelected
|
|
101
|
+
? "border-primary bg-primary text-white"
|
|
102
|
+
: "border-muted-foreground/30"
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
{isSelected && <Check className="h-4 w-4" />}
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div className="flex-1">
|
|
109
|
+
<div className="flex items-center gap-2">
|
|
110
|
+
<p className="font-bold text-foreground">{option.label}</p>
|
|
111
|
+
{hasBadge && (
|
|
112
|
+
<span className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded-full bg-primary/10 text-primary">
|
|
113
|
+
{option.badge}
|
|
114
|
+
</span>
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
<p className="text-sm text-muted-foreground mt-0.5">
|
|
118
|
+
{option.description}
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{hasIcon && option.icon && (
|
|
123
|
+
<div className="w-10 h-10 rounded-xl bg-muted flex items-center justify-center shrink-0">
|
|
124
|
+
<option.icon className="h-5 w-5 text-muted-foreground" />
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
</button>
|
|
128
|
+
);
|
|
129
|
+
})}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export default UserTypeStep;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding Components Export
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { OnboardingWizard } from './OnboardingWizard';
|
|
6
|
+
export { UserTypeStep } from './UserTypeStep';
|
|
7
|
+
export { AppFocusStep } from './AppFocusStep';
|
|
8
|
+
export { PlatformsStep } from './PlatformsStep';
|
|
9
|
+
export { PlanStep } from './PlanStep';
|
|
@@ -1,28 +1,53 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding Hooks
|
|
3
|
+
*
|
|
4
|
+
* Custom React hooks for onboarding functionality
|
|
5
|
+
*/
|
|
2
6
|
|
|
3
|
-
// src/domains/onboarding/hooks/useOnboarding.ts
|
|
4
7
|
import { useState, useCallback } from "react";
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
import type { OnboardingState, OnboardingConfig } from "../types/onboarding";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Use Onboarding Hook
|
|
12
|
+
*
|
|
13
|
+
* Manages onboarding state and actions
|
|
14
|
+
*
|
|
15
|
+
* @param config - Onboarding configuration
|
|
16
|
+
* @param initialState - Initial state
|
|
17
|
+
* @returns Onboarding state and actions
|
|
18
|
+
*/
|
|
19
|
+
export function useOnboarding(
|
|
20
|
+
config: OnboardingConfig,
|
|
21
|
+
initialState?: Partial<OnboardingState>
|
|
22
|
+
) {
|
|
23
|
+
const [state, setState] = useState<OnboardingState>({
|
|
7
24
|
currentStep: 1,
|
|
8
25
|
connectedPlatforms: [],
|
|
9
26
|
billingCycle: "monthly",
|
|
10
27
|
stepData: {},
|
|
11
|
-
...initialState
|
|
28
|
+
...initialState,
|
|
12
29
|
});
|
|
30
|
+
|
|
13
31
|
const totalSteps = config.steps.length;
|
|
32
|
+
|
|
33
|
+
// Navigation actions
|
|
14
34
|
const goToNext = useCallback(() => {
|
|
15
35
|
const currentStepConfig = config.steps[state.currentStep - 1];
|
|
36
|
+
|
|
37
|
+
// Validate if needed
|
|
16
38
|
if (currentStepConfig?.validate) {
|
|
17
39
|
const isValid = currentStepConfig.validate(state);
|
|
18
40
|
if (!isValid) return false;
|
|
19
41
|
}
|
|
42
|
+
|
|
20
43
|
if (state.currentStep < totalSteps) {
|
|
21
44
|
setState((prev) => ({ ...prev, currentStep: prev.currentStep + 1 }));
|
|
22
45
|
return true;
|
|
23
46
|
}
|
|
47
|
+
|
|
24
48
|
return false;
|
|
25
49
|
}, [config.steps, state, totalSteps]);
|
|
50
|
+
|
|
26
51
|
const goToPrev = useCallback(() => {
|
|
27
52
|
if (state.currentStep > 1) {
|
|
28
53
|
setState((prev) => ({ ...prev, currentStep: prev.currentStep - 1 }));
|
|
@@ -30,14 +55,19 @@ function useOnboarding(config, initialState) {
|
|
|
30
55
|
}
|
|
31
56
|
return false;
|
|
32
57
|
}, [state.currentStep]);
|
|
33
|
-
|
|
58
|
+
|
|
59
|
+
const goToStep = useCallback((step: number) => {
|
|
34
60
|
if (step >= 1 && step <= totalSteps) {
|
|
35
61
|
setState((prev) => ({ ...prev, currentStep: step }));
|
|
36
62
|
}
|
|
37
63
|
}, [totalSteps]);
|
|
38
|
-
|
|
64
|
+
|
|
65
|
+
// State update action
|
|
66
|
+
const updateState = useCallback((updates: Partial<OnboardingState>) => {
|
|
39
67
|
setState((prev) => ({ ...prev, ...updates }));
|
|
40
68
|
}, []);
|
|
69
|
+
|
|
70
|
+
// Validation helper
|
|
41
71
|
const canGoNext = useCallback(() => {
|
|
42
72
|
const currentStepConfig = config.steps[state.currentStep - 1];
|
|
43
73
|
if (currentStepConfig?.validate) {
|
|
@@ -45,11 +75,18 @@ function useOnboarding(config, initialState) {
|
|
|
45
75
|
}
|
|
46
76
|
return true;
|
|
47
77
|
}, [config.steps, state]);
|
|
78
|
+
|
|
79
|
+
// Progress calculation
|
|
48
80
|
const getProgress = useCallback(() => {
|
|
49
|
-
return state.currentStep / totalSteps * 100;
|
|
81
|
+
return (state.currentStep / totalSteps) * 100;
|
|
50
82
|
}, [state.currentStep, totalSteps]);
|
|
83
|
+
|
|
84
|
+
// Is first step
|
|
51
85
|
const isFirstStep = state.currentStep === 1;
|
|
86
|
+
|
|
87
|
+
// Is last step
|
|
52
88
|
const isLastStep = state.currentStep === totalSteps;
|
|
89
|
+
|
|
53
90
|
return {
|
|
54
91
|
// State
|
|
55
92
|
state,
|
|
@@ -58,43 +95,52 @@ function useOnboarding(config, initialState) {
|
|
|
58
95
|
isFirstStep,
|
|
59
96
|
isLastStep,
|
|
60
97
|
progress: getProgress(),
|
|
98
|
+
|
|
61
99
|
// Actions
|
|
62
100
|
goToNext,
|
|
63
101
|
goToPrev,
|
|
64
102
|
goToStep,
|
|
65
103
|
updateState,
|
|
66
|
-
canGoNext
|
|
104
|
+
canGoNext,
|
|
67
105
|
};
|
|
68
106
|
}
|
|
69
|
-
|
|
70
|
-
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Use Onboarding Step Hook
|
|
110
|
+
*
|
|
111
|
+
* Hook for managing individual step state
|
|
112
|
+
*
|
|
113
|
+
* @param stepId - Step identifier
|
|
114
|
+
* @returns Step state and actions
|
|
115
|
+
*/
|
|
116
|
+
export function useOnboardingStep(stepId: string) {
|
|
117
|
+
const [data, setData] = useState<Record<string, unknown>>({});
|
|
71
118
|
const [isValid, setIsValid] = useState(false);
|
|
72
119
|
const [isTouched, setIsTouched] = useState(false);
|
|
73
|
-
|
|
120
|
+
|
|
121
|
+
const updateData = useCallback((updates: Record<string, unknown>) => {
|
|
74
122
|
setData((prev) => ({ ...prev, ...updates }));
|
|
75
123
|
setIsTouched(true);
|
|
76
124
|
}, []);
|
|
77
|
-
|
|
125
|
+
|
|
126
|
+
const validate = useCallback((validator: (data: Record<string, unknown>) => boolean) => {
|
|
78
127
|
const valid = validator(data);
|
|
79
128
|
setIsValid(valid);
|
|
80
129
|
return valid;
|
|
81
130
|
}, []);
|
|
131
|
+
|
|
82
132
|
const reset = useCallback(() => {
|
|
83
133
|
setData({});
|
|
84
134
|
setIsValid(false);
|
|
85
135
|
setIsTouched(false);
|
|
86
136
|
}, []);
|
|
137
|
+
|
|
87
138
|
return {
|
|
88
139
|
data,
|
|
89
140
|
isValid,
|
|
90
141
|
isTouched,
|
|
91
142
|
updateData,
|
|
92
143
|
validate,
|
|
93
|
-
reset
|
|
144
|
+
reset,
|
|
94
145
|
};
|
|
95
146
|
}
|
|
96
|
-
export {
|
|
97
|
-
useOnboarding,
|
|
98
|
-
useOnboardingStep
|
|
99
|
-
};
|
|
100
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @umituz/web-dashboard - Onboarding Domain
|
|
3
|
+
*
|
|
4
|
+
* Config-driven Onboarding System
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { OnboardingWizard } from './components';
|
|
8
|
+
export { UserTypeStep } from './components';
|
|
9
|
+
export { AppFocusStep } from './components';
|
|
10
|
+
export { PlatformsStep } from './components';
|
|
11
|
+
export { PlanStep } from './components';
|
|
12
|
+
export { useOnboarding, useOnboardingStep } from './hooks';
|
|
13
|
+
export {
|
|
14
|
+
validateStep,
|
|
15
|
+
getStepTitle,
|
|
16
|
+
getStepDescription,
|
|
17
|
+
calculateProgress,
|
|
18
|
+
getCompletedSteps,
|
|
19
|
+
formatOnboardingData,
|
|
20
|
+
generateOnboardingEvent,
|
|
21
|
+
isValidEmail,
|
|
22
|
+
isValidPassword,
|
|
23
|
+
} from './utils';
|
|
24
|
+
export type {
|
|
25
|
+
UserTypeOption,
|
|
26
|
+
PlatformOption,
|
|
27
|
+
PlanOption,
|
|
28
|
+
OnboardingStep,
|
|
29
|
+
OnboardingConfig,
|
|
30
|
+
OnboardingState,
|
|
31
|
+
OnboardingActions,
|
|
32
|
+
OnboardingWizardProps,
|
|
33
|
+
StepProgressProps,
|
|
34
|
+
StepNavigationProps,
|
|
35
|
+
} from './types';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding Types Export
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
UserTypeOption,
|
|
7
|
+
PlatformOption,
|
|
8
|
+
PlanOption,
|
|
9
|
+
OnboardingStep,
|
|
10
|
+
OnboardingConfig,
|
|
11
|
+
OnboardingState,
|
|
12
|
+
OnboardingActions,
|
|
13
|
+
OnboardingWizardProps,
|
|
14
|
+
StepProgressProps,
|
|
15
|
+
StepNavigationProps,
|
|
16
|
+
} from './onboarding';
|