diff --git a/frontend/package.json b/frontend/package.json index 375a469..c1c7110 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite", "start": "vite --host", - "build": "tsc -b && vite build", + "build": "vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 21a0c3b..fddac47 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -32,7 +32,7 @@ importers: devDependencies: '@testing-library/jest-dom': specifier: ^6.4.6 - version: 6.4.6(vitest@1.6.0(jsdom@24.1.0)) + version: 6.4.6(@types/jest@29.5.12)(vitest@1.6.0(@types/node@22.1.0)(jsdom@24.1.0)) '@testing-library/react': specifier: ^16.0.0 version: 16.0.0(@testing-library/dom@10.2.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -53,7 +53,7 @@ importers: version: 7.14.1(eslint@8.57.0)(typescript@5.5.2) '@vitejs/plugin-react-swc': specifier: ^3.5.0 - version: 3.7.0(vite@5.3.2) + version: 3.7.0(vite@5.3.2(@types/node@22.1.0)) autoprefixer: specifier: ^10.4.19 version: 10.4.19(postcss@8.4.39) @@ -89,10 +89,10 @@ importers: version: 5.5.2 vite: specifier: ^5.3.1 - version: 5.3.2 + version: 5.3.2(@types/node@22.1.0) vitest: specifier: ^1.6.0 - version: 1.6.0(jsdom@24.1.0) + version: 1.6.0(@types/node@22.1.0)(jsdom@24.1.0) packages: @@ -292,10 +292,18 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -546,9 +554,24 @@ packages: '@types/fullpage.js@2.9.6': resolution: {integrity: sha512-NNl9nQc2g7C0Dc7rokZhyy8IJJh/HNVdPE23Tne6nb6rOknetNzwu3gBNP/zMRMeawHRe8i149yWrpzJ4lUwxg==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/jquery@3.5.30': resolution: {integrity: sha512-nbWKkkyb919DOUxjmRVk8vwtDb0/k8FKncmUKFi+NY+QXqWltooxTrswvz4LspQwxvLdvzBN1TImr6cw3aQx2A==} + '@types/node@22.1.0': + resolution: {integrity: sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==} + '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} @@ -561,6 +584,15 @@ packages: '@types/sizzle@2.3.8': resolution: {integrity: sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@typescript-eslint/eslint-plugin@7.14.1': resolution: {integrity: sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==} engines: {node: ^18.18.0 || >=20.0.0} @@ -819,6 +851,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -1004,6 +1040,10 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1065,6 +1105,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1179,6 +1223,9 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -1388,6 +1435,26 @@ packages: resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} engines: {node: '>=14'} + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true @@ -1914,6 +1981,10 @@ packages: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -2076,6 +2147,9 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + undici-types@6.13.0: + resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==} + universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -2382,10 +2456,25 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + optional: true + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.1.0 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + optional: true + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -2537,7 +2626,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.6(vitest@1.6.0(jsdom@24.1.0))': + '@testing-library/jest-dom@6.4.6(@types/jest@29.5.12)(vitest@1.6.0(@types/node@22.1.0)(jsdom@24.1.0))': dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.7 @@ -2548,7 +2637,8 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 optionalDependencies: - vitest: 1.6.0(jsdom@24.1.0) + '@types/jest': 29.5.12 + vitest: 1.6.0(@types/node@22.1.0)(jsdom@24.1.0) '@testing-library/react@16.0.0(@testing-library/dom@10.2.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -2568,10 +2658,34 @@ snapshots: dependencies: '@types/jquery': 3.5.30 + '@types/istanbul-lib-coverage@2.0.6': + optional: true + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + optional: true + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + optional: true + + '@types/jest@29.5.12': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + optional: true + '@types/jquery@3.5.30': dependencies: '@types/sizzle': 2.3.8 + '@types/node@22.1.0': + dependencies: + undici-types: 6.13.0 + optional: true + '@types/prop-types@15.7.12': {} '@types/react-dom@18.3.0': @@ -2585,6 +2699,17 @@ snapshots: '@types/sizzle@2.3.8': {} + '@types/stack-utils@2.0.3': + optional: true + + '@types/yargs-parser@21.0.3': + optional: true + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + optional: true + '@typescript-eslint/eslint-plugin@7.14.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/regexpp': 4.11.0 @@ -2668,10 +2793,10 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.7.0(vite@5.3.2)': + '@vitejs/plugin-react-swc@3.7.0(vite@5.3.2(@types/node@22.1.0))': dependencies: '@swc/core': 1.6.6 - vite: 5.3.2 + vite: 5.3.2(@types/node@22.1.0) transitivePeerDependencies: - '@swc/helpers' @@ -2923,6 +3048,9 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + ci-info@3.9.0: + optional: true + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -3166,6 +3294,9 @@ snapshots: escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: + optional: true + escape-string-regexp@4.0.0: {} eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): @@ -3282,6 +3413,15 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + optional: true + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -3420,6 +3560,9 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + graceful-fs@4.2.11: + optional: true + graphemer@1.4.0: {} has-bigints@1.0.2: {} @@ -3612,6 +3755,48 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + optional: true + + jest-get-type@29.6.3: + optional: true + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + optional: true + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.24.7 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + optional: true + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.1.0 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + optional: true + jiti@1.21.6: {} js-tokens@4.0.0: {} @@ -4141,6 +4326,11 @@ snapshots: source-map-js@1.2.0: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + optional: true + stackback@0.0.2: {} std-env@3.7.0: {} @@ -4350,6 +4540,9 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + undici-types@6.13.0: + optional: true + universalify@0.2.0: {} update-browserslist-db@1.0.16(browserslist@4.23.1): @@ -4369,13 +4562,13 @@ snapshots: util-deprecate@1.0.2: {} - vite-node@1.6.0: + vite-node@1.6.0(@types/node@22.1.0): dependencies: cac: 6.7.14 debug: 4.3.5 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.3.2 + vite: 5.3.2(@types/node@22.1.0) transitivePeerDependencies: - '@types/node' - less @@ -4386,15 +4579,16 @@ snapshots: - supports-color - terser - vite@5.3.2: + vite@5.3.2(@types/node@22.1.0): dependencies: esbuild: 0.21.5 postcss: 8.4.39 rollup: 4.18.0 optionalDependencies: + '@types/node': 22.1.0 fsevents: 2.3.3 - vitest@1.6.0(jsdom@24.1.0): + vitest@1.6.0(@types/node@22.1.0)(jsdom@24.1.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 @@ -4413,10 +4607,11 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.8.0 tinypool: 0.8.4 - vite: 5.3.2 - vite-node: 1.6.0 + vite: 5.3.2(@types/node@22.1.0) + vite-node: 1.6.0(@types/node@22.1.0) why-is-node-running: 2.2.2 optionalDependencies: + '@types/node': 22.1.0 jsdom: 24.1.0 transitivePeerDependencies: - less diff --git a/frontend/src/Router.tsx b/frontend/src/Router.tsx index 74d0bda..b6f4ce4 100644 --- a/frontend/src/Router.tsx +++ b/frontend/src/Router.tsx @@ -16,14 +16,15 @@ import WordList from "./pages/WordList"; import LoadingPage from "./components/LoadingPage.tsx"; // Mocking the isLogin variable for the sake of this example -const isLogin = true; // This should be replaced with your actual login check logic +// This should be replaced with your actual login check logic +const isLogin = true; const PrivateRoutes = () => { const location = useLocation(); - // 未ログインチェック - // (isLoginを判定する処理は省略してます) - if (isLogin === false) { + // Unauthenticated check + // (The process for determining isLogin is omitted) + if (!isLogin) { return ; } return ; @@ -34,7 +35,7 @@ function Router() { } /> - {/* PrivateRoutes内に設定された画面はサインインが必須になる */} + {/* Screens set within PrivateRoutes require sign-in */} }> } /> diff --git a/frontend/src/components/SwipeableCard.test.tsx b/frontend/src/components/SwipeableCard.test.tsx index 5940dfc..d88ccc9 100644 --- a/frontend/src/components/SwipeableCard.test.tsx +++ b/frontend/src/components/SwipeableCard.test.tsx @@ -2,30 +2,33 @@ import React from "react"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { describe, it, expect, vi } from "vitest"; import SwipeableCard from "./SwipeableCard"; +import { DOWN, LEFT, RIGHT, UP } from "react-swipeable/src/types"; const setup = (props = {}) => { const onSwiped = vi.fn(); const utils = render( - , + ); const card = screen.getByText("Test Content"); return { ...utils, card, onSwiped }; }; -const swipe = (element, direction) => { +const swipe = (element: HTMLElement | null, direction: string) => { + if (!element) return; + const touchStart = { clientX: 0, clientY: 0 }; const touchEnd = { clientX: 0, clientY: 0 }; - if (direction === "left") { + if (direction === LEFT) { touchStart.clientX = 100; touchEnd.clientX = 0; - } else if (direction === "right") { + } else if (direction === RIGHT) { touchStart.clientX = 0; touchEnd.clientX = 100; - } else if (direction === "up") { + } else if (direction === UP) { touchStart.clientY = 100; touchEnd.clientY = 0; - } else if (direction === "down") { + } else if (direction === DOWN) { touchStart.clientY = 0; touchEnd.clientY = 100; } @@ -42,17 +45,17 @@ describe("SwipeableCard", () => { }); const swipeDirections = [ - { direction: "left", expectedClass: "text-pink-700 opacity-30" }, - { direction: "right", expectedClass: "text-green-700 opacity-30" }, - { direction: "up", expectedClass: "" }, - { direction: "down", expectedClass: "text-green-700 opacity-30" }, + { direction: LEFT, expectedClass: "text-pink-700 opacity-30" }, + { direction: RIGHT, expectedClass: "text-green-700 opacity-30" }, + { direction: UP, expectedClass: "" }, + { direction: DOWN, expectedClass: "text-green-700 opacity-30" }, ]; swipeDirections.forEach(({ direction, expectedClass }) => { - if (direction === "up") { + if (direction === UP) { it(`flips the card on swipe ${direction}`, async () => { const { container } = setup(); - const card = container.querySelector(".swipeable-card"); + const card = container.querySelector(".swipeable-card") as HTMLElement; swipe(card, direction); // Wait for the flip to complete @@ -75,13 +78,11 @@ describe("SwipeableCard", () => { swipe(card, direction); if (expectedClass) { await waitFor(() => - expect(screen.getByTestId("wartermark-id")).toHaveClass( - expectedClass, - ), + expect(screen.getByTestId("watermark-id")).toHaveClass(expectedClass) ); } else { await waitFor(() => - expect(screen.getByTestId("wartermark-id")).toBeEmptyDOMElement(), + expect(screen.getByTestId("watermark-id")).toBeEmptyDOMElement() ); } }); @@ -90,12 +91,12 @@ describe("SwipeableCard", () => { it("keeps the watermark centered during card flip", async () => { const { getByTestId, container } = setup(); - const watermark = getByTestId("wartermark-id"); - const card = container.querySelector(".swipeable-card"); + const watermark = getByTestId("watermark-id"); + const card = container.querySelector(".swipeable-card") as HTMLElement; // Get watermark position before the flip const initialRect = watermark.getBoundingClientRect(); - swipe(card, "up"); + swipe(card, UP); // Wait for the flip to complete await waitFor(() => { diff --git a/frontend/src/components/SwipeableCard.tsx b/frontend/src/components/SwipeableCard.tsx index 8f1a1c3..5967425 100644 --- a/frontend/src/components/SwipeableCard.tsx +++ b/frontend/src/components/SwipeableCard.tsx @@ -4,6 +4,8 @@ import { IoIosHeart } from "react-icons/io"; import { AiFillDislike } from "react-icons/ai"; import { GrValidate } from "react-icons/gr"; import "./SwipeableCard.css"; +import { DOWN, LEFT, RIGHT, SwipeEventData, UP } from "react-swipeable/src/types"; +import {HandledEvents} from "react-swipeable/src/types.ts"; interface SwipeableCardProps { subtitle: string; @@ -18,40 +20,39 @@ function SwipeableCard({ subtitle, content, onSwiped }: SwipeableCardProps) { const [swipeClass, setSwipeClass] = useState(""); const handlers = useSwipeable({ - onSwipedLeft: () => handleSwipe("left"), - onSwipedRight: () => handleSwipe("right"), - onSwipedUp: () => handleSwipe("up"), - onSwipedDown: () => handleSwipe("down"), - onSwiping: (eventData) => handleSwiping(eventData), - onTap: (eventData) => handleTapping(eventData), + onSwiped: (swipeEventData: SwipeEventData) => handleSwipe(swipeEventData), + onSwiping: (swipeEventData: SwipeEventData) => handleSwiping(swipeEventData), + onTap: (tapEventData) => handleTapping(tapEventData), }); - const handleSwipe = (dir: string) => { - if (dir === "up") { + const handleSwipe = (swipeEventData: SwipeEventData) => { + if (swipeEventData.dir === UP) { setWatermark(null); setIsFlipped(true); } else { setWatermark(null); setSwipeClass(""); - onSwiped(dir); + onSwiped(swipeEventData.dir); } }; - const handleTapping = ({ dir }: { dir: string }) => { - setIsFlipped(false); - console.log(dir); + const handleTapping = (tapEventData: { event: HandledEvents }) => { + if(tapEventData.event.isTrusted) { + setIsFlipped(false); + } }; - const handleSwiping = ({ dir }: { dir: string }) => { - if (dir === "Left") { + const handleSwiping = (eventData: SwipeEventData) => { + const { dir } = eventData; + if (dir === LEFT) { setSwipeClass("swipe-left"); setWatermark(); setWatermarkColor("text-pink-700 opacity-30"); - } else if (dir === "Right") { + } else if (dir === RIGHT) { setSwipeClass("swipe-right"); setWatermark(); setWatermarkColor("text-green-700 opacity-30"); - } else if (dir === "Down") { + } else if (dir === DOWN) { setSwipeClass(""); setWatermark(); setWatermarkColor("text-green-700 opacity-30"); @@ -63,27 +64,27 @@ function SwipeableCard({ subtitle, content, onSwiped }: SwipeableCardProps) { }; return ( - <> -
- {watermark} -
-
-
-

- {subtitle} -

-

{content}

+ <> +
+ {watermark}
+
+
+

+ {subtitle} +

+

{content}

+
-
{content} (Back)
-
- +
{content} (Back)
+
+ ); } diff --git a/frontend/src/components/TopMenu.test.tsx b/frontend/src/components/TopMenu.test.tsx index 73e24d4..d5925e0 100644 --- a/frontend/src/components/TopMenu.test.tsx +++ b/frontend/src/components/TopMenu.test.tsx @@ -1,17 +1,29 @@ -// __tests__/TopMenu.test.tsx import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import "@testing-library/jest-dom"; import React from "react"; -import TopMenu from "./TopMenu"; // Adjust the import path as necessary +import TopMenu from "./TopMenu"; import { BrowserRouter } from "react-router-dom"; import { vi } from "vitest"; // Mock fetch global.fetch = vi.fn(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ results: [] }), - }), + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ results: [] }), + headers: new Headers(), + redirected: false, + status: 200, + statusText: "OK", + type: "basic", + url: "", + clone: () => ({}), + body: null, + bodyUsed: false, + arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), + blob: () => Promise.resolve(new Blob()), + formData: () => Promise.resolve(new FormData()), + text: () => Promise.resolve(""), + } as Response), ); describe("TopMenu Component", () => { @@ -78,9 +90,23 @@ describe("TopMenu Component", () => { test("handles API call failure gracefully", async () => { (global.fetch as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ - ok: false, - }), + Promise.resolve({ + ok: false, + headers: new Headers(), + redirected: false, + status: 500, + statusText: "Internal Server Error", + type: "basic", + url: "", + clone: () => ({}), + body: null, + bodyUsed: false, + arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), + blob: () => Promise.resolve(new Blob()), + formData: () => Promise.resolve(new FormData()), + text: () => Promise.resolve(""), + json: () => Promise.resolve({}), + } as Response), ); render( diff --git a/frontend/src/components/TopMenu.tsx b/frontend/src/components/TopMenu.tsx index d5ca690..0236bec 100644 --- a/frontend/src/components/TopMenu.tsx +++ b/frontend/src/components/TopMenu.tsx @@ -1,11 +1,11 @@ -import React, { useState } from "react"; +import React, { useState, KeyboardEvent } from "react"; import { IoIosSearch, IoIosSettings } from "react-icons/io"; import { Link } from "react-router-dom"; function TopMenu() { const [searchTerm, setSearchTerm] = useState(""); - const handleKeyDown = async (event) => { + const handleKeyDown = async (event: KeyboardEvent) => { if (event.key === "Enter") { // Call the REST API try { diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index e81c8ce..40e3c03 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -11,14 +11,10 @@ function Home() { ]); const [currentCardIndex, setCurrentCardIndex] = useState(0); + const likeMenu = true; - const handleSwiped = (dir: string) => { + const handleSwiped = () => { setCurrentCardIndex((prev) => (prev + 1) % cards.length); - // if (dir === "left") { - // setCurrentCardIndex((prev) => (prev > 0 ? prev - 1 : cards.length - 1)); - // } else if (dir === "right") { - // setCurrentCardIndex((prev) => (prev + 1) % cards.length); - // } }; return ( @@ -32,7 +28,7 @@ function Home() { onSwiped={handleSwiped} /> )} - + ); } diff --git a/frontend/src/pages/WordList.test.tsx b/frontend/src/pages/WordList.test.tsx index a11bbea..3dd3e60 100644 --- a/frontend/src/pages/WordList.test.tsx +++ b/frontend/src/pages/WordList.test.tsx @@ -11,7 +11,7 @@ const mockPeople = [ email: "leslie.alexander@example.com", role: "Co-Founder / CEO", imageUrl: - "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", + "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", lastSeen: "3h ago", lastSeenDateTime: "2023-01-23T13:23Z", }, @@ -20,19 +20,18 @@ const mockPeople = [ email: "michael.foster@example.com", role: "Co-Founder / CTO", imageUrl: - "https://images.unsplash.com/photo-1519244703995-f4e0f30006d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", + "https://images.unsplash.com/photo-1519244703995-f4e0f30006d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", lastSeen: "3h ago", lastSeenDateTime: "2023-01-23T13:23Z", }, - // Add more mock people if necessary ]; // Helper function to render the component const renderComponent = () => { return render( - - - , + + + , ); }; @@ -40,10 +39,10 @@ describe("WordList Component", () => { beforeEach(() => { // Mock the fetch function global.fetch = vi.fn(() => - Promise.resolve({ - json: () => Promise.resolve(mockPeople), - }), - ) as jest.Mock; + Promise.resolve({ + json: () => Promise.resolve(mockPeople), + }), + ) as unknown as jest.Mock; }); it("renders the component and shows the loading state initially", () => { @@ -72,16 +71,16 @@ describe("WordList Component", () => { email: "tom.cook@example.com", role: "Director of Product", imageUrl: - "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", + "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", lastSeen: null, }, ]; global.fetch = vi.fn(() => - Promise.resolve({ - json: () => Promise.resolve(mockPeopleWithOnlineStatus), - }), - ) as jest.Mock; + Promise.resolve({ + json: () => Promise.resolve(mockPeopleWithOnlineStatus), + }), + ) as unknown as jest.Mock; renderComponent(); diff --git a/frontend/src/pages/WordList.tsx b/frontend/src/pages/WordList.tsx index 2456a16..72f2c83 100644 --- a/frontend/src/pages/WordList.tsx +++ b/frontend/src/pages/WordList.tsx @@ -3,7 +3,16 @@ import TopMenu from "../components/TopMenu"; import Menu from "../components/Menu.tsx"; import { FaChevronLeft, FaChevronRight } from "react-icons/fa"; -const peopleInit = [ +interface Person { + name: string; + email: string; + role: string; + imageUrl: string; + lastSeen: string | null; + lastSeenDateTime?: string; +} + +const peopleInit: Person[] = [ { name: "Leslie Alexander", email: "leslie.alexander@example.com", @@ -59,7 +68,7 @@ const peopleInit = [ ]; function WordList() { - const [people, setPeople] = useState([]); + const [people, setPeople] = useState([]); const likeMenu = false; useEffect(() => { diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index ea9d0cd..da45a6d 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,11 +1,21 @@ { - "files": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.node.json" - } - ] + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "skipLibCheck": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "exclude": ["node_modules"] } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 861b04b..07dc33a 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,7 +1,12 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react-swc' -// https://vitejs.dev/config/ export default defineConfig({ + base: '/', plugins: [react()], + build: { + target: 'esnext', // Set for modern browsers compatibility + outDir: 'dist', // Specify the output directory + sourcemap: false, // Disable source map generation + }, }) diff --git a/render.yaml b/render.yaml index 59b5eaa..70cb5df 100644 --- a/render.yaml +++ b/render.yaml @@ -23,7 +23,7 @@ services: repo: https://github.com/yasuflatland-lf/flamingo-armond rootDir: frontend buildCommand: npm install -g pnpm && pnpm install && pnpm run build - staticPublishPath: frontend/build + staticPublishPath: dist envVars: - fromGroup: flamingo-armond buildFilter: