diff --git a/.idea/GitLink.xml b/.idea/GitLink.xml new file mode 100644 index 00000000..009597cc --- /dev/null +++ b/.idea/GitLink.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/codestream.xml b/.idea/codestream.xml new file mode 100644 index 00000000..6b92fb41 --- /dev/null +++ b/.idea/codestream.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 6b3b5df2..9f111639 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "next build", "dev": "npm-run-all --parallel next:dev convex:dev ", "convex:dev": "convex dev --tail-logs", - "next:dev": "next dev --turbo", + "next:dev": "next dev --turbo --experimental-https", "format": "prettier --check . --ignore-path .gitignore --ignore-path .prettierignore", "lint": "next lint", "start": "next start", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e3bf037..bea98094 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@clerk/nextjs': specifier: ^6.5.1 - version: 6.9.6(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 6.9.5(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@emoji-mart/data': specifier: ^1.2.1 version: 1.2.1 @@ -64,10 +64,10 @@ importers: version: 6.0.1(react@19.0.0) '@sentry/nextjs': specifier: ^8 - version: 8.47.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(webpack@5.96.1) + version: 8.47.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(webpack@5.96.1) '@serwist/next': specifier: 9.0.11 - version: 9.0.11(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.2)(webpack@5.96.1) + version: 9.0.11(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.2)(webpack@5.96.1) '@t3-oss/env-nextjs': specifier: ^0.11.1 version: 0.11.1(typescript@5.7.2)(zod@3.24.1) @@ -103,7 +103,7 @@ importers: version: 12.0.0-alpha.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) geist: specifier: ^1.3.1 - version: 1.3.1(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) + version: 1.3.1(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) jiti: specifier: ^2.4.1 version: 2.4.2 @@ -112,10 +112,10 @@ importers: version: 0.469.0(react@19.0.0) next: specifier: ^15.0.3 - version: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next-axiom: specifier: ^1.7.0 - version: 1.9.1(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + version: 1.9.1(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) next-themes: specifier: ^0.4.4 version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -145,7 +145,7 @@ importers: version: 10.0.0(react@19.0.0) react-scan: specifier: ^0.0.54 - version: 0.0.54(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@3.29.5) + version: 0.0.54(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@3.29.5) sonner: specifier: ^1.7.0 version: 1.7.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -334,8 +334,8 @@ packages: react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 - '@clerk/nextjs@6.9.6': - resolution: {integrity: sha512-wmbQd2UYOnvGtidgEAqD6f2JZjvKMlmZqnT2HbR3GKwiGme3c1wLrkPye5tknaFLJHsA+Zfp7MJtL7mu07yCzw==} + '@clerk/nextjs@6.9.5': + resolution: {integrity: sha512-0d4pdjCGU6TyrLA5eGtlcFt9vVbwtRuXq3tWpYgvii3kwG8ulUsCLl52c48nmnHPl23O+/rqCiufzRuWzBTxwQ==} engines: {node: '>=18.17.0'} peerDependencies: next: ^13.5.4 || ^14.0.3 || ^15.0.0 @@ -1045,56 +1045,56 @@ packages: '@microsoft/fetch-event-source@2.0.1': resolution: {integrity: sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==} - '@next/env@15.1.3': - resolution: {integrity: sha512-Q1tXwQCGWyA3ehMph3VO+E6xFPHDKdHFYosadt0F78EObYxPio0S09H9UGYznDe6Wc8eLKLG89GqcFJJDiK5xw==} + '@next/env@15.1.1': + resolution: {integrity: sha512-ldU8IpUqxa87LsWyMh8eIqAzejt8+ZuEsdtCV+fpDog++cBO5b/PWaI7wQQwun8LKJeFFpnY4kv/6r+/dCON6A==} '@next/eslint-plugin-next@15.1.3': resolution: {integrity: sha512-oeP1vnc5Cq9UoOb8SYHAEPbCXMzOgG70l+Zfd+Ie00R25FOm+CCVNrcIubJvB1tvBgakXE37MmqSycksXVPRqg==} - '@next/swc-darwin-arm64@15.1.3': - resolution: {integrity: sha512-aZtmIh8jU89DZahXQt1La0f2EMPt/i7W+rG1sLtYJERsP7GRnNFghsciFpQcKHcGh4dUiyTB5C1X3Dde/Gw8gg==} + '@next/swc-darwin-arm64@15.1.1': + resolution: {integrity: sha512-pq7Hzu0KaaH6UYcCQ22mOuj2mWCD6iqGvYprp/Ep1EcCxbdNOSS+8EJADFbPHsaXLkaonIJ8lTKBGWXaFxkeNQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.1.3': - resolution: {integrity: sha512-aw8901rjkVBK5mbq5oV32IqkJg+CQa6aULNlN8zyCWSsePzEG3kpDkAFkkTOh3eJ0p95KbkLyWBzslQKamXsLA==} + '@next/swc-darwin-x64@15.1.1': + resolution: {integrity: sha512-h567/b/AHAnMpaJ1D3l3jKLrzNOgN9bmDSRd+Gb0hXTkLZh8mE0Kd9MbIw39QeTZQJ3192uFRFWlDjWiifwVhQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.1.3': - resolution: {integrity: sha512-YbdaYjyHa4fPK4GR4k2XgXV0p8vbU1SZh7vv6El4bl9N+ZSiMfbmqCuCuNU1Z4ebJMumafaz6UCC2zaJCsdzjw==} + '@next/swc-linux-arm64-gnu@15.1.1': + resolution: {integrity: sha512-I5Q6M3T9jzTUM2JlwTBy/VBSX+YCDvPLnSaJX5wE5GEPeaJkipMkvTA9+IiFK5PG5ljXTqVFVUj5BSHiYLCpoQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.1.3': - resolution: {integrity: sha512-qgH/aRj2xcr4BouwKG3XdqNu33SDadqbkqB6KaZZkozar857upxKakbRllpqZgWl/NDeSCBYPmUAZPBHZpbA0w==} + '@next/swc-linux-arm64-musl@15.1.1': + resolution: {integrity: sha512-4cPMSYmyXlOAk8U04ouEACEGnOwYM9uJOXZnm9GBXIKRbNEvBOH9OePhHiDWqOws6iaHvGayaKr+76LmM41yJA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.1.3': - resolution: {integrity: sha512-uzafnTFwZCPN499fNVnS2xFME8WLC9y7PLRs/yqz5lz1X/ySoxfaK2Hbz74zYUdEg+iDZPd8KlsWaw9HKkLEVw==} + '@next/swc-linux-x64-gnu@15.1.1': + resolution: {integrity: sha512-KgIiKDdV35KwL9TrTxPFGsPb3J5RuDpw828z3MwMQbWaOmpp/T4MeWQCwo+J2aOxsyAcfsNE334kaWXCb6YTTA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.1.3': - resolution: {integrity: sha512-el6GUFi4SiDYnMTTlJJFMU+GHvw0UIFnffP1qhurrN1qJV3BqaSRUjkDUgVV44T6zpw1Lc6u+yn0puDKHs+Sbw==} + '@next/swc-linux-x64-musl@15.1.1': + resolution: {integrity: sha512-aHP/29x8loFhB3WuW2YaWaYFJN389t6/SBsug19aNwH+PRLzDEQfCvtuP6NxRCido9OAoExd+ZuYJKF9my1Kpg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.1.3': - resolution: {integrity: sha512-6RxKjvnvVMM89giYGI1qye9ODsBQpHSHVo8vqA8xGhmRPZHDQUE4jcDbhBwK0GnFMqBnu+XMg3nYukNkmLOLWw==} + '@next/swc-win32-arm64-msvc@15.1.1': + resolution: {integrity: sha512-klbzXYwqHMwiucNFF0tWiWJyPb45MBX1q/ATmxrMjEYgA+V/0OXc9KmNVRIn6G/ab0ASUk4uWqxik5m6wvm1sg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.1.3': - resolution: {integrity: sha512-VId/f5blObG7IodwC5Grf+aYP0O8Saz1/aeU3YcWqNdIUAmFQY3VEPKPaIzfv32F/clvanOb2K2BR5DtDs6XyQ==} + '@next/swc-win32-x64-msvc@15.1.1': + resolution: {integrity: sha512-V5fm4aULqHSlMQt3U1rWAWuwJTFsb6Yh4P8p1kQFoayAF9jAQtjBvHku4zCdrtQuw9u9crPC0FNML00kN4WGhA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3297,8 +3297,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@15.1.3: - resolution: {integrity: sha512-5igmb8N8AEhWDYzogcJvtcRDU6n4cMGtBklxKD4biYv4LXN8+awc/bbQ2IM2NQHdVPgJ6XumYXfo3hBtErg1DA==} + next@15.1.1: + resolution: {integrity: sha512-SBZlcvdIxajw8//H3uOR1G3iu3jxsra/77m2ulRIxi3m89p+s3ACsoOXR49JEAbaun/DVoRJ9cPKq8eF/oNB5g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -3539,9 +3539,6 @@ packages: posthog-js@1.203.3: resolution: {integrity: sha512-DTK6LfL87xC7PPleKDParEIfkXl7hXtuDeSOPfhcyCXLuVspq0z7YyRB5dQE9Pbalf3yoGqUKvomYFp/BGVfQg==} - preact@10.25.3: - resolution: {integrity: sha512-dzQmIFtM970z+fP9ziQ3yG4e3ULIbwZzJ734vaMVUTaKQ2+Ru1Ou/gjshOYVHCcd1rpAelC6ngjvjDXph98unQ==} - preact@10.25.4: resolution: {integrity: sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==} @@ -4354,7 +4351,7 @@ snapshots: '@babel/generator@7.26.2': dependencies: '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 + '@babel/types': 7.26.3 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.0.2 @@ -4404,7 +4401,7 @@ snapshots: '@babel/parser@7.26.2': dependencies: - '@babel/types': 7.26.0 + '@babel/types': 7.26.3 '@babel/parser@7.26.3': dependencies: @@ -4426,7 +4423,7 @@ snapshots: '@babel/generator': 7.26.2 '@babel/parser': 7.26.2 '@babel/template': 7.25.9 - '@babel/types': 7.26.0 + '@babel/types': 7.26.3 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: @@ -4484,14 +4481,14 @@ snapshots: react-dom: 19.0.0(react@19.0.0) tslib: 2.4.1 - '@clerk/nextjs@6.9.6(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@clerk/nextjs@6.9.5(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@clerk/backend': 1.21.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@clerk/clerk-react': 5.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@clerk/shared': 2.20.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@clerk/types': 4.40.0 crypto-js: 4.2.0 - next: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) server-only: 0.0.1 @@ -4961,34 +4958,34 @@ snapshots: '@microsoft/fetch-event-source@2.0.1': {} - '@next/env@15.1.3': {} + '@next/env@15.1.1': {} '@next/eslint-plugin-next@15.1.3': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.1.3': + '@next/swc-darwin-arm64@15.1.1': optional: true - '@next/swc-darwin-x64@15.1.3': + '@next/swc-darwin-x64@15.1.1': optional: true - '@next/swc-linux-arm64-gnu@15.1.3': + '@next/swc-linux-arm64-gnu@15.1.1': optional: true - '@next/swc-linux-arm64-musl@15.1.3': + '@next/swc-linux-arm64-musl@15.1.1': optional: true - '@next/swc-linux-x64-gnu@15.1.3': + '@next/swc-linux-x64-gnu@15.1.1': optional: true - '@next/swc-linux-x64-musl@15.1.3': + '@next/swc-linux-x64-musl@15.1.1': optional: true - '@next/swc-win32-arm64-msvc@15.1.3': + '@next/swc-win32-arm64-msvc@15.1.1': optional: true - '@next/swc-win32-x64-msvc@15.1.3': + '@next/swc-win32-x64-msvc@15.1.1': optional: true '@nodelib/fs.scandir@2.1.5': @@ -5290,10 +5287,10 @@ snapshots: '@preact/signals-core@1.8.0': {} - '@preact/signals@1.3.1(preact@10.25.3)': + '@preact/signals@1.3.1(preact@10.25.4)': dependencies: '@preact/signals-core': 1.8.0 - preact: 10.25.3 + preact: 10.25.4 '@prisma/instrumentation@5.22.0': dependencies: @@ -5741,7 +5738,7 @@ snapshots: '@sentry/core@8.47.0': {} - '@sentry/nextjs@8.47.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(webpack@5.96.1)': + '@sentry/nextjs@8.47.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(webpack@5.96.1)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.28.0 @@ -5754,7 +5751,7 @@ snapshots: '@sentry/vercel-edge': 8.47.0 '@sentry/webpack-plugin': 2.22.7(webpack@5.96.1) chalk: 3.0.0 - next: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -5848,14 +5845,14 @@ snapshots: optionalDependencies: typescript: 5.7.2 - '@serwist/next@9.0.11(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.2)(webpack@5.96.1)': + '@serwist/next@9.0.11(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(typescript@5.7.2)(webpack@5.96.1)': dependencies: '@serwist/build': 9.0.11(typescript@5.7.2) '@serwist/webpack-plugin': 9.0.11(typescript@5.7.2)(webpack@5.96.1) '@serwist/window': 9.0.11(typescript@5.7.2) chalk: 5.3.0 glob: 10.4.5 - next: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) serwist: 9.0.11(typescript@5.7.2) zod: 3.23.8 optionalDependencies: @@ -7053,9 +7050,9 @@ snapshots: functions-have-names@1.2.3: {} - geist@1.3.1(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)): + geist@1.3.1(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)): dependencies: - next: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) gensync@1.0.0-beta.2: {} @@ -7493,9 +7490,9 @@ snapshots: neo-async@2.6.2: {} - next-axiom@1.9.1(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0): + next-axiom@1.9.1(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0): dependencies: - next: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 use-deep-compare: 1.3.0(react@19.0.0) whatwg-fetch: 3.6.20 @@ -7505,9 +7502,9 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@next/env': 15.1.3 + '@next/env': 15.1.1 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 @@ -7517,14 +7514,14 @@ snapshots: react-dom: 19.0.0(react@19.0.0) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@19.0.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.1.3 - '@next/swc-darwin-x64': 15.1.3 - '@next/swc-linux-arm64-gnu': 15.1.3 - '@next/swc-linux-arm64-musl': 15.1.3 - '@next/swc-linux-x64-gnu': 15.1.3 - '@next/swc-linux-x64-musl': 15.1.3 - '@next/swc-win32-arm64-msvc': 15.1.3 - '@next/swc-win32-x64-msvc': 15.1.3 + '@next/swc-darwin-arm64': 15.1.1 + '@next/swc-darwin-x64': 15.1.1 + '@next/swc-linux-arm64-gnu': 15.1.1 + '@next/swc-linux-arm64-musl': 15.1.1 + '@next/swc-linux-x64-gnu': 15.1.1 + '@next/swc-linux-x64-musl': 15.1.1 + '@next/swc-win32-arm64-msvc': 15.1.1 + '@next/swc-win32-x64-msvc': 15.1.1 '@opentelemetry/api': 1.9.0 babel-plugin-react-compiler: 19.0.0-beta-b2e8e9c-20241220 sharp: 0.33.5 @@ -7735,8 +7732,6 @@ snapshots: preact: 10.25.4 web-vitals: 4.2.4 - preact@10.25.3: {} - preact@10.25.4: {} prelude-ls@1.2.1: {} @@ -7828,14 +7823,14 @@ snapshots: react: 19.0.0 shallow-equal: 3.1.0 - react-scan@0.0.54(next@15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@3.29.5): + react-scan@0.0.54(next@15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@3.29.5): dependencies: '@babel/core': 7.26.0 '@babel/generator': 7.26.3 '@babel/types': 7.26.3 '@clack/core': 0.3.5 '@clack/prompts': 0.8.2 - '@preact/signals': 1.3.1(preact@10.25.3) + '@preact/signals': 1.3.1(preact@10.25.4) '@rollup/pluginutils': 5.1.4(rollup@3.29.5) '@types/node': 20.17.11 bippy: 0.0.25 @@ -7844,12 +7839,12 @@ snapshots: kleur: 4.1.5 mri: 1.2.0 playwright: 1.49.1 - preact: 10.25.3 + preact: 10.25.4 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) tsx: 4.19.2 optionalDependencies: - next: 15.1.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next: 15.1.1(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) unplugin: 2.1.0 transitivePeerDependencies: - rollup diff --git a/src/components/message.tsx b/src/components/message.tsx index 3ab24a0b..f528863c 100644 --- a/src/components/message.tsx +++ b/src/components/message.tsx @@ -2,11 +2,6 @@ import { useUser } from "@clerk/nextjs"; import { useFloating, type ReferenceType } from "@floating-ui/react"; import { useLongPress } from "@reactuses/core"; import { useQueryWithStatus } from "~/app/convex-client-provider"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "~/components/ui/popover"; import { cn } from "~/lib/utils"; import { useMutation } from "convex/react"; import { type FunctionReturnType } from "convex/server"; @@ -25,12 +20,13 @@ import { Reply, Trash2, } from "lucide-react"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect } from "react"; import { createPortal } from "react-dom"; import { useInView } from "react-intersection-observer"; import { toast } from "sonner"; import { api } from "../../convex/_generated/api"; -import type { Doc, Id } from "../../convex/_generated/dataModel"; +import type { Id } from "../../convex/_generated/dataModel"; +import { ReactionHandler } from "./reactions"; dayjs.extend(relativeTime); @@ -38,6 +34,16 @@ export type Message = NonNullable< FunctionReturnType >[number]; +export type UserInfos = [ + FunctionReturnType | undefined, + ( + | undefined + | NonNullable< + FunctionReturnType + >["otherUser"] + ), +]; + const EditedLabel = ({ message }: { message: Message }) => (
{message.type === "message" && message.modified && "Edited"} @@ -63,136 +69,6 @@ const ReplyToMessage = ({ message }: { message: Message }) => { } }; -const ReactionQuickView = ({ - reactions, -}: { - reactions: Doc<"reactions">[]; -}) => { - const [animatingEmojis, setAnimatingEmojis] = useState>( - new Set(), - ); - const previousReactions = useRef([]); - const isFirstRender = useRef(true); - - useEffect(() => { - if (isFirstRender.current) { - isFirstRender.current = false; - previousReactions.current = reactions.map((r) => r.emoji); - return; // Skip animation logic on first render - } - - const currentReactions = reactions.map((r) => r.emoji); - const newReactions = currentReactions.filter( - (emoji) => !previousReactions.current.includes(emoji), - ); - - if (newReactions.length > 0) { - setAnimatingEmojis(new Set(newReactions)); - const timeoutId = setTimeout(() => { - setAnimatingEmojis(new Set()); - }, 500); // Match this with your animation duration - // The setTimeout should be cleaned up when the component unmounts or when new reactions are added before the animation completes. - return () => clearTimeout(timeoutId); - } - - previousReactions.current = currentReactions; - }, [reactions]); - - return ( - reactions - // Reduce the reactions array to count occurrences of each emoji - // acc: accumulator array of {emoji, count} objects - // reaction: current reaction being processed - // Returns: array of unique emojis with their counts - .reduce( - (acc, reaction) => { - const existingReaction = acc.find((r) => r.emoji === reaction.emoji); - if (existingReaction) { - existingReaction.count++; - } else { - acc.push({ - emoji: reaction.emoji, - count: 1, - }); - } - return acc; - }, - [] as { emoji: string; count: number }[], - ) - .map((reaction, index) => ( -
- - {reaction.emoji} - - {reaction.count > 1 && ( - - {reaction.count} - - )} -
- )) - ); -}; - -const ReactionDetails = ({ - reactions, - userInfos, -}: { - reactions: Doc<"reactions">[]; - userInfos: [ - FunctionReturnType | undefined, - ( - | undefined - | NonNullable< - FunctionReturnType - >["otherUser"] - ), - ]; -}) => { - // Group reactions by emoji - const reactionsByEmoji = reactions.reduce( - (acc, reaction) => { - (acc[reaction.emoji] = acc[reaction.emoji] ?? []).push(reaction); - return acc; - }, - {} as Record, - ); - - return ( -
- {Object.entries(reactionsByEmoji).map(([emoji, reactions]) => ( -
-
- {emoji} -
- {reactions - .map((reaction) => { - const user = - userInfos[0]?._id === reaction.userId - ? userInfos[0] - : Array.isArray(userInfos[1]) - ? userInfos[1].find((u) => u._id === reaction.userId) - : userInfos[1]; - return user?.username; - }) - .join(", ")} -
-
-
- ))} -
- ); -}; - export const Message = ({ message, selectedMessageId, @@ -217,15 +93,7 @@ export const Message = ({ setReplyToMessageId: React.Dispatch< React.SetStateAction | undefined> >; - userInfos: [ - FunctionReturnType | undefined, - ( - | undefined - | NonNullable< - FunctionReturnType - >["otherUser"] - ), - ]; + userInfos: UserInfos; setShowFullEmojiPicker: React.Dispatch>; isInBottomHalf: boolean | null; refsFullEmojiPicker: { @@ -643,26 +511,12 @@ export const Message = ({ )}
- {message.type === "message" && - message.reactions && - message.reactions.length > 0 && ( - - - - - - - - - )} +
{message.type == "message" && !message.deleted @@ -853,26 +707,12 @@ export const Message = ({ )}
- {message.type === "message" && - message.reactions && - message.reactions.length > 0 && ( - - - - - - - - - )} + {chatContainerElement && message._id == selectedMessageId && diff --git a/src/components/reactions.tsx b/src/components/reactions.tsx new file mode 100644 index 00000000..abb32584 --- /dev/null +++ b/src/components/reactions.tsx @@ -0,0 +1,165 @@ +import { usePrevious } from "~/lib/hooks"; +import { cn } from "~/lib/utils"; +import type { api } from "convex/_generated/api"; +import type { Doc, Id } from "convex/_generated/dataModel"; +import type { FunctionReturnType } from "convex/server"; +import { motion } from "framer-motion"; +import { useEffect, useState } from "react"; +import type { Message, UserInfos } from "./message"; +import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; + +export const ReactionHandler = (props: { + message: Message; + selectedMessageId: Id<"messages"> | null; + userInfos: UserInfos; + side: "left" | "right"; +}) => { + const message = props.message; + const selectedMessageId = props.selectedMessageId; + const userInfos = props.userInfos; + + // Can't be a ref because it needs to be passed to a child component as a prop + const [isFirstMount, setIsFirstMount] = useState(true); + + // Set isFirstMount to false AFTER the first render + useEffect(() => { + setIsFirstMount(false); + }, []); + + return ( + message.type === "message" && + message.reactions && + message.reactions.length > 0 && ( + + + + + + + + + ) + ); +}; + +// Component that shows a compact view of message reactions, displaying emojis and their counts +const ReactionQuickView = ({ + reactions, + isFirstMount, +}: { + reactions: Doc<"reactions">[]; // Array of reaction documents from the database + isFirstMount: boolean; // Boolean that is true on first render, false on subsequent renders +}) => { + // Hook that stores previous reactions to compare for animations + // Maps reactions to just emoji strings for comparison + const prevReactions = usePrevious(reactions.map((r) => r.emoji)); + + // Count how many times each emoji appears in reactions + // Creates an object like: { "👍": 2, "❤️": 1 } + const currentReactionCounts = reactions.reduce( + (acc, reaction) => { + acc[reaction.emoji] = (acc[reaction.emoji] ?? 0) + 1; + return acc; + }, + {} as Record, + ); + + // Render each emoji and its count with animations + return Object.entries(currentReactionCounts).map(([emoji, count]) => { + // Determine if this emoji reaction is new (wasn't in previous reactions) + const isNew = !prevReactions?.includes(emoji); + + return ( + // motion.div enables animations from framer-motion library + + + {emoji} + + {/* Show count if more than one reaction */} + {count > 1 && ( + + {count} + + )} + + ); + }); +}; + +// Component that shows detailed view of reactions, including who reacted with what +const ReactionDetails = ({ + reactions, + userInfos, // Tuple containing current user data and other chat participants' data +}: { + reactions: Doc<"reactions">[]; + userInfos: [ + FunctionReturnType | undefined, + ( + | undefined + | NonNullable< + FunctionReturnType + >["otherUser"] + ), + ]; +}) => { + // Group reactions by emoji + // Creates object like: { "👍": [reaction1, reaction2], "❤️": [reaction3] } + const reactionsByEmoji = reactions.reduce( + (acc, reaction) => { + const emojiArray = acc[reaction.emoji] ?? []; + emojiArray.push(reaction); + acc[reaction.emoji] = emojiArray; + return acc; + }, + {} as Record, + ); + + return ( +
+ {Object.entries(reactionsByEmoji).map(([emoji, reactions]) => ( +
+
+ {emoji} +
+ {/* Create comma-separated list of usernames who used this emoji */} + {reactions + .map((reaction) => { + // Find user info either from current user or other chat participants + const user = + userInfos[0]?._id === reaction.userId + ? userInfos[0] + : Array.isArray(userInfos[1]) + ? userInfos[1].find((u) => u._id === reaction.userId) + : userInfos[1]; + return user?.username; + }) + .join(", ")} +
+
+
+ ))} +
+ ); +}; diff --git a/tailwind.config.ts b/tailwind.config.ts index 25678adb..f61a8e0e 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -83,16 +83,11 @@ const config = { backgroundPosition: "350% 50%, 350% 50%", }, }, - jump: { - "0%, 100%": { transform: "translateY(0) scale(1)" }, - "50%": { transform: "translateY(-8px) scale(1.2)" }, - }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", aurora: "aurora 60s linear infinite", - jump: "jump ease-in-out", }, }, },