add users table, user form, show\create\delete user, router service
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
import React, {memo} from 'react';
|
||||
import {Route, Switch} from 'react-router-dom';
|
||||
import {createStore} from '@reatom/core';
|
||||
import {context} from '@reatom/react';
|
||||
import mainPageRouter from '_pages/main/routing';
|
||||
import usersPageRouter from '_pages/users/routing';
|
||||
@ -12,6 +11,8 @@ import NotFoundPage from '_pages/not-found/components/page';
|
||||
import MainLayout from '../main-layout';
|
||||
import jss from 'jss';
|
||||
import preset from 'jss-preset-default';
|
||||
import {store} from '../../../core/infrastructure/atom/store';
|
||||
import ConnectedRouter from '../../../core/blocks/connected-router/ConnectedRouter';
|
||||
|
||||
jss.setup(preset());
|
||||
|
||||
@ -33,23 +34,23 @@ const styles = {
|
||||
jss.createStyleSheet(styles).attach();
|
||||
|
||||
const Page: React.FC = () => {
|
||||
const store = createStore();
|
||||
|
||||
return (
|
||||
<context.Provider value={store}>
|
||||
<MainLayout>
|
||||
<Switch>
|
||||
{mainPageRouter}
|
||||
{usersPageRouter}
|
||||
{actionsPageRouter}
|
||||
{conditionsPageRouter}
|
||||
{graphsPageRouter}
|
||||
{currenciesPageRouter}
|
||||
<Route>
|
||||
<NotFoundPage />
|
||||
</Route>
|
||||
</Switch>
|
||||
</MainLayout>
|
||||
<ConnectedRouter>
|
||||
<MainLayout>
|
||||
<Switch>
|
||||
{mainPageRouter}
|
||||
{usersPageRouter}
|
||||
{actionsPageRouter}
|
||||
{conditionsPageRouter}
|
||||
{graphsPageRouter}
|
||||
{currenciesPageRouter}
|
||||
<Route>
|
||||
<NotFoundPage />
|
||||
</Route>
|
||||
</Switch>
|
||||
</MainLayout>
|
||||
</ConnectedRouter>
|
||||
</context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -21,6 +21,7 @@ type RequestEntities<T> = {
|
||||
type EntityWithId<T> = T & {
|
||||
id: string;
|
||||
};
|
||||
type EntityWithoutId<T> = Omit<T, 'id'>;
|
||||
|
||||
type ResponseEntities<T> = {
|
||||
data: EntityWithId<T>[];
|
||||
@ -63,8 +64,8 @@ export class CrudAPI<T> {
|
||||
return http.get<never, T>(`${this.endpoint}/${id}`);
|
||||
}
|
||||
|
||||
create = (entity: T): Promise<EntityWithId<T>> => {
|
||||
return http.post<never, T, EntityWithId<T>>(this.endpoint, undefined, entity);
|
||||
create = (entity: EntityWithoutId<T>): Promise<EntityWithId<T>> => {
|
||||
return http.post<never, EntityWithoutId<T>, EntityWithId<T>>(this.endpoint, undefined, entity);
|
||||
}
|
||||
|
||||
update = (id: string, entity: T): Promise<EntityWithId<T>> => {
|
||||
|
||||
22
src/core/blocks/connected-router/ConnectedRouter.tsx
Normal file
22
src/core/blocks/connected-router/ConnectedRouter.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import {useAtom} from '@reatom/react';
|
||||
import React, {FC, Fragment, memo, PropsWithChildren, useEffect} from 'react';
|
||||
import {useHistory} from 'react-router';
|
||||
import {routerAtom} from '../../infrastructure/atom/routerAtom';
|
||||
|
||||
const ConnectedRouter: FC<PropsWithChildren<unknown>> = ({children}) => {
|
||||
const history = useHistory();
|
||||
|
||||
const route = useAtom(routerAtom);
|
||||
|
||||
useEffect(() => {
|
||||
history.push(route);
|
||||
}, [history, route]);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{children}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ConnectedRouter);
|
||||
1
src/core/blocks/connected-router/index.ts
Normal file
1
src/core/blocks/connected-router/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './ConnectedRouter';
|
||||
@ -8,5 +8,9 @@ export const ROUTES = {
|
||||
};
|
||||
|
||||
export const ENDPOINT = {
|
||||
USERS: 'http://vigdorov.ru:3011/users',
|
||||
USERS: 'https://localhost:3189/api/users',
|
||||
ACTIONS: 'https://localhost:3189/api/bot/actions',
|
||||
CONDITIONS: 'https://localhost:3189/api/bot/conditions',
|
||||
GRAPHS: 'https://localhost:3189/api/bot/graphs',
|
||||
CURRENCIES: 'https://localhost:3189/api/bot/currencies',
|
||||
};
|
||||
|
||||
17
src/core/infrastructure/atom/routerAtom.ts
Normal file
17
src/core/infrastructure/atom/routerAtom.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {declareAction, declareAtom} from '@reatom/core';
|
||||
import {createHashHistory} from 'history';
|
||||
import {store} from './store';
|
||||
|
||||
const {location: {pathname, search}} = createHashHistory();
|
||||
|
||||
const routerAction = declareAction<string>();
|
||||
|
||||
export const routerAtom = declareAtom(`${pathname}${search}`, on => [
|
||||
on(routerAction, (_state, payload) => payload),
|
||||
]);
|
||||
|
||||
export const bindedActions = {
|
||||
routerAction: (route: string) => {
|
||||
store.dispatch(routerAction(route));
|
||||
},
|
||||
};
|
||||
3
src/core/infrastructure/atom/store.ts
Normal file
3
src/core/infrastructure/atom/store.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import {createStore} from '@reatom/core';
|
||||
|
||||
export const store = createStore();
|
||||
38
src/core/infrastructure/atom/usersAtom.ts
Normal file
38
src/core/infrastructure/atom/usersAtom.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import {declareAction, declareAtom} from '@reatom/core';
|
||||
import {User} from '../../../pages/users/types';
|
||||
import {store} from './store';
|
||||
|
||||
export type FieldData = {
|
||||
name: keyof User | Array<keyof User>;
|
||||
value?: any;
|
||||
touched?: boolean;
|
||||
validating?: boolean;
|
||||
errors?: string[];
|
||||
};
|
||||
|
||||
const INIT_USERS: User[] = [];
|
||||
export const INIT_USER: FieldData[] = [
|
||||
{name: 'id', value: ''},
|
||||
{name: 'login', value: ''},
|
||||
{name: 'password', value: ''},
|
||||
];
|
||||
export const loadUsersAction = declareAction<User[]>();
|
||||
|
||||
export const usersAtom = declareAtom(INIT_USERS, on => [
|
||||
on(loadUsersAction, (_state, payload) => payload),
|
||||
]);
|
||||
|
||||
export const loadUserForm = declareAction<FieldData[]>();
|
||||
|
||||
export const userFormAtom = declareAtom(INIT_USER, on => [
|
||||
on(loadUserForm, (_state, payload) => payload),
|
||||
]);
|
||||
|
||||
export const bindedActions = {
|
||||
loadUsersAction: (users: User[]) => {
|
||||
store.dispatch(loadUsersAction(users));
|
||||
},
|
||||
loadUserForm: (fieldData: FieldData[]) => {
|
||||
store.dispatch(loadUserForm(fieldData));
|
||||
}
|
||||
};
|
||||
34
src/core/services/RouterService.ts
Normal file
34
src/core/services/RouterService.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import {decode, encode, ParsedUrlQuery} from 'querystring';
|
||||
import {bindedActions} from '../infrastructure/atom/routerAtom';
|
||||
import {isNotEmpty} from '../referers/common';
|
||||
|
||||
type PushQueryOptions = {
|
||||
reset?: boolean;
|
||||
shouldRefresh?: boolean;
|
||||
};
|
||||
|
||||
const getQuery = () => decode(window.location.search.slice(1));
|
||||
|
||||
class RouterService {
|
||||
push(route: string) {
|
||||
bindedActions.routerAction(route);
|
||||
}
|
||||
|
||||
pushWithQuery(path: string, query: ParsedUrlQuery, options?: PushQueryOptions) {
|
||||
const currentQuery = getQuery();
|
||||
|
||||
const finalQuery = encode({
|
||||
...(!options?.reset ? {
|
||||
...currentQuery,
|
||||
} : {}),
|
||||
...(options?.shouldRefresh ? {
|
||||
__timestamp: Date.now(),
|
||||
} : {}),
|
||||
...query,
|
||||
});
|
||||
|
||||
this.push([path, finalQuery].filter(isNotEmpty).join('?'));
|
||||
}
|
||||
}
|
||||
|
||||
export const routerService = new RouterService();
|
||||
6
src/core/types/EntityModes.ts
Normal file
6
src/core/types/EntityModes.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum EntityMode {
|
||||
Create = 'create',
|
||||
Show = 'show',
|
||||
Copy = 'copy',
|
||||
Edit = 'edit',
|
||||
}
|
||||
4
src/pages/actions/api/ActionsAPI.ts
Normal file
4
src/pages/actions/api/ActionsAPI.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import {ENDPOINT} from '_consts/common';
|
||||
import {CrudAPI} from '../../../core/api/CrudAPI';
|
||||
|
||||
export const actionsAPI = new CrudAPI(ENDPOINT.ACTIONS);
|
||||
@ -1,4 +1,7 @@
|
||||
import React, {FC, memo} from 'react';
|
||||
import {actionsAPI} from '../../api/ActionsAPI';
|
||||
|
||||
actionsAPI.request();
|
||||
|
||||
const Page: FC = () => {
|
||||
return (
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {ENDPOINT} from '_consts/common';
|
||||
import {CrudAPI} from '../../../core/api/CrudAPI';
|
||||
import {User} from '../types';
|
||||
|
||||
export const usersAPI = new CrudAPI(ENDPOINT.USERS);
|
||||
export const usersAPI = new CrudAPI<User>(ENDPOINT.USERS);
|
||||
|
||||
@ -1,11 +1,41 @@
|
||||
import {Button, Layout} from 'antd';
|
||||
import React, {FC, memo} from 'react';
|
||||
import {usersAPI} from '../../api/UsersAPI';
|
||||
import {createUseStyles} from 'react-jss';
|
||||
import {ROUTES} from '../../../../core/consts/common';
|
||||
import {routerService} from '../../../../core/services/RouterService';
|
||||
import {EntityMode} from '../../../../core/types/EntityModes';
|
||||
import UserSidebar from '../user-sidebar/UserSidebar';
|
||||
import UsersTable from '../users-table/UsersTable';
|
||||
|
||||
usersAPI.request();
|
||||
const useStyles = createUseStyles({
|
||||
header: {
|
||||
backgroundColor: '#fff',
|
||||
}
|
||||
});
|
||||
|
||||
const handleClickNewUser = () => {
|
||||
routerService.pushWithQuery(ROUTES.USERS, {
|
||||
mode: EntityMode.Create,
|
||||
});
|
||||
};
|
||||
|
||||
const Page: FC = () => {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<div>users</div>
|
||||
<Layout>
|
||||
<Layout.Header className={classes.header}>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handleClickNewUser}
|
||||
>
|
||||
New user
|
||||
</Button>
|
||||
</Layout.Header>
|
||||
<Layout.Content>
|
||||
<UsersTable />
|
||||
<UserSidebar />
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
201
src/pages/users/components/user-sidebar/UserSidebar.tsx
Normal file
201
src/pages/users/components/user-sidebar/UserSidebar.tsx
Normal file
@ -0,0 +1,201 @@
|
||||
import {useAtom} from '@reatom/react';
|
||||
import {Button, Drawer, Form, Input} from 'antd';
|
||||
import React, {FC, Fragment, memo, useCallback, useEffect, useMemo} from 'react';
|
||||
import {createUseStyles} from 'react-jss';
|
||||
import {ROUTES} from '../../../../core/consts/common';
|
||||
import {useQuery} from '../../../../core/hooks/useQuery';
|
||||
import {bindedActions, FieldData, userFormAtom} from '../../../../core/infrastructure/atom/usersAtom';
|
||||
import {isNotEmpty} from '../../../../core/referers/common';
|
||||
import {routerService} from '../../../../core/services/RouterService';
|
||||
import {EntityMode} from '../../../../core/types/EntityModes';
|
||||
import {usersService} from '../../services/UsersServices';
|
||||
import {User} from '../../types';
|
||||
import {queryParsers} from '../../utils';
|
||||
|
||||
const AVAILABLE_CLOSE_MODES = [EntityMode.Show];
|
||||
const DISABLED_FORM_MODES = [EntityMode.Show];
|
||||
const SHOW_ID_MODES = [EntityMode.Show];
|
||||
|
||||
const useStyles = createUseStyles({
|
||||
button: {
|
||||
marginRight: '8px',
|
||||
}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
routerService.push(ROUTES.USERS);
|
||||
};
|
||||
|
||||
const onFieldsChange = (_: FieldData[], allFields: FieldData[]) => {
|
||||
bindedActions.loadUserForm(allFields);
|
||||
};
|
||||
|
||||
const UserSidebar: FC = () => {
|
||||
const {mode, id} = useQuery(queryParsers);
|
||||
const fields = useAtom(userFormAtom);
|
||||
const classes = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
usersService.loadUser(id);
|
||||
}, [id, mode]);
|
||||
|
||||
const disabled = useMemo(() => !mode || DISABLED_FORM_MODES.includes(mode), [mode]);
|
||||
|
||||
const handleCreate = useCallback(() => {
|
||||
const user = fields.reduce<User>((acc, {name, value}) => {
|
||||
if (Array.isArray(name)) {
|
||||
if (isNotEmpty(name[0])) {
|
||||
acc[name[0]] = value;
|
||||
}
|
||||
} else {
|
||||
acc[name] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {id: '', login: '', password: ''});
|
||||
usersService.createUser(user);
|
||||
}, [fields]);
|
||||
|
||||
const handleCopy = useCallback(() => {
|
||||
if (id) {
|
||||
routerService.pushWithQuery(ROUTES.USERS, {
|
||||
id,
|
||||
mode: EntityMode.Copy,
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
if (id) {
|
||||
routerService.pushWithQuery(ROUTES.USERS, {
|
||||
id,
|
||||
mode: EntityMode.Edit,
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
usersService.removeUser(id);
|
||||
}, [id]);
|
||||
|
||||
const handleBackdrop = useCallback(() => {
|
||||
if (mode && AVAILABLE_CLOSE_MODES.includes(mode)) {
|
||||
handleClose();
|
||||
}
|
||||
}, [mode]);
|
||||
|
||||
const title = useMemo(() => {
|
||||
switch (mode) {
|
||||
case EntityMode.Create:
|
||||
return 'Creating a user';
|
||||
case EntityMode.Copy:
|
||||
return `Coping user "${id}"`;
|
||||
case EntityMode.Edit:
|
||||
return `Editing user "${id}"`;
|
||||
case EntityMode.Show:
|
||||
return `Viewing user "${id}"`;
|
||||
default:
|
||||
return `Mode "${mode}" not supported for user form`;
|
||||
}
|
||||
}, [mode, id]);
|
||||
|
||||
const primaryButton = useMemo(() => {
|
||||
switch (mode) {
|
||||
case EntityMode.Create:
|
||||
case EntityMode.Copy:
|
||||
return (
|
||||
<Button
|
||||
className={classes.button}
|
||||
onClick={handleCreate}
|
||||
type="primary"
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
);
|
||||
case EntityMode.Edit:
|
||||
return (
|
||||
<Button
|
||||
className={classes.button}
|
||||
type="primary"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
);
|
||||
case EntityMode.Show:
|
||||
return (
|
||||
<Button
|
||||
className={classes.button}
|
||||
onClick={handleEdit}
|
||||
type="primary"
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}, [mode, classes, handleEdit, handleCreate]);
|
||||
|
||||
const renderFooter = useMemo(() => {
|
||||
return (
|
||||
<div>
|
||||
{primaryButton}
|
||||
{mode === EntityMode.Show && (
|
||||
<Fragment>
|
||||
<Button
|
||||
className={classes.button}
|
||||
onClick={handleCopy}
|
||||
>
|
||||
Copy
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.button}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Fragment>
|
||||
)}
|
||||
<Button onClick={handleClose}>Cancel</Button>
|
||||
</div>
|
||||
);
|
||||
}, [primaryButton, mode, classes, handleCopy, handleDelete]);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
visible={!!mode}
|
||||
closable={false}
|
||||
onClose={handleBackdrop}
|
||||
width="600"
|
||||
title={title}
|
||||
footer={renderFooter}
|
||||
>
|
||||
<Form
|
||||
fields={fields}
|
||||
onFieldsChange={onFieldsChange as any}
|
||||
>
|
||||
<Form.Item
|
||||
label="Login"
|
||||
name="login"
|
||||
>
|
||||
<Input disabled={disabled} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Password"
|
||||
name="password"
|
||||
>
|
||||
<Input disabled={disabled} />
|
||||
</Form.Item>
|
||||
{mode && SHOW_ID_MODES.includes(mode) && (
|
||||
<Form.Item
|
||||
label="ID"
|
||||
name="id"
|
||||
>
|
||||
<Input disabled={disabled} />
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(UserSidebar);
|
||||
1
src/pages/users/components/user-sidebar/index.ts
Normal file
1
src/pages/users/components/user-sidebar/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './UserSidebar';
|
||||
57
src/pages/users/components/users-table/UsersTable.tsx
Normal file
57
src/pages/users/components/users-table/UsersTable.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import {useAtom} from '@reatom/react';
|
||||
import {Table} from 'antd';
|
||||
import {head} from 'lodash';
|
||||
import React, {FC, memo, useEffect, useMemo} from 'react';
|
||||
import {ROUTES} from '../../../../core/consts/common';
|
||||
import {usersAtom} from '../../../../core/infrastructure/atom/usersAtom';
|
||||
import {routerService} from '../../../../core/services/RouterService';
|
||||
import {EntityMode} from '../../../../core/types/EntityModes';
|
||||
import {objectKeys} from '../../../../core/utils/objectKeys';
|
||||
import {usersService} from '../../services/UsersServices';
|
||||
import {User} from '../../types';
|
||||
|
||||
const onRow = (user: User) => ({
|
||||
onClick: () => {
|
||||
routerService.pushWithQuery(ROUTES.USERS, {
|
||||
id: user.id,
|
||||
mode: EntityMode.Show,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const UsersTable: FC = () => {
|
||||
const users = useAtom(usersAtom);
|
||||
|
||||
useEffect(() => {
|
||||
usersService.loadUsers();
|
||||
}, []);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return objectKeys(head(users) ?? {}).map(field => {
|
||||
return {
|
||||
title: field,
|
||||
dataIndex: field,
|
||||
key: field,
|
||||
};
|
||||
});
|
||||
}, [users]);
|
||||
|
||||
const dataSource = useMemo(() => {
|
||||
return users.map(user => {
|
||||
return {
|
||||
...user,
|
||||
key: user.id,
|
||||
};
|
||||
});
|
||||
}, [users]);
|
||||
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
onRow={onRow}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(UsersTable);
|
||||
1
src/pages/users/components/users-table/index.ts
Normal file
1
src/pages/users/components/users-table/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './UsersTable';
|
||||
56
src/pages/users/services/UsersServices.ts
Normal file
56
src/pages/users/services/UsersServices.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import {ROUTES} from '../../../core/consts/common';
|
||||
import {bindedActions, FieldData, INIT_USER} from '../../../core/infrastructure/atom/usersAtom';
|
||||
import {routerService} from '../../../core/services/RouterService';
|
||||
import {objectEntries} from '../../../core/utils/objectEntries';
|
||||
import {usersAPI} from '../api/UsersAPI';
|
||||
import {User} from '../types';
|
||||
|
||||
class UsersService {
|
||||
loadUsers() {
|
||||
return usersAPI
|
||||
.request()
|
||||
.then(({data}) => {
|
||||
bindedActions.loadUsersAction(data);
|
||||
});
|
||||
}
|
||||
|
||||
loadUser(id?: string) {
|
||||
if (id) {
|
||||
usersAPI
|
||||
.find(id)
|
||||
.then(user => {
|
||||
const fieldData = objectEntries(user).reduce<FieldData[]>((acc, [name, value]) => {
|
||||
acc.push({name, value});
|
||||
return acc;
|
||||
}, []);
|
||||
bindedActions.loadUserForm(fieldData);
|
||||
});
|
||||
}
|
||||
bindedActions.loadUserForm(INIT_USER);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
createUser({id, ...user}: User) {
|
||||
usersAPI
|
||||
.create(user)
|
||||
.then(() => {
|
||||
this.loadUsers().then(() => {
|
||||
routerService.push(ROUTES.USERS);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeUser(id?: string) {
|
||||
if (id) {
|
||||
usersAPI
|
||||
.remove(id)
|
||||
.then(() => {
|
||||
this.loadUsers().then(() => {
|
||||
routerService.push(ROUTES.USERS);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const usersService = new UsersService();
|
||||
12
src/pages/users/types.ts
Normal file
12
src/pages/users/types.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import {EntityMode} from '../../core/types/EntityModes';
|
||||
|
||||
export type User = {
|
||||
id: string;
|
||||
login: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type QueryParams = {
|
||||
id?: string;
|
||||
mode?: EntityMode;
|
||||
};
|
||||
8
src/pages/users/utils.ts
Normal file
8
src/pages/users/utils.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import {QueryParsers} from '../../core/utils/getQueryFromUrl';
|
||||
import {stringParser} from '../../core/utils/queryParsers';
|
||||
import {QueryParams} from './types';
|
||||
|
||||
export const queryParsers: QueryParsers<QueryParams> = {
|
||||
id: stringParser(),
|
||||
mode: stringParser(),
|
||||
};
|
||||
@ -26,6 +26,19 @@ module.exports = {
|
||||
compress: true,
|
||||
open: true,
|
||||
port: 3189,
|
||||
http2: true,
|
||||
proxy: {
|
||||
'/api/users': {
|
||||
target: 'http://vigdorov.ru:3011',
|
||||
pathRewrite: { '^/api': '' },
|
||||
secure: false,
|
||||
},
|
||||
'/api/bot': {
|
||||
target: 'http://vigdorov.ru:3012',
|
||||
pathRewrite: { '^/api/bot': '' },
|
||||
secure: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
|
||||
Reference in New Issue
Block a user