diff --git a/package-lock.json b/package-lock.json index 5976c38..1c30ed8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,8 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.1", + "@types/node": "^18.16.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-feather": "^2.0.10", @@ -23,9 +25,12 @@ "react-slick": "^0.29.0", "redux": "^4.2.1", "slick-carousel": "^1.8.1", + "typescript": "^5.0.4", "web-vitals": "^2.1.4" }, "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.1", "tailwindcss": "^3.2.7" } }, @@ -3482,95 +3487,6 @@ "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" } }, - "node_modules/@testing-library/dom": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.1.tgz", - "integrity": "sha512-fTOVsMY9QLFCCXRHG3Ese6cMH5qIWwSbgxZsgeF5TNsy81HKaZ4kgehnSF8FsR3OF+numlIV2YcU79MzbnhSig==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true - }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.16.5", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", @@ -3955,9 +3871,9 @@ } }, "node_modules/@types/jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", - "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", + "version": "29.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.1.tgz", + "integrity": "sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -4206,9 +4122,9 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "node_modules/@types/node": { - "version": "18.15.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz", - "integrity": "sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw==" + "version": "18.16.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", + "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4241,9 +4157,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz", + "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4251,9 +4167,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", - "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.1.tgz", + "integrity": "sha512-8QZEV9+Kwy7tXFmjJrp3XUKQSs9LTnE0KnoUb0YCguWBiNW0Yfb2iBMYZ08WPg35IR6P3Z0s00B15SwZnO26+w==", "dependencies": { "@types/react": "*" } @@ -11626,12 +11542,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jquery": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz", - "integrity": "sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ==", - "peer": true - }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -16303,16 +16213,15 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/unbox-primitive": { @@ -18831,14 +18740,12 @@ "@csstools/postcss-unset-value": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", - "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", - "requires": {} + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==" }, "@csstools/selector-specificity": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.1.1.tgz", - "integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==", - "requires": {} + "integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==" }, "@eslint-community/eslint-utils": { "version": "4.2.0", @@ -19759,75 +19666,7 @@ "@tailwindcss/line-clamp": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz", - "integrity": "sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==", - "requires": {} - }, - "@testing-library/dom": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.1.tgz", - "integrity": "sha512-fTOVsMY9QLFCCXRHG3Ese6cMH5qIWwSbgxZsgeF5TNsy81HKaZ4kgehnSF8FsR3OF+numlIV2YcU79MzbnhSig==", - "peer": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } + "integrity": "sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==" }, "@testing-library/jest-dom": { "version": "5.16.5", @@ -20150,9 +19989,9 @@ } }, "@types/jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", - "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", + "version": "29.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.1.tgz", + "integrity": "sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==", "requires": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -20348,9 +20187,9 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "@types/node": { - "version": "18.15.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz", - "integrity": "sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw==" + "version": "18.16.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", + "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==" }, "@types/parse-json": { "version": "4.0.0", @@ -20383,9 +20222,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz", + "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -20393,9 +20232,9 @@ } }, "@types/react-dom": { - "version": "18.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", - "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.1.tgz", + "integrity": "sha512-8QZEV9+Kwy7tXFmjJrp3XUKQSs9LTnE0KnoUb0YCguWBiNW0Yfb2iBMYZ08WPg35IR6P3Z0s00B15SwZnO26+w==", "requires": { "@types/react": "*" } @@ -20786,14 +20625,12 @@ "acorn-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "requires": {} + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" }, "acorn-node": { "version": "1.8.2", @@ -20879,8 +20716,7 @@ "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "requires": {} + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" }, "ansi-escapes": { "version": "4.3.2", @@ -21190,8 +21026,7 @@ "babel-plugin-named-asset-import": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "requires": {} + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==" }, "babel-plugin-polyfill-corejs2": { "version": "0.3.3", @@ -21799,8 +21634,7 @@ "css-declaration-sorter": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", - "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", - "requires": {} + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==" }, "css-has-pseudo": { "version": "3.0.4", @@ -21883,8 +21717,7 @@ "css-prefers-color-scheme": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", - "requires": {} + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==" }, "css-select": { "version": "4.3.0", @@ -21988,8 +21821,7 @@ "cssnano-utils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", - "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", - "requires": {} + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==" }, "csso": { "version": "4.2.0", @@ -22889,8 +22721,7 @@ "eslint-plugin-react-hooks": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "requires": {} + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==" }, "eslint-plugin-testing-library": { "version": "5.10.2", @@ -23912,8 +23743,7 @@ "icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "requires": {} + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" }, "idb": { "version": "7.1.1", @@ -25005,8 +24835,7 @@ "jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "requires": {} + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==" }, "jest-regex-util": { "version": "27.5.1", @@ -25765,12 +25594,6 @@ } } }, - "jquery": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz", - "integrity": "sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ==", - "peer": true - }, "js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -26686,8 +26509,7 @@ "postcss-browser-comments": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", - "requires": {} + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==" }, "postcss-calc": { "version": "8.2.4", @@ -26785,26 +26607,22 @@ "postcss-discard-comments": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", - "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", - "requires": {} + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==" }, "postcss-discard-duplicates": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", - "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", - "requires": {} + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==" }, "postcss-discard-empty": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", - "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", - "requires": {} + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==" }, "postcss-discard-overridden": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", - "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", - "requires": {} + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==" }, "postcss-double-position-gradients": { "version": "3.1.2", @@ -26826,8 +26644,7 @@ "postcss-flexbugs-fixes": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "requires": {} + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==" }, "postcss-focus-visible": { "version": "6.0.4", @@ -26848,14 +26665,12 @@ "postcss-font-variant": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "requires": {} + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==" }, "postcss-gap-properties": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", - "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", - "requires": {} + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==" }, "postcss-image-set-function": { "version": "4.0.7", @@ -26878,8 +26693,7 @@ "postcss-initial": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "requires": {} + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==" }, "postcss-js": { "version": "4.0.1", @@ -26920,14 +26734,12 @@ "postcss-logical": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "requires": {} + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==" }, "postcss-media-minmax": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "requires": {} + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==" }, "postcss-merge-longhand": { "version": "5.1.7", @@ -26988,8 +26800,7 @@ "postcss-modules-extract-imports": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "requires": {} + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==" }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -27047,8 +26858,7 @@ "postcss-normalize-charset": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", - "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", - "requires": {} + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==" }, "postcss-normalize-display-values": { "version": "5.1.0", @@ -27119,8 +26929,7 @@ "postcss-opacity-percentage": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", - "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", - "requires": {} + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==" }, "postcss-ordered-values": { "version": "5.1.3", @@ -27142,8 +26951,7 @@ "postcss-page-break": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "requires": {} + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==" }, "postcss-place": { "version": "7.0.5", @@ -27237,8 +27045,7 @@ "postcss-replace-overflow-wrap": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "requires": {} + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==" }, "postcss-selector-not": { "version": "6.0.1", @@ -27632,8 +27439,7 @@ "react-loading-skeleton": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.2.0.tgz", - "integrity": "sha512-kN12x4Ud69jbksr2EdhYywAFeW4bPdvFQ9p3ID1OM/QeFjgwFSmSUY2a6P6uOb5ACzWp3ozY8C+7+04KR6+PHA==", - "requires": {} + "integrity": "sha512-kN12x4Ud69jbksr2EdhYywAFeW4bPdvFQ9p3ID1OM/QeFjgwFSmSUY2a6P6uOb5ACzWp3ozY8C+7+04KR6+PHA==" }, "react-redux": { "version": "8.0.5", @@ -27798,8 +27604,7 @@ "redux-thunk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", - "requires": {} + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==" }, "regenerate": { "version": "1.4.2", @@ -28324,8 +28129,7 @@ "slick-carousel": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/slick-carousel/-/slick-carousel-1.8.1.tgz", - "integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==", - "requires": {} + "integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA==" }, "sockjs": { "version": "0.3.24", @@ -28589,8 +28393,7 @@ "style-loader": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "requires": {} + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==" }, "stylehacks": { "version": "5.1.1", @@ -28994,10 +28797,9 @@ } }, "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==" }, "unbox-primitive": { "version": "1.0.2", @@ -29091,8 +28893,7 @@ "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" }, "util-deprecate": { "version": "1.0.2", @@ -29366,8 +29167,7 @@ "ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "requires": {} + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==" } } }, @@ -29825,8 +29625,7 @@ "ws": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "requires": {} + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==" }, "xml-name-validator": { "version": "3.0.0", diff --git a/package.json b/package.json index a88423d..7b3cf72 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.1", + "@types/node": "^18.16.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-feather": "^2.0.10", @@ -18,6 +20,7 @@ "react-slick": "^0.29.0", "redux": "^4.2.1", "slick-carousel": "^1.8.1", + "typescript": "^5.0.4", "web-vitals": "^2.1.4" }, "scripts": { @@ -45,6 +48,8 @@ ] }, "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.1", "tailwindcss": "^3.2.7" } } diff --git a/src/App.test.js b/src/App.test.tsx similarity index 50% rename from src/App.test.js rename to src/App.test.tsx index 1f03afe..9382b9a 100644 --- a/src/App.test.js +++ b/src/App.test.tsx @@ -1,7 +1,7 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; +import { render, screen } from "@testing-library/react"; +import App from "./App"; -test('renders learn react link', () => { +test("renders learn react link", () => { render(); const linkElement = screen.getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); diff --git a/src/App.jsx b/src/App.tsx similarity index 100% rename from src/App.jsx rename to src/App.tsx diff --git a/src/components/layout/Header.jsx b/src/components/layout/Header.tsx similarity index 88% rename from src/components/layout/Header.jsx rename to src/components/layout/Header.tsx index f937e70..4f5f767 100644 --- a/src/components/layout/Header.jsx +++ b/src/components/layout/Header.tsx @@ -1,6 +1,7 @@ +import { ReactElement } from "react"; import { Link } from "react-router-dom"; -export default function Header() { +export default function Header(): ReactElement { return (
diff --git a/src/components/sections/articlespage/Blog.jsx b/src/components/sections/articlespage/Blog.tsx similarity index 88% rename from src/components/sections/articlespage/Blog.jsx rename to src/components/sections/articlespage/Blog.tsx index d925c29..3b2210a 100644 --- a/src/components/sections/articlespage/Blog.jsx +++ b/src/components/sections/articlespage/Blog.tsx @@ -4,7 +4,11 @@ import CardSkeleton from "../../ui/Card/Skeleton"; import ErrorFound from "../../ui/ErrorFound"; import NotFound from "../../ui/NotFound"; -export default function Blog({ whichTab }) { +export default function Blog({ + whichTab, +}: { + whichTab: string; +}): React.ReactElement { const { data, isError, isLoading } = useGetArticlesQuery(whichTab); return ( diff --git a/src/components/sections/homepage/Blog.jsx b/src/components/sections/homepage/Blog.tsx similarity index 69% rename from src/components/sections/homepage/Blog.jsx rename to src/components/sections/homepage/Blog.tsx index 57e0938..cf3fa83 100644 --- a/src/components/sections/homepage/Blog.jsx +++ b/src/components/sections/homepage/Blog.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { Dispatch, useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { setArticles } from "../../../features/articles"; import { useGetArticlesQuery } from "../../../services/articlesApi"; @@ -6,15 +6,17 @@ import Card from "../../ui/Card"; import CardSkeleton from "../../ui/Card/Skeleton"; import ErrorFound from "../../ui/ErrorFound"; import NotFound from "../../ui/NotFound"; +import { Articles } from "interfaces/articles"; +import { AnyAction } from "redux"; -export default function Blog() { +export default function Blog(): React.ReactElement { const { data: headlines, isLoading, isError, } = useGetArticlesQuery("headlines"); - const dispatch = useDispatch(); - const data = useSelector((state) => state.articles); + const dispatch: Dispatch = useDispatch(); + const data = useSelector((state: Articles) => state.articles); useEffect(() => { if (headlines) { dispatch(setArticles(headlines)); @@ -24,11 +26,13 @@ export default function Blog() { return ( <> {isError && } -
+
{isLoading ? ( ) : data?.length === 0 ? ( - +
+ +
) : ( data.map((article, index) => { return ; diff --git a/src/components/sections/homepage/NavSkeleton.jsx b/src/components/sections/homepage/NavSkeleton.jsx deleted file mode 100644 index 2878670..0000000 --- a/src/components/sections/homepage/NavSkeleton.jsx +++ /dev/null @@ -1,7 +0,0 @@ -import Skeleton from "react-loading-skeleton"; - -export default function NavSkeleton({ count }) { - return Array(count) - .fill() - .map((_, index) => ); -} diff --git a/src/components/sections/homepage/NavSkeleton.tsx b/src/components/sections/homepage/NavSkeleton.tsx new file mode 100644 index 0000000..f5c6566 --- /dev/null +++ b/src/components/sections/homepage/NavSkeleton.tsx @@ -0,0 +1,13 @@ +import Skeleton from "react-loading-skeleton"; + +export default function NavSkeleton({ count }: { count: number }) { + return ( + <> + {Array(count) + .fill("") + .map((_, index) => ( + + ))} + + ); +} diff --git a/src/components/sections/homepage/Navigation.jsx b/src/components/sections/homepage/Navigation.tsx similarity index 81% rename from src/components/sections/homepage/Navigation.jsx rename to src/components/sections/homepage/Navigation.tsx index cc5313b..a9783b3 100644 --- a/src/components/sections/homepage/Navigation.jsx +++ b/src/components/sections/homepage/Navigation.tsx @@ -5,10 +5,11 @@ import Slider from "react-slick"; import settings from "../../../config/reactSlickSetting"; import { Link } from "react-router-dom"; import NavSkeleton from "./NavSkeleton"; +import { Publisher } from "interfaces/publisher"; -export default function Navigation() { - const { data: publishers, isLoading } = useGetPublisherQuery(); - const [whichTab, setWhichTab] = useState(""); +export default function Navigation(): React.ReactElement { + const { data: publishers, isLoading } = useGetPublisherQuery(undefined); + const [whichTab, setWhichTab] = useState(""); return (
@@ -17,7 +18,7 @@ export default function Navigation() { ) : ( - {publishers?.sources.map((item) => ( + {publishers?.sources.map((item: Publisher) => ( { - return ( -
- -
- - -
- -
- ); - }); -} diff --git a/src/components/ui/Card/Skeleton.tsx b/src/components/ui/Card/Skeleton.tsx new file mode 100644 index 0000000..d0b761f --- /dev/null +++ b/src/components/ui/Card/Skeleton.tsx @@ -0,0 +1,22 @@ +import Skeleton from "react-loading-skeleton"; + +export default function CardSkeleton({ count }: { count?: number }) { + return ( + <> + {Array(count) + .fill("") + .map((_, index) => { + return ( +
+ +
+ + +
+ +
+ ); + })} + + ); +} diff --git a/src/components/ui/Card/index.jsx b/src/components/ui/Card/index.tsx similarity index 81% rename from src/components/ui/Card/index.jsx rename to src/components/ui/Card/index.tsx index 04a7034..3521737 100644 --- a/src/components/ui/Card/index.jsx +++ b/src/components/ui/Card/index.tsx @@ -1,9 +1,11 @@ import { Link } from "react-router-dom"; import getDateTime from "../../../utils/getDateTime"; +import { Article } from "interfaces/articles"; -export default function Card({ article }) { +export default function Card({ article }: { article: Article }) { const { title, urlToImage, publishedAt } = article; const date = new Date(publishedAt); + return (
@@ -13,7 +15,7 @@ export default function Card({ article }) { alt={title} />
- {getDateTime(date.getMonth(), date.getDay())} + {getDateTime(date.getMonth(), date.getDate())} {date.getMinutes()} min
diff --git a/src/components/ui/ErrorFound.jsx b/src/components/ui/ErrorFound.tsx similarity index 89% rename from src/components/ui/ErrorFound.jsx rename to src/components/ui/ErrorFound.tsx index 494bab4..56ca81a 100644 --- a/src/components/ui/ErrorFound.jsx +++ b/src/components/ui/ErrorFound.tsx @@ -1,4 +1,4 @@ -export default function ErrorFound() { +export default function ErrorFound(): React.ReactElement { return (
diff --git a/src/components/ui/NotFound.jsx b/src/components/ui/NotFound.tsx similarity index 87% rename from src/components/ui/NotFound.jsx rename to src/components/ui/NotFound.tsx index c8992c1..34a8d1e 100644 --- a/src/components/ui/NotFound.jsx +++ b/src/components/ui/NotFound.tsx @@ -1,6 +1,6 @@ -export default function NotFound() { +export default function NotFound(): React.ReactElement { return ( -
+
- - setSearch(event.target.value)} - value={search} - className="outline-none placeholder:text-black" - placeholder="Search..." - /> - {search.length > 0 && ( -
- - setSearch("")} - /> -
- )} - - ); -} diff --git a/src/components/ui/SearchInput.tsx b/src/components/ui/SearchInput.tsx new file mode 100644 index 0000000..75a025a --- /dev/null +++ b/src/components/ui/SearchInput.tsx @@ -0,0 +1,71 @@ +import { ChangeEvent, useEffect, useState } from "react"; +import { Search, X, Circle } from "react-feather"; +import { useDispatch } from "react-redux"; +import { setArticles } from "../../features/articles"; +import { + useGetArticlesQuery, + useSearchArticlesQuery, +} from "../../services/articlesApi"; + +export default function SearchInput(): React.ReactElement { + const [search, setSearch] = useState(""); + const [keyword, setKeyword] = useState(); + const { data: article } = useSearchArticlesQuery(keyword); + const { data: headlines } = useGetArticlesQuery("headlines"); + const [loading, setLoading] = useState(false); + const dispatch = useDispatch(); + + useEffect(() => { + if (keyword) { + dispatch(setArticles(article)); + } + }, [article, dispatch, keyword]); + + const debounce = (cb: Function) => { + let timeout; + if (timeout) clearTimeout(timeout); + timeout = setTimeout(() => { + cb(); + }, 1000); + }; + function onChangleText(event: ChangeEvent): void { + setLoading(true); + setSearch(event.target.value); + debounce(() => { + if (event.target.value.length > 0) { + setLoading(false); + setKeyword(event.target.value); + } + }); + } + + return ( +
+ + + {search.length > 0 && ( +
+ {loading ? ( + + ) : ( + { + setSearch(""); + setKeyword(undefined); + dispatch(setArticles(headlines)); + }} + /> + )} +
+ )} + + ); +} diff --git a/src/components/wrappers/PageWrapper.jsx b/src/components/wrappers/PageWrapper.jsx deleted file mode 100644 index fa45839..0000000 --- a/src/components/wrappers/PageWrapper.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import Header from "../layout/Header"; - -const PageWrapper = ({ children }) => { - return ( -
-
- {children} -
- ); -}; - -export default PageWrapper; diff --git a/src/components/wrappers/PageWrapper.tsx b/src/components/wrappers/PageWrapper.tsx new file mode 100644 index 0000000..1e4ad73 --- /dev/null +++ b/src/components/wrappers/PageWrapper.tsx @@ -0,0 +1,18 @@ +import Header from "../layout/Header"; +type Props = React.PropsWithChildren<{ + as: "div" | "section" | "aside"; +}>; + +const PageWrapper = ({ + as: Component = "section", + children, +}: Props): React.ReactElement => { + return ( + +
+ {children} + + ); +}; + +export default PageWrapper; diff --git a/src/config/reactSlickSetting.js b/src/config/reactSlickSetting.ts similarity index 100% rename from src/config/reactSlickSetting.js rename to src/config/reactSlickSetting.ts diff --git a/src/features/articles.js b/src/features/articles.ts similarity index 55% rename from src/features/articles.js rename to src/features/articles.ts index 30e24bc..d99439d 100644 --- a/src/features/articles.js +++ b/src/features/articles.ts @@ -1,9 +1,10 @@ -import { createSlice } from "@reduxjs/toolkit"; +import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { Article } from "interfaces/articles"; const articlesSlice = createSlice({ name: "articles", initialState: [], reducers: { - setArticles: (state, action) => { + setArticles: (state: Array
, action: PayloadAction) => { return (state = action.payload); }, }, diff --git a/src/index.js b/src/index.tsx similarity index 60% rename from src/index.js rename to src/index.tsx index 510a87d..7e21238 100644 --- a/src/index.js +++ b/src/index.tsx @@ -1,25 +1,27 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; +import { createRoot } from "react-dom/client"; import "react-loading-skeleton/dist/skeleton.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { Provider } from "react-redux"; import store from "./store"; -import PageWrapper from "./components/wrappers/PageWrapper"; +import Wrapper from "./components/wrappers/PageWrapper"; import "./index.css"; import "slick-carousel/slick/slick.css"; import "slick-carousel/slick/slick-theme.css"; import { BrowserRouter } from "react-router-dom"; -const root = ReactDOM.createRoot(document.getElementById("root")); +import { StrictMode } from "react"; + +const root = createRoot(document.getElementById("root")); + root.render( - + - + - + - + ); -reportWebVitals(); +reportWebVitals(undefined); diff --git a/src/interfaces/articles.ts b/src/interfaces/articles.ts new file mode 100644 index 0000000..54df7ff --- /dev/null +++ b/src/interfaces/articles.ts @@ -0,0 +1,18 @@ +export interface Article { + source: Source; + author: string; + title: string; + description: string; + url: string; + urlToImage: string; + publishedAt: string; + content: string; +} +export interface Source { + id: any; + name: string; +} + +export interface Articles { + articles: Article[]; +} diff --git a/src/interfaces/publisher.ts b/src/interfaces/publisher.ts new file mode 100644 index 0000000..8917e7a --- /dev/null +++ b/src/interfaces/publisher.ts @@ -0,0 +1,9 @@ +export interface Publisher { + id: string; + name: string; + description: string; + url: URL; + category: string; + language: string; + country: string; +} diff --git a/src/pages/Article.jsx b/src/pages/Article.tsx similarity index 87% rename from src/pages/Article.jsx rename to src/pages/Article.tsx index 96d5ca3..183f5cf 100644 --- a/src/pages/Article.jsx +++ b/src/pages/Article.tsx @@ -1,16 +1,20 @@ -import { Link, useLocation } from "react-router-dom"; +import { useNavigate, useLocation } from "react-router-dom"; import getDateTime from "../utils/getDateTime"; import { ArrowLeft } from "react-feather"; export default function Article() { const { state } = useLocation(); + const navigate = useNavigate(); const date = new Date(state.publishedAt); return (
- +
navigate(-1)} + className="mt-3 flex items-center gap-5" + > Back - +

{state.title}

diff --git a/src/pages/Articles.jsx b/src/pages/Articles.tsx similarity index 100% rename from src/pages/Articles.jsx rename to src/pages/Articles.tsx diff --git a/src/pages/Home.jsx b/src/pages/Home.tsx similarity index 100% rename from src/pages/Home.jsx rename to src/pages/Home.tsx diff --git a/src/reportWebVitals.js b/src/reportWebVitals.ts similarity index 100% rename from src/reportWebVitals.js rename to src/reportWebVitals.ts diff --git a/src/services/articlesApi.js b/src/services/articlesApi.js deleted file mode 100644 index e45fec5..0000000 --- a/src/services/articlesApi.js +++ /dev/null @@ -1,28 +0,0 @@ -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -const { REACT_APP_API_KEY, REACT_APP_API_URL } = process.env; -export const articlesApi = createApi({ - reducerPath: "articlesApi", - baseQuery: fetchBaseQuery({ - baseUrl: REACT_APP_API_URL, - }), - - endpoints: (builder) => ({ - getArticles: builder.query({ - query: (publisher) => { - if (publisher) { - return publisher === "headlines" - ? `top-headlines?country=us&pageSize=10&apiKey=${REACT_APP_API_KEY}` - : `top-headlines?sources=${publisher}&pageSize=10&apiKey=${REACT_APP_API_KEY}`; - } - }, - transformResponse: (response) => response.articles, - }), - searchArticles: builder.query({ - query: (keyword) => { - return `everything?q=${keyword}&pageSize=10&apiKey=${REACT_APP_API_KEY}`; - }, - transformResponse: (response) => response.articles, - }), - }), -}); -export const { useGetArticlesQuery, useSearchArticlesQuery } = articlesApi; diff --git a/src/services/articlesApi.ts b/src/services/articlesApi.ts new file mode 100644 index 0000000..6eceab0 --- /dev/null +++ b/src/services/articlesApi.ts @@ -0,0 +1,51 @@ +import { EndpointBuilder } from "@reduxjs/toolkit/dist/query/endpointDefinitions"; +import { + BaseQueryFn, + FetchArgs, + FetchBaseQueryError, + FetchBaseQueryMeta, + createApi, + fetchBaseQuery, +} from "@reduxjs/toolkit/query/react"; +import { Articles } from "interfaces/articles"; +const { REACT_APP_API_KEY, REACT_APP_API_URL } = process.env; +export const articlesApi = createApi({ + reducerPath: "articlesApi", + baseQuery: fetchBaseQuery({ + baseUrl: REACT_APP_API_URL, + }), + + endpoints: ( + builder: EndpointBuilder< + BaseQueryFn< + string | FetchArgs, + unknown, + FetchBaseQueryError, + {}, + FetchBaseQueryMeta + >, + never, + "articlesApi" + > + ) => ({ + getArticles: builder.query({ + query: (publisher: string) => { + if (publisher) { + return publisher === "headlines" + ? `top-headlines?country=us&pageSize=10&apiKey=${REACT_APP_API_KEY}` + : `top-headlines?sources=${publisher}&pageSize=10&apiKey=${REACT_APP_API_KEY}`; + } + }, + transformResponse: (response: Articles) => response.articles, + }), + searchArticles: builder.query({ + query: (keyword: string) => { + if (keyword) + return `everything?q=${keyword}&pageSize=10&apiKey=${REACT_APP_API_KEY}`; + }, + transformResponse: (response: Articles) => response.articles, + }), + }), +}); + +export const { useGetArticlesQuery, useSearchArticlesQuery } = articlesApi; diff --git a/src/services/publishersApi.js b/src/services/publishersApi.js deleted file mode 100644 index c510be0..0000000 --- a/src/services/publishersApi.js +++ /dev/null @@ -1,16 +0,0 @@ -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -const { REACT_APP_API_KEY, REACT_APP_API_URL } = process.env; -export const publishersApi = createApi({ - reducerPath: "publishersApi", - baseQuery: fetchBaseQuery({ - baseUrl: REACT_APP_API_URL, - }), - endpoints: (builder) => ({ - getPublisher: builder.query({ - query: () => - `top-headlines/sources?country=us&apiKey=${REACT_APP_API_KEY}`, - }), - }), -}); - -export const { useGetPublisherQuery } = publishersApi; diff --git a/src/services/publishersApi.ts b/src/services/publishersApi.ts new file mode 100644 index 0000000..cb31023 --- /dev/null +++ b/src/services/publishersApi.ts @@ -0,0 +1,36 @@ +import { EndpointBuilder } from "@reduxjs/toolkit/dist/query/endpointDefinitions"; +import { + BaseQueryFn, + FetchArgs, + FetchBaseQueryError, + FetchBaseQueryMeta, + createApi, + fetchBaseQuery, +} from "@reduxjs/toolkit/query/react"; +const { REACT_APP_API_KEY, REACT_APP_API_URL } = process.env; +export const publishersApi = createApi({ + reducerPath: "publishersApi", + baseQuery: fetchBaseQuery({ + baseUrl: REACT_APP_API_URL, + }), + endpoints: ( + builder: EndpointBuilder< + BaseQueryFn< + string | FetchArgs, + unknown, + FetchBaseQueryError, + {}, + FetchBaseQueryMeta + >, + never, + "publishersApi" + > + ) => ({ + getPublisher: builder.query({ + query: () => + `top-headlines/sources?country=us&apiKey=${REACT_APP_API_KEY}`, + }), + }), +}); + +export const { useGetPublisherQuery } = publishersApi; diff --git a/src/setupTests.js b/src/setupTests.ts similarity index 100% rename from src/setupTests.js rename to src/setupTests.ts diff --git a/src/store/index.js b/src/store/index.ts similarity index 100% rename from src/store/index.js rename to src/store/index.ts diff --git a/src/utils/getDateTime.js b/src/utils/getDateTime.ts similarity index 55% rename from src/utils/getDateTime.js rename to src/utils/getDateTime.ts index 951dc50..c621af5 100644 --- a/src/utils/getDateTime.js +++ b/src/utils/getDateTime.ts @@ -12,6 +12,6 @@ const monthNames = [ "Nov", "Dec", ]; -export default function getDateTime(month, day) { - return monthNames[month] + " " + day; +export default function getDateTime(month: number, day: number) { + return monthNames[month] + " " + (day + 1); } diff --git a/tailwind.config.js b/tailwind.config.js index a3d33e0..61408d3 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,6 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ["./src/**/*.{js,jsx}"], + content: ["./src/**/*.{js,jsx,tsx,ts}"], theme: { extend: {}, }, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..10c205a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "jsx": "preserve", + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "module": "commonjs", /* Specify what module code is generated. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}