From dca17e31e8bc7908d36d5e4dee24c018bcce5243 Mon Sep 17 00:00:00 2001 From: goodm2ice Date: Fri, 25 Feb 2022 16:57:08 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=B5=D0=BC=D0=BE=D0=B8=D0=B7=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D0=BE=20=D0=B1=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D1=88=D0=B5=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?= =?UTF-8?q?=20=D0=B8=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9,=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B0=D0=B4=D1=80=D0=B5=D1=81=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=81=D0=BE=20=D1=81=D1=82=D0=B0=D1=80=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D1=8B=20=D0=B2=D1=85=D0=BE=D0=B4=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=B5=D0=B4=D1=8B=D0=B4=D1=83=D1=89=D1=83?= =?UTF-8?q?=D1=8E,=20=D0=BA=D0=BE=D1=81=D0=BC=D0=B5=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 5 ++- src/components/Layout/AdminLayoutPortal.tsx | 30 ++++++++------ src/components/LoaderPortal.tsx | 7 ++-- src/components/PageHeader.tsx | 30 ++++++++------ src/components/Poprompt.tsx | 6 +-- src/components/Private/PrivateContent.tsx | 7 ++-- .../Private/PrivateDefaultRoute.tsx | 19 ++++++--- src/components/Private/PrivateMenuItem.tsx | 15 ++++--- src/components/Private/PrivateRoute.tsx | 2 +- src/components/Table/EditableCell.tsx | 12 +++--- src/components/Table/EditableTable.jsx | 41 +++++++++---------- src/components/Table/index.tsx | 11 +++-- src/components/Table/sorters.ts | 8 ++-- src/components/UploadForm.jsx | 6 +-- src/components/UserMenu.tsx | 21 +++++----- src/components/WellTreeSelector.tsx | 26 +++++++----- src/components/{ => icons}/Loader.tsx | 0 src/components/icons/index.ts | 1 + src/components/views/MarkView.tsx | 33 --------------- src/components/views/RoleView.tsx | 6 +-- src/components/views/index.ts | 2 - src/index.js | 20 ++++----- src/pages/Cluster/ClusterWells.jsx | 16 ++++---- src/pages/Deposit.jsx | 6 ++- src/pages/DrillingProgram/index.jsx | 2 +- src/pages/Login.jsx | 16 ++++---- src/pages/Register.jsx | 6 +-- .../WellCompositeSections.jsx | 16 ++++---- src/pages/WellOperations/index.jsx | 9 ++-- src/reportWebVitals.js | 18 ++++---- 30 files changed, 201 insertions(+), 196 deletions(-) rename src/components/{ => icons}/Loader.tsx (100%) delete mode 100644 src/components/views/MarkView.tsx diff --git a/src/App.js b/src/App.js index ecc71fa..18b2b83 100644 --- a/src/App.js +++ b/src/App.js @@ -15,12 +15,13 @@ import Login from '@pages/Login' import Register from '@pages/Register' import '@styles/App.less' +import { memo } from 'react' //OpenAPI.BASE = 'http://localhost:3000' OpenAPI.TOKEN = async () => getUserToken() OpenAPI.HEADERS = {'Content-Type': 'application/json'} -export const App = () => ( +export const App = memo(() => ( @@ -36,6 +37,6 @@ export const App = () => ( -) +)) export default App diff --git a/src/components/Layout/AdminLayoutPortal.tsx b/src/components/Layout/AdminLayoutPortal.tsx index 72442d8..ba234b7 100644 --- a/src/components/Layout/AdminLayoutPortal.tsx +++ b/src/components/Layout/AdminLayoutPortal.tsx @@ -1,5 +1,5 @@ import { memo, ReactNode } from 'react' -import { Link } from 'react-router-dom' +import { Link, useLocation } from 'react-router-dom' import { Button, Layout, LayoutProps } from 'antd' import PageHeader from '@components/PageHeader' @@ -8,17 +8,21 @@ export type AdminLayoutPortalProps = LayoutProps & { title?: ReactNode } -export const AdminLayoutPortal = memo(({ title, ...props }) => ( - - - - - - - - -)) +export const AdminLayoutPortal = memo(({ title, ...props }) => { + const location = useLocation() + + return ( + + + + + + + + + ) +}) export default AdminLayoutPortal diff --git a/src/components/LoaderPortal.tsx b/src/components/LoaderPortal.tsx index e6d1970..2357420 100644 --- a/src/components/LoaderPortal.tsx +++ b/src/components/LoaderPortal.tsx @@ -1,17 +1,18 @@ import { HTMLAttributes } from 'react' -import Loader from './Loader' +import { Loader } from '@components/icons' type LoaderPortalProps = HTMLAttributes & { show?: boolean, fade?: boolean, + spinnerProps?: HTMLAttributes, } -export const LoaderPortal: React.FC = ({ className, show, fade = true, children, ...other }) => ( +export const LoaderPortal: React.FC = ({ className, show, fade = true, children, spinnerProps, ...other }) => (
{children}
{show && fade &&
} - {show &&
} + {show &&
}
) diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx index 52f7658..12ab867 100644 --- a/src/components/PageHeader.tsx +++ b/src/components/PageHeader.tsx @@ -1,5 +1,5 @@ import { memo } from 'react' -import { Link } from 'react-router-dom' +import { Link, useLocation } from 'react-router-dom' import { Layout } from 'antd' import { BasicProps } from 'antd/lib/layout/layout' @@ -14,17 +14,21 @@ export type PageHeaderProps = BasicProps & { children?: React.ReactNode } -export const PageHeader: React.FC = memo(({ title = 'Мониторинг', isAdmin, children, ...other }) => ( - - - - - - {children} -

{title}

- -
-
-)) +export const PageHeader: React.FC = memo(({ title = 'Мониторинг', isAdmin, children, ...other }) => { + const location = useLocation() + + return ( + + + + + + {children} +

{title}

+ +
+
+ ) +}) export default PageHeader diff --git a/src/components/Poprompt.tsx b/src/components/Poprompt.tsx index 410e552..74f36b5 100644 --- a/src/components/Poprompt.tsx +++ b/src/components/Poprompt.tsx @@ -1,4 +1,4 @@ -import { memo, ReactNode, useState } from 'react' +import { memo, ReactNode, useCallback, useState } from 'react' import { Button, ButtonProps, Form, FormProps, Popover, PopoverProps } from 'antd' export type PopromptProps = PopoverProps & { @@ -13,10 +13,10 @@ export type PopromptProps = PopoverProps & { export const Poprompt = memo(({ formProps, buttonProps, footer, children, onDone, text, ...other }) => { const [visible, setVisible] = useState(false) - const onFormFinish = (values: any) => { + const onFormFinish = useCallback((values: any) => { setVisible(false) onDone?.(values) - } + }, [onDone]) return ( + children?: ReactElement } -export const PrivateContent: React.FC = ({ absolutePath, children = null }) => +export const PrivateContent = memo(({ absolutePath, children = null }) => isURLAvailable(absolutePath) ? children : null +) export default PrivateContent diff --git a/src/components/Private/PrivateDefaultRoute.tsx b/src/components/Private/PrivateDefaultRoute.tsx index 6e9ef08..0154875 100644 --- a/src/components/Private/PrivateDefaultRoute.tsx +++ b/src/components/Private/PrivateDefaultRoute.tsx @@ -1,5 +1,5 @@ import { memo } from 'react' -import { Redirect, Route, RouteProps } from 'react-router-dom' +import { Redirect, Route, RouteProps, useLocation } from 'react-router-dom' import { getUserId } from '@utils/storage' import { isURLAvailable } from '@utils/permissions' @@ -9,10 +9,17 @@ export type PrivateDefaultRouteProps = RouteProps & { elseRedirect?: string } -export const PrivateDefaultRoute = memo(({ elseRedirect, urls, ...other }) => ( - - isURLAvailable(url)) ?? elseRedirect ?? (getUserId() ? '/access_denied' : '/login') }} /> - -)) +export const PrivateDefaultRoute = memo(({ elseRedirect, urls, ...other }) => { + const location = useLocation() + + return ( + + isURLAvailable(url)) ?? elseRedirect ?? (getUserId() ? '/access_denied' : '/login'), + state: { from: location.pathname }, + }} /> + + ) +}) export default PrivateDefaultRoute diff --git a/src/components/Private/PrivateMenuItem.tsx b/src/components/Private/PrivateMenuItem.tsx index 16dd34b..fd48ee9 100644 --- a/src/components/Private/PrivateMenuItem.tsx +++ b/src/components/Private/PrivateMenuItem.tsx @@ -3,7 +3,7 @@ import { Menu, MenuItemProps } from 'antd' import { memo, NamedExoticComponent } from 'react' import { isURLAvailable } from '@utils/permissions' -import { Link } from 'react-router-dom' +import { Link, useLocation } from 'react-router-dom' export type PrivateMenuItemProps = MenuItemProps & { root: string @@ -16,11 +16,14 @@ export type PrivateMenuLinkProps = MenuItemProps & { title: string } -export const PrivateMenuItemLink = memo(({ root = '', path, title, ...other }) => ( - - {title} - -)) +export const PrivateMenuItemLink = memo(({ root = '', path, title, ...other }) => { + const location = useLocation() + return ( + + {title} + + ) +}) export const PrivateMenuItem: NamedExoticComponent & { Link: NamedExoticComponent diff --git a/src/components/Private/PrivateRoute.tsx b/src/components/Private/PrivateRoute.tsx index 366aaa4..901a0b6 100644 --- a/src/components/Private/PrivateRoute.tsx +++ b/src/components/Private/PrivateRoute.tsx @@ -14,7 +14,7 @@ export type PrivateRouteProps = RouteProps & { } export const defaultRedirect = (location?: Location) => ( - + ) export const PrivateRoute = memo(({ root = '', path, component, children, redirect = defaultRedirect, ...other }) => { diff --git a/src/components/Table/EditableCell.tsx b/src/components/Table/EditableCell.tsx index bd79b78..2cf2180 100644 --- a/src/components/Table/EditableCell.tsx +++ b/src/components/Table/EditableCell.tsx @@ -1,7 +1,8 @@ +import { memo } from 'react' import { Form, Input } from 'antd' import { NamePath, Rule } from 'rc-field-form/lib/interface' -type EditableCellProps = { +type EditableCellProps = React.DetailedHTMLProps, HTMLTableDataCellElement> & { editing?: boolean dataIndex?: NamePath input?: React.Component @@ -13,7 +14,7 @@ type EditableCellProps = { initialValue: any } -export const EditableCell = ({ +export const EditableCell = memo(({ editing, dataIndex, input, @@ -22,8 +23,9 @@ export const EditableCell = ({ formItemRules, children, initialValue, -}: EditableCellProps) => ( - + ...other +}) => ( + {!editing ? children : ( )} -) +)) diff --git a/src/components/Table/EditableTable.jsx b/src/components/Table/EditableTable.jsx index d12992c..510fe21 100644 --- a/src/components/Table/EditableTable.jsx +++ b/src/components/Table/EditableTable.jsx @@ -1,6 +1,6 @@ import { Form, Table, Button, Popconfirm } from 'antd' import { EditOutlined, SaveOutlined, PlusOutlined, CloseCircleOutlined, DeleteOutlined } from '@ant-design/icons' -import { useState, useEffect } from 'react' +import { useState, useEffect, memo, useCallback } from 'react' import { invokeWebApiWrapperAsync } from '@components/factory' @@ -42,7 +42,7 @@ export const tryAddKeys = (items) => { return items.map((item, index) => ({...item, key: item.key ?? item.id ?? index })) } -export const EditableTable = ({ +export const EditableTable = memo(({ columns, dataSource, onChange, // Метод вызывается со всем dataSource с измененными элементами после любого действия @@ -62,14 +62,14 @@ export const EditableTable = ({ setData(tryAddKeys(dataSource)) }, [dataSource]) - const isEditing = (record) => record?.key === editingKey + const isEditing = useCallback((record) => record?.key === editingKey, [editingKey]) - const edit = (record) => { + const edit = useCallback((record) => { form.setFieldsValue({...record}) setEditingKey(record.key) - } + }, [form]) - const cancel = () => { + const cancel = useCallback(() => { if (editingKey === newRowKeyValue) { const newData = [...data] const index = newData.findIndex((item) => newRowKeyValue === item.key) @@ -77,9 +77,9 @@ export const EditableTable = ({ setData(newData) } setEditingKey('') - } + }, [data, editingKey]) - const addNewRow = async () => { + const addNewRow = useCallback(async () => { let newRow = { ...form.initialValues, key:newRowKeyValue @@ -88,9 +88,9 @@ export const EditableTable = ({ const newData = [newRow, ...data] setData(newData) edit(newRow) - } + }, [data, edit, form.initialValues]) - const save = async (record) => { + const save = useCallback(async (record) => { try { const row = await form.validateFields() const newData = [...data] @@ -121,8 +121,7 @@ export const EditableTable = ({ } try { - if (onChange) - onChange(newData) + onChange?.(newData) } catch (err) { console.log('callback onChange fault:', err) } @@ -130,9 +129,9 @@ export const EditableTable = ({ } catch (errInfo) { console.log('Validate Failed:', errInfo) } - } + }, [data, editingKey, form, onChange, onRowAdd, onRowEdit]) - const deleteRow = (record) =>{ + const deleteRow = useCallback((record) => { const newData = [...data] const index = newData.findIndex((item) => record.key === item.key) @@ -140,10 +139,8 @@ export const EditableTable = ({ setData(newData) onRowDelete(record) - - if (onChange) - onChange(newData) - } + onChange?.(newData) + }, [data, onChange, onRowDelete]) const operationColumn = { width: buttonsWidth ?? 82, @@ -180,7 +177,7 @@ export const EditableTable = ({ ), } - const handleColumn = (col) => { + const handleColumn = useCallback((col) => { if (col.children) col.children = col.children.map(handleColumn) @@ -197,13 +194,13 @@ export const EditableTable = ({ input: col.input, isRequired: col.isRequired, title: col.title, - dataType: col.dataType, + datatype: col.datatype, formItemClass: col.formItemClass, formItemRules: col.formItemRules, initialValue: col.initialValue, }), } - } + }, [isEditing]) const mergedColumns = [...columns.map(handleColumn), operationColumn] @@ -221,4 +218,4 @@ export const EditableTable = ({ /> ) -} +}) diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index c263f33..d9c737e 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -1,7 +1,6 @@ import { memo, useEffect, useState, ReactNode } from 'react' import { InputNumber, Select, Table as RawTable, Tag, SelectProps, TableProps } from 'antd' -import { SelectValue } from 'antd/lib/select' -import { OptionsType } from 'rc-select/lib/interface' +import { DefaultOptionType, SelectValue } from 'antd/lib/select' import { Rule } from 'rc-field-form/lib/interface' import { tryAddKeys } from './EditableTable' @@ -210,7 +209,7 @@ export const makeNumericAvgRange = ( export const makeSelectColumn = ( title: string, dataIndex: string, - options: OptionsType, + options: DefaultOptionType[], defaultValue?: T, other?: columnPropsOther, selectOther?: SelectProps @@ -229,7 +228,7 @@ const makeTagInput = >(value_key: string, label_ke onChange?: (values: T[]) => void, other?: SelectProps, }>(({ options, value, onChange, other }) => { - const [selectOptions, setSelectOptions] = useState([]) + const [selectOptions, setSelectOptions] = useState([]) const [selectedValue, setSelectedValue] = useState([]) useEffect(() => { @@ -307,6 +306,6 @@ export type TableContainer = TableProps & { children?: ReactNode } -export const Table = ({dataSource, children, ...other}: TableContainer) => ( +export const Table = memo(({dataSource, children, ...other}) => ( {children} -) +)) diff --git a/src/components/Table/sorters.ts b/src/components/Table/sorters.ts index f29d7b6..5e60a3b 100644 --- a/src/components/Table/sorters.ts +++ b/src/components/Table/sorters.ts @@ -1,6 +1,8 @@ -export const makeNumericSorter = (key: string) => (a: any, b: any) => Number(a[key]) - Number(b[key]) +import { RawDate } from "@asb/utils" -export const makeStringSorter = (key: string) => (a: any, b: any) => { +export const makeNumericSorter = (key: string) => (a: Record, b: Record) => Number(a[key]) - Number(b[key]) + +export const makeStringSorter = (key: string) => (a: Record | null | undefined, b: Record | null | undefined) => { if (!a && !b) return 0 if (!a) return 1 if (!b) return -1 @@ -8,7 +10,7 @@ export const makeStringSorter = (key: string) => (a: any, b: any) => { return ('' + a[key]).localeCompare(b[key]) } -export const makeDateSorter = (key: string) => (a: any, b: any) => { +export const makeDateSorter = (key: string) => (a: Record, b: Record) => { const date = new Date(a[key]) if (Number.isNaN(date.getTime())) diff --git a/src/components/UploadForm.jsx b/src/components/UploadForm.jsx index 5add690..2d0f244 100644 --- a/src/components/UploadForm.jsx +++ b/src/components/UploadForm.jsx @@ -1,4 +1,4 @@ -import { memo, useState } from 'react' +import { memo, useCallback, useState } from 'react' import { Upload, Button } from 'antd' import { UploadOutlined } from '@ant-design/icons' @@ -8,7 +8,7 @@ import { ErrorFetch } from './ErrorFetch' export const UploadForm = memo(({ url, disabled, accept, style, formData, onUploadStart, onUploadSuccess, onUploadComplete, onUploadError }) => { const [fileList, setfileList] = useState([]) - const handleFileSend = async () => { + const handleFileSend = useCallback(async () => { onUploadStart?.() try { const formDataLocal = new FormData() @@ -34,7 +34,7 @@ export const UploadForm = memo(({ url, disabled, accept, style, formData, onUplo setfileList([]) onUploadComplete?.() } - } + }, [fileList, formData, onUploadComplete, onUploadError, onUploadStart, onUploadSuccess, url]) const isSendButtonEnabled = fileList.length > 0 return( diff --git a/src/components/UserMenu.tsx b/src/components/UserMenu.tsx index 4fd88ba..9227abc 100644 --- a/src/components/UserMenu.tsx +++ b/src/components/UserMenu.tsx @@ -1,5 +1,5 @@ -import { memo, MouseEventHandler, useState } from 'react' -import { Link, useHistory } from 'react-router-dom' +import { memo, MouseEventHandler, useCallback, useState } from 'react' +import { Link, useHistory, useLocation } from 'react-router-dom' import { Button, Dropdown, DropDownProps, Menu } from 'antd' import { UserOutlined } from '@ant-design/icons' @@ -14,16 +14,17 @@ export const UserMenu = memo(({ isAdmin, ...other }) => { const [isModalVisible, setIsModalVisible] = useState(false) const history = useHistory() + const location = useLocation() - const onChangePasswordClick: MouseEventHandler = (e) => { + const onChangePasswordClick: MouseEventHandler = useCallback((e) => { setIsModalVisible(true) e.preventDefault() - } + }, []) - const onChangePasswordOk = () => { + const onChangePasswordOk = useCallback(() => { setIsModalVisible(false) - history.push('/login') - } + history.push({ pathname: '/login', state: { from: location.pathname }}) + }, [history, location]) return ( <> @@ -33,15 +34,15 @@ export const UserMenu = memo(({ isAdmin, ...other }) => { overlay={( {isAdmin ? ( - + ) : ( - + )} Сменить пароль - Выход + Выход )} diff --git a/src/components/WellTreeSelector.tsx b/src/components/WellTreeSelector.tsx index 8c8bb9f..15f96f2 100644 --- a/src/components/WellTreeSelector.tsx +++ b/src/components/WellTreeSelector.tsx @@ -1,7 +1,10 @@ import { TreeSelect } from 'antd' import { DefaultValueType } from 'rc-tree-select/lib/interface' -import { useState, useEffect, ReactNode } from 'react' -import { useHistory, useRouteMatch } from 'react-router-dom' +import { useState, useEffect, ReactNode, useCallback, memo } from 'react' +import { useHistory, useLocation, useRouteMatch } from 'react-router-dom' + +import { RawValueType } from 'rc-tree-select/lib/TreeSelect' +import { LabelInValueType } from 'rc-select/lib/Select' import { isRawDate } from '@utils' import LoaderPortal from './LoaderPortal' @@ -54,11 +57,12 @@ const getLabel = (wellsTree: TreeNodeData[], value?: string): string | undefined return value } -export const WellTreeSelector = () => { - const [wellsTree, setWellsTree] = useState([]) // TODO: Исправить тип (необходимо разобраться с типом value rc-select) +export const WellTreeSelector = memo(({ ...other }) => { + const [wellsTree, setWellsTree] = useState([]) const [showLoader, setShowLoader] = useState(false) const [value, setValue] = useState() const history = useHistory() + const location = useLocation() const routeMatch = useRouteMatch('/:route/:id') useEffect(() => { @@ -100,14 +104,15 @@ export const WellTreeSelector = () => { setValue(getLabel(wellsTree, routeMatch?.url)) }, [wellsTree, routeMatch]) - const onChange = (value: string): void => { + const onChange = useCallback((value: string): void => { if (wellsTree) setValue(getLabel(wellsTree, value)) - } + }, [wellsTree]) - const onSelect = (value: string): void => { - if (value) history.push(value) - } + const onSelect = useCallback((value: RawValueType | LabelInValueType): void => { + if (['number', 'string'].includes(typeof value)) + history.push({ pathname: String(value), state: { from: location.pathname }}) + }, [history, location]) return ( @@ -123,9 +128,10 @@ export const WellTreeSelector = () => { onChange={onChange} value={value} style={{ width: '350px' }} + {...other} /> ) -} +}) export default WellTreeSelector diff --git a/src/components/Loader.tsx b/src/components/icons/Loader.tsx similarity index 100% rename from src/components/Loader.tsx rename to src/components/icons/Loader.tsx diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index b290f4a..fe5c856 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -3,3 +3,4 @@ export type { WellIconColors, WellIconProps, WellIconState } from './WellIcon' export { PointerIcon } from './PointerIcon' export { WellIcon } from './WellIcon' +export { Loader } from './Loader' diff --git a/src/components/views/MarkView.tsx b/src/components/views/MarkView.tsx deleted file mode 100644 index f7eb4fa..0000000 --- a/src/components/views/MarkView.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Tooltip, Tag, Typography, Popconfirm, Button } from 'antd' -import { memo } from 'react' - -import { FileMarkDto } from '@api' -import { UserView } from './UserView' - -const markTypes: { [id: number]: {color: string, text: string} } = { - 0: {color: 'orange', text: 'неизвестно'}, - 1: {color: 'green', text: 'согласовано'}, -} - -const { Text } = Typography - -export type MarkViewProps = { - mark: FileMarkDto - onDelete?: (e?: React.MouseEvent) => void -} - -export const MarkView = memo(({ mark, onDelete }) => { - const markType = markTypes[mark.idMarkType ?? 0] ?? markTypes[0] - return }> - - - {`${markType.text} ${new Date(mark.dateCreated ?? 0).toLocaleString()}`} - - {!mark?.isDeleted && ( - - - - )} - - -}) diff --git a/src/components/views/RoleView.tsx b/src/components/views/RoleView.tsx index 60e5452..8974419 100644 --- a/src/components/views/RoleView.tsx +++ b/src/components/views/RoleView.tsx @@ -10,10 +10,12 @@ export type RoleViewProps = { } export const RoleView = memo(({ role }) => { + if (!role) return ( - ) + const hasIncludedRoles = (role?.roles?.length && role.roles.length > 0) ? 1 : 0 const hasPermissions = (role?.permissions?.length && role.permissions.length > 0) ? 1 : 0 - return role ? ( + return ( (({ role }) => { > {role.caption} - ) : ( - - ) }) diff --git a/src/components/views/index.ts b/src/components/views/index.ts index 51dae3a..b535f0e 100644 --- a/src/components/views/index.ts +++ b/src/components/views/index.ts @@ -1,13 +1,11 @@ export type { PermissionViewProps } from './PermissionView' export type { TelemetryViewProps } from './TelemetryView' export type { CompanyViewProps } from './CompanyView' -export type { MarkViewProps } from './MarkView' export type { RoleViewProps } from './RoleView' export type { UserViewProps } from './UserView' export { PermissionView } from './PermissionView' export { TelemetryView, getTelemetryLabel } from './TelemetryView' export { CompanyView } from './CompanyView' -export { MarkView } from './MarkView' export { RoleView } from './RoleView' export { UserView } from './UserView' \ No newline at end of file diff --git a/src/index.js b/src/index.js index 0dda601..6542cdd 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,17 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './styles/index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from 'react' +import ReactDOM from 'react-dom' +import App from './App' +import reportWebVitals from './reportWebVitals' -ReactDOM.render( +import '@styles/index.css' + +ReactDOM.render(( - , - document.getElementById('root') -); + +), document.getElementById('root')) // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); +reportWebVitals() diff --git a/src/pages/Cluster/ClusterWells.jsx b/src/pages/Cluster/ClusterWells.jsx index 4fa191a..c11dd59 100644 --- a/src/pages/Cluster/ClusterWells.jsx +++ b/src/pages/Cluster/ClusterWells.jsx @@ -1,5 +1,5 @@ -import { Link } from 'react-router-dom' -import { useState, useEffect } from 'react' +import { Link, useLocation } from 'react-router-dom' +import { useState, useEffect, memo } from 'react' import { Tag, Button, Modal } from 'antd' import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons' @@ -35,7 +35,9 @@ const filtersWellsType = [] const DAY_IN_MS = 86_400_000 const ONLINE_DEADTIME = 600_000 -export const ClusterWells = ({ statsWells }) => { +const getDate = (str) => isRawDate(str) ? new Date(str).toLocaleString() : '-' + +export const ClusterWells = memo(({ statsWells }) => { const [selectedWellId, setSelectedWellId] = useState(0) const [isTVDModalVisible, setIsTVDModalVisible] = useState(false) const [isOpsModalVisible, setIsOpsModalVisible] = useState(false) @@ -43,6 +45,8 @@ export const ClusterWells = ({ statsWells }) => { const [tableData, setTableData] = useState([]) const [showLoader, setShowLoader] = useState(false) + const location = useLocation() + useEffect(() => { if (!isOpsModalVisible || selectedWellId <= 0) { setWellOperations([]) @@ -104,12 +108,10 @@ export const ClusterWells = ({ statsWells }) => { setTableData(data) }, [statsWells]) - const getDate = (str) => isRawDate(str) ? new Date(str).toLocaleString() : '-' - const columns = [ makeTextColumn('скв №', 'caption', null, null, (_, item) => ( - + { ) -} +}) export default ClusterWells diff --git a/src/pages/Deposit.jsx b/src/pages/Deposit.jsx index 5ca30af..0218aca 100644 --- a/src/pages/Deposit.jsx +++ b/src/pages/Deposit.jsx @@ -1,5 +1,5 @@ import { Map, Overlay } from 'pigeon-maps' -import { Link } from 'react-router-dom' +import { Link, useLocation } from 'react-router-dom' import { useState, useEffect, memo } from 'react' import { ClusterService } from '@api' @@ -41,6 +41,8 @@ export const Deposit = memo(() => { const [showLoader, setShowLoader] = useState(false) const [viewParams, setViewParams] = useState(defaultViewParams) + const location = useLocation() + useEffect(() => invokeWebApiWrapperAsync( async () => { const data = await ClusterService.getClusters() @@ -62,7 +64,7 @@ export const Deposit = memo(() => { anchor={[cluster.latitude, cluster.longitude]} key={`${cluster.latitude} ${cluster.longitude}`} > - + {cluster.caption} diff --git a/src/pages/DrillingProgram/index.jsx b/src/pages/DrillingProgram/index.jsx index 9f4a6d1..ebc0f3c 100644 --- a/src/pages/DrillingProgram/index.jsx +++ b/src/pages/DrillingProgram/index.jsx @@ -1,4 +1,4 @@ -import { Button, Layout, Menu } from 'antd' +import { Button, Layout } from 'antd' import { CheckOutlined, CloseOutlined, diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index cdb27b4..0f30f3b 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,13 +1,13 @@ -import { memo, useState } from 'react' -import { Link, useHistory } from 'react-router-dom' +import { memo, useCallback, useState } from 'react' +import { Link, useHistory, useLocation } from 'react-router-dom' import { Card, Form, Input, Button } from 'antd' import { UserOutlined, LockOutlined } from '@ant-design/icons' -import { AuthService } from '@api' -import { setUser } from '@utils/storage' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { loginRules, passwordRules } from '@utils/validationRules' +import { setUser } from '@utils/storage' +import { AuthService } from '@api' import '@styles/index.css' import Logo from '@images/Logo' @@ -16,19 +16,21 @@ const logoIcon = export const Login = memo(() => { const history = useHistory() + const location = useLocation() const [showLoader, setShowLoader] = useState(false) - const handleLogin = (formData) => invokeWebApiWrapperAsync( + const handleLogin = useCallback((formData) => invokeWebApiWrapperAsync( async () => { const user = await AuthService.login(formData) if (!user) throw Error('Неправильный логин или пароль') setUser(user) - history.push('well') + console.log(location.state?.from) + history.push(location.state?.from ?? 'well') }, setShowLoader, (ex) => ex?.message ?? 'Ошибка входа', 'Вход в систему' - ) + ), [history, location]) return ( diff --git a/src/pages/Register.jsx b/src/pages/Register.jsx index 34ae670..c5c17fd 100644 --- a/src/pages/Register.jsx +++ b/src/pages/Register.jsx @@ -1,4 +1,4 @@ -import { memo, useState } from 'react' +import { memo, useCallback, useState } from 'react' import { Link, useHistory } from 'react-router-dom' import { Card, Form, Input, Button } from 'antd' import { @@ -54,7 +54,7 @@ export const Register = memo(() => { const [showLoader, setShowLoader] = useState(false) const history = useHistory() - const handleRegister = (formData) => invokeWebApiWrapperAsync( + const handleRegister = useCallback((formData) => invokeWebApiWrapperAsync( async () => { await AuthService.register(formData) history.push('/login') @@ -62,7 +62,7 @@ export const Register = memo(() => { setShowLoader, `Ошибка отправки заявки на регистрацию`, 'Отправка заявки на регистрацию' - ) + ), [history]) return ( diff --git a/src/pages/WellCompositeEditor/WellCompositeSections.jsx b/src/pages/WellCompositeEditor/WellCompositeSections.jsx index 141d0ce..1004f4c 100644 --- a/src/pages/WellCompositeEditor/WellCompositeSections.jsx +++ b/src/pages/WellCompositeEditor/WellCompositeSections.jsx @@ -1,5 +1,5 @@ -import { Link } from 'react-router-dom' -import { useState, useEffect, memo } from 'react' +import { Link, useLocation } from 'react-router-dom' +import { useState, useEffect, memo, useCallback } from 'react' import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons' import { Table, Tag, Button, Badge, Divider, Modal, Row, Col, Popconfirm } from 'antd' @@ -42,6 +42,8 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection const [isOpsModalVisible, setIsOpsModalVisible] = useState(false) const [isParamsModalVisible, setIsParamsModalVisible] = useState(false) + const location = useLocation() + useEffect(() => (async() => setParamsColumns(await getColumns(idWell)))(), [idWell]) useEffect(() => { @@ -125,7 +127,7 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection const columns = [ makeTextColumn('скв №', 'caption', null, null, - (text, item) => {text ?? '-'} + (text, item) => {text ?? '-'} ), makeTextColumn('Секция', 'sectionType', filtersSectionsType, null, (text) => text ?? '-'), makeNumericColumnPlanFact('Глубина, м', 'sectionWellDepth', filtersMinMax, makeFilterMinMaxFunction), @@ -187,7 +189,7 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection ) } - const onParamButtonClick = () => invokeWebApiWrapperAsync( + const onParamButtonClick = useCallback(() => invokeWebApiWrapperAsync( async () => { setIsParamsModalVisible(true) const params = await DrillParamsService.getCompositeAll(idWell) @@ -196,9 +198,9 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection setShowParamsLoader, `Не удалось загрузить список режимов для скважины "${idWell}"`, 'Получение списка режимов скважины' - ) + ), [idWell]) - const onParamsAddClick = () => invokeWebApiWrapperAsync( + const onParamsAddClick = useCallback(() => invokeWebApiWrapperAsync( async () => { await DrillParamsService.save(idWell, params) setIsParamsModalVisible(false) @@ -206,7 +208,7 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection setShowLoader, `Не удалось добавить режимы в список скважины "${idWell}"`, 'Добавление режима скважины' - ) + ), [idWell, params]) return ( <> diff --git a/src/pages/WellOperations/index.jsx b/src/pages/WellOperations/index.jsx index 5bfd6fb..082d138 100644 --- a/src/pages/WellOperations/index.jsx +++ b/src/pages/WellOperations/index.jsx @@ -1,6 +1,6 @@ -import { memo } from 'react' +import { memo, useCallback } from 'react' import { Layout, Menu } from 'antd' -import { Switch, useParams, useHistory } from 'react-router-dom' +import { Switch, useParams, useHistory, useLocation } from 'react-router-dom' import { BarChartOutlined, BuildOutlined, @@ -23,9 +23,12 @@ const { Content } = Layout export const WellOperations = memo(({ idWell }) => { const { tab } = useParams() const history = useHistory() + const location = useLocation() const rootPath = `/well/${idWell}/operations` - const onImported = () => history.push(`${rootPath}`) + const onImported = useCallback(() => + history.push({ pathname: `${rootPath}`, state: { from: location.pathname }}) + , [history, location, rootPath]) const isIEBarDisabled = !['plan', 'fact'].includes(tab) diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js index 5253d3a..7d10e17 100644 --- a/src/reportWebVitals.js +++ b/src/reportWebVitals.js @@ -1,13 +1,13 @@ -const reportWebVitals = onPerfEntry => { +export const reportWebVitals = onPerfEntry => { if (onPerfEntry && onPerfEntry instanceof Function) { import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); + getCLS(onPerfEntry) + getFID(onPerfEntry) + getFCP(onPerfEntry) + getLCP(onPerfEntry) + getTTFB(onPerfEntry) + }) } -}; +} -export default reportWebVitals; +export default reportWebVitals