From 33183e250de18cb1304216de16aa42f8301c77db 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: Sun, 18 Feb 2024 21:33:40 +0500 Subject: [PATCH] reg teble(delete edit) --- src/assets/theme.ts | 11 +- src/components/UI/contextMenu/ContextMenu.tsx | 66 ++++++ src/components/UI/input/Checkbox.tsx | 35 +++ src/components/UI/input/MainInput.tsx | 4 +- src/components/UI/input/SearchInput.tsx | 42 ++++ src/components/UI/loader/Loader.tsx | 2 +- src/components/UI/modal/Modal.tsx | 14 +- src/components/UI/table/Table.tsx | 38 ++++ .../UI/table/pagination/Pagination.tsx | 90 ++++++++ src/components/layout/Layout.tsx | 14 +- src/constants/host.ts | 2 +- src/images/arrow.svg | 3 + src/images/edit.svg | 3 + src/images/menu.svg | 5 + src/images/minus.svg | 3 + src/images/off.svg | 9 + src/images/ok.svg | 3 + src/images/on.svg | 9 + src/images/params.svg | 3 + src/images/play.svg | 10 + src/images/search.svg | 3 + src/images/stop.svg | 13 ++ src/images/trash.svg | 11 + src/pages/Login.tsx | 2 +- src/pages/Registrations/Registrations.tsx | 150 ++++++++++--- .../Registrations/blocks/EditRegModal.tsx | 99 ++++++++ src/pages/Registrations/blocks/NewRegForm.tsx | 38 ---- .../Registrations/blocks/NewRegModal.tsx | 101 +++++++++ src/pages/Registrations/blocks/RegTable.tsx | 122 ++++++++++ .../Registrations/blocks/RegTableItem.tsx | 211 ++++++++++++++++++ src/pages/Registrations/types.ts | 23 +- src/services/Registrations.ts | 15 -- src/services/registrationsServices.ts | 67 ++++++ src/services/{User.ts => userSrvices.ts} | 0 34 files changed, 1118 insertions(+), 103 deletions(-) create mode 100644 src/components/UI/contextMenu/ContextMenu.tsx create mode 100644 src/components/UI/input/Checkbox.tsx create mode 100644 src/components/UI/input/SearchInput.tsx create mode 100644 src/components/UI/table/Table.tsx create mode 100644 src/components/UI/table/pagination/Pagination.tsx create mode 100644 src/images/arrow.svg create mode 100644 src/images/edit.svg create mode 100644 src/images/menu.svg create mode 100644 src/images/minus.svg create mode 100644 src/images/off.svg create mode 100644 src/images/ok.svg create mode 100644 src/images/on.svg create mode 100644 src/images/params.svg create mode 100644 src/images/play.svg create mode 100644 src/images/search.svg create mode 100644 src/images/stop.svg create mode 100644 src/images/trash.svg create mode 100644 src/pages/Registrations/blocks/EditRegModal.tsx delete mode 100644 src/pages/Registrations/blocks/NewRegForm.tsx create mode 100644 src/pages/Registrations/blocks/NewRegModal.tsx create mode 100644 src/pages/Registrations/blocks/RegTable.tsx create mode 100644 src/pages/Registrations/blocks/RegTableItem.tsx delete mode 100644 src/services/Registrations.ts create mode 100644 src/services/registrationsServices.ts rename src/services/{User.ts => userSrvices.ts} (100%) diff --git a/src/assets/theme.ts b/src/assets/theme.ts index 7b1d308..e987fc2 100644 --- a/src/assets/theme.ts +++ b/src/assets/theme.ts @@ -4,7 +4,7 @@ export const theme = { secondary: '#003333', bg: '#F5F5F5', textColor: '#292929', - focusColor: '#EDEDED 50%', + focusColor: '#EDEDED', // typography h1: ` @@ -12,11 +12,11 @@ export const theme = { font-size: 36px; `, h2: ` - font-weight: 500; + font-weight: 600; font-size: 24px; `, h3: ` - font-weight: 500; + font-weight: 600; font-size: 18px; `, paragraph: ` @@ -27,5 +27,8 @@ export const theme = { // shadows mainShadow: ` box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); - ` + `, + innerShadow: ` + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1) inset; +` } diff --git a/src/components/UI/contextMenu/ContextMenu.tsx b/src/components/UI/contextMenu/ContextMenu.tsx new file mode 100644 index 0000000..8226801 --- /dev/null +++ b/src/components/UI/contextMenu/ContextMenu.tsx @@ -0,0 +1,66 @@ +import React, { useEffect, useRef } from 'react' +import styled, { css } from 'styled-components' + +type Props = { + active: boolean + children: React.ReactNode + setActive: (param: boolean) => void +} + +interface I_Active { + active: boolean +} + +const Container = styled.div` + position: relative; + + .target { + cursor: pointer; + } + + .content { + z-index: 1; + position: absolute; + top: 30px; + right: 0; + padding: 15px; + background: ${(props) => props.theme.bg}; + ${(props) => props.theme.mainShadow} + border-radius: 12px; + width: 200px; + flex-direction: column; + gap: 20px; + + ${(props) => + props.active + ? css` + display: flex; + ` + : css` + display: none; + `} + } +` + +export default function ContextMenu({ active, children, setActive }: Props) { + const menuRef = useRef(null) + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (menuRef.current && !menuRef.current.contains(event.target as Node)) { + setActive(false) + } + } + + document.addEventListener('mousedown', handleClickOutside) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, []) + + return ( + + {children} + + ) +} diff --git a/src/components/UI/input/Checkbox.tsx b/src/components/UI/input/Checkbox.tsx new file mode 100644 index 0000000..d4a18b3 --- /dev/null +++ b/src/components/UI/input/Checkbox.tsx @@ -0,0 +1,35 @@ +import styled, { css } from 'styled-components' + +type Props = { + value: 'off' | 'ok' | 'minus' + onClick: () => void +} + +type ContainerProps = { + value: string +} + +const Container = styled.div` +cursor: pointer; + width: 20px; + height: 20px; + border-radius: 6px; + border: 1px solid ${(props) => props.theme.textColor}; + display: flex; + align-items: center; + justify-content: center; + ${(props) => + (props.value === 'ok' || props.value === 'minus') && + css` + background: ${(props) => props.theme.textColor}; + `} +` + +export default function Checkbox({ value, onClick }: Props) { + return ( + + {value === 'ok' && } + {value === 'minus' && } + + ) +} diff --git a/src/components/UI/input/MainInput.tsx b/src/components/UI/input/MainInput.tsx index 3b256b0..77330a8 100644 --- a/src/components/UI/input/MainInput.tsx +++ b/src/components/UI/input/MainInput.tsx @@ -28,7 +28,7 @@ const Placeholder = styled.label` cursor: text; position: absolute; top: ${(props) => (props.showPlaceholder ? '30%' : '-20%')}; - left: ${(props) => (props.showPlaceholder ? '25px' : '0px')}; + left: ${(props) => (props.showPlaceholder ? '22px' : '0px')}; border-radius: 5px; transform: translateY(-50%); transform: scale(${(props) => (props.showPlaceholder ? '1' : '0.85')}); @@ -38,7 +38,7 @@ const Placeholder = styled.label` ` type Props = { - value: string + value: string | number onChange: (e: React.ChangeEvent) => void placeholder: string type?: string diff --git a/src/components/UI/input/SearchInput.tsx b/src/components/UI/input/SearchInput.tsx new file mode 100644 index 0000000..1c117b3 --- /dev/null +++ b/src/components/UI/input/SearchInput.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import styled from 'styled-components' + +type Props = { + value: string + onChange: (e: React.ChangeEvent) => void + placeholder: string +} + +const InputContainer = styled.div` + width: 100%; + display: flex; + + input { + width: 100%; + ${props => props.theme.innerShadow} + padding: 15px 25px; + border-radius: 12px; + outline: none; + border: none; + background: ${props => props.theme.bg}; + ${props => props.theme.paragraph} + } + + img { + margin-left: -45px; + } +` + +export default function SearchInput({ value, onChange, placeholder }: Props) { + return ( + + + + + ) +} diff --git a/src/components/UI/loader/Loader.tsx b/src/components/UI/loader/Loader.tsx index 42d8132..820d197 100644 --- a/src/components/UI/loader/Loader.tsx +++ b/src/components/UI/loader/Loader.tsx @@ -45,7 +45,7 @@ export const LoaderModal = styled.div` width: 100px; height: 100px; display: flex; - background: var(--color-main); + background: ${props => props.theme.bg}; justify-content: center; align-items: center; border-radius: 15px; diff --git a/src/components/UI/modal/Modal.tsx b/src/components/UI/modal/Modal.tsx index 502bada..5c48723 100644 --- a/src/components/UI/modal/Modal.tsx +++ b/src/components/UI/modal/Modal.tsx @@ -13,9 +13,18 @@ interface modalContainer { const Container = styled.div` - ${props => props.modal ? css`display: block;` : css`display: none;`} - .bg { + ${(props) => + props.modal + ? css` + display: block; + ` + : css` + display: none; + `} + + .bg { + z-index: 1; position: fixed; bottom: 0px; left: 0; @@ -26,6 +35,7 @@ const Container = styled.div` } .content { + z-index: 2; position: fixed; padding: 20px; border-radius: 12px; diff --git a/src/components/UI/table/Table.tsx b/src/components/UI/table/Table.tsx new file mode 100644 index 0000000..770239c --- /dev/null +++ b/src/components/UI/table/Table.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import styled from 'styled-components' + +type Props = { + children: React.ReactNode +} + +const TableContainer = styled.table` + padding: 10px; + ${(props) => props.theme.mainShadow} + border-radius: 12px; + width: 100%; + + table { + background: ${(props) => props.theme.bg}; + border-collapse: collapse; + width: 100%; + } + + td, + th { + border-bottom: 1px solid ${(props) => props.theme.text}; + padding: 10px; + text-align: left; + } + + tr:last-child td { + border-bottom: none; + } +` + +export default function Table({ children }: Props) { + return ( + + {children}
+
+ ) +} diff --git a/src/components/UI/table/pagination/Pagination.tsx b/src/components/UI/table/pagination/Pagination.tsx new file mode 100644 index 0000000..f69c677 --- /dev/null +++ b/src/components/UI/table/pagination/Pagination.tsx @@ -0,0 +1,90 @@ +import styled, { css } from 'styled-components' + +type Props = { + pageNumber: number + pageCount: number + setPageNumber: (param: number) => void +} + +interface I_Active { + active: boolean +} + +const Container = styled.div` + display: flex; + gap: 8px; +` + +const Button = styled.div` + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border-radius: 6px; + width: 32px; + height: 32px; + + ${(props) => + props.active + ? css` + border: 1px solid #919eab; + ` + : css` + cursor: default; + background: #919eab; + `} + + &:last-of-type { + transform: rotate(180deg); + } +` + +const Item = styled.div` + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border-radius: 6px; + width: 32px; + height: 32px; + + ${(props) => + props.active + ? css` + border: 1px solid ${(props) => props.theme.primary}; + color: ${(props) => props.theme.primary}; + ` + : css` + border: 1px solid #919eab; + `} +` + +export default function Pagination({ + pageNumber, + pageCount, + setPageNumber +}: Props) { + return ( + + + + 1 + + + 2 + + ... + + {pageCount - 1} + + + {pageCount} + + + + ) +} diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index 151352e..de809e0 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -18,13 +18,13 @@ export default function Layout({ children }: Props) { const currentPath = location.pathname const navigate = useNavigate() - useEffect(() => { - const hasCookie = document.cookie.includes('_identid') - if (!hasCookie) { - navigate('/login') - return - } - }, []) + // useEffect(() => { + // const hasCookie = document.cookie.includes('_identid') + // if (!hasCookie) { + // navigate('/login') + // return + // } + // }, []) useEffect(() => { if (currentPath === '/') { navigate('/registrations') diff --git a/src/constants/host.ts b/src/constants/host.ts index 91f1966..7f62f37 100644 --- a/src/constants/host.ts +++ b/src/constants/host.ts @@ -1 +1 @@ -export const HOST_NAME = 'http://127.0.0.1:8070/api/v1' \ No newline at end of file +export const HOST_NAME = 'http://localhost:8070/api/v1' \ No newline at end of file diff --git a/src/images/arrow.svg b/src/images/arrow.svg new file mode 100644 index 0000000..af8f9af --- /dev/null +++ b/src/images/arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/edit.svg b/src/images/edit.svg new file mode 100644 index 0000000..2bdc817 --- /dev/null +++ b/src/images/edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/menu.svg b/src/images/menu.svg new file mode 100644 index 0000000..7778048 --- /dev/null +++ b/src/images/menu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/minus.svg b/src/images/minus.svg new file mode 100644 index 0000000..c402ac9 --- /dev/null +++ b/src/images/minus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/off.svg b/src/images/off.svg new file mode 100644 index 0000000..c747e5b --- /dev/null +++ b/src/images/off.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/images/ok.svg b/src/images/ok.svg new file mode 100644 index 0000000..d46525d --- /dev/null +++ b/src/images/ok.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/on.svg b/src/images/on.svg new file mode 100644 index 0000000..66f1be8 --- /dev/null +++ b/src/images/on.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/images/params.svg b/src/images/params.svg new file mode 100644 index 0000000..3b5d81c --- /dev/null +++ b/src/images/params.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/play.svg b/src/images/play.svg new file mode 100644 index 0000000..f7dbf4d --- /dev/null +++ b/src/images/play.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/images/search.svg b/src/images/search.svg new file mode 100644 index 0000000..ddf366a --- /dev/null +++ b/src/images/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/stop.svg b/src/images/stop.svg new file mode 100644 index 0000000..48c97a5 --- /dev/null +++ b/src/images/stop.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/images/trash.svg b/src/images/trash.svg new file mode 100644 index 0000000..f215030 --- /dev/null +++ b/src/images/trash.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index c84f974..42ade44 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom' import MainButton from 'src/components/UI/button/MainButton' import MainInput from 'src/components/UI/input/MainInput' import Loader from 'src/components/UI/loader/Loader' -import UserService from 'src/services/User' +import UserService from 'src/services/userSrvices' import styled from 'styled-components' type Props = {} diff --git a/src/pages/Registrations/Registrations.tsx b/src/pages/Registrations/Registrations.tsx index ce4f31b..5326b72 100644 --- a/src/pages/Registrations/Registrations.tsx +++ b/src/pages/Registrations/Registrations.tsx @@ -1,13 +1,30 @@ import { useEffect, useState } from 'react' import MainButton from 'src/components/UI/button/MainButton' -import Modal from 'src/components/UI/modal/Modal' -import RegistrationsService from 'src/services/Registrations' +import SearchInput from 'src/components/UI/input/SearchInput' +import Pagination from 'src/components/UI/table/pagination/Pagination' +import RegistrationsService from 'src/services/registrationsServices' import styled from 'styled-components' -import NewRegForm from './blocks/NewRegForm' -import { T_NewRegistration } from './types' +import NewRegModal from './blocks/NewRegModal' +import RegTable from './blocks/RegTable' +import { T_ColumnsState, T_NewRegistration, T_RegistrationItem } from './types' type Props = {} +const Container = styled.div` + display: flex; + flex-direction: column; + gap: 20px; + align-items: start; + padding: 40px 20px; + + .bottom-menu { + display: flex; + align-items: start; + width: 100%; + justify-content: space-between; + } +` + const Notification = styled.div` position: absolute; top: 50%; @@ -19,20 +36,58 @@ const Notification = styled.div` align-items: center; ` -const ModalContainer = styled.div` +const SelectNotification = styled.div` display: flex; - flex-direction: column; - gap: 20px; - width: 440px; + width: 100%; + justify-content: space-between; + align-items: center; + padding: 10px 20px; + ${(props) => props.theme.mainShadow} + border-radius: 12px; - .buttonBlock { - display: flex; - gap: 20px; + img { + padding: 5px; + cursor: pointer; + border-radius: 6px; + transition: 300ms; + + &:hover { + background: ${(props) => props.theme.focusColor}; + transform: scale(1.1); + } } ` export default function Registrations({}: Props) { - const [registrations, setRegistrations] = useState([]) + const [pageCount, setPageCount] = useState(10) + const [pageNumber, setPageNumber] = useState(1) + + const [registrations, setRegistrations] = useState([]) + const [searchQuery, setSearchQuery] = useState('') + + const handleSearchQueryChange = (e: React.ChangeEvent) => { + setSearchQuery(e.target.value) + } + + const [activeColumns, setActiveColumns] = useState({ + RegNum: { name: 'Номер поставки', status: true }, + ContNum: { name: 'Номер контракта', status: true }, + Email: { name: 'Эл. почта', status: false }, + Count: { name: 'Кол-во активаций', status: false }, + EndDate: { name: 'Дата окончания', status: false }, + CreatedDate: { name: 'Дата создания', status: true }, + UpdatedDate: { name: 'Дата изменения', status: true }, + Enabled: { name: 'Статус', status: true } + }) + + const [checkedColumns, setCheckedColumns] = useState([]) + const [selectAll, setSelectAll] = useState(false) + const [notChecked, setNotChecked] = useState([]) + + useEffect(() => { + notChecked.length === registrations.length && + (setSelectAll(false), setNotChecked([])) + }, [notChecked]) const [newReg, setNewReg] = useState({ RegNum: '', @@ -44,6 +99,10 @@ export default function Registrations({}: Props) { const [modal, setModal] = useState(false) + useEffect(() => { + console.log(registrations) + }, [registrations]) + useEffect(() => { setNewReg({ RegNum: '', @@ -63,11 +122,10 @@ export default function Registrations({}: Props) { useEffect(() => { getReg() - console.log(registrations) }, []) return ( -
+ {registrations.length === 0 ? (

Активных лицензий нет

@@ -76,23 +134,53 @@ export default function Registrations({}: Props) {
) : ( - <> - )} - - - -
- setModal(false)} - > - Отмена - - Создать + <> +

