From d245ab2675429940f45c72d1fd6ad589d9f723fe Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sat, 7 Sep 2024 06:48:31 -0400 Subject: [PATCH 01/15] upgrade deps --- package-lock.json | 270 +++++++----------- package.json | 24 +- .../Diagnostics/PlatformDiagnostics.tsx | 2 +- .../Auth/SignIn/components/SignInForm.tsx | 2 +- .../Users/components/UserAdd/UserAddModal.tsx | 2 +- 5 files changed, 123 insertions(+), 177 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0471303..f88b8f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,11 +19,11 @@ "@fortawesome/react-fontawesome": "0.2.2", "@ionic/react": "8.2.7", "@ionic/react-router": "8.2.7", - "@tanstack/react-query": "5.52.1", - "@tanstack/react-query-devtools": "5.52.1", + "@tanstack/react-query": "5.55.0", + "@tanstack/react-query-devtools": "5.55.0", "@types/react-router": "5.1.20", "@types/react-router-dom": "5.3.3", - "axios": "1.7.5", + "axios": "1.7.7", "classnames": "2.5.1", "dayjs": "1.11.13", "formik": "2.4.6", @@ -39,28 +39,28 @@ "@capacitor/cli": "6.1.2", "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "6.5.0", - "@testing-library/react": "16.0.0", + "@testing-library/react": "16.0.1", "@testing-library/user-event": "14.5.2", "@types/lodash": "4.17.7", - "@types/react": "18.3.4", + "@types/react": "18.3.5", "@types/react-dom": "18.3.0", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.2.0", - "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/eslint-plugin": "8.4.0", + "@typescript-eslint/parser": "8.4.0", "@vitejs/plugin-legacy": "5.4.2", "@vitejs/plugin-react": "4.3.1", "@vitest/coverage-v8": "2.0.5", - "cypress": "13.13.3", + "cypress": "13.14.2", "eslint": "8.57.0", - "eslint-plugin-react": "7.35.0", + "eslint-plugin-react": "7.35.2", "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.11", "jsdom": "25.0.0", - "msw": "2.3.5", - "sass": "1.77.8", + "msw": "2.4.2", + "sass": "1.78.0", "terser": "5.31.6", "typescript": "5.5.4", - "vite": "5.4.2", + "vite": "5.4.3", "vitest": "2.0.5" } }, @@ -3434,9 +3434,9 @@ ] }, "node_modules/@stencil/core": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.20.0.tgz", - "integrity": "sha512-WPrTHFngvN081RY+dJPneKQLwnOFD60OMCOQGmmSHfCW0f4ujPMzzhwWU1gcSwXPWXz5O+8cBiiCaxAbJU7kAg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.21.0.tgz", + "integrity": "sha512-v50lnVbzS8mpMSnEVxR+G75XpvxHKtkJaQrNPE8+/fF6Ppr5z4bcdcBhcP8LPfEW+4BZcic6VifMXRwTopc+kw==", "bin": { "stencil": "bin/stencil" }, @@ -3446,29 +3446,29 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.52.0.tgz", - "integrity": "sha512-U1DOEgltjUwalN6uWYTewSnA14b+tE7lSylOiASKCAO61ENJeCq9VVD/TXHA6O5u9+6v5+UgGYBSccTKDoyMqw==", + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.54.1.tgz", + "integrity": "sha512-hKS+WRpT5zBFip21pB6Jx1C0hranWQrbv5EJ7qPoiV5MYI3C8rTCqWC9DdBseiPT1JgQWh8Y55YthuYZNiw3Xw==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/query-devtools": { - "version": "5.51.16", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.51.16.tgz", - "integrity": "sha512-ajwuq4WnkNCMj/Hy3KR8d3RtZ6PSKc1dD2vs2T408MdjgKzQ3klVoL6zDgVO7X+5jlb5zfgcO3thh4ojPhfIaw==", + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.54.0.tgz", + "integrity": "sha512-B8Sa6mh7/4m2fyk2/YnUXeOZ1/us7G/C/i1It8YcCbieXc8vf1AdSYjR+mZIoJeKOKLqA741hZqfj8d4F1NCVg==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "5.52.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.52.1.tgz", - "integrity": "sha512-soyn4dNIUZ8US8NaPVXv06gkZFHaZnPfKWPDjRJjFRW3Y7WZ0jx72eT6zhw3VQlkMPysmXye8l35ewPHspKgbQ==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.55.0.tgz", + "integrity": "sha512-2uYuxEbRQD8TORUiTUacEOwt1e8aoSqUOJFGY5TUrh6rQ3U85zrMS2wvbNhBhXGh6Vj69QDCP2yv8tIY7joo6Q==", "dependencies": { - "@tanstack/query-core": "5.52.0" + "@tanstack/query-core": "5.54.1" }, "funding": { "type": "github", @@ -3479,18 +3479,18 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.52.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.52.1.tgz", - "integrity": "sha512-6KwSm9vcIIK26osQJtT52Gyccz/DyHPT216B7kt4ihg22G2rtGZ7sCXYQO25XEHyVwVingwHdZ7auj+ydgg4Zg==", + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.55.0.tgz", + "integrity": "sha512-omUloSS7Ru+LNmXeK56ygtAgMXMR5M74v8kn4lRjMkjT/aTJHWGI2yJh0I1EE1a8tjwXyviqy+qWfJaeqQcTIA==", "dependencies": { - "@tanstack/query-devtools": "5.51.16" + "@tanstack/query-devtools": "5.54.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.52.1", + "@tanstack/react-query": "^5.55.0", "react": "^18 || ^19" } }, @@ -3553,9 +3553,9 @@ "dev": true }, "node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5" @@ -3704,9 +3704,9 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", - "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", + "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -3793,16 +3793,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", - "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.4.0.tgz", + "integrity": "sha512-rg8LGdv7ri3oAlenMACk9e+AR4wUV0yrrG+XKsGKOK0EVgeEDqurkXMPILG2836fW4ibokTB5v4b6Z9+GYQDEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/type-utils": "8.2.0", - "@typescript-eslint/utils": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.4.0", + "@typescript-eslint/type-utils": "8.4.0", + "@typescript-eslint/utils": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3826,15 +3826,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", - "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.4.0.tgz", + "integrity": "sha512-NHgWmKSgJk5K9N16GIhQ4jSobBoJwrmURaLErad0qlLjrpP5bECYg+wxVTGlGZmJbU03jj/dfnb6V9bw+5icsA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.4.0", + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/typescript-estree": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0", "debug": "^4.3.4" }, "engines": { @@ -3854,13 +3854,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", - "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.4.0.tgz", + "integrity": "sha512-n2jFxLeY0JmKfUqy3P70rs6vdoPjHK8P/w+zJcV3fk0b0BwRXC/zxRTEnAsgYT7MwdQDt/ZEbtdzdVC+hcpF0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0" + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3871,13 +3871,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", - "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.4.0.tgz", + "integrity": "sha512-pu2PAmNrl9KX6TtirVOrbLPLwDmASpZhK/XU7WvoKoCUkdtq9zF7qQ7gna0GBZFN0hci0vHaSusiL2WpsQk37A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/typescript-estree": "8.4.0", + "@typescript-eslint/utils": "8.4.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3895,9 +3895,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", - "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.4.0.tgz", + "integrity": "sha512-T1RB3KQdskh9t3v/qv7niK6P8yvn7ja1mS7QK7XfRVL6wtZ8/mFs/FHf4fKvTA0rKnqnYxl/uHFNbnEt0phgbw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3908,15 +3908,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", - "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.4.0.tgz", + "integrity": "sha512-kJ2OIP4dQw5gdI4uXsaxUZHRwWAGpREJ9Zq6D5L0BweyOrWsL6Sz0YcAZGWhvKnH7fm1J5YFE1JrQL0c9dd53A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -3972,15 +3972,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", - "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.4.0.tgz", + "integrity": "sha512-swULW8n1IKLjRAgciCkTCafyTHHfwVQFt8DovmaF69sKbOxTSFMmIZaSHjqO9i/RV0wIblaawhzvtva8Nmm7lQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0" + "@typescript-eslint/scope-manager": "8.4.0", + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/typescript-estree": "8.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3994,12 +3994,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", - "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.4.0.tgz", + "integrity": "sha512-zTQD6WLNTre1hj5wp09nBIDiOc2U5r/qmzo7wxPn4ZgAjHql09EofqhF9WF+fZHzL5aCyaIpPcT2hyxl73kr9A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/types": "8.4.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -4371,15 +4371,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -4561,9 +4552,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", - "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -5240,9 +5231,9 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.13.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.3.tgz", - "integrity": "sha512-hUxPrdbJXhUOTzuML+y9Av7CKoYznbD83pt8g3klgpioEha0emfx4WNIuVRx0C76r0xV2MIwAW9WYiXfVJYFQw==", + "version": "13.14.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz", + "integrity": "sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5510,18 +5501,6 @@ "node": ">=6" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -5896,9 +5875,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", - "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", + "version": "7.35.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz", + "integrity": "sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==", "dev": true, "dependencies": { "array-includes": "^3.1.8", @@ -6697,26 +6676,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -6746,6 +6705,8 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -8211,9 +8172,9 @@ "dev": true }, "node_modules/msw": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.3.5.tgz", - "integrity": "sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.4.2.tgz", + "integrity": "sha512-GImSQGhn19czhVpxPdiUDK8CMZ6jbBcvOhzfJd8KFErjEER2wDKWs1UYaetJs2GSNlAqt6heZYm7g3eLatTcog==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -8226,7 +8187,6 @@ "@types/cookie": "^0.6.0", "@types/statuses": "^2.0.4", "chalk": "^4.1.2", - "graphql": "^16.8.1", "headers-polyfill": "^4.0.2", "is-node-process": "^1.2.0", "outvariant": "^1.4.2", @@ -8245,9 +8205,13 @@ "url": "https://github.com/sponsors/mswjs" }, "peerDependencies": { - "typescript": ">= 4.7.x" + "graphql": ">= 16.8.x", + "typescript": ">= 4.8.x" }, "peerDependenciesMeta": { + "graphql": { + "optional": true + }, "typescript": { "optional": true } @@ -8678,15 +8642,6 @@ "isarray": "0.0.1" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -8765,9 +8720,9 @@ } }, "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "version": "8.4.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", "dev": true, "funding": [ { @@ -9435,9 +9390,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.77.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", - "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", + "version": "1.78.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.78.0.tgz", + "integrity": "sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -9575,15 +9530,6 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -10487,13 +10433,13 @@ } }, "node_modules/vite": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", - "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.3.tgz", + "integrity": "sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.41", + "postcss": "^8.4.43", "rollup": "^4.20.0" }, "bin": { diff --git a/package.json b/package.json index 618b6cc..8a38f0c 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,11 @@ "@fortawesome/react-fontawesome": "0.2.2", "@ionic/react": "8.2.7", "@ionic/react-router": "8.2.7", - "@tanstack/react-query": "5.52.1", - "@tanstack/react-query-devtools": "5.52.1", + "@tanstack/react-query": "5.55.0", + "@tanstack/react-query-devtools": "5.55.0", "@types/react-router": "5.1.20", "@types/react-router-dom": "5.3.3", - "axios": "1.7.5", + "axios": "1.7.7", "classnames": "2.5.1", "dayjs": "1.11.13", "formik": "2.4.6", @@ -49,28 +49,28 @@ "@capacitor/cli": "6.1.2", "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "6.5.0", - "@testing-library/react": "16.0.0", + "@testing-library/react": "16.0.1", "@testing-library/user-event": "14.5.2", "@types/lodash": "4.17.7", - "@types/react": "18.3.4", + "@types/react": "18.3.5", "@types/react-dom": "18.3.0", "@types/uuid": "10.0.0", - "@typescript-eslint/eslint-plugin": "8.2.0", - "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/eslint-plugin": "8.4.0", + "@typescript-eslint/parser": "8.4.0", "@vitejs/plugin-legacy": "5.4.2", "@vitejs/plugin-react": "4.3.1", "@vitest/coverage-v8": "2.0.5", - "cypress": "13.13.3", + "cypress": "13.14.2", "eslint": "8.57.0", - "eslint-plugin-react": "7.35.0", + "eslint-plugin-react": "7.35.2", "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.11", "jsdom": "25.0.0", - "msw": "2.3.5", - "sass": "1.77.8", + "msw": "2.4.2", + "sass": "1.78.0", "terser": "5.31.6", "typescript": "5.5.4", - "vite": "5.4.2", + "vite": "5.4.3", "vitest": "2.0.5" } } diff --git a/src/pages/Account/components/Diagnostics/PlatformDiagnostics.tsx b/src/pages/Account/components/Diagnostics/PlatformDiagnostics.tsx index 8b53d74..b35882a 100644 --- a/src/pages/Account/components/Diagnostics/PlatformDiagnostics.tsx +++ b/src/pages/Account/components/Diagnostics/PlatformDiagnostics.tsx @@ -36,7 +36,7 @@ const PlatformDiagnostics = ({ )} - Platforms + Platforms {platforms.map((platform) => ( diff --git a/src/pages/Auth/SignIn/components/SignInForm.tsx b/src/pages/Auth/SignIn/components/SignInForm.tsx index 40b7d24..e3a61f9 100644 --- a/src/pages/Auth/SignIn/components/SignInForm.tsx +++ b/src/pages/Auth/SignIn/components/SignInForm.tsx @@ -130,7 +130,7 @@ const SignInForm = ({ className, testid = 'form-signin' }: SignInFormProps): JSX - +

This example application uses{' '} } - + {error && ( Date: Sat, 7 Sep 2024 07:01:23 -0400 Subject: [PATCH 02/15] meta tag --- index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.html b/index.html index b0fdf8c..481a712 100644 --- a/index.html +++ b/index.html @@ -22,6 +22,8 @@ + +

From 4f63703e5c897a9d07350203502d03c615507973 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:20:15 -0400 Subject: [PATCH 03/15] initial Textarea --- src/common/components/Input/Textarea.tsx | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/common/components/Input/Textarea.tsx diff --git a/src/common/components/Input/Textarea.tsx b/src/common/components/Input/Textarea.tsx new file mode 100644 index 0000000..9507836 --- /dev/null +++ b/src/common/components/Input/Textarea.tsx @@ -0,0 +1,52 @@ +import { IonTextarea, TextareaCustomEvent } from '@ionic/react'; +import { ComponentPropsWithoutRef } from 'react'; +import classNames from 'classnames'; + +import { PropsWithTestId } from '../types'; +import { useField } from 'formik'; + +/** + * Properties for the `Textarea` component. + * @see {@link PropsWithTestId} + * @see {@link IonTextarea} + */ +interface TextareaProps + extends PropsWithTestId, + Omit, 'name'>, + Required, 'name'>> {} + +/** + * The `Textarea` component renders a standardized `IonTextarea` which is + * integrated with Formik. + * + * @param {TextareaProps} props - Component properties. + * @returns {JSX.Element} JSX + */ +const Textarea = ({ + className, + testid = 'textarea', + ...textareaProps +}: TextareaProps): JSX.Element => { + const [field, meta, helpers] = useField(textareaProps.name); + + return ( + { + await helpers.setValue(e.detail.value); + }} + data-testid={testid} + {...field} + {...textareaProps} + errorText={meta.error} + > + ); +}; + +export default Textarea; From 817dffacefdf0b8fabc621f7e55f37c57cd95572 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:21:16 -0400 Subject: [PATCH 04/15] initial useGetProfile --- src/pages/Account/api/useGetProfile.ts | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/pages/Account/api/useGetProfile.ts diff --git a/src/pages/Account/api/useGetProfile.ts b/src/pages/Account/api/useGetProfile.ts new file mode 100644 index 0000000..0f0752f --- /dev/null +++ b/src/pages/Account/api/useGetProfile.ts @@ -0,0 +1,35 @@ +import { useQuery } from '@tanstack/react-query'; + +import { Profile } from 'common/models/profile'; +import { User } from 'common/models/user'; +import { QueryKey, StorageKey } from 'common/utils/constants'; +import storage from 'common/utils/storage'; + +/** + * A query hook to fetch the user `Profile` values. + * @returns Returns a `UserQueryResult` with `Profile` data. + */ +export const useGetProfile = () => { + const getProfile = async (): Promise => { + return new Promise((resolve, reject) => { + try { + const storedProfile = storage.getItem(StorageKey.UserProfile); + if (storedProfile) { + return resolve(JSON.parse(storedProfile)); + } else { + const storedUser = storage.getItem(StorageKey.User); + if (storedUser) { + const user: User = JSON.parse(storedUser); + return resolve({ name: user.name, email: user.email }); + } else { + return reject('Profile not found.'); + } + } + } catch (err) { + return reject(err); + } + }); + }; + + return useQuery({ queryKey: [QueryKey.UserProfile], queryFn: () => getProfile() }); +}; From 6e9bb179a96054c307305a5f8fba9f123f334979 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:21:58 -0400 Subject: [PATCH 05/15] Profile type --- src/common/models/profile.ts | 8 +++++++ src/common/utils/constants.ts | 2 ++ src/pages/Account/api/useUpdateProfile.ts | 27 ++++++++--------------- 3 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 src/common/models/profile.ts diff --git a/src/common/models/profile.ts b/src/common/models/profile.ts new file mode 100644 index 0000000..9da227b --- /dev/null +++ b/src/common/models/profile.ts @@ -0,0 +1,8 @@ +import { User } from './user'; + +/** + * The `Profile` type. + */ +export type Profile = Pick & { + bio?: string; +}; diff --git a/src/common/utils/constants.ts b/src/common/utils/constants.ts index 31c1528..1904897 100644 --- a/src/common/utils/constants.ts +++ b/src/common/utils/constants.ts @@ -6,6 +6,7 @@ import { Settings } from 'common/models/settings'; export enum QueryKey { AppInfo = 'AppInfo', Settings = 'Settings', + UserProfile = 'UserProfile', Users = 'Users', UserTokens = 'UserTokens', } @@ -15,6 +16,7 @@ export enum QueryKey { */ export enum StorageKey { Settings = 'ionic-playground.settings', + UserProfile = 'ionic-playground.user-profile', User = 'ionic-playground.user', UserTokens = 'ionic-playground.user-tokens', } diff --git a/src/pages/Account/api/useUpdateProfile.ts b/src/pages/Account/api/useUpdateProfile.ts index b187ae5..04b06bb 100644 --- a/src/pages/Account/api/useUpdateProfile.ts +++ b/src/pages/Account/api/useUpdateProfile.ts @@ -1,14 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { User } from 'common/models/user'; +import { Profile } from 'common/models/profile'; import { QueryKey, StorageKey } from 'common/utils/constants'; import storage from 'common/utils/storage'; -/** - * The `Profile` object. This is a contrived type for demonstration purposes. - */ -export type Profile = Pick; - /** * The `useUpdateProfile` mutatation function variables. * @param {Profile} profile - The updated `Profile` object. @@ -27,18 +22,14 @@ export type UpdateProfileVariables = { export const useUpdateProfile = () => { const queryClient = useQueryClient(); - const updateProfile = ({ profile }: UpdateProfileVariables): Promise => { + const updateProfile = ({ profile }: UpdateProfileVariables): Promise => { return new Promise((resolve, reject) => { try { - const storedProfile = storage.getItem(StorageKey.User); - if (storedProfile) { - const currentProfile: User = JSON.parse(storedProfile); - const updatedProfile: User = { ...currentProfile, ...profile }; - storage.setItem(StorageKey.User, JSON.stringify(updatedProfile)); - return resolve(updatedProfile); - } else { - return reject(new Error('Profile not found.')); - } + const storedProfile = storage.getItem(StorageKey.UserProfile) ?? '{}'; + const currentProfile: Profile = JSON.parse(storedProfile); + const updatedProfile: Profile = { ...currentProfile, ...profile }; + storage.setItem(StorageKey.UserProfile, JSON.stringify(updatedProfile)); + return resolve(updatedProfile); } catch (err) { return reject(err); } @@ -49,9 +40,9 @@ export const useUpdateProfile = () => { mutationFn: updateProfile, onSuccess: (data) => { // update cached query data - queryClient.setQueryData([QueryKey.Users, 'current'], data); + queryClient.setQueryData([QueryKey.UserProfile], data); // you may [also|instead] choose to invalidate certain cached queries, triggering refetch - // queryClient.invalidateQueries({ queryKey: [QueryKey.Users, 'current'] }); + // queryClient.invalidateQueries({ queryKey: [QueryKey.UserProfile] }); }, }); }; From b50ee295b0ecb415a53b66c41e06e95495a62225 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:22:18 -0400 Subject: [PATCH 06/15] ProfileForm changes --- .../components/Profile/ProfileForm.tsx | 54 ++++++------------- .../components/Profile/ProfilePage.tsx | 8 +-- 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/src/pages/Account/components/Profile/ProfileForm.tsx b/src/pages/Account/components/Profile/ProfileForm.tsx index 36592aa..c4de8b4 100644 --- a/src/pages/Account/components/Profile/ProfileForm.tsx +++ b/src/pages/Account/components/Profile/ProfileForm.tsx @@ -6,7 +6,7 @@ import classNames from 'classnames'; import './ProfileForm.scss'; import { BaseComponentProps } from 'common/components/types'; -import { User } from 'common/models/user'; +import { Profile } from 'common/models/profile'; import { useProgress } from 'common/hooks/useProgress'; import { useUpdateProfile } from 'pages/Account/api/useUpdateProfile'; import { useToasts } from 'common/hooks/useToasts'; @@ -14,12 +14,13 @@ import { DismissButton } from 'common/components/Toast/Toast'; import ErrorCard from 'common/components/Card/ErrorCard'; import Input from 'common/components/Input/Input'; import ButtonRow from 'common/components/Button/ButtonRow'; +import Textarea from 'common/components/Input/Textarea'; /** * Profile form values. * @see {@link User} */ -type ProfileFormValues = Pick; +type ProfileFormValues = Profile; /** * Properties for the `ProfileForm` component. @@ -27,7 +28,7 @@ type ProfileFormValues = Pick({ name: string().required('Required. '), - username: string() - .required('Required. ') - .min(8, 'Must be at least 8 characters. ') - .max(30, 'Must be at most 30 characters. '), email: string().required('Required. ').email('Must be an email address. '), - phone: string().required('Required. '), - website: string().url('Must be a URL. '), + bio: string().max(500, 'Must be 500 characters or less. '), }); /** @@ -52,7 +48,7 @@ const validationSchema = object({ const ProfileForm = ({ className, testid = 'form-profile', - user, + profile, }: ProfileFormProps): JSX.Element => { const focusInput = useRef(null); const [error, setError] = useState(''); @@ -82,11 +78,9 @@ const ProfileForm = ({ enableReinitialize={true} initialValues={{ - email: user.email, - name: user.name, - phone: user.phone, - username: user.username, - website: user.website, + email: profile.email, + name: profile.name, + bio: profile.bio, }} onSubmit={(values, { setSubmitting }) => { setProgress(true); @@ -125,16 +119,6 @@ const ProfileForm = ({ ref={focusInput} data-testid={`${testid}-field-name`} /> - - - diff --git a/src/pages/Account/components/Profile/ProfilePage.tsx b/src/pages/Account/components/Profile/ProfilePage.tsx index a85d266..49fb132 100644 --- a/src/pages/Account/components/Profile/ProfilePage.tsx +++ b/src/pages/Account/components/Profile/ProfilePage.tsx @@ -1,7 +1,7 @@ import { IonCol, IonContent, IonGrid, IonPage, IonRow } from '@ionic/react'; import { PropsWithTestId } from 'common/components/types'; -import { useGetCurrentUser } from 'common/api/useGetCurrentUser'; +import { useGetProfile } from 'pages/Account/api/useGetProfile'; import ProgressProvider from 'common/providers/ProgressProvider'; import Container from 'common/components/Content/Container'; import LoaderSkeleton from 'common/components/Loader/LoaderSkeleton'; @@ -12,7 +12,7 @@ import ErrorCard from 'common/components/Card/ErrorCard'; import CardRow from 'common/components/Card/CardRow'; const ProfilePage = ({ testid = 'page-profile' }: PropsWithTestId): JSX.Element => { - const { data: user, isError, isLoading } = useGetCurrentUser(); + const { data: profile, isError, isLoading } = useGetProfile(); return ( @@ -38,7 +38,7 @@ const ProfilePage = ({ testid = 'page-profile' }: PropsWithTestId): JSX.Element )} - {user && ( + {profile && ( <>
Profile
@@ -47,7 +47,7 @@ const ProfilePage = ({ testid = 'page-profile' }: PropsWithTestId): JSX.Element - + From ae2ffbf0a1e9c378f6d1bfe687de292193787531 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:30:04 -0400 Subject: [PATCH 07/15] forwardRef support --- src/common/components/Input/Textarea.tsx | 55 +++++++++++++----------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/common/components/Input/Textarea.tsx b/src/common/components/Input/Textarea.tsx index 9507836..aee4fd4 100644 --- a/src/common/components/Input/Textarea.tsx +++ b/src/common/components/Input/Textarea.tsx @@ -1,5 +1,5 @@ import { IonTextarea, TextareaCustomEvent } from '@ionic/react'; -import { ComponentPropsWithoutRef } from 'react'; +import { ComponentPropsWithoutRef, forwardRef } from 'react'; import classNames from 'classnames'; import { PropsWithTestId } from '../types'; @@ -19,34 +19,37 @@ interface TextareaProps * The `Textarea` component renders a standardized `IonTextarea` which is * integrated with Formik. * + * Optionally accepts a forwarded `ref` which allows the parent to manipulate + * the textarea, performing actions programmatically such as giving focus. + * * @param {TextareaProps} props - Component properties. * @returns {JSX.Element} JSX */ -const Textarea = ({ - className, - testid = 'textarea', - ...textareaProps -}: TextareaProps): JSX.Element => { - const [field, meta, helpers] = useField(textareaProps.name); +const Textarea = forwardRef( + ({ className, testid = 'textarea', ...textareaProps }: TextareaProps, ref): JSX.Element => { + const [field, meta, helpers] = useField(textareaProps.name); - return ( - { - await helpers.setValue(e.detail.value); - }} - data-testid={testid} - {...field} - {...textareaProps} - errorText={meta.error} - > - ); -}; + return ( + { + await helpers.setValue(e.detail.value); + }} + data-testid={testid} + {...field} + {...textareaProps} + errorText={meta.error} + ref={ref} + > + ); + }, +); +Textarea.displayName = 'Textarea'; export default Textarea; From 31c8d203f9487584b16f4882ce1e698a56e92007 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:33:58 -0400 Subject: [PATCH 08/15] docs --- src/pages/Account/components/Profile/ProfilePage.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/Account/components/Profile/ProfilePage.tsx b/src/pages/Account/components/Profile/ProfilePage.tsx index 49fb132..14c1612 100644 --- a/src/pages/Account/components/Profile/ProfilePage.tsx +++ b/src/pages/Account/components/Profile/ProfilePage.tsx @@ -11,6 +11,13 @@ import ProfileForm from './ProfileForm'; import ErrorCard from 'common/components/Card/ErrorCard'; import CardRow from 'common/components/Card/CardRow'; +/** + * The `ProfilePage` component renders the page layout for the user profile + * management page. + * + * @param {PropsWithTestId} props - Component properties. + * @returns {JSX.Element} JSX + */ const ProfilePage = ({ testid = 'page-profile' }: PropsWithTestId): JSX.Element => { const { data: profile, isError, isLoading } = useGetProfile(); From 7dfa769c82e9d1f5cdcf01014e80ff94f7f7065a Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 06:41:45 -0400 Subject: [PATCH 09/15] sign out --- src/pages/Auth/SignOut/api/useSignOut.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/Auth/SignOut/api/useSignOut.ts b/src/pages/Auth/SignOut/api/useSignOut.ts index f7c95f3..6f5d8ab 100644 --- a/src/pages/Auth/SignOut/api/useSignOut.ts +++ b/src/pages/Auth/SignOut/api/useSignOut.ts @@ -23,6 +23,7 @@ export const useSignOut = () => { try { storage.removeItem(StorageKey.UserTokens); storage.removeItem(StorageKey.User); + storage.removeItem(StorageKey.UserProfile); resolve(); } catch (err) { reject(err); @@ -35,6 +36,7 @@ export const useSignOut = () => { onSuccess: () => { queryClient.resetQueries({ queryKey: [QueryKey.UserTokens] }); queryClient.resetQueries({ queryKey: [QueryKey.Users] }); + queryClient.resetQueries({ queryKey: [QueryKey.UserProfile] }); }, }); }; From e2cc6a51164485f8df61301cd2e8c3fdc076ffe3 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 07:40:08 -0400 Subject: [PATCH 10/15] tests --- src/__fixtures__/profiles.ts | 7 ++ src/common/models/profile.ts | 2 +- .../api/__tests__/useGetProfile.test.ts | 74 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/__fixtures__/profiles.ts create mode 100644 src/pages/Account/api/__tests__/useGetProfile.test.ts diff --git a/src/__fixtures__/profiles.ts b/src/__fixtures__/profiles.ts new file mode 100644 index 0000000..83d347b --- /dev/null +++ b/src/__fixtures__/profiles.ts @@ -0,0 +1,7 @@ +import { Profile } from 'common/models/profile'; + +export const profileFixture1: Profile = { + name: 'Test User', + email: 'test1@example.com', + bio: 'My name is Test User.', +}; diff --git a/src/common/models/profile.ts b/src/common/models/profile.ts index 9da227b..11fd134 100644 --- a/src/common/models/profile.ts +++ b/src/common/models/profile.ts @@ -1,7 +1,7 @@ import { User } from './user'; /** - * The `Profile` type. + * The [user] `Profile` type. */ export type Profile = Pick & { bio?: string; diff --git a/src/pages/Account/api/__tests__/useGetProfile.test.ts b/src/pages/Account/api/__tests__/useGetProfile.test.ts new file mode 100644 index 0000000..13924c2 --- /dev/null +++ b/src/pages/Account/api/__tests__/useGetProfile.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { renderHook, waitFor } from 'test/test-utils'; +import storage from 'common/utils/storage'; +import { StorageKey } from 'common/utils/constants'; +import { profileFixture1 } from '__fixtures__/profiles'; +import { userFixture1 } from '__fixtures__/users'; + +import { useGetProfile } from '../useGetProfile'; + +describe('useGetProfile', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should get profile', async () => { + // ARRANGE + const getItemSpy = vi.spyOn(storage, 'getItem'); + getItemSpy.mockReturnValue(JSON.stringify(profileFixture1)); + const { result } = renderHook(() => useGetProfile()); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + // ASSERT + expect(result.current.isSuccess).toBe(true); + expect(result.current.data).toEqual(profileFixture1); + }); + + it('should initialize profile from current user', async () => { + // ARRANGE + const getItemSpy = vi.spyOn(storage, 'getItem'); + // no stored profile; use current user + getItemSpy.mockImplementation((key: StorageKey) => { + if (key == StorageKey.UserProfile) return null; + if (key == StorageKey.User) return JSON.stringify(userFixture1); + return null; + }); + const { result } = renderHook(() => useGetProfile()); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + // ASSERT + expect(result.current.isSuccess).toBe(true); + expect(result.current.data?.name).toBe(userFixture1.name); + expect(result.current.data?.email).toBe(userFixture1.email); + expect(result.current.data?.bio).toBeUndefined(); + }); + + it('should error with profile not found', async () => { + // ARRANGE + const getItemSpy = vi.spyOn(storage, 'getItem'); + // no stored profile; use current user + getItemSpy.mockImplementation(() => { + return null; + }); + const { result } = renderHook(() => useGetProfile()); + await waitFor(() => expect(result.current.isError).toBe(true)); + + // ASSERT + expect(result.current.isError).toBe(true); + expect(result.current.error).toBe('Profile not found.'); + }); + + it('should return error', async () => { + // ARRANGE + const getItemSpy = vi.spyOn(storage, 'getItem'); + getItemSpy.mockImplementation(() => { + throw new Error('test'); + }); + const { result } = renderHook(() => useGetProfile()); + await waitFor(() => expect(result.current.isError).toBe(true)); + + // ASSERT + expect(result.current.isError).toBe(true); + }); +}); From dfec55c1d4f23763bdd65fb188b8cdd049d40327 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Sun, 8 Sep 2024 07:46:38 -0400 Subject: [PATCH 11/15] tests --- .../Input/__tests__/Textarea.test.tsx | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/common/components/Input/__tests__/Textarea.test.tsx diff --git a/src/common/components/Input/__tests__/Textarea.test.tsx b/src/common/components/Input/__tests__/Textarea.test.tsx new file mode 100644 index 0000000..2369673 --- /dev/null +++ b/src/common/components/Input/__tests__/Textarea.test.tsx @@ -0,0 +1,44 @@ +import { describe, expect, it } from 'vitest'; +import userEvent from '@testing-library/user-event'; +import { Form, Formik } from 'formik'; + +import { render, screen } from 'test/test-utils'; + +import Textarea from '../Textarea'; + +describe('Textarea', () => { + it('should render successfully', async () => { + // ARRANGE + render( + {}}> +
+