devextreme-cli 1.3.0-beta.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/index.js +1 -1
  2. package/package.json +32 -9
  3. package/src/.DS_Store +0 -0
  4. package/src/application.js +1 -1
  5. package/src/applications/application.angular.js +46 -10
  6. package/src/applications/application.react.js +4 -4
  7. package/src/applications/application.vue.js +103 -35
  8. package/src/commands.json +34 -25
  9. package/src/templates/.DS_Store +0 -0
  10. package/src/templates/react/application/src/App.js +3 -3
  11. package/src/templates/react/application/src/Content.js +1 -1
  12. package/src/templates/react/application/src/{NotAuthenticatedContent.js → UnauthenticatedContent.js} +1 -1
  13. package/src/templates/react/application/src/api/auth.js +1 -1
  14. package/src/templates/react/application/src/app-info.js +4 -2
  15. package/src/templates/react/application/src/components/change-password-form/change-password-form.js +1 -1
  16. package/src/templates/react/application/src/components/create-account-form/create-account-form.js +1 -1
  17. package/src/templates/react/application/src/components/footer/footer.js +2 -2
  18. package/src/templates/react/application/src/components/header/header.js +37 -37
  19. package/src/templates/react/application/src/components/login-form/login-form.js +1 -1
  20. package/src/templates/react/application/src/components/reset-password-form/reset-password-form.js +2 -2
  21. package/src/templates/react/application/src/components/side-navigation-menu/side-navigation-menu.js +5 -5
  22. package/src/templates/react/application/src/components/user-panel/user-panel.js +8 -2
  23. package/src/templates/react/application/src/dx-styles.scss +6 -1
  24. package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.js +1 -1
  25. package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.js +1 -1
  26. package/src/templates/react/application/src/layouts/single-card/single-card.js +11 -10
  27. package/src/templates/react/application/src/utils/media-query.js +1 -1
  28. package/src/templates/react/application/src/utils/patches.scss +1 -1
  29. package/src/templates/react/sample-pages/home/home.js +47 -46
  30. package/src/templates/react/sample-pages/profile/profile.js +3 -3
  31. package/src/templates/react/sample-pages/tasks/tasks.js +70 -68
  32. package/src/templates/vue-v2/.DS_Store +0 -0
  33. package/src/templates/vue-v2/application/.DS_Store +0 -0
  34. package/src/templates/vue-v2/application/devextreme.json +38 -0
  35. package/src/templates/vue-v2/application/src/.DS_Store +0 -0
  36. package/src/templates/{vue → vue-v2}/application/src/App.vue +3 -3
  37. package/src/templates/{vue → vue-v2}/application/src/app-info.js +0 -0
  38. package/src/templates/{vue → vue-v2}/application/src/app-navigation.js +0 -0
  39. package/src/templates/{vue → vue-v2}/application/src/auth.js +0 -0
  40. package/src/templates/{vue/application/src/components/the-footer.vue → vue-v2/application/src/components/app-footer.vue} +0 -0
  41. package/src/templates/{vue → vue-v2}/application/src/components/header-toolbar.vue +8 -1
  42. package/src/templates/{vue → vue-v2}/application/src/components/side-nav-menu.vue +0 -0
  43. package/src/templates/{vue → vue-v2}/application/src/components/user-panel.vue +0 -0
  44. package/src/templates/{vue → vue-v2}/application/src/dx-styles.scss +4 -0
  45. package/src/templates/{vue → vue-v2}/application/src/layouts/side-nav-inner-toolbar.vue +0 -0
  46. package/src/templates/{vue → vue-v2}/application/src/layouts/side-nav-outer-toolbar.vue +0 -0
  47. package/src/templates/{vue → vue-v2}/application/src/layouts/single-card.vue +0 -0
  48. package/src/templates/{vue → vue-v2}/application/src/main.js +0 -0
  49. package/src/templates/{vue → vue-v2}/application/src/router.js +0 -0
  50. package/src/templates/{vue → vue-v2}/application/src/themes/metadata.additional.json +0 -0
  51. package/src/templates/{vue → vue-v2}/application/src/themes/metadata.base.json +0 -0
  52. package/src/templates/{vue → vue-v2}/application/src/utils/media-query.js +0 -0
  53. package/src/templates/{vue → vue-v2}/application/src/views/change-password-form.vue +2 -3
  54. package/src/templates/{vue → vue-v2}/application/src/views/create-account-form.vue +2 -3
  55. package/src/templates/{vue → vue-v2}/application/src/views/login-form.vue +2 -3
  56. package/src/templates/{vue → vue-v2}/application/src/views/reset-password-form.vue +2 -3
  57. package/src/templates/{vue → vue-v2}/application/vue.config.js +0 -0
  58. package/src/templates/{vue → vue-v2}/page/page.vue +0 -0
  59. package/src/templates/{vue → vue-v2}/sample-pages/home.vue +5 -5
  60. package/src/templates/{vue → vue-v2}/sample-pages/profile.vue +1 -1
  61. package/src/templates/{vue → vue-v2}/sample-pages/tasks.vue +1 -0
  62. package/src/templates/vue-v3/.DS_Store +0 -0
  63. package/src/templates/vue-v3/application/.DS_Store +0 -0
  64. package/src/templates/{vue → vue-v3}/application/devextreme.json +3 -0
  65. package/src/templates/vue-v3/application/src/.DS_Store +0 -0
  66. package/src/templates/vue-v3/application/src/App.vue +101 -0
  67. package/src/templates/vue-v3/application/src/app-info.js +3 -0
  68. package/src/templates/vue-v3/application/src/app-navigation.js +21 -0
  69. package/src/templates/vue-v3/application/src/auth.js +101 -0
  70. package/src/templates/vue-v3/application/src/components/app-footer.vue +21 -0
  71. package/src/templates/vue-v3/application/src/components/header-toolbar.vue +161 -0
  72. package/src/templates/vue-v3/application/src/components/side-nav-menu.vue +204 -0
  73. package/src/templates/vue-v3/application/src/components/user-panel.vue +114 -0
  74. package/src/templates/vue-v3/application/src/dx-styles.scss +57 -0
  75. package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +192 -0
  76. package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +144 -0
  77. package/src/templates/vue-v3/application/src/layouts/single-card.vue +83 -0
  78. package/src/templates/vue-v3/application/src/main.js +10 -0
  79. package/src/templates/vue-v3/application/src/router.js +130 -0
  80. package/src/templates/vue-v3/application/src/themes/metadata.additional.json +12 -0
  81. package/src/templates/vue-v3/application/src/themes/metadata.base.json +7 -0
  82. package/src/templates/vue-v3/application/src/utils/media-query.js +33 -0
  83. package/src/templates/vue-v3/application/src/views/change-password-form.vue +115 -0
  84. package/src/templates/vue-v3/application/src/views/create-account-form.vue +155 -0
  85. package/src/templates/vue-v3/application/src/views/login-form.vue +146 -0
  86. package/src/templates/vue-v3/application/src/views/reset-password-form.vue +117 -0
  87. package/src/templates/vue-v3/application/vue.config.js +3 -0
  88. package/src/templates/vue-v3/page/page.vue +13 -0
  89. package/src/templates/vue-v3/sample-pages/home.vue +173 -0
  90. package/src/templates/vue-v3/sample-pages/profile.vue +88 -0
  91. package/src/templates/vue-v3/sample-pages/tasks.vue +133 -0
  92. package/src/themebuider.js +42 -63
  93. package/src/utility/latest-versions.js +4 -4
  94. package/src/utility/package-manager.js +8 -2
  95. package/src/{layout.js → utility/prompts/layout.js} +4 -4
  96. package/src/utility/prompts/prompts.js +16 -0
  97. package/src/utility/prompts/vue-version.js +29 -0
  98. package/src/utility/run-command.js +3 -4
  99. package/src/utility/prompts.js +0 -11
