From c6cdea7fd5597e800101c21035986526b046e936 Mon Sep 17 00:00:00 2001 From: Valerii Patsiorin Date: Tue, 10 Dec 2024 16:07:09 +0100 Subject: [PATCH 1/6] feat: change project's main page --- package-lock.json | 159 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- src/app/App.tsx | 3 +- 3 files changed, 164 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b1dfa392..053042670 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-storybook": "^0.8.0", "fork-ts-checker-webpack-plugin": "^8.0.0", + "gh-pages": "^6.2.0", "html-webpack-plugin": "^5.5.1", "husky": "^8.0.0", "jest": "^29.5.0", @@ -11021,6 +11022,13 @@ "integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==", "dev": true }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", + "dev": true, + "license": "MIT" + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -12511,6 +12519,34 @@ "node": ">=10" } }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -13147,6 +13183,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gh-pages": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.2.0.tgz", + "integrity": "sha512-HMXJ8th9u5wRXaZCnLcs/d3oVvCHiZkaP5KQExQljYGwJjQbSPyTdHe/Gc1IvYUR/rWiZLxNobIqfoMHKTKjHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.4", + "commander": "^11.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^11.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gh-pages/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/giget": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.1.tgz", @@ -21335,6 +21404,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/style-loader": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", @@ -21964,6 +22046,19 @@ "node": ">=12" } }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", @@ -31513,6 +31608,12 @@ "integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==", "dev": true }, + "email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", + "dev": true + }, "emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -32645,6 +32746,23 @@ } } }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true + }, + "filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -33105,6 +33223,29 @@ "get-intrinsic": "^1.1.1" } }, + "gh-pages": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.2.0.tgz", + "integrity": "sha512-HMXJ8th9u5wRXaZCnLcs/d3oVvCHiZkaP5KQExQljYGwJjQbSPyTdHe/Gc1IvYUR/rWiZLxNobIqfoMHKTKjHQ==", + "dev": true, + "requires": { + "async": "^3.2.4", + "commander": "^11.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^11.1.0" + }, + "dependencies": { + "commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true + } + } + }, "giget": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.1.tgz", @@ -39034,6 +39175,15 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "style-loader": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", @@ -39512,6 +39662,15 @@ "punycode": "^2.1.1" } }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", diff --git a/package.json b/package.json index 492664d1f..d66d26e2b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "test": "jest src", "lint": "eslint src --fix", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "deploy": "npx gh-pages -d dist" }, "license": "MIT", "devDependencies": { @@ -46,6 +47,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-storybook": "^0.8.0", "fork-ts-checker-webpack-plugin": "^8.0.0", + "gh-pages": "^6.2.0", "html-webpack-plugin": "^5.5.1", "husky": "^8.0.0", "jest": "^29.5.0", diff --git a/src/app/App.tsx b/src/app/App.tsx index dcc0ff8ad..7fde26a0a 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -8,7 +8,8 @@ function App() {
logo

- Текст писать тут + Привет,
+ мне не хочется ничего о себе рассказывать.

