diff --git a/.vscode/settings.json b/.vscode/settings.json index 91af0e49..4d1e42ba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,7 @@ "qaub", "QRSTUVWXYZ", "Reala", + "CredentialsSignin", "skippable", "sonner", "thephotoblog", diff --git a/README.md b/README.md index 6a522602..a0f985d3 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,9 @@ Installation ### 4. Develop locally 1. Clone code -2. Install dependencies `pnpm i` -3. Run `vc dev` to utilize Vercel-stored environment variables +2. Run `pnpm i` to install dependencies +3. Set environment variable `AUTH_URL` locally (not in production) to `http://localhost:3000/api/url` (_this is a temporary limitation of `next-auth` v5.0_) +4. Run `vc dev` to start dev server, and utilize Vercel-stored environment variables ### 5. Add Analytics (optional) @@ -68,8 +69,8 @@ Installation FAQ - -Q: My images/content have fallen out of sync with my database and/or production site no longer matches local development. What do I do?
-A: Navigate to `/admin/configuration` and click the "Clear Cache" button. +Q: My images/content have fallen out of sync with my database and/or my production site no longer matches local development. What do I do?
+A: Navigate to `/admin/configuration` and click "Clear Cache" button. Q: I'm seeing server-side runtime errors when loading a page after updating my fork. What do I do?
-A: Navigate to `/admin/configuration` and click the "Clear Cache" button. If this doesn't help, [open an issue](https://github.com/sambecker/exif-photo-blog/issues/new). +A: Navigate to `/admin/configuration` and click "Clear Cache" button. If this doesn't help, [open an issue](https://github.com/sambecker/exif-photo-blog/issues/new). diff --git a/next.config.js b/next.config.js index 1f6a9f76..7f85dff9 100644 --- a/next.config.js +++ b/next.config.js @@ -19,9 +19,6 @@ const nextConfig = { }], minimumCacheTTL: 31536000, }, - experimental: { - serverActions: true, - }, }; module.exports = withBundleAnalyzer(nextConfig); diff --git a/package.json b/package.json index 14ed1e39..8cf9717c 100644 --- a/package.json +++ b/package.json @@ -9,37 +9,37 @@ "analyze": "ANALYZE=true next build" }, "dependencies": { - "@next/bundle-analyzer": "^13.5.6", + "@next/bundle-analyzer": "^14.0.1", "@tailwindcss/forms": "^0.5.6", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.0.0", - "@types/jest": "^29.5.6", - "@types/node": "^20.8.7", - "@types/react": "18.2.29", - "@types/react-dom": "18.2.8", - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", + "@types/jest": "^29.5.7", + "@types/node": "^20.8.9", + "@types/react": "18.2.33", + "@types/react-dom": "18.2.14", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", "@vercel/analytics": "^1.1.1", - "@vercel/blob": "^0.14.0", + "@vercel/blob": "^0.14.1", "@vercel/postgres": "0.5.0", "autoprefixer": "10.4.16", "camelcase-keys": "^9.1.2", "date-fns": "^2.30.0", - "eslint": "8.51.0", - "eslint-config-next": "13.5.6", + "eslint": "8.52.0", + "eslint-config-next": "14.0.1", "framer-motion": "^10.16.4", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "nanoid": "^5.0.2", - "next": "^13.5.6", - "next-auth": "0.0.0-manual.c885ac1d", + "next": "^14.0.1", + "next-auth": "5.0.0-beta.3", "next-themes": "^0.2.1", "postcss": "8.4.31", "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.11.0", "sonner": "^1.0.3", - "tailwindcss": "3.3.3", + "tailwindcss": "3.3.5", "ts-exif-parser": "^0.2.2", "typescript": "5.2.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f2698b77..2826b6e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,41 +6,41 @@ settings: dependencies: '@next/bundle-analyzer': - specifier: ^13.5.6 - version: 13.5.6 + specifier: ^14.0.1 + version: 14.0.1 '@tailwindcss/forms': specifier: ^0.5.6 - version: 0.5.6(tailwindcss@3.3.3) + version: 0.5.6(tailwindcss@3.3.5) '@testing-library/jest-dom': specifier: ^6.1.4 - version: 6.1.4(@types/jest@29.5.6)(jest@29.7.0) + version: 6.1.4(@types/jest@29.5.7)(jest@29.7.0) '@testing-library/react': specifier: ^14.0.0 version: 14.0.0(react-dom@18.2.0)(react@18.2.0) '@types/jest': - specifier: ^29.5.6 - version: 29.5.6 + specifier: ^29.5.7 + version: 29.5.7 '@types/node': - specifier: ^20.8.7 - version: 20.8.7 + specifier: ^20.8.9 + version: 20.8.9 '@types/react': - specifier: 18.2.29 - version: 18.2.29 + specifier: 18.2.33 + version: 18.2.33 '@types/react-dom': - specifier: 18.2.8 - version: 18.2.8 + specifier: 18.2.14 + version: 18.2.14 '@typescript-eslint/eslint-plugin': - specifier: ^6.8.0 - version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) + specifier: ^6.9.1 + version: 6.9.1(@typescript-eslint/parser@6.9.1)(eslint@8.52.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: ^6.8.0 - version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) + specifier: ^6.9.1 + version: 6.9.1(eslint@8.52.0)(typescript@5.2.2) '@vercel/analytics': specifier: ^1.1.1 version: 1.1.1 '@vercel/blob': - specifier: ^0.14.0 - version: 0.14.0 + specifier: ^0.14.1 + version: 0.14.1 '@vercel/postgres': specifier: 0.5.0 version: 0.5.0 @@ -54,17 +54,17 @@ dependencies: specifier: ^2.30.0 version: 2.30.0 eslint: - specifier: 8.51.0 - version: 8.51.0 + specifier: 8.52.0 + version: 8.52.0 eslint-config-next: - specifier: 13.5.6 - version: 13.5.6(eslint@8.51.0)(typescript@5.2.2) + specifier: 14.0.1 + version: 14.0.1(eslint@8.52.0)(typescript@5.2.2) framer-motion: specifier: ^10.16.4 version: 10.16.4(react-dom@18.2.0)(react@18.2.0) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.8.7) + version: 29.7.0(@types/node@20.8.9) jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 @@ -72,14 +72,14 @@ dependencies: specifier: ^5.0.2 version: 5.0.2 next: - specifier: ^13.5.6 - version: 13.5.6(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0) + specifier: ^14.0.1 + version: 14.0.1(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0) next-auth: - specifier: 0.0.0-manual.c885ac1d - version: 0.0.0-manual.c885ac1d(next@13.5.6)(react@18.2.0) + specifier: 5.0.0-beta.3 + version: 5.0.0-beta.3(next@14.0.1)(react@18.2.0) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@13.5.6)(react-dom@18.2.0)(react@18.2.0) + version: 0.2.1(next@14.0.1)(react-dom@18.2.0)(react@18.2.0) postcss: specifier: 8.4.31 version: 8.4.31 @@ -96,8 +96,8 @@ dependencies: specifier: ^1.0.3 version: 1.0.3(react-dom@18.2.0)(react@18.2.0) tailwindcss: - specifier: 3.3.3 - version: 3.3.3 + specifier: 3.3.5 + version: 3.3.5 ts-exif-parser: specifier: ^0.2.2 version: 0.2.2 @@ -495,13 +495,13 @@ packages: dev: false optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.51.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.52.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.51.0 + eslint: 8.52.0 eslint-visitor-keys: 3.4.3 dev: false @@ -527,8 +527,8 @@ packages: - supports-color dev: false - /@eslint/js@8.51.0: - resolution: {integrity: sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==} + /@eslint/js@8.52.0: + resolution: {integrity: sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: false @@ -537,11 +537,11 @@ packages: engines: {node: '>=14'} dev: false - /@humanwhocodes/config-array@0.11.11: - resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 1.2.1 + '@humanwhocodes/object-schema': 2.0.1 debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: @@ -553,8 +553,8 @@ packages: engines: {node: '>=12.22'} dev: false - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: false /@istanbuljs/load-nyc-config@1.1.0: @@ -578,7 +578,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -599,14 +599,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.8.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.8.7) + jest-config: 29.7.0(@types/node@20.8.9) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -634,7 +634,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 jest-mock: 29.7.0 dev: false @@ -661,7 +661,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.8.7 + '@types/node': 20.8.9 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -694,7 +694,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.19 - '@types/node': 20.8.7 + '@types/node': 20.8.9 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -782,7 +782,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.8.7 + '@types/node': 20.8.9 '@types/yargs': 17.0.24 chalk: 4.1.2 dev: false @@ -823,8 +823,8 @@ packages: '@types/pg': 8.6.6 dev: false - /@next/bundle-analyzer@13.5.6: - resolution: {integrity: sha512-4P5YVpR3N/B5+p0TQ/rPAr+9fsjkdfCVTGzJhKwE7XHqS+QME4gYxAYeGKkfkHEkP2A3GKXs8QSp0LjIvWLI3g==} + /@next/bundle-analyzer@14.0.1: + resolution: {integrity: sha512-AbZZnj4gZ1ZQFppZxAC9e8+skj0rFiSvY6E6Ut+ydS1r6oizR7PMu/7o02psIm4ekAsmp2O1Eq8IowHQgPWPCQ==} dependencies: webpack-bundle-analyzer: 4.7.0 transitivePeerDependencies: @@ -832,18 +832,18 @@ packages: - utf-8-validate dev: false - /@next/env@13.5.6: - resolution: {integrity: sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==} + /@next/env@14.0.1: + resolution: {integrity: sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A==} dev: false - /@next/eslint-plugin-next@13.5.6: - resolution: {integrity: sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg==} + /@next/eslint-plugin-next@14.0.1: + resolution: {integrity: sha512-bLjJMwXdzvhnQOnxvHoTTUh/+PYk6FF/DCgHi4BXwXCINer+o1ZYfL9aVeezj/oI7wqGJOqwGIXrlBvPbAId3w==} dependencies: glob: 7.1.7 dev: false - /@next/swc-darwin-arm64@13.5.6: - resolution: {integrity: sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==} + /@next/swc-darwin-arm64@14.0.1: + resolution: {integrity: sha512-JyxnGCS4qT67hdOKQ0CkgFTp+PXub5W1wsGvIq98TNbF3YEIN7iDekYhYsZzc8Ov0pWEsghQt+tANdidITCLaw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -851,8 +851,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@13.5.6: - resolution: {integrity: sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==} + /@next/swc-darwin-x64@14.0.1: + resolution: {integrity: sha512-625Z7bb5AyIzswF9hvfZWa+HTwFZw+Jn3lOBNZB87lUS0iuCYDHqk3ujuHCkiyPtSC0xFBtYDLcrZ11mF/ap3w==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -860,8 +860,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@13.5.6: - resolution: {integrity: sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==} + /@next/swc-linux-arm64-gnu@14.0.1: + resolution: {integrity: sha512-iVpn3KG3DprFXzVHM09kvb//4CNNXBQ9NB/pTm8LO+vnnnaObnzFdS5KM+w1okwa32xH0g8EvZIhoB3fI3mS1g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -869,8 +869,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@13.5.6: - resolution: {integrity: sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==} + /@next/swc-linux-arm64-musl@14.0.1: + resolution: {integrity: sha512-mVsGyMxTLWZXyD5sen6kGOTYVOO67lZjLApIj/JsTEEohDDt1im2nkspzfV5MvhfS7diDw6Rp/xvAQaWZTv1Ww==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -878,8 +878,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@13.5.6: - resolution: {integrity: sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==} + /@next/swc-linux-x64-gnu@14.0.1: + resolution: {integrity: sha512-wMqf90uDWN001NqCM/auRl3+qVVeKfjJdT9XW+RMIOf+rhUzadmYJu++tp2y+hUbb6GTRhT+VjQzcgg/QTD9NQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -887,8 +887,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@13.5.6: - resolution: {integrity: sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==} + /@next/swc-linux-x64-musl@14.0.1: + resolution: {integrity: sha512-ol1X1e24w4j4QwdeNjfX0f+Nza25n+ymY0T2frTyalVczUmzkVD7QGgPTZMHfR1aLrO69hBs0G3QBYaj22J5GQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -896,8 +896,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@13.5.6: - resolution: {integrity: sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==} + /@next/swc-win32-arm64-msvc@14.0.1: + resolution: {integrity: sha512-WEmTEeWs6yRUEnUlahTgvZteh5RJc4sEjCQIodJlZZ5/VJwVP8p2L7l6VhzQhT4h7KvLx/Ed4UViBdne6zpIsw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -905,8 +905,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@13.5.6: - resolution: {integrity: sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==} + /@next/swc-win32-ia32-msvc@14.0.1: + resolution: {integrity: sha512-oFpHphN4ygAgZUKjzga7SoH2VGbEJXZa/KL8bHCAwCjDWle6R1SpiGOdUdA8EJ9YsG1TYWpzY6FTbUA+iAJeww==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -914,8 +914,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@13.5.6: - resolution: {integrity: sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==} + /@next/swc-win32-x64-msvc@14.0.1: + resolution: {integrity: sha512-FFp3nOJ/5qSpeWT0BZQ+YE1pSMk4IMpkME/1DwKBwhg4mJLB9L+6EXuJi4JEwaJdl5iN+UUlmUD3IsR1kx5fAg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -978,13 +978,13 @@ packages: tslib: 2.6.2 dev: false - /@tailwindcss/forms@0.5.6(tailwindcss@3.3.3): + /@tailwindcss/forms@0.5.6(tailwindcss@3.3.5): resolution: {integrity: sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==} peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.3.3 + tailwindcss: 3.3.5 dev: false /@testing-library/dom@9.3.3: @@ -1001,7 +1001,7 @@ packages: pretty-format: 27.5.1 dev: false - /@testing-library/jest-dom@6.1.4(@types/jest@29.5.6)(jest@29.7.0): + /@testing-library/jest-dom@6.1.4(@types/jest@29.5.7)(jest@29.7.0): resolution: {integrity: sha512-wpoYrCYwSZ5/AxcrjLxJmCU6I5QAJXslEeSiMQqaWmP2Kzpd1LvF/qxmAIW2qposULGWq2gw30GgVNFLSc2Jnw==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} peerDependencies: @@ -1021,12 +1021,12 @@ packages: dependencies: '@adobe/css-tools': 4.3.1 '@babel/runtime': 7.22.15 - '@types/jest': 29.5.6 + '@types/jest': 29.5.7 aria-query: 5.3.0 chalk: 3.0.0 css.escape: 1.5.1 dom-accessibility-api: 0.5.16 - jest: 29.7.0(@types/node@20.8.7) + jest: 29.7.0(@types/node@20.8.9) lodash: 4.17.21 redent: 3.0.0 dev: false @@ -1040,7 +1040,7 @@ packages: dependencies: '@babel/runtime': 7.22.15 '@testing-library/dom': 9.3.3 - '@types/react-dom': 18.2.8 + '@types/react-dom': 18.2.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -1086,7 +1086,7 @@ packages: /@types/graceful-fs@4.1.7: resolution: {integrity: sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==} dependencies: - '@types/node': 20.8.7 + '@types/node': 20.8.9 dev: false /@types/istanbul-lib-coverage@2.0.4: @@ -1105,8 +1105,8 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: false - /@types/jest@29.5.6: - resolution: {integrity: sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==} + /@types/jest@29.5.7: + resolution: {integrity: sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==} dependencies: expect: 29.7.0 pretty-format: 29.7.0 @@ -1115,7 +1115,7 @@ packages: /@types/jsdom@20.0.1: resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} dependencies: - '@types/node': 20.8.7 + '@types/node': 20.8.9 '@types/tough-cookie': 4.0.3 parse5: 7.1.2 dev: false @@ -1128,16 +1128,16 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: false - /@types/node@20.8.7: - resolution: {integrity: sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==} + /@types/node@20.8.9: + resolution: {integrity: sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==} dependencies: - undici-types: 5.25.3 + undici-types: 5.26.5 dev: false /@types/pg@8.6.6: resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} dependencies: - '@types/node': 20.8.7 + '@types/node': 20.8.9 pg-protocol: 1.6.0 pg-types: 2.2.0 dev: false @@ -1146,14 +1146,14 @@ packages: resolution: {integrity: sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg==} dev: false - /@types/react-dom@18.2.8: - resolution: {integrity: sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw==} + /@types/react-dom@18.2.14: + resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==} dependencies: - '@types/react': 18.2.29 + '@types/react': 18.2.33 dev: false - /@types/react@18.2.29: - resolution: {integrity: sha512-Z+ZrIRocWtdD70j45izShRwDuiB4JZqDegqMFW/I8aG5DxxLKOzVNoq62UIO82v9bdgi+DO1jvsb9sTEZUSm+Q==} + /@types/react@18.2.33: + resolution: {integrity: sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==} dependencies: '@types/prop-types': 15.7.6 '@types/scheduler': 0.16.3 @@ -1186,8 +1186,8 @@ packages: '@types/yargs-parser': 21.0.0 dev: false - /@typescript-eslint/eslint-plugin@6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==} + /@typescript-eslint/eslint-plugin@6.9.1(@typescript-eslint/parser@6.9.1)(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -1198,13 +1198,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.8.1 - '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.8.0 - '@typescript-eslint/type-utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/parser': 6.9.1(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.9.1 + '@typescript-eslint/type-utils': 6.9.1(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.9.1(eslint@8.52.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.9.1 debug: 4.3.4 - eslint: 8.51.0 + eslint: 8.52.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -1215,8 +1215,8 @@ packages: - supports-color dev: false - /@typescript-eslint/parser@6.8.0(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==} + /@typescript-eslint/parser@6.9.1(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1225,27 +1225,27 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.8.0 - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/scope-manager': 6.9.1 + '@typescript-eslint/types': 6.9.1 + '@typescript-eslint/typescript-estree': 6.9.1(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.9.1 debug: 4.3.4 - eslint: 8.51.0 + eslint: 8.52.0 typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: false - /@typescript-eslint/scope-manager@6.8.0: - resolution: {integrity: sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==} + /@typescript-eslint/scope-manager@6.9.1: + resolution: {integrity: sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/types': 6.9.1 + '@typescript-eslint/visitor-keys': 6.9.1 dev: false - /@typescript-eslint/type-utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==} + /@typescript-eslint/type-utils@6.9.1(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1254,23 +1254,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.9.1(typescript@5.2.2) + '@typescript-eslint/utils': 6.9.1(eslint@8.52.0)(typescript@5.2.2) debug: 4.3.4 - eslint: 8.51.0 + eslint: 8.52.0 ts-api-utils: 1.0.3(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: false - /@typescript-eslint/types@6.8.0: - resolution: {integrity: sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==} + /@typescript-eslint/types@6.9.1: + resolution: {integrity: sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: false - /@typescript-eslint/typescript-estree@6.8.0(typescript@5.2.2): - resolution: {integrity: sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==} + /@typescript-eslint/typescript-estree@6.9.1(typescript@5.2.2): + resolution: {integrity: sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -1278,8 +1278,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/visitor-keys': 6.8.0 + '@typescript-eslint/types': 6.9.1 + '@typescript-eslint/visitor-keys': 6.9.1 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -1290,45 +1290,49 @@ packages: - supports-color dev: false - /@typescript-eslint/utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==} + /@typescript-eslint/utils@6.9.1(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.2 - '@typescript-eslint/scope-manager': 6.8.0 - '@typescript-eslint/types': 6.8.0 - '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) - eslint: 8.51.0 + '@typescript-eslint/scope-manager': 6.9.1 + '@typescript-eslint/types': 6.9.1 + '@typescript-eslint/typescript-estree': 6.9.1(typescript@5.2.2) + eslint: 8.52.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: false - /@typescript-eslint/visitor-keys@6.8.0: - resolution: {integrity: sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==} + /@typescript-eslint/visitor-keys@6.9.1: + resolution: {integrity: sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/types': 6.9.1 eslint-visitor-keys: 3.4.3 dev: false + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: false + /@vercel/analytics@1.1.1: resolution: {integrity: sha512-+NqgNmSabg3IFfxYhrWCfB/H+RCUOCR5ExRudNG2+pcRehq628DJB5e1u1xqwpLtn4pAYii4D98w7kofORAGQA==} dependencies: server-only: 0.0.1 dev: false - /@vercel/blob@0.14.0: - resolution: {integrity: sha512-+yzFCdejyf9KZObUwBlR/k6aFJoRTL9YZ53Nj+IfXYfPhR1gVyKdGsp/kNd9QHuamrBKtILzMJUuOuwudG5ncQ==} + /@vercel/blob@0.14.1: + resolution: {integrity: sha512-pGdEbzZ6wKJf5tknzeHP6bpDAmWvJQc9IsT2fvmI2hSLG/ir0hLt0ABcYv7W1aMHnSo4VQlcjucKOPMsaePmBg==} engines: {node: '>=16.14'} dependencies: jest-environment-jsdom: 29.7.0 - undici: 5.26.2 + undici: 5.26.4 transitivePeerDependencies: - bufferutil - canvas @@ -1894,7 +1898,7 @@ packages: engines: {node: '>= 0.6'} dev: false - /create-jest@29.7.0(@types/node@20.8.7): + /create-jest@29.7.0(@types/node@20.8.9): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -1903,7 +1907,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.8.7) + jest-config: 29.7.0(@types/node@20.8.9) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -2291,8 +2295,8 @@ packages: source-map: 0.6.1 dev: false - /eslint-config-next@13.5.6(eslint@8.51.0)(typescript@5.2.2): - resolution: {integrity: sha512-o8pQsUHTo9aHqJ2YiZDym5gQAMRf7O2HndHo/JZeY7TDD+W4hk6Ma8Vw54RHiBeb7OWWO5dPirQB+Is/aVQ7Kg==} + /eslint-config-next@14.0.1(eslint@8.52.0)(typescript@5.2.2): + resolution: {integrity: sha512-QfIFK2WD39H4WOespjgf6PLv9Bpsd7KGGelCtmq4l67nGvnlsGpuvj0hIT+aIy6p5gKH+lAChYILsyDlxP52yg==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 typescript: '>=3.3.1' @@ -2300,16 +2304,16 @@ packages: typescript: optional: true dependencies: - '@next/eslint-plugin-next': 13.5.6 + '@next/eslint-plugin-next': 14.0.1 '@rushstack/eslint-patch': 1.4.0 - '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) - eslint: 8.51.0 + '@typescript-eslint/parser': 6.9.1(eslint@8.52.0)(typescript@5.2.2) + eslint: 8.52.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.51.0) - eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.51.0) - eslint-plugin-jsx-a11y: 6.7.1(eslint@8.51.0) - eslint-plugin-react: 7.33.2(eslint@8.51.0) - eslint-plugin-react-hooks: 4.6.0(eslint@8.51.0) + eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.52.0) + eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.52.0) + eslint-plugin-jsx-a11y: 6.7.1(eslint@8.52.0) + eslint-plugin-react: 7.33.2(eslint@8.52.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.52.0) typescript: 5.2.2 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -2326,7 +2330,7 @@ packages: - supports-color dev: false - /eslint-import-resolver-typescript@3.6.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.51.0): + /eslint-import-resolver-typescript@3.6.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.52.0): resolution: {integrity: sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -2335,9 +2339,9 @@ packages: dependencies: debug: 4.3.4 enhanced-resolve: 5.15.0 - eslint: 8.51.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.51.0) - eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.51.0) + eslint: 8.52.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.52.0) + eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.52.0) fast-glob: 3.3.1 get-tsconfig: 4.7.0 is-core-module: 2.13.0 @@ -2349,7 +2353,7 @@ packages: - supports-color dev: false - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.51.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.52.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -2370,16 +2374,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.9.1(eslint@8.52.0)(typescript@5.2.2) debug: 3.2.7 - eslint: 8.51.0 + eslint: 8.52.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.51.0) + eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.52.0) transitivePeerDependencies: - supports-color dev: false - /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-typescript@3.6.0)(eslint@8.51.0): + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.52.0): resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} peerDependencies: @@ -2389,16 +2393,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.9.1(eslint@8.52.0)(typescript@5.2.2) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.51.0 + eslint: 8.52.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.51.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.52.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -2414,7 +2418,7 @@ packages: - supports-color dev: false - /eslint-plugin-jsx-a11y@6.7.1(eslint@8.51.0): + /eslint-plugin-jsx-a11y@6.7.1(eslint@8.52.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} engines: {node: '>=4.0'} peerDependencies: @@ -2429,7 +2433,7 @@ packages: axobject-query: 3.2.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.51.0 + eslint: 8.52.0 has: 1.0.3 jsx-ast-utils: 3.3.5 language-tags: 1.0.5 @@ -2439,16 +2443,16 @@ packages: semver: 6.3.1 dev: false - /eslint-plugin-react-hooks@4.6.0(eslint@8.51.0): + /eslint-plugin-react-hooks@4.6.0(eslint@8.52.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.51.0 + eslint: 8.52.0 dev: false - /eslint-plugin-react@7.33.2(eslint@8.51.0): + /eslint-plugin-react@7.33.2(eslint@8.52.0): resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} peerDependencies: @@ -2459,7 +2463,7 @@ packages: array.prototype.tosorted: 1.1.2 doctrine: 2.1.0 es-iterator-helpers: 1.0.15 - eslint: 8.51.0 + eslint: 8.52.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 @@ -2486,18 +2490,19 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: false - /eslint@8.51.0: - resolution: {integrity: sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==} + /eslint@8.52.0: + resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) '@eslint-community/regexpp': 4.8.1 '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.51.0 - '@humanwhocodes/config-array': 0.11.11 + '@eslint/js': 8.52.0 + '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 @@ -3319,7 +3324,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -3340,7 +3345,7 @@ packages: - supports-color dev: false - /jest-cli@29.7.0(@types/node@20.8.7): + /jest-cli@29.7.0(@types/node@20.8.9): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -3354,10 +3359,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.8.7) + create-jest: 29.7.0(@types/node@20.8.9) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.8.7) + jest-config: 29.7.0(@types/node@20.8.9) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -3368,7 +3373,7 @@ packages: - ts-node dev: false - /jest-config@29.7.0(@types/node@20.8.7): + /jest-config@29.7.0(@types/node@20.8.9): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -3383,7 +3388,7 @@ packages: '@babel/core': 7.23.0 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 babel-jest: 29.7.0(@babel/core@7.23.0) chalk: 4.1.2 ci-info: 3.8.0 @@ -3449,7 +3454,7 @@ packages: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 20.8.7 + '@types/node': 20.8.9 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -3466,7 +3471,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 jest-mock: 29.7.0 jest-util: 29.7.0 dev: false @@ -3482,7 +3487,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.7 - '@types/node': 20.8.7 + '@types/node': 20.8.9 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -3533,7 +3538,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 jest-util: 29.7.0 dev: false @@ -3588,7 +3593,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -3619,7 +3624,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -3671,7 +3676,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -3696,7 +3701,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.7 + '@types/node': 20.8.9 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -3708,13 +3713,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.8.7 + '@types/node': 20.8.9 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: false - /jest@29.7.0(@types/node@20.8.7): + /jest@29.7.0(@types/node@20.8.9): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -3727,7 +3732,7 @@ packages: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.8.7) + jest-cli: 29.7.0(@types/node@20.8.9) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -4048,10 +4053,10 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: false - /next-auth@0.0.0-manual.c885ac1d(next@13.5.6)(react@18.2.0): - resolution: {integrity: sha512-kL5Ead+uIQNjfSWjo/MVxzte+jJSD+N/XIGkYmqyjQmNxE5wDvJ6zuwo+h+QPBnTVf+jmOsOlzr65tPN7OY5fA==} + /next-auth@5.0.0-beta.3(next@14.0.1)(react@18.2.0): + resolution: {integrity: sha512-WOKhATBFGeONV+29HzFmspNmL7NXxrsCWLfaDKmAd/4DD1nqXE0BzNFH8t3SJBx7PUDMnB6F7xB76LM/AaV1MQ==} peerDependencies: - next: ^13.5.3 + next: ^14 nodemailer: ^6.6.5 react: ^18.2.0 peerDependenciesMeta: @@ -4059,25 +4064,25 @@ packages: optional: true dependencies: '@auth/core': 0.0.0-manual.e9863699 - next: 13.5.6(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0) + next: 14.0.1(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false - /next-themes@0.2.1(next@13.5.6)(react-dom@18.2.0)(react@18.2.0): + /next-themes@0.2.1(next@14.0.1)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} peerDependencies: next: '*' react: '*' react-dom: '*' dependencies: - next: 13.5.6(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0) + next: 14.0.1(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /next@13.5.6(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==} - engines: {node: '>=16.14.0'} + /next@14.0.1(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA==} + engines: {node: '>=18.17.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -4090,7 +4095,7 @@ packages: sass: optional: true dependencies: - '@next/env': 13.5.6 + '@next/env': 14.0.1 '@swc/helpers': 0.5.2 busboy: 1.6.0 caniuse-lite: 1.0.30001538 @@ -4100,15 +4105,15 @@ packages: styled-jsx: 5.1.1(@babel/core@7.23.0)(react@18.2.0) watchpack: 2.4.0 optionalDependencies: - '@next/swc-darwin-arm64': 13.5.6 - '@next/swc-darwin-x64': 13.5.6 - '@next/swc-linux-arm64-gnu': 13.5.6 - '@next/swc-linux-arm64-musl': 13.5.6 - '@next/swc-linux-x64-gnu': 13.5.6 - '@next/swc-linux-x64-musl': 13.5.6 - '@next/swc-win32-arm64-msvc': 13.5.6 - '@next/swc-win32-ia32-msvc': 13.5.6 - '@next/swc-win32-x64-msvc': 13.5.6 + '@next/swc-darwin-arm64': 14.0.1 + '@next/swc-darwin-x64': 14.0.1 + '@next/swc-linux-arm64-gnu': 14.0.1 + '@next/swc-linux-arm64-musl': 14.0.1 + '@next/swc-linux-x64-gnu': 14.0.1 + '@next/swc-linux-x64-musl': 14.0.1 + '@next/swc-win32-arm64-msvc': 14.0.1 + '@next/swc-win32-ia32-msvc': 14.0.1 + '@next/swc-win32-x64-msvc': 14.0.1 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5026,8 +5031,8 @@ packages: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: false - /tailwindcss@3.3.3: - resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==} + /tailwindcss@3.3.5: + resolution: {integrity: sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==} engines: {node: '>=14.0.0'} hasBin: true dependencies: @@ -5238,12 +5243,12 @@ packages: which-boxed-primitive: 1.0.2 dev: false - /undici-types@5.25.3: - resolution: {integrity: sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==} + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: false - /undici@5.26.2: - resolution: {integrity: sha512-a4PDLQgLTPHVzOK+x3F79/M4GtyYPl+aX9AAK7aQxpwxDwCqkeZCScy7Gk5kWT3JtdFq1uhO3uZJdLtHI4dK9A==} + /undici@5.26.4: + resolution: {integrity: sha512-OG+QOf0fTLtazL9P9X7yqWxQ+Z0395Wk6DSkyTxtaq3wQEjIroVe7Y4asCX/vcCxYpNGMnwz8F0qbRYUoaQVMw==} engines: {node: '>=14.0'} dependencies: '@fastify/busboy': 2.0.0 diff --git a/src/admin/DeleteButton.tsx b/src/admin/DeleteButton.tsx index 4709a58e..99307aea 100644 --- a/src/admin/DeleteButton.tsx +++ b/src/admin/DeleteButton.tsx @@ -1,9 +1,10 @@ import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; +import { FaTimes } from 'react-icons/fa'; export default function DeleteButton () { return ×} + icon={} > Delete ; diff --git a/src/app/(static)/home-image/route.tsx b/src/app/(static)/home-image/route.tsx index 6d1e6053..28a29351 100644 --- a/src/app/(static)/home-image/route.tsx +++ b/src/app/(static)/home-image/route.tsx @@ -6,7 +6,7 @@ import { } from '@/photo/image-response'; import HomeImageResponse from '@/photo/image-response/HomeImageResponse'; import { getIBMPlexMonoMedium } from '@/site/font'; -import { ImageResponse } from 'next/server'; +import { ImageResponse } from 'next/og'; export const runtime = 'edge'; diff --git a/src/app/(static)/p/[photoId]/image/route.tsx b/src/app/(static)/p/[photoId]/image/route.tsx index eab06594..ae887b7e 100644 --- a/src/app/(static)/p/[photoId]/image/route.tsx +++ b/src/app/(static)/p/[photoId]/image/route.tsx @@ -3,7 +3,7 @@ import { getImageCacheHeadersForAuth, getPhotoCached } from '@/cache'; import { IMAGE_OG_SIZE } from '@/photo/image-response'; import PhotoImageResponse from '@/photo/image-response/PhotoImageResponse'; import { getIBMPlexMonoMedium } from '@/site/font'; -import { ImageResponse } from 'next/server'; +import { ImageResponse } from 'next/og'; export const runtime = 'edge'; diff --git a/src/app/(static)/shot-on/[camera]/image/route.tsx b/src/app/(static)/shot-on/[camera]/image/route.tsx index 88fd7569..a453f2a4 100644 --- a/src/app/(static)/shot-on/[camera]/image/route.tsx +++ b/src/app/(static)/shot-on/[camera]/image/route.tsx @@ -7,7 +7,7 @@ import { } from '@/photo/image-response'; import CameraImageResponse from '@/photo/image-response/CameraImageResponse'; import { getIBMPlexMonoMedium } from '@/site/font'; -import { ImageResponse } from 'next/server'; +import { ImageResponse } from 'next/og'; export const runtime = 'edge'; diff --git a/src/app/(static)/tag/[tag]/image/route.tsx b/src/app/(static)/tag/[tag]/image/route.tsx index 860d258f..1368faa5 100644 --- a/src/app/(static)/tag/[tag]/image/route.tsx +++ b/src/app/(static)/tag/[tag]/image/route.tsx @@ -6,7 +6,7 @@ import { } from '@/photo/image-response'; import TagImageResponse from '@/photo/image-response/TagImageResponse'; import { getIBMPlexMonoMedium } from '@/site/font'; -import { ImageResponse } from 'next/server'; +import { ImageResponse } from 'next/og'; export const runtime = 'edge'; diff --git a/src/app/(static)/template-image-tight/route.tsx b/src/app/(static)/template-image-tight/route.tsx index 3d325b9c..3808d205 100644 --- a/src/app/(static)/template-image-tight/route.tsx +++ b/src/app/(static)/template-image-tight/route.tsx @@ -7,7 +7,7 @@ import { import TemplateImageResponse from '@/photo/image-response/TemplateImageResponse'; import { getIBMPlexMonoMedium } from '@/site/font'; -import { ImageResponse } from 'next/server'; +import { ImageResponse } from 'next/og'; export const runtime = 'edge'; diff --git a/src/app/(static)/template-image/route.tsx b/src/app/(static)/template-image/route.tsx index e670ffde..a852fc7e 100644 --- a/src/app/(static)/template-image/route.tsx +++ b/src/app/(static)/template-image/route.tsx @@ -7,7 +7,7 @@ import { import TemplateImageResponse from '@/photo/image-response/TemplateImageResponse'; import { getIBMPlexMonoMedium } from '@/site/font'; -import { ImageResponse } from 'next/server'; +import { ImageResponse } from 'next/og'; export const runtime = 'edge'; diff --git a/src/app/api/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts similarity index 100% rename from src/app/api/[...nextauth]/route.ts rename to src/app/api/auth/[...nextauth]/route.ts diff --git a/src/auth/SignInForm.tsx b/src/auth/SignInForm.tsx index a8e717bd..c7f840b4 100644 --- a/src/auth/SignInForm.tsx +++ b/src/auth/SignInForm.tsx @@ -3,60 +3,55 @@ import FieldSetWithStatus from '@/components/FieldSetWithStatus'; import InfoBlock from '@/components/InfoBlock'; import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; -import { PATH_ADMIN_PHOTOS } from '@/site/paths'; -import { signIn } from 'next-auth/react'; import { useLayoutEffect, useRef, useState } from 'react'; +import { signInAction } from './action'; +import { useFormState } from 'react-dom'; +import ErrorNote from '@/components/ErrorNote'; +import { CREDENTIALS_SIGN_IN_ERROR } from '.'; export default function SignInForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); - const [isSigningIn, setIsSigningIn] = useState(false); + const [response, action] = useFormState(signInAction, undefined); const emailRef = useRef(null); useLayoutEffect(() => { emailRef.current?.focus(); }, []); + const isFormValid = + email.length > 0 && + password.length > 0; + return ( -
{ - e.preventDefault(); - setIsSigningIn(true); - signIn( - 'credentials', - { - email, - password, - callbackUrl: PATH_ADMIN_PHOTOS, - }, - ) - .catch(() => setIsSigningIn(false)); - }} - > -
- - + +
+ {response === CREDENTIALS_SIGN_IN_ERROR && + + Invalid email/password + } +
+ + +
+ + Sign in +
- - Sign in - ); diff --git a/src/auth/action.ts b/src/auth/action.ts new file mode 100644 index 00000000..734da6e9 --- /dev/null +++ b/src/auth/action.ts @@ -0,0 +1,21 @@ +'use server'; + +import { CREDENTIALS_SIGN_IN_ERROR, signIn, signOut } from '@/auth'; + +export const signInAction = async ( + _prevState: string | undefined, + formData: FormData, +) => { + try { + await signIn('credentials', Object.fromEntries(formData)); + } catch (error) { + if ((error as Error).message.includes(CREDENTIALS_SIGN_IN_ERROR)) { + return CREDENTIALS_SIGN_IN_ERROR; + } + throw error; + } +}; + +export const signOutAction = async () => { + await signOut(); +}; diff --git a/src/auth/index.ts b/src/auth/index.ts index f548eb5c..db3cc98d 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -1,25 +1,17 @@ import { isPathProtected } from '@/site/paths'; -import NextAuth, { User, type DefaultSession } from 'next-auth'; +import NextAuth, { User } from 'next-auth'; import Credentials from 'next-auth/providers/credentials'; -declare module 'next-auth' { - interface Session { - user: { - id: string - } & DefaultSession['user'] - } -} +export const CREDENTIALS_SIGN_IN_ERROR = 'CredentialsSignin'; export const { handlers: { GET, POST }, + signIn, + signOut, auth, } = NextAuth({ providers: [ Credentials({ - credentials: { - email: { label: 'Email', type: 'text' }, - password: { label: 'Password', type: 'password' }, - }, async authorize({ email, password }) { if ( process.env.ADMIN_EMAIL && process.env.ADMIN_EMAIL === email && diff --git a/src/cache/index.ts b/src/cache/index.ts index 282baf77..ccc85309 100644 --- a/src/cache/index.ts +++ b/src/cache/index.ts @@ -15,7 +15,7 @@ import { } from '@/services/postgres'; import { parseCachedPhotosDates, parseCachedPhotoDates } from '@/photo'; import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob'; -import { AuthSession } from 'next-auth'; +import type { Session } from 'next-auth'; import { Camera, createCameraKey } from '@/camera'; import { PATHS_ADMIN, PATHS_TO_CACHE } from '@/site/paths'; @@ -226,7 +226,7 @@ export const getBlobPhotoUrlsCached: typeof getBlobPhotoUrls = (...args) => } )(); -export const getImageCacheHeadersForAuth = (session: AuthSession | null) => { +export const getImageCacheHeadersForAuth = (session: Session | null) => { return { 'Cache-Control': !session?.user ? 's-maxage=3600, stale-while-revalidate=59' diff --git a/src/components/ErrorNote.tsx b/src/components/ErrorNote.tsx new file mode 100644 index 00000000..aaca7190 --- /dev/null +++ b/src/components/ErrorNote.tsx @@ -0,0 +1,25 @@ +import { cc } from '@/utility/css'; +import { BiErrorAlt } from 'react-icons/bi'; + +export default function ErrorNote({ + children, +}: { + children: React.ReactNode +}) { + return ( +
+ + {children} +
+ ); +} diff --git a/src/components/FieldSetWithStatus.tsx b/src/components/FieldSetWithStatus.tsx index c518e37d..bdc62717 100644 --- a/src/components/FieldSetWithStatus.tsx +++ b/src/components/FieldSetWithStatus.tsx @@ -1,7 +1,8 @@ 'use client'; import { LegacyRef } from 'react'; -import { experimental_useFormStatus as useFormStatus } from 'react-dom'; +// @ts-ignore +import { useFormStatus } from 'react-dom'; import Spinner from './Spinner'; import { cc } from '@/utility/css'; diff --git a/src/components/ImageInput.tsx b/src/components/ImageInput.tsx index 3c9d8ca9..3241786b 100644 --- a/src/components/ImageInput.tsx +++ b/src/components/ImageInput.tsx @@ -4,9 +4,9 @@ import { blobToImage } from '@/utility/blob'; import { useRef, useState } from 'react'; import { CopyExif } from '@/lib/CopyExif'; import { cc } from '@/utility/css'; -import { AiOutlineCloudUpload } from 'react-icons/ai'; import Spinner from './Spinner'; import { ACCEPTED_PHOTO_FILE_TYPES } from '@/photo'; +import { FiUploadCloud } from 'react-icons/fi'; const INPUT_ID = 'file'; @@ -49,10 +49,10 @@ export default function ImageInput({ > {loading - ? - : + : } Upload Photo diff --git a/src/components/SubmitButtonWithStatus.tsx b/src/components/SubmitButtonWithStatus.tsx index e14c2aca..bb9d661e 100644 --- a/src/components/SubmitButtonWithStatus.tsx +++ b/src/components/SubmitButtonWithStatus.tsx @@ -1,17 +1,20 @@ 'use client'; import { HTMLProps } from 'react'; -import { experimental_useFormStatus as useFormStatus } from 'react-dom'; +// @ts-ignore +import { useFormStatus } from 'react-dom'; import Spinner from './Spinner'; import { cc } from '@/utility/css'; interface Props extends HTMLProps { icon?: JSX.Element + styleAsLink?: boolean } export default function SubmitButtonWithStatus(props: Props) { const { icon, + styleAsLink, children, disabled, className, @@ -28,14 +31,17 @@ export default function SubmitButtonWithStatus(props: Props) { className={cc( className, 'inline-flex items-center gap-2', + styleAsLink && 'link', )} {...buttonProps} > {(icon || pending) && {pending ? diff --git a/src/site/FooterAuth.tsx b/src/site/FooterAuth.tsx index cab90f4e..5a6fc589 100644 --- a/src/site/FooterAuth.tsx +++ b/src/site/FooterAuth.tsx @@ -2,22 +2,23 @@ import { cc } from '@/utility/css'; import Link from 'next/link'; -import { useSession, signOut } from 'next-auth/react'; +import { useSession } from 'next-auth/react'; import ThemeSwitcher from '@/site/ThemeSwitcher'; import SiteGrid from '../components/SiteGrid'; import { usePathname } from 'next/navigation'; import { isPathSignIn } from '@/site/paths'; +import { signOutAction } from '@/auth/action'; +import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; const LINK_STYLE = cc( 'cursor-pointer', - 'hover:text-gray-600', + 'hover:text-gray-300', + 'hover:dark:text-gray-600', ); export default function FooterAuth() { const { data: session, status } = useSession(); - const hasState = status !== 'loading'; - const path = usePathname(); return ( @@ -27,27 +28,30 @@ export default function FooterAuth() { 'my-8', 'text-dim', )}> -
- {hasState - ? <> - {session?.user === undefined && - <>Loading ...} - {session?.user.email && <> -
{session.user.email}
-
signOut()} +
+ {status === 'loading' + ? <>Loading ... + : <> + {session?.user?.email &&
+ {session.user.email} +
} + {status === 'authenticated' && +
+ + Sign Out + +
} + {status === 'unauthenticated' && + - Sign Out -
- } - - : - Sign In - } + Sign In + } + }
{!isPathSignIn(path) && }
} diff --git a/src/site/globals.css b/src/site/globals.css index 242dca91..7a080dc2 100644 --- a/src/site/globals.css +++ b/src/site/globals.css @@ -72,10 +72,11 @@ px-4 text-base shadow-sm - disabled:bg-gray-100 dark:disabled:bg-gray-900 disabled:cursor-not-allowed active:bg-gray-100 dark:active:bg-gray-900 hover:border-gray-300 dark:hover:border-gray-600 - hover:disabled:border-gray-200 + disabled:cursor-not-allowed + disabled:bg-gray-100 dark:disabled:bg-gray-900 + disabled:border-gray-200 disabled:dark:border-gray-700 } button.subtle, .button.subtle { @apply @@ -97,6 +98,11 @@ @apply text-medium } + button.link { + @apply + p-0 min-h-0 + border-none active:bg-transparent shadow-none + } /* Toasts */ .toaster [data-sonner-toast] { @apply