final ref hw3

This commit is contained in:
neko
2022-09-14 16:18:09 +03:00
parent 816a387f72
commit 018cd6422f
9 changed files with 210 additions and 64 deletions

View File

@@ -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/>*/}

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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}
/>
)
}

View File

@@ -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 (

View 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)
})

View 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)
})

View 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!')
})

View 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)
})