Система управления и контроля ОСГОС

+ + {(selectAll || checkedColumns.length !== 0) && ( + +

+ {selectAll + ? 'Количесво не определено' + : checkedColumns.length !== 0 && + `Выбранно: ${checkedColumns.length}`} +

+ +
+ )} + +
+ + setModal(true)}>Добавить
- - -
+ + )} + +
) } diff --git a/src/pages/Registrations/blocks/EditRegModal.tsx b/src/pages/Registrations/blocks/EditRegModal.tsx new file mode 100644 index 0000000..5e5d3f4 --- /dev/null +++ b/src/pages/Registrations/blocks/EditRegModal.tsx @@ -0,0 +1,99 @@ +import { useEffect, 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 styled from 'styled-components' +import { T_NewRegistration } from '../types' + +type Props = { + modal: boolean + setModal: (param: boolean) => void + registration: T_NewRegistration + editReg: (param: T_NewRegistration) => void +} + +const ModalContainer = styled.div` + display: flex; + flex-direction: column; + gap: 20px; + width: 440px; + + .buttonBlock { + display: flex; + gap: 20px; + } +` + +export default function EditRegModal({ + modal, + setModal, + registration, + editReg +}: Props) { + const [editRegData, setEditRegData] = useState(registration) + + const handleContNumChange = (e: React.ChangeEvent) => { + setEditRegData({ ...registration, ContNum: e.target.value }) + } + const handleRegNumChange = (e: React.ChangeEvent) => { + setEditRegData({ ...registration, RegNum: e.target.value }) + } + const handleEmailChange = (e: React.ChangeEvent) => { + setEditRegData({ ...registration, Email: e.target.value }) + } + const handleCountChange = (e: React.ChangeEvent) => { + setEditRegData({ ...registration, Count: e.target.value }) + } + const handleEndDateChange = (e: React.ChangeEvent) => { + setEditRegData({ ...registration, EndDate: e.target.value }) + } + + useEffect(() => { + console.log(editRegData) + }, []) + + return ( + + + + + + + +
+ setModal(false)} + > + Отмена + + editReg(editRegData)}> + Сохранить + +
+
+
+ ) +} diff --git a/src/pages/Registrations/blocks/NewRegForm.tsx b/src/pages/Registrations/blocks/NewRegForm.tsx deleted file mode 100644 index ae6f56a..0000000 --- a/src/pages/Registrations/blocks/NewRegForm.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react' -import { T_NewRegistration } from '../types' -import MainInput from 'src/components/UI/input/MainInput' - -type Props = { - newReg: T_NewRegistration - setNewReg: (param: T_NewRegistration) => void -} - -export default function NewRegForm({newReg, setNewReg}: Props) { - - const handleContNumChange = (e: React.ChangeEvent) => { - setNewReg({ ...newReg, ContNum: e.target.value }) - } - const handleRegNumChange = (e: React.ChangeEvent) => { - setNewReg({ ...newReg, RegNum: e.target.value }) - } - const handleEmailChange = (e: React.ChangeEvent) => { - setNewReg({ ...newReg, Email: e.target.value }) - } - const handleCountChange = (e: React.ChangeEvent) => { - setNewReg({ ...newReg, Count: e.target.value }) - } - const handleEndDateChange = (e: React.ChangeEvent) => { - setNewReg({ ...newReg, EndDate: e.target.value }) - } - - - return ( - <> - - - - - - - ) -} \ No newline at end of file diff --git a/src/pages/Registrations/blocks/NewRegModal.tsx b/src/pages/Registrations/blocks/NewRegModal.tsx new file mode 100644 index 0000000..57e95ad --- /dev/null +++ b/src/pages/Registrations/blocks/NewRegModal.tsx @@ -0,0 +1,101 @@ +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 RegistrationsService from 'src/services/registrationsServices' +import styled from 'styled-components' +import { T_NewRegistration } from '../types' + +const ModalContainer = styled.div` + display: flex; + flex-direction: column; + gap: 20px; + width: 440px; + + .buttonBlock { + display: flex; + gap: 20px; + } +` + +type Props = { + modal: boolean + setModal: (param: boolean) => void + newReg: T_NewRegistration + setNewReg: (param: T_NewRegistration) => void + getReg: () => void +} + +export default function NewRegModal({ + modal, + setModal, + newReg, + setNewReg, + getReg +}: Props) { + const CreateReg = async () => { + await RegistrationsService.createRegistration(newReg) + getReg() + setModal(false) + } + + const handleContNumChange = (e: React.ChangeEvent) => { + setNewReg({ ...newReg, ContNum: e.target.value }) + } + const handleRegNumChange = (e: React.ChangeEvent) => { + setNewReg({ ...newReg, RegNum: e.target.value }) + } + const handleEmailChange = (e: React.ChangeEvent) => { + setNewReg({ ...newReg, Email: e.target.value }) + } + const handleCountChange = (e: React.ChangeEvent) => { + setNewReg({ ...newReg, Count: e.target.value }) + } + const handleEndDateChange = (e: React.ChangeEvent) => { + setNewReg({ ...newReg, EndDate: e.target.value }) + } + + return ( + + + + + + + +
+ setModal(false)} + > + Отмена + + + Создать + +
+
+
+ ) +} diff --git a/src/pages/Registrations/blocks/RegTable.tsx b/src/pages/Registrations/blocks/RegTable.tsx new file mode 100644 index 0000000..b845213 --- /dev/null +++ b/src/pages/Registrations/blocks/RegTable.tsx @@ -0,0 +1,122 @@ +import { useEffect, useRef, useState } from 'react' +import Checkbox from 'src/components/UI/input/Checkbox' +import Table from 'src/components/UI/table/Table' +import styled, { css } from 'styled-components' +import { T_ColumnsState, T_RegistrationItem } from '../types' +import RegTableItem from './RegTableItem' +import ContextMenu from 'src/components/UI/contextMenu/ContextMenu' + +const Item = styled.div` + display: flex; + gap: 10px; + cursor: pointer; +` + +type Props = { + selectAll: boolean + notChecked: number[] + setNotChecked: (param: any) => void + setSelectAll: (param: any) => void + checkedColumns: number[] + setCheckedColumns: (param: any) => void + activeColumns: T_ColumnsState + setActiveColumns: (param: any) => void + registrations: T_RegistrationItem[] + getReg: () => void +} + +export default function RegTable({ + selectAll, + notChecked, + setNotChecked, + setSelectAll, + checkedColumns, + setCheckedColumns, + activeColumns, + setActiveColumns, + registrations, + getReg +}: Props) { + const [contextMenuState, setContextMenuState] = useState(false) + + + + return ( + + + + + {Object.entries(activeColumns).map( + ([index, item]) => + item.status === true && + )} + + + + + {registrations.map((registration) => ( + + ))} + +
+ { + selectAll + ? (setSelectAll(false), + setNotChecked([]), + setCheckedColumns([])) + : checkedColumns.length === 0 + ? (setSelectAll(true), setNotChecked([])) + : setCheckedColumns([]) + }} + /> + {item.name} + +
+ setContextMenuState(!contextMenuState)} + /> +
+
+ {Object.entries(activeColumns).map(([key, item]) => ( + { + const updatedActiveColumns = { ...activeColumns } + updatedActiveColumns[key].status = + !updatedActiveColumns[key].status + setActiveColumns(updatedActiveColumns) + }} + > + {}} + /> +

{item.name}

+
+ ))} +
+
+
+ ) +} diff --git a/src/pages/Registrations/blocks/RegTableItem.tsx b/src/pages/Registrations/blocks/RegTableItem.tsx new file mode 100644 index 0000000..234f59e --- /dev/null +++ b/src/pages/Registrations/blocks/RegTableItem.tsx @@ -0,0 +1,211 @@ +import { useState } from 'react' +import MainButton from 'src/components/UI/button/MainButton' +import ContextMenu from 'src/components/UI/contextMenu/ContextMenu' +import Checkbox from 'src/components/UI/input/Checkbox' +import Modal from 'src/components/UI/modal/Modal' +import RegistrationsService from 'src/services/registrationsServices' +import styled from 'styled-components' +import { T_ColumnsState, T_NewRegistration, T_RegistrationItem } from '../types' +import EditRegModal from './EditRegModal' + +type Props = { + registration: T_RegistrationItem + selectAll: boolean + notChecked: number[] + checkedColumns: number[] + setNotChecked: (param: any) => void + setCheckedColumns: (param: any) => void + activeColumns: T_ColumnsState + getReg: () => void +} + +const Item = styled.div` + display: flex; + gap: 10px; + cursor: pointer; +` + +const DeleteNotification = styled.div` + .button-container { + display: flex; + gap: 20px; + margin-top: 20px; + } +` + +export default function ({ + registration, + selectAll, + notChecked, + checkedColumns, + setNotChecked, + setCheckedColumns, + activeColumns, + getReg +}: Props) { + const [contextMenuState, setContextMenuState] = useState(false) + const [deleteNotificationState, setDeleteNotificationState] = useState(false) + const [editModalState, setEditModalState] = useState(false) + + const deleteReg = async () => { + setContextMenuState(false) + const response = await RegistrationsService.deleteRegistration( + registration.Id + ) + if (response.status === 200) { + getReg() + } + setDeleteNotificationState(false) + } + + const onReg = async () => { + setContextMenuState(false) + const response = await RegistrationsService.onRegistration(registration.Id) + if (response.status === 200) { + getReg() + } + } + + const offReg = async () => { + setContextMenuState(false) + const response = await RegistrationsService.offRegistration(registration.Id) + if (response.status === 200) { + getReg() + } + } + + const editReg = async (reg: T_NewRegistration) => { + setContextMenuState(false) + const response = await RegistrationsService.editRegistration( + registration.Id, + reg + ) + if (response.status === 200) { + getReg() + } + setEditModalState(false) + } + + return ( + <> + + + { + selectAll + ? notChecked.includes(registration.Id) + ? setNotChecked( + notChecked.filter((item) => item !== registration.Id) + ) + : setNotChecked([...notChecked, registration.Id]) + : checkedColumns.includes(registration.Id) + ? (setCheckedColumns( + checkedColumns.filter((item) => item !== registration.Id) + ), + setNotChecked([...notChecked, registration.Id])) + : setCheckedColumns([...checkedColumns, registration.Id]) + }} + /> + + {Object.entries(activeColumns).map(([key, item]) => + activeColumns[key as keyof typeof activeColumns].status ? ( + +

+ {' '} + {key === 'Enabled' ? ( + registration[key as keyof typeof registration] ? ( + + ) : ( + + ) + ) : ( + registration[key as keyof typeof registration] + )} +

+ + ) : null + )} + + +
+ setContextMenuState(!contextMenuState)} + /> +
+
+ { + setEditModalState(true) + setContextMenuState(false) + }} + > + +

