mirror of
https://github.com/IgnatZakalinsky/home-works.git
synced 2025-12-16 20:39:24 +00:00
final ref hw3
This commit is contained in:
@@ -2,6 +2,7 @@ import React from 'react'
|
||||
import s from './App.module.css'
|
||||
import HW1 from '../s2-homeworks/hw01/HW1'
|
||||
import HW2 from '../s2-homeworks/hw02/HW2'
|
||||
import HW3 from '../s2-homeworks/hw03/HW3'
|
||||
|
||||
function App() {
|
||||
// для дз 12
|
||||
@@ -17,7 +18,7 @@ function App() {
|
||||
>
|
||||
<HW1/>
|
||||
<HW2/>
|
||||
{/*<HW3/>*/}
|
||||
<HW3/>
|
||||
{/*<HW4/>*/}
|
||||
|
||||
{/*<HW5/>*/}
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
}
|
||||
|
||||
.error {
|
||||
position: absolute;
|
||||
margin-top: 7px;
|
||||
|
||||
color: #cc0000;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
font-weight: 400;
|
||||
@@ -19,21 +21,23 @@
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 370px;
|
||||
padding: 8px 0 8px 12px;
|
||||
|
||||
border: 1px solid #d1d1d1;
|
||||
border-radius: 5px;
|
||||
width: 370px;
|
||||
|
||||
color: #000;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
padding: 8px 0 8px 12px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
outline: none;
|
||||
border: 1px solid #06c;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.errorInput {
|
||||
@@ -41,19 +45,21 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
height: 36px;
|
||||
margin-left: 12px;
|
||||
padding: 8px 24px;
|
||||
|
||||
background: #06c;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
outline: none;
|
||||
padding: 8px 24px;
|
||||
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
@@ -67,12 +73,14 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.count {
|
||||
.text {
|
||||
margin-bottom: 9px;
|
||||
|
||||
opacity: .5;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
.greeting {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React, { ChangeEvent, KeyboardEvent } from 'react'
|
||||
import React, {ChangeEvent, KeyboardEvent} from 'react'
|
||||
import s from './Greeting.module.css'
|
||||
|
||||
type GreetingPropsType = {
|
||||
name: string // need to fix any
|
||||
setNameCallback: (e: ChangeEvent<HTMLInputElement>) => void // need to fix any
|
||||
addUser: () => void // need to fix any
|
||||
onBlur: () => void // need to fix any
|
||||
onEnter: (e: KeyboardEvent<HTMLInputElement>) => void
|
||||
error: string // need to fix any
|
||||
totalUsers: number // need to fix any
|
||||
lastUser?: string // need to fix any
|
||||
name: any // need to fix any
|
||||
setNameCallback: any // need to fix any
|
||||
addUser: any // need to fix any
|
||||
onBlur: any // need to fix any
|
||||
onEnter: any // need to fix any
|
||||
error: any // need to fix any
|
||||
totalUsers: any // need to fix any
|
||||
lastUserName?: any // need to fix any
|
||||
}
|
||||
|
||||
// презентационная компонента (для верстальщика)
|
||||
@@ -19,19 +19,23 @@ const Greeting: React.FC<GreetingPropsType> = (
|
||||
setNameCallback,
|
||||
addUser,
|
||||
onEnter,
|
||||
onBlur,
|
||||
error,
|
||||
totalUsers,
|
||||
lastUser,
|
||||
onBlur,
|
||||
lastUserName,
|
||||
} // деструктуризация пропсов
|
||||
) => {
|
||||
const inputClass = error ? `${s.input} ${s.errorInput}` : s.input // need to fix with (?:)
|
||||
|
||||
return (
|
||||
<div id={'hw3-form'} className={s.greetingForm}>
|
||||
<div id={'hw3-users-total'} className={s.count}>
|
||||
{totalUsers}
|
||||
<div className={s.text}>
|
||||
{'Людей добавили: '}
|
||||
<span id={'hw3-users-total'}>
|
||||
{totalUsers}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className={s.inputAndButtonContainer}>
|
||||
<div>
|
||||
<input
|
||||
@@ -51,15 +55,15 @@ const Greeting: React.FC<GreetingPropsType> = (
|
||||
id={'hw3-button'}
|
||||
onClick={addUser}
|
||||
className={s.button}
|
||||
disabled={!name}
|
||||
disabled={!name.trim()}
|
||||
>
|
||||
add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{lastUser && (
|
||||
{lastUserName && (
|
||||
<div className={s.greeting}>
|
||||
hello <span id={'hw3-last-user'}>{lastUser}</span>!
|
||||
hello <span id={'hw3-last-user'}>{lastUserName}</span>!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,30 @@ import Greeting from './Greeting'
|
||||
import { UserType } from './HW3'
|
||||
|
||||
type GreetingContainerPropsType = {
|
||||
users: UserType[] // need to fix any
|
||||
addUserCallback: (name: string) => void // need to fix any
|
||||
users: any // need to fix any
|
||||
addUserCallback: any // need to fix any
|
||||
}
|
||||
|
||||
export const pureAddUser = (name: any, setError: any, setName: any, addUserCallback: any) => {
|
||||
// если имя пустое - показать ошибку, иначе - добавить юзера и очистить инпут
|
||||
if (!name.trim()) {
|
||||
setError('name is required!')
|
||||
} else {
|
||||
addUserCallback(name)
|
||||
setName('')
|
||||
}
|
||||
}
|
||||
|
||||
export const pureOnBlur = (name: any, setError: any) => { // если имя пустое - показать ошибку
|
||||
if (!name.trim()) {
|
||||
setError('name is required!')
|
||||
}
|
||||
}
|
||||
|
||||
export const pureOnEnter = (e: any, addUser: any) => { // если нажата кнопка Enter - добавить
|
||||
if (e.key === 'Enter') {
|
||||
addUser()
|
||||
}
|
||||
}
|
||||
|
||||
// более простой и понятный для новичков
|
||||
@@ -16,54 +38,39 @@ const GreetingContainer: React.FC<GreetingContainerPropsType> = ({
|
||||
addUserCallback,
|
||||
}) => {
|
||||
// деструктуризация пропсов
|
||||
const [name, setName] = useState<string>('') // need to fix any
|
||||
const [error, setError] = useState<string>('') // need to fix any
|
||||
const [name, setName] = useState<any>('') // need to fix any
|
||||
const [error, setError] = useState<any>('') // need to fix any
|
||||
|
||||
const setNameCallback = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
// need to fix any // нельзя пробелы перед и после имени, можно в середине
|
||||
const setNameCallback = (e: any) => { // need to fix any
|
||||
setName(e.currentTarget.value) // need to fix
|
||||
|
||||
error && setError('')
|
||||
}
|
||||
const addUser = () => {
|
||||
addUserCallback(name)
|
||||
setName('')
|
||||
pureAddUser(name, setError, setName, addUserCallback)
|
||||
}
|
||||
|
||||
const onBlur = () => {
|
||||
const trimmedName = name.trim()
|
||||
|
||||
if (!trimmedName) {
|
||||
setError('name is required!')
|
||||
}
|
||||
setName(trimmedName) // need to fix
|
||||
pureOnBlur(name, setError)
|
||||
}
|
||||
|
||||
const onEnter = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
const trimmedName = name.trim()
|
||||
|
||||
if (!trimmedName) {
|
||||
setName('')
|
||||
setError('name is required!')
|
||||
} else {
|
||||
addUserCallback(trimmedName)
|
||||
setName('')
|
||||
}
|
||||
}
|
||||
const onEnter = (e: any) => {
|
||||
pureOnEnter(e, addUser)
|
||||
}
|
||||
|
||||
const totalUsers = users.length // need to fix
|
||||
const lastUserName = users[users.length - 1]?.name // need to fix
|
||||
|
||||
return (
|
||||
<Greeting
|
||||
onBlur={onBlur}
|
||||
name={name}
|
||||
setNameCallback={setNameCallback}
|
||||
addUser={addUser}
|
||||
onBlur={onBlur}
|
||||
onEnter={onEnter}
|
||||
error={error}
|
||||
totalUsers={totalUsers}
|
||||
lastUser={users[users.length - 1]?.name}
|
||||
lastUserName={lastUserName}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
import React, { useState } from 'react'
|
||||
import { v1 } from 'uuid'
|
||||
import s from './Greeting.module.css'
|
||||
import s2 from '../../s1-main/App.module.css'
|
||||
import GreetingContainer from './GreetingContainer'
|
||||
|
||||
/*
|
||||
* 1 - описать тип UserType
|
||||
* 2 - указать нужный тип в useState с users
|
||||
* 3 - дописать типы и логику функции pureAddUserCallback и проверить её тестами
|
||||
* 4 - в файле GreetingContainer.tsx дописать типизацию пропсов
|
||||
* 5 - в файле GreetingContainer.tsx указать нужные типы в useState с name и error
|
||||
* 6 - в файле GreetingContainer.tsx дописать тип и логику функции setNameCallback
|
||||
* 7 - в файле GreetingContainer.tsx дописать логику функций pureAddUser, pureOnBlur, pureOnEnter и проверить их тестами
|
||||
* 8 - в файле GreetingContainer.tsx вычислить количество добавленных и имя последнего (totalUsers, lastUserName)
|
||||
* 9 - в файле Greeting.tsx дописать типизацию пропсов
|
||||
* 10 - в файле Greeting.tsx вычислить inputClass в зависимости от наличия ошибки
|
||||
* 11 - сделать стили в соответствии с дизайном
|
||||
* */
|
||||
|
||||
// types
|
||||
export type UserType = {
|
||||
_id: string // need to fix any
|
||||
name: string // need to fix any
|
||||
_id: any // need to fix any
|
||||
name: any // need to fix any
|
||||
}
|
||||
|
||||
export const pureAddUserCallback = (name: any, setUsers: any, users: any) => { // need to fix any
|
||||
const user = { // need to fix
|
||||
_id: v1(),
|
||||
name,
|
||||
}
|
||||
setUsers([...users, user])
|
||||
}
|
||||
|
||||
const HW3 = () => {
|
||||
const [users, setUsers] = useState<UserType[]>([]) // need to fix any
|
||||
const [users, setUsers] = useState<any>([]) // need to fix any
|
||||
|
||||
const addUserCallback = (name: string) => {
|
||||
// need to fix any
|
||||
const user = {
|
||||
_id: v1(),
|
||||
name,
|
||||
}
|
||||
setUsers([...users, user]) // need to fix
|
||||
const addUserCallback = (name: any) => { // need to fix any
|
||||
pureAddUserCallback(name, setUsers, users)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
43
src/s2-homeworks/hw03/tests/pureAddUser.test.tsx
Normal file
43
src/s2-homeworks/hw03/tests/pureAddUser.test.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react'
|
||||
import {pureAddUser} from '../GreetingContainer'
|
||||
|
||||
let name: any
|
||||
const setName = (a: any) => {
|
||||
name = a
|
||||
}
|
||||
let error: any
|
||||
const setError = (a: any) => {
|
||||
error = a
|
||||
}
|
||||
let added: any
|
||||
const addUserCallback = () => {
|
||||
added = true
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
name = ''
|
||||
error = ''
|
||||
added = false
|
||||
})
|
||||
|
||||
test('name 1', () => {
|
||||
name = '1'
|
||||
pureAddUser(name, setError, setName, addUserCallback)
|
||||
expect(name).toBe('')
|
||||
expect(error).toBe('')
|
||||
expect(added).toBe(true)
|
||||
})
|
||||
test('name 2', () => {
|
||||
name = ''
|
||||
pureAddUser(name, setError, setName, addUserCallback)
|
||||
expect(name).toBe('')
|
||||
expect(error).toBe('name is required!')
|
||||
expect(added).toBe(false)
|
||||
})
|
||||
test('name 3', () => {
|
||||
name = ' '
|
||||
pureAddUser(name, setError, setName, addUserCallback)
|
||||
expect(name).toBe(' ')
|
||||
expect(error).toBe('name is required!')
|
||||
expect(added).toBe(false)
|
||||
})
|
||||
18
src/s2-homeworks/hw03/tests/pureAddUserCallback.test.tsx
Normal file
18
src/s2-homeworks/hw03/tests/pureAddUserCallback.test.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import {pureAddUserCallback} from '../HW3'
|
||||
|
||||
let initialState: any[]
|
||||
const setName = (a: any[]) => {
|
||||
initialState = a
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initialState = []
|
||||
})
|
||||
|
||||
test('name 1', () => {
|
||||
pureAddUserCallback('name', setName, initialState)
|
||||
expect(initialState.length).toBe(1)
|
||||
expect(initialState[0].name).toBe('name')
|
||||
expect(!!initialState[0]._id).toBe(true)
|
||||
})
|
||||
29
src/s2-homeworks/hw03/tests/pureOnBlur.test.tsx
Normal file
29
src/s2-homeworks/hw03/tests/pureOnBlur.test.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import {pureOnBlur} from '../GreetingContainer'
|
||||
|
||||
let name: any
|
||||
let error: any
|
||||
const setError = (a: any) => {
|
||||
error = a
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
name = ''
|
||||
error = ''
|
||||
})
|
||||
|
||||
test('name 1', () => {
|
||||
name = '1'
|
||||
pureOnBlur(name, setError)
|
||||
expect(error).toBe('')
|
||||
})
|
||||
test('name 2', () => {
|
||||
name = ''
|
||||
pureOnBlur(name, setError)
|
||||
expect(error).toBe('name is required!')
|
||||
})
|
||||
test('name 3', () => {
|
||||
name = ' '
|
||||
pureOnBlur(name, setError)
|
||||
expect(error).toBe('name is required!')
|
||||
})
|
||||
20
src/s2-homeworks/hw03/tests/pureOnEnter.test.tsx
Normal file
20
src/s2-homeworks/hw03/tests/pureOnEnter.test.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import {pureOnEnter} from '../GreetingContainer'
|
||||
|
||||
let added: any
|
||||
const addUser = () => {
|
||||
added = true
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
added = false
|
||||
})
|
||||
|
||||
test('name 1', () => {
|
||||
pureOnEnter({key: 'Enter'} as any, addUser)
|
||||
expect(added).toBe(true)
|
||||
})
|
||||
test('name 2', () => {
|
||||
pureOnEnter({key: ''} as any, addUser)
|
||||
expect(added).toBe(false)
|
||||
})
|
||||
Reference in New Issue
Block a user