add prettier and reformat all files

This commit is contained in:
2022-07-11 12:23:43 +02:00
parent 35e4d96726
commit dfab85da65
72 changed files with 1065 additions and 823 deletions

7
.prettierrc.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
trailingComma: 'es5',
tabWidth: 4,
semi: false,
singleQuote: true,
endOfLine: 'auto',
}

View File

@@ -1,56 +1,57 @@
{ {
"name": "home-works", "name": "home-works",
"homepage": "https://IgnatZakalinsky.github.io/home-works", "homepage": "https://IgnatZakalinsky.github.io/home-works",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@emotion/react": "^11.9.3", "@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3", "@emotion/styled": "^11.9.3",
"@mui/material": "^5.8.4", "@mui/material": "^5.8.4",
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0", "@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1", "@testing-library/user-event": "^13.2.1",
"@types/jest": "^27.0.1", "@types/jest": "^27.0.1",
"@types/node": "^16.7.13", "@types/node": "^16.7.13",
"@types/react": "^18.0.0", "@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0", "@types/react-dom": "^18.0.0",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"axios": "^0.27.2", "axios": "^0.27.2",
"gh-pages": "^4.0.0", "gh-pages": "^4.0.0",
"react": "^18.1.0", "prettier": "^2.7.1",
"react-dom": "^18.1.0", "react": "^18.1.0",
"react-redux": "^8.0.2", "react-dom": "^18.1.0",
"react-router-dom": "^6.3.0", "react-redux": "^8.0.2",
"react-scripts": "5.0.1", "react-router-dom": "^6.3.0",
"redux": "^4.2.0", "react-scripts": "5.0.1",
"typescript": "^4.4.2", "redux": "^4.2.0",
"uuid": "^8.3.2", "typescript": "^4.4.2",
"web-vitals": "^2.1.0" "uuid": "^8.3.2",
}, "web-vitals": "^2.1.0"
"scripts": { },
"start": "react-scripts start", "scripts": {
"build": "react-scripts build", "start": "react-scripts start",
"test": "react-scripts test", "build": "react-scripts build",
"eject": "react-scripts eject", "test": "react-scripts test",
"predeploy": "npm run build", "eject": "react-scripts eject",
"deploy": "gh-pages -d build" "predeploy": "npm run build",
}, "deploy": "gh-pages -d build"
"eslintConfig": { },
"extends": [ "eslintConfig": {
"react-app", "extends": [
"react-app/jest" "react-app",
] "react-app/jest"
}, ]
"browserslist": { },
"production": [ "browserslist": {
">0.2%", "production": [
"not dead", ">0.2%",
"not op_mini all" "not dead",
], "not op_mini all"
"development": [ ],
"last 1 chrome version", "development": [
"last 1 firefox version", "last 1 chrome version",
"last 1 safari version" "last 1 firefox version",
] "last 1 safari version"
} ]
}
} }

View File

@@ -1,21 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" data-theme="1"> <html lang="en" data-theme="1">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Web site created using create-react-app" content="Web site created using create-react-app"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML. Only files inside the `public` folder can be referenced from the HTML.
@@ -24,12 +24,12 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>React App</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!-- <!--
This HTML file is a template. This HTML file is a template.
If you open it directly in the browser, you will see an empty page. If you open it directly in the browser, you will see an empty page.
@@ -38,6 +38,5 @@
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> --></body>
</body>
</html> </html>

View File

@@ -1,25 +1,25 @@
{ {
"short_name": "React App", "short_name": "React App",
"name": "Create React App Sample", "name": "Create React App Sample",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon" "type": "image/x-icon"
}, },
{ {
"src": "logo192.png", "src": "logo192.png",
"type": "image/png", "type": "image/png",
"sizes": "192x192" "sizes": "192x192"
}, },
{ {
"src": "logo512.png", "src": "logo512.png",
"type": "image/png", "type": "image/png",
"sizes": "512x512" "sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#000000",
"background_color": "#ffffff" "background_color": "#ffffff"
} }

View File

@@ -7,17 +7,16 @@
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
'Helvetica Neue', sans-serif; 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
box-sizing: border-box; box-sizing: border-box;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }
[data-theme='1'] { [data-theme='1'] {
@@ -68,7 +67,6 @@ code {
--success: #16a34a; --success: #16a34a;
--warning: #d97706; --warning: #d97706;
--error: #dc2626; --error: #dc2626;
} }
html { html {

View File

@@ -3,16 +3,14 @@ import ReactDOM from 'react-dom/client'
import './index.css' import './index.css'
import App from './s1-main/App' import App from './s1-main/App'
import reportWebVitals from './reportWebVitals' import reportWebVitals from './reportWebVitals'
import {Provider} from 'react-redux' import { Provider } from 'react-redux'
import store from './s2-homeworks/hw10/bll/store' import store from './s2-homeworks/hw10/bll/store'
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
document.getElementById('root') as HTMLElement
)
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<Provider store={store}> <Provider store={store}>
<App/> <App />
</Provider> </Provider>
</React.StrictMode> </React.StrictMode>
) )

View File

@@ -1,15 +1,17 @@
import { ReportHandler } from 'web-vitals'; import { ReportHandler } from 'web-vitals'
const reportWebVitals = (onPerfEntry?: ReportHandler) => { const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) { if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { import('web-vitals').then(
getCLS(onPerfEntry); ({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getFID(onPerfEntry); getCLS(onPerfEntry)
getFCP(onPerfEntry); getFID(onPerfEntry)
getLCP(onPerfEntry); getFCP(onPerfEntry)
getTTFB(onPerfEntry); getLCP(onPerfEntry)
}); getTTFB(onPerfEntry)
} }
}; )
}
}
export default reportWebVitals; export default reportWebVitals

View File

@@ -3,7 +3,6 @@
} }
.hw { .hw {
} }
.hwTitle { .hwTitle {
@@ -25,5 +24,5 @@
hr { hr {
border-top: 1px solid #d9d9d9; border-top: 1px solid #d9d9d9;
margin: 0 margin: 0;
} }

View File

@@ -25,7 +25,7 @@ const App = () => {
{/*<HW3/>*/} {/*<HW3/>*/}
{/*<HW4/>*/} {/*<HW4/>*/}
<HW5/> <HW5 />
</div> </div>
) )
} }

View File

@@ -4,38 +4,48 @@ import s from './Message.module.css'
// создать тип вместо any и отобразить приходящие данные // создать тип вместо any и отобразить приходящие данные
const FriendMessage = (props: any) => { const FriendMessage = (props: any) => {
return ( return (
<div id={'hw1-friend-message-' + props.message.id} className={s.friendMessage}> <div
id={'hw1-friend-message-' + props.message.id}
className={s.friendMessage}
>
<div className={s.friendImageAndMessage}> <div className={s.friendImageAndMessage}>
<img <img
id={'hw1-friend-avatar-' + props.message.id} id={'hw1-friend-avatar-' + props.message.id}
// создаёт студент // создаёт студент
src={props.message.user.avatar} src={props.message.user.avatar}
width={'50px'} height={'50px'} width={'50px'}
height={'50px'}
alt={'avatar'} alt={'avatar'}
// //
/> />
<div className={s.friendMessageText}> <div className={s.friendMessageText}>
<div id={'hw1-friend-name-' + props.message.id} className={s.friendName}> <div
id={'hw1-friend-name-' + props.message.id}
className={s.friendName}
>
{/*создаёт студент*/} {/*создаёт студент*/}
{props.message.user.name} {props.message.user.name}
{/**/} {/**/}
</div> </div>
<div id={'hw1-friend-text-' + props.message.id} className={s.friendText}> <div
id={'hw1-friend-text-' + props.message.id}
className={s.friendText}
>
{/*создаёт студент*/} {/*создаёт студент*/}
{props.message.message.text} {props.message.message.text}
{/**/} {/**/}
</div> </div>
</div> </div>
</div> </div>
<div id={'hw1-friend-time-' + props.message.id} className={s.friendTime}> <div
id={'hw1-friend-time-' + props.message.id}
className={s.friendTime}
>
{/*создаёт студент*/} {/*создаёт студент*/}
{props.message.message.time} {props.message.message.time}
{/**/} {/**/}
</div> </div>
</div> </div>
) )
} }

View File

