reg teble(delete edit)
|
@ -4,7 +4,7 @@ export const theme = {
|
||||||
secondary: '#003333',
|
secondary: '#003333',
|
||||||
bg: '#F5F5F5',
|
bg: '#F5F5F5',
|
||||||
textColor: '#292929',
|
textColor: '#292929',
|
||||||
focusColor: '#EDEDED 50%',
|
focusColor: '#EDEDED',
|
||||||
|
|
||||||
// typography
|
// typography
|
||||||
h1: `
|
h1: `
|
||||||
|
@ -12,11 +12,11 @@ export const theme = {
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
`,
|
`,
|
||||||
h2: `
|
h2: `
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
`,
|
`,
|
||||||
h3: `
|
h3: `
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
`,
|
`,
|
||||||
paragraph: `
|
paragraph: `
|
||||||
|
@ -27,5 +27,8 @@ export const theme = {
|
||||||
// shadows
|
// shadows
|
||||||
mainShadow: `
|
mainShadow: `
|
||||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
|
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
|
||||||
`
|
`,
|
||||||
|
innerShadow: `
|
||||||
|
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1) inset;
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<I_Active>`
|
||||||
|
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<HTMLDivElement>(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 (
|
||||||
|
<Container active={active} ref={menuRef}>
|
||||||
|
{children}
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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<ContainerProps>`
|
||||||
|
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 (
|
||||||
|
<Container onClick={onClick} value={value}>
|
||||||
|
{value === 'ok' && <img src='/src/images/ok.svg' />}
|
||||||
|
{value === 'minus' && <img src='/src/images/minus.svg' />}
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ const Placeholder = styled.label<PlaceholderProps>`
|
||||||
cursor: text;
|
cursor: text;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: ${(props) => (props.showPlaceholder ? '30%' : '-20%')};
|
top: ${(props) => (props.showPlaceholder ? '30%' : '-20%')};
|
||||||
left: ${(props) => (props.showPlaceholder ? '25px' : '0px')};
|
left: ${(props) => (props.showPlaceholder ? '22px' : '0px')};
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
transform: scale(${(props) => (props.showPlaceholder ? '1' : '0.85')});
|
transform: scale(${(props) => (props.showPlaceholder ? '1' : '0.85')});
|
||||||
|
@ -38,7 +38,7 @@ const Placeholder = styled.label<PlaceholderProps>`
|
||||||
`
|
`
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: string
|
value: string | number
|
||||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
placeholder: string
|
placeholder: string
|
||||||
type?: string
|
type?: string
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import React from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: string
|
||||||
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => 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 (
|
||||||
|
<InputContainer>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
placeholder={placeholder}
|
||||||
|
/>
|
||||||
|
<img src='/src/images/search.svg' alt='' />
|
||||||
|
</InputContainer>
|
||||||
|
)
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ export const LoaderModal = styled.div`
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
display: flex;
|
display: flex;
|
||||||
background: var(--color-main);
|
background: ${props => props.theme.bg};
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
|
|
|
@ -13,9 +13,18 @@ interface modalContainer {
|
||||||
|
|
||||||
const Container = styled.div<modalContainer>`
|
const Container = styled.div<modalContainer>`
|
||||||
|
|
||||||
${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;
|
position: fixed;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -26,6 +35,7 @@ const Container = styled.div<modalContainer>`
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
z-index: 2;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
|
@ -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 (
|
||||||
|
<TableContainer>
|
||||||
|
<table>{children}</table>
|
||||||
|
</TableContainer>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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<I_Active>`
|
||||||
|
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<I_Active>`
|
||||||
|
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 (
|
||||||
|
<Container>
|
||||||
|
<Button active={false}>
|
||||||
|
<img src='/src/images/arrow.svg' alt='' />
|
||||||
|
</Button>
|
||||||
|
<Item active={true}>
|
||||||
|
1
|
||||||
|
</Item>
|
||||||
|
<Item active={false}>
|
||||||
|
2
|
||||||
|
</Item>
|
||||||
|
<Item active={false}>...</Item>
|
||||||
|
<Item active={false}>
|
||||||
|
{pageCount - 1}
|
||||||
|
</Item>
|
||||||
|
<Item active={false}>
|
||||||
|
{pageCount}
|
||||||
|
</Item>
|
||||||
|
<Button active={true}>
|
||||||
|
<img src='/src/images/arrow.svg' alt='' />
|
||||||
|
</Button>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
|
@ -18,13 +18,13 @@ export default function Layout({ children }: Props) {
|
||||||
const currentPath = location.pathname
|
const currentPath = location.pathname
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const hasCookie = document.cookie.includes('_identid')
|
// const hasCookie = document.cookie.includes('_identid')
|
||||||
if (!hasCookie) {
|
// if (!hasCookie) {
|
||||||
navigate('/login')
|
// navigate('/login')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}, [])
|
// }, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentPath === '/') {
|
if (currentPath === '/') {
|
||||||
navigate('/registrations')
|
navigate('/registrations')
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export const HOST_NAME = 'http://127.0.0.1:8070/api/v1'
|
export const HOST_NAME = 'http://localhost:8070/api/v1'
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.65991 1.91L3.07991 6.5L7.65991 11.09L6.24991 12.5L0.249912 6.5L6.24991 0.5L7.65991 1.91Z" fill="#C4CDD5"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 220 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.32507 14.045L2.23007 16.965C2.18802 17.0774 2.1792 17.1995 2.20468 17.3167C2.23015 17.434 2.28883 17.5414 2.37372 17.6262C2.4586 17.711 2.5661 17.7696 2.68337 17.7949C2.80064 17.8203 2.92274 17.8113 3.03507 17.7692L5.95423 16.6742C6.28835 16.549 6.59182 16.3538 6.84423 16.1017L15.3001 7.64584C15.3001 7.64584 15.0051 6.76167 14.1217 5.87751C13.2384 4.99418 12.3534 4.69918 12.3534 4.69918L3.89757 13.155C3.64541 13.4074 3.45021 13.7109 3.32507 14.045ZM13.5326 3.52001L14.6851 2.36751C14.8917 2.16084 15.1676 2.02918 15.4559 2.07751C15.8617 2.14418 16.4826 2.34584 17.0676 2.93168C17.6534 3.51751 17.8551 4.13751 17.9217 4.54334C17.9701 4.83168 17.8384 5.10751 17.6317 5.31418L16.4784 6.46668C16.4784 6.46668 16.1842 5.58334 15.3001 4.70001C14.4167 3.81501 13.5326 3.52001 13.5326 3.52001Z" fill="#292929"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 963 B |
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="25" height="26" viewBox="0 0 25 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.7917 14.0417C20.367 14.0417 20.8333 13.5754 20.8333 13C20.8333 12.4247 20.367 11.9584 19.7917 11.9584C19.2164 11.9584 18.75 12.4247 18.75 13C18.75 13.5754 19.2164 14.0417 19.7917 14.0417Z" stroke="#292929" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12.4999 14.0417C13.0752 14.0417 13.5416 13.5754 13.5416 13C13.5416 12.4247 13.0752 11.9584 12.4999 11.9584C11.9246 11.9584 11.4583 12.4247 11.4583 13C11.4583 13.5754 11.9246 14.0417 12.4999 14.0417Z" stroke="#292929" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5.20841 14.0417C5.78371 14.0417 6.25008 13.5754 6.25008 13C6.25008 12.4247 5.78371 11.9584 5.20841 11.9584C4.63312 11.9584 4.16675 12.4247 4.16675 13C4.16675 13.5754 4.63312 14.0417 5.20841 14.0417Z" stroke="#292929" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 974 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="14" height="2" viewBox="0 0 14 2" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 1C14 1.26522 13.9078 1.51957 13.7437 1.70711C13.5796 1.89464 13.3571 2 13.125 2H0.875C0.642936 2 0.420376 1.89464 0.256282 1.70711C0.0921872 1.51957 0 1.26522 0 1C0 0.734784 0.0921872 0.48043 0.256282 0.292893C0.420376 0.105357 0.642936 0 0.875 0H13.125C13.3571 0 13.5796 0.105357 13.7437 0.292893C13.9078 0.48043 14 0.734784 14 1Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 502 B |
After Width: | Height: | Size: 21 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.7099 1.20986C14.617 1.11613 14.5064 1.04174 14.3845 0.990969C14.2627 0.940201 14.132 0.914062 13.9999 0.914062C13.8679 0.914062 13.7372 0.940201 13.6154 0.990969C13.4935 1.04174 13.3829 1.11613 13.29 1.20986L5.83995 8.66986L2.70995 5.52986C2.61343 5.43662 2.49949 5.36331 2.37463 5.3141C2.24978 5.2649 2.11645 5.24077 1.98227 5.24309C1.84809 5.24541 1.71568 5.27414 1.5926 5.32763C1.46953 5.38113 1.35819 5.45834 1.26495 5.55486C1.17171 5.65138 1.0984 5.76532 1.04919 5.89018C0.999989 6.01503 0.975859 6.14836 0.97818 6.28254C0.980502 6.41672 1.00923 6.54913 1.06272 6.67221C1.11622 6.79529 1.19343 6.90662 1.28995 6.99986L5.12995 10.8399C5.22291 10.9336 5.33351 11.008 5.45537 11.0588C5.57723 11.1095 5.70794 11.1357 5.83995 11.1357C5.97196 11.1357 6.10267 11.1095 6.22453 11.0588C6.34639 11.008 6.45699 10.9336 6.54995 10.8399L14.7099 2.67986C14.8115 2.58622 14.8925 2.47257 14.9479 2.34607C15.0033 2.21957 15.0319 2.08296 15.0319 1.94486C15.0319 1.80676 15.0033 1.67015 14.9479 1.54365C14.8925 1.41715 14.8115 1.3035 14.7099 1.20986Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.6662 0C14.3125 4.21276e-06 13.9732 0.140441 13.7231 0.390416C13.473 0.640391 13.3325 0.979428 13.3325 1.33294V2.00006H1.33324C0.979518 2.00007 0.640288 2.1405 0.390169 2.39046C0.140049 2.64042 -0.000474239 2.97944 -0.000488281 3.33294C-0.000489881 3.50799 0.0340067 3.68131 0.101032 3.84303C0.168057 4.00475 0.266298 4.1517 0.390146 4.27547C0.513993 4.39925 0.661022 4.49743 0.822838 4.56442C0.984654 4.6314 1.15809 4.66588 1.33324 4.66588H13.3325V5.33379C13.3325 5.6873 13.473 6.02634 13.7231 6.27632C13.9732 6.52629 14.3125 6.66673 14.6662 6.66673C15.0199 6.66673 15.3591 6.52629 15.6093 6.27632C15.8594 6.02634 15.9999 5.6873 15.9999 5.33379V4.66588H18.6657C18.8409 4.66589 19.0143 4.63142 19.1761 4.56444C19.338 4.49745 19.485 4.39927 19.6089 4.27549C19.7327 4.15172 19.831 4.00477 19.898 3.84305C19.965 3.68133 19.9995 3.50799 19.9995 3.33294C19.9995 3.1579 19.965 2.98457 19.898 2.82286C19.8309 2.66114 19.7327 2.5142 19.6088 2.39043C19.485 2.26666 19.3379 2.16849 19.1761 2.10151C19.0143 2.03453 18.8409 2.00006 18.6657 2.00006H15.9999V1.33294C15.9999 0.979428 15.8594 0.640391 15.6093 0.390416C15.3591 0.140441 15.0199 4.21276e-06 14.6662 0ZM4.99951 6.66667C4.82436 6.66666 4.65092 6.70113 4.48909 6.76812C4.32727 6.8351 4.18024 6.93328 4.05638 7.05706C3.93253 7.18083 3.83428 7.32778 3.76725 7.4895C3.70022 7.65123 3.66572 7.82456 3.66572 7.99961V8.66667H1.33363C1.15848 8.66667 0.985044 8.70115 0.823229 8.76813C0.661413 8.83512 0.514384 8.93331 0.390536 9.05708C0.266688 9.18086 0.168447 9.3278 0.101422 9.48952C0.0343973 9.65124 -9.92786e-05 9.82457 -9.76621e-05 9.99961C-9.92786e-05 10.1747 0.0343973 10.348 0.101422 10.5097C0.168447 10.6714 0.266688 10.8184 0.390536 10.9421C0.514384 11.0659 0.661413 11.1641 0.823229 11.2311C0.985044 11.2981 1.15848 11.3326 1.33363 11.3326H3.66572V12.0005C3.66572 12.1755 3.70022 12.3488 3.76725 12.5106C3.83428 12.6723 3.93253 12.8192 4.05638 12.943C4.18024 13.0668 4.32727 13.165 4.48909 13.2319C4.65092 13.2989 4.82436 13.3334 4.99951 13.3334C5.35324 13.3334 5.69248 13.193 5.9426 12.943C6.19272 12.693 6.33324 12.354 6.33324 12.0005V11.3326H18.6662C18.8413 11.3326 19.0148 11.2981 19.1766 11.2311C19.3384 11.1641 19.4854 11.0659 19.6093 10.9421C19.7331 10.8184 19.8314 10.6714 19.8984 10.5097C19.9654 10.348 19.9999 10.1747 19.9999 9.99961C19.9999 9.82457 19.9654 9.65124 19.8984 9.48952C19.8314 9.3278 19.7331 9.18086 19.6093 9.05708C19.4854 8.93331 19.3384 8.83512 19.1766 8.76813C19.0148 8.70115 18.8413 8.66667 18.6662 8.66667H6.33324V7.99961C6.33324 7.64609 6.19272 7.30706 5.9426 7.05708C5.69248 6.80711 5.35324 6.66667 4.99951 6.66667ZM9.33285 13.3334C8.97913 13.3334 8.6399 13.4738 8.38978 13.7238C8.13966 13.9738 7.99914 14.3128 7.99912 14.6663V15.3333H1.33363C1.15848 15.3333 0.985044 15.3678 0.823229 15.4348C0.661413 15.5018 0.514384 15.6 0.390536 15.7237C0.266688 15.8475 0.168447 15.9945 0.101422 16.1562C0.0343973 16.3179 -9.92786e-05 16.4912 -9.76621e-05 16.6663C-8.35946e-05 17.0198 0.140439 17.3588 0.390559 17.6088C0.640679 17.8587 0.979909 17.9992 1.33363 17.9992H7.99912V18.6671C7.99914 19.0206 8.13966 19.3596 8.38978 19.6096C8.6399 19.8596 8.97913 20 9.33285 20C9.68656 20 10.0258 19.8596 10.2759 19.6096C10.526 19.3596 10.6666 19.0206 10.6666 18.6671V17.9992H18.6662C19.0199 17.9992 19.3591 17.8587 19.6092 17.6088C19.8594 17.3588 19.9999 17.0198 19.9999 16.6663C19.9999 16.4912 19.9654 16.3179 19.8984 16.1562C19.8314 15.9945 19.7331 15.8475 19.6093 15.7237C19.4854 15.6 19.3384 15.5018 19.1766 15.4348C19.0148 15.3678 18.8413 15.3333 18.6662 15.3333H10.6666V14.6663C10.6666 14.3128 10.526 13.9738 10.2759 13.7238C10.0258 13.4738 9.68656 13.3334 9.33285 13.3334Z" fill="black"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,10 @@
|
||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_61_2312)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.415 6.61716L5.14475 0.365623C3.42531 -0.680357 1.28564 0.642997 1.28564 2.74871V15.2512C1.28564 17.3596 3.42531 18.6802 5.14475 17.6342L15.415 11.3859C17.1473 10.3316 17.1473 7.67137 15.415 6.61716Z" fill="#292929"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_61_2312">
|
||||||
|
<rect width="18" height="18" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 515 B |
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.3672 17.3346L21.875 21.875M19.7917 11.4583C19.7917 16.0607 16.0607 19.7917 11.4583 19.7917C6.85596 19.7917 3.125 16.0607 3.125 11.4583C3.125 6.85596 6.85596 3.125 11.4583 3.125C16.0607 3.125 19.7917 6.85596 19.7917 11.4583Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 422 B |
|
@ -0,0 +1,13 @@
|
||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_61_2486)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.415 6.61716L5.14475 0.365623C3.42531 -0.680357 1.28564 0.642997 1.28564 2.74871V15.2512C1.28564 17.3596 3.42531 18.6802 5.14475 17.6342L15.415 11.3859C17.1473 10.3316 17.1473 7.67137 15.415 6.61716Z" fill="#292929"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.28711 6.61716L13.4623 0.365623C15.1658 -0.680357 17.2856 0.642997 17.2856 2.74871V15.2512C17.2856 17.3596 15.1658 18.6802 13.4623 17.6342L3.28711 11.3859C1.57082 10.3316 1.57082 7.67137 3.28711 6.61716Z" fill="#292929"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.44895 11.5272L2.30107 3.14838C1.43976 1.74561 2.52948 2.31443e-08 4.26345 9.89385e-08L14.5587 5.48957e-07C16.2949 6.24849e-07 17.3824 1.74561 16.521 3.14838L11.3758 11.5272C10.5077 12.9405 8.31704 12.9405 7.44895 11.5272Z" fill="#292929"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.51423 5.17895L2.30468 14.4982C1.43304 16.0585 2.53582 18 4.29057 18L14.7091 18C16.4661 18 17.5667 16.0585 16.695 14.4982L11.4881 5.17895C10.6096 3.60702 8.39272 3.60702 7.51423 5.17895Z" fill="#292929"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_61_2486">
|
||||||
|
<rect width="18" height="18" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_88_910)">
|
||||||
|
<path d="M6.66675 1.74996V2.58329H2.50008C2.03985 2.58329 1.66675 2.95639 1.66675 3.41663V4.24996C1.66675 4.71019 2.03985 5.08329 2.50008 5.08329H17.5001C17.9603 5.08329 18.3334 4.71019 18.3334 4.24996V3.41663C18.3334 2.95639 17.9603 2.58329 17.5001 2.58329H13.3334V1.74996C13.3334 1.28972 12.9603 0.916626 12.5001 0.916626H7.50008C7.03985 0.916626 6.66675 1.28972 6.66675 1.74996Z" fill="#292929"/>
|
||||||
|
<path d="M3.26929 6.75H16.7306L15.9454 17.3513C15.8486 18.6568 14.7613 19.6667 13.4522 19.6667H6.54774C5.23867 19.6667 4.15127 18.6568 4.05457 17.3513L3.26929 6.75Z" fill="#292929"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_88_910">
|
||||||
|
<rect width="20" height="20" fill="white" transform="translate(0 0.5)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 855 B |
|
@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom'
|
||||||
import MainButton from 'src/components/UI/button/MainButton'
|
import MainButton from 'src/components/UI/button/MainButton'
|
||||||
import MainInput from 'src/components/UI/input/MainInput'
|
import MainInput from 'src/components/UI/input/MainInput'
|
||||||
import Loader from 'src/components/UI/loader/Loader'
|
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'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
type Props = {}
|
type Props = {}
|
||||||
|
|
|
@ -1,13 +1,30 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import MainButton from 'src/components/UI/button/MainButton'
|
import MainButton from 'src/components/UI/button/MainButton'
|
||||||
import Modal from 'src/components/UI/modal/Modal'
|
import SearchInput from 'src/components/UI/input/SearchInput'
|
||||||
import RegistrationsService from 'src/services/Registrations'
|
import Pagination from 'src/components/UI/table/pagination/Pagination'
|
||||||
|
import RegistrationsService from 'src/services/registrationsServices'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import NewRegForm from './blocks/NewRegForm'
|
import NewRegModal from './blocks/NewRegModal'
|
||||||
import { T_NewRegistration } from './types'
|
import RegTable from './blocks/RegTable'
|
||||||
|
import { T_ColumnsState, T_NewRegistration, T_RegistrationItem } from './types'
|
||||||
|
|
||||||
type Props = {}
|
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`
|
const Notification = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
@ -19,20 +36,58 @@ const Notification = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ModalContainer = styled.div`
|
const SelectNotification = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
width: 100%;
|
||||||
gap: 20px;
|
justify-content: space-between;
|
||||||
width: 440px;
|
align-items: center;
|
||||||
|
padding: 10px 20px;
|
||||||
|
${(props) => props.theme.mainShadow}
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
.buttonBlock {
|
img {
|
||||||
display: flex;
|
padding: 5px;
|
||||||
gap: 20px;
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: 300ms;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: ${(props) => props.theme.focusColor};
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function Registrations({}: Props) {
|
export default function Registrations({}: Props) {
|
||||||
const [registrations, setRegistrations] = useState([])
|
const [pageCount, setPageCount] = useState(10)
|
||||||
|
const [pageNumber, setPageNumber] = useState(1)
|
||||||
|
|
||||||
|
const [registrations, setRegistrations] = useState<T_RegistrationItem[]>([])
|
||||||
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
|
|
||||||
|
const handleSearchQueryChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setSearchQuery(e.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [activeColumns, setActiveColumns] = useState<T_ColumnsState>({
|
||||||
|
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<number[]>([])
|
||||||
|
const [selectAll, setSelectAll] = useState<boolean>(false)
|
||||||
|
const [notChecked, setNotChecked] = useState<number[]>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
notChecked.length === registrations.length &&
|
||||||
|
(setSelectAll(false), setNotChecked([]))
|
||||||
|
}, [notChecked])
|
||||||
|
|
||||||
const [newReg, setNewReg] = useState<T_NewRegistration>({
|
const [newReg, setNewReg] = useState<T_NewRegistration>({
|
||||||
RegNum: '',
|
RegNum: '',
|
||||||
|
@ -44,6 +99,10 @@ export default function Registrations({}: Props) {
|
||||||
|
|
||||||
const [modal, setModal] = useState(false)
|
const [modal, setModal] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(registrations)
|
||||||
|
}, [registrations])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNewReg({
|
setNewReg({
|
||||||
RegNum: '',
|
RegNum: '',
|
||||||
|
@ -63,11 +122,10 @@ export default function Registrations({}: Props) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getReg()
|
getReg()
|
||||||
console.log(registrations)
|
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Container>
|
||||||
{registrations.length === 0 ? (
|
{registrations.length === 0 ? (
|
||||||
<Notification>
|
<Notification>
|
||||||
<h2>Активных лицензий нет</h2>
|
<h2>Активных лицензий нет</h2>
|
||||||
|
@ -76,23 +134,53 @@ export default function Registrations({}: Props) {
|
||||||
</MainButton>
|
</MainButton>
|
||||||
</Notification>
|
</Notification>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<>
|
||||||
)}
|
<h2>Система управления и контроля ОСГОС</h2>
|
||||||
<Modal modal={modal} setModal={setModal}>
|
<SearchInput
|
||||||
<ModalContainer>
|
value={searchQuery}
|
||||||
<NewRegForm newReg={newReg} setNewReg={setNewReg} />
|
onChange={handleSearchQueryChange}
|
||||||
<div className='buttonBlock'>
|
placeholder='Введите номер контракта, поставки или email'
|
||||||
<MainButton
|
/>
|
||||||
color='secondary'
|
{(selectAll || checkedColumns.length !== 0) && (
|
||||||
fullWidth={true}
|
<SelectNotification>
|
||||||
onClick={() => setModal(false)}
|
<h3>
|
||||||
>
|
{selectAll
|
||||||
Отмена
|
? 'Количесво не определено'
|
||||||
</MainButton>
|
: checkedColumns.length !== 0 &&
|
||||||
<MainButton fullWidth={true}>Создать</MainButton>
|
`Выбранно: ${checkedColumns.length}`}
|
||||||
|
</h3>
|
||||||
|
<img src='/src/images/trash.svg' alt='' />
|
||||||
|
</SelectNotification>
|
||||||
|
)}
|
||||||
|
<RegTable
|
||||||
|
selectAll={selectAll}
|
||||||
|
notChecked={notChecked}
|
||||||
|
setNotChecked={setNotChecked}
|
||||||
|
setSelectAll={setSelectAll}
|
||||||
|
checkedColumns={checkedColumns}
|
||||||
|
setCheckedColumns={setCheckedColumns}
|
||||||
|
activeColumns={activeColumns}
|
||||||
|
setActiveColumns={setActiveColumns}
|
||||||
|
registrations={registrations}
|
||||||
|
getReg={getReg}
|
||||||
|
/>
|
||||||
|
<div className='bottom-menu'>
|
||||||
|
<Pagination
|
||||||
|
setPageNumber={setPageNumber}
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
pageCount={pageCount}
|
||||||
|
/>
|
||||||
|
<MainButton onClick={() => setModal(true)}>Добавить</MainButton>
|
||||||
</div>
|
</div>
|
||||||
</ModalContainer>
|
</>
|
||||||
</Modal>
|
)}
|
||||||
</div>
|
<NewRegModal
|
||||||
|
modal={modal}
|
||||||
|
setModal={setModal}
|
||||||
|
newReg={newReg}
|
||||||
|
setNewReg={setNewReg}
|
||||||
|
getReg={getReg}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<HTMLInputElement>) => {
|
||||||
|
setEditRegData({ ...registration, ContNum: e.target.value })
|
||||||
|
}
|
||||||
|
const handleRegNumChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setEditRegData({ ...registration, RegNum: e.target.value })
|
||||||
|
}
|
||||||
|
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setEditRegData({ ...registration, Email: e.target.value })
|
||||||
|
}
|
||||||
|
const handleCountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setEditRegData({ ...registration, Count: e.target.value })
|
||||||
|
}
|
||||||
|
const handleEndDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setEditRegData({ ...registration, EndDate: e.target.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(editRegData)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal modal={modal} setModal={setModal}>
|
||||||
|
<ModalContainer>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Номер контракта'
|
||||||
|
value={editRegData.ContNum}
|
||||||
|
onChange={handleContNumChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Номер поставки'
|
||||||
|
value={editRegData.RegNum}
|
||||||
|
onChange={handleRegNumChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Email'
|
||||||
|
value={editRegData.Email}
|
||||||
|
onChange={handleEmailChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Кол-во активаций'
|
||||||
|
value={editRegData.Count}
|
||||||
|
onChange={handleCountChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Дата окончания'
|
||||||
|
value={editRegData.EndDate}
|
||||||
|
onChange={handleEndDateChange}
|
||||||
|
type='date'
|
||||||
|
/>
|
||||||
|
<div className='buttonBlock'>
|
||||||
|
<MainButton
|
||||||
|
color='secondary'
|
||||||
|
fullWidth={true}
|
||||||
|
onClick={() => setModal(false)}
|
||||||
|
>
|
||||||
|
Отмена
|
||||||
|
</MainButton>
|
||||||
|
<MainButton fullWidth={true} onClick={() => editReg(editRegData)}>
|
||||||
|
Сохранить
|
||||||
|
</MainButton>
|
||||||
|
</div>
|
||||||
|
</ModalContainer>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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<HTMLInputElement>) => {
|
|
||||||
setNewReg({ ...newReg, ContNum: e.target.value })
|
|
||||||
}
|
|
||||||
const handleRegNumChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setNewReg({ ...newReg, RegNum: e.target.value })
|
|
||||||
}
|
|
||||||
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setNewReg({ ...newReg, Email: e.target.value })
|
|
||||||
}
|
|
||||||
const handleCountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setNewReg({ ...newReg, Count: e.target.value })
|
|
||||||
}
|
|
||||||
const handleEndDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setNewReg({ ...newReg, EndDate: e.target.value })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<MainInput placeholder='Номер контракта' value={newReg.ContNum} onChange={handleContNumChange}/>
|
|
||||||
<MainInput placeholder='Номер поставки' value={newReg.RegNum} onChange={handleRegNumChange}/>
|
|
||||||
<MainInput placeholder='Email' value={newReg.Email} onChange={handleEmailChange}/>
|
|
||||||
<MainInput placeholder='Кол-во активаций' value={newReg.Count} onChange={handleCountChange}/>
|
|
||||||
<MainInput placeholder='Дата окончания' value={newReg.EndDate} onChange={handleEndDateChange}/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -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<HTMLInputElement>) => {
|
||||||
|
setNewReg({ ...newReg, ContNum: e.target.value })
|
||||||
|
}
|
||||||
|
const handleRegNumChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setNewReg({ ...newReg, RegNum: e.target.value })
|
||||||
|
}
|
||||||
|
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setNewReg({ ...newReg, Email: e.target.value })
|
||||||
|
}
|
||||||
|
const handleCountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setNewReg({ ...newReg, Count: e.target.value })
|
||||||
|
}
|
||||||
|
const handleEndDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setNewReg({ ...newReg, EndDate: e.target.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal modal={modal} setModal={setModal}>
|
||||||
|
<ModalContainer>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Номер контракта'
|
||||||
|
value={newReg.ContNum}
|
||||||
|
onChange={handleContNumChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Номер поставки'
|
||||||
|
value={newReg.RegNum}
|
||||||
|
onChange={handleRegNumChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Email'
|
||||||
|
value={newReg.Email}
|
||||||
|
onChange={handleEmailChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Кол-во активаций'
|
||||||
|
value={typeof newReg.Count === 'string' ? newReg.Count : ''}
|
||||||
|
onChange={handleCountChange}
|
||||||
|
/>
|
||||||
|
<MainInput
|
||||||
|
placeholder='Дата окончания'
|
||||||
|
value={newReg.EndDate}
|
||||||
|
onChange={handleEndDateChange}
|
||||||
|
type='date'
|
||||||
|
/>
|
||||||
|
<div className='buttonBlock'>
|
||||||
|
<MainButton
|
||||||
|
color='secondary'
|
||||||
|
fullWidth={true}
|
||||||
|
onClick={() => setModal(false)}
|
||||||
|
>
|
||||||
|
Отмена
|
||||||
|
</MainButton>
|
||||||
|
<MainButton fullWidth={true} onClick={CreateReg}>
|
||||||
|
Создать
|
||||||
|
</MainButton>
|
||||||
|
</div>
|
||||||
|
</ModalContainer>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<Table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<Checkbox
|
||||||
|
value={
|
||||||
|
selectAll
|
||||||
|
? notChecked.length === 0
|
||||||
|
? 'ok'
|
||||||
|
: 'minus'
|
||||||
|
: checkedColumns.length === 0
|
||||||
|
? 'off'
|
||||||
|
: 'minus'
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
selectAll
|
||||||
|
? (setSelectAll(false),
|
||||||
|
setNotChecked([]),
|
||||||
|
setCheckedColumns([]))
|
||||||
|
: checkedColumns.length === 0
|
||||||
|
? (setSelectAll(true), setNotChecked([]))
|
||||||
|
: setCheckedColumns([])
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
|
{Object.entries(activeColumns).map(
|
||||||
|
([index, item]) =>
|
||||||
|
item.status === true && <th key={index}>{item.name}</th>
|
||||||
|
)}
|
||||||
|
<th>
|
||||||
|
<ContextMenu active={contextMenuState} setActive={setContextMenuState}>
|
||||||
|
<div className='target'>
|
||||||
|
<img
|
||||||
|
src='/src/images/params.svg'
|
||||||
|
alt=''
|
||||||
|
onClick={() => setContextMenuState(!contextMenuState)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='content'>
|
||||||
|
{Object.entries(activeColumns).map(([key, item]) => (
|
||||||
|
<Item
|
||||||
|
key={key}
|
||||||
|
onClick={() => {
|
||||||
|
const updatedActiveColumns = { ...activeColumns }
|
||||||
|
updatedActiveColumns[key].status =
|
||||||
|
!updatedActiveColumns[key].status
|
||||||
|
setActiveColumns(updatedActiveColumns)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
value={item.status ? 'ok' : 'off'}
|
||||||
|
onClick={() => {}}
|
||||||
|
/>
|
||||||
|
<p>{item.name}</p>
|
||||||
|
</Item>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ContextMenu>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{registrations.map((registration) => (
|
||||||
|
<RegTableItem
|
||||||
|
registration={registration}
|
||||||
|
selectAll={selectAll}
|
||||||
|
notChecked={notChecked}
|
||||||
|
checkedColumns={checkedColumns}
|
||||||
|
setNotChecked={setNotChecked}
|
||||||
|
setCheckedColumns={setCheckedColumns}
|
||||||
|
activeColumns={activeColumns}
|
||||||
|
getReg={getReg}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
)
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<>
|
||||||
|
<tr key={registration.Id}>
|
||||||
|
<td>
|
||||||
|
<Checkbox
|
||||||
|
value={
|
||||||
|
selectAll
|
||||||
|
? notChecked.includes(registration.Id)
|
||||||
|
? 'off'
|
||||||
|
: 'ok'
|
||||||
|
: checkedColumns.includes(registration.Id)
|
||||||
|
? 'ok'
|
||||||
|
: 'off'
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
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])
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
{Object.entries(activeColumns).map(([key, item]) =>
|
||||||
|
activeColumns[key as keyof typeof activeColumns].status ? (
|
||||||
|
<td key={key}>
|
||||||
|
<p>
|
||||||
|
{' '}
|
||||||
|
{key === 'Enabled' ? (
|
||||||
|
registration[key as keyof typeof registration] ? (
|
||||||
|
<img src='/src/images/on.svg' />
|
||||||
|
) : (
|
||||||
|
<img src='/src/images/off.svg' />
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
registration[key as keyof typeof registration]
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
) : null
|
||||||
|
)}
|
||||||
|
<td>
|
||||||
|
<ContextMenu
|
||||||
|
active={contextMenuState}
|
||||||
|
setActive={setContextMenuState}
|
||||||
|
>
|
||||||
|
<div className='target'>
|
||||||
|
<img
|
||||||
|
src='/src/images/menu.svg'
|
||||||
|
alt=''
|
||||||
|
onClick={() => setContextMenuState(!contextMenuState)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='content'>
|
||||||
|
<Item
|
||||||
|
onClick={() => {
|
||||||
|
setEditModalState(true)
|
||||||
|
setContextMenuState(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img src='/src/images/edit.svg' alt='' />
|
||||||
|
<p>Редактировать</p>
|
||||||
|
</Item>
|
||||||
|
<Item
|
||||||
|
onClick={() => {
|
||||||
|
setContextMenuState(false)
|
||||||
|
setDeleteNotificationState(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img src='/src/images/trash.svg' alt='' />
|
||||||
|
<p>Удалить</p>
|
||||||
|
</Item>
|
||||||
|
{registration.Enabled ? (
|
||||||
|
<Item onClick={offReg}>
|
||||||
|
<img src='/src/images/stop.svg' alt='' />
|
||||||
|
<p>Выключить</p>
|
||||||
|
</Item>
|
||||||
|
) : (
|
||||||
|
<Item onClick={onReg}>
|
||||||
|
<img src='/src/images/play.svg' alt='' />
|
||||||
|
<p>Включить</p>
|
||||||
|
</Item>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ContextMenu>
|
||||||
|
</td>
|
||||||
|
<Modal
|
||||||
|
modal={deleteNotificationState}
|
||||||
|
setModal={setDeleteNotificationState}
|
||||||
|
>
|
||||||
|
<DeleteNotification>
|
||||||
|
<h3>Вы действительно хотите удалить лицензию?</h3>
|
||||||
|
<div className='button-container'>
|
||||||
|
<MainButton
|
||||||
|
color={'secondary'}
|
||||||
|
fullWidth={true}
|
||||||
|
onClick={() => setDeleteNotificationState(false)}
|
||||||
|
>
|
||||||
|
Отмена
|
||||||
|
</MainButton>
|
||||||
|
<MainButton fullWidth={true} onClick={() => deleteReg()}>
|
||||||
|
Удалить
|
||||||
|
</MainButton>
|
||||||
|
</div>
|
||||||
|
</DeleteNotification>
|
||||||
|
</Modal>
|
||||||
|
<EditRegModal
|
||||||
|
modal={editModalState}
|
||||||
|
setModal={setEditModalState}
|
||||||
|
registration={registration}
|
||||||
|
editReg={editReg}
|
||||||
|
/>
|
||||||
|
</tr>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
|
@ -2,6 +2,27 @@ export type T_NewRegistration = {
|
||||||
RegNum: string
|
RegNum: string
|
||||||
ContNum: string
|
ContNum: string
|
||||||
Email: string
|
Email: string
|
||||||
Count: string
|
Count: string | number
|
||||||
EndDate: string
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
import axios, { AxiosResponse } from 'axios'
|
|
||||||
import { HOST_NAME } from 'src/constants/host'
|
|
||||||
|
|
||||||
export default class RegistrationsService {
|
|
||||||
static async getRegistration(): Promise<AxiosResponse> {
|
|
||||||
try {
|
|
||||||
const response = await axios.get(`${HOST_NAME}/regs`, {
|
|
||||||
withCredentials: true
|
|
||||||
})
|
|
||||||
return response
|
|
||||||
} catch (error: any) {
|
|
||||||
return error.response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<AxiosResponse> {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${HOST_NAME}/regs`)
|
||||||
|
return response
|
||||||
|
} catch (error: any) {
|
||||||
|
return error.response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async createRegistration(
|
||||||
|
newReg: T_NewRegistration
|
||||||
|
): Promise<AxiosResponse> {
|
||||||
|
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<AxiosResponse> {
|
||||||
|
try {
|
||||||
|
const response = await axios.delete(`${HOST_NAME}/regs/${id}`)
|
||||||
|
return response
|
||||||
|
} catch (error: any) {
|
||||||
|
return error.response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async onRegistration(id: number): Promise<AxiosResponse> {
|
||||||
|
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<AxiosResponse> {
|
||||||
|
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<AxiosResponse> {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`${HOST_NAME}/regs/${id}`, reg)
|
||||||
|
return response
|
||||||
|
} catch (error: any) {
|
||||||
|
return error.response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|