From 089a185b9cdf9579ab41e5b1f9a09c528620f36f Mon Sep 17 00:00:00 2001 From: Valerii Patsiorin Date: Tue, 10 Dec 2024 16:18:11 +0100 Subject: [PATCH 2/6] feat: make the react logo faster --- src/app/App.css | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/app/App.css b/src/app/App.css index 78b8850cf..bf919f4be 100644 --- a/src/app/App.css +++ b/src/app/App.css @@ -1,38 +1,38 @@ .App { - text-align: center; + text-align: center; } .App-logo { - height: 40vmin; - pointer-events: none; + height: 40vmin; + pointer-events: none; } @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } + .App-logo { + animation: App-logo-spin infinite 2s linear; + } } .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } .App-link { - color: #61dafb; + color: #61dafb; } @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } From 1073a2f7ab11c2f2f5598b7401ea75d2930d8835 Mon Sep 17 00:00:00 2001 From: patsiorin <37371870+patsiorin@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:08:11 +0100 Subject: [PATCH 3/6] Delete .github/workflows/main.yml --- .github/workflows/main.yml | 63 -------------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 0f5ba90b0..000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Test, Lint, Build and Deploy on Github Pages - -on: - push: - branches: ["master", "main"] - - # Позволяет запустить этот рабочий процесс вручную на вкладке Actions - workflow_dispatch: - -permissions: - contents: write - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x] - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - # Устанавливаем зависимости - - name: Install dependencies - run: npm install - - # Запускаем тесты и линтер - - name: Run tests and linter - run: npm run lint && npm test - - # Собираем приложение - - name: Build Application - run: npm run build - - # Публикуем приложение на Github Pages - - name: Deploy to Github Pages - uses: JamesIves/github-pages-deploy-action@4.2.1 - with: - branch: gh-pages - folder: dist - - # # Собираем Storybook - # - name: Build Storybook - # run: npm run build-storybook - # - # # Публикуем Storybook на Github Pages - # - name: Deploy Storybook to Github Pages - # uses: JamesIves/github-pages-deploy-action@4.2.1 - # with: - # branch: gh-pages - # folder: storybook-static - # commit-message: "Automatically publish Storybook" - - # Останавливаем выполнение строго при неудачных тестах - - name: Fail on failed tests - run: | - if [ ${{ job.status }} == 'failure' ]; then exit 1; fi; From 87556df41cdbcd5076d29ddc1f2eb340e57eb4b7 Mon Sep 17 00:00:00 2001 From: patsiorin <37371870+patsiorin@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:08:32 +0100 Subject: [PATCH 4/6] Create main.yml --- .github/workflows/main.yml | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..0f5ba90b0 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,63 @@ +name: Test, Lint, Build and Deploy on Github Pages + +on: + push: + branches: ["master", "main"] + + # Позволяет запустить этот рабочий процесс вручную на вкладке Actions + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + # Устанавливаем зависимости + - name: Install dependencies + run: npm install + + # Запускаем тесты и линтер + - name: Run tests and linter + run: npm run lint && npm test + + # Собираем приложение + - name: Build Application + run: npm run build + + # Публикуем приложение на Github Pages + - name: Deploy to Github Pages + uses: JamesIves/github-pages-deploy-action@4.2.1 + with: + branch: gh-pages + folder: dist + + # # Собираем Storybook + # - name: Build Storybook + # run: npm run build-storybook + # + # # Публикуем Storybook на Github Pages + # - name: Deploy Storybook to Github Pages + # uses: JamesIves/github-pages-deploy-action@4.2.1 + # with: + # branch: gh-pages + # folder: storybook-static + # commit-message: "Automatically publish Storybook" + + # Останавливаем выполнение строго при неудачных тестах + - name: Fail on failed tests + run: | + if [ ${{ job.status }} == 'failure' ]; then exit 1; fi; From e76d7fe81dccefd40170ca2eb3685c922e07708a Mon Sep 17 00:00:00 2001 From: Valerii Patsiorin Date: Tue, 10 Dec 2024 16:52:35 +0100 Subject: [PATCH 5/6] fix: recreate branch --- src/app/App.tsx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index 7fde26a0a..110deadaa 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -8,8 +8,27 @@ function App() {
logo

- Привет,
- мне не хочется ничего о себе рассказывать. +

+ Привет, меня зовут Валерий. +
+ я не люблю о себе рассказывать,
+ но раз вы настаиваете: +

+
    +
  • + Цели: + найти и устранить пробелы в знаниях React и сопутствующих технологий; +
  • +
  • + В той или иной степени владею: + JS, TS, HTML, CSS, PHP, JAVA, C#; +
  • +
  • + О себе: + работаю в небольшой компании, занимаюсь в основном фронтендом. За спиной есть несколько проектов на + React+Next.js{' '} +
  • +

From d1edbc09171bd5a5381d33fc581de2377c498136 Mon Sep 17 00:00:00 2001 From: Valerii Patsiorin Date: Thu, 26 Dec 2024 16:32:14 +0100 Subject: [PATCH 6/6] feat: add homework "typescrypt 1" solution --- src/homeworks/ts1/1_base.test.js | 45 +++---- src/homeworks/ts1/{1_base.js => 1_base.ts} | 39 ++++-- src/homeworks/ts1/2_repair.ts | 82 ++++++------ src/homeworks/ts1/3_write.test.js | 63 +++++---- src/homeworks/ts1/3_write.ts | 143 ++++++++++++++------- 5 files changed, 213 insertions(+), 159 deletions(-) rename src/homeworks/ts1/{1_base.js => 1_base.ts} (51%) diff --git a/src/homeworks/ts1/1_base.test.js b/src/homeworks/ts1/1_base.test.js index ee68dc16f..dbd708234 100644 --- a/src/homeworks/ts1/1_base.test.js +++ b/src/homeworks/ts1/1_base.test.js @@ -1,26 +1,21 @@ -// Этот блок кода удалить и раскомментировать код ниже -it('remove it', () => { - expect(true).toBe(true); -}); +import { transformCustomers } from './1_base'; + +describe('all', () => { + it('transformCustomers', () => { + const customers = [ + { id: 1, name: 'John', age: 25, isSubscribed: true }, + { id: 2, name: 'Mary', age: 40, isSubscribed: false }, + { id: 3, name: 'Bob', age: 32, isSubscribed: true }, + { id: 4, name: 'Alice', age: 22, isSubscribed: true }, + { id: 5, name: 'David', age: 48, isSubscribed: false }, + ]; -// import { transformCustomers } from './1_base'; -// -// describe('all', () => { -// it('transformCustomers', () => { -// const customers = [ -// { id: 1, name: 'John', age: 25, isSubscribed: true }, -// { id: 2, name: 'Mary', age: 40, isSubscribed: false }, -// { id: 3, name: 'Bob', age: 32, isSubscribed: true }, -// { id: 4, name: 'Alice', age: 22, isSubscribed: true }, -// { id: 5, name: 'David', age: 48, isSubscribed: false }, -// ]; -// -// expect(transformCustomers(customers)).toEqual({ -// 1: { name: 'John', age: 25, isSubscribed: true }, -// 2: { name: 'Mary', age: 40, isSubscribed: false }, -// 3: { name: 'Bob', age: 32, isSubscribed: true }, -// 4: { name: 'Alice', age: 22, isSubscribed: true }, -// 5: { name: 'David', age: 48, isSubscribed: false }, -// }); -// }); -// }); + expect(transformCustomers(customers)).toEqual({ + 1: { name: 'John', age: 25, isSubscribed: true }, + 2: { name: 'Mary', age: 40, isSubscribed: false }, + 3: { name: 'Bob', age: 32, isSubscribed: true }, + 4: { name: 'Alice', age: 22, isSubscribed: true }, + 5: { name: 'David', age: 48, isSubscribed: false }, + }); + }); +}); diff --git a/src/homeworks/ts1/1_base.js b/src/homeworks/ts1/1_base.ts similarity index 51% rename from src/homeworks/ts1/1_base.js rename to src/homeworks/ts1/1_base.ts index 611b3a92f..05e91d986 100644 --- a/src/homeworks/ts1/1_base.js +++ b/src/homeworks/ts1/1_base.ts @@ -1,16 +1,16 @@ /** * Нужно превратить файл в ts и указать типы аргументов и типы возвращаемого значения * */ -export const removePlus = (string) => string.replace(/^\+/, ''); +export const removePlus = (string: string): string => string.replace(/^\+/, ''); -export const addPlus = (string) => `+${string}`; +export const addPlus = (string: string): string => `+${string}`; -export const removeFirstZeros = (value) => value.replace(/^(-)?[0]+(-?\d+.*)$/, '$1$2'); +export const removeFirstZeros = (value: string): string => value.replace(/^(-)?[0]+(-?\d+.*)$/, '$1$2'); -export const getBeautifulNumber = (value, separator = ' ') => +export const getBeautifulNumber = (value: number, separator: string = ' '): string => value?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator); -export const round = (value, accuracy = 2) => { +export const round = (value: number, accuracy: number = 2): number => { const d = 10 ** accuracy; return Math.round(value * d) / d; }; @@ -18,7 +18,7 @@ export const round = (value, accuracy = 2) => { const transformRegexp = /(matrix\(-?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, )(-?\d+(\.\d+)?), (-?\d+(\.\d+)?)\)/; -export const getTransformFromCss = (transformCssString) => { +export const getTransformFromCss = (transformCssString: string): {x: number, y: number} => { const data = transformCssString.match(transformRegexp); if (!data) return { x: 0, y: 0 }; return { @@ -27,20 +27,20 @@ export const getTransformFromCss = (transformCssString) => { }; }; -export const getColorContrastValue = ([red, green, blue]) => +export const getColorContrastValue = ([red, green, blue]: [number, number, number]): number => // http://www.w3.org/TR/AERT#color-contrast Math.round((red * 299 + green * 587 + blue * 114) / 1000); -export const getContrastType = (contrastValue) => (contrastValue > 125 ? 'black' : 'white'); +export const getContrastType = (contrastValue: number): 'black' | 'white' => (contrastValue > 125 ? 'black' : 'white'); export const shortColorRegExp = /^#[0-9a-f]{3}$/i; export const longColorRegExp = /^#[0-9a-f]{6}$/i; -export const checkColor = (color) => { +export const checkColor = (color: string): void => { if (!longColorRegExp.test(color) && !shortColorRegExp.test(color)) throw new Error(`invalid hex color: ${color}`); }; -export const hex2rgb = (color) => { +export const hex2rgb = (color: string): [number, number, number] => { checkColor(color); if (shortColorRegExp.test(color)) { const red = parseInt(color.substring(1, 2), 16); @@ -54,11 +54,22 @@ export const hex2rgb = (color) => { return [red, green, blue]; }; -export const getNumberedArray = (arr) => arr.map((value, number) => ({ value, number })); -export const toStringArray = (arr) => arr.map(({ value, number }) => `${value}_${number}`); +export const getNumberedArray = (arr: number[]): {value: number, number: number}[] => arr.map((value, number) => ({ value, number })); +export const toStringArray = (arr: {value: number, number: number}[]): string[] => arr.map(({ value, number }) => `${value}_${number}`); -export const transformCustomers = (customers) => { - return customers.reduce((acc, customer) => { +type Customer = { + id: string, + name: string, + age: number, + isSubscribed: boolean +} + +type CustomerRecord = { + [key: string]: Omit +} + +export const transformCustomers = (customers: Customer[]): CustomerRecord => { + return customers.reduce((acc: CustomerRecord, customer) => { acc[customer.id] = { name: customer.name, age: customer.age, isSubscribed: customer.isSubscribed }; return acc; }, {}); diff --git a/src/homeworks/ts1/2_repair.ts b/src/homeworks/ts1/2_repair.ts index 19e98c068..a32c89dbe 100644 --- a/src/homeworks/ts1/2_repair.ts +++ b/src/homeworks/ts1/2_repair.ts @@ -3,45 +3,45 @@ * */ // // Мы это не проходили, но по тексту ошибки можно понять, как это починить -// export const getFakeApi = async (): void => { -// const result = await fetch('https://jsonplaceholder.typicode.com/todos/1').then((response) => response.json()); -// console.log(result); -// }; -// -// // Мы это не проходили, но по тексту ошибки можно понять, как это починить -// export class SomeClass { -// constructor() { -// this.set = new Set([1]); -// this.channel = new BroadcastChannel('test-broadcast-channel'); -// } -// } -// -// export type Data = { -// type: 'Money' | 'Percent'; -// value: DataValue; -// }; -// -// export type DataValue = Money | Percent; -// -// export type Money = { -// currency: string; -// amount: number; -// }; -// -// export type Percent = { -// percent: number; -// }; -// +export const getFakeApi = async (): Promise => { + const result = await fetch('https://jsonplaceholder.typicode.com/todos/1').then((response) => response.json()); + console.log(result); +}; + +// Мы это не проходили, но по тексту ошибки можно понять, как это починить +export class SomeClass { + set: Set; + channel: BroadcastChannel; + + constructor() { + this.set = new Set([1]); + this.channel = new BroadcastChannel('test-broadcast-channel'); + } +} + +export type Data = { type: 'Money'; value: Money } | { type: 'Percent'; value: Percent }; + +export type Money = { + currency: string; + amount: number; +}; + +export type Percent = { + percent: number; +}; + // // Здесь, возможно, нужно использовать as, возможно в switch передавать немного по-другому -// const getDataAmount = (data: Data): number => { -// switch (data.type) { -// case 'Money': -// return data.value.amount; -// -// default: { -// // eslint-disable-next-line @typescript-eslint/no-unused-vars -// const unhandled: never = data; // здесь, возможно, нужно использовать нечто другое. :never должен остаться -// throw new Error(`unknown type: ${data.type}`); -// } -// } -// }; +const getDataAmount = (data: Data): number => { + switch (data.type) { + case 'Money': + return data.value.amount; + case 'Percent': + return data.value.percent; + + default: { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const unhandled: never = data; // здесь, возможно, нужно использовать нечто другое. :never должен остаться + throw new Error(`unknown type: ${(data as any).type}`); + } + } +}; diff --git a/src/homeworks/ts1/3_write.test.js b/src/homeworks/ts1/3_write.test.js index 5b5173063..a11ac89c3 100644 --- a/src/homeworks/ts1/3_write.test.js +++ b/src/homeworks/ts1/3_write.test.js @@ -1,35 +1,30 @@ -// Этот блок кода удалить и раскомментировать код ниже -it('remove it', () => { - expect(true).toBe(true); -}); +import { createRandomOperation, createRandomProduct } from './3_write'; + +describe('all', () => { + it('operation', () => { + const createdAt = '2023-06-06T12:06:56.957Z'; + const operation = createRandomOperation(createdAt); + expect(operation).toHaveProperty('createdAt', createdAt); + expect(operation).toHaveProperty('id'); + expect(operation).toHaveProperty('name'); + expect(operation).toHaveProperty('desc'); + expect(operation).toHaveProperty('createdAt'); + expect(operation).toHaveProperty('amount'); + expect(operation).toHaveProperty('category'); + expect(operation).toHaveProperty('type'); + }); -// import { createRandomOperation, createRandomProduct } from './3_write'; -// -// describe('all', () => { -// it('operation', () => { -// const createdAt = '2023-06-06T12:06:56.957Z'; -// const operation = createRandomOperation(createdAt); -// expect(operation).toHaveProperty('createdAt', createdAt); -// expect(operation).toHaveProperty('id'); -// expect(operation).toHaveProperty('name'); -// expect(operation).toHaveProperty('desc'); -// expect(operation).toHaveProperty('createdAt'); -// expect(operation).toHaveProperty('amount'); -// expect(operation).toHaveProperty('category'); -// expect(operation).toHaveProperty('type'); -// }); -// -// it('product', () => { -// const createdAt = '2023-06-06T12:06:56.957Z'; -// const product = createRandomProduct(createdAt); -// expect(product).toHaveProperty('createdAt', createdAt); -// expect(product).toHaveProperty('id'); -// expect(product).toHaveProperty('name'); -// expect(product).toHaveProperty('photo'); -// expect(product).toHaveProperty('desc'); -// expect(product).toHaveProperty('createdAt'); -// expect(product).toHaveProperty('oldPrice'); -// expect(product).toHaveProperty('price'); -// expect(product).toHaveProperty('category'); -// }); -// }); + it('product', () => { + const createdAt = '2023-06-06T12:06:56.957Z'; + const product = createRandomProduct(createdAt); + expect(product).toHaveProperty('createdAt', createdAt); + expect(product).toHaveProperty('id'); + expect(product).toHaveProperty('name'); + expect(product).toHaveProperty('photo'); + expect(product).toHaveProperty('desc'); + expect(product).toHaveProperty('createdAt'); + expect(product).toHaveProperty('oldPrice'); + expect(product).toHaveProperty('price'); + expect(product).toHaveProperty('category'); + }); +}); diff --git a/src/homeworks/ts1/3_write.ts b/src/homeworks/ts1/3_write.ts index 15f9dcdf2..b17c8e96b 100644 --- a/src/homeworks/ts1/3_write.ts +++ b/src/homeworks/ts1/3_write.ts @@ -1,56 +1,109 @@ -/** - * Функции написанные здесь пригодятся на последующих уроках - * С помощью этих функций мы будем добавлять элементы в список для проверки динамической загрузки - * Поэтому в идеале чтобы функции возвращали случайные данные, но в то же время не абракадабру. - * В целом сделайте так, как вам будет удобно. - * */ +type Category = { + id: string; + name: string; + photo?: string; +}; -/** - * Нужно создать тип Category, он будет использоваться ниже. - * Категория содержит - * - id (строка) - * - name (строка) - * - photo (строка, необязательно) - * - * Продукт (Product) содержит - * - id (строка) - * - name (строка) - * - photo (строка) - * - desc (строка, необязательно) - * - createdAt (строка) - * - oldPrice (число, необязательно) - * - price (число) - * - category (Категория) - * - * Операция (Operation) может быть либо тратой (Cost), либо доходом (Profit) - * - * Трата (Cost) содержит - * - id (строка) - * - name (строка) - * - desc (строка, необязательно) - * - createdAt (строка) - * - amount (число) - * - category (Категория) - * - type ('Cost') - * - * Доход (Profit) содержит - * - id (строка) - * - name (строка) - * - desc (строка, необязательно) - * - createdAt (строка) - * - amount (число) - * - category (Категория) - * - type ('Profit') - * */ +type Product = { + id: string; + name: string; + photo: string; + desc?: string; + createdAt: string; + oldPrice?: number; + price: number; + category: Category; +}; + +type BaseOperation = { + id: string; + name: string; + desc?: string; + createdAt: string; + amount: number; + category: Category; +}; + +type Cost = BaseOperation & { + type: 'Cost'; +}; + +type Profit = BaseOperation & { + type: 'Profit'; +}; + +type Operation = Cost | Profit; + +const getRandomItem = (array: T[]): T => array[Math.floor(Math.random() * array.length)]; + +const ids = ['prod_001', 'prod_002', 'prod_003', 'prod_004']; +const names = ['Laptop', 'T-Shirt', 'Novel', 'Blender']; +const photos = ['laptop.jpg', 'tshirt.jpg', 'novel.jpg', 'blender.jpg']; +const descriptions = [ + 'A high-end laptop.', + 'A comfortable cotton t-shirt.', + 'A bestselling novel.', + 'A powerful kitchen blender.', +]; +const prices = [299.99, 19.99, 9.99, 49.99]; +const oldPrices = [399.99, 24.99, 14.99, 59.99]; +const categories: Category[] = [ + { + id: 'cat_001', + name: 'Electronics', + photo: 'cat_001_photo.jpg', + }, + { + id: 'cat_002', + name: 'Clothing', + photo: 'cat_002_photo.jpg', + }, + { + id: 'cat_003', + name: 'Electronics', + photo: 'cat_003_photo.jpg', + }, + { + id: 'cat_004', + name: 'Books', + photo: undefined, + }, +]; /** * Создает случайный продукт (Product). * Принимает дату создания (строка) * */ -// export const createRandomProduct = (createdAt: string) => {}; +export const createRandomProduct = (createdAt: string): Product => { + return { + id: getRandomItem(ids), + name: getRandomItem(names), + photo: getRandomItem(photos), + desc: Math.random() > 0.5 ? getRandomItem(descriptions) : undefined, + createdAt: createdAt, + oldPrice: Math.random() > 0.5 ? getRandomItem(oldPrices) : undefined, + price: getRandomItem(prices), + category: getRandomItem(categories), + }; +}; + +const operationIds = ['op_001', 'op_002', 'op_003', 'op_004']; +const operationNames = ['Rent Payment', 'Salary Payment', 'Grocery Shopping', 'Freelance Project']; +const operationDescriptions = ['Monthly rent', 'Monthly salary', 'Buying groceries', 'Completed a freelance project']; +const operationAmounts = [50, 100, 500, 1000, 2000]; /** * Создает случайную операцию (Operation). * Принимает дату создания (строка) * */ -// export const createRandomOperation = (createdAt: string) => {}; +export const createRandomOperation = (createdAt: string): Operation => { + return { + id: getRandomItem(operationIds), + name: getRandomItem(operationNames), + desc: Math.random() > 0.5 ? getRandomItem(operationDescriptions) : undefined, + createdAt, + amount: getRandomItem(operationAmounts), + category: getRandomItem(categories), + type: Math.random() > 0.5 ? 'Cost' : 'Profit', + } as Operation; +};