@@ -32,7 +32,6 @@ export const friendMessage0: MessageType = {
}, },
} }
const HW1 = () => { const HW1 = () => {
return ( return (
<div id={'hw1'} className={s2.hw}> <div id={'hw1'} className={s2.hw}>
@@ -40,21 +39,20 @@ const HW1 = () => {
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>Homework #1</div> <div className={s2.hwTitle}>Homework #1</div>
<hr/> <hr />
<div className={s2.hwContainer}> <div className={s2.hwContainer}>
{/*проверка отображения (не менять)*/} {/*проверка отображения (не менять)*/}
<div> <div>
<Message message={message0}/> <Message message={message0} />
{/*не обязательно*/} {/*не обязательно*/}
<FriendMessage message={friendMessage0}/> <FriendMessage message={friendMessage0} />
</div> </div>
{/*для автоматической проверки дз (не менять)*/} {/*для автоматической проверки дз (не менять)*/}
<MessageSender M={Message}/> <MessageSender M={Message} />
</div> </div>
{/*<hr/>*/} {/*<hr/>*/}
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr /> <hr />

View File

@@ -63,7 +63,8 @@
max-width: 70%; max-width: 70%;
height: 100%; height: 100%;
background-color: #06c; background-color: #06c;
box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03), 0 1px 2px rgba(29, 33, 38, 0.1); box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03),
0 1px 2px rgba(29, 33, 38, 0.1);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-right: 20px; margin-right: 20px;
@@ -119,7 +120,8 @@
.textarea { .textarea {
box-sizing: border-box; box-sizing: border-box;
background: #f5f7fb; background: #f5f7fb;
box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03), 0 1px 2px rgba(29, 33, 38, 0.1); box-shadow: 0 5px 20px rgba(29, 33, 38, 0.03),
0 1px 2px rgba(29, 33, 38, 0.1);
border-radius: 20px; border-radius: 20px;
width: 100%; width: 100%;
border: none; border: none;
@@ -173,4 +175,3 @@ img {
width: 48px; width: 48px;
text-align: center; text-align: center;
} }

View File

@@ -11,7 +11,6 @@ const Message = (props: MessagePropsType) => {
<div className={s.imageAndMessage}> <div className={s.imageAndMessage}>
<img <img
id={'hw1-avatar-' + props.message.id} id={'hw1-avatar-' + props.message.id}
// создаёт студент // создаёт студент
src={props.message.user.avatar} src={props.message.user.avatar}
alt={'avatar'} alt={'avatar'}
@@ -36,7 +35,6 @@ const Message = (props: MessagePropsType) => {
{/**/} {/**/}
</div> </div>
</div> </div>
) )
} }

View File

@@ -9,33 +9,44 @@ const MessageSender = (props: any) => {
const [text, setText] = useState<any>('') const [text, setText] = useState<any>('')
const addMessage = () => { const addMessage = () => {
setMessages([...messages, { setMessages([
id: messages.length ? messages.length + 1 : 1, ...messages,
user: message0.user, {
message: { id: messages.length ? messages.length + 1 : 1,
text, user: message0.user,
time: new Date().toTimeString().slice(0, 5), message: {
text,
time: new Date().toTimeString().slice(0, 5),
},
}, },
}]) ])
setTimeout(() => setText(''), 4) setTimeout(() => setText(''), 4)
} }
return ( return (
<> <>
{messages.map(m => <M key={'message' + m.id} message={m}/>)} {messages.map((m) => (
<M key={'message' + m.id} message={m} />
))}
<div id={'hw1-send-message-form'} className={s.sendForm}> <div id={'hw1-send-message-form'} className={s.sendForm}>
<textarea <textarea
id={'hw1-textarea'} id={'hw1-textarea'}
value={text} value={text}
onChange={e => setText(e.currentTarget.value)} onChange={(e) => setText(e.currentTarget.value)}
placeholder={'Type your message'} placeholder={'Type your message'}
onKeyDown={e => e.key === 'Enter' && e.shiftKey && addMessage()} onKeyDown={(e) =>
e.key === 'Enter' && e.shiftKey && addMessage()
}
title={'Shift+Enter for send'} title={'Shift+Enter for send'}
className={s.textarea} className={s.textarea}
rows={1} rows={1}
/> />
<button id={'hw1-button'} onClick={addMessage} className={s.button}> <button
id={'hw1-button'}
onClick={addMessage}
className={s.button}
>
{/*текст кнопки могут изменить студенты*/} {/*текст кнопки могут изменить студенты*/}
Send Send
{/**/} {/**/}

View File

@@ -9,12 +9,17 @@ type AffairPropsType = {
} }
function Affair(props: AffairPropsType) { function Affair(props: AffairPropsType) {
const deleteCallback = () => {props.deleteAffairCallback(props.affair._id)} // need to fix // создаёт студент const deleteCallback = () => {
props.deleteAffairCallback(props.affair._id)
} // need to fix // создаёт студент
const priorityClass = s.item + ' ' + s[props.affair.priority] const priorityClass = s.item + ' ' + s[props.affair.priority]
return ( return (
<div id={'hw2-affair-' + props.affair._id} className={s.affair + ' ' + s[props.affair.priority]}> <div
id={'hw2-affair-' + props.affair._id}
className={s.affair + ' ' + s[props.affair.priority]}
>
<div id={'hw2-name-' + props.affair._id} className={priorityClass}> <div id={'hw2-name-' + props.affair._id} className={priorityClass}>
{/*создаёт студент*/} {/*создаёт студент*/}
{props.affair.name} {props.affair.name}
@@ -33,9 +38,7 @@ function Affair(props: AffairPropsType) {
onClick={deleteCallback} // создаёт студент onClick={deleteCallback} // создаёт студент
className={priorityClass + ' ' + s.closeButton} className={priorityClass + ' ' + s.closeButton}
> >
{/*текст кнопки могут изменить студенты*/} {/*текст кнопки могут изменить студенты*/}X{/**/}
X
{/**/}
</button> </button>
</div> </div>
) )

View File

@@ -69,7 +69,6 @@
display: flex; display: flex;
gap: 24px; gap: 24px;
margin-bottom: 32px; margin-bottom: 32px;
} }
.closeButton { .closeButton {

View File

@@ -3,7 +3,8 @@ import Affair from './Affair'
import { AffairType, FilterType } from './HW2' import { AffairType, FilterType } from './HW2'
import s from './Affairs.module.css' import s from './Affairs.module.css'
type AffairsPropsType = { // need to fix any type AffairsPropsType = {
// need to fix any
data: any // AffairType[] data: any // AffairType[]
setFilter: any // (filter: FilterType) => void setFilter: any // (filter: FilterType) => void
// setFilter: Dispatch<SetStateAction<FilterType>> // setFilter: Dispatch<SetStateAction<FilterType>>
@@ -36,10 +37,22 @@ function Affairs(props: AffairsPropsType) {
// props.setFilter(e.currentTarget.value as FilterType) // props.setFilter(e.currentTarget.value as FilterType)
// } // }
const cnAll = s.button + ' ' + s.all + ' ' + (props.filter === 'all' ? s.active : '') const cnAll =
const cnHigh = s.button + ' ' + s.high + ' ' + (props.filter === 'high' ? s.active : '') s.button + ' ' + s.all + ' ' + (props.filter === 'all' ? s.active : '')
const cnMiddle = s.button + ' ' + s.middle + ' ' + (props.filter === 'middle' ? s.active : '') const cnHigh =
const cnLow = s.button + ' ' + s.low + ' ' + (props.filter === 'low' ? s.active : '') s.button +
' ' +
s.high +
' ' +
(props.filter === 'high' ? s.active : '')
const cnMiddle =
s.button +
' ' +
s.middle +
' ' +
(props.filter === 'middle' ? s.active : '')
const cnLow =
s.button + ' ' + s.low + ' ' + (props.filter === 'low' ? s.active : '')
// const setClass = (filter: FilterType) => { // const setClass = (filter: FilterType) => {
// return s.button + (props.filter === filter ? ' ' + s.active : '') // return s.button + (props.filter === filter ? ' ' + s.active : '')
// } // }
@@ -47,14 +60,36 @@ function Affairs(props: AffairsPropsType) {
return ( return (
<div className={s.container}> <div className={s.container}>
<div className={s.buttonContainer}> <div className={s.buttonContainer}>
<button id={'hw2-button-all'} onClick={setAll} className={cnAll}>All</button> <button
<button id={'hw2-button-high'} onClick={setHigh} className={cnHigh}>High</button> id={'hw2-button-all'}
<button id={'hw2-button-middle'} onClick={setMiddle} className={cnMiddle}>Middle</button> onClick={setAll}
<button id={'hw2-button-low'} onClick={setLow} className={cnLow}>Low</button> className={cnAll}
</div> >
<div className={s.affairs}> All
{mappedAffairs} </button>
<button
id={'hw2-button-high'}
onClick={setHigh}
className={cnHigh}
>
High
</button>
<button
id={'hw2-button-middle'}
onClick={setMiddle}
className={cnMiddle}
>
Middle
</button>
<button
id={'hw2-button-low'}
onClick={setLow}
className={cnLow}
>
Low
</button>
</div> </div>
<div className={s.affairs}>{mappedAffairs}</div>
{/*<button onClick={set} className={setClass('all')} value={'all'}>All</button>*/} {/*<button onClick={set} className={setClass('all')} value={'all'}>All</button>*/}
{/*<button onClick={set} className={setClass('high')} value={'high'}>High</button>*/} {/*<button onClick={set} className={setClass('high')} value={'high'}>High</button>*/}
{/*<button onClick={set} className={setClass('middle')} value={'middle'}>Middle</button>*/} {/*<button onClick={set} className={setClass('middle')} value={'middle'}>Middle</button>*/}

View File

@@ -1,11 +1,7 @@
import React from 'react' import React from 'react'
function AlternativeAffairs() { function AlternativeAffairs() {
return ( return <div></div>
<div>
</div>
)
} }
export default AlternativeAffairs export default AlternativeAffairs

View File

@@ -13,26 +13,29 @@ export type AffairType = {
export type FilterType = 'all' | AffairPriorityType export type FilterType = 'all' | AffairPriorityType
// constants // constants
const defaultAffairs: any = [ // need to fix any // AffairType[] const defaultAffairs: any = [
{_id: 1, name: 'React', priority: 'high'}, // студенты могут изменить содержимое name и количество элементов в массиве, ...priority не менять! // need to fix any // AffairType[]
{_id: 2, name: 'anime', priority: 'low'}, { _id: 1, name: 'React', priority: 'high' }, // студенты могут изменить содержимое name и количество элементов в массиве, ...priority не менять!
{_id: 3, name: 'games', priority: 'low'}, { _id: 2, name: 'anime', priority: 'low' },
{_id: 4, name: 'work', priority: 'high'}, { _id: 3, name: 'games', priority: 'low' },
{_id: 5, name: 'html & css', priority: 'middle'}, { _id: 4, name: 'work', priority: 'high' },
{ _id: 5, name: 'html & css', priority: 'middle' },
] ]
// pure helper functions // pure helper functions
export const filterAffairs = (affairs: any, filter: any): any => { // need to fix any // (affairs: AffairType[], filter: FilterType): AffairType[] export const filterAffairs = (affairs: any, filter: any): any => {
// need to fix any // (affairs: AffairType[], filter: FilterType): AffairType[]
if (filter === 'all') return affairs // создаёт студент if (filter === 'all') return affairs // создаёт студент
// else if (filter === 'low') return affairs.filter(a => a.priority === 'low') // else if (filter === 'low') return affairs.filter(a => a.priority === 'low')
// else if (filter === 'middle') return affairs.filter(a => a.priority === 'middle') // else if (filter === 'middle') return affairs.filter(a => a.priority === 'middle')
// else if (filter === 'high') return affairs.filter(a => a.priority === 'high') // else if (filter === 'high') return affairs.filter(a => a.priority === 'high')
// else { // else {
// } // }
// return [] // return []
else return affairs.filter((a: any) => a.priority === filter) // need to fix // создаёт студент else return affairs.filter((a: any) => a.priority === filter) // need to fix // создаёт студент
} }
export const deleteAffair = (affairs: any, _id: any): any => { // need to fix any // (affairs: AffairType[], _id: number): AffairType[] export const deleteAffair = (affairs: any, _id: any): any => {
// need to fix any // (affairs: AffairType[], _id: number): AffairType[]
return affairs.filter((a: any) => a._id !== _id) // need to fix // создаёт студент return affairs.filter((a: any) => a._id !== _id) // need to fix // создаёт студент
} }
@@ -41,15 +44,16 @@ function HW2() {
const [filter, setFilter] = useState<any>('all') // need to fix any // FilterType const [filter, setFilter] = useState<any>('all') // need to fix any // FilterType
const filteredAffairs = filterAffairs(affairs, filter) const filteredAffairs = filterAffairs(affairs, filter)
const deleteAffairCallback = (_id: any) => setAffairs(deleteAffair(affairs, _id)) // need to fix any // number const deleteAffairCallback = (_id: any) =>
setAffairs(deleteAffair(affairs, _id)) // need to fix any // number
return ( return (
<div id={'hw2'} className={s2.hw} style={{marginTop: '39px'}}> <div id={'hw2'} className={s2.hw} style={{ marginTop: '39px' }}>
{/*<hr/>*/} {/*<hr/>*/}
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>Homework #2</div> <div className={s2.hwTitle}>Homework #2</div>
<hr/> <hr />
{/*не менять*/} {/*не менять*/}
<Affairs <Affairs
@@ -61,7 +65,7 @@ function HW2() {
{/*<hr/>*/} {/*<hr/>*/}
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -1,16 +1,16 @@
import React from 'react' import React from 'react'
import {AffairType, deleteAffair} from '../HW2' import { AffairType, deleteAffair } from '../HW2'
let initialState: AffairType[] let initialState: AffairType[]
beforeEach(() => { beforeEach(() => {
initialState = [ initialState = [
{_id: 1, name: 'React', priority: 'high'}, { _id: 1, name: 'React', priority: 'high' },
{_id: 2, name: 'anime', priority: 'low'}, { _id: 2, name: 'anime', priority: 'low' },
{_id: 3, name: 'games', priority: 'low'}, { _id: 3, name: 'games', priority: 'low' },
{_id: 4, name: 'work', priority: 'high'}, { _id: 4, name: 'work', priority: 'high' },
{_id: 5, name: 'html & css', priority: 'middle'}, { _id: 5, name: 'html & css', priority: 'middle' },
{_id: 6, name: 'porn', priority: 'low'}, { _id: 6, name: 'porn', priority: 'low' },
] ]
}) })

View File

@@ -1,16 +1,16 @@
import React from 'react' import React from 'react'
import {AffairType, filterAffairs} from '../HW2' import { AffairType, filterAffairs } from '../HW2'
let initialState: AffairType[] let initialState: AffairType[]
beforeEach(() => { beforeEach(() => {
initialState = [ initialState = [
{_id: 1, name: 'React', priority: 'high'}, { _id: 1, name: 'React', priority: 'high' },
{_id: 2, name: 'anime', priority: 'low'}, { _id: 2, name: 'anime', priority: 'low' },
{_id: 3, name: 'games', priority: 'low'}, { _id: 3, name: 'games', priority: 'low' },
{_id: 4, name: 'work', priority: 'high'}, { _id: 4, name: 'work', priority: 'high' },
{_id: 5, name: 'html & css', priority: 'middle'}, { _id: 5, name: 'html & css', priority: 'middle' },
{_id: 6, name: 'porn', priority: 'low'}, { _id: 6, name: 'porn', priority: 'low' },
] ]
}) })

View File

@@ -1,61 +1,61 @@
.greetingForm { .greetingForm {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 31px 0 0 70px; padding: 31px 0 0 70px;
height: 336px; height: 336px;
} }
.inputAndButtonContainer { .inputAndButtonContainer {
display: flex; display: flex;
gap: 24px; gap: 24px;
margin-bottom: 22px; margin-bottom: 22px;
} }
.error { .error {
margin-top: 7px; margin-top: 7px;
color: #cc0000; color: #cc0000;
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 17px; line-height: 17px;
} }
.input { .input {
border: 1px solid #d1d1d1; border: 1px solid #d1d1d1;
border-radius: 5px; border-radius: 5px;
width: 370px; width: 370px;
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
font-size: 16px; font-size: 16px;
line-height: 20px; line-height: 20px;
padding: 8px 0 8px 12px; padding: 8px 0 8px 12px;
color: #000; color: #000;
} }
.input:focus { .input:focus {
outline: none; outline: none;
border: 1px solid #06c; border: 1px solid #06c;
} }
.errorInput { .errorInput {
border: 1px solid #cc0000; border: 1px solid #cc0000;
} }
.button { .button {
margin-left: 12px; margin-left: 12px;
background: #06c; background: #06c;
color: white; color: white;
border: none; border: none;
border-radius: 3px; border-radius: 3px;
outline: none; outline: none;
padding: 8px 24px; padding: 8px 24px;
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
font-weight: 600; font-weight: 600;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
cursor: pointer; cursor: pointer;
height: 36px; height: 36px;
} }
.button:focus { .button:focus {
@@ -65,16 +65,16 @@
} }
.button:disabled { .button:disabled {
opacity: 0.5; opacity: 0.5;
cursor: default; cursor: default;
} }
.count { .count {
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 17px; line-height: 17px;
margin-bottom: 9px; margin-bottom: 9px;
} }
.greeting { .greeting {

View File

@@ -14,13 +14,24 @@ type GreetingPropsType = {
// презентационная компонента (для верстальщика) // презентационная компонента (для верстальщика)
const Greeting: React.FC<GreetingPropsType> = ( const Greeting: React.FC<GreetingPropsType> = (
{name, setNameCallback, addUser, onEnter, error, totalUsers, lastUser, onBlur} // деструктуризация пропсов {
name,
setNameCallback,
addUser,
onEnter,
error,
totalUsers,
lastUser,
onBlur,
} // деструктуризация пропсов
) => { ) => {
const inputClass = error ? `${s.input} ${s.errorInput}` : s.input // need to fix with (?:) const inputClass = error ? `${s.input} ${s.errorInput}` : s.input // need to fix with (?:)
return ( return (
<div id={'hw3-form'} className={s.greetingForm}> <div id={'hw3-form'} className={s.greetingForm}>
<div id={'hw3-users-total'} className={s.count}>{totalUsers}</div> <div id={'hw3-users-total'} className={s.count}>
{totalUsers}
</div>
<div className={s.inputAndButtonContainer}> <div className={s.inputAndButtonContainer}>
<div> <div>
<input <input
@@ -31,18 +42,24 @@ const Greeting: React.FC<GreetingPropsType> = (
onKeyDown={onEnter} onKeyDown={onEnter}
onBlur={onBlur} onBlur={onBlur}
/> />
<div id={'hw3-error'} className={s.error}>{error}</div> <div id={'hw3-error'} className={s.error}>
{error}
</div>
</div> </div>
<button id={'hw3-button'} onClick={addUser} className={s.button} disabled={!name}>add</button> <button
id={'hw3-button'}
onClick={addUser}
className={s.button}
disabled={!name}
>
add
</button>
</div> </div>
{lastUser && ( {lastUser && (
<div className={s.greeting}> <div className={s.greeting}>
hello{' '} hello <span id={'hw3-last-user'}>{lastUser}</span>!
<span id={'hw3-last-user'}>{lastUser}</span>
!
</div> </div>
)} )}
</div> </div>

View File

@@ -11,11 +11,16 @@ type GreetingContainerPropsType = {
// function GreetingContainer(props: GreetingPropsType) { // function GreetingContainer(props: GreetingPropsType) {
// более современный и удобный для про :) // более современный и удобный для про :)
const GreetingContainer: React.FC<GreetingContainerPropsType> = ({users, addUserCallback}) => { // деструктуризация пропсов const GreetingContainer: React.FC<GreetingContainerPropsType> = ({
users,
addUserCallback,
}) => {
// деструктуризация пропсов
const [name, setName] = useState<string>('') // need to fix any const [name, setName] = useState<string>('') // need to fix any
const [error, setError] = useState<string>('') // need to fix any const [error, setError] = useState<string>('') // need to fix any
const setNameCallback = (e: ChangeEvent<HTMLInputElement>) => { // need to fix any // нельзя пробелы перед и после имени, можно в середине const setNameCallback = (e: ChangeEvent<HTMLInputElement>) => {
// need to fix any // нельзя пробелы перед и после имени, можно в середине
setName(e.currentTarget.value) // need to fix setName(e.currentTarget.value) // need to fix
error && setError('') error && setError('')
} }

View File

@@ -6,14 +6,15 @@ import GreetingContainer from './GreetingContainer'
// types // types
export type UserType = { export type UserType = {
_id: string// need to fix any _id: string // need to fix any
name: string // need to fix any name: string // need to fix any
} }
const HW3 = () => { const HW3 = () => {
const [users, setUsers] = useState<UserType[]>([]) // need to fix any const [users, setUsers] = useState<UserType[]>([]) // need to fix any
const addUserCallback = (name: string) => { // need to fix any const addUserCallback = (name: string) => {
// need to fix any
const user = { const user = {
_id: v1(), _id: v1(),
name, name,
@@ -30,11 +31,13 @@ const HW3 = () => {
{/*для автоматической проверки дз (не менять)*/} {/*для автоматической проверки дз (не менять)*/}
<hr />
<hr/>
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<GreetingContainer users={users} addUserCallback={addUserCallback}/> <GreetingContainer
<hr/> users={users}
addUserCallback={addUserCallback}
/>
<hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -8,12 +8,12 @@ const HW4 = () => {
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>Homework #4</div> <div className={s2.hwTitle}>Homework #4</div>
<hr/> <hr />
{/*проверка отображения*/} {/*проверка отображения*/}
{/*демонстрация возможностей компонент:*/} {/*демонстрация возможностей компонент:*/}
<Stand/> <Stand />
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
{/*<hr/>*/} {/*<hr/>*/}
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}

View File

@@ -22,4 +22,4 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 36px; gap: 36px;
} }

View File

@@ -1,8 +1,8 @@
import React, {useState} from 'react' import React, { useState } from 'react'
import s from './Stand.module.css' import s from './Stand.module.css'
import SuperInputText from './common/c1-SuperInputText/SuperInputText' import SuperInputText from './common/c1-SuperInputText/SuperInputText'
import SuperCheckbox from './common/c3-SuperCheckbox/SuperCheckbox' import SuperCheckbox from './common/c3-SuperCheckbox/SuperCheckbox'
import SuperButton from "./common/c2-SuperButton/SuperButton"; import SuperButton from './common/c2-SuperButton/SuperButton'
const Stand = () => { const Stand = () => {
const [stateForAllInputs, setValue] = useState('') const [stateForAllInputs, setValue] = useState('')
@@ -21,7 +21,11 @@ const Stand = () => {
onChangeText={setValue} onChangeText={setValue}
error={error} error={error}
onEnter={() => { onEnter={() => {
setError(stateForAllInputs.trim() ? undefined : 'some error') setError(
stateForAllInputs.trim()
? undefined
: 'some error'
)
setValue('') setValue('')
}} }}
/> />
@@ -31,7 +35,7 @@ const Stand = () => {
<SuperInputText <SuperInputText
id={'hw4-super-input-like-old'} id={'hw4-super-input-like-old'}
value={stateForAllInputs} value={stateForAllInputs}
onChange={e => setValue(e.currentTarget.value)} onChange={(e) => setValue(e.currentTarget.value)}
/> />
</div> </div>
</div> </div>
@@ -39,17 +43,26 @@ const Stand = () => {
<div className={s.buttons}> <div className={s.buttons}>
{/*обычная кнопка:*/} {/*обычная кнопка:*/}
<div> <div>
<SuperButton id={'hw4-super-button-default'}>default</SuperButton> <SuperButton id={'hw4-super-button-default'}>
default
</SuperButton>
</div> </div>
{/*красная кнопка:*/} {/*красная кнопка:*/}
<div> <div>
<SuperButton id={'hw4-super-button-red'} xType={'red'}>red</SuperButton> <SuperButton id={'hw4-super-button-red'} xType={'red'}>
red
</SuperButton>
</div> </div>
{/*задизэйбленная кнопка:*/} {/*задизэйбленная кнопка:*/}
<div> <div>
<SuperButton id={'hw4-super-button-disabled'} xType={'red'} disabled>disabled</SuperButton> <SuperButton
id={'hw4-super-button-disabled'}
xType={'red'}
disabled
>
disabled
</SuperButton>
</div> </div>
</div> </div>
<div className={s.checkboxes}> <div className={s.checkboxes}>
@@ -68,7 +81,7 @@ const Stand = () => {
<SuperCheckbox <SuperCheckbox
id={'hw4-super-checkbox-like-old'} id={'hw4-super-checkbox-like-old'}
checked={stateForAllCheckboxes} checked={stateForAllCheckboxes}
onChange={e => setChecked(e.currentTarget.checked)} onChange={(e) => setChecked(e.currentTarget.checked)}
/> />
</div> </div>
</div> </div>

View File

@@ -1,29 +1,40 @@
import React, { ChangeEvent, DetailedHTMLProps, InputHTMLAttributes, KeyboardEvent, ReactNode } from 'react' import React, {
ChangeEvent,
DetailedHTMLProps,
InputHTMLAttributes,
KeyboardEvent,
ReactNode,
} from 'react'
import s from './SuperInputText.module.css' import s from './SuperInputText.module.css'
// тип пропсов обычного инпута // тип пропсов обычного инпута
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> type DefaultInputPropsType = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type // здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType) // (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
type SuperInputTextPropsType = Omit<DefaultInputPropsType, 'type'> & { // и + ещё пропсы которых нет в стандартном инпуте type SuperInputTextPropsType = Omit<DefaultInputPropsType, 'type'> & {
// и + ещё пропсы которых нет в стандартном инпуте
onChangeText?: (value: string) => void onChangeText?: (value: string) => void
onEnter?: () => void onEnter?: () => void
error?: ReactNode error?: ReactNode
spanClassName?: string spanClassName?: string
} }
const SuperInputText: React.FC<SuperInputTextPropsType> = ( const SuperInputText: React.FC<SuperInputTextPropsType> = ({
{ onChange,
onChange, onChangeText, onChangeText,
onKeyPress, onEnter, onKeyPress,
error, onEnter,
className, spanClassName, error,
id, className,
spanClassName,
id,
...restProps// все остальные пропсы попадут в объект restProps ...restProps // все остальные пропсы попадут в объект restProps
} }) => {
) => {
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => { const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
onChange?.(e) // если есть пропс onChange, то передать ему е (поскольку onChange не обязателен) onChange?.(e) // если есть пропс onChange, то передать ему е (поскольку onChange не обязателен)
@@ -32,13 +43,17 @@ const SuperInputText: React.FC<SuperInputTextPropsType> = (
const onKeyPressCallback = (e: KeyboardEvent<HTMLInputElement>) => { const onKeyPressCallback = (e: KeyboardEvent<HTMLInputElement>) => {
onKeyPress?.(e) onKeyPress?.(e)
onEnter // если есть пропс onEnter onEnter && // если есть пропс onEnter
&& e.key === 'Enter' // и если нажата кнопка Enter e.key === 'Enter' && // и если нажата кнопка Enter
&& onEnter() // то вызвать его onEnter() // то вызвать его
} }
const finalSpanClassName = `${s.error} ${spanClassName ? spanClassName : ''}` const finalSpanClassName = `${s.error} ${
const finalInputClassName = `${s.input} ${error ? s.errorInput : s.superInput} ${className}` // задача на смешивание классов spanClassName ? spanClassName : ''
}`
const finalInputClassName = `${s.input} ${
error ? s.errorInput : s.superInput
} ${className}` // задача на смешивание классов
return ( return (
<div className={s.inputWrapper}> <div className={s.inputWrapper}>
@@ -48,10 +63,14 @@ const SuperInputText: React.FC<SuperInputTextPropsType> = (
onChange={onChangeCallback} onChange={onChangeCallback}
onKeyPress={onKeyPressCallback} onKeyPress={onKeyPressCallback}
className={finalInputClassName} className={finalInputClassName}
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри) {...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
/> />
<span id={id ? id + '-span' : undefined} className={finalSpanClassName}>{error}</span> <span
id={id ? id + '-span' : undefined}
className={finalSpanClassName}
>
{error}
</span>
</div> </div>
) )
} }

View File

@@ -1,26 +1,24 @@
import React, {ButtonHTMLAttributes, DetailedHTMLProps} from 'react' import React, { ButtonHTMLAttributes, DetailedHTMLProps } from 'react'
import s from './SuperButton.module.css' import s from './SuperButton.module.css'
// тип пропсов обычной кнопки, children в котором храниться название кнопки там уже описан // тип пропсов обычной кнопки, children в котором храниться название кнопки там уже описан
type DefaultButtonPropsType = DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> type DefaultButtonPropsType = DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>
type SuperButtonPropsType = DefaultButtonPropsType & { type SuperButtonPropsType = DefaultButtonPropsType & {
xType?: string xType?: string
} }
const SuperButton: React.FC<SuperButtonPropsType> = ( const SuperButton: React.FC<SuperButtonPropsType> = ({
{ xType,
xType, className, className,
disabled, disabled,
...restProps// все остальные пропсы попадут в объект restProps, там же будет children ...restProps // все остальные пропсы попадут в объект restProps, там же будет children
} }) => {
) => {
const finalClassName = `${s.button} ${ const finalClassName = `${s.button} ${
disabled disabled ? s.disabled : xType === 'red' ? s.red : s.default
? s.disabled
: xType === 'red'
? s.red
: s.default
} ${className}` // задачка на смешивание классов } ${className}` // задачка на смешивание классов
return ( return (

View File

@@ -30,7 +30,7 @@
.checkbox:checked { .checkbox:checked {
appearance: none; appearance: none;
background-image: url("checked.svg"); background-image: url('checked.svg');
/*background: #99ff99;*/ /*background: #99ff99;*/
} }
@@ -41,4 +41,4 @@
.spanClassName { .spanClassName {
font-family: 'Montserrat', sans-serif; font-family: 'Montserrat', sans-serif;
color: #06c; color: #06c;
} }

View File

@@ -1,25 +1,33 @@
import React, {ChangeEvent, DetailedHTMLProps, InputHTMLAttributes} from 'react' import React, {
ChangeEvent,
DetailedHTMLProps,
InputHTMLAttributes,
} from 'react'
import s from './SuperCheckbox.module.css' import s from './SuperCheckbox.module.css'
// тип пропсов обычного инпута // тип пропсов обычного инпута
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> type DefaultInputPropsType = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
type SuperCheckboxPropsType = Omit<DefaultInputPropsType, 'type'> & { type SuperCheckboxPropsType = Omit<DefaultInputPropsType, 'type'> & {
onChangeChecked?: (checked: boolean) => void onChangeChecked?: (checked: boolean) => void
spanClassName?: string spanClassName?: string
} }
const SuperCheckbox: React.FC<SuperCheckboxPropsType> = ( const SuperCheckbox: React.FC<SuperCheckboxPropsType> = ({
{ onChange,
onChange, onChangeChecked, onChangeChecked,
className, spanClassName, className,
children, // в эту переменную попадёт текст, типизировать не нужно так как он затипизирован в React.FC spanClassName,
id, children, // в эту переменную попадёт текст, типизировать не нужно так как он затипизирован в React.FC
id,
...restProps// все остальные пропсы попадут в объект restProps ...restProps // все остальные пропсы попадут в объект restProps
} }) => {
) => { const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => { // задачка на написание онченджа // задачка на написание онченджа
onChange?.(e) onChange?.(e)
onChangeChecked?.(e.currentTarget.checked) onChangeChecked?.(e.currentTarget.checked)
@@ -34,10 +42,16 @@ const SuperCheckbox: React.FC<SuperCheckboxPropsType> = (
type={'checkbox'} type={'checkbox'}
onChange={onChangeCallback} onChange={onChangeCallback}
className={finalInputClassName} className={finalInputClassName}
{...restProps} // отдаём инпуту остальные пропсы если они есть (checked например там внутри) {...restProps} // отдаём инпуту остальные пропсы если они есть (checked например там внутри)
/> />
{children && <span id={id ? id + '-span' : undefined} className={s.spanClassName}>{children}</span>} {children && (
<span
id={id ? id + '-span' : undefined}
className={s.spanClassName}
>
{children}
</span>
)}
</label> // благодаря label нажатие на спан передастся в инпут </label> // благодаря label нажатие на спан передастся в инпут
) )
} }

View File

@@ -8,7 +8,7 @@ function HW5() {
<HashRouter> <HashRouter>
{/*в gh-pages лучше работает HashRouter*/} {/*в gh-pages лучше работает HashRouter*/}
<Layout> <Layout>
<Pages/> <Pages />
</Layout> </Layout>
</HashRouter> </HashRouter>
) )

View File

@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {Routes, Route, Navigate} from 'react-router-dom' import { Routes, Route, Navigate } from 'react-router-dom'
import Error404 from './pages/Error404' import Error404 from './pages/Error404'
import PreJunior from './pages/PreJunior' import PreJunior from './pages/PreJunior'
import Junior from './pages/Junior' import Junior from './pages/Junior'
@@ -16,18 +16,16 @@ function Pages() {
<div> <div>
{/*Routes выбирает первый подходящий роут*/} {/*Routes выбирает первый подходящий роут*/}
<Routes> <Routes>
{/*роутинг будут писать студенты*/} {/*роутинг будут писать студенты*/}
{/*в начале мы попадаем на страницу '/' и переходим сразу на страницу PRE_JUNIOR*/} {/*в начале мы попадаем на страницу '/' и переходим сразу на страницу PRE_JUNIOR*/}
<Route path={'/'} element={<Navigate to={PATH.PRE_JUNIOR}/>}/> <Route path={'/'} element={<Navigate to={PATH.PRE_JUNIOR} />} />
<Route path={PATH.PRE_JUNIOR} element={<PreJunior/>}/> <Route path={PATH.PRE_JUNIOR} element={<PreJunior />} />
<Route path={PATH.JUNIOR} element={<Junior/>}/> <Route path={PATH.JUNIOR} element={<Junior />} />
<Route path={PATH.JUNIOR_PLUS} element={<JuniorPlus/>}/> <Route path={PATH.JUNIOR_PLUS} element={<JuniorPlus />} />
{/*он отрисуется если пользователь захочет попасть на несуществующую страницу*/} {/*он отрисуется если пользователь захочет попасть на несуществующую страницу*/}
<Route path={'/*'} element={<Error404/>}/> <Route path={'/*'} element={<Error404 />} />
</Routes> </Routes>
</div> </div>
) )

View File

@@ -7,21 +7,19 @@ type PropsType = {
handleOpen: () => void handleOpen: () => void
} }
export const Header: FC<PropsType> = ({open, handleOpen}) => { export const Header: FC<PropsType> = ({ open, handleOpen }) => {
// hw5-menu изначально отсутствует, при нажатии на бургер - появляется, при повторном нажатии исчезает // hw5-menu изначально отсутствует, при нажатии на бургер - появляется, при повторном нажатии исчезает
return ( return (
<> <>
<div id={'hw5-header'} className={s.header}> <div id={'hw5-header'} className={s.header}>
<img src={burgerIcon} <img
id={'hw5-burger-menu'} src={burgerIcon}
className={s.burgerMenuIcon} id={'hw5-burger-menu'}
onClick={handleOpen} className={s.burgerMenuIcon}
alt={'open menu'}/> onClick={handleOpen}
alt={'open menu'}
/>
</div> </div>
</> </>
) )
} }

View File

@@ -6,7 +6,7 @@ type PropsType = {
children: ReactNode children: ReactNode
} }
export const Layout: FC<PropsType> = ({children}) => { export const Layout: FC<PropsType> = ({ children }) => {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const handleClose = () => setOpen(false) const handleClose = () => setOpen(false)
const handleOpen = () => setOpen(true) const handleOpen = () => setOpen(true)
@@ -17,11 +17,9 @@ export const Layout: FC<PropsType> = ({children}) => {
return ( return (
<> <>
<Sidebar open={open} handleClose={handleClose}/> <Sidebar open={open} handleClose={handleClose} />
<Header open={open} handleOpen={handleOpen}/> <Header open={open} handleOpen={handleOpen} />
{children} {children}
</> </>
) )
} }

View File

@@ -11,4 +11,4 @@
display: flex; display: flex;
height: calc(100vh - var(--header_height)); height: calc(100vh - var(--header_height));
justify-content: center; justify-content: center;
} }

View File

@@ -8,12 +8,12 @@ function Junior() {
return ( return (
<div id={'hw5-page-junior'}> <div id={'hw5-page-junior'}>
junior page junior page
<HW6/> <HW6 />
<HW7/> <HW7 />
<HW8/> <HW8 />
<HW9/> <HW9 />
</div> </div>
) )
} }
export default Junior export default Junior

View File

@@ -8,12 +8,12 @@ function JuniorPlus() {
return ( return (
<div id={'hw5-page-junior-plus'}> <div id={'hw5-page-junior-plus'}>
junior plus page junior plus page
<HW10/> <HW10 />
<HW11/> <HW11 />
<HW12/> <HW12 />
<HW13/> <HW13 />
</div> </div>
) )
} }
export default JuniorPlus export default JuniorPlus

View File

@@ -8,12 +8,12 @@ function PreJunior() {
return ( return (
<div id={'hw5-page-pre-junior'}> <div id={'hw5-page-pre-junior'}>
{/*pre junior page*/} {/*pre junior page*/}
<HW1/> <HW1 />
<HW2/> <HW2 />
<HW3/> <HW3 />
<HW4/> <HW4 />
</div> </div>
) )
} }
export default PreJunior export default PreJunior

View File

@@ -12,7 +12,8 @@
} }
.sidebar.open { .sidebar.open {
box-shadow: 0 10px 40px rgba(29, 33, 38, 0.13), 0 1px 2px rgba(29, 33, 38, 0.1); box-shadow: 0 10px 40px rgba(29, 33, 38, 0.13),
0 1px 2px rgba(29, 33, 38, 0.1);
left: 0; left: 0;
position: fixed; position: fixed;
transition: 0.2s ease-out; transition: 0.2s ease-out;
@@ -69,4 +70,4 @@
.close img { .close img {
height: 24px; height: 24px;
width: 24px; width: 24px;
} }

View File

@@ -9,28 +9,27 @@ type PropsType = {
handleClose: () => void handleClose: () => void
} }
export const Sidebar: FC<PropsType> = ({open, handleClose}) => { export const Sidebar: FC<PropsType> = ({ open, handleClose }) => {
return ( return (
<> <>
{/*бэкграунд справа от открытого меню*/} {/*бэкграунд справа от открытого меню*/}
{open && <div className={s.background} onClick={handleClose}/>} {open && <div className={s.background} onClick={handleClose} />}
<aside className={`${s.sidebar} ${open ? s.open : ''}`}> <aside className={`${s.sidebar} ${open ? s.open : ''}`}>
<button className={s.close} onClick={handleClose}> <button className={s.close} onClick={handleClose}>
<img <img
src={closeIcon} src={closeIcon}
alt='close sidebar' alt="close sidebar"
id={'hw5-menu-close'} id={'hw5-menu-close'}
/> />
</button> </button>
<nav id={'hw5-menu'} className={s.nav}> <nav id={'hw5-menu'} className={s.nav}>
<NavLink <NavLink
id={'hw5-pre-junior-link'} id={'hw5-pre-junior-link'}
to={PATH.PRE_JUNIOR} to={PATH.PRE_JUNIOR}
onClick={handleClose} onClick={handleClose}
className={({isActive}) => isActive ? s.active : ''} // делает студент className={({ isActive }) => (isActive ? s.active : '')} // делает студент
> >
Pre-junior Pre-junior
</NavLink> </NavLink>
@@ -38,7 +37,7 @@ export const Sidebar: FC<PropsType> = ({open, handleClose}) => {
id={'hw5-junior-link'} id={'hw5-junior-link'}
to={PATH.JUNIOR} to={PATH.JUNIOR}
onClick={handleClose} onClick={handleClose}
className={({isActive}) => isActive ? s.active : ''} // делает студент className={({ isActive }) => (isActive ? s.active : '')} // делает студент
> >
Junior Junior
</NavLink> </NavLink>
@@ -46,14 +45,12 @@ export const Sidebar: FC<PropsType> = ({open, handleClose}) => {
id={'hw5-junior-plus-link'} id={'hw5-junior-plus-link'}
to={PATH.JUNIOR_PLUS} to={PATH.JUNIOR_PLUS}
onClick={handleClose} onClick={handleClose}
className={({isActive}) => isActive ? s.active : ''} // делает студент className={({ isActive }) => (isActive ? s.active : '')} // делает студент
> >
Junior+ Junior+
</NavLink> </NavLink>
</nav> </nav>
</aside> </aside>
</> </>
) )
} }

View File

@@ -1,6 +1,6 @@
import React, {useState} from 'react' import React, { useState } from 'react'
import SuperEditableSpan from './common/c4-SuperEditableSpan/SuperEditableSpan' import SuperEditableSpan from './common/c4-SuperEditableSpan/SuperEditableSpan'
import {restoreState, saveState} from './localStorage/localStorage' import { restoreState, saveState } from './localStorage/localStorage'
import s2 from '../../s1-main/App.module.css' import s2 from '../../s1-main/App.module.css'
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton' import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
@@ -10,13 +10,14 @@ const HW6 = () => {
const save = () => { const save = () => {
saveState<string>('hw6-editable-span-value', value) saveState<string>('hw6-editable-span-value', value)
} }
const restore = () => { // делают студенты const restore = () => {
// делают студенты
setValue(restoreState<string>('hw6-editable-span-value', '')) setValue(restoreState<string>('hw6-editable-span-value', ''))
} }
return ( return (
<div id={'hw6'} className={s2.hw}> <div id={'hw6'} className={s2.hw}>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 6</div> <div className={s2.hwTitle}>homeworks 6</div>
@@ -27,15 +28,22 @@ const HW6 = () => {
id={'hw6-spanable-input'} id={'hw6-spanable-input'}
value={value} value={value}
onChangeText={setValue} onChangeText={setValue}
spanProps={{children: value ? undefined : 'enter text...', id: 'hw6-editable-span'}} spanProps={{
children: value ? undefined : 'enter text...',
id: 'hw6-editable-span',
}}
/> />
</div> </div>
<SuperButton id={'hw6-save'} onClick={save}>save to ls</SuperButton> <SuperButton id={'hw6-save'} onClick={save}>
<SuperButton id={'hw6-restore'} onClick={restore}>get from ls</SuperButton> save to ls
</SuperButton>
<SuperButton id={'hw6-restore'} onClick={restore}>
get from ls
</SuperButton>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -6,4 +6,4 @@
cursor: pointer; cursor: pointer;
color: #77aaff; color: #77aaff;
} }

View File

@@ -1,15 +1,27 @@
import React, {DetailedHTMLProps, InputHTMLAttributes, HTMLAttributes, useState} from 'react' import React, {
DetailedHTMLProps,
InputHTMLAttributes,
HTMLAttributes,
useState,
} from 'react'
import s from './SuperEditableSpan.module.css' import s from './SuperEditableSpan.module.css'
import SuperInputText from '../../../hw04/common/c1-SuperInputText/SuperInputText' import SuperInputText from '../../../hw04/common/c1-SuperInputText/SuperInputText'
// тип пропсов обычного инпута // тип пропсов обычного инпута
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> type DefaultInputPropsType = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
// тип пропсов обычного спана // тип пропсов обычного спана
type DefaultSpanPropsType = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> type DefaultSpanPropsType = DetailedHTMLProps<
HTMLAttributes<HTMLSpanElement>,
HTMLSpanElement
>
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type // здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType) // (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & { // и + ещё пропсы которых нет в стандартном инпуте type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & {
// и + ещё пропсы которых нет в стандартном инпуте
onChangeText?: (value: string) => void onChangeText?: (value: string) => void
onEnter?: () => void onEnter?: () => void
error?: string error?: string
@@ -17,18 +29,17 @@ type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & { // и + е
spanProps?: DefaultSpanPropsType // пропсы для спана spanProps?: DefaultSpanPropsType // пропсы для спана
} }
const SuperEditableSpan: React.FC<SuperEditableSpanType> = ( const SuperEditableSpan: React.FC<SuperEditableSpanType> = ({
{ autoFocus,
autoFocus, onBlur,
onBlur, onEnter,
onEnter, spanProps,
spanProps,
...restProps// все остальные пропсы попадут в объект restProps ...restProps // все остальные пропсы попадут в объект restProps
} }) => {
) => {
const [editMode, setEditMode] = useState<boolean>(false) const [editMode, setEditMode] = useState<boolean>(false)
const {children, onDoubleClick, className, ...restSpanProps} = spanProps || {} const { children, onDoubleClick, className, ...restSpanProps } =
spanProps || {}
const onEnterCallback = () => { const onEnterCallback = () => {
setEditMode(false) // выключить editMode при нажатии Enter // делают студенты setEditMode(false) // выключить editMode при нажатии Enter // делают студенты
@@ -40,7 +51,9 @@ const SuperEditableSpan: React.FC<SuperEditableSpanType> = (
onBlur?.(e) onBlur?.(e)
} }
const onDoubleClickCallBack = (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => { const onDoubleClickCallBack = (
e: React.MouseEvent<HTMLSpanElement, MouseEvent>
) => {
setEditMode(true) // включить editMode при двойном клике // делают студенты setEditMode(true) // включить editMode при двойном клике // делают студенты
onDoubleClick?.(e) onDoubleClick?.(e)
@@ -50,27 +63,23 @@ const SuperEditableSpan: React.FC<SuperEditableSpanType> = (
return ( return (
<> <>
{editMode {editMode ? (
? ( <SuperInputText
<SuperInputText autoFocus={autoFocus || true}
autoFocus={autoFocus || true} onBlur={onBlurCallback}
onBlur={onBlurCallback} onEnter={onEnterCallback}
onEnter={onEnterCallback} {...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
/>
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри) ) : (
/> <span
) : ( onDoubleClick={onDoubleClickCallBack}
<span className={spanClassName}
onDoubleClick={onDoubleClickCallBack} {...restSpanProps}
className={spanClassName} >
{/*если нет захардкодженного текста для спана, то значение инпута*/}
{...restSpanProps} {children || restProps.value}
> </span>
{/*если нет захардкодженного текста для спана, то значение инпута*/} )}
{children || restProps.value}
</span>
)
}
</> </>
) )
} }

View File

@@ -21,7 +21,7 @@ type StateType = {
} }
// сохраняем объект типа StateType в ячейке 'test' // сохраняем объект типа StateType в ячейке 'test'
saveState<StateType>('test', {x: 'A', y: 1}) saveState<StateType>('test', { x: 'A', y: 1 })
// получем в переменную state объект из ячейки 'test' или дэфолтный объект если ячейка пуста // получем в переменную state объект из ячейки 'test' или дэфолтный объект если ячейка пуста
const state: StateType = restoreState<StateType>('test', {x: '', y: 0}) const state: StateType = restoreState<StateType>('test', { x: '', y: 0 })

View File

@@ -1,9 +1,13 @@
import React, {useState} from 'react' import React, { useState } from 'react'
import SuperSelect from './common/c5-SuperSelect/SuperSelect' import SuperSelect from './common/c5-SuperSelect/SuperSelect'
import SuperRadio from './common/c6-SuperRadio/SuperRadio' import SuperRadio from './common/c6-SuperRadio/SuperRadio'
import s2 from '../../s1-main/App.module.css' import s2 from '../../s1-main/App.module.css'
const arr = [{id: 1, value: 'x'}, {id: 2, value: 'y'}, {id: 3, value: 'z'}] // value может быть изменено const arr = [
{ id: 1, value: 'x' },
{ id: 2, value: 'y' },
{ id: 3, value: 'z' },
] // value может быть изменено
const HW7 = () => { const HW7 = () => {
const [value, onChangeOption] = useState(1) // селект и радио должны работать синхронно const [value, onChangeOption] = useState(1) // селект и радио должны работать синхронно
@@ -11,7 +15,7 @@ const HW7 = () => {
return ( return (
<div id={'hw7'} className={s2.hw}> <div id={'hw7'} className={s2.hw}>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 7</div> <div className={s2.hwTitle}>homeworks 7</div>
@@ -35,9 +39,9 @@ const HW7 = () => {
/> />
</div> </div>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -1,37 +1,37 @@
.select { .select {
width: 100px; width: 100px;
padding: 5px; padding: 5px;
cursor: pointer; cursor: pointer;
appearance: none; appearance: none;
background-color: var(--primary); background-color: var(--primary);
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
linear-gradient(135deg, currentColor 50%, transparent 50%); linear-gradient(135deg, currentColor 50%, transparent 50%);
background-position: calc(100% - 20px) calc(1px + 50%), background-position: calc(100% - 20px) calc(1px + 50%),
calc(100% - 16px) calc(1px + 50%); calc(100% - 16px) calc(1px + 50%);
background-size: 4px 4px, 4px 4px; background-size: 4px 4px, 4px 4px;
background-repeat: no-repeat; background-repeat: no-repeat;
border-radius: 2px; border-radius: 2px;
border: 2px solid var(--primary); border: 2px solid var(--primary);
color: var(--primary-content); color: var(--primary-content);
} }
.select:focus { .select:focus {
outline: none; outline: none;
} }
.option { .option {
/*padding: 30px;*/ /*padding: 30px;*/
color: var(--primary-content); color: var(--primary-content);
background: var(--primary); background: var(--primary);
} }
.option:checked { .option:checked {
color: var(--secondary-content); color: var(--secondary-content);
background: var(--primary); background: var(--primary);
} }
.option:hover { .option:hover {
box-shadow: 0 0 10px 100px #fed20f inset; box-shadow: 0 0 10px 100px #fed20f inset;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
background: red; background: red;
} }

View File

@@ -1,37 +1,54 @@
import React, {SelectHTMLAttributes, DetailedHTMLProps, ChangeEvent} from 'react' import React, {
SelectHTMLAttributes,
DetailedHTMLProps,
ChangeEvent,
} from 'react'
import s from './SuperSelect.module.css' import s from './SuperSelect.module.css'
type DefaultSelectPropsType = DetailedHTMLProps<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement> type DefaultSelectPropsType = DetailedHTMLProps<
SelectHTMLAttributes<HTMLSelectElement>,
HTMLSelectElement
>
type SuperSelectPropsType = DefaultSelectPropsType & { type SuperSelectPropsType = DefaultSelectPropsType & {
options?: any[] options?: any[]
onChangeOption?: (option: any) => void onChangeOption?: (option: any) => void
} }
const SuperSelect: React.FC<SuperSelectPropsType> = ( const SuperSelect: React.FC<SuperSelectPropsType> = ({
{ options,
options, className, className,
onChange, onChangeOption, onChange,
...restProps onChangeOption,
} ...restProps
) => { }) => {
const mappedOptions: any[] = options ? options.map(o => ( const mappedOptions: any[] = options
<option id={'hw7-option-' + o.id} className={s.option} key={o.id} value={o.id}>{o.value}</option> ? options.map((o) => (
)) : [] // map options with key <option
id={'hw7-option-' + o.id}
className={s.option}
key={o.id}
value={o.id}
>
{o.value}
</option>
))
: [] // map options with key
const onChangeCallback = (e: ChangeEvent<HTMLSelectElement>) => { // делают студенты const onChangeCallback = (e: ChangeEvent<HTMLSelectElement>) => {
// делают студенты
onChange?.(e) onChange?.(e)
onChangeOption?.(+e.currentTarget.value) onChangeOption?.(+e.currentTarget.value)
} }
const finalSelectClassName = s.select + ( const finalSelectClassName = s.select + (className ? ' ' + className : '')
className
? ' ' + className
: ''
)
return ( return (
<select className={finalSelectClassName} onChange={onChangeCallback} {...restProps}> <select
className={finalSelectClassName}
onChange={onChangeCallback}
{...restProps}
>
{mappedOptions} {mappedOptions}
</select> </select>
) )

View File

@@ -23,4 +23,4 @@
.label { .label {
cursor: pointer; cursor: pointer;
} }

View File

@@ -1,9 +1,20 @@
import React, {ChangeEvent, InputHTMLAttributes, DetailedHTMLProps, HTMLAttributes} from 'react' import React, {
ChangeEvent,
InputHTMLAttributes,
DetailedHTMLProps,
HTMLAttributes,
} from 'react'
import s from './SuperRadio.module.css' import s from './SuperRadio.module.css'
type DefaultRadioPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> type DefaultRadioPropsType = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
// тип пропсов обычного спана // тип пропсов обычного спана
type DefaultSpanPropsType = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> type DefaultSpanPropsType = DetailedHTMLProps<
HTMLAttributes<HTMLSpanElement>,
HTMLSpanElement
>
type SuperRadioPropsType = Omit<DefaultRadioPropsType, 'type'> & { type SuperRadioPropsType = Omit<DefaultRadioPropsType, 'type'> & {
options?: any[] options?: any[]
@@ -12,54 +23,53 @@ type SuperRadioPropsType = Omit<DefaultRadioPropsType, 'type'> & {
spanProps?: DefaultSpanPropsType // пропсы для спана spanProps?: DefaultSpanPropsType // пропсы для спана
} }
const SuperRadio: React.FC<SuperRadioPropsType> = ( const SuperRadio: React.FC<SuperRadioPropsType> = ({
{ id,
id, name,
name, className, className,
options, value, options,
onChange, onChangeOption, value,
spanProps, onChange,
...restProps onChangeOption,
} spanProps,
) => { ...restProps
}) => {
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => { const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
onChange?.(e) onChange?.(e)
onChangeOption?.(+e.currentTarget.value) onChangeOption?.(+e.currentTarget.value)
} }
const finalRadioClassName = `${s.radio} ${className ? className : ''}` const finalRadioClassName = `${s.radio} ${className ? className : ''}`
const spanClassName = `${s.span} ${spanProps?.className ? spanProps.className : ''}` const spanClassName = `${s.span} ${
spanProps?.className ? spanProps.className : ''
}`
const mappedOptions: any[] = options ? options.map(o => ( const mappedOptions: any[] = options
<label key={name + '-' + o.id} className={s.label}> ? options.map((o) => (
<input <label key={name + '-' + o.id} className={s.label}>
id={id + '-input-' + o.id} <input
className={finalRadioClassName} id={id + '-input-' + o.id}
type={'radio'} className={finalRadioClassName}
type={'radio'}
// name, checked, value делают студенты
name={name}
checked={o.id === value}
value={o.id}
onChange={onChangeCallback}
{...restProps}
/>
<span
id={id + '-span-' + o.id}
{...spanProps}
className={spanClassName}
>
{o.value}
</span>
</label>
))
: []
// name, checked, value делают студенты return <>{mappedOptions}</>
name={name}
checked={o.id === value}
value={o.id}
onChange={onChangeCallback}
{...restProps}
/>
<span
id={id + '-span-' + o.id}
{...spanProps}
className={spanClassName}
>
{o.value}
</span>
</label>
)) : []
return (
<>
{mappedOptions}
</>
)
} }
export default SuperRadio export default SuperRadio

View File

@@ -4,4 +4,4 @@
width: 200px; width: 200px;
margin-left: 10px; margin-left: 10px;
} }

View File

@@ -1,55 +1,70 @@
import React, {useState} from 'react' import React, { useState } from 'react'
import {homeWorkReducer} from './bll/homeWorkReducer' import { homeWorkReducer } from './bll/homeWorkReducer'
import s from './HW8.module.css' import s from './HW8.module.css'
import s2 from '../../s1-main/App.module.css' import s2 from '../../s1-main/App.module.css'
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton' import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
import User from './User' import User from './User'
export type UserType = { // need to fix any export type UserType = {
// need to fix any
_id: number _id: number
name: string name: string
age: number age: number
} }
const initialPeople: UserType[] = [ // студенты могут поменять имя/возраст/количество объектов, _id должны быть целочисленные const initialPeople: UserType[] = [
{_id: 0, name: 'Кот', age: 3}, // студенты могут поменять имя/возраст/количество объектов, _id должны быть целочисленные
{_id: 1, name: 'Александр', age: 66}, { _id: 0, name: 'Кот', age: 3 },
{_id: 2, name: 'Коля', age: 16}, { _id: 1, name: 'Александр', age: 66 },
{_id: 3, name: 'Виктор', age: 44}, { _id: 2, name: 'Коля', age: 16 },
{_id: 4, name: 'Дмитрий', age: 40}, { _id: 3, name: 'Виктор', age: 44 },
{_id: 5, name: 'Ирина', age: 55}, { _id: 4, name: 'Дмитрий', age: 40 },
{ _id: 5, name: 'Ирина', age: 55 },
] ]
const HW8 = () => { const HW8 = () => {
const [people, setPeople] = useState<UserType[]>(initialPeople) // need to fix any const [people, setPeople] = useState<UserType[]>(initialPeople) // need to fix any
// need to fix any // need to fix any
const finalPeople = people.map((u: UserType) => <User key={u._id} u={u}/>) const finalPeople = people.map((u: UserType) => <User key={u._id} u={u} />)
const sortUp = () => setPeople(homeWorkReducer(initialPeople, {type: 'sort', payload: 'up'})) // в алфавитном порядке a.name > b.name const sortUp = () =>
const sortDown = () => setPeople(homeWorkReducer(initialPeople, {type: 'sort', payload: 'down'})) // в обратном порядке a.name < b.name setPeople(
const check18 = () => setPeople(homeWorkReducer(initialPeople, {type: 'check', payload: 18})) // совершеннолетние homeWorkReducer(initialPeople, { type: 'sort', payload: 'up' })
) // в алфавитном порядке a.name > b.name
const sortDown = () =>
setPeople(
homeWorkReducer(initialPeople, { type: 'sort', payload: 'down' })
) // в обратном порядке a.name < b.name
const check18 = () =>
setPeople(
homeWorkReducer(initialPeople, { type: 'check', payload: 18 })
) // совершеннолетние
return ( return (
<div id={'hw3'} className={s2.hw}> <div id={'hw3'} className={s2.hw}>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 8</div> <div className={s2.hwTitle}>homeworks 8</div>
<div id={'hw8-users'}> <div id={'hw8-users'}>{finalPeople}</div>
{finalPeople}
</div>
<div> <div>
<SuperButton id={'hw8-button-up'} onClick={sortUp}>sort up</SuperButton> <SuperButton id={'hw8-button-up'} onClick={sortUp}>
<SuperButton id={'hw8-button-down'} onClick={sortDown}>sort down</SuperButton> sort up
<SuperButton id={'hw8-button-18'} onClick={check18}>check 18</SuperButton> </SuperButton>
<SuperButton id={'hw8-button-down'} onClick={sortDown}>
sort down
</SuperButton>
<SuperButton id={'hw8-button-18'} onClick={check18}>
check 18
</SuperButton>
</div> </div>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {UserType} from './HW8' import { UserType } from './HW8'
import s from './HW8.module.css' import s from './HW8.module.css'
// types // types
@@ -7,8 +7,7 @@ type UserPropsType = {
u: UserType u: UserType
} }
const User: React.FC<UserPropsType> = ({u}) => { const User: React.FC<UserPropsType> = ({ u }) => {
return ( return (
<div id={'hw8-user-' + u._id + '-' + u.age} className={s.item}> <div id={'hw8-user-' + u._id + '-' + u.age} className={s.item}>
<span id={'hw8-user-name-' + u._id}>{u.name}</span> <span id={'hw8-user-name-' + u._id}>{u.name}</span>

View File

@@ -1,9 +1,17 @@
import {UserType} from '../HW8' import { UserType } from '../HW8'
type ActionType = {type: 'sort', payload: 'up' | 'down'} | {type: 'check', payload: number} type ActionType =
| { type: 'sort'; payload: 'up' | 'down' }
| { type: 'check'; payload: number }
export const homeWorkReducer = (state: UserType[], action: ActionType): UserType[] => { // need to fix any export const homeWorkReducer = (
switch (action.type) { // делают студенты state: UserType[],
action: ActionType
): UserType[] => {
// need to fix any
switch (
action.type // делают студенты
) {
case 'sort': { case 'sort': {
const newState = [...state].sort((a, b) => { const newState = [...state].sort((a, b) => {
if (a.name > b.name) return 1 if (a.name > b.name) return 1
@@ -14,8 +22,9 @@ export const homeWorkReducer = (state: UserType[], action: ActionType): UserType
return action.payload === 'up' ? newState : newState.reverse() return action.payload === 'up' ? newState : newState.reverse()
} }
case 'check': { case 'check': {
return state.filter(a => a.age >= action.payload) return state.filter((a) => a.age >= action.payload)
} }
default: return state default:
return state
} }
} }

View File

@@ -1,32 +1,41 @@
import React from 'react' import React from 'react'
import {homeWorkReducer} from '../homeWorkReducer' import { homeWorkReducer } from '../homeWorkReducer'
import {UserType} from '../../HW8' import { UserType } from '../../HW8'
let initialState: UserType[] // need to fix any let initialState: UserType[] // need to fix any
beforeEach(() => { beforeEach(() => {
initialState = [ initialState = [
{_id: 0, name: 'Кот', age: 3}, { _id: 0, name: 'Кот', age: 3 },
{_id: 1, name: 'Александр', age: 66}, { _id: 1, name: 'Александр', age: 66 },
{_id: 2, name: 'Коля', age: 16}, { _id: 2, name: 'Коля', age: 16 },
{_id: 3, name: 'Виктор', age: 44}, { _id: 3, name: 'Виктор', age: 44 },
{_id: 4, name: 'Дмитрий', age: 40}, { _id: 4, name: 'Дмитрий', age: 40 },
{_id: 5, name: 'Ирина', age: 55}, { _id: 5, name: 'Ирина', age: 55 },
] ]
}) })
test('sort name up', () => { test('sort name up', () => {
const newState = homeWorkReducer(initialState, {type: 'sort', payload: 'up'}) const newState = homeWorkReducer(initialState, {
type: 'sort',
payload: 'up',
})
expect(newState[0]._id).toBe(1) expect(newState[0]._id).toBe(1)
}) })
test('sort name down', () => { test('sort name down', () => {
const newState = homeWorkReducer(initialState, {type: 'sort', payload: 'down'}) const newState = homeWorkReducer(initialState, {
type: 'sort',
payload: 'down',
})
expect(newState[0]._id).toBe(0) expect(newState[0]._id).toBe(0)
}) })
test('check age 18', () => { test('check age 18', () => {
const newState = homeWorkReducer(initialState, {type: 'check', payload: 18}) const newState = homeWorkReducer(initialState, {
type: 'check',
payload: 18,
})
expect(newState.length).toBe(4) expect(newState.length).toBe(4)
}) })

View File

@@ -1,19 +1,23 @@
import React, {useState} from 'react' import React, { useState } from 'react'
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton' import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
import {restoreState} from '../hw06/localStorage/localStorage' import { restoreState } from '../hw06/localStorage/localStorage'
function Clock() { function Clock() {
const [timerId, setTimerId] = useState<number | undefined>(undefined) const [timerId, setTimerId] = useState<number | undefined>(undefined)
const [date, setDate] = useState<Date>(new Date(restoreState('hw9-date', 0))) // for autotests const [date, setDate] = useState<Date>(
new Date(restoreState('hw9-date', 0))
) // for autotests
const [show, setShow] = useState<boolean>(false) const [show, setShow] = useState<boolean>(false)
const stop = () => { // пишут студенты const stop = () => {
// пишут студенты
if (timerId) { if (timerId) {
clearInterval(timerId) clearInterval(timerId)
setTimerId(undefined) setTimerId(undefined)
} }
} }
const start = () => { // пишут студенты const start = () => {
// пишут студенты
const id: number = +setInterval(() => { const id: number = +setInterval(() => {
setDate(new Date()) setDate(new Date())
}, 1000) }, 1000)
@@ -28,11 +32,11 @@ function Clock() {
} }
// логику напишет Андрей :) // |v| видел такое в реальных часах |v| // логику напишет Андрей :) // |v| видел такое в реальных часах |v|
const stringTime = date?.toLocaleTimeString() || <br/> // часы24:минуты:секунды (01:02:03)/(23:02:03)/(24:00:00)/(00:00:01) // пишут студенты const stringTime = date?.toLocaleTimeString() || <br /> // часы24:минуты:секунды (01:02:03)/(23:02:03)/(24:00:00)/(00:00:01) // пишут студенты
const stringDate = date?.toLocaleDateString() || <br/> // день.месяц.год (01.02.2022) // пишут студенты, варианты 01.02.0123/01.02.-123/01.02.12345 не рассматриваем const stringDate = date?.toLocaleDateString() || <br /> // день.месяц.год (01.02.2022) // пишут студенты, варианты 01.02.0123/01.02.-123/01.02.12345 не рассматриваем
// день недели на английском, месяц на английском // день недели на английском, месяц на английском
const stringDay = 'Monday' || <br/> // пишут студенты const stringDay = 'Monday' || <br /> // пишут студенты
const stringMonth = 'May' || <br/> // пишут студенты const stringMonth = 'May' || <br /> // пишут студенты
return ( return (
<div> <div>
@@ -53,13 +57,12 @@ function Clock() {
</> </>
) : ( ) : (
<> <>
<br/> <br />
<br/> <br />
</> </>
)} )}
</div> </div>
<SuperButton <SuperButton
id={'hw9-button-start'} id={'hw9-button-start'}
disabled={!!timerId} // пишут студенты disabled={!!timerId} // пишут студенты

View File

@@ -5,17 +5,17 @@ import s2 from '../../s1-main/App.module.css'
const HW9 = () => { const HW9 = () => {
return ( return (
<div id={'hw9'} className={s2.hw}> <div id={'hw9'} className={s2.hw}>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 9</div> <div className={s2.hwTitle}>homeworks 9</div>
{/*should work (должно работать)*/} {/*should work (должно работать)*/}
<Clock/> <Clock />
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -1,13 +1,15 @@
import React from 'react' import React from 'react'
import {useDispatch, useSelector} from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import {AppStoreType} from './bll/store' import { AppStoreType } from './bll/store'
import {loadingAC} from './bll/loadingReducer' import { loadingAC } from './bll/loadingReducer'
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton' import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
import s2 from '../../s1-main/App.module.css' import s2 from '../../s1-main/App.module.css'
const HW10 = () => { const HW10 = () => {
// useSelector, useDispatch // useSelector, useDispatch
const isLoading = useSelector<AppStoreType, boolean>((state: any) => state.loading.isLoading) const isLoading = useSelector<AppStoreType, boolean>(
(state: any) => state.loading.isLoading
)
const dispatch = useDispatch() const dispatch = useDispatch()
const setLoading = () => { const setLoading = () => {
@@ -23,25 +25,28 @@ const HW10 = () => {
return ( return (
<div id={'hw10'} className={s2.hw}> <div id={'hw10'} className={s2.hw}>
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 10</div> <div className={s2.hwTitle}>homeworks 10</div>
{/*should work (должно работать)*/} {/*should work (должно работать)*/}
{isLoading {isLoading ? (
? ( <div id={'hw10-loading'}>крутилка...</div>
<div id={'hw10-loading'}>крутилка...</div> ) : (
) : ( <div>
<div> <SuperButton
<SuperButton id={'hw10-button-start-loading'} onClick={setLoading}>set loading...</SuperButton> id={'hw10-button-start-loading'}
</div> onClick={setLoading}
) >
} set loading...
</SuperButton>
</div>
)}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr/> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )

View File

@@ -1,16 +1,21 @@
const initState = { const initState = {
isLoading: false isLoading: false,
} }
export const loadingReducer = (state = initState, action: LoadingActionType): typeof initState=> { // fix any export const loadingReducer = (
state = initState,
action: LoadingActionType
): typeof initState => {
// fix any
switch (action.type) { switch (action.type) {
case 'CHANGE_LOADING': { case 'CHANGE_LOADING': {
return { return {
...state, ...state,
isLoading: action.isLoading isLoading: action.isLoading,
} }
} }
default: return state default:
return state
} }
} }
@@ -19,4 +24,7 @@ type LoadingActionType = {
isLoading: boolean isLoading: boolean
} }
export const loadingAC = (isLoading: boolean): LoadingActionType => ({type: 'CHANGE_LOADING', isLoading}) // fix any export const loadingAC = (isLoading: boolean): LoadingActionType => ({
type: 'CHANGE_LOADING',
isLoading,
}) // fix any

View File

@@ -1,6 +1,6 @@
import {loadingReducer} from './loadingReducer' import { loadingReducer } from './loadingReducer'
import {combineReducers, legacy_createStore} from 'redux' import { combineReducers, legacy_createStore } from 'redux'
import {themeReducer} from '../../hw12/bll/themeReducer' import { themeReducer } from '../../hw12/bll/themeReducer'
const reducers = combineReducers({ const reducers = combineReducers({
loading: loadingReducer, // hw10 loading: loadingReducer, // hw10

View File

@@ -6,69 +6,69 @@ import { restoreState } from '../hw06/localStorage/localStorage'
import { Slider } from '@mui/material' import { Slider } from '@mui/material'
function HW11() { function HW11() {
const [value1, setValue1] = useState(restoreState<number>('hw11-value1', 0)) const [value1, setValue1] = useState(restoreState<number>('hw11-value1', 0))
const [value2, setValue2] = useState( const [value2, setValue2] = useState(
restoreState<number>('hw11-value2', 100) restoreState<number>('hw11-value2', 100)
) )
const change = (event: Event, newValue: number | number[]) => { const change = (event: Event, newValue: number | number[]) => {
if (Array.isArray(newValue)) { if (Array.isArray(newValue)) {
setValue1(newValue[0]) setValue1(newValue[0])
setValue2(newValue[1]) setValue2(newValue[1])
} else { } else {
setValue1(newValue) setValue1(newValue)
} }
} }
return ( return (
<div id={'hw11'} className={s2.hw}> <div id={'hw11'} className={s2.hw}>
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 11</div> <div className={s2.hwTitle}>homeworks 11</div>
{/*should work (должно работать)*/} {/*should work (должно работать)*/}
<div> <div>
<span <span
id={'hw11-value'} id={'hw11-value'}
style={{ display: 'inline-block', width: 32 }} style={{ display: 'inline-block', width: 32 }}
> >
{value1} {value1}
</span> </span>
<Slider <Slider
// сделать так чтоб value1 изменялось // сделать так чтоб value1 изменялось
value={value1} value={value1}
onChange={change} onChange={change}
sx={{ width: '160px' }} sx={{ width: '160px' }}
/> />
</div> </div>
<div> <div>
<span <span
id={'hw11-value-1'} id={'hw11-value-1'}
style={{ display: 'inline-block', width: 32 }} style={{ display: 'inline-block', width: 32 }}
> >
{value1} {value1}
</span> </span>
<Slider <Slider
value={[value1, value2]} value={[value1, value2]}
onChange={change} onChange={change}
sx={{ width: '160px' }} sx={{ width: '160px' }}
/> />
<span <span
id={'hw11-value-2'} id={'hw11-value-2'}
style={{ display: 'inline-block', width: 32 }} style={{ display: 'inline-block', width: 32 }}
> >
{value2} {value2}
</span> </span>
</div> </div>
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )
} }
export default HW11 export default HW11

View File

@@ -18,4 +18,4 @@
background: red; background: red;
cursor: pointer; cursor: pointer;
z-index: 2; z-index: 2;
} }

View File

@@ -1,24 +1,31 @@
import React, {ChangeEvent, DetailedHTMLProps, InputHTMLAttributes} from 'react' import React, {
ChangeEvent,
DetailedHTMLProps,
InputHTMLAttributes,
} from 'react'
import s from './SuperRange.module.css' import s from './SuperRange.module.css'
// тип пропсов обычного инпута // тип пропсов обычного инпута
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> type DefaultInputPropsType = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута // здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType) // (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
type SuperRangePropsType = DefaultInputPropsType & { // и + ещё пропсы которых нет в стандартном инпуте type SuperRangePropsType = DefaultInputPropsType & {
// и + ещё пропсы которых нет в стандартном инпуте
onChangeRange?: (value: number) => void onChangeRange?: (value: number) => void
}; }
const SuperRange: React.FC<SuperRangePropsType> = ( const SuperRange: React.FC<SuperRangePropsType> = ({
{ type, // достаём и игнорируем чтоб нельзя было задать другой тип инпута
type, // достаём и игнорируем чтоб нельзя было задать другой тип инпута onChange,
onChange, onChangeRange, onChangeRange,
className, className,
...restProps// все остальные пропсы попадут в объект restProps ...restProps // все остальные пропсы попадут в объект restProps
} }) => {
) => {
const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => { const onChangeCallback = (e: ChangeEvent<HTMLInputElement>) => {
onChange && onChange(e) // сохраняем старую функциональность onChange && onChange(e) // сохраняем старую функциональность
@@ -35,7 +42,6 @@ const SuperRange: React.FC<SuperRangePropsType> = (
type={'range'} type={'range'}
onChange={onChangeCallback} onChange={onChangeCallback}
className={finalRangeClassName} className={finalRangeClassName}
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри) {...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
/> />
</> </>

View File

@@ -1,7 +1,10 @@
import React, {DetailedHTMLProps, InputHTMLAttributes} from 'react' import React, { DetailedHTMLProps, InputHTMLAttributes } from 'react'
import SuperRange from '../c7-SuperRange/SuperRange' import SuperRange from '../c7-SuperRange/SuperRange'
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> type DefaultInputPropsType = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
type SuperDoubleRangePropsType = Omit<DefaultInputPropsType, 'value'> & { type SuperDoubleRangePropsType = Omit<DefaultInputPropsType, 'value'> & {
onChangeRange?: (value: [number, number]) => void onChangeRange?: (value: [number, number]) => void
@@ -9,13 +12,12 @@ type SuperDoubleRangePropsType = Omit<DefaultInputPropsType, 'value'> & {
// min, max, step, disable, ... // min, max, step, disable, ...
} }
const SuperDoubleRange: React.FC<SuperDoubleRangePropsType> = ( const SuperDoubleRange: React.FC<SuperDoubleRangePropsType> = ({
{ onChangeRange,
onChangeRange, value, value,
// min, max, step, disable, ... // min, max, step, disable, ...
...restProps ...restProps
} }) => {
) => {
// сделать самому, можно подключать библиотеки // сделать самому, можно подключать библиотеки
const [value1, value2] = value || [-1, -1] const [value1, value2] = value || [-1, -1]
@@ -28,9 +30,26 @@ const SuperDoubleRange: React.FC<SuperDoubleRangePropsType> = (
// взять двойной ползунок из материал-юай и повесить на него ид // взять двойной ползунок из материал-юай и повесить на него ид
return ( return (
<div id={'hw11-double-slider'} style={{position: "relative", display: "inline-block", width: 176}}> <div
<SuperRange style={{position: "absolute", top: -12}} value={value?.[0]} onChangeRange={change1} {...restProps}/> id={'hw11-double-slider'}
<SuperRange style={{position: "absolute", top: -12}} value={value?.[1]} onChangeRange={change2} {...restProps}/> style={{
position: 'relative',
display: 'inline-block',
width: 176,
}}
>
<SuperRange
style={{ position: 'absolute', top: -12 }}
value={value?.[0]}
onChangeRange={change1}
{...restProps}
/>
<SuperRange
style={{ position: 'absolute', top: -12 }}
value={value?.[1]}
onChangeRange={change2}
{...restProps}
/>
</div> </div>
) )
} }

View File

@@ -20,4 +20,4 @@
.some-text { .some-text {
color: darkslateblue; color: darkslateblue;
} }

View File

@@ -6,44 +6,44 @@ import { useDispatch, useSelector } from 'react-redux'
import { changeThemeId } from './bll/themeReducer' import { changeThemeId } from './bll/themeReducer'
const themes = [ const themes = [
{ id: 1, value: 'light' }, { id: 1, value: 'light' },
{ id: 2, value: 'dark' }, { id: 2, value: 'dark' },
{ id: 3, value: 'retro' }, { id: 3, value: 'retro' },
] ]
const HW12 = () => { const HW12 = () => {
const themeId = useSelector((state: any) => state.theme.themeId) const themeId = useSelector((state: any) => state.theme.themeId)
const theme = themes.find((t) => t.id === themeId)!.value const theme = themes.find((t) => t.id === themeId)!.value
const dispatch = useDispatch() const dispatch = useDispatch()
const change = (id: number) => { const change = (id: number) => {
dispatch(changeThemeId(id)) dispatch(changeThemeId(id))
} }
return ( return (
<div id={'hw12'} className={s2.hw + ' ' + s[theme]}> <div id={'hw12'} className={s2.hw + ' ' + s[theme]}>
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div <div
id={'hw12-text'} id={'hw12-text'}
className={s2.hwTitle + ' ' + s[theme + '-text']} className={s2.hwTitle + ' ' + s[theme + '-text']}
> >
homeworks 12 homeworks 12
</div> </div>
<SuperSelect <SuperSelect
id={'hw12-select-theme'} id={'hw12-select-theme'}
value={themeId} value={themeId}
options={themes} options={themes}
onChangeOption={change} onChangeOption={change}
/> />
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )
} }
export default HW12 export default HW12

View File

@@ -1,8 +1,9 @@
const initState = { const initState = {
themeId: 1 themeId: 1,
} }
export const themeReducer = (state = initState, action: any): any => { // fix any export const themeReducer = (state = initState, action: any): any => {
// fix any
switch (action.type) { switch (action.type) {
case 'SET_THEME_ID': { case 'SET_THEME_ID': {
return { return {
@@ -10,8 +11,9 @@ export const themeReducer = (state = initState, action: any): any => { // fix an
themeId: action.id, themeId: action.id,
} }
} }
default: return state default:
return state
} }
} }
export const changeThemeId = (id: number): any => ({type: 'SET_THEME_ID', id}) // fix any export const changeThemeId = (id: number): any => ({ type: 'SET_THEME_ID', id }) // fix any

View File

@@ -3,86 +3,86 @@ import s2 from '../../s1-main/App.module.css'
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton' import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
import axios from 'axios' import axios from 'axios'
axios.interceptors.response.use( axios.interceptors.response.use(
(response) => response, (response) => response,
(error) => { (error) => {
console.log(error) console.log(error)
if (typeof error.response === 'undefined') { if (typeof error.response === 'undefined') {
console.log(error) console.log(error)
} }
return Promise.reject(error) return Promise.reject(error)
} }
) )
const HW13 = () => { const HW13 = () => {
const [answer, setAnswer] = useState('') const [answer, setAnswer] = useState('')
const [info, setInfo] = useState('') const [info, setInfo] = useState('')
const send = (x?: boolean | null) => () => { const send = (x?: boolean | null) => () => {
const url = const url =
x === null x === null
? 'https://xxxxxx.ccc' ? 'https://xxxxxx.ccc'
: 'https://neko-cafe-back.herokuapp.com/auth/test' : 'https://neko-cafe-back.herokuapp.com/auth/test'
setAnswer('...loading') setAnswer('...loading')
setInfo('...loading') setInfo('...loading')
axios axios
.post(url, { success: x }) .post(url, { success: x })
.then((res) => { .then((res) => {
setAnswer(res.data.errorText) setAnswer(res.data.errorText)
setInfo(res.data.info) setInfo(res.data.info)
}) })
.catch((e) => { .catch((e) => {
console.log(e) console.log(e)
setAnswer(e.response?.data?.errorText || e.message) setAnswer(e.response?.data?.errorText || e.message)
setInfo(e.response?.data?.info || e.name) setInfo(e.response?.data?.info || e.name)
}) })
} }
return ( return (
<div id={'hw13'} className={s2.hw}> <div id={'hw13'} className={s2.hw}>
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<div className={s2.hwTitle}>homeworks 13</div> <div className={s2.hwTitle}>homeworks 13</div>
{/*для автоматической проверки дз (не менять)*/} {/*для автоматической проверки дз (не менять)*/}
<SuperButton <SuperButton
id={'hw13-send-true'} id={'hw13-send-true'}
onClick={send(true)} onClick={send(true)}
disabled={answer === '...loading'} disabled={answer === '...loading'}
> >
send true send true
</SuperButton> </SuperButton>
<SuperButton <SuperButton
id={'hw13-send-false'} id={'hw13-send-false'}
onClick={send(false)} onClick={send(false)}
disabled={answer === '...loading'} disabled={answer === '...loading'}
> >
send false send false
</SuperButton> </SuperButton>
<SuperButton <SuperButton
id={'hw13-send-undefined'} id={'hw13-send-undefined'}
onClick={send(undefined)} onClick={send(undefined)}
disabled={answer === '...loading'} disabled={answer === '...loading'}
> >
send undefined send undefined
</SuperButton> </SuperButton>
<SuperButton <SuperButton
id={'hw13-send-null'} id={'hw13-send-null'}
onClick={send(null)} onClick={send(null)}
disabled={answer === '...loading'} disabled={answer === '...loading'}
> >
send null send null
</SuperButton> </SuperButton>
<div id={'hw13-answer'}>{answer}</div> <div id={'hw13-answer'}>{answer}</div>
<div id={'hw13-info'}>{info}</div> <div id={'hw13-info'}>{info}</div>
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
<hr /> <hr />
{/*можно убрать этот тег*/} {/*можно убрать этот тег*/}
</div> </div>
) )
} }
export default HW13 export default HW13

View File

@@ -2,4 +2,4 @@
// allows you to do things like: // allows you to do things like:
// expect(element).toHaveTextContent(/react/i) // expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom // learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom'; import '@testing-library/jest-dom'

View File

@@ -1,26 +1,20 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"lib": [ "lib": ["dom", "dom.iterable", "esnext"],
"dom", "allowJs": true,
"dom.iterable", "skipLibCheck": true,
"esnext" "esModuleInterop": true,
], "allowSyntheticDefaultImports": true,
"allowJs": true, "strict": true,
"skipLibCheck": true, "forceConsistentCasingInFileNames": true,
"esModuleInterop": true, "noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true, "module": "esnext",
"strict": true, "moduleResolution": "node",
"forceConsistentCasingInFileNames": true, "resolveJsonModule": true,
"noFallthroughCasesInSwitch": true, "isolatedModules": true,
"module": "esnext", "noEmit": true,
"moduleResolution": "node", "jsx": "react-jsx"
"resolveJsonModule": true, },
"isolatedModules": true, "include": ["src"]
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
} }

View File

@@ -7358,6 +7358,11 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
prettier@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"