devextreme-cli 1.6.4 → 1.6.5
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 +3 -3
- package/src/applications/application.vue.js +16 -67
- package/src/commands.json +0 -3
- package/src/templates/react/application/src/components/change-password-form/ChangePasswordForm.tsx +86 -86
- package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.tsx +107 -107
- package/src/templates/react/application/src/components/side-navigation-menu/SideNavigationMenu.scss +1 -1
- package/src/templates/react/application/src/dx-styles.scss +17 -0
- package/src/templates/react/application/src/types.tsx +55 -55
- package/src/templates/react/sample-pages/tasks/tasks.tsx +1 -0
- package/src/templates/vue-v3/application/src/components/side-nav-menu.vue +1 -1
- package/src/templates/vue-v3/sample-pages/tasks-page.vue +1 -0
- package/src/utility/latest-versions.js +3 -3
- package/src/templates/vue-v2/application/devextreme.json +0 -39
- package/src/templates/vue-v2/application/src/App.vue +0 -91
- package/src/templates/vue-v2/application/src/app-info.js +0 -3
- package/src/templates/vue-v2/application/src/app-navigation.js +0 -21
- package/src/templates/vue-v2/application/src/auth.js +0 -101
- package/src/templates/vue-v2/application/src/components/app-footer.vue +0 -21
- package/src/templates/vue-v2/application/src/components/header-toolbar.vue +0 -157
- package/src/templates/vue-v2/application/src/components/side-nav-menu.vue +0 -190
- package/src/templates/vue-v2/application/src/components/user-panel.vue +0 -114
- package/src/templates/vue-v2/application/src/dx-styles.scss +0 -65
- package/src/templates/vue-v2/application/src/layouts/side-nav-inner-toolbar.vue +0 -158
- package/src/templates/vue-v2/application/src/layouts/side-nav-outer-toolbar.vue +0 -122
- package/src/templates/vue-v2/application/src/layouts/single-card.vue +0 -67
- package/src/templates/vue-v2/application/src/main.js +0 -16
- package/src/templates/vue-v2/application/src/router.js +0 -149
- package/src/templates/vue-v2/application/src/themes/metadata.additional.json +0 -11
- package/src/templates/vue-v2/application/src/themes/metadata.base.json +0 -7
- package/src/templates/vue-v2/application/src/utils/media-query.js +0 -33
- package/src/templates/vue-v2/application/src/views/change-password-form.vue +0 -105
- package/src/templates/vue-v2/application/src/views/create-account-form.vue +0 -143
- package/src/templates/vue-v2/application/src/views/login-form.vue +0 -133
- package/src/templates/vue-v2/application/src/views/reset-password-form.vue +0 -108
- package/src/templates/vue-v2/application/vue.config.js +0 -1
- package/src/templates/vue-v2/page/page.vue +0 -13
- package/src/templates/vue-v2/sample-pages/home-page.vue +0 -173
- package/src/templates/vue-v2/sample-pages/profile-page.vue +0 -84
- package/src/templates/vue-v2/sample-pages/tasks-page.vue +0 -134
- package/src/utility/prompts/vue-version.js +0 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devextreme-cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"description": "DevExtreme CLI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"devexpress",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"eslint-plugin-vue": "^7.20.0",
|
|
66
66
|
"eslint-stylish": "^0.2.0",
|
|
67
67
|
"jest": "^29.7.0",
|
|
68
|
-
"jest-image-snapshot": "^6.
|
|
68
|
+
"jest-image-snapshot": "^6.4.0",
|
|
69
69
|
"prettier": "^2.8.8",
|
|
70
70
|
"rimraf": "^2.7.1",
|
|
71
71
|
"tree-kill": "^1.2.2",
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"typescript": "^4.0.2",
|
|
74
74
|
"typescript-eslint-parser": "^22.0.0"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "ba5f2db7dea0fb8fbf7d77050e305356309f790f"
|
|
77
77
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const getLayoutInfo = require('../utility/prompts/layout');
|
|
4
|
-
const getVersionInfo = require('../utility/prompts/vue-version');
|
|
5
4
|
const templateCreator = require('../utility/template-creator');
|
|
6
5
|
const packageManager = require('../utility/package-manager');
|
|
7
6
|
const packageJsonUtils = require('../utility/package-json-utils');
|
|
@@ -14,21 +13,8 @@ const { toolingVersionOptionName, extractToolingVersion } = require('../utility/
|
|
|
14
13
|
const defaultStyles = [
|
|
15
14
|
'devextreme/dist/css/dx.light.css'
|
|
16
15
|
];
|
|
17
|
-
const defaultVueVersion = 'v3';
|
|
18
|
-
|
|
19
|
-
const getVueVersion = () => {
|
|
20
|
-
const devextremeConfig = require('../utility/devextreme-config').read();
|
|
21
|
-
|
|
22
|
-
return devextremeConfig.vue
|
|
23
|
-
? `v${devextremeConfig.vue.version}`
|
|
24
|
-
: defaultVueVersion;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const preparePackageJsonForTemplate = (appPath, appName, version) => {
|
|
28
|
-
if(!version) {
|
|
29
|
-
version = getVueVersion();
|
|
30
|
-
}
|
|
31
16
|
|
|
17
|
+
const preparePackageJsonForTemplate = (appPath, appName) => {
|
|
32
18
|
const dependencies = [
|
|
33
19
|
{ name: 'sass', version: '^1.34.1' },
|
|
34
20
|
{ name: 'vue-router', version: '^3.0.1' },
|
|
@@ -36,12 +22,10 @@ const preparePackageJsonForTemplate = (appPath, appName, version) => {
|
|
|
36
22
|
{ name: 'sass-loader', version: '^10', dev: true }
|
|
37
23
|
];
|
|
38
24
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const indexVueRouter = nameDepends.indexOf('vue-router');
|
|
25
|
+
const nameDepends = dependencies.map(d => d.name);
|
|
26
|
+
const indexVueRouter = nameDepends.indexOf('vue-router');
|
|
42
27
|
|
|
43
|
-
|
|
44
|
-
}
|
|
28
|
+
dependencies[indexVueRouter].version = '^4.0.1';
|
|
45
29
|
|
|
46
30
|
const scripts = [
|
|
47
31
|
{ name: 'build-themes', value: 'devextreme build' },
|
|
@@ -54,27 +38,18 @@ const preparePackageJsonForTemplate = (appPath, appName, version) => {
|
|
|
54
38
|
};
|
|
55
39
|
|
|
56
40
|
async function createVueApp(name, templateOptions) {
|
|
57
|
-
const { version } = templateOptions;
|
|
58
41
|
const toolingVersion = extractToolingVersion(templateOptions);
|
|
59
|
-
const argList = ['-p', `@vue/cli${toolingVersion}`, 'vue', 'create', name, '--registry', 'https://registry.npmjs.org/'];
|
|
60
|
-
|
|
61
|
-
if(version === 'v2') {
|
|
62
|
-
argList.push('-p "Default (Vue 2)"');
|
|
63
|
-
} else {
|
|
64
|
-
argList.push('-p "Default (Vue 3)"');
|
|
65
|
-
}
|
|
42
|
+
const argList = ['-p', `@vue/cli${toolingVersion}`, 'vue', 'create', name, '--registry', 'https://registry.npmjs.org/', '-p "Default (Vue 3)"'];
|
|
66
43
|
|
|
67
44
|
return runCommand('npx', argList);
|
|
68
45
|
}
|
|
69
46
|
|
|
70
47
|
const create = async(appName, options) => {
|
|
71
|
-
const version = await getVersionInfo(options.version);
|
|
72
48
|
const layout = await getLayoutInfo(options.layout);
|
|
73
49
|
|
|
74
50
|
const templateOptions = {
|
|
75
51
|
project: stringUtils.humanize(appName),
|
|
76
52
|
layout: layout,
|
|
77
|
-
version: version,
|
|
78
53
|
[toolingVersionOptionName]: options[toolingVersionOptionName]
|
|
79
54
|
};
|
|
80
55
|
|
|
@@ -99,13 +74,7 @@ const getCorrectPath = (extension, pathToApp) => {
|
|
|
99
74
|
};
|
|
100
75
|
|
|
101
76
|
const addTemplate = (appPath, appName, templateOptions) => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if(!version) {
|
|
105
|
-
version = getVueVersion();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const applicationTemplatePath = path.join(templateCreator.getTempaltePath(`vue-${version}`), 'application');
|
|
77
|
+
const applicationTemplatePath = path.join(templateCreator.getTempaltePath('vue-v3'), 'application');
|
|
109
78
|
const styles = [
|
|
110
79
|
'./themes/generated/theme.additional.css',
|
|
111
80
|
'./themes/generated/theme.base.css',
|
|
@@ -116,7 +85,7 @@ const addTemplate = (appPath, appName, templateOptions) => {
|
|
|
116
85
|
if(!templateOptions.empty) {
|
|
117
86
|
addSamplePages(appPath, templateOptions);
|
|
118
87
|
}
|
|
119
|
-
preparePackageJsonForTemplate(appPath, appName
|
|
88
|
+
preparePackageJsonForTemplate(appPath, appName);
|
|
120
89
|
install({}, appPath, styles);
|
|
121
90
|
};
|
|
122
91
|
|
|
@@ -136,14 +105,8 @@ const addStylesToApp = (appPath, styles) => {
|
|
|
136
105
|
});
|
|
137
106
|
};
|
|
138
107
|
|
|
139
|
-
const addSamplePages = (appPath
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if(!version) {
|
|
143
|
-
version = getVueVersion();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const samplePageTemplatePath = path.join(templateCreator.getTempaltePath(`vue-${version}`), 'sample-pages');
|
|
108
|
+
const addSamplePages = (appPath) => {
|
|
109
|
+
const samplePageTemplatePath = path.join(templateCreator.getTempaltePath('vue-v3'), 'sample-pages');
|
|
147
110
|
const pagesPath = createPathToPage(appPath);
|
|
148
111
|
templateCreator.moveTemplateFilesToProject(samplePageTemplatePath, pagesPath, {}, getCorrectPath);
|
|
149
112
|
};
|
|
@@ -152,35 +115,23 @@ const getComponentPageName = (viewName) => {
|
|
|
152
115
|
return `${stringUtils.classify(viewName)}`;
|
|
153
116
|
};
|
|
154
117
|
|
|
155
|
-
const getVueRoute = (viewName, componentName, pagePath
|
|
156
|
-
if(!version) {
|
|
157
|
-
version = getVueVersion();
|
|
158
|
-
}
|
|
159
|
-
|
|
118
|
+
const getVueRoute = (viewName, componentName, pagePath) => {
|
|
160
119
|
const path = `path: "/${pagePath}"`;
|
|
161
120
|
const name = `name: "${stringUtils.dasherize(viewName)}"`;
|
|
162
121
|
|
|
163
|
-
const metaPart =
|
|
164
|
-
? 'meta: { requiresAuth: true }'
|
|
165
|
-
: 'meta: {\n requiresAuth: true,\n layout: defaultLayout\n }';
|
|
122
|
+
const metaPart = 'meta: {\n requiresAuth: true,\n layout: defaultLayout\n }';
|
|
166
123
|
|
|
167
|
-
const componentPart =
|
|
168
|
-
? `components:\n {\n layout: defaultLayout,\n content: ${componentName}\n }`
|
|
169
|
-
: `component: ${componentName}`;
|
|
124
|
+
const componentPart = `component: ${componentName}`;
|
|
170
125
|
|
|
171
126
|
const commonPart = `\n {\n ${path},\n ${name},\n ${metaPart},\n ${componentPart}\n }`;
|
|
172
127
|
|
|
173
128
|
return commonPart;
|
|
174
129
|
};
|
|
175
130
|
|
|
176
|
-
const getNavigationData = (viewName, componentName, icon
|
|
177
|
-
if(!version) {
|
|
178
|
-
version = getVueVersion();
|
|
179
|
-
}
|
|
180
|
-
|
|
131
|
+
const getNavigationData = (viewName, componentName, icon) => {
|
|
181
132
|
const pagePath = stringUtils.dasherize(viewName);
|
|
182
133
|
return {
|
|
183
|
-
route: getVueRoute(viewName, componentName, pagePath
|
|
134
|
+
route: getVueRoute(viewName, componentName, pagePath),
|
|
184
135
|
navigation: `\n {\n text: \'${stringUtils.humanize(viewName)}\',\n path: \'/${pagePath}\',\n icon: \'${icon}\'\n }`
|
|
185
136
|
};
|
|
186
137
|
};
|
|
@@ -196,15 +147,13 @@ const createPathToPage = (appPath) => {
|
|
|
196
147
|
};
|
|
197
148
|
|
|
198
149
|
const addView = (pageName, options) => {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
const pageTemplatePath = path.join(templateCreator.getTempaltePath(`vue-${version}`), 'page');
|
|
150
|
+
const pageTemplatePath = path.join(templateCreator.getTempaltePath('vue-v3'), 'page');
|
|
202
151
|
|
|
203
152
|
const componentName = getComponentPageName(pageName);
|
|
204
153
|
const pathToPage = createPathToPage(process.cwd());
|
|
205
154
|
const routingModulePath = path.join(process.cwd(), 'src', 'router.js');
|
|
206
155
|
const navigationModulePath = path.join(process.cwd(), 'src', 'app-navigation.js');
|
|
207
|
-
const navigationData = getNavigationData(pageName, componentName, options && options.icon || 'folder'
|
|
156
|
+
const navigationData = getNavigationData(pageName, componentName, options && options.icon || 'folder');
|
|
208
157
|
const getCorrectExtension = (fileExtension) => fileExtension;
|
|
209
158
|
templateCreator.addPageToApp(pageName, pathToPage, pageTemplatePath, getCorrectExtension);
|
|
210
159
|
moduleUtils.insertImport(routingModulePath, `./views/${pageName}`, componentName, true);
|
package/src/commands.json
CHANGED
|
@@ -15,9 +15,6 @@
|
|
|
15
15
|
}, {
|
|
16
16
|
"name": "--empty",
|
|
17
17
|
"description": "Skips sample view generation (default: false)"
|
|
18
|
-
}, {
|
|
19
|
-
"name": "--version",
|
|
20
|
-
"description": "Specifies whether to generate a Vue 2 or Vue 3 application. Available values: 2 (default) and 3"
|
|
21
18
|
}, {
|
|
22
19
|
"name": "--template",
|
|
23
20
|
"description": "Create template with typescsript support. Specifies for React & Vue application"
|
package/src/templates/react/application/src/components/change-password-form/ChangePasswordForm.tsx
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
|
-
import Form, {
|
|
4
|
-
Item,
|
|
5
|
-
Label,
|
|
6
|
-
ButtonItem,
|
|
7
|
-
ButtonOptions,
|
|
8
|
-
RequiredRule,
|
|
9
|
-
CustomRule,
|
|
10
|
-
} from 'devextreme-react/form';
|
|
11
|
-
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
|
-
import notify from 'devextreme/ui/notify';
|
|
13
|
-
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
14
|
-
import { changePassword } from '../../api/auth';
|
|
15
|
-
|
|
16
|
-
export default function ChangePasswordForm() {
|
|
17
|
-
const navigate = useNavigate();
|
|
18
|
-
const [loading, setLoading] = useState(false);
|
|
19
|
-
const formData = useRef({ password: '' });
|
|
20
|
-
const { recoveryCode } = useParams();
|
|
21
|
-
|
|
22
|
-
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
const { password } = formData.current;
|
|
25
|
-
setLoading(true);
|
|
26
|
-
|
|
27
|
-
const result = await changePassword(password, recoveryCode);
|
|
28
|
-
setLoading(false);
|
|
29
|
-
|
|
30
|
-
if (result.isOk) {
|
|
31
|
-
navigate('/login');
|
|
32
|
-
} else {
|
|
33
|
-
notify(result.message, 'error', 2000);
|
|
34
|
-
}
|
|
35
|
-
}, [navigate, recoveryCode]);
|
|
36
|
-
|
|
37
|
-
const confirmPassword = useCallback(
|
|
38
|
-
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
39
|
-
[]
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<form onSubmit={onSubmit}>
|
|
44
|
-
<Form formData={formData.current} disabled={loading}>
|
|
45
|
-
<Item
|
|
46
|
-
dataField={'password'}
|
|
47
|
-
editorType={'dxTextBox'}
|
|
48
|
-
editorOptions={passwordEditorOptions}
|
|
49
|
-
>
|
|
50
|
-
<RequiredRule message="Password is required" />
|
|
51
|
-
<Label visible={false} />
|
|
52
|
-
</Item>
|
|
53
|
-
<Item
|
|
54
|
-
dataField={'confirmedPassword'}
|
|
55
|
-
editorType={'dxTextBox'}
|
|
56
|
-
editorOptions={confirmedPasswordEditorOptions}
|
|
57
|
-
>
|
|
58
|
-
<RequiredRule message="Password is required" />
|
|
59
|
-
<CustomRule
|
|
60
|
-
message={'Passwords do not match'}
|
|
61
|
-
validationCallback={confirmPassword}
|
|
62
|
-
/>
|
|
63
|
-
<Label visible={false} />
|
|
64
|
-
</Item>
|
|
65
|
-
<ButtonItem>
|
|
66
|
-
<ButtonOptions
|
|
67
|
-
width={'100%'}
|
|
68
|
-
type={'default'}
|
|
69
|
-
useSubmitBehavior={true}
|
|
70
|
-
>
|
|
71
|
-
<span className="dx-button-text">
|
|
72
|
-
{
|
|
73
|
-
loading
|
|
74
|
-
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
75
|
-
: 'Continue'
|
|
76
|
-
}
|
|
77
|
-
</span>
|
|
78
|
-
</ButtonOptions>
|
|
79
|
-
</ButtonItem>
|
|
80
|
-
</Form>
|
|
81
|
-
</form>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
86
|
-
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
|
1
|
+
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
+
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
|
+
import Form, {
|
|
4
|
+
Item,
|
|
5
|
+
Label,
|
|
6
|
+
ButtonItem,
|
|
7
|
+
ButtonOptions,
|
|
8
|
+
RequiredRule,
|
|
9
|
+
CustomRule,
|
|
10
|
+
} from 'devextreme-react/form';
|
|
11
|
+
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
|
+
import notify from 'devextreme/ui/notify';
|
|
13
|
+
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
14
|
+
import { changePassword } from '../../api/auth';
|
|
15
|
+
|
|
16
|
+
export default function ChangePasswordForm() {
|
|
17
|
+
const navigate = useNavigate();
|
|
18
|
+
const [loading, setLoading] = useState(false);
|
|
19
|
+
const formData = useRef({ password: '' });
|
|
20
|
+
const { recoveryCode } = useParams();
|
|
21
|
+
|
|
22
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
const { password } = formData.current;
|
|
25
|
+
setLoading(true);
|
|
26
|
+
|
|
27
|
+
const result = await changePassword(password, recoveryCode);
|
|
28
|
+
setLoading(false);
|
|
29
|
+
|
|
30
|
+
if (result.isOk) {
|
|
31
|
+
navigate('/login');
|
|
32
|
+
} else {
|
|
33
|
+
notify(result.message, 'error', 2000);
|
|
34
|
+
}
|
|
35
|
+
}, [navigate, recoveryCode]);
|
|
36
|
+
|
|
37
|
+
const confirmPassword = useCallback(
|
|
38
|
+
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
39
|
+
[]
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<form onSubmit={onSubmit}>
|
|
44
|
+
<Form formData={formData.current} disabled={loading}>
|
|
45
|
+
<Item
|
|
46
|
+
dataField={'password'}
|
|
47
|
+
editorType={'dxTextBox'}
|
|
48
|
+
editorOptions={passwordEditorOptions}
|
|
49
|
+
>
|
|
50
|
+
<RequiredRule message="Password is required" />
|
|
51
|
+
<Label visible={false} />
|
|
52
|
+
</Item>
|
|
53
|
+
<Item
|
|
54
|
+
dataField={'confirmedPassword'}
|
|
55
|
+
editorType={'dxTextBox'}
|
|
56
|
+
editorOptions={confirmedPasswordEditorOptions}
|
|
57
|
+
>
|
|
58
|
+
<RequiredRule message="Password is required" />
|
|
59
|
+
<CustomRule
|
|
60
|
+
message={'Passwords do not match'}
|
|
61
|
+
validationCallback={confirmPassword}
|
|
62
|
+
/>
|
|
63
|
+
<Label visible={false} />
|
|
64
|
+
</Item>
|
|
65
|
+
<ButtonItem>
|
|
66
|
+
<ButtonOptions
|
|
67
|
+
width={'100%'}
|
|
68
|
+
type={'default'}
|
|
69
|
+
useSubmitBehavior={true}
|
|
70
|
+
>
|
|
71
|
+
<span className="dx-button-text">
|
|
72
|
+
{
|
|
73
|
+
loading
|
|
74
|
+
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
75
|
+
: 'Continue'
|
|
76
|
+
}
|
|
77
|
+
</span>
|
|
78
|
+
</ButtonOptions>
|
|
79
|
+
</ButtonItem>
|
|
80
|
+
</Form>
|
|
81
|
+
</form>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
86
|
+
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.tsx
CHANGED
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link, useNavigate } from 'react-router-dom';
|
|
3
|
-
import Form, {
|
|
4
|
-
Item,
|
|
5
|
-
Label,
|
|
6
|
-
ButtonItem,
|
|
7
|
-
ButtonOptions,
|
|
8
|
-
RequiredRule,
|
|
9
|
-
CustomRule,
|
|
10
|
-
EmailRule
|
|
11
|
-
} from 'devextreme-react/form';
|
|
12
|
-
import notify from 'devextreme/ui/notify';
|
|
13
|
-
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
14
|
-
import { createAccount } from '../../api/auth';
|
|
15
|
-
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
16
|
-
import './CreateAccountForm.scss';
|
|
17
|
-
|
|
18
|
-
export default function CreateAccountForm() {
|
|
19
|
-
const navigate = useNavigate();
|
|
20
|
-
const [loading, setLoading] = useState(false);
|
|
21
|
-
const formData = useRef({ email: '', password: '' });
|
|
22
|
-
|
|
23
|
-
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
24
|
-
e.preventDefault();
|
|
25
|
-
const { email, password } = formData.current;
|
|
26
|
-
setLoading(true);
|
|
27
|
-
|
|
28
|
-
const result = await createAccount(email, password);
|
|
29
|
-
setLoading(false);
|
|
30
|
-
|
|
31
|
-
if (result.isOk) {
|
|
32
|
-
navigate('/login');
|
|
33
|
-
} else {
|
|
34
|
-
notify(result.message, 'error', 2000);
|
|
35
|
-
}
|
|
36
|
-
}, [navigate]);
|
|
37
|
-
|
|
38
|
-
const confirmPassword = useCallback(
|
|
39
|
-
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
40
|
-
[]
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<form className={'create-account-form'} onSubmit={onSubmit}>
|
|
45
|
-
<Form formData={formData.current} disabled={loading}>
|
|
46
|
-
<Item
|
|
47
|
-
dataField={'email'}
|
|
48
|
-
editorType={'dxTextBox'}
|
|
49
|
-
editorOptions={emailEditorOptions}
|
|
50
|
-
>
|
|
51
|
-
<RequiredRule message="Email is required" />
|
|
52
|
-
<EmailRule message="Email is invalid" />
|
|
53
|
-
<Label visible={false} />
|
|
54
|
-
</Item>
|
|
55
|
-
<Item
|
|
56
|
-
dataField={'password'}
|
|
57
|
-
editorType={'dxTextBox'}
|
|
58
|
-
editorOptions={passwordEditorOptions}
|
|
59
|
-
>
|
|
60
|
-
<RequiredRule message="Password is required" />
|
|
61
|
-
<Label visible={false} />
|
|
62
|
-
</Item>
|
|
63
|
-
<Item
|
|
64
|
-
dataField={'confirmedPassword'}
|
|
65
|
-
editorType={'dxTextBox'}
|
|
66
|
-
editorOptions={confirmedPasswordEditorOptions}
|
|
67
|
-
>
|
|
68
|
-
<RequiredRule message="Password is required" />
|
|
69
|
-
<CustomRule
|
|
70
|
-
message={'Passwords do not match'}
|
|
71
|
-
validationCallback={confirmPassword}
|
|
72
|
-
/>
|
|
73
|
-
<Label visible={false} />
|
|
74
|
-
</Item>
|
|
75
|
-
<Item>
|
|
76
|
-
<div className='policy-info'>
|
|
77
|
-
By creating an account, you agree to the <Link to="#">Terms of Service</Link> and <Link to="#">Privacy Policy</Link>
|
|
78
|
-
</div>
|
|
79
|
-
</Item>
|
|
80
|
-
<ButtonItem>
|
|
81
|
-
<ButtonOptions
|
|
82
|
-
width={'100%'}
|
|
83
|
-
type={'default'}
|
|
84
|
-
useSubmitBehavior={true}
|
|
85
|
-
>
|
|
86
|
-
<span className="dx-button-text">
|
|
87
|
-
{
|
|
88
|
-
loading
|
|
89
|
-
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
90
|
-
: 'Create a new account'
|
|
91
|
-
}
|
|
92
|
-
</span>
|
|
93
|
-
</ButtonOptions>
|
|
94
|
-
</ButtonItem>
|
|
95
|
-
<Item>
|
|
96
|
-
<div className={'login-link'}>
|
|
97
|
-
Have an account? <Link to={'/login'}>Sign In</Link>
|
|
98
|
-
</div>
|
|
99
|
-
</Item>
|
|
100
|
-
</Form>
|
|
101
|
-
</form>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const emailEditorOptions = { stylingMode: 'filled', placeholder: 'Email', mode: 'email' };
|
|
106
|
-
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
107
|
-
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
|
1
|
+
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
3
|
+
import Form, {
|
|
4
|
+
Item,
|
|
5
|
+
Label,
|
|
6
|
+
ButtonItem,
|
|
7
|
+
ButtonOptions,
|
|
8
|
+
RequiredRule,
|
|
9
|
+
CustomRule,
|
|
10
|
+
EmailRule
|
|
11
|
+
} from 'devextreme-react/form';
|
|
12
|
+
import notify from 'devextreme/ui/notify';
|
|
13
|
+
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
14
|
+
import { createAccount } from '../../api/auth';
|
|
15
|
+
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
|
|
16
|
+
import './CreateAccountForm.scss';
|
|
17
|
+
|
|
18
|
+
export default function CreateAccountForm() {
|
|
19
|
+
const navigate = useNavigate();
|
|
20
|
+
const [loading, setLoading] = useState(false);
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
22
|
+
|
|
23
|
+
const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
const { email, password } = formData.current;
|
|
26
|
+
setLoading(true);
|
|
27
|
+
|
|
28
|
+
const result = await createAccount(email, password);
|
|
29
|
+
setLoading(false);
|
|
30
|
+
|
|
31
|
+
if (result.isOk) {
|
|
32
|
+
navigate('/login');
|
|
33
|
+
} else {
|
|
34
|
+
notify(result.message, 'error', 2000);
|
|
35
|
+
}
|
|
36
|
+
}, [navigate]);
|
|
37
|
+
|
|
38
|
+
const confirmPassword = useCallback(
|
|
39
|
+
({ value }<%=#isTypeScript%>: ValidationCallbackData<%=/isTypeScript%>) => value === formData.current.password,
|
|
40
|
+
[]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<form className={'create-account-form'} onSubmit={onSubmit}>
|
|
45
|
+
<Form formData={formData.current} disabled={loading}>
|
|
46
|
+
<Item
|
|
47
|
+
dataField={'email'}
|
|
48
|
+
editorType={'dxTextBox'}
|
|
49
|
+
editorOptions={emailEditorOptions}
|
|
50
|
+
>
|
|
51
|
+
<RequiredRule message="Email is required" />
|
|
52
|
+
<EmailRule message="Email is invalid" />
|
|
53
|
+
<Label visible={false} />
|
|
54
|
+
</Item>
|
|
55
|
+
<Item
|
|
56
|
+
dataField={'password'}
|
|
57
|
+
editorType={'dxTextBox'}
|
|
58
|
+
editorOptions={passwordEditorOptions}
|
|
59
|
+
>
|
|
60
|
+
<RequiredRule message="Password is required" />
|
|
61
|
+
<Label visible={false} />
|
|
62
|
+
</Item>
|
|
63
|
+
<Item
|
|
64
|
+
dataField={'confirmedPassword'}
|
|
65
|
+
editorType={'dxTextBox'}
|
|
66
|
+
editorOptions={confirmedPasswordEditorOptions}
|
|
67
|
+
>
|
|
68
|
+
<RequiredRule message="Password is required" />
|
|
69
|
+
<CustomRule
|
|
70
|
+
message={'Passwords do not match'}
|
|
71
|
+
validationCallback={confirmPassword}
|
|
72
|
+
/>
|
|
73
|
+
<Label visible={false} />
|
|
74
|
+
</Item>
|
|
75
|
+
<Item>
|
|
76
|
+
<div className='policy-info'>
|
|
77
|
+
By creating an account, you agree to the <Link to="#">Terms of Service</Link> and <Link to="#">Privacy Policy</Link>
|
|
78
|
+
</div>
|
|
79
|
+
</Item>
|
|
80
|
+
<ButtonItem>
|
|
81
|
+
<ButtonOptions
|
|
82
|
+
width={'100%'}
|
|
83
|
+
type={'default'}
|
|
84
|
+
useSubmitBehavior={true}
|
|
85
|
+
>
|
|
86
|
+
<span className="dx-button-text">
|
|
87
|
+
{
|
|
88
|
+
loading
|
|
89
|
+
? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
|
|
90
|
+
: 'Create a new account'
|
|
91
|
+
}
|
|
92
|
+
</span>
|
|
93
|
+
</ButtonOptions>
|
|
94
|
+
</ButtonItem>
|
|
95
|
+
<Item>
|
|
96
|
+
<div className={'login-link'}>
|
|
97
|
+
Have an account? <Link to={'/login'}>Sign In</Link>
|
|
98
|
+
</div>
|
|
99
|
+
</Item>
|
|
100
|
+
</Form>
|
|
101
|
+
</form>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const emailEditorOptions = { stylingMode: 'filled', placeholder: 'Email', mode: 'email' };
|
|
106
|
+
const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
|
|
107
|
+
const confirmedPasswordEditorOptions = { stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' };
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
@import "./themes/generated/variables.base.scss";
|
|
2
2
|
|
|
3
|
+
body {
|
|
4
|
+
font-family:
|
|
5
|
+
-apple-system,
|
|
6
|
+
BlinkMacSystemFont,
|
|
7
|
+
'Segoe UI',
|
|
8
|
+
'Roboto',
|
|
9
|
+
'Oxygen',
|
|
10
|
+
'Ubuntu',
|
|
11
|
+
'Cantarell',
|
|
12
|
+
'Fira Sans',
|
|
13
|
+
'Droid Sans',
|
|
14
|
+
'Helvetica Neue',
|
|
15
|
+
sans-serif;
|
|
16
|
+
-webkit-font-smoothing: antialiased;
|
|
17
|
+
-moz-osx-font-smoothing: grayscale;
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
.app {
|
|
4
21
|
background-color: darken($base-bg, 5.00);
|
|
5
22
|
display: flex;
|