devextreme-cli 1.3.2 → 1.3.3
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/index.js +4 -2
- package/package.json +8 -3
- package/src/application.js +17 -17
- package/src/applications/application.angular.js +38 -21
- package/src/applications/application.react.js +81 -37
- package/src/applications/application.vue.js +70 -33
- package/src/commands.json +3 -0
- package/src/templates/react/application/src/{App.js → App.tsx} +0 -0
- package/src/templates/react/application/src/{Content.js → Content.tsx} +11 -9
- package/src/templates/react/application/src/UnauthenticatedContent.tsx +46 -0
- package/src/templates/react/application/src/api/{auth.js → auth.tsx} +4 -4
- package/src/templates/react/application/src/{app-info.js → app-info.tsx} +0 -0
- package/src/templates/react/application/src/{app-navigation.js → app-navigation.tsx} +0 -0
- package/src/templates/react/application/src/app-routes.tsx +24 -0
- package/src/templates/react/application/src/components/change-password-form/{change-password-form.js → ChangePasswordForm.tsx} +6 -6
- package/src/templates/react/application/src/components/create-account-form/{create-account-form.scss → CreateAccountForm.scss} +0 -0
- package/src/templates/react/application/src/components/create-account-form/{create-account-form.js → CreateAccountForm.tsx} +7 -7
- package/src/templates/react/application/src/components/footer/{footer.scss → Footer.scss} +0 -0
- package/src/templates/react/application/src/components/footer/{footer.js → Footer.tsx} +1 -1
- package/src/templates/react/application/src/components/header/{header.scss → Header.scss} +0 -0
- package/src/templates/react/application/src/components/header/{header.js → Header.tsx} +4 -3
- package/src/templates/react/application/src/components/index.tsx +7 -0
- package/src/templates/react/application/src/components/login-form/{login-form.scss → LoginForm.scss} +0 -0
- package/src/templates/react/application/src/components/login-form/{login-form.js → LoginForm.tsx} +6 -6
- package/src/templates/react/application/src/components/reset-password-form/{reset-password-form.scss → ResetPasswordForm.scss} +0 -0
- package/src/templates/react/application/src/components/reset-password-form/{reset-password-form.js → ResetPasswordForm.tsx} +7 -7
- package/src/templates/react/application/src/components/side-navigation-menu/{side-navigation-menu.scss → SideNavigationMenu.scss} +0 -0
- package/src/templates/react/application/src/components/side-navigation-menu/{side-navigation-menu.js → SideNavigationMenu.tsx} +8 -10
- package/src/templates/react/application/src/components/user-panel/{user-panel.scss → UserPanel.scss} +0 -0
- package/src/templates/react/application/src/components/user-panel/{user-panel.js → UserPanel.tsx} +8 -8
- package/src/templates/react/application/src/contexts/{auth.js → auth.tsx} +6 -5
- package/src/templates/react/application/src/contexts/navigation.tsx +35 -0
- package/src/templates/react/application/src/layouts/{index.js → index.tsx} +0 -0
- package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/{side-nav-inner-toolbar.js → side-nav-inner-toolbar.tsx} +12 -9
- package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/{side-nav-outer-toolbar.js → side-nav-outer-toolbar.tsx} +11 -10
- package/src/templates/react/application/src/layouts/single-card/{single-card.js → single-card.tsx} +2 -1
- package/src/templates/react/application/src/{polyfills.js → polyfills.tsx} +0 -0
- package/src/templates/react/application/src/types.tsx +53 -0
- package/src/templates/react/application/src/utils/{default-user.js → default-user.tsx} +0 -0
- package/src/templates/react/application/src/utils/{media-query.js → media-query.tsx} +4 -3
- package/src/templates/react/application/src/utils/{patches.js → patches.tsx} +1 -1
- package/src/templates/react/page/{page.js → page.tsx} +0 -0
- package/src/templates/react/sample-pages/home/{home.js → home.tsx} +0 -0
- package/src/templates/react/sample-pages/{index.js → index.tsx} +0 -0
- package/src/templates/react/sample-pages/profile/{profile.js → profile.tsx} +0 -0
- package/src/templates/react/sample-pages/tasks/{tasks.js → tasks.tsx} +1 -1
- package/src/templates/vue-v2/application/devextreme.json +2 -1
- package/src/templates/vue-v3/application/devextreme.json +2 -1
- package/src/utility/prompts/layout.js +9 -21
- package/src/utility/prompts/prompts.js +24 -8
- package/src/utility/prompts/typescript.js +18 -0
- package/src/utility/prompts/vue-version.js +9 -21
- package/src/utility/template-creator.js +11 -6
- package/src/utility/typescript-extension.js +24 -0
- package/src/templates/react/application/src/UnauthenticatedContent.js +0 -35
- package/src/templates/react/application/src/app-routes.js +0 -24
- package/src/templates/react/application/src/components/index.js +0 -7
- package/src/templates/react/application/src/contexts/navigation.js +0 -34
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Routes, Route, Navigate } from 'react-router-dom';
|
|
2
|
+
import { SingleCard } from './layouts';
|
|
3
|
+
import { LoginForm, ResetPasswordForm, ChangePasswordForm, CreateAccountForm } from './components';
|
|
4
|
+
|
|
5
|
+
export default function UnauthenticatedContent() {
|
|
6
|
+
return (
|
|
7
|
+
<Routes>
|
|
8
|
+
<Route
|
|
9
|
+
path='/login'
|
|
10
|
+
element={
|
|
11
|
+
<SingleCard title="Sign In">
|
|
12
|
+
<LoginForm />
|
|
13
|
+
</SingleCard>
|
|
14
|
+
}
|
|
15
|
+
/>
|
|
16
|
+
<Route
|
|
17
|
+
path='/create-account'
|
|
18
|
+
element={
|
|
19
|
+
<SingleCard title="Sign Up">
|
|
20
|
+
<CreateAccountForm />
|
|
21
|
+
</SingleCard>
|
|
22
|
+
}
|
|
23
|
+
/>
|
|
24
|
+
<Route
|
|
25
|
+
path='/reset-password'
|
|
26
|
+
element={
|
|
27
|
+
<SingleCard
|
|
28
|
+
title="Reset Password"
|
|
29
|
+
description="Please enter the email address that you used to register, and we will send you a link to reset your password via Email."
|
|
30
|
+
>
|
|
31
|
+
<ResetPasswordForm />
|
|
32
|
+
</SingleCard>
|
|
33
|
+
}
|
|
34
|
+
/>
|
|
35
|
+
<Route
|
|
36
|
+
path='/change-password/:recoveryCode'
|
|
37
|
+
element={
|
|
38
|
+
<SingleCard title="Change Password">
|
|
39
|
+
<ChangePasswordForm />
|
|
40
|
+
</SingleCard>
|
|
41
|
+
}
|
|
42
|
+
/>
|
|
43
|
+
<Route path='*' element={<Navigate to={'/login'} />}></Route>
|
|
44
|
+
</Routes>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import defaultUser from '../utils/default-user';
|
|
2
2
|
|
|
3
|
-
export async function signIn(email
|
|
3
|
+
export async function signIn(email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
4
4
|
try {
|
|
5
5
|
// Send request
|
|
6
6
|
console.log(email, password);
|
|
@@ -34,7 +34,7 @@ export async function getUser() {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export async function createAccount(email
|
|
37
|
+
export async function createAccount(email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
38
38
|
try {
|
|
39
39
|
// Send request
|
|
40
40
|
console.log(email, password);
|
|
@@ -51,7 +51,7 @@ export async function createAccount(email, password) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export async function changePassword(email
|
|
54
|
+
export async function changePassword(email<%=#isTypeScript%>: string<%=/isTypeScript%>, recoveryCode<%=#isTypeScript%>?: string<%=/isTypeScript%>) {
|
|
55
55
|
try {
|
|
56
56
|
// Send request
|
|
57
57
|
console.log(email, recoveryCode);
|
|
@@ -68,7 +68,7 @@ export async function changePassword(email, recoveryCode) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export async function resetPassword(email) {
|
|
71
|
+
export async function resetPassword(email<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
72
72
|
try {
|
|
73
73
|
// Send request
|
|
74
74
|
console.log(email);
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HomePage, TasksPage, ProfilePage } from './pages';
|
|
2
|
+
import { withNavigationWatcher } from './contexts/navigation';
|
|
3
|
+
|
|
4
|
+
const routes = [<%=^empty%>
|
|
5
|
+
{
|
|
6
|
+
path: '/tasks',
|
|
7
|
+
element: TasksPage
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
path: '/profile',
|
|
11
|
+
element: ProfilePage
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: '/home',
|
|
15
|
+
element: HomePage
|
|
16
|
+
}
|
|
17
|
+
<%=/empty%>];
|
|
18
|
+
|
|
19
|
+
export default routes.map(route => {
|
|
20
|
+
return {
|
|
21
|
+
...route,
|
|
22
|
+
element: withNavigationWatcher(route.element, route.path)
|
|
23
|
+
};
|
|
24
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useNavigate, useParams } from 'react-router-dom';
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -12,10 +12,10 @@ import LoadIndicator from 'devextreme-react/load-indicator';
|
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import { changePassword } from '../../api/auth';
|
|
14
14
|
|
|
15
|
-
export default function ChangePasswordForm(
|
|
16
|
-
const
|
|
15
|
+
export default function ChangePasswordForm() {
|
|
16
|
+
const navigate = useNavigate();
|
|
17
17
|
const [loading, setLoading] = useState(false);
|
|
18
|
-
const formData = useRef({});
|
|
18
|
+
const formData = useRef({ password: '' });
|
|
19
19
|
const { recoveryCode } = useParams();
|
|
20
20
|
|
|
21
21
|
const onSubmit = useCallback(async (e) => {
|
|
@@ -27,11 +27,11 @@ export default function ChangePasswordForm(props) {
|
|
|
27
27
|
setLoading(false);
|
|
28
28
|
|
|
29
29
|
if (result.isOk) {
|
|
30
|
-
|
|
30
|
+
navigate('/login');
|
|
31
31
|
} else {
|
|
32
32
|
notify(result.message, 'error', 2000);
|
|
33
33
|
}
|
|
34
|
-
}, [
|
|
34
|
+
}, [navigate, recoveryCode]);
|
|
35
35
|
|
|
36
36
|
const confirmPassword = useCallback(
|
|
37
37
|
({ value }) => value === formData.current.password,
|
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link,
|
|
2
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -12,12 +12,12 @@ import Form, {
|
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
14
14
|
import { createAccount } from '../../api/auth';
|
|
15
|
-
import './
|
|
15
|
+
import './CreateAccountForm.scss';
|
|
16
16
|
|
|
17
|
-
export default function CreateAccountForm(
|
|
18
|
-
const
|
|
17
|
+
export default function CreateAccountForm() {
|
|
18
|
+
const navigate = useNavigate();
|
|
19
19
|
const [loading, setLoading] = useState(false);
|
|
20
|
-
const formData = useRef({});
|
|
20
|
+
const formData = useRef({ email: '', password: '' });
|
|
21
21
|
|
|
22
22
|
const onSubmit = useCallback(async (e) => {
|
|
23
23
|
e.preventDefault();
|
|
@@ -28,11 +28,11 @@ export default function CreateAccountForm(props) {
|
|
|
28
28
|
setLoading(false);
|
|
29
29
|
|
|
30
30
|
if (result.isOk) {
|
|
31
|
-
|
|
31
|
+
navigate('/login');
|
|
32
32
|
} else {
|
|
33
33
|
notify(result.message, 'error', 2000);
|
|
34
34
|
}
|
|
35
|
-
}, [
|
|
35
|
+
}, [navigate]);
|
|
36
36
|
|
|
37
37
|
const confirmPassword = useCallback(
|
|
38
38
|
({ value }) => value === formData.current.password,
|
|
File without changes
|
|
File without changes
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Toolbar, { Item } from 'devextreme-react/toolbar';
|
|
3
3
|
import Button from 'devextreme-react/button';
|
|
4
|
-
import UserPanel from '../user-panel/
|
|
5
|
-
import './
|
|
4
|
+
import UserPanel from '../user-panel/UserPanel';
|
|
5
|
+
import './Header.scss';
|
|
6
6
|
import { Template } from 'devextreme-react/core/template';
|
|
7
|
+
<%=#isTypeScript%>import type { HeaderProps } from '../../types';<%=/isTypeScript%>
|
|
7
8
|
|
|
8
|
-
export default function Header({ menuToggleEnabled, title, toggleMenu }) {
|
|
9
|
+
export default function Header({ menuToggleEnabled, title, toggleMenu }<%=#isTypeScript%>: HeaderProps<%=/isTypeScript%>) {
|
|
9
10
|
return (
|
|
10
11
|
<header className={'header-component'}>
|
|
11
12
|
<Toolbar className={'header-toolbar'}>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Header } from './header/Header';
|
|
2
|
+
export { default as Footer } from './footer/Footer';
|
|
3
|
+
export { default as LoginForm } from './login-form/LoginForm';
|
|
4
|
+
export { default as ResetPasswordForm } from './reset-password-form/ResetPasswordForm';
|
|
5
|
+
export { default as CreateAccountForm } from './create-account-form/CreateAccountForm';
|
|
6
|
+
export { default as ChangePasswordForm } from './change-password-form/ChangePasswordForm';
|
|
7
|
+
export { default as SideNavigationMenu } from './side-navigation-menu/SideNavigationMenu';
|
package/src/templates/react/application/src/components/login-form/{login-form.scss → LoginForm.scss}
RENAMED
|
File without changes
|
package/src/templates/react/application/src/components/login-form/{login-form.js → LoginForm.tsx}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link,
|
|
2
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -12,13 +12,13 @@ import LoadIndicator from 'devextreme-react/load-indicator';
|
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import { useAuth } from '../../contexts/auth';
|
|
14
14
|
|
|
15
|
-
import './
|
|
15
|
+
import './LoginForm.scss';
|
|
16
16
|
|
|
17
17
|
export default function LoginForm() {
|
|
18
|
-
const
|
|
18
|
+
const navigate = useNavigate();
|
|
19
19
|
const { signIn } = useAuth();
|
|
20
20
|
const [loading, setLoading] = useState(false);
|
|
21
|
-
const formData = useRef({});
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
22
22
|
|
|
23
23
|
const onSubmit = useCallback(async (e) => {
|
|
24
24
|
e.preventDefault();
|
|
@@ -33,8 +33,8 @@ export default function LoginForm() {
|
|
|
33
33
|
}, [signIn]);
|
|
34
34
|
|
|
35
35
|
const onCreateAccountClick = useCallback(() => {
|
|
36
|
-
|
|
37
|
-
}, [
|
|
36
|
+
navigate('/create-account');
|
|
37
|
+
}, [navigate]);
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
40
|
<form className={'login-form'} onSubmit={onSubmit}>
|
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { Link,
|
|
2
|
+
import { Link, useNavigate } from "react-router-dom";
|
|
3
3
|
import Form, {
|
|
4
4
|
Item,
|
|
5
5
|
Label,
|
|
@@ -11,14 +11,14 @@ import Form, {
|
|
|
11
11
|
import LoadIndicator from 'devextreme-react/load-indicator';
|
|
12
12
|
import notify from 'devextreme/ui/notify';
|
|
13
13
|
import { resetPassword } from '../../api/auth';
|
|
14
|
-
import './
|
|
14
|
+
import './ResetPasswordForm.scss';
|
|
15
15
|
|
|
16
16
|
const notificationText = 'We\'ve sent a link to reset your password. Check your inbox.';
|
|
17
17
|
|
|
18
|
-
export default function ResetPasswordForm(
|
|
19
|
-
const
|
|
18
|
+
export default function ResetPasswordForm() {
|
|
19
|
+
const navigate = useNavigate();
|
|
20
20
|
const [loading, setLoading] = useState(false);
|
|
21
|
-
const formData = useRef({});
|
|
21
|
+
const formData = useRef({ email: '', password: '' });
|
|
22
22
|
|
|
23
23
|
const onSubmit = useCallback(async (e) => {
|
|
24
24
|
e.preventDefault();
|
|
@@ -29,12 +29,12 @@ export default function ResetPasswordForm(props) {
|
|
|
29
29
|
setLoading(false);
|
|
30
30
|
|
|
31
31
|
if (result.isOk) {
|
|
32
|
-
|
|
32
|
+
navigate('/login');
|
|
33
33
|
notify(notificationText, 'success', 2500);
|
|
34
34
|
} else {
|
|
35
35
|
notify(result.message, 'error', 2000);
|
|
36
36
|
}
|
|
37
|
-
}, [
|
|
37
|
+
}, [navigate]);
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
40
|
<form className={'reset-password-form'} onSubmit={onSubmit}>
|
|
File without changes
|
|
@@ -3,11 +3,12 @@ import TreeView from 'devextreme-react/tree-view';
|
|
|
3
3
|
import { navigation } from '../../app-navigation';
|
|
4
4
|
import { useNavigation } from '../../contexts/navigation';
|
|
5
5
|
import { useScreenSize } from '../../utils/media-query';
|
|
6
|
-
import './
|
|
6
|
+
import './SideNavigationMenu.scss';
|
|
7
|
+
<%=#isTypeScript%>import type { SideNavigationMenuProps } from '../../types';<%=/isTypeScript%>
|
|
7
8
|
|
|
8
9
|
import * as events from 'devextreme/events';
|
|
9
10
|
|
|
10
|
-
export default function SideNavigationMenu(props) {
|
|
11
|
+
export default function SideNavigationMenu(props<%=#isTypeScript%>: React.PropsWithChildren<SideNavigationMenuProps><%=/isTypeScript%>) {
|
|
11
12
|
const {
|
|
12
13
|
children,
|
|
13
14
|
selectedItemChanged,
|
|
@@ -18,12 +19,9 @@ export default function SideNavigationMenu(props) {
|
|
|
18
19
|
|
|
19
20
|
const { isLarge } = useScreenSize();
|
|
20
21
|
function normalizePath () {
|
|
21
|
-
return navigation.map((item) =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
return {...item, expanded: isLarge};
|
|
26
|
-
});
|
|
22
|
+
return navigation.map((item) => (
|
|
23
|
+
{ ...item, expanded: isLarge, path: item.path && !(/^\//.test(item.path)) ? `/${item.path}` : item.path }
|
|
24
|
+
))
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
const items = useMemo(
|
|
@@ -34,7 +32,7 @@ export default function SideNavigationMenu(props) {
|
|
|
34
32
|
|
|
35
33
|
const { navigationData: { currentPath } } = useNavigation();
|
|
36
34
|
|
|
37
|
-
const treeViewRef = useRef();
|
|
35
|
+
const treeViewRef = useRef<%=#isTypeScript%><TreeView><%=/isTypeScript%>(null);
|
|
38
36
|
const wrapperRef = useRef();
|
|
39
37
|
const getWrapperRef = useCallback((element) => {
|
|
40
38
|
const prevElement = wrapperRef.current;
|
|
@@ -43,7 +41,7 @@ export default function SideNavigationMenu(props) {
|
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
wrapperRef.current = element;
|
|
46
|
-
events.on(element, 'dxclick', e => {
|
|
44
|
+
events.on(element, 'dxclick', (e<%=#isTypeScript%>: React.PointerEvent<%=/isTypeScript%>) => {
|
|
47
45
|
openMenu(e);
|
|
48
46
|
});
|
|
49
47
|
}, [openMenu]);
|
package/src/templates/react/application/src/components/user-panel/{user-panel.scss → UserPanel.scss}
RENAMED
|
File without changes
|
package/src/templates/react/application/src/components/user-panel/{user-panel.js → UserPanel.tsx}
RENAMED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useNavigate } from "react-router-dom";
|
|
3
3
|
import ContextMenu, { Position } from 'devextreme-react/context-menu';
|
|
4
4
|
import List from 'devextreme-react/list';
|
|
5
5
|
import { useAuth } from '../../contexts/auth';
|
|
6
|
-
import './
|
|
6
|
+
import './UserPanel.scss';
|
|
7
|
+
<%=#isTypeScript%>import type { UserPanelProps } from '../../types';<%=/isTypeScript%>
|
|
7
8
|
|
|
8
|
-
export default function UserPanel({ menuMode }) {
|
|
9
|
+
export default function UserPanel({ menuMode }<%=#isTypeScript%>: UserPanelProps<%=/isTypeScript%>) {
|
|
9
10
|
const { user, signOut } = useAuth();
|
|
10
|
-
const
|
|
11
|
+
const navigate = useNavigate();
|
|
11
12
|
|
|
12
13
|
function navigateToProfile() {
|
|
13
|
-
|
|
14
|
+
navigate("/profile");
|
|
14
15
|
}
|
|
15
16
|
const menuItems = useMemo(() => ([
|
|
16
17
|
{
|
|
@@ -24,19 +25,18 @@ export default function UserPanel({ menuMode }) {
|
|
|
24
25
|
onClick: signOut
|
|
25
26
|
}
|
|
26
27
|
]), [signOut]);
|
|
27
|
-
|
|
28
28
|
return (
|
|
29
29
|
<div className={'user-panel'}>
|
|
30
30
|
<div className={'user-info'}>
|
|
31
31
|
<div className={'image-container'}>
|
|
32
32
|
<div
|
|
33
33
|
style={{
|
|
34
|
-
background: `url(${user
|
|
34
|
+
background: `url(${user<%=#isTypeScript%>!<%=/isTypeScript%>.avatarUrl}) no-repeat #fff`,
|
|
35
35
|
backgroundSize: 'cover'
|
|
36
36
|
}}
|
|
37
37
|
className={'user-image'} />
|
|
38
38
|
</div>
|
|
39
|
-
<div className={'user-name'}>{user
|
|
39
|
+
<div className={'user-name'}>{user<%=#isTypeScript%>!<%=/isTypeScript%>.email}</div>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
42
|
{menuMode === 'context' && (
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect, createContext, useContext, useCallback } from 'react';
|
|
2
2
|
import { getUser, signIn as sendSignInRequest } from '../api/auth';
|
|
3
|
+
<%=#isTypeScript%>import type { User, AuthContextType } from '../types';<%=/isTypeScript%>
|
|
3
4
|
|
|
4
|
-
function AuthProvider(props) {
|
|
5
|
-
const [user, setUser] = useState();
|
|
5
|
+
function AuthProvider(props<%=#isTypeScript%>: React.PropsWithChildren<unknown><%=/isTypeScript%>) {
|
|
6
|
+
const [user, setUser] = useState<%=#isTypeScript%><User><%=/isTypeScript%>();
|
|
6
7
|
const [loading, setLoading] = useState(true);
|
|
7
8
|
|
|
8
9
|
useEffect(() => {
|
|
@@ -16,7 +17,7 @@ function AuthProvider(props) {
|
|
|
16
17
|
})();
|
|
17
18
|
}, []);
|
|
18
19
|
|
|
19
|
-
const signIn = useCallback(async (email
|
|
20
|
+
const signIn = useCallback(async (email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) => {
|
|
20
21
|
const result = await sendSignInRequest(email, password);
|
|
21
22
|
if (result.isOk) {
|
|
22
23
|
setUser(result.data);
|
|
@@ -26,7 +27,7 @@ function AuthProvider(props) {
|
|
|
26
27
|
}, []);
|
|
27
28
|
|
|
28
29
|
const signOut = useCallback(() => {
|
|
29
|
-
setUser();
|
|
30
|
+
setUser(undefined);
|
|
30
31
|
}, []);
|
|
31
32
|
|
|
32
33
|
|
|
@@ -35,7 +36,7 @@ function AuthProvider(props) {
|
|
|
35
36
|
);
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
const AuthContext = createContext({});
|
|
39
|
+
const AuthContext = createContext<%=#isTypeScript%><AuthContextType><%=/isTypeScript%>({ loading: false }<%=#isTypeScript%> as AuthContextType<%=/isTypeScript%>);
|
|
39
40
|
const useAuth = () => useContext(AuthContext);
|
|
40
41
|
|
|
41
42
|
export { AuthProvider, useAuth }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { useState, createContext, useContext, useEffect } from 'react';
|
|
2
|
+
<%=#isTypeScript%>import type { NavigationContextType } from '../types';<%=/isTypeScript%>
|
|
3
|
+
|
|
4
|
+
const NavigationContext = createContext<%=#isTypeScript%><NavigationContextType><%=/isTypeScript%>({}<%=#isTypeScript%> as NavigationContextType<%=/isTypeScript%>);
|
|
5
|
+
const useNavigation = () => useContext(NavigationContext);
|
|
6
|
+
|
|
7
|
+
function NavigationProvider(props<%=#isTypeScript%>: React.PropsWithChildren<unknown><%=/isTypeScript%>) {
|
|
8
|
+
const [navigationData, setNavigationData] = useState({ currentPath: '' });
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<NavigationContext.Provider
|
|
12
|
+
value={{ navigationData, setNavigationData }}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function withNavigationWatcher(Component<%=#isTypeScript%>: React.ElementType<%=/isTypeScript%>, path<%=#isTypeScript%>: string<%=/isTypeScript%>) {
|
|
19
|
+
const WrappedComponent = function (props<%=#isTypeScript%>: unknown<%=/isTypeScript%>) {
|
|
20
|
+
const { setNavigationData } = useNavigation();
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setNavigationData<%=#isTypeScript%>!<%=/isTypeScript%>({ currentPath: path });
|
|
24
|
+
}, [path, setNavigationData]);
|
|
25
|
+
|
|
26
|
+
return <Component {...props} />;
|
|
27
|
+
}
|
|
28
|
+
return <WrappedComponent />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
NavigationProvider,
|
|
33
|
+
useNavigation,
|
|
34
|
+
withNavigationWatcher
|
|
35
|
+
}
|
|
File without changes
|
|
@@ -3,16 +3,17 @@ import Drawer from 'devextreme-react/drawer';
|
|
|
3
3
|
import ScrollView from 'devextreme-react/scroll-view';
|
|
4
4
|
import Toolbar, { Item } from 'devextreme-react/toolbar';
|
|
5
5
|
import React, { useState, useCallback, useRef } from 'react';
|
|
6
|
-
import {
|
|
6
|
+
import { useNavigate } from 'react-router';
|
|
7
7
|
import { Header, SideNavigationMenu, Footer } from '../../components';
|
|
8
8
|
import './side-nav-inner-toolbar.scss';
|
|
9
9
|
import { useScreenSize } from '../../utils/media-query';
|
|
10
10
|
import { Template } from 'devextreme-react/core/template';
|
|
11
11
|
import { useMenuPatch } from '../../utils/patches';
|
|
12
|
+
<%=#isTypeScript%>import type { SideNavToolbarProps } from '../../types';<%=/isTypeScript%>
|
|
12
13
|
|
|
13
|
-
export default function SideNavInnerToolbar({ title, children }) {
|
|
14
|
-
const scrollViewRef = useRef();
|
|
15
|
-
const
|
|
14
|
+
export default function SideNavInnerToolbar({ title, children }<%=#isTypeScript%>: React.PropsWithChildren<SideNavToolbarProps><%=/isTypeScript%>) {
|
|
15
|
+
const scrollViewRef = useRef<%=#isTypeScript%><ScrollView><%=/isTypeScript%>(null);
|
|
16
|
+
const navigate = useNavigate();
|
|
16
17
|
const { isXSmall, isLarge } = useScreenSize();
|
|
17
18
|
const [patchCssClass, onMenuReady] = useMenuPatch();
|
|
18
19
|
const [menuStatus, setMenuStatus] = useState(
|
|
@@ -42,6 +43,7 @@ export default function SideNavInnerToolbar({ title, children }) {
|
|
|
42
43
|
? MenuStatus.Closed
|
|
43
44
|
: prevMenuStatus
|
|
44
45
|
);
|
|
46
|
+
return true;
|
|
45
47
|
}, [isLarge]);
|
|
46
48
|
|
|
47
49
|
const onNavigationChanged = useCallback(({ itemData: { path }, event, node }) => {
|
|
@@ -50,14 +52,14 @@ export default function SideNavInnerToolbar({ title, children }) {
|
|
|
50
52
|
return;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
scrollViewRef.current
|
|
55
|
+
navigate(path);
|
|
56
|
+
scrollViewRef.current<%=#isTypeScript%>?<%=/isTypeScript%>.instance.scrollTo(0);
|
|
55
57
|
|
|
56
58
|
if (!isLarge || menuStatus === MenuStatus.TemporaryOpened) {
|
|
57
59
|
setMenuStatus(MenuStatus.Closed);
|
|
58
60
|
event.stopPropagation();
|
|
59
61
|
}
|
|
60
|
-
}, [
|
|
62
|
+
}, [navigate, menuStatus, isLarge]);
|
|
61
63
|
|
|
62
64
|
return (
|
|
63
65
|
<div className={'side-nav-inner-toolbar'}>
|
|
@@ -80,12 +82,12 @@ export default function SideNavInnerToolbar({ title, children }) {
|
|
|
80
82
|
/>
|
|
81
83
|
<ScrollView ref={scrollViewRef} className={'layout-body with-footer'}>
|
|
82
84
|
<div className={'content'}>
|
|
83
|
-
{React.Children.map(children, item => {
|
|
85
|
+
{React.Children.map(children, (item<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
84
86
|
return item.type !== Footer && item;
|
|
85
87
|
})}
|
|
86
88
|
</div>
|
|
87
89
|
<div className={'content-block'}>
|
|
88
|
-
{React.Children.map(children, item => {
|
|
90
|
+
{React.Children.map(children, (item<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
89
91
|
return item.type === Footer && item;
|
|
90
92
|
})}
|
|
91
93
|
</div>
|
|
@@ -122,3 +124,4 @@ const MenuStatus = {
|
|
|
122
124
|
Opened: 2,
|
|
123
125
|
TemporaryOpened: 3
|
|
124
126
|
};
|
|
127
|
+
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import Drawer from 'devextreme-react/drawer';
|
|
2
2
|
import ScrollView from 'devextreme-react/scroll-view';
|
|
3
3
|
import React, { useState, useCallback, useRef } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { useNavigate } from 'react-router';
|
|
5
5
|
import { Header, SideNavigationMenu, Footer } from '../../components';
|
|
6
6
|
import './side-nav-outer-toolbar.scss';
|
|
7
7
|
import { useScreenSize } from '../../utils/media-query';
|
|
8
8
|
import { Template } from 'devextreme-react/core/template';
|
|
9
9
|
import { useMenuPatch } from '../../utils/patches';
|
|
10
|
+
<%=#isTypeScript%>import type { SideNavToolbarProps } from '../../types';<%=/isTypeScript%>
|
|
10
11
|
|
|
11
|
-
export default function SideNavOuterToolbar({ title, children }) {
|
|
12
|
-
const scrollViewRef = useRef();
|
|
13
|
-
const
|
|
12
|
+
export default function SideNavOuterToolbar({ title, children }<%=#isTypeScript%>: React.PropsWithChildren<SideNavToolbarProps><%=/isTypeScript%>) {
|
|
13
|
+
const scrollViewRef = useRef<%=#isTypeScript%><ScrollView><%=/isTypeScript%>(null);
|
|
14
|
+
const navigate = useNavigate();
|
|
14
15
|
const { isXSmall, isLarge } = useScreenSize();
|
|
15
16
|
const [patchCssClass, onMenuReady] = useMenuPatch();
|
|
16
17
|
const [menuStatus, setMenuStatus] = useState(
|
|
@@ -40,6 +41,7 @@ export default function SideNavOuterToolbar({ title, children }) {
|
|
|
40
41
|
? MenuStatus.Closed
|
|
41
42
|
: prevMenuStatus
|
|
42
43
|
);
|
|
44
|
+
return true;
|
|
43
45
|
}, [isLarge]);
|
|
44
46
|
|
|
45
47
|
const onNavigationChanged = useCallback(({ itemData: { path }, event, node }) => {
|
|
@@ -48,19 +50,18 @@ export default function SideNavOuterToolbar({ title, children }) {
|
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
scrollViewRef.current
|
|
53
|
+
navigate(path);
|
|
54
|
+
scrollViewRef.current<%=#isTypeScript%>?<%=/isTypeScript%>.instance.scrollTo(0);
|
|
53
55
|
|
|
54
56
|
if (!isLarge || menuStatus === MenuStatus.TemporaryOpened) {
|
|
55
57
|
setMenuStatus(MenuStatus.Closed);
|
|
56
58
|
event.stopPropagation();
|
|
57
59
|
}
|
|
58
|
-
}, [
|
|
60
|
+
}, [navigate, menuStatus, isLarge]);
|
|
59
61
|
|
|
60
62
|
return (
|
|
61
63
|
<div className={'side-nav-outer-toolbar'}>
|
|
62
64
|
<Header
|
|
63
|
-
className={'layout-header'}
|
|
64
65
|
menuToggleEnabled
|
|
65
66
|
toggleMenu={toggleMenu}
|
|
66
67
|
title={title}
|
|
@@ -80,12 +81,12 @@ export default function SideNavOuterToolbar({ title, children }) {
|
|
|
80
81
|
<div className={'container'}>
|
|
81
82
|
<ScrollView ref={scrollViewRef} className={'layout-body with-footer'}>
|
|
82
83
|
<div className={'content'}>
|
|
83
|
-
{React.Children.map(children, item => {
|
|
84
|
+
{React.Children.map(children, (item<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
84
85
|
return item.type !== Footer && item;
|
|
85
86
|
})}
|
|
86
87
|
</div>
|
|
87
88
|
<div className={'content-block'}>
|
|
88
|
-
{React.Children.map(children, item => {
|
|
89
|
+
{React.Children.map(children, (item<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
|
|
89
90
|
return item.type === Footer && item;
|
|
90
91
|
})}
|
|
91
92
|
</div>
|
package/src/templates/react/application/src/layouts/single-card/{single-card.js → single-card.tsx}
RENAMED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import ScrollView from 'devextreme-react/scroll-view';
|
|
3
3
|
import './single-card.scss';
|
|
4
|
+
<%=#isTypeScript%>import type { SingleCardProps } from '../../types';<%=/isTypeScript%>
|
|
4
5
|
|
|
5
|
-
export default function SingleCard({ title, description, children }) {
|
|
6
|
+
export default function SingleCard({ title, description, children }<%=#isTypeScript%>: React.PropsWithChildren<SingleCardProps><%=/isTypeScript%>) {
|
|
6
7
|
return (
|
|
7
8
|
<ScrollView height={'100%'} width={'100%'} className={'with-footer single-card'}>
|
|
8
9
|
<div className={'dx-card content'}>
|
|
File without changes
|