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.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);
+ }
}
diff --git a/src/app/App.tsx b/src/app/App.tsx
index dcc0ff8ad..110deadaa 100644
--- a/src/app/App.tsx
+++ b/src/app/App.tsx
@@ -8,7 +8,27 @@ function App() {
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;
+};