Редактировать

+
+ { + setContextMenuState(false) + setDeleteNotificationState(true) + }} + > + +

Удалить

+
+ {registration.Enabled ? ( + + +

Выключить

+
+ ) : ( + + +

Включить

+
+ )} +
+
+ + + +

Вы действительно хотите удалить лицензию?

+
+ setDeleteNotificationState(false)} + > + Отмена + + deleteReg()}> + Удалить + +
+
+
+ + + + ) +} diff --git a/src/pages/Registrations/types.ts b/src/pages/Registrations/types.ts index 4d4b640..5a5a78e 100644 --- a/src/pages/Registrations/types.ts +++ b/src/pages/Registrations/types.ts @@ -2,6 +2,27 @@ export type T_NewRegistration = { RegNum: string ContNum: string Email: string - Count: string + Count: string | number EndDate: string } + +export interface T_RegistrationItem { + Id: number; + RegNum: string; + ContNum: string; + Email: string; + Count: number; + EndDate: string; + CreatedDate: string; + UpdatedDate: string; + Enabled: boolean; +} + +export type T_Column = { + name: string + status: boolean +} + +export type T_ColumnsState = { + [key: string]: T_Column +} diff --git a/src/services/Registrations.ts b/src/services/Registrations.ts deleted file mode 100644 index 7cb95f6..0000000 --- a/src/services/Registrations.ts +++ /dev/null @@ -1,15 +0,0 @@ -import axios, { AxiosResponse } from 'axios' -import { HOST_NAME } from 'src/constants/host' - -export default class RegistrationsService { - static async getRegistration(): Promise { - try { - const response = await axios.get(`${HOST_NAME}/regs`, { - withCredentials: true - }) - return response - } catch (error: any) { - return error.response - } - } -} diff --git a/src/services/registrationsServices.ts b/src/services/registrationsServices.ts new file mode 100644 index 0000000..6400ea3 --- /dev/null +++ b/src/services/registrationsServices.ts @@ -0,0 +1,67 @@ +import axios, { AxiosResponse } from 'axios' +import { HOST_NAME } from 'src/constants/host' +import { T_NewRegistration } from 'src/pages/Registrations/types' + +export default class RegistrationsService { + static async getRegistration(): Promise { + try { + const response = await axios.get(`${HOST_NAME}/regs`) + return response + } catch (error: any) { + return error.response + } + } + + static async createRegistration( + newReg: T_NewRegistration + ): Promise { + const date = new Date(newReg.EndDate) + const isoDateStr = date.toISOString() + newReg.EndDate = isoDateStr + if (typeof newReg.Count === 'string') { + newReg.Count = parseInt(newReg.Count, 10) + } + try { + const response = await axios.post(`${HOST_NAME}/regs`, newReg) + return response + } catch (error: any) { + return error.response + } + } + + static async deleteRegistration(id: number): Promise { + try { + const response = await axios.delete(`${HOST_NAME}/regs/${id}`) + return response + } catch (error: any) { + return error.response + } + } + + static async onRegistration(id: number): Promise { + try { + const response = await axios.post(`${HOST_NAME}/regs/${id}/state/enable`) + return response + } catch (error: any) { + return error.response + } + } + + static async offRegistration(id: number): Promise { + try { + const response = await axios.post(`${HOST_NAME}/regs/${id}/state/disable`) + return response + } catch (error: any) { + return error.response + } + } + + static async editRegistration(id: number, reg: T_NewRegistration): Promise { + try { + const response = await axios.post(`${HOST_NAME}/regs/${id}`, reg) + return response + } catch (error: any) { + return error.response + } + } +} diff --git a/src/services/User.ts b/src/services/userSrvices.ts similarity index 100% rename from src/services/User.ts rename to src/services/userSrvices.ts