mirror of
https://github.com/IgnatZakalinsky/home-works.git
synced 2025-12-18 04:39:24 +00:00
add hw 14-15 for design
This commit is contained in:
@@ -3,6 +3,8 @@ import HW10 from '../../hw10/HW10'
|
|||||||
import HW11 from '../../hw11/HW11'
|
import HW11 from '../../hw11/HW11'
|
||||||
import HW12 from '../../hw12/HW12'
|
import HW12 from '../../hw12/HW12'
|
||||||
import HW13 from '../../hw13/HW13'
|
import HW13 from '../../hw13/HW13'
|
||||||
|
import HW14 from '../../hw14/HW14'
|
||||||
|
import HW15 from '../../hw15/HW15'
|
||||||
|
|
||||||
function JuniorPlus() {
|
function JuniorPlus() {
|
||||||
return (
|
return (
|
||||||
@@ -11,6 +13,8 @@ function JuniorPlus() {
|
|||||||
<HW11 />
|
<HW11 />
|
||||||
<HW12 />
|
<HW12 />
|
||||||
<HW13 />
|
<HW13 />
|
||||||
|
<HW14 />
|
||||||
|
<HW15 />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
3
src/s2-homeworks/hw14/HW14.module.css
Normal file
3
src/s2-homeworks/hw14/HW14.module.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.tech {
|
||||||
|
|
||||||
|
}
|
||||||
84
src/s2-homeworks/hw14/HW14.tsx
Normal file
84
src/s2-homeworks/hw14/HW14.tsx
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import React, {useEffect, useState} from 'react'
|
||||||
|
import s2 from '../../s1-main/App.module.css'
|
||||||
|
import s from './HW14.module.css'
|
||||||
|
import axios from 'axios'
|
||||||
|
import SuperDebouncedInput from './common/c8-SuperDebouncedInput/SuperDebouncedInput'
|
||||||
|
import {useSearchParams} from 'react-router-dom'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1 - дописать функцию onChangeTextCallback в SuperPagination
|
||||||
|
* 2 - дописать функцию sendQuery в HW14
|
||||||
|
* 3 - дописать функцию onChangeText в HW14
|
||||||
|
* 4 - сделать стили в соответствии с дизайном
|
||||||
|
* 5 - добавить HW14 в HW5/pages/JuniorPlus
|
||||||
|
* */
|
||||||
|
|
||||||
|
const getTechs = (find: string) => {
|
||||||
|
return axios
|
||||||
|
.get<{techs: string[]}>(
|
||||||
|
'https://incubator-personal-page-back.herokuapp.com/api/3.0/homework/test2',
|
||||||
|
{params: {find}}
|
||||||
|
)
|
||||||
|
.catch((e) => {
|
||||||
|
alert(e.response?.data?.errorText || e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const HW14 = () => {
|
||||||
|
const [find, setFind] = useState('')
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
|
const [techs, setTechs] = useState<string[]>([])
|
||||||
|
|
||||||
|
const sendQuery = (value: string) => {
|
||||||
|
getTechs(value)
|
||||||
|
.then((res) => {
|
||||||
|
// делает студент
|
||||||
|
|
||||||
|
if (res) setTechs(res.data.techs)
|
||||||
|
|
||||||
|
//
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangeText = (value: string) => {
|
||||||
|
setFind(value)
|
||||||
|
// делает студент
|
||||||
|
|
||||||
|
const findQuery: {find?: string} = value ? {find: value} : {} // если нет - то не записывать в урл
|
||||||
|
const {find, ...lastQueries} = Object.fromEntries(searchParams)
|
||||||
|
|
||||||
|
setSearchParams({...lastQueries, ...findQuery})
|
||||||
|
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const params = Object.fromEntries(searchParams)
|
||||||
|
sendQuery(params.find || '')
|
||||||
|
setFind(params.find || '')
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const mappedTechs = techs.map(t => (
|
||||||
|
<div key={t} id={'hw14-tech-' + t} className={s.tech}>
|
||||||
|
{t}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id={'hw14'}>
|
||||||
|
<div className={s2.hwTitle}>Homework #14</div>
|
||||||
|
|
||||||
|
<div className={s2.hw}>
|
||||||
|
<SuperDebouncedInput
|
||||||
|
id={'hw14-super-debounced-input'}
|
||||||
|
value={find}
|
||||||
|
onChangeText={onChangeText}
|
||||||
|
onDebouncedChange={sendQuery}
|
||||||
|
/>
|
||||||
|
{mappedTechs}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HW14
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React, {DetailedHTMLProps, InputHTMLAttributes, ReactNode, useState} from 'react'
|
||||||
|
import SuperInputText from '../../../hw04/common/c1-SuperInputText/SuperInputText'
|
||||||
|
|
||||||
|
// тип пропсов обычного инпута
|
||||||
|
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>,
|
||||||
|
HTMLInputElement>
|
||||||
|
|
||||||
|
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
||||||
|
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
||||||
|
export type SuperDebouncedInputPropsType = Omit<DefaultInputPropsType, 'type'> & {
|
||||||
|
// и + ещё пропсы которых нет в стандартном инпуте
|
||||||
|
onChangeText?: (value: string) => void
|
||||||
|
onEnter?: () => void
|
||||||
|
error?: ReactNode
|
||||||
|
spanClassName?: string
|
||||||
|
} // илм экспортировать тип SuperInputTextPropsType
|
||||||
|
& { // плюс специальный пропс SuperPagination
|
||||||
|
onDebouncedChange?: (value: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const SuperDebouncedInput: React.FC<SuperDebouncedInputPropsType> = (
|
||||||
|
{
|
||||||
|
onChangeText,
|
||||||
|
onDebouncedChange,
|
||||||
|
|
||||||
|
...restProps // все остальные пропсы попадут в объект restProps
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const [timerId, setTimerId] = useState<number | undefined>(undefined)
|
||||||
|
|
||||||
|
const onChangeTextCallback = (value: string) => {
|
||||||
|
onChangeText?.(value)
|
||||||
|
|
||||||
|
if (onDebouncedChange) {
|
||||||
|
// делает студент
|
||||||
|
|
||||||
|
timerId && clearTimeout(timerId)
|
||||||
|
const id = +setTimeout(() => {
|
||||||
|
onDebouncedChange(value)
|
||||||
|
setTimerId(undefined)
|
||||||
|
}, 1500)
|
||||||
|
setTimerId(id)
|
||||||
|
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SuperInputText onChangeText={onChangeTextCallback} {...restProps}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SuperDebouncedInput
|
||||||
3
src/s2-homeworks/hw15/HW15.module.css
Normal file
3
src/s2-homeworks/hw15/HW15.module.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.tech {
|
||||||
|
|
||||||
|
}
|
||||||
141
src/s2-homeworks/hw15/HW15.tsx
Normal file
141
src/s2-homeworks/hw15/HW15.tsx
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
import React, {useEffect, useState} from 'react'
|
||||||
|
import s2 from '../../s1-main/App.module.css'
|
||||||
|
import s from './HW15.module.css'
|
||||||
|
import axios from 'axios'
|
||||||
|
import SuperPagination from './common/c9-SuperPagination/SuperPagination'
|
||||||
|
import {useSearchParams} from 'react-router-dom'
|
||||||
|
import SuperButton from "../hw04/common/c2-SuperButton/SuperButton";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1 - дописать SuperPagination
|
||||||
|
* 2 - дописать функцию send в HW15
|
||||||
|
* 3 - дописать функцию onChangeText в HW15
|
||||||
|
* 4 - сделать стили в соответствии с дизайном
|
||||||
|
* 5 - добавить HW15 в HW5/pages/JuniorPlus
|
||||||
|
* */
|
||||||
|
|
||||||
|
type TechType = {
|
||||||
|
id: number
|
||||||
|
tech: string
|
||||||
|
developer: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTechs = (params: any) => {
|
||||||
|
return axios
|
||||||
|
.get<{ techs: TechType[], totalCount: number }>(
|
||||||
|
'https://incubator-personal-page-back.herokuapp.com/api/3.0/homework/test3',
|
||||||
|
{params}
|
||||||
|
)
|
||||||
|
.catch((e) => {
|
||||||
|
alert(e.response?.data?.errorText || e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const HW15 = () => {
|
||||||
|
const [sort, setSort] = useState('')
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const [count, setCount] = useState(4)
|
||||||
|
const [totalCount, setTotalCount] = useState(100)
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
|
const [techs, setTechs] = useState<TechType[]>([])
|
||||||
|
|
||||||
|
const sendQuery = (params: any) => {
|
||||||
|
getTechs(params)
|
||||||
|
.then((res) => {
|
||||||
|
// делает студент
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
setTechs(res.data.techs)
|
||||||
|
setTotalCount(res.data.totalCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChange = (newPage: number, newCount: number) => {
|
||||||
|
// делает студент
|
||||||
|
|
||||||
|
setPage(newPage)
|
||||||
|
setCount(newCount)
|
||||||
|
const pageQuery: { page?: string } = newPage !== 1 ? {page: newPage + ''} : {} // если стандарт - то не записывать в урл
|
||||||
|
const countQuery: { count?: string } = newCount !== 4 ? {count: newCount + ''} : {} // если стандарт - то не записывать в урл
|
||||||
|
const {count, page, ...lastQueries} = Object.fromEntries(searchParams)
|
||||||
|
|
||||||
|
sendQuery({page: newPage || '', count: newCount || ''})
|
||||||
|
setSearchParams({...lastQueries, ...pageQuery, ...countQuery})
|
||||||
|
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const params = Object.fromEntries(searchParams)
|
||||||
|
sendQuery({page: params.page, count: params.count})
|
||||||
|
setPage(+params.page || 1)
|
||||||
|
setCount(+params.count || 4)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const mappedTechs = techs.map(t => (
|
||||||
|
<div key={t.id} className={s.tech}>
|
||||||
|
<span id={'hw15-tech-' + t.id}>
|
||||||
|
{t.tech}
|
||||||
|
</span>
|
||||||
|
-----
|
||||||
|
<span id={'hw15-developer-' + t.id}>
|
||||||
|
{t.developer}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id={'hw15'}>
|
||||||
|
<div className={s2.hwTitle}>Homework #15</div>
|
||||||
|
|
||||||
|
<div className={s2.hw}>
|
||||||
|
<SuperPagination
|
||||||
|
page={page}
|
||||||
|
count={count}
|
||||||
|
totalCount={totalCount}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
таблица:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
tech
|
||||||
|
<SuperButton // позже СуперСорт
|
||||||
|
onClick={() => setSort(sort === '1tech'
|
||||||
|
? '0tech'
|
||||||
|
: sort == '0tech'
|
||||||
|
? ''
|
||||||
|
: '1tech')}
|
||||||
|
>
|
||||||
|
{sort === '1tech'
|
||||||
|
? '\\/'
|
||||||
|
: sort === '0tech'
|
||||||
|
? '/\\'
|
||||||
|
: '-'}
|
||||||
|
</SuperButton>
|
||||||
|
developer
|
||||||
|
<SuperButton
|
||||||
|
onClick={() => setSort(sort === '1developer'
|
||||||
|
? '0developer'
|
||||||
|
: sort === '0developer'
|
||||||
|
? ''
|
||||||
|
: '1developer')}
|
||||||
|
>
|
||||||
|
{sort === '1developer'
|
||||||
|
? '\\/'
|
||||||
|
: sort === '0developer'
|
||||||
|
? '/\\'
|
||||||
|
: '-'}
|
||||||
|
</SuperButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{mappedTechs}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HW15
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import SuperButton from '../../../hw04/common/c2-SuperButton/SuperButton'
|
||||||
|
import SuperSelect from '../../../hw07/common/c5-SuperSelect/SuperSelect'
|
||||||
|
|
||||||
|
export type SuperPaginationPropsType = {
|
||||||
|
id?: string
|
||||||
|
page: number
|
||||||
|
count: number
|
||||||
|
totalCount: number
|
||||||
|
onChange: (page: number, count: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const SuperPagination: React.FC<SuperPaginationPropsType> = (
|
||||||
|
{
|
||||||
|
page, count, totalCount, onChange, id = 'hw15',
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
let pages = []
|
||||||
|
const lastPage = Math.ceil(totalCount / count)
|
||||||
|
|
||||||
|
for (let i = 1; i <= lastPage; i++) pages.push((
|
||||||
|
<SuperButton
|
||||||
|
key={id + '-page-' + i}
|
||||||
|
id={id + '-page-' + i}
|
||||||
|
onClick={() => onChange(i, count)}
|
||||||
|
xType={i === page ? undefined : 'secondary'}
|
||||||
|
|
||||||
|
>
|
||||||
|
{i}
|
||||||
|
</SuperButton>
|
||||||
|
))
|
||||||
|
|
||||||
|
// 1 ... 4 5 (6) 7 8 ... 11 // выбрана страница 6
|
||||||
|
// 1 2 3 4 (5) 6 7 ... 11 // выбрана страница 5
|
||||||
|
// делает студент
|
||||||
|
|
||||||
|
if ((page + 4) < lastPage) {
|
||||||
|
pages[page + 2] = (
|
||||||
|
<span key={id + '-span-' + (page + 3)} id={id + '-span-' + (page + 3)}>
|
||||||
|
{' ... '}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
pages = pages.filter((p, i) => i < (page + 3) || i === (lastPage - 1))
|
||||||
|
}
|
||||||
|
if (page > 5) {
|
||||||
|
pages[1] = (
|
||||||
|
<span key={id + '-span-' + 2} id={id + '-span-' + 2}>
|
||||||
|
{' ... '}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
pages = pages.filter((p, i) => i < 2 || i > page - 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SuperSelect
|
||||||
|
value={count}
|
||||||
|
options={[
|
||||||
|
{id: 4, value: 4},
|
||||||
|
{id: 7, value: 7},
|
||||||
|
{id: 10, value: 10},
|
||||||
|
]}
|
||||||
|
onChange={e => onChange(page, Number(e.currentTarget.value))}
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
|
{pages}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SuperPagination
|
||||||
Reference in New Issue
Block a user