devextreme-cli 1.3.1 → 1.4.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 (70) hide show
  1. package/index.js +4 -2
  2. package/package.json +8 -3
  3. package/src/application.js +19 -19
  4. package/src/applications/application.angular.js +48 -46
  5. package/src/applications/application.react.js +76 -39
  6. package/src/applications/application.vue.js +71 -34
  7. package/src/commands.json +3 -0
  8. package/src/templates/react/application/src/{App.js → App.tsx} +0 -0
  9. package/src/templates/react/application/src/{Content.js → Content.tsx} +11 -9
  10. package/src/templates/react/application/src/UnauthenticatedContent.tsx +46 -0
  11. package/src/templates/react/application/src/api/{auth.js → auth.tsx} +4 -4
  12. package/src/templates/react/application/src/{app-info.js → app-info.tsx} +0 -0
  13. package/src/templates/react/application/src/{app-navigation.js → app-navigation.tsx} +0 -0
  14. package/src/templates/react/application/src/app-routes.tsx +24 -0
  15. package/src/templates/react/application/src/components/change-password-form/{change-password-form.js → ChangePasswordForm.tsx} +9 -8
  16. package/src/templates/react/application/src/components/create-account-form/{create-account-form.scss → CreateAccountForm.scss} +0 -0
  17. package/src/templates/react/application/src/components/create-account-form/{create-account-form.js → CreateAccountForm.tsx} +10 -9
  18. package/src/templates/react/application/src/components/footer/{footer.scss → Footer.scss} +0 -0
  19. package/src/templates/react/application/src/components/footer/{footer.js → Footer.tsx} +1 -1
  20. package/src/templates/react/application/src/components/header/{header.scss → Header.scss} +0 -0
  21. package/src/templates/react/application/src/components/header/{header.js → Header.tsx} +4 -3
  22. package/src/templates/react/application/src/components/index.tsx +7 -0
  23. package/src/templates/react/application/src/components/login-form/{login-form.scss → LoginForm.scss} +0 -0
  24. package/src/templates/react/application/src/components/login-form/{login-form.js → LoginForm.tsx} +7 -7
  25. package/src/templates/react/application/src/components/reset-password-form/{reset-password-form.scss → ResetPasswordForm.scss} +0 -0
  26. package/src/templates/react/application/src/components/reset-password-form/{reset-password-form.js → ResetPasswordForm.tsx} +8 -8
  27. package/src/templates/react/application/src/components/side-navigation-menu/{side-navigation-menu.scss → SideNavigationMenu.scss} +0 -0
  28. package/src/templates/react/application/src/components/side-navigation-menu/{side-navigation-menu.js → SideNavigationMenu.tsx} +10 -12
  29. package/src/templates/react/application/src/components/user-panel/{user-panel.scss → UserPanel.scss} +0 -0
  30. package/src/templates/react/application/src/components/user-panel/{user-panel.js → UserPanel.tsx} +8 -8
  31. package/src/templates/react/application/src/contexts/{auth.js → auth.tsx} +6 -5
  32. package/src/templates/react/application/src/contexts/navigation.tsx +35 -0
  33. package/src/templates/react/application/src/dx-styles.scss +25 -13
  34. package/src/templates/react/application/src/layouts/{index.js → index.tsx} +0 -0
  35. package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.scss +1 -16
  36. package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/{side-nav-inner-toolbar.js → side-nav-inner-toolbar.tsx} +20 -15
  37. package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.scss +0 -9
  38. package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/{side-nav-outer-toolbar.js → side-nav-outer-toolbar.tsx} +19 -16
  39. package/src/templates/react/application/src/layouts/single-card/{single-card.js → single-card.tsx} +2 -1
  40. package/src/templates/react/application/src/{polyfills.js → polyfills.tsx} +0 -0
  41. package/src/templates/react/application/src/types.tsx +57 -0
  42. package/src/templates/react/application/src/utils/{default-user.js → default-user.tsx} +0 -0
  43. package/src/templates/react/application/src/utils/{media-query.js → media-query.tsx} +4 -3
  44. package/src/templates/react/application/src/utils/{patches.js → patches.tsx} +1 -1
  45. package/src/templates/react/page/{page.js → page.tsx} +0 -0
  46. package/src/templates/react/sample-pages/home/{home.js → home.tsx} +0 -0
  47. package/src/templates/react/sample-pages/{index.js → index.tsx} +0 -0
  48. package/src/templates/react/sample-pages/profile/{profile.js → profile.tsx} +0 -0
  49. package/src/templates/react/sample-pages/tasks/{tasks.js → tasks.tsx} +1 -1
  50. package/src/templates/vue-v2/application/devextreme.json +2 -1
  51. package/src/templates/vue-v2/application/src/dx-styles.scss +12 -0
  52. package/src/templates/vue-v2/application/src/layouts/side-nav-inner-toolbar.vue +0 -15
  53. package/src/templates/vue-v2/application/src/layouts/side-nav-outer-toolbar.vue +0 -9
  54. package/src/templates/vue-v3/application/devextreme.json +2 -1
  55. package/src/templates/vue-v3/application/src/dx-styles.scss +12 -0
  56. package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +2 -17
  57. package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +0 -9
  58. package/src/themebuider.js +19 -4
  59. package/src/utility/latest-versions.js +3 -3
  60. package/src/utility/ng-version.js +35 -0
  61. package/src/utility/prompts/layout.js +9 -21
  62. package/src/utility/prompts/prompts.js +24 -8
  63. package/src/utility/prompts/typescript.js +18 -0
  64. package/src/utility/prompts/vue-version.js +9 -21
  65. package/src/utility/template-creator.js +11 -6
  66. package/src/utility/typescript-extension.js +24 -0
  67. package/src/templates/react/application/src/UnauthenticatedContent.js +0 -35
  68. package/src/templates/react/application/src/app-routes.js +0 -24
  69. package/src/templates/react/application/src/components/index.js +0 -7
  70. package/src/templates/react/application/src/contexts/navigation.js +0 -34
