diff --git a/eslint.config.mjs b/eslint.config.mjs index b10bdd0..2417366 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -16,6 +16,7 @@ export default [ }, "rules": { "no-unused-vars": "off", + "react/prop-types": "off", "@typescript-eslint/no-unused-vars": [ "warn", // or "error" { diff --git a/locales/ru.json b/locales/ru.json new file mode 100644 index 0000000..e900945 --- /dev/null +++ b/locales/ru.json @@ -0,0 +1,3 @@ +{ + "key.to.override": "name: {{name}}" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 73f563e..9ef041b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "license": "ISC", "dependencies": { - "@brojs/cli": "^1.3.0", + "@brojs/cli": "1.4.0-alpha.2", "@chakra-ui/react": "^2.10.3", "@eslint/js": "^9.11.0", "@stylistic/eslint-plugin": "^2.8.0", @@ -1726,22 +1726,20 @@ } }, "node_modules/@brojs/cli": { - "version": "1.3.0", - "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fcli/-/1.3.0/cli-1.3.0.tgz", - "integrity": "sha512-qQYpMqglmVsd5Wt32NKKAGqjJQYKr1xXXNa5sVZkAiJTUHcEu3868SWB8voPQpxuQSogPkjuRvEjjrAF2mf+jA==", + "version": "1.4.0-alpha.2", + "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fcli/-/1.4.0-alpha.2/cli-1.4.0-alpha.2.tgz", + "integrity": "sha512-1bXiz2Gix1MLM91asWLIh+d054K2jr8pOnaiMopUpefGaO6NYlYUQKTUebo4M+QBF+2maym7wRdxDblgVJuvjg==", "license": "ISC", "dependencies": { "@brojs/dev-server": "^1.3.0", "@brojs/fire.app": "^1.3.0", + "@brojs/i18nextreactconfig": "^1.4.0-alpha.1", "@brojs/templates": "^1.3.0", "@brojs/utils": "^1.3.0", "@brojs/webpack-config": "^1.3.0", "axios": "^1.7.2", "chalk": "^5.3.0", - "commander": "^12.1.0", - "i18next-browser-languagedetector": "^8.0.0", - "i18next-http-backend": "^2.5.2", - "react-i18next": "^14.1.2" + "commander": "^12.1.0" }, "bin": { "brojs": "bin/cli.js" @@ -1770,6 +1768,18 @@ "integrity": "sha512-4jt/o944FttMUDU5fnGknaa8alz/0FaFATtgc5lVcsJ1Us4TKamHXtx4aj1hw6Pe89aBu61KLy8aCwNE24O0Mg==", "license": "ISC" }, + "node_modules/@brojs/i18nextreactconfig": { + "version": "1.4.0-alpha.1", + "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fi18nextreactconfig/-/1.4.0-alpha.1/i18nextreactconfig-1.4.0-alpha.1.tgz", + "integrity": "sha512-pFCEFw8cvfUlqFGqzr94i9qaq6DIJX6AotLZXXYvqPzouWlc+1f/O68NFw3S3Eqd/dW4pt3WyeqKqHaEYtlMpg==", + "license": "ISC", + "dependencies": { + "i18next": "^23.16.4", + "i18next-browser-languagedetector": "^8.0.0", + "i18next-http-backend": "^2.6.2", + "react-i18next": "^15.1.0" + } + }, "node_modules/@brojs/templates": { "version": "1.3.0", "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Ftemplates/-/1.3.0/templates-1.3.0.tgz", @@ -6373,9 +6383,9 @@ } }, "node_modules/i18next": { - "version": "23.16.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.2.tgz", - "integrity": "sha512-dFyxwLXxEQK32f6tITBMaRht25mZPJhQ0WbC0p3bO2mWBal9lABTMqSka5k+GLSRWLzeJBKDpH7BeIA9TZI7Jg==", + "version": "23.16.4", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.4.tgz", + "integrity": "sha512-9NIYBVy9cs4wIqzurf7nLXPyf3R78xYbxExVqHLK9od3038rjpyOEzW+XB130kZ1N4PZ9inTtJ471CRJ4Ituyg==", "funding": [ { "type": "individual", @@ -6391,7 +6401,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.23.2" } @@ -8469,12 +8478,12 @@ } }, "node_modules/react-i18next": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.3.tgz", - "integrity": "sha512-wZnpfunU6UIAiJ+bxwOiTmBOAaB14ha97MjOEnLGac2RJ+h/maIYXZuTHlmyqQVX1UVHmU1YDTQ5vxLmwfXTjw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.1.0.tgz", + "integrity": "sha512-zj3nJynMnZsy2gPZiOTC7XctCY5eQGqT3tcKMmfJWC9FMvgd+960w/adq61j8iPzpwmsXejqID9qC3Mqu1Xu2Q==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", + "@babel/runtime": "^7.25.0", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { diff --git a/package.json b/package.json index ab5d75e..bba5013 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "license": "ISC", "description": "", "dependencies": { - "@brojs/cli": "^1.3.0", + "@brojs/cli": "1.4.0-alpha.2", "@chakra-ui/react": "^2.10.3", "@eslint/js": "^9.11.0", "@stylistic/eslint-plugin": "^2.8.0", diff --git a/src/components/profile/profile.tsx b/src/components/profile/profile.tsx index 7129973..f528539 100644 --- a/src/components/profile/profile.tsx +++ b/src/components/profile/profile.tsx @@ -1,37 +1,70 @@ import { Avatar, Box, + Button, Card, CardBody, CardFooter, CardHeader, + Center, HStack, Heading, Icon, + Input, Text, + VStack, } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' import { FaRegStar, FaStar } from 'react-icons/fa6' +import { Link, generatePath } from 'react-router-dom' +import React, { memo, useCallback, useState } from 'react' -import React, { useState } from 'react' +import { URLs } from '../../__data__/urls' type User = Record & { + id: string name: string avatar?: string rated: number + friends?: User[] } -export const Profile = ({ user }: { user: User }) => { +export const Profile = ({ + user, + isLink, + title, +}: { + user: User + isLink?: boolean + title?: string +}) => { const [rated, setRated] = useState(user.rated || 0) + const [isTrue, setTrue] = useState(false) + const { t } = useTranslation() + + const handleSubmit = useCallback(() => { + fetch('/#') + }, []) + return ( - Данные профиля + {title || 'Данные профиля'} - +
+ +
- Имя: {user.name.toUpperCase()} + {isLink ? ( + + Имя: {user.name.toUpperCase()} + {t('key.to.override', { name: user.name.toUpperCase() })} + + ) : ( + Имя: {user.name.toUpperCase()} + )} @@ -54,13 +87,80 @@ export const Profile = ({ user }: { user: User }) => { > - ), + ) )}
+ {!isLink &&
} + + {user.friends && + user.friends.map((friend) => ( + + ))} + -
{JSON.stringify(user, null, 4)}
+ {!isLink && ( + {isTrue ? : } + )} + ) } + +const Form = memo<{ initialState: string; onSubmit(value: string): void }>( + ({ initialState, onSubmit }) => { + const [message, setMessage] = useState(initialState) + + const handleMessageChange = (event) => { + setMessage(event.target.value) + } + + return ( + + Написать сообщение: + + { + event.preventDefault() + onSubmit(message) + }} + > + + + + + + +
+ ) + }, +) + +Form.displayName = 'FormMemo' + +const Counter = () => { + const [value, setValue] = useState(0) + + return ( + + {value} + + + + + ) +} diff --git a/src/dashboard.tsx b/src/dashboard.tsx index 429f69b..86a0755 100644 --- a/src/dashboard.tsx +++ b/src/dashboard.tsx @@ -1,5 +1,6 @@ import React from 'react' import { Navigate, Route, Routes } from 'react-router-dom' +import { Container } from '@chakra-ui/react' import { URLs } from './__data__/urls' @@ -13,7 +14,7 @@ export const Dashboard = () => { path={URLs.baseUrl} element={} /> - } /> + } /> } /> ) diff --git a/src/index.tsx b/src/index.tsx index 1847d80..58571bc 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,6 +2,11 @@ /* eslint-disable react/display-name */ import React from 'react' import ReactDOM from 'react-dom/client' +import { i18nextReactInitConfig } from '@brojs/cli' +import i18next from 'i18next' + +i18next.t = i18next.t.bind(i18next) +const config = i18nextReactInitConfig(i18next) import App from './app' @@ -9,7 +14,8 @@ export default () => let rootElement: ReactDOM.Root -export const mount = (Сomponent, element = document.getElementById('app')) => { +export const mount = async (Сomponent, element = document.getElementById('app')) => { + await config rootElement = ReactDOM.createRoot(element) rootElement.render(<Сomponent/>) diff --git a/src/pages/by.tsx b/src/pages/by.tsx index b1d3130..3e19b4b 100644 --- a/src/pages/by.tsx +++ b/src/pages/by.tsx @@ -1,31 +1,56 @@ import { Container, Heading } from '@chakra-ui/react' -import React from 'react' +import React, { useState } from 'react' import { useParams } from 'react-router-dom' import { Profile } from '../components' const users = { 'some-user-id': { + id: 'some-user-id', name: 'alexandr', - secondName: null, + surname: null, email: null, rated: 3, - avatar: 'https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash' - } + avatar: + 'https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash', + friends: [ + { + id: '2', + name: 'not alexandr', + surname: null, + email: null, + rated: 2, + avatar: 'https://www.gravatar.com/avatar/6e?d=robohash', + }, + ], + }, + '2': { + id: '2', + name: 'not alexandr', + surname: null, + email: null, + rated: 2, + avatar: 'https://www.gravatar.com/avatar/6e?d=robohash', + friends: [ + { + id: 'some-user-id', + name: 'alexandr', + surname: null, + email: null, + rated: 3, + avatar: + 'https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash', + }, + ], + }, } export const ByPage = () => { const params = useParams() - const user = users[params.userId] + if (!users[params.userId]) { + return Пользователь не найден + } - return ( - - {user ? ( - - ) : ( - Пользователь не найден - )} - - ) + return }