@dashadmin/dash-app-common 1.3.25 → 1.3.28
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/README.md +35 -0
- package/dist/DashApp.js +176 -1
- package/dist/DashAppLoader.js +348 -3
- package/dist/DashDefaultResources.js +10 -1
- package/dist/components/DashDefaultPrivateApp.js +150 -1
- package/dist/components/DashDefaultPrivateResources.js +10 -1
- package/dist/components/DashDefaultPublicApp.js +20 -1
- package/dist/components/DashResourceLoader.js +245 -1
- package/dist/defaults/extensions/bootstrap/DashDefaultErrorBoundary.js +78 -1
- package/dist/defaults/extensions/bootstrap/dashDefaultInitializeApp.js +59 -1
- package/dist/defaults/extensions/bootstrap/index.js +24 -1
- package/dist/defaults/extensions/components/DashDefaultLoader.js +43 -2
- package/dist/defaults/extensions/components/dashDefaultAutoAdminComponents.js +67 -1
- package/dist/defaults/extensions/components/dashDefaultNotification.js +28 -1
- package/dist/defaults/extensions/components/dashDefaultStaticComponents.js +15 -1
- package/dist/defaults/extensions/components/index.js +13 -1
- package/dist/defaults/extensions/electron/dashDefaultIpcListeners.js +38 -1
- package/dist/defaults/extensions/electron/index.js +5 -1
- package/dist/defaults/extensions/hooks/index.js +12 -1
- package/dist/defaults/extensions/hooks/useDashDefaultLazyAutoAdminComponents.js +17 -1
- package/dist/defaults/extensions/hooks/useDashDefaultLazyI18nProvider.js +51 -1
- package/dist/defaults/extensions/hooks/useDashDefaultLazyResources.js +19 -1
- package/dist/defaults/extensions/hooks/useDashDefaultMountTracker.js +22 -1
- package/dist/defaults/extensions/hooks/useDashDefaultRoutePath.js +17 -1
- package/dist/defaults/extensions/i18n/dashDefaultI18nProvider.js +44 -1
- package/dist/defaults/extensions/i18n/dashDefaultTranslations.js +87 -1
- package/dist/defaults/extensions/i18n/index.js +24 -1
- package/dist/defaults/extensions/index.js +190 -1
- package/dist/defaults/extensions/layout/dashDefaultDomainAppLayout.js +58 -1
- package/dist/defaults/extensions/layout/index.js +12 -1
- package/dist/defaults/extensions/managers/DashDefaultWSMessagesManager.js +84 -1
- package/dist/defaults/extensions/managers/index.js +5 -1
- package/dist/defaults/extensions/providers/dashDefaultAuthProvider.js +220 -1
- package/dist/defaults/extensions/providers/dashDefaultDataProvider.js +395 -1
- package/dist/defaults/extensions/providers/index.js +24 -1
- package/dist/defaults/extensions/router/DashDefaultLanding.js +46 -1
- package/dist/defaults/extensions/router/dashDefaultPrivateRoutes.js +38 -1
- package/dist/defaults/extensions/router/dashDefaultPublicRoutes.js +65 -1
- package/dist/defaults/extensions/router/dashDefaultRouter.js +39 -1
- package/dist/defaults/extensions/router/dashDefaultSharedRoutes.js +40 -1
- package/dist/defaults/extensions/router/index.js +12 -1
- package/dist/defaults/extensions/state/dashDefaultAppCommon.js +57 -1
- package/dist/defaults/extensions/state/dashDefaultAppSettings.js +38 -1
- package/dist/defaults/extensions/state/dashDefaultInitialAppState.js +31 -1
- package/dist/defaults/extensions/state/dashDefaultLayoutSettings.js +48 -1
- package/dist/defaults/extensions/state/dashDefaultQueryClient.js +58 -1
- package/dist/defaults/extensions/state/dashDefaultResourcesIcons.js +24 -1
- package/dist/defaults/extensions/state/index.js +29 -1
- package/dist/defaults/extensions/styles/index.js +2 -1
- package/dist/defaults/extensions/theme/dashDefaultThemeOptions.js +74 -1
- package/dist/defaults/extensions/theme/index.js +6 -1
- package/dist/defaults/extensions/utils/IPCMessageBrokerContext.js +12 -1
- package/dist/defaults/extensions/utils/dashDefaultAuthProviderUtils.js +29 -1
- package/dist/defaults/extensions/utils/dashDefaultDataProviderUtils.js +37 -1
- package/dist/defaults/extensions/utils/dashDefaultNotificationsProcessor.js +149 -1
- package/dist/defaults/extensions/utils/index.js +44 -1
- package/dist/defaults/filters/demo/dashDefaultDemoFilters.js +36 -1
- package/dist/defaults/filters/demo/index.js +4 -1
- package/dist/defaults/filters/index.js +5 -1
- package/dist/defaults/index.js +14 -1
- package/dist/defaults/pages/Account/DashDefaultRegister.js +282 -1
- package/dist/defaults/pages/Account/DashDefaultSignUp.js +420 -1
- package/dist/defaults/pages/Account/DashDefaultSignUpSuccess.js +101 -1
- package/dist/defaults/pages/Account/index.js +8 -1
- package/dist/defaults/pages/DashDefaultLogin.js +218 -1
- package/dist/defaults/pages/Misc/DashDefaultNotFound.js +74 -1
- package/dist/defaults/pages/Misc/DashDefaultServerError.js +79 -1
- package/dist/defaults/pages/Misc/DashDefaultUnauthorized.js +90 -1
- package/dist/defaults/pages/Misc/index.js +8 -1
- package/dist/defaults/pages/Static/DashDefaultPrivacyPage.js +48 -1
- package/dist/defaults/pages/Static/DashDefaultStaticPage.js +55 -1
- package/dist/defaults/pages/Static/DashDefaultTermsPage.js +52 -1
- package/dist/defaults/pages/Static/index.js +8 -1
- package/dist/defaults/pages/index.js +25 -1
- package/dist/defaults/schemas/dashDefaultSchema.js +14 -1
- package/dist/defaults/schemas/demo/dashDefaultTodoSchema.js +24 -1
- package/dist/defaults/schemas/demo/index.js +4 -1
- package/dist/defaults/schemas/index.js +7 -1
- package/dist/filters/demo/todoFilters.js +36 -1
- package/dist/index.js +56 -5975
- package/dist/resources/demo/todoResource.js +58 -1
- package/dist/schemas/defaultSchema.js +14 -1
- package/dist/schemas/demo/todoSchema.js +24 -1
- package/package.json +132 -77
- package/src/DashApp.tsx +294 -0
- package/src/DashAppLoader.tsx +717 -0
- package/src/DashDefaultResources.tsx +10 -0
- package/src/components/DashDefaultPrivateApp.tsx +358 -0
- package/src/components/DashDefaultPrivateResources.tsx +10 -0
- package/src/components/DashDefaultPublicApp.tsx +40 -0
- package/src/components/DashResourceLoader.tsx +564 -0
- package/src/defaults/extensions/bootstrap/DashDefaultErrorBoundary.tsx +113 -0
- package/src/defaults/extensions/bootstrap/dashDefaultInitializeApp.ts +81 -0
- package/src/defaults/extensions/bootstrap/index.ts +32 -0
- package/src/defaults/extensions/components/DashDefaultLoader.tsx +59 -0
- package/src/defaults/extensions/components/dashDefaultAutoAdminComponents.tsx +49 -0
- package/src/defaults/extensions/components/dashDefaultNotification.tsx +37 -0
- package/src/defaults/extensions/components/dashDefaultStaticComponents.tsx +34 -0
- package/src/defaults/extensions/components/index.ts +17 -0
- package/src/defaults/extensions/electron/dashDefaultIpcListeners.ts +62 -0
- package/src/defaults/extensions/electron/index.ts +7 -0
- package/src/defaults/extensions/hooks/index.ts +11 -0
- package/src/defaults/extensions/hooks/useDashDefaultLazyAutoAdminComponents.ts +25 -0
- package/src/defaults/extensions/hooks/useDashDefaultLazyI18nProvider.ts +38 -0
- package/src/defaults/extensions/hooks/useDashDefaultLazyResources.ts +29 -0
- package/src/defaults/extensions/hooks/useDashDefaultMountTracker.ts +28 -0
- package/src/defaults/extensions/hooks/useDashDefaultRoutePath.ts +27 -0
- package/src/defaults/extensions/i18n/dashDefaultI18nProvider.ts +66 -0
- package/src/defaults/extensions/i18n/dashDefaultTranslations.ts +82 -0
- package/src/defaults/extensions/i18n/index.ts +22 -0
- package/src/defaults/extensions/index.ts +177 -0
- package/src/defaults/extensions/layout/dashDefaultDomainAppLayout.tsx +126 -0
- package/src/defaults/extensions/layout/index.ts +12 -0
- package/src/defaults/extensions/managers/DashDefaultWSMessagesManager.tsx +99 -0
- package/src/defaults/extensions/managers/index.ts +7 -0
- package/src/defaults/extensions/providers/dashDefaultAuthProvider.ts +256 -0
- package/src/defaults/extensions/providers/dashDefaultDataProvider.ts +513 -0
- package/src/defaults/extensions/providers/index.ts +25 -0
- package/src/defaults/extensions/router/DashDefaultLanding.tsx +51 -0
- package/src/defaults/extensions/router/dashDefaultPrivateRoutes.tsx +50 -0
- package/src/defaults/extensions/router/dashDefaultPublicRoutes.tsx +86 -0
- package/src/defaults/extensions/router/dashDefaultRouter.tsx +54 -0
- package/src/defaults/extensions/router/dashDefaultSharedRoutes.tsx +56 -0
- package/src/defaults/extensions/router/index.ts +13 -0
- package/src/defaults/extensions/state/dashDefaultAppCommon.ts +54 -0
- package/src/defaults/extensions/state/dashDefaultAppSettings.ts +29 -0
- package/src/defaults/extensions/state/dashDefaultInitialAppState.ts +75 -0
- package/src/defaults/extensions/state/dashDefaultLayoutSettings.ts +59 -0
- package/src/defaults/extensions/state/dashDefaultQueryClient.ts +59 -0
- package/src/defaults/extensions/state/dashDefaultResourcesIcons.tsx +23 -0
- package/src/defaults/extensions/state/index.ts +29 -0
- package/src/defaults/extensions/styles/index.ts +17 -0
- package/src/defaults/extensions/theme/dashDefaultThemeOptions.ts +89 -0
- package/src/defaults/extensions/theme/index.ts +7 -0
- package/src/defaults/extensions/utils/IPCMessageBrokerContext.tsx +22 -0
- package/src/defaults/extensions/utils/dashDefaultAuthProviderUtils.ts +36 -0
- package/src/defaults/extensions/utils/dashDefaultDataProviderUtils.ts +46 -0
- package/src/defaults/extensions/utils/dashDefaultNotificationsProcessor.tsx +208 -0
- package/src/defaults/extensions/utils/index.ts +42 -0
- package/src/defaults/filters/demo/dashDefaultDemoFilters.tsx +50 -0
- package/src/defaults/filters/demo/index.ts +6 -0
- package/src/defaults/filters/index.ts +11 -0
- package/src/defaults/index.ts +27 -0
- package/src/defaults/pages/Account/DashDefaultRegister.tsx +281 -0
- package/src/defaults/pages/Account/DashDefaultSignUp.tsx +492 -0
- package/src/defaults/pages/Account/DashDefaultSignUpSuccess.tsx +113 -0
- package/src/defaults/pages/Account/index.ts +8 -0
- package/src/defaults/pages/DashDefaultLogin.tsx +224 -0
- package/src/defaults/pages/Misc/DashDefaultNotFound.tsx +96 -0
- package/src/defaults/pages/Misc/DashDefaultServerError.tsx +102 -0
- package/src/defaults/pages/Misc/DashDefaultUnauthorized.tsx +116 -0
- package/src/defaults/pages/Misc/index.ts +8 -0
- package/src/defaults/pages/Static/DashDefaultPrivacyPage.tsx +85 -0
- package/src/defaults/pages/Static/DashDefaultStaticPage.tsx +75 -0
- package/src/defaults/pages/Static/DashDefaultTermsPage.tsx +69 -0
- package/src/defaults/pages/Static/index.ts +8 -0
- package/src/defaults/pages/index.ts +28 -0
- package/src/defaults/schemas/dashDefaultSchema.tsx +25 -0
- package/src/defaults/schemas/demo/dashDefaultTodoSchema.tsx +39 -0
- package/src/defaults/schemas/demo/index.ts +6 -0
- package/src/defaults/schemas/index.ts +14 -0
- package/src/filters/demo/todoFilters.tsx +39 -0
- package/src/index.ts +131 -0
- package/src/resources/demo/todoResource.tsx +68 -0
- package/src/schemas/defaultSchema.tsx +14 -0
- package/src/schemas/demo/todoSchema.tsx +27 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default SignUp Page
|
|
3
|
+
*
|
|
4
|
+
* SignUp page with subscription plan selection.
|
|
5
|
+
*/
|
|
6
|
+
import React, { createRef, useEffect, useState } from 'react';
|
|
7
|
+
import { useDispatch } from 'react-redux';
|
|
8
|
+
import { useForm } from 'react-hook-form';
|
|
9
|
+
import Button from '@mui/material/Button';
|
|
10
|
+
import { useNavigate } from 'react-router-dom';
|
|
11
|
+
import { useNotify } from 'react-admin';
|
|
12
|
+
import ReCAPTCHA from 'react-google-recaptcha';
|
|
13
|
+
import {
|
|
14
|
+
Grid,
|
|
15
|
+
IconButton,
|
|
16
|
+
TextField,
|
|
17
|
+
Card,
|
|
18
|
+
CardContent,
|
|
19
|
+
Typography,
|
|
20
|
+
Box,
|
|
21
|
+
Chip,
|
|
22
|
+
FormControl,
|
|
23
|
+
FormLabel,
|
|
24
|
+
Divider,
|
|
25
|
+
Alert,
|
|
26
|
+
useTheme,
|
|
27
|
+
useMediaQuery
|
|
28
|
+
} from '@mui/material';
|
|
29
|
+
import HomeIcon from '@mui/icons-material/Home';
|
|
30
|
+
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
31
|
+
import GoogleIcon from '@mui/icons-material/Google';
|
|
32
|
+
|
|
33
|
+
import { DASH_REDUX_ACTIONS } from 'dash-admin-state';
|
|
34
|
+
import DictionaryContext from 'dash-admin/src/contexts/dictionary/DictionaryContext';
|
|
35
|
+
import { useAxios } from 'dash-axios-hook';
|
|
36
|
+
import { useDialog } from 'dash-dialog';
|
|
37
|
+
import { DASHAdminSystemConstants } from 'dash-constants';
|
|
38
|
+
import { RutValidator } from 'dash-admin/src/utils/validators';
|
|
39
|
+
import FullLayoutMarkup from 'dash-admin/src/default-theme/FullLayoutMarkup';
|
|
40
|
+
import { priceFormatter } from 'dash-utils';
|
|
41
|
+
|
|
42
|
+
interface SubscriptionPlan {
|
|
43
|
+
id: number;
|
|
44
|
+
name: string;
|
|
45
|
+
slug: string;
|
|
46
|
+
description: string;
|
|
47
|
+
price: number;
|
|
48
|
+
billing_cycle: 'monthly' | 'yearly';
|
|
49
|
+
features: string[];
|
|
50
|
+
is_active: boolean;
|
|
51
|
+
trial_days: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface SignUpFormData {
|
|
55
|
+
email: string;
|
|
56
|
+
clientname: string;
|
|
57
|
+
public_id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
lastname: string;
|
|
60
|
+
password: string;
|
|
61
|
+
confirm_password: string;
|
|
62
|
+
phone: string;
|
|
63
|
+
selected_plan_id?: number;
|
|
64
|
+
'g-recaptcha-response'?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface DefaultSignUpPageProps {
|
|
68
|
+
panelSettings?: {
|
|
69
|
+
horizontalLogo?: string;
|
|
70
|
+
loginBackground?: string;
|
|
71
|
+
};
|
|
72
|
+
showRutField?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const DefaultSignUpPage: React.FC<DefaultSignUpPageProps> = (props) => {
|
|
76
|
+
const { panelSettings, showRutField = true } = props;
|
|
77
|
+
|
|
78
|
+
const enableRecaptcha: boolean = DASHAdminSystemConstants.system.RECAPTCHA_ENABLED;
|
|
79
|
+
const enableGoogleSignup: boolean = DASHAdminSystemConstants.system.GOOGLE_SIGNUP !== false;
|
|
80
|
+
const recaptchaRef = createRef<ReCAPTCHA>();
|
|
81
|
+
const [recpatcha, setRecaptcha] = useState(null);
|
|
82
|
+
const [plans, setPlans] = useState<SubscriptionPlan[]>([]);
|
|
83
|
+
const [selectedPlan, setSelectedPlan] = useState<number | null>(null);
|
|
84
|
+
const [loading, setLoading] = useState(false);
|
|
85
|
+
const [plansLoading, setPlansLoading] = useState(true);
|
|
86
|
+
const [googleAuthLoading, setGoogleAuthLoading] = useState(false);
|
|
87
|
+
|
|
88
|
+
const theme = useTheme();
|
|
89
|
+
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
|
90
|
+
|
|
91
|
+
const dispatch = useDispatch();
|
|
92
|
+
const dialog = useDialog();
|
|
93
|
+
const dict = React.useContext(DictionaryContext);
|
|
94
|
+
const navigate = useNavigate();
|
|
95
|
+
const form = useForm<SignUpFormData>();
|
|
96
|
+
const {
|
|
97
|
+
register,
|
|
98
|
+
handleSubmit,
|
|
99
|
+
setError,
|
|
100
|
+
clearErrors,
|
|
101
|
+
formState: { errors },
|
|
102
|
+
setValue,
|
|
103
|
+
watch
|
|
104
|
+
} = form;
|
|
105
|
+
const axios = useAxios();
|
|
106
|
+
const notify = useNotify();
|
|
107
|
+
|
|
108
|
+
const onChangeRecaptcha = (value: string) => {
|
|
109
|
+
clearErrors('g-recaptcha-response');
|
|
110
|
+
setRecaptcha(value);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Load subscription plans
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const loadPlans = async () => {
|
|
116
|
+
try {
|
|
117
|
+
setPlansLoading(true);
|
|
118
|
+
const response = await axios.get('/subscription-plans');
|
|
119
|
+
if (response.data?.data) {
|
|
120
|
+
setPlans(response.data.data);
|
|
121
|
+
if (response.data.data.length > 0) {
|
|
122
|
+
setSelectedPlan(response.data.data[0].id);
|
|
123
|
+
setValue('selected_plan_id', response.data.data[0].id);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error('Error loading subscription plans:', error);
|
|
128
|
+
notify('Error loading subscription plans', { type: 'warning' });
|
|
129
|
+
} finally {
|
|
130
|
+
setPlansLoading(false);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
loadPlans();
|
|
135
|
+
}, []);
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
dispatch(
|
|
139
|
+
DASH_REDUX_ACTIONS.updatePage({
|
|
140
|
+
title: null,
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
143
|
+
}, []);
|
|
144
|
+
|
|
145
|
+
const handlePlanSelection = (planId: number) => {
|
|
146
|
+
setSelectedPlan(planId);
|
|
147
|
+
setValue('selected_plan_id', planId);
|
|
148
|
+
clearErrors('selected_plan_id');
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const handleGoogleSignUp = async () => {
|
|
152
|
+
if (!enableGoogleSignup) {
|
|
153
|
+
notify('Google signup is currently disabled', { type: 'warning' });
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
setGoogleAuthLoading(true);
|
|
159
|
+
const googleAuthUrl = DASHAdminSystemConstants.system.API_URL + `/api/auth/google/redirect?signup=true&plan_id=${selectedPlan || ''}`;
|
|
160
|
+
window.location.href = googleAuthUrl;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Google authentication error:', error);
|
|
163
|
+
notify('Google authentication error', { type: 'error' });
|
|
164
|
+
} finally {
|
|
165
|
+
setGoogleAuthLoading(false);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
async function onSubmit(data: SignUpFormData) {
|
|
170
|
+
try {
|
|
171
|
+
setLoading(true);
|
|
172
|
+
clearErrors();
|
|
173
|
+
|
|
174
|
+
if (!selectedPlan) {
|
|
175
|
+
setError('selected_plan_id', {
|
|
176
|
+
type: 'required',
|
|
177
|
+
message: 'Please select a subscription plan'
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (data.clientname) {
|
|
183
|
+
const bracketed_name = 'client[name]';
|
|
184
|
+
data[bracketed_name] = data.clientname;
|
|
185
|
+
delete data.clientname;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
data.selected_plan_id = selectedPlan;
|
|
189
|
+
|
|
190
|
+
if (enableRecaptcha) {
|
|
191
|
+
const recaptchaValue =
|
|
192
|
+
recaptchaRef.current && recaptchaRef.current.getValue
|
|
193
|
+
? recaptchaRef.current.getValue()
|
|
194
|
+
: recpatcha;
|
|
195
|
+
data['g-recaptcha-response'] = recaptchaValue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const response = await axios.post('/auth/user/signup', data, {
|
|
199
|
+
headers: { 'Content-Type': 'multipart/form-data' },
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (response.status >= 200) {
|
|
203
|
+
notify('Account created successfully!', { type: 'success' });
|
|
204
|
+
navigate('/signup-success', {
|
|
205
|
+
state: {
|
|
206
|
+
email: data.email,
|
|
207
|
+
planName: plans.find(p => p.id === selectedPlan)?.name
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
dialog({
|
|
212
|
+
variant: 'danger',
|
|
213
|
+
title: 'Error',
|
|
214
|
+
content: 'An error occurred, please try again',
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
} catch (error: any) {
|
|
218
|
+
console.error('SignUp error:', error);
|
|
219
|
+
|
|
220
|
+
if (error.response?.data?.errors) {
|
|
221
|
+
const errors = error.response.data.errors;
|
|
222
|
+
for (const key in errors) {
|
|
223
|
+
if (key === 'client.name') {
|
|
224
|
+
setError('clientname', {
|
|
225
|
+
type: 'custom',
|
|
226
|
+
message: dict.get(errors[key], true),
|
|
227
|
+
});
|
|
228
|
+
} else {
|
|
229
|
+
setError(key as keyof SignUpFormData, {
|
|
230
|
+
type: 'custom',
|
|
231
|
+
message: dict.get(errors[key], true)
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
notify('Registration error occurred', { type: 'error' });
|
|
237
|
+
}
|
|
238
|
+
} finally {
|
|
239
|
+
setLoading(false);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const formatPrice = (price: number, billingCycle: string) => {
|
|
244
|
+
return `${priceFormatter(price, 'USD')}/${billingCycle === 'monthly' ? 'mo' : 'yr'}`;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const getTrialText = (trialDays: number) => {
|
|
248
|
+
return trialDays > 0 ? `${trialDays} days free trial` : 'No trial period';
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<FullLayoutMarkup
|
|
253
|
+
className='dash-signup'
|
|
254
|
+
logo={panelSettings?.horizontalLogo}
|
|
255
|
+
loginBackground={panelSettings?.loginBackground}
|
|
256
|
+
>
|
|
257
|
+
<form onSubmit={handleSubmit(onSubmit)} className='dash-app-login-form'>
|
|
258
|
+
<Box sx={{ display: 'flex', alignItems: 'center', mb: 4, mt: 2, gap: 1 }}>
|
|
259
|
+
<IconButton color='primary' size='large' onClick={() => navigate('/')}>
|
|
260
|
+
<HomeIcon />
|
|
261
|
+
</IconButton>
|
|
262
|
+
<Typography
|
|
263
|
+
variant={isMobile ? "h5" : "h4"}
|
|
264
|
+
component="h1"
|
|
265
|
+
className='dash-app-login-form-title'
|
|
266
|
+
sx={{ fontWeight: 'bold' }}
|
|
267
|
+
>
|
|
268
|
+
Create Your Account
|
|
269
|
+
</Typography>
|
|
270
|
+
</Box>
|
|
271
|
+
|
|
272
|
+
{enableGoogleSignup && (
|
|
273
|
+
<>
|
|
274
|
+
<div className='dash-app-form-item'>
|
|
275
|
+
<Button
|
|
276
|
+
fullWidth
|
|
277
|
+
variant="outlined"
|
|
278
|
+
startIcon={<GoogleIcon />}
|
|
279
|
+
onClick={handleGoogleSignUp}
|
|
280
|
+
disabled={googleAuthLoading || !selectedPlan}
|
|
281
|
+
size="large"
|
|
282
|
+
>
|
|
283
|
+
{googleAuthLoading ? 'Connecting...' : 'Continue with Google'}
|
|
284
|
+
</Button>
|
|
285
|
+
</div>
|
|
286
|
+
<Divider sx={{ my: 3 }}>
|
|
287
|
+
<Typography variant="body2" color="textSecondary">
|
|
288
|
+
or sign up with email
|
|
289
|
+
</Typography>
|
|
290
|
+
</Divider>
|
|
291
|
+
</>
|
|
292
|
+
)}
|
|
293
|
+
|
|
294
|
+
{/* Subscription Plans */}
|
|
295
|
+
<div className='dash-app-form-item'>
|
|
296
|
+
<FormControl component="fieldset" fullWidth>
|
|
297
|
+
<FormLabel component="legend">
|
|
298
|
+
<Typography variant={isMobile ? "h6" : "h5"} gutterBottom>
|
|
299
|
+
Choose Your Plan
|
|
300
|
+
</Typography>
|
|
301
|
+
</FormLabel>
|
|
302
|
+
|
|
303
|
+
{plansLoading ? (
|
|
304
|
+
<Box display="flex" justifyContent="center" p={2}>
|
|
305
|
+
<Typography>Loading plans...</Typography>
|
|
306
|
+
</Box>
|
|
307
|
+
) : (
|
|
308
|
+
<Grid container spacing={2}>
|
|
309
|
+
{plans.map((plan) => (
|
|
310
|
+
<Grid key={plan.id} size={{ xs: 12, sm: 6, md: 4 }}>
|
|
311
|
+
<Card
|
|
312
|
+
variant={selectedPlan === plan.id ? "outlined" : "elevation"}
|
|
313
|
+
sx={{
|
|
314
|
+
cursor: 'pointer',
|
|
315
|
+
border: selectedPlan === plan.id ? 2 : 1,
|
|
316
|
+
borderColor: selectedPlan === plan.id ? 'primary.main' : 'divider',
|
|
317
|
+
'&:hover': { borderColor: 'primary.main' },
|
|
318
|
+
height: '100%'
|
|
319
|
+
}}
|
|
320
|
+
onClick={() => handlePlanSelection(plan.id)}
|
|
321
|
+
>
|
|
322
|
+
<CardContent>
|
|
323
|
+
<Box display="flex" alignItems="center" mb={2}>
|
|
324
|
+
<Typography variant="h6">{plan.name}</Typography>
|
|
325
|
+
{selectedPlan === plan.id && (
|
|
326
|
+
<CheckCircleIcon color="primary" sx={{ ml: 'auto' }} />
|
|
327
|
+
)}
|
|
328
|
+
</Box>
|
|
329
|
+
<Typography variant="h4" color="primary" gutterBottom>
|
|
330
|
+
${formatPrice(plan.price, plan.billing_cycle)}
|
|
331
|
+
</Typography>
|
|
332
|
+
<Chip label={getTrialText(plan.trial_days)} color="secondary" size="small" sx={{ mb: 2 }} />
|
|
333
|
+
<Typography variant="body2" color="textSecondary">
|
|
334
|
+
{plan.description}
|
|
335
|
+
</Typography>
|
|
336
|
+
</CardContent>
|
|
337
|
+
</Card>
|
|
338
|
+
</Grid>
|
|
339
|
+
))}
|
|
340
|
+
</Grid>
|
|
341
|
+
)}
|
|
342
|
+
|
|
343
|
+
{errors.selected_plan_id && (
|
|
344
|
+
<Alert severity="error" sx={{ mt: 2 }}>
|
|
345
|
+
{errors.selected_plan_id.message}
|
|
346
|
+
</Alert>
|
|
347
|
+
)}
|
|
348
|
+
</FormControl>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
{/* User Information Form */}
|
|
352
|
+
<Typography variant="h6" gutterBottom sx={{ mt: 4 }}>
|
|
353
|
+
Account Information
|
|
354
|
+
</Typography>
|
|
355
|
+
|
|
356
|
+
<div className='dash-app-form-item'>
|
|
357
|
+
<TextField
|
|
358
|
+
label="Email"
|
|
359
|
+
required
|
|
360
|
+
fullWidth
|
|
361
|
+
{...register('email', { required: 'Email is required' })}
|
|
362
|
+
inputProps={{ type: 'email' }}
|
|
363
|
+
error={!!errors.email}
|
|
364
|
+
helperText={errors.email?.message}
|
|
365
|
+
/>
|
|
366
|
+
</div>
|
|
367
|
+
|
|
368
|
+
<div className='dash-app-form-item'>
|
|
369
|
+
<TextField
|
|
370
|
+
label="Business Name"
|
|
371
|
+
required
|
|
372
|
+
fullWidth
|
|
373
|
+
{...register('clientname', { required: 'Business name is required' })}
|
|
374
|
+
error={!!errors.clientname}
|
|
375
|
+
helperText={errors.clientname?.message}
|
|
376
|
+
/>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
{showRutField && (
|
|
380
|
+
<div className='dash-app-form-item'>
|
|
381
|
+
<TextField
|
|
382
|
+
label="RUT"
|
|
383
|
+
placeholder='11.111.111-1'
|
|
384
|
+
fullWidth
|
|
385
|
+
{...register('public_id', { validate: RutValidator })}
|
|
386
|
+
error={!!errors.public_id}
|
|
387
|
+
helperText={errors.public_id?.message}
|
|
388
|
+
/>
|
|
389
|
+
</div>
|
|
390
|
+
)}
|
|
391
|
+
|
|
392
|
+
<Grid container spacing={2}>
|
|
393
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
394
|
+
<div className='dash-app-form-item'>
|
|
395
|
+
<TextField
|
|
396
|
+
label="First Name"
|
|
397
|
+
required
|
|
398
|
+
fullWidth
|
|
399
|
+
{...register('name', { required: 'First name is required' })}
|
|
400
|
+
error={!!errors.name}
|
|
401
|
+
helperText={errors.name?.message}
|
|
402
|
+
/>
|
|
403
|
+
</div>
|
|
404
|
+
</Grid>
|
|
405
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
406
|
+
<div className='dash-app-form-item'>
|
|
407
|
+
<TextField
|
|
408
|
+
label="Last Name"
|
|
409
|
+
required
|
|
410
|
+
fullWidth
|
|
411
|
+
{...register('lastname', { required: 'Last name is required' })}
|
|
412
|
+
error={!!errors.lastname}
|
|
413
|
+
helperText={errors.lastname?.message}
|
|
414
|
+
/>
|
|
415
|
+
</div>
|
|
416
|
+
</Grid>
|
|
417
|
+
</Grid>
|
|
418
|
+
|
|
419
|
+
<Grid container spacing={2}>
|
|
420
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
421
|
+
<div className='dash-app-form-item'>
|
|
422
|
+
<TextField
|
|
423
|
+
label="Password"
|
|
424
|
+
type='password'
|
|
425
|
+
required
|
|
426
|
+
fullWidth
|
|
427
|
+
{...register('password', { required: 'Password is required', minLength: { value: 8, message: 'Password must be at least 8 characters' } })}
|
|
428
|
+
error={!!errors.password}
|
|
429
|
+
helperText={errors.password?.message}
|
|
430
|
+
/>
|
|
431
|
+
</div>
|
|
432
|
+
</Grid>
|
|
433
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
434
|
+
<div className='dash-app-form-item'>
|
|
435
|
+
<TextField
|
|
436
|
+
label="Confirm Password"
|
|
437
|
+
type='password'
|
|
438
|
+
required
|
|
439
|
+
fullWidth
|
|
440
|
+
{...register('confirm_password', { required: 'Please confirm your password' })}
|
|
441
|
+
error={!!errors.confirm_password}
|
|
442
|
+
helperText={errors.confirm_password?.message}
|
|
443
|
+
/>
|
|
444
|
+
</div>
|
|
445
|
+
</Grid>
|
|
446
|
+
</Grid>
|
|
447
|
+
|
|
448
|
+
<div className='dash-app-form-item'>
|
|
449
|
+
<TextField
|
|
450
|
+
label="Contact Phone"
|
|
451
|
+
placeholder='+1 234 567 8900'
|
|
452
|
+
required
|
|
453
|
+
fullWidth
|
|
454
|
+
{...register('phone', { required: 'Phone number is required' })}
|
|
455
|
+
error={!!errors.phone}
|
|
456
|
+
helperText={errors.phone?.message}
|
|
457
|
+
/>
|
|
458
|
+
</div>
|
|
459
|
+
|
|
460
|
+
{enableRecaptcha && (
|
|
461
|
+
<div className='dash-app-form-item'>
|
|
462
|
+
<ReCAPTCHA
|
|
463
|
+
ref={recaptchaRef}
|
|
464
|
+
sitekey={DASHAdminSystemConstants.system.RECAPTCHA_TOKEN}
|
|
465
|
+
onChange={onChangeRecaptcha}
|
|
466
|
+
/>
|
|
467
|
+
</div>
|
|
468
|
+
)}
|
|
469
|
+
|
|
470
|
+
<div className='dash-app-form-item'>
|
|
471
|
+
<Button
|
|
472
|
+
disabled={(!recpatcha && enableRecaptcha) || loading || !selectedPlan}
|
|
473
|
+
type='submit'
|
|
474
|
+
fullWidth
|
|
475
|
+
variant='contained'
|
|
476
|
+
size="large"
|
|
477
|
+
>
|
|
478
|
+
{loading ? 'Creating Account...' : 'Create Account & Start Trial'}
|
|
479
|
+
</Button>
|
|
480
|
+
</div>
|
|
481
|
+
|
|
482
|
+
<div className='dash-app-form-item'>
|
|
483
|
+
<Button fullWidth onClick={() => navigate('/')} disabled={loading}>
|
|
484
|
+
Cancel
|
|
485
|
+
</Button>
|
|
486
|
+
</div>
|
|
487
|
+
</form>
|
|
488
|
+
</FullLayoutMarkup>
|
|
489
|
+
);
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
export default DefaultSignUpPage;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default SignUp Success Page
|
|
3
|
+
*
|
|
4
|
+
* Success page displayed after successful registration.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { useLocation, useNavigate } from 'react-router-dom';
|
|
8
|
+
import {
|
|
9
|
+
Box,
|
|
10
|
+
Typography,
|
|
11
|
+
Button,
|
|
12
|
+
Paper,
|
|
13
|
+
Container
|
|
14
|
+
} from '@mui/material';
|
|
15
|
+
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
|
|
16
|
+
import EmailIcon from '@mui/icons-material/Email';
|
|
17
|
+
|
|
18
|
+
import FullLayoutMarkup from 'dash-admin/src/default-theme/FullLayoutMarkup';
|
|
19
|
+
|
|
20
|
+
interface SignUpSuccessState {
|
|
21
|
+
email?: string;
|
|
22
|
+
planName?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface DefaultSignUpSuccessPageProps {
|
|
26
|
+
panelSettings?: {
|
|
27
|
+
horizontalLogo?: string;
|
|
28
|
+
loginBackground?: string;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DefaultSignUpSuccessPage: React.FC<DefaultSignUpSuccessPageProps> = (props) => {
|
|
33
|
+
const { panelSettings } = props;
|
|
34
|
+
const location = useLocation();
|
|
35
|
+
const navigate = useNavigate();
|
|
36
|
+
const state = location.state as SignUpSuccessState;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<FullLayoutMarkup
|
|
40
|
+
className='dash-signup-success'
|
|
41
|
+
logo={panelSettings?.horizontalLogo}
|
|
42
|
+
loginBackground={panelSettings?.loginBackground}
|
|
43
|
+
>
|
|
44
|
+
<Container maxWidth="sm">
|
|
45
|
+
<Paper
|
|
46
|
+
elevation={3}
|
|
47
|
+
sx={{
|
|
48
|
+
p: 4,
|
|
49
|
+
textAlign: 'center',
|
|
50
|
+
borderRadius: 2
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<CheckCircleOutlineIcon
|
|
54
|
+
color="success"
|
|
55
|
+
sx={{ fontSize: 80, mb: 2 }}
|
|
56
|
+
/>
|
|
57
|
+
|
|
58
|
+
<Typography variant="h4" component="h1" gutterBottom>
|
|
59
|
+
Account Created Successfully!
|
|
60
|
+
</Typography>
|
|
61
|
+
|
|
62
|
+
<Typography variant="body1" color="textSecondary" paragraph>
|
|
63
|
+
Thank you for signing up{state?.planName ? ` for the ${state.planName} plan` : ''}.
|
|
64
|
+
</Typography>
|
|
65
|
+
|
|
66
|
+
<Box
|
|
67
|
+
sx={{
|
|
68
|
+
display: 'flex',
|
|
69
|
+
alignItems: 'center',
|
|
70
|
+
justifyContent: 'center',
|
|
71
|
+
bgcolor: 'info.light',
|
|
72
|
+
borderRadius: 1,
|
|
73
|
+
p: 2,
|
|
74
|
+
my: 3
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
<EmailIcon sx={{ mr: 1, color: 'info.dark' }} />
|
|
78
|
+
<Typography variant="body2" color="info.dark">
|
|
79
|
+
We've sent a verification email to <strong>{state?.email || 'your email address'}</strong>.
|
|
80
|
+
Please check your inbox and verify your email to complete the registration.
|
|
81
|
+
</Typography>
|
|
82
|
+
</Box>
|
|
83
|
+
|
|
84
|
+
<Typography variant="body2" color="textSecondary" paragraph>
|
|
85
|
+
If you don't see the email, please check your spam folder or request a new verification email.
|
|
86
|
+
</Typography>
|
|
87
|
+
|
|
88
|
+
<Box sx={{ mt: 4, display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
89
|
+
<Button
|
|
90
|
+
variant="contained"
|
|
91
|
+
color="primary"
|
|
92
|
+
size="large"
|
|
93
|
+
onClick={() => navigate('/login')}
|
|
94
|
+
fullWidth
|
|
95
|
+
>
|
|
96
|
+
Go to Login
|
|
97
|
+
</Button>
|
|
98
|
+
|
|
99
|
+
<Button
|
|
100
|
+
variant="outlined"
|
|
101
|
+
onClick={() => navigate('/')}
|
|
102
|
+
fullWidth
|
|
103
|
+
>
|
|
104
|
+
Back to Home
|
|
105
|
+
</Button>
|
|
106
|
+
</Box>
|
|
107
|
+
</Paper>
|
|
108
|
+
</Container>
|
|
109
|
+
</FullLayoutMarkup>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export default DefaultSignUpSuccessPage;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account Pages Module
|
|
3
|
+
*
|
|
4
|
+
* Exports all default account-related pages.
|
|
5
|
+
*/
|
|
6
|
+
export { default as DashDefaultRegister } from './DashDefaultRegister';
|
|
7
|
+
export { default as DashDefaultSignUp } from './DashDefaultSignUp';
|
|
8
|
+
export { default as DashDefaultSignUpSuccess } from './DashDefaultSignUpSuccess';
|