package/src/commands.json CHANGED
@@ -18,6 +18,9 @@
18
18
  }, {
19
19
  "name": "--version",
20
20
  "description": "Specifies whether to generate a Vue 2 or Vue 3 application. Available values: 2 (default) and 3"
21
+ }, {
22
+ "name": "--template",
23
+ "description": "Create template with typescsript support. Specifies for React & Vue application"
21
24
  }]
22
25
  }]
23
26
  }, {
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { Switch, Route<%=^empty%>, Redirect<%=/empty%> } from 'react-router-dom';
1
+ import { Routes, Route, Navigate } from 'react-router-dom';
3
2
  import appInfo from './app-info';
4
3
  import routes from './app-routes';
5
4
  import { <%=layout%> as SideNavBarLayout } from './layouts';
@@ -8,17 +7,19 @@ import { Footer } from './components';
8
7
  export default function Content() {
9
8
  return (
10
9
  <SideNavBarLayout title={appInfo.title}>
11
- <Switch>
12
- {routes.map(({ path, component }) => (
10
+ <Routes>
11
+ {routes.map(({ path, element }) => (
13
12
  <Route
14
- exact
15
13
  key={path}
16
14
  path={path}
17
- component={component}
15
+ element={element}
18
16
  />
19
- ))}<%=^empty%>
20
- <Redirect to={'/home'} /><%=/empty%>
21
- </Switch>
17
+ ))}
18
+ <Route
19
+ path='*'
20
+ element={<Navigate to='/home' />}
21
+ />
22
+ </Routes>
22
23
  <Footer>
23
24
  Copyright © 2011-{new Date().getFullYear()} {appInfo.title} Inc.
24
25
  <br />
@@ -28,3 +29,4 @@ export default function Content() {
28
29
  </SideNavBarLayout>
29
30
  );
30
31
  }
32
+
@@ -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, password) {
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, password) {
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, recoveryCode) {
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);
@@ -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 { useHistory, useParams } from 'react-router-dom';
2
+ import { useNavigate, useParams } from 'react-router-dom';
3
3
  import Form, {
4
4
  Item,
5
5
  Label,
@@ -10,15 +10,16 @@ import Form, {
10
10
  } from 'devextreme-react/form';
11
11
  import LoadIndicator from 'devextreme-react/load-indicator';
12
12
  import notify from 'devextreme/ui/notify';
13
+ <%=#isTypeScript%>import { ValidationType } from '../../types';<%=/isTypeScript%>
13
14
  import { changePassword } from '../../api/auth';
14
15
 
15
- export default function ChangePasswordForm(props) {
16
- const history = useHistory();
16
+ export default function ChangePasswordForm() {
17
+ const navigate = useNavigate();
17
18
  const [loading, setLoading] = useState(false);
18
- const formData = useRef({});
19
+ const formData = useRef({ password: '' });
19
20
  const { recoveryCode } = useParams();
20
21
 
21
- const onSubmit = useCallback(async (e) => {
22
+ const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
22
23
  e.preventDefault();
23
24
  const { password } = formData.current;
24
25
  setLoading(true);
@@ -27,14 +28,14 @@ export default function ChangePasswordForm(props) {
27
28
  setLoading(false);
28
29
 
29
30
  if (result.isOk) {
30
- history.push('/login');
31
+ navigate('/login');
31
32
  } else {
32
33
  notify(result.message, 'error', 2000);
33
34
  }
34
- }, [history, recoveryCode]);
35
+ }, [navigate, recoveryCode]);
35
36
 
36
37
  const confirmPassword = useCallback(
37
- ({ value }) => value === formData.current.password,
38
+ ({ value }<%=#isTypeScript%>: ValidationType<%=/isTypeScript%>) => value === formData.current.password,
38
39
  []
39
40
  );
40
41
 
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useCallback } from 'react';
2
- import { Link, useHistory } from 'react-router-dom';
2
+ import { Link, useNavigate } from 'react-router-dom';
3
3
  import Form, {
4
4
  Item,
5
5
  Label,
@@ -12,14 +12,15 @@ 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 './create-account-form.scss';
15
+ <%=#isTypeScript%>import { ValidationType } from '../../types';<%=/isTypeScript%>
16
+ import './CreateAccountForm.scss';
16
17
 
17
- export default function CreateAccountForm(props) {
18
- const history = useHistory();
18
+ export default function CreateAccountForm() {
19
+ const navigate = useNavigate();
19
20
  const [loading, setLoading] = useState(false);
20
- const formData = useRef({});
21
+ const formData = useRef({ email: '', password: '' });
21
22
 
22
- const onSubmit = useCallback(async (e) => {
23
+ const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
23
24
  e.preventDefault();
24
25
  const { email, password } = formData.current;
25
26
  setLoading(true);
@@ -28,14 +29,14 @@ export default function CreateAccountForm(props) {
28
29
  setLoading(false);
29
30
 
30
31
  if (result.isOk) {
31
- history.push('/login');
32
+ navigate('/login');
32
33
  } else {
33
34
  notify(result.message, 'error', 2000);
34
35
  }
35
- }, [history]);
36
+ }, [navigate]);
36
37
 
37
38
  const confirmPassword = useCallback(
38
- ({ value }) => value === formData.current.password,
39
+ ({ value }<%=#isTypeScript%>: ValidationType<%=/isTypeScript%>) => value === formData.current.password,
39
40
  []
40
41
  );
41
42
 
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import './footer.scss';
2
+ import './Footer.scss';
3
3
 
4
4
  export default function Footer({ ...rest }) {
5
5
  return <footer className={'footer'} {...rest} />;
@@ -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/user-panel';
5
- import './header.scss';
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';
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useCallback } from 'react';
2
- import { Link, useHistory } from 'react-router-dom';
2
+ import { Link, useNavigate } from 'react-router-dom';
3
3
  import Form, {
4
4
  Item,
5
5
  Label,
@@ -12,15 +12,15 @@ 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 './login-form.scss';
15
+ import './LoginForm.scss';
16
16
 
17
17
  export default function LoginForm() {
18
- const history = useHistory();
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
- const onSubmit = useCallback(async (e) => {
23
+ const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
24
24
  e.preventDefault();
25
25
  const { email, password } = formData.current;
26
26
  setLoading(true);
@@ -33,8 +33,8 @@ export default function LoginForm() {
33
33
  }, [signIn]);
34
34
 
35
35
  const onCreateAccountClick = useCallback(() => {
36
- history.push('/create-account');
37
- }, [history]);
36
+ navigate('/create-account');
37
+ }, [navigate]);
38
38
 
39
39
  return (
40
40
  <form className={'login-form'} onSubmit={onSubmit}>
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useCallback } from 'react';
2
- import { Link, useHistory } from "react-router-dom";
2
+ import { Link, useNavigate } from "react-router-dom";
3
3
  import Form, {
4
4
  Item,
5
5
  Label,
@@ -11,16 +11,16 @@ 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 './reset-password-form.scss';
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(props) {
19
- const history = useHistory();
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
- const onSubmit = useCallback(async (e) => {
23
+ const onSubmit = useCallback(async (e<%=#isTypeScript%>: any<%=/isTypeScript%>) => {
24
24
  e.preventDefault();
25
25
  const { email } = formData.current;
26
26
  setLoading(true);
@@ -29,12 +29,12 @@ export default function ResetPasswordForm(props) {
29
29
  setLoading(false);
30
30
 
31
31
  if (result.isOk) {
32
- history.push('/login');
32
+ navigate('/login');
33
33
  notify(notificationText, 'success', 2500);
34
34
  } else {
35
35
  notify(result.message, 'error', 2000);
36
36
  }
37
- }, [history]);
37
+ }, [navigate]);
38
38
 
39
39
  return (
40
40
  <form className={'reset-password-form'} onSubmit={onSubmit}>
@@ -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 './side-navigation-menu.scss';
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
- if(item.path && !(/^\//.test(item.path))){
23
- item.path = `/${item.path}`;
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,16 +32,16 @@ export default function SideNavigationMenu(props) {
34
32
 
35
33
  const { navigationData: { currentPath } } = useNavigation();
36
34
 
37
- const treeViewRef = useRef();
38
- const wrapperRef = useRef();
39
- const getWrapperRef = useCallback((element) => {
35
+ const treeViewRef = useRef<%=#isTypeScript%><TreeView><%=/isTypeScript%>(null);
36
+ const wrapperRef = useRef<%=#isTypeScript%><HTMLDivElement><%=/isTypeScript%>();
37
+ const getWrapperRef = useCallback((element<%=#isTypeScript%>: HTMLDivElement<%=/isTypeScript%>) => {
40
38
  const prevElement = wrapperRef.current;
41
39
  if (prevElement) {
42
40
  events.off(prevElement, 'dxclick');
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]);
@@ -1,16 +1,17 @@
1
1
  import React, { useMemo } from 'react';
2
- import { useHistory } from "react-router-dom";
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 './user-panel.scss';
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 history = useHistory();
11
+ const navigate = useNavigate();
11
12
 
12
13
  function navigateToProfile() {
13
- history.push("/profile");
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.avatarUrl}) no-repeat #fff`,
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.email}</div>
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, password) => {
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%>: Record<string, 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
+ }
@@ -5,26 +5,38 @@
5
5
  display: flex;
6
6
  height: 100%;
7
7
  width: 100%;
8
- }
9
8
 
10
- .side-nav-outer-toolbar .dx-drawer {
11
- height: calc(100% - 56px)
12
- }
9
+ .content {
10
+ line-height: 1.5;
11
+ flex-grow: 1;
13
12
 
14
- .app .content {
15
- line-height: 1.5;
13
+ h2 {
14
+ font-size: 30px;
15
+ margin-top: 20px;
16
+ margin-bottom: 20px;
17
+ }
18
+ }
16
19
 
17
- h2 {
18
- font-size: 30px;
20
+ .container {
21
+ height: 100%;
22
+ flex-direction: column;
23
+ display: flex;
24
+ }
25
+
26
+ .layout-body {
27
+ flex: 1;
28
+ min-height: 0;
29
+ }
30
+
31
+ .content-block {
32
+ margin-left: 40px;
33
+ margin-right: 40px;
19
34
  margin-top: 20px;
20
- margin-bottom: 20px;
21
35
  }
22
36
  }
23
37
 
24
- .app .content-block {
25
- margin-left: 40px;
26
- margin-right: 40px;
27
- margin-top: 20px;
38
+ .side-nav-outer-toolbar .dx-drawer {
39
+ height: calc(100% - 56px)
28
40
  }
29
41
 
30
42
  .screen-x-small .content-block {
@@ -2,21 +2,6 @@
2
2
  width: 100%;
3
3
  }
4
4
 
5
- .container {
6
- height: 100%;
7
- flex-direction: column;
8
- display: flex;
9
- }
10
-
11
- .layout-body {
12
- flex: 1;
13
- min-height: 0;
14
- }
15
-
16
- .content {
17
- flex-grow: 1;
18
- }
19
-
20
5
  #navigation-header {
21
6
  @import "../../themes/generated/variables.additional.scss";
22
7
  background-color: $base-accent;
@@ -29,7 +14,7 @@
29
14
  .screen-x-small & {
30
15
  padding-left: 20px;
31
16
  }
32
-
17
+
33
18
  .dx-theme-generic & {
34
19
  padding-top: 10px;
35
20
  padding-bottom: 10px;