@@ -0,0 +1,144 @@
1
+ <template>
2
+ <div class="side-nav-outer-toolbar">
3
+ <header-toolbar
4
+ class="layout-header"
5
+ :menu-toggle-enabled="true"
6
+ :toggle-menu-func="toggleMenu"
7
+ :title="title"
8
+ />
9
+ <dx-drawer
10
+ class="layout-body"
11
+ position="before"
12
+ template="menuTemplate"
13
+ v-model:opened="menuOpened"
14
+ :opened-state-mode="drawerOptions.menuMode"
15
+ :reveal-mode="drawerOptions.menuRevealMode"
16
+ :min-size="drawerOptions.minMenuSize"
17
+ :max-size="drawerOptions.maxMenuSize"
18
+ :shading="drawerOptions.shaderEnabled"
19
+ :close-on-outside-click="drawerOptions.closeOnOutsideClick"
20
+ >
21
+ <dx-scroll-view ref="scrollViewRef" class="with-footer">
22
+ <slot />
23
+ <slot name="footer" />
24
+ </dx-scroll-view>
25
+ <template #menuTemplate>
26
+ <side-nav-menu
27
+ :compact-mode="!menuOpened"
28
+ @click="handleSideBarClick"
29
+ />
30
+ </template>
31
+ </dx-drawer>
32
+ </div>
33
+ </template>
34
+
35
+ <script>
36
+ import DxDrawer from "devextreme-vue/drawer";
37
+ import DxScrollView from "devextreme-vue/scroll-view";
38
+
39
+ import menuItems from "../app-navigation";
40
+ import HeaderToolbar from "../components/header-toolbar";
41
+ import SideNavMenu from "../components/side-nav-menu";
42
+ import { computed, ref, watch} from 'vue';
43
+ import { useRoute } from 'vue-router';
44
+
45
+ export default {
46
+ props: {
47
+ title: String,
48
+ isXSmall: Boolean,
49
+ isLarge: Boolean
50
+ },
51
+ setup(props) {
52
+ const route = useRoute();
53
+
54
+ const scrollViewRef = ref(null);
55
+ const menuOpened = ref(props.isLarge);
56
+ const menuTemporaryOpened = ref(false);
57
+
58
+ function toggleMenu(e) {
59
+ const pointerEvent = e.event;
60
+ pointerEvent.stopPropagation();
61
+ if (menuOpened.value) {
62
+ menuTemporaryOpened.value = false;
63
+ }
64
+ menuOpened.value = !menuOpened.value;
65
+ }
66
+
67
+ function handleSideBarClick() {
68
+ if (menuOpened.value === false) {
69
+ menuTemporaryOpened.value = true;
70
+ }
71
+ menuOpened.value = true;
72
+ }
73
+
74
+ const drawerOptions = computed(() => {
75
+ const shaderEnabled = !props.isLarge;
76
+
77
+ return {
78
+ menuMode: props.isLarge ? "shrink" : "overlap",
79
+ menuRevealMode: props.isXSmall ? "slide" : "expand",
80
+ minMenuSize: props.isXSmall ? 0 : 60,
81
+ maxMenuSize: props.isXSmall ? 250 : undefined,
82
+ closeOnOutsideClick: shaderEnabled,
83
+ shaderEnabled
84
+ };
85
+ });
86
+
87
+ watch(
88
+ () => props.isLarge,
89
+ () => {
90
+ if (!menuTemporaryOpened.value) {
91
+ menuOpened.value = props.isLarge;
92
+ }
93
+ });
94
+
95
+ watch(
96
+ () => route.path,
97
+ () => {
98
+ if (menuTemporaryOpened.value || !props.isLarge) {
99
+ menuOpened.value = false;
100
+ menuTemporaryOpened.value = false;
101
+ }
102
+ scrollViewRef.value.instance.scrollTo(0);
103
+ }
104
+ );
105
+
106
+ return {
107
+ menuOpened,
108
+ menuItems,
109
+ toggleMenu,
110
+ handleSideBarClick,
111
+ drawerOptions,
112
+ scrollViewRef
113
+ };
114
+ },
115
+ components: {
116
+ DxDrawer,
117
+ DxScrollView,
118
+ HeaderToolbar,
119
+ SideNavMenu
120
+ }
121
+ };
122
+ </script>
123
+
124
+ <style lang="scss">
125
+ .side-nav-outer-toolbar {
126
+ flex-direction: column;
127
+ display: flex;
128
+ height: 100%;
129
+ width: 100%;
130
+ }
131
+
132
+ .layout-header {
133
+ z-index: 1501;
134
+ }
135
+
136
+ .layout-body {
137
+ flex: 1;
138
+ min-height: 0;
139
+ }
140
+
141
+ .content {
142
+ flex-grow: 1;
143
+ }
144
+ </style>
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <dx-scroll-view height="100%" width="100%" class="with-footer single-card">
3
+ <div class="dx-card content">
4
+ <div class="header">
5
+ <div class="title">{{title}}</div>
6
+ <div class="description">{{description}}</div>
7
+ </div>
8
+ <slot />
9
+ </div>
10
+ </dx-scroll-view>
11
+ </template>
12
+
13
+ <script>
14
+ import DxScrollView from "devextreme-vue/scroll-view";
15
+
16
+ import { useRoute } from 'vue-router';
17
+ import { watch, ref } from 'vue';
18
+
19
+ export default {
20
+ components: {
21
+ DxScrollView
22
+ },
23
+ setup() {
24
+ const route = useRoute();
25
+
26
+ const title = ref(route.meta.title);
27
+ const description = ref("");
28
+
29
+ watch(() => route.path,
30
+ () => {
31
+ title.value = route.meta.title;
32
+ description.value = route.meta.description;
33
+ }
34
+ )
35
+ return {
36
+ title,
37
+ description
38
+ }
39
+ }
40
+ };
41
+ </script>
42
+
43
+ <style lang="scss">
44
+ @import "../themes/generated/variables.base.scss";
45
+
46
+ .single-card {
47
+ width: 100%;
48
+ height: 100%;
49
+
50
+ .dx-card {
51
+ width: 330px;
52
+ margin: auto auto;
53
+ padding: 40px;
54
+ flex-grow: 0;
55
+
56
+ .screen-x-small & {
57
+ width: 100%;
58
+ height: 100%;
59
+ border-radius: 0;
60
+ box-shadow: none;
61
+ margin: 0;
62
+ border: 0;
63
+ flex-grow: 1;
64
+ }
65
+
66
+ .header {
67
+ margin-bottom: 30px;
68
+
69
+ .title {
70
+ color: $base-text-color;
71
+ line-height: 28px;
72
+ font-weight: 500;
73
+ font-size: 24px;
74
+ }
75
+
76
+ .description {
77
+ color: rgba($base-text-color, alpha($base-text-color) * 0.7);
78
+ line-height: 18px;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ </style>
@@ -0,0 +1,10 @@
1
+ import { createApp } from "vue";
2
+ import router from "./router";
3
+
4
+ import App from "./App";
5
+ import appInfo from "./app-info";
6
+
7
+ const app = createApp(App);
8
+ app.use(router);
9
+ app.config.globalProperties.$appInfo = appInfo;
10
+ app.mount('#app');
@@ -0,0 +1,130 @@
1
+ import auth from "./auth";
2
+ import { createRouter, createWebHashHistory } from "vue-router";
3
+
4
+ <%=^empty%>import Home from "./views/home";
5
+ import Profile from "./views/profile";
6
+ import Tasks from "./views/tasks";
7
+ <%=/empty%>import defaultLayout from "./layouts/<%=layout%>";
8
+ import simpleLayout from "./layouts/single-card";
9
+
10
+ function loadView(view) {
11
+ return () => import (/* webpackChunkName: "login" */ `./views/${view}.vue`)
12
+ }
13
+
14
+ const router = new createRouter({
15
+ routes: [<%=#empty%>
16
+ {
17
+ path: "/",
18
+ meta: {
19
+ layout: defaultLayout
20
+ }
21
+ },<%=/empty%><%=^empty%>
22
+ {
23
+ path: "/home",
24
+ name: "home",
25
+ meta: {
26
+ requiresAuth: true,
27
+ layout: defaultLayout
28
+ },
29
+ component: Home
30
+ },
31
+ {
32
+ path: "/profile",
33
+ name: "profile",
34
+ meta: {
35
+ requiresAuth: true,
36
+ layout: defaultLayout
37
+ },
38
+ component: Profile
39
+ },
40
+ {
41
+ path: "/tasks",
42
+ name: "tasks",
43
+ meta: {
44
+ requiresAuth: true,
45
+ layout: defaultLayout
46
+ },
47
+ component: Tasks
48
+ },<%=/empty%>
49
+ {
50
+ path: "/login-form",
51
+ name: "login-form",
52
+ meta: {
53
+ requiresAuth: false,
54
+ layout: simpleLayout,
55
+ title: "Sign In"
56
+ },
57
+ component: loadView("login-form")
58
+ },
59
+ {
60
+ path: "/reset-password",
61
+ name: "reset-password",
62
+ meta: {
63
+ requiresAuth: false,
64
+ layout: simpleLayout,
65
+ title: "Reset Password",
66
+ description: "Please enter the email address that you used to register, and we will send you a link to reset your password via Email."
67
+ },
68
+ component: loadView("reset-password-form")
69
+ },
70
+ {
71
+ path: "/create-account",
72
+ name: "create-account",
73
+ meta: {
74
+ requiresAuth: false,
75
+ layout: simpleLayout,
76
+ title: "Sign Up"
77
+ },
78
+ component: loadView("create-account-form"),
79
+ },
80
+ {
81
+ path: "/change-password/:recoveryCode",
82
+ name: "change-password",
83
+ meta: {
84
+ requiresAuth: false,
85
+ layout: simpleLayout,
86
+ title: "Change Password"
87
+ },
88
+ component: loadView("change-password-form")
89
+ },<%=^empty%>
90
+ {
91
+ path: "/",
92
+ redirect: "/home"
93
+ },
94
+ {
95
+ path: "/recovery",
96
+ redirect: "/home"
97
+ },
98
+ {
99
+ path: "/:pathMatch(.*)*",
100
+ redirect: "/home"
101
+ }<%=/empty%><%=#empty%>
102
+ {
103
+ path: "/:pathMatch(.*)*",
104
+ redirect: "/"
105
+ }<%=/empty%>
106
+ ],
107
+ history: createWebHashHistory()
108
+ });
109
+
110
+ router.beforeEach((to, from, next) => {
111
+
112
+ if (to.name === "login-form" && auth.loggedIn()) {
113
+ next({ name: "home" });
114
+ }
115
+
116
+ if (to.matched.some(record => record.meta.requiresAuth)) {
117
+ if (!auth.loggedIn()) {
118
+ next({
119
+ name: "login-form",
120
+ query: { redirect: to.fullPath }
121
+ });
122
+ } else {
123
+ next();
124
+ }
125
+ } else {
126
+ next();
127
+ }
128
+ });
129
+
130
+ export default router;
@@ -0,0 +1,12 @@
1
+ {
2
+ "items": [],
3
+ "baseTheme": "material.orange.dark",
4
+ "assetsBasePath": "../../../node_modules/devextreme/dist/css/",
5
+ "outputColorScheme": "additional",
6
+ "makeSwatch": true,
7
+ "base": true,
8
+ "widgets": [
9
+ "treeview",
10
+ "navbar"
11
+ ]
12
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "items": [],
3
+ "baseTheme": "material.orange.light",
4
+ "assetsBasePath": "../../../node_modules/devextreme/dist/css/",
5
+ "outputColorScheme": "base",
6
+ "base": true
7
+ }
@@ -0,0 +1,33 @@
1
+ const Breakpoints = {
2
+ XSmall: "(max-width: 599.99px)",
3
+ Small: "(min-width: 600px) and (max-width: 959.99px)",
4
+ Medium: "(min-width: 960px) and (max-width: 1279.99px)",
5
+ Large: "(min-width: 1280px)"
6
+ };
7
+
8
+ let handlers = [];
9
+ const xSmallMedia = window.matchMedia(Breakpoints.XSmall);
10
+ const smallMedia = window.matchMedia(Breakpoints.Small);
11
+ const mediumMedia = window.matchMedia(Breakpoints.Medium);
12
+ const largeMedia = window.matchMedia(Breakpoints.Large);
13
+
14
+ [xSmallMedia, smallMedia, mediumMedia, largeMedia].forEach(media => {
15
+ media.addListener(() => {
16
+ handlers.forEach(handler => handler());
17
+ });
18
+ });
19
+
20
+ export const sizes = () => {
21
+ return {
22
+ "screen-x-small": xSmallMedia.matches,
23
+ "screen-small": smallMedia.matches,
24
+ "screen-medium": mediumMedia.matches,
25
+ "screen-large": largeMedia.matches
26
+ };
27
+ };
28
+
29
+ export const subscribe = handler => handlers.push(handler);
30
+
31
+ export const unsubscribe = handler => {
32
+ handlers = handlers.filter(item => item !== handler);
33
+ };
@@ -0,0 +1,115 @@
1
+ <template>
2
+ <form @submit.prevent="onSubmit">
3
+ <dx-form :form-data="formData" :disabled="loading">
4
+ <dx-item
5
+ data-field="password"
6
+ editor-type="dxTextBox"
7
+ :editor-options="{ stylingMode: 'filled', placeholder: 'Password', mode: 'password' }"
8
+ >
9
+ <dx-required-rule message="Password is required" />
10
+ <dx-label :visible="false" />
11
+ </dx-item>
12
+ <dx-item
13
+ data-field="confirmedPassword"
14
+ editor-type="dxTextBox"
15
+ :editor-options="{ stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' }"
16
+ >
17
+ <dx-required-rule message="Password is required" />
18
+ <dx-custom-rule
19
+ message="Passwords do not match"
20
+ :validation-callback="confirmPassword"
21
+ />
22
+ <dx-label :visible="false" />
23
+ </dx-item>
24
+ <dx-button-item>
25
+ <dx-button-options
26
+ width="100%"
27
+ type="default"
28
+ template="changePassword"
29
+ :use-submit-behavior="true"
30
+ >
31
+ </dx-button-options>
32
+ </dx-button-item>
33
+
34
+ <template #changePassword>
35
+ <div>
36
+ <span class="dx-button-text">
37
+ <dx-loadIndicator v-if="loading" width="24px" height="24px" :visible="true" />
38
+ <span v-if="!loading">Continue</span>
39
+ </span>
40
+ </div>
41
+ </template>
42
+ </dx-form>
43
+ </form>
44
+ </template>
45
+
46
+ <script>
47
+ import DxForm, {
48
+ DxItem,
49
+ DxLabel,
50
+ DxButtonItem,
51
+ DxButtonOptions,
52
+ DxCustomRule,
53
+ DxRequiredRule
54
+ } from 'devextreme-vue/form';
55
+ import DxLoadIndicator from 'devextreme-vue/load-indicator';
56
+ import notify from 'devextreme/ui/notify';
57
+ import { useRouter, useRoute } from 'vue-router';
58
+ import { ref, reactive } from "vue";
59
+
60
+ import auth from "../auth";
61
+
62
+ export default {
63
+ components: {
64
+ DxForm,
65
+ DxItem,
66
+ DxLabel,
67
+ DxButtonItem,
68
+ DxButtonOptions,
69
+ DxRequiredRule,
70
+ DxCustomRule,
71
+ DxLoadIndicator
72
+ },
73
+ setup() {
74
+ const router = useRouter();
75
+ const route = useRoute();
76
+
77
+ const recoveryCode = ref("");
78
+ const loading = ref(false);
79
+ const formData = reactive({
80
+ password:""
81
+ });
82
+
83
+ recoveryCode.value = route.params.recoveryCode;
84
+
85
+ async function onSubmit() {
86
+ const { password } = formData;
87
+ loading.value = true;
88
+
89
+ const result = await auth.changePassword(password, recoveryCode.value);
90
+ loading.value = false;
91
+
92
+ if (result.isOk) {
93
+ router.push("/login-form");
94
+ } else {
95
+ notify(result.message, 'error', 2000);
96
+ }
97
+ }
98
+
99
+ function confirmPassword (e) {
100
+ return e.value === formData.password;
101
+ }
102
+
103
+ return {
104
+ loading,
105
+ formData,
106
+ onSubmit,
107
+ confirmPassword
108
+ }
109
+ }
110
+ }
111
+ </script>
112
+
113
+ <style>
114
+
115
+ </style>
@@ -0,0 +1,155 @@
1
+ <template>
2
+ <form class="create-account-form" @submit.prevent="onSubmit">
3
+ <dx-form :form-data="formData" :disabled="loading">
4
+ <dx-item
5
+ data-field="email"
6
+ editor-type="dxTextBox"
7
+ :editor-options="{ stylingMode: 'filled', placeholder: 'Email', mode: 'email' }"
8
+ >
9
+ <dx-required-rule message="Email is required" />
10
+ <dx-email-rule message="Email is invalid" />
11
+ <dx-label :visible="false" />
12
+ </dx-item>
13
+ <dx-item
14
+ data-field="password"
15
+ editor-type="dxTextBox"
16
+ :editor-options="{ stylingMode: 'filled', placeholder: 'Password', mode: 'password' }"
17
+ >
18
+ <dx-required-rule message="Password is required" />
19
+ <dx-label :visible="false" />
20
+ </dx-item>
21
+ <dx-item
22
+ data-field="confirmedPassword"
23
+ editor-type="dxTextBox"
24
+ :editor-options="{ stylingMode: 'filled', placeholder: 'Confirm Password', mode: 'password' }"
25
+ >
26
+ <dx-required-rule message="Password is required" />
27
+ <dx-custom-rule
28
+ message="Passwords do not match"
29
+ :validation-callback="confirmPassword"
30
+ />
31
+ <dx-label :visible="false" />
32
+ </dx-item>
33
+ <dx-item>
34
+ <template #default>
35
+ <div class='policy-info'>
36
+ By creating an account, you agree to the <router-link to="#">Terms of Service</router-link> and <router-link to="#">Privacy Policy</router-link>
37
+ </div>
38
+ </template>
39
+ </dx-item>
40
+ <dx-button-item>
41
+ <dx-button-options
42
+ width="100%"
43
+ type="default"
44
+ template="createAccount"
45
+ :use-submit-behavior="true"
46
+ >
47
+ </dx-button-options>
48
+ </dx-button-item>
49
+ <dx-item>
50
+ <template #default>
51
+ <div class="login-link">
52
+ Have an account? <router-link to="/login-form">Sign In</router-link>
53
+ </div>
54
+ </template>
55
+ </dx-item>
56
+ <template #createAccount>
57
+ <div>
58
+ <span class="dx-button-text">
59
+ <dx-loadIndicator v-if="loading" width="24px" height="24px" :visible="true" />
60
+ <span v-if="!loading">Create a new account</span>
61
+ </span>
62
+ </div>
63
+ </template>
64
+ </dx-form>
65
+ </form>
66
+ </template>
67
+
68
+ <script>
69
+ import DxForm, {
70
+ DxItem,
71
+ DxLabel,
72
+ DxButtonItem,
73
+ DxButtonOptions,
74
+ DxCustomRule,
75
+ DxRequiredRule,
76
+ DxEmailRule
77
+ } from 'devextreme-vue/form';
78
+ import DxLoadIndicator from 'devextreme-vue/load-indicator';
79
+ import notify from 'devextreme/ui/notify';
80
+ import { useRouter } from 'vue-router';
81
+ import { ref, reactive } from 'vue';
82
+
83
+ import auth from "../auth";
84
+
85
+ export default {
86
+ components: {
87
+ DxForm,
88
+ DxItem,
89
+ DxLabel,
90
+ DxButtonItem,
91
+ DxButtonOptions,
92
+ DxRequiredRule,
93
+ DxCustomRule,
94
+ DxEmailRule,
95
+ DxLoadIndicator
96
+ },
97
+ setup() {
98
+ const router = useRouter();
99
+
100
+ const loading = ref(false);
101
+ const formData = reactive({
102
+ email:"",
103
+ password:""
104
+ });
105
+
106
+ const onSubmit = async () => {
107
+ const { email, password } = formData;
108
+ loading.value = true;
109
+
110
+ const result = await auth.createAccount(email, password);
111
+ loading.value = false;
112
+
113
+ if (result.isOk) {
114
+ router.push("/login-form");
115
+ } else {
116
+ notify(result.message, 'error', 2000);
117
+ }
118
+ };
119
+
120
+ function confirmPassword(e) {
121
+ return e.value === formData.password;
122
+ }
123
+
124
+ return {
125
+ formData,
126
+ loading,
127
+ onSubmit,
128
+ confirmPassword
129
+ }
130
+ }
131
+ }
132
+ </script>
133
+
134
+ <style lang="scss">
135
+ @import "../themes/generated/variables.base.scss";
136
+
137
+ .create-account-form {
138
+ .policy-info {
139
+ margin: 10px 0;
140
+ color: rgba($base-text-color, alpha($base-text-color) * 0.7);
141
+ font-size: 14px;
142
+ font-style: normal;
143
+
144
+ a {
145
+ color: rgba($base-text-color, alpha($base-text-color) * 0.7);
146
+ }
147
+ }
148
+
149
+ .login-link {
150
+ color: $base-accent;
151
+ font-size: 16px;
152
+ text-align: center;
153
+ }
154
+ }
155
+ </style>