From 7c247316aeed72b01e4ca01899e95dc9e637b25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=B8=D0=BE=D1=81=D0=B8=D1=84=20=D0=B1=D1=80=D1=8B=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 29 Feb 2024 02:29:28 +0500 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D1=81=D0=B5=20=D0=B1=D0=B0=D0=B3=D0=B8=20=D0=B8?= =?UTF-8?q?=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=B2=20=D1=80=D0=B5?= =?UTF-8?q?=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=B8=20+=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B4=D0=BE=D1=82=D0=BA=D1=83=20=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B2=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20+=20=D0=BF=D0=B0=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=D0=B0=20=D0=B2=20=D1=81=D1=81=D1=8B?= =?UTF-8?q?=D0=BB=D0=BA=D0=B0=D1=85=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D1=8E=D1=82=20=D0=BD=D0=B0=20=D0=B2=D1=81=D0=B5=D1=85=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/globalStyles.ts | 20 +- src/components/UI/input/Textarea.tsx | 9 +- src/pages/Registrations/Registrations.tsx | 53 ++++- .../Registrations/blocks/EditRegModal.tsx | 146 ++++++++----- src/pages/Registrations/blocks/RegTable.tsx | 74 +++++-- .../Registrations/blocks/RegTableItem.tsx | 16 +- src/pages/Repository/Repository.tsx | 44 +++- src/pages/Repository/blocks/EditRepModal.tsx | 198 ++++++++++-------- src/pages/Repository/blocks/NewRepModal.tsx | 70 ++++--- src/pages/Repository/blocks/RepTable.tsx | 71 +++++-- src/pages/Repository/blocks/RepTableItem.tsx | 100 ++++----- src/pages/Store/Store.tsx | 2 +- src/services/repositoryServices.ts | 49 +++-- 13 files changed, 535 insertions(+), 317 deletions(-) diff --git a/src/assets/globalStyles.ts b/src/assets/globalStyles.ts index ea05c62..eedd7ef 100644 --- a/src/assets/globalStyles.ts +++ b/src/assets/globalStyles.ts @@ -6,35 +6,33 @@ export const GlobalStyles = createGlobalStyle` padding: 0; box-sizing: border-box; } - + body { font-family: "Roboto"; - color: ${props => props.theme.textColor}; - background: ${props => props.theme.bg}; + color: ${(props) => props.theme.textColor}; + background: ${(props) => props.theme.bg}; position: relative; min-height: 100vh; } a { text-decoration: none; - color: ${props => props.theme.textColor}; + color: ${(props) => props.theme.textColor}; } h1 { - ${props => props.theme.h1} + ${(props) => props.theme.h1} } - h2 { - ${props => props.theme.h2} + ${(props) => props.theme.h2} } - h3 { - ${props => props.theme.h3} + ${(props) => props.theme.h3} } p { - ${props => props.theme.paragraph} + ${(props) => props.theme.paragraph} } -` \ No newline at end of file +` diff --git a/src/components/UI/input/Textarea.tsx b/src/components/UI/input/Textarea.tsx index 9efbb1b..9a6725b 100644 --- a/src/components/UI/input/Textarea.tsx +++ b/src/components/UI/input/Textarea.tsx @@ -9,15 +9,16 @@ const TextareaContainer = styled.div` border-radius: 12px; background: ${(props) => props.theme.bg}; border: 1px solid ${(props) => props.theme.text}; - font-size: 18px; - font-weight: 500; outline: none; resize: none; height: 110px; width: 100%; overflow: -moz-scrollbars-none; - scrollbar-width: none; - } + scrollbar-width: none; + font-family: Roboto; + font-size: 18px; + font-weight: 400; +} ` interface PlaceholderProps { diff --git a/src/pages/Registrations/Registrations.tsx b/src/pages/Registrations/Registrations.tsx index a2542dd..1ae3b69 100644 --- a/src/pages/Registrations/Registrations.tsx +++ b/src/pages/Registrations/Registrations.tsx @@ -15,6 +15,7 @@ import { SearchNotification } from './styles' import { T_ColumnsState, T_NewRegistration, T_RegistrationItem } from './types' +import { useLocation, useNavigate } from 'react-router-dom' type Props = {} @@ -26,17 +27,36 @@ export default function Registrations({}: Props) { const [registrations, setRegistrations] = useState([]) - const handleSearchQueryChange = (e: React.ChangeEvent) => { - setQueryParams({ ...queryParams, search: e.target.value }) - } + const location = useLocation() + const searchParams = new URLSearchParams(location.search) + const navigate = useNavigate() const [queryParams, setQueryParams] = useState({ page: 1, count: 10, search: '', - order: undefined + order: 'email' }) + const handleSearchQueryChange = (e: React.ChangeEvent) => { + const newSearchQuery = e.target.value + setQueryParams({ ...queryParams, search: e.target.value, page: 1 }) + const searchParams = new URLSearchParams(window.location.search) + if (searchParams.has('page')) { + searchParams.delete('page') + } + searchParams.append('page', '1') + if (searchParams.has('search')) { + searchParams.delete('search') + } + if (newSearchQuery.trim() !== '') { + searchParams.append('search', newSearchQuery.trim()) + } + navigate(`?${searchParams.toString()}`) + } + + + const getReg = async () => { setSearchNotification(false) setErrorState(false) @@ -54,6 +74,21 @@ export default function Registrations({}: Props) { setLoadingState(false) } + useEffect(() => { + const pageParam = searchParams.get('page') + const countParam = searchParams.get('count') + const searchParam = searchParams.get('search') + const orderParam = searchParams.get('order') + setQueryParams((prevState) => ({ + ...prevState, + page: pageParam ? parseInt(pageParam, 10) : prevState.page, + count: countParam ? parseInt(countParam, 10) : prevState.count, + search: searchParam || prevState.search, + order: orderParam || prevState.order + })) + getReg() + }, []) + useEffect(() => { getReg() }, [queryParams]) @@ -66,7 +101,7 @@ export default function Registrations({}: Props) { EndDate: { name: 'Дата окончания', status: true }, CreatedDate: { name: 'Дата создания', status: false }, UpdatedDate: { name: 'Дата изменения', status: true }, - Enabled: { name: 'Статус', status: true } + Enabled: { name: 'Состояние', status: true } }) const [checkedColumns, setCheckedColumns] = useState([]) @@ -127,10 +162,6 @@ export default function Registrations({}: Props) { }) }, [modal]) - useEffect(() => { - getReg() - }, []) - return ( <> {loadingState ? ( @@ -167,9 +198,9 @@ export default function Registrations({}: Props) {

{selectAll - ? `Выбранно: ${totalCount - notChecked.length}` + ? `Выбрано: ${totalCount - notChecked.length}` : checkedColumns.length !== 0 && - `Выбранно: ${checkedColumns.length}`} + `Выбрано: ${checkedColumns.length}`}

void - registration: T_NewRegistration - editReg: (param: T_NewRegistration) => void + registration: T_RegistrationItem + getReg: () => void } const ModalContainer = styled.div` @@ -24,16 +25,45 @@ const ModalContainer = styled.div` } ` +const ErrorContainer = styled.div` + position: relative; + z-index: 4; + + .content { + display: flex; + flex-direction: column; + align-items: end; + width:420px; + gap: 20px; + } +` + export default function EditRegModal({ modal, setModal, registration, - editReg + getReg }: Props) { const [editRegData, setEditRegData] = useState(registration) const [errorMessage, setErrorMessage] = useState(false) + const editReg = async () => { + try { + const response = await RegistrationsService.editRegistration( + registration.Id, + editRegData + ) + if (response.status === 200) { + getReg() + setModal(false) + } else if (response.status === 406) { + console.log(1) + setErrorMessage(true) + } + } catch (error) {} + } + const handleContNumChange = (e: React.ChangeEvent) => { setEditRegData({ ...editRegData, ContNum: e.target.value }) } @@ -44,12 +74,24 @@ export default function EditRegModal({ setEditRegData({ ...editRegData, Email: e.target.value }) } const handleCountChange = (e: React.ChangeEvent) => { - setEditRegData({ ...editRegData, Count: e.target.value }) + setEditRegData({ ...editRegData, Count: parseInt(e.target.value) }) } const handleEndDateChange = (e: React.ChangeEvent) => { setEditRegData({ ...editRegData, EndDate: e.target.value }) } + useEffect(() => { + function formatDate(isoDateString: string): string { + const date = new Date(isoDateString) + const year = date.getFullYear() + const month = ('0' + (date.getMonth() + 1)).slice(-2) + const day = ('0' + date.getDate()).slice(-2) + return `${year}-${month}-${day}` + } + const formattedDate = formatDate(registration.EndDate) + setEditRegData({ ...registration, EndDate: formattedDate }) + }, [modal]) + useEffect(() => { function formatDate(isoDateString: string): string { const date = new Date(isoDateString) @@ -63,47 +105,57 @@ export default function EditRegModal({ }, []) return ( - - - - - - - -
- setModal(false)} - > - Отмена - - editReg(editRegData)}> - Сохранить - -
-
-
+ <> + + + + + + + +
+ setModal(false)} + > + Отмена + + + Сохранить + +
+
+
+ + +
+

Номер контракта/поставки уже существует

+ setErrorMessage(false)}>Ok +
+
+
+ ) } diff --git a/src/pages/Registrations/blocks/RegTable.tsx b/src/pages/Registrations/blocks/RegTable.tsx index 5dfa50c..151b884 100644 --- a/src/pages/Registrations/blocks/RegTable.tsx +++ b/src/pages/Registrations/blocks/RegTable.tsx @@ -1,4 +1,5 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' +import { useNavigate } from 'react-router-dom' import ContextMenu from 'src/components/UI/contextMenu/ContextMenu' import Checkbox from 'src/components/UI/input/Checkbox' import Table from 'src/components/UI/table/Table' @@ -71,28 +72,65 @@ export default function RegTable({ }: Props) { const [contextMenuState, setContextMenuState] = useState(false) - const [activeSort, setActiveSort] = useState('') + const navigate = useNavigate() + + const [activeSort, setActiveSort] = useState('email') const [sortState, setSortState] = useState(false) const sort = (value: string) => { - const sortOptions: { [key: string]: string } = { - 'Номер поставки': 'reg', - 'Номер контракта': 'cont', - 'Эл. почта': 'email', - 'Кол-во активаций': 'count', - 'Дата окончания': 'end', - 'Дата изменения': 'updated', - 'Статус': 'enabled' - }; + const sortOptions: { [key: string]: string } = { + 'Номер поставки': 'reg', + 'Номер контракта': 'cont', + 'Эл. почта': 'email', + 'Кол-во активаций': 'count', + 'Дата окончания': 'end', + 'Дата изменения': 'updated', + Состояние: 'enabled' + } - const sortParam = sortOptions[value]; - if (!sortParam) return; + const sortParam = sortOptions[value] + if (!sortParam) return - setActiveSort(value); - const newOrder = queryParams.order === sortParam ? `!${sortParam}` : sortParam; - setQueryParams({ ...queryParams, order: newOrder }); - setSortState(queryParams.order === sortParam); -}; + setActiveSort(value) + const newOrder = + queryParams.order === sortParam ? `!${sortParam}` : sortParam + setQueryParams({ ...queryParams, order: newOrder }) + setSortState(queryParams.order === sortParam) + + const searchParams = new URLSearchParams(window.location.search) + if (searchParams.has('order')) { + searchParams.delete('order') + } + if (newOrder.trim() !== '') { + searchParams.append('order', newOrder.trim()) + } + navigate(`?${searchParams.toString()}`) + } + + useEffect(() => { + const searchParams = new URLSearchParams(location.search) + const orderParam = searchParams.get('order') + + // Проверяем наличие параметра order в URL + if (orderParam) { + const sortOptions: { [key: string]: string } = { + reg: 'Номер поставки', + cont: 'Номер контракта', + email: 'Эл. почта', + count: 'Кол-во активаций', + end: 'Дата окончания', + updated: 'Дата изменения', + enabled: 'Состояние', + } + + const activeSortValue = sortOptions[orderParam.replace('!', '')] + const sortStateValue = orderParam[0] === '!' + + setActiveSort(activeSortValue || '') + setSortState(sortStateValue) + + } + }, []) return ( diff --git a/src/pages/Registrations/blocks/RegTableItem.tsx b/src/pages/Registrations/blocks/RegTableItem.tsx index 90cb50a..03303fd 100644 --- a/src/pages/Registrations/blocks/RegTableItem.tsx +++ b/src/pages/Registrations/blocks/RegTableItem.tsx @@ -74,17 +74,7 @@ export default function RrgTableItem ({ } } - const editReg = async (reg: T_NewRegistration) => { - setContextMenuState(false) - const response = await RegistrationsService.editRegistration( - registration.Id, - reg - ) - if (response.status === 200) { - getReg() - } - setEditModalState(false) - } + return ( <> @@ -116,7 +106,7 @@ export default function RrgTableItem ({ }} /> - {Object.entries(activeColumns).map(([key, item]) => + {Object.entries(activeColumns).map(([key, _]) => activeColumns[key as keyof typeof activeColumns].status ? ( diff --git a/src/pages/Repository/Repository.tsx b/src/pages/Repository/Repository.tsx index 7856b72..8fad704 100644 --- a/src/pages/Repository/Repository.tsx +++ b/src/pages/Repository/Repository.tsx @@ -16,6 +16,7 @@ import { SearchNotification } from './styles' import { T_ColumnsState, T_RepositoryItem } from './types' +import { useLocation, useNavigate } from 'react-router-dom' type Props = {} @@ -29,9 +30,9 @@ export default function Repository({}: Props) { const [Repository, setRepository] = useState([]) - const handleSearchQueryChange = (e: React.ChangeEvent) => { - setQueryParams({ ...queryParams, search: e.target.value }) - } + const location = useLocation() + const searchParams = new URLSearchParams(location.search) + const navigate = useNavigate() const [queryParams, setQueryParams] = useState({ page: 1, @@ -40,6 +41,23 @@ export default function Repository({}: Props) { order: undefined }) + const handleSearchQueryChange = (e: React.ChangeEvent) => { + const newSearchQuery = e.target.value + setQueryParams({ ...queryParams, search: e.target.value, page: 1 }) + const searchParams = new URLSearchParams(window.location.search) + if (searchParams.has('page')) { + searchParams.delete('page') + } + searchParams.append('page', '1') + if (searchParams.has('search')) { + searchParams.delete('search') + } + if (newSearchQuery.trim() !== '') { + searchParams.append('search', newSearchQuery.trim()) + } + navigate(`?${searchParams.toString()}`) + } + const getRep = async () => { if (!firstLoadingState) setLoadingState(true) setErrorState(false) @@ -59,7 +77,19 @@ export default function Repository({}: Props) { setLoadingState(false) setFirstLoadingState(false) } + useEffect(() => { + const pageParam = searchParams.get('page') + const countParam = searchParams.get('count') + const searchParam = searchParams.get('search') + const orderParam = searchParams.get('order') + setQueryParams((prevState) => ({ + ...prevState, + page: pageParam ? parseInt(pageParam, 10) : prevState.page, + count: countParam ? parseInt(countParam, 10) : prevState.count, + search: searchParam || prevState.search, + order: orderParam || prevState.order + })) getRep() }, []) @@ -73,8 +103,8 @@ export default function Repository({}: Props) { Description: { name: 'Полное описание', status: true }, ShortDescription: { name: 'Краткое описание', status: true }, Category: { name: 'Категория', status: true }, - UpdatedDate: { name: 'Дата изменения', status: true }, - Enabled: { name: 'Статус', status: true } + UpdatedDate: { name: 'Дата обновления', status: true }, + Enabled: { name: 'Состояние', status: true } }) const [checkedColumns, setCheckedColumns] = useState([]) @@ -122,7 +152,7 @@ export default function Repository({}: Props) { return ( <> - {loadingState ? ( + {firstLoadingState ? ( @@ -190,6 +220,7 @@ export default function Repository({}: Props) { getRep={getRep} queryParams={queryParams} setQueryParams={setQueryParams} + loadingState={loadingState} />
)} - )} diff --git a/src/pages/Repository/blocks/EditRepModal.tsx b/src/pages/Repository/blocks/EditRepModal.tsx index 5f0afdf..52b9291 100644 --- a/src/pages/Repository/blocks/EditRepModal.tsx +++ b/src/pages/Repository/blocks/EditRepModal.tsx @@ -1,8 +1,8 @@ import { useEffect, useRef, useState } from 'react' import MainButton from 'src/components/UI/button/MainButton' import MainInput from 'src/components/UI/input/MainInput' -import Modal from 'src/components/UI/modal/Modal' import Textarea from 'src/components/UI/input/Textarea' +import Modal from 'src/components/UI/modal/Modal' import RepositoryService from 'src/services/repositoryServices' import styled from 'styled-components' import { T_NewRepository, T_RepositoryItem } from '../types' @@ -52,7 +52,12 @@ const NewRepFileBlock = styled.div` font-weight: 600; } ` -export default function EditRepModal({ modal, setModal, repository, getRep }: Props){ +export default function EditRepModal({ + modal, + setModal, + repository, + getRep +}: Props) { const [error, setError] = useState({ state: false, message: '' @@ -75,10 +80,14 @@ export default function EditRepModal({ modal, setModal, repository, getRep }: Pr const handleNameChange = (e: React.ChangeEvent) => { setEditRepData({ ...editRepData, Name: e.target.value }) } - const handleDescriptionChange = (e: React.ChangeEvent) => { + const handleDescriptionChange = ( + e: React.ChangeEvent + ) => { setEditRepData({ ...editRepData, Description: e.target.value }) } - const handleShortDescriptionChange = (e: React.ChangeEvent) => { + const handleShortDescriptionChange = ( + e: React.ChangeEvent + ) => { setEditRepData({ ...editRepData, ShortDescription: e.target.value }) } const handleVersionChange = (e: React.ChangeEvent) => { @@ -93,15 +102,26 @@ export default function EditRepModal({ modal, setModal, repository, getRep }: Pr useEffect(() => { setFormValid( editRepData.Name !== '' && - editRepData.Description !== '' && - editRepData.ShortDescription !== '' && - editRepData.Version !== '' && - editRepData.Category !== '' + editRepData.Description !== '' && + editRepData.ShortDescription !== '' && + editRepData.Version !== '' && + editRepData.Category !== '' ) }, [editRepData]) - const fileInputRef = useRef(null); - const [selectedFile, setSelectedFile] = useState(null); - + + useEffect(() => { + setEditRepData({ + Name: repository.Name, + Description: repository.Description, + ShortDescription: repository.ShortDescription, + Version: repository.Version, + Category: repository.Category + }) + }, [modal]) + + const fileInputRef = useRef(null) + const [selectedFile, setSelectedFile] = useState(null) + const handleFileChange = () => { const file = fileInputRef.current?.files?.[0] if (file) { @@ -114,70 +134,75 @@ export default function EditRepModal({ modal, setModal, repository, getRep }: Pr } const updateRep = async () => { setLoading(true) - try { - if ( - !( - editRepData.Category === repository.Category && - editRepData.Description === repository.Description && - editRepData.Name === repository.Name && - editRepData.ShortDescription === repository.ShortDescription && - editRepData.Version === repository.Version - ) - ) { - const response = await RepositoryService.editRepository(repository.Id, editRepData) - if (response.status === 406) { - setError({ state: true, message: response.data }) - setLoading(false) - return - } + try { + if ( + !( + editRepData.Category === repository.Category && + editRepData.Description === repository.Description && + editRepData.Name === repository.Name && + editRepData.ShortDescription === repository.ShortDescription && + editRepData.Version === repository.Version + ) + ) { + const response = await RepositoryService.editRepository( + repository.Id, + editRepData + ) + if (response.status === 406) { + setError({ state: true, message: response.data }) + setLoading(false) + return } - - if (repository.Url !== selectedFile && selectedFile instanceof File) { - const response = await RepositoryService.addFile(selectedFile, repository.Id) - if (response.status === 406) { - setError({ state: true, message: response.data }) - setLoading(false) - return - } + } + + if (repository.Url !== selectedFile && selectedFile instanceof File) { + const response = await RepositoryService.addFile( + selectedFile, + repository.Id + ) + if (response.status === 406) { + setError({ state: true, message: response.data }) + setLoading(false) + return } - setLoading(false) - setModal(false) - getRep() - } catch (error) {} - } - + } + setLoading(false) + setModal(false) + getRep() + } catch (error) {} + } + return ( <> - - - -

Изменение пакета в репозитории

- - - -

@@ -203,7 +193,7 @@ export default function RrgTableItem ({ modal={editModalState} setModal={setEditModalState} registration={registration} - editReg={editReg} + getReg={getReg} />