diff --git a/package.json b/package.json index 4cecf15..4eee4cf 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@supabase/ssr": "^0.6.1", - "@supabase/supabase-js": "^2.49.9", + "@supabase/supabase-js": "^2.49.10", "@t3-oss/env-nextjs": "^0.12.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -35,14 +35,16 @@ "react-dom": "^19.1.0", "react-hook-form": "^7.57.0", "sonner": "^2.0.5", - "zod": "^3.25.49" + "zod": "^3.25.51" }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", "@tailwindcss/postcss": "^4.1.8", + "@types/cors": "^2.8.18", + "@types/express": "^5.0.2", "@types/node": "^20.17.57", "@types/react": "^19.1.6", - "@types/react-dom": "^19.1.5", + "@types/react-dom": "^19.1.6", "eslint": "^9.28.0", "eslint-config-next": "^15.3.3", "postcss": "^8.5.4", @@ -51,7 +53,7 @@ "tailwind-merge": "^3.3.0", "tailwindcss": "^4.1.8", "tailwindcss-animate": "^1.0.7", - "tw-animate-css": "^1.3.3", + "tw-animate-css": "^1.3.4", "typescript": "^5.8.3", "typescript-eslint": "^8.33.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3a2aed..a680456 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,31 +13,31 @@ importers: version: 5.0.1(react-hook-form@7.57.0(react@19.1.0)) '@radix-ui/react-avatar': specifier: ^1.1.10 - version: 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-checkbox': specifier: ^1.3.2 - version: 1.3.2(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 1.3.2(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-dropdown-menu': specifier: ^2.1.15 - version: 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-label': specifier: ^2.1.7 - version: 2.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 2.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-separator': specifier: ^1.1.7 - version: 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.3(@types/react@19.1.6)(react@19.1.0) '@supabase/ssr': specifier: ^0.6.1 - version: 0.6.1(@supabase/supabase-js@2.49.9) + version: 0.6.1(@supabase/supabase-js@2.49.10) '@supabase/supabase-js': - specifier: ^2.49.9 - version: 2.49.9 + specifier: ^2.49.10 + version: 2.49.10 '@t3-oss/env-nextjs': specifier: ^0.12.0 - version: 0.12.0(typescript@5.8.3)(zod@3.25.49) + version: 0.12.0(typescript@5.8.3)(zod@3.25.51) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -66,8 +66,8 @@ importers: specifier: ^2.0.5 version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) zod: - specifier: ^3.25.49 - version: 3.25.49 + specifier: ^3.25.51 + version: 3.25.51 devDependencies: '@eslint/eslintrc': specifier: ^3.3.1 @@ -75,6 +75,12 @@ importers: '@tailwindcss/postcss': specifier: ^4.1.8 version: 4.1.8 + '@types/cors': + specifier: ^2.8.18 + version: 2.8.18 + '@types/express': + specifier: ^5.0.2 + version: 5.0.2 '@types/node': specifier: ^20.17.57 version: 20.17.57 @@ -82,8 +88,8 @@ importers: specifier: ^19.1.6 version: 19.1.6 '@types/react-dom': - specifier: ^19.1.5 - version: 19.1.5(@types/react@19.1.6) + specifier: ^19.1.6 + version: 19.1.6(@types/react@19.1.6) eslint: specifier: ^9.28.0 version: 9.28.0(jiti@2.4.2) @@ -109,8 +115,8 @@ importers: specifier: ^1.0.7 version: 1.0.7(tailwindcss@4.1.8) tw-animate-css: - specifier: ^1.3.3 - version: 1.3.3 + specifier: ^1.3.4 + version: 1.3.4 typescript: specifier: ^5.8.3 version: 5.8.3 @@ -784,8 +790,8 @@ packages: '@supabase/postgrest-js@1.19.4': resolution: {integrity: sha512-O4soKqKtZIW3olqmbXXbKugUtByD2jPa8kL2m2c1oozAO11uCcGrRhkZL0kVxjBLrXHE0mdSkFsMj7jDSfyNpw==} - '@supabase/realtime-js@2.11.9': - resolution: {integrity: sha512-fLseWq8tEPCO85x3TrV9Hqvk7H4SGOqnFQ223NPJSsxjSYn0EmzU1lvYO6wbA0fc8DE94beCAiiWvGvo4g33lQ==} + '@supabase/realtime-js@2.11.10': + resolution: {integrity: sha512-SJKVa7EejnuyfImrbzx+HaD9i6T784khuw1zP+MBD7BmJYChegGxYigPzkKX8CK8nGuDntmeSD3fvriaH0EGZA==} '@supabase/ssr@0.6.1': resolution: {integrity: sha512-QtQgEMvaDzr77Mk3vZ3jWg2/y+D8tExYF7vcJT+wQ8ysuvOeGGjYbZlvj5bHYsj/SpC0bihcisnwPrM4Gp5G4g==} @@ -795,8 +801,8 @@ packages: '@supabase/storage-js@2.7.1': resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==} - '@supabase/supabase-js@2.49.9': - resolution: {integrity: sha512-lB2A2X8k1aWAqvlpO4uZOdfvSuZ2s0fCMwJ1Vq6tjWsi3F+au5lMbVVn92G0pG8gfmis33d64Plkm6eSDs6jRA==} + '@supabase/supabase-js@2.49.10': + resolution: {integrity: sha512-IRPcIdncuhD2m1eZ2Fkg0S1fq9SXlHfmAetBxPN66kVFtTucR8b01xKuVmKqcIJokB17umMf1bmqyS8yboXGsw==} '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -923,29 +929,62 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/body-parser@1.19.5': + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/cors@2.8.18': + resolution: {integrity: sha512-nX3d0sxJW41CqQvfOzVG1NCTXfFDrDWIghCZncpHeWlVFd81zxB/DLhg7avFg6eHLCRX7ckBmoIIcqa++upvJA==} + '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/express-serve-static-core@5.0.6': + resolution: {integrity: sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==} + + '@types/express@5.0.2': + resolution: {integrity: sha512-BtjL3ZwbCQriyb0DGw+Rt12qAXPiBTPs815lsUvtt1Grk0vLRMZNMUZ741d5rjk+UQOxfDiBZ3dxpX00vSkK3g==} + + '@types/http-errors@2.0.4': + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/node@20.17.57': resolution: {integrity: sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==} '@types/phoenix@1.6.6': resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} - '@types/react-dom@19.1.5': - resolution: {integrity: sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg==} + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/react-dom@19.1.6': + resolution: {integrity: sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==} peerDependencies: '@types/react': ^19.0.0 '@types/react@19.1.6': resolution: {integrity: sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==} + '@types/send@0.17.4': + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -1205,8 +1244,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001720: - resolution: {integrity: sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==} + caniuse-lite@1.0.30001721: + resolution: {integrity: sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -2364,8 +2403,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tw-animate-css@1.3.3: - resolution: {integrity: sha512-tXE2TRWrskc4TU3RDd7T8n8Np/wCfoeH9gz22c7PzYqNPQ9FBGFbWWzwL0JyHcFp+jHozmF76tbHfPAx22ua2Q==} + tw-animate-css@1.3.4: + resolution: {integrity: sha512-dd1Ht6/YQHcNbq0znIT6dG8uhO7Ce+VIIhZUhjsryXsMPJQz3bZg7Q2eNzLwipb25bRZslGb2myio5mScd1TFg==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -2488,8 +2527,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod@3.25.49: - resolution: {integrity: sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q==} + zod@3.25.51: + resolution: {integrity: sha512-TQSnBldh+XSGL+opiSIq0575wvDPqu09AqWe1F7JhUMKY+M91/aGlK4MhpVNO7MgYfHcVCB1ffwAUTJzllKJqg==} snapshots: @@ -2750,19 +2789,19 @@ snapshots: '@radix-ui/primitive@1.1.2': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.6)(react@19.1.0) @@ -2770,15 +2809,15 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.6)(react@19.1.0) @@ -2786,19 +2825,19 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.3(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.6)(react@19.1.0)': dependencies: @@ -2818,33 +2857,33 @@ snapshots: optionalDependencies: '@types/react': 19.1.6 - '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.6)(react@19.1.0)': dependencies: @@ -2852,16 +2891,16 @@ snapshots: optionalDependencies: '@types/react': 19.1.6 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) '@radix-ui/react-id@1.1.1(@types/react@19.1.6)(react@19.1.0)': dependencies: @@ -2870,31 +2909,31 @@ snapshots: optionalDependencies: '@types/react': 19.1.6 - '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-menu@2.1.15(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-menu@2.1.15(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.3(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.6)(react@19.1.0) aria-hidden: 1.2.6 @@ -2903,15 +2942,15 @@ snapshots: react-remove-scroll: 2.7.1(@types/react@19.1.6)(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@floating-ui/react-dom': 2.1.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.6)(react@19.1.0) @@ -2921,19 +2960,19 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.6)(react@19.1.0) @@ -2941,42 +2980,42 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.6)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.6)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.6)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) - '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.5(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.6 - '@types/react-dom': 19.1.5(@types/react@19.1.6) + '@types/react-dom': 19.1.6(@types/react@19.1.6) '@radix-ui/react-slot@1.2.3(@types/react@19.1.6)(react@19.1.0)': dependencies: @@ -3070,7 +3109,7 @@ snapshots: dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/realtime-js@2.11.9': + '@supabase/realtime-js@2.11.10': dependencies: '@supabase/node-fetch': 2.6.15 '@types/phoenix': 1.6.6 @@ -3080,22 +3119,22 @@ snapshots: - bufferutil - utf-8-validate - '@supabase/ssr@0.6.1(@supabase/supabase-js@2.49.9)': + '@supabase/ssr@0.6.1(@supabase/supabase-js@2.49.10)': dependencies: - '@supabase/supabase-js': 2.49.9 + '@supabase/supabase-js': 2.49.10 cookie: 1.0.2 '@supabase/storage-js@2.7.1': dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/supabase-js@2.49.9': + '@supabase/supabase-js@2.49.10': dependencies: '@supabase/auth-js': 2.69.1 '@supabase/functions-js': 2.4.4 '@supabase/node-fetch': 2.6.15 '@supabase/postgrest-js': 1.19.4 - '@supabase/realtime-js': 2.11.9 + '@supabase/realtime-js': 2.11.10 '@supabase/storage-js': 2.7.1 transitivePeerDependencies: - bufferutil @@ -3107,17 +3146,17 @@ snapshots: dependencies: tslib: 2.8.1 - '@t3-oss/env-core@0.12.0(typescript@5.8.3)(zod@3.25.49)': + '@t3-oss/env-core@0.12.0(typescript@5.8.3)(zod@3.25.51)': optionalDependencies: typescript: 5.8.3 - zod: 3.25.49 + zod: 3.25.51 - '@t3-oss/env-nextjs@0.12.0(typescript@5.8.3)(zod@3.25.49)': + '@t3-oss/env-nextjs@0.12.0(typescript@5.8.3)(zod@3.25.51)': dependencies: - '@t3-oss/env-core': 0.12.0(typescript@5.8.3)(zod@3.25.49) + '@t3-oss/env-core': 0.12.0(typescript@5.8.3)(zod@3.25.51) optionalDependencies: typescript: 5.8.3 - zod: 3.25.49 + zod: 3.25.51 '@tailwindcss/node@4.1.8': dependencies: @@ -3196,19 +3235,53 @@ snapshots: tslib: 2.8.1 optional: true + '@types/body-parser@1.19.5': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 20.17.57 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 20.17.57 + + '@types/cors@2.8.18': + dependencies: + '@types/node': 20.17.57 + '@types/estree@1.0.7': {} + '@types/express-serve-static-core@5.0.6': + dependencies: + '@types/node': 20.17.57 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + '@types/express@5.0.2': + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 5.0.6 + '@types/serve-static': 1.15.7 + + '@types/http-errors@2.0.4': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} + '@types/mime@1.3.5': {} + '@types/node@20.17.57': dependencies: undici-types: 6.19.8 '@types/phoenix@1.6.6': {} - '@types/react-dom@19.1.5(@types/react@19.1.6)': + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/react-dom@19.1.6(@types/react@19.1.6)': dependencies: '@types/react': 19.1.6 @@ -3216,6 +3289,17 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/send@0.17.4': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 20.17.57 + + '@types/serve-static@1.15.7': + dependencies: + '@types/http-errors': 2.0.4 + '@types/node': 20.17.57 + '@types/send': 0.17.4 + '@types/ws@8.18.1': dependencies: '@types/node': 20.17.57 @@ -3507,7 +3591,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001720: {} + caniuse-lite@1.0.30001721: {} chalk@4.1.2: dependencies: @@ -4350,7 +4434,7 @@ snapshots: '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 - caniuse-lite: 1.0.30001720 + caniuse-lite: 1.0.30001721 postcss: 8.4.31 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) @@ -4803,7 +4887,7 @@ snapshots: tslib@2.8.1: {} - tw-animate-css@1.3.3: {} + tw-animate-css@1.3.4: {} type-check@0.4.0: dependencies: @@ -4968,4 +5052,4 @@ snapshots: yocto-queue@0.1.0: {} - zod@3.25.49: {} + zod@3.25.51: {} diff --git a/src/app/(auth-pages)/profile/page.tsx b/src/app/(auth-pages)/profile/page.tsx index 4b74787..be7610c 100644 --- a/src/app/(auth-pages)/profile/page.tsx +++ b/src/app/(auth-pages)/profile/page.tsx @@ -81,7 +81,7 @@ const ProfilePage = () => { } return ( -
+
Your Profile diff --git a/src/components/context/auth.tsx b/src/components/context/auth.tsx index ca41c65..bf8ccf6 100644 --- a/src/components/context/auth.tsx +++ b/src/components/context/auth.tsx @@ -14,7 +14,7 @@ import { getSignedUrl, getUser, updateProfile as updateProfileAction, -} from '@/lib/actions'; +} from '@/lib/hooks'; import { type User, type Profile, @@ -119,7 +119,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { }; }, [fetchUserData]); - const updateProfile = async (data: { + const updateProfile = useCallback(async (data: { full_name?: string; email?: string; avatar_url?: string; @@ -151,15 +151,12 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { console.error('Error updating profile:', error); toast.error(error instanceof Error ? error.message : 'Failed to update profile'); return { success: false, error }; - } finally { - setIsLoading(false); } - }; + }, []); - const refreshUserData = async () => { - console.log('Manual refresh triggered'); + const refreshUserData = useCallback(async () => { await fetchUserData(); - }; + }, [fetchUserData]); const value = { user, @@ -171,7 +168,11 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { refreshUserData, }; - return {children}; + return ( + + {children} + + ); } export const useAuth = () => { diff --git a/src/components/default/profile/AvatarUpload.tsx b/src/components/default/profile/AvatarUpload.tsx index 55446bc..4be301d 100644 --- a/src/components/default/profile/AvatarUpload.tsx +++ b/src/components/default/profile/AvatarUpload.tsx @@ -28,7 +28,7 @@ export const AvatarUpload = ({ onAvatarUploaded }: AvatarUploadProps) => { maxHeight: 500, quality: 0.8, }, - prevPath: profile?.avatar_url, + replace: {replace: true, path: profile?.avatar_url ?? file.name}, }); if (result.success && result.path) { await onAvatarUploaded(result.path); diff --git a/src/env.js b/src/env.js index bca9294..484a5e3 100644 --- a/src/env.js +++ b/src/env.js @@ -18,6 +18,7 @@ export const env = createEnv({ client: { NEXT_PUBLIC_SUPABASE_URL: z.string().url(), NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1), + NEXT_PUBLIC_SITE_URL: z.string().url(), }, /** @@ -29,6 +30,7 @@ export const env = createEnv({ NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, + NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially diff --git a/src/lib/actions/storage.ts b/src/lib/actions/storage.ts old mode 100644 new mode 100755 index f8636dd..5f6ea02 --- a/src/lib/actions/storage.ts +++ b/src/lib/actions/storage.ts @@ -23,18 +23,16 @@ export type UploadStorageProps = { file: File; options?: { cacheControl?: string; - upsert?: boolean; contentType?: string; }; }; export type ReplaceStorageProps = { bucket: string; - prevPath: string; + path: string; file: File; options?: { cacheControl?: string; - upsert?: boolean; contentType?: string; }; }; @@ -135,21 +133,15 @@ export const uploadFile = async ({ export const replaceFile = async ({ bucket, - prevPath, + path, file, options = {}, }: ReplaceStorageProps): Promise> => { try { - options.upsert = true; const supabase = await createServerClient(); - //const deleteFileData = await deleteFile({ - //bucket, - //path: [...prevPath], - //}); const { data, error } = await supabase.storage .from(bucket) - //.update(path, file, options); - .update(prevPath, file, options); + .update(path, file, {...options, upsert: true}); if (error) throw error; if (!data?.path) throw new Error('No path returned from upload'); return { success: true, data: data.path }; diff --git a/src/lib/hooks/auth.ts b/src/lib/hooks/auth.ts new file mode 100644 index 0000000..884f18f --- /dev/null +++ b/src/lib/hooks/auth.ts @@ -0,0 +1,133 @@ +'use client' +import { encodedRedirect } from '@/utils/utils'; +import { createClient } from '@/utils/supabase'; +import { redirect } from 'next/navigation'; +import type { User } from '@/utils/supabase'; +import type { Result } from './index'; + +export const signUp = async (formData: FormData) => { + const name = formData.get('name') as string; + const email = formData.get('email') as string; + const password = formData.get('password') as string; + const supabase = createClient(); + const origin = process.env.NEXT_PUBLIC_SITE_URL!; + + if (!email || !password) { + return encodedRedirect( + 'error', + '/sign-up', + 'Email & password are required', + ); + } + + const { error } = await supabase.auth.signUp({ + email, + password, + options: { + emailRedirectTo: `${origin}/auth/callback`, + data: { + full_name: name, + email, + provider: 'email', + }, + }, + }); + if (error) { + return encodedRedirect('error', '/sign-up', error.message); + } else { + return encodedRedirect( + 'success', + '/sign-up', + 'Thanks for signing up! Please check your email for a verification link.', + ); + } +}; + +export const signIn = async ( + formData: FormData, +): Promise> => { + const email = formData.get('email') as string; + const password = formData.get('password') as string; + const supabase = createClient(); + + const { error } = await supabase.auth.signInWithPassword({ + email, + password, + }); + if (error) { + return { success: false, error: error.message }; + } else { + return { success: true, data: null }; + } +}; + +export const forgotPassword = async (formData: FormData) => { + const email = formData.get('email') as string; + const supabase = createClient(); + const origin = process.env.NEXT_PUBLIC_SITE_URL!; + const callbackUrl = formData.get('callbackUrl') as string; + + if (!email) { + return encodedRedirect('error', '/forgot-password', 'Email is required'); + } + + const { error } = await supabase.auth.resetPasswordForEmail(email, { + redirectTo: `${origin}/auth/callback?redirect_to=/reset-password`, + }); + + if (error) { + return encodedRedirect( + 'error', + '/forgot-password', + 'Could not reset password', + ); + } + + if (callbackUrl) { + return redirect(callbackUrl); + } + + return encodedRedirect( + 'success', + '/forgot-password', + 'Check your email for a link to reset your password.', + ); +}; + + +export const resetPassword = async (formData: FormData): Promise> => { + const password = formData.get('password') as string; + const confirmPassword = formData.get('confirmPassword') as string; + if (!password || !confirmPassword) { + return { success: false, error: 'Password and confirm password are required!' }; + } + const supabase = createClient(); + if (password !== confirmPassword) { + return { success: false, error: 'Passwords do not match!' }; + } + const { error } = await supabase.auth.updateUser({ + password, + }); + if (error) { + return { success: false, error: `Password update failed: ${error.message}` }; + } + return { success: true, data: null }; +}; + +export const signOut = async (): Promise> => { + const supabase = createClient(); + const { error } = await supabase.auth.signOut(); + if (error) return { success: false, error: error.message } + return { success: true, data: null }; +}; + +export const getUser = async (): Promise> => { + try { + const supabase = createClient(); + const { data, error } = await supabase.auth.getUser(); + if (error) throw error; + return { success: true, data: data.user }; + } catch (error) { + return { success: false, error: 'Could not get user!' }; + } +}; diff --git a/src/lib/hooks/index.ts b/src/lib/hooks/index.ts old mode 100644 new mode 100755 index 8d80488..cd51501 --- a/src/lib/hooks/index.ts +++ b/src/lib/hooks/index.ts @@ -1,2 +1,9 @@ -export * from './resizeImage'; +export * from './auth'; +export * from './public'; +//export * from './resizeImage'; +export * from './storage'; export * from './useFileUpload'; + +export type Result = + | { success: true; data: T } + | { success: false; error: string }; diff --git a/src/lib/hooks/public.ts b/src/lib/hooks/public.ts new file mode 100644 index 0000000..87786b8 --- /dev/null +++ b/src/lib/hooks/public.ts @@ -0,0 +1,79 @@ +'use client'; + +import { createClient, type Profile } from '@/utils/supabase'; +import { getUser } from '@/lib/hooks'; +import type { Result } from './index'; + +export const getProfile = async (): Promise> => { + try { + const user = await getUser(); + if (!user.success || user.data === undefined) + throw new Error('User not found'); + const supabase = createClient(); + const { data, error } = await supabase + .from('profiles') + .select('*') + .eq('id', user.data.id) + .single(); + if (error) throw error; + return { success: true, data: data as Profile }; + } catch (error) { + return { + success: false, + error: + error instanceof Error + ? error.message + : 'Unknown error getting profile', + }; + } +}; + +type updateProfileProps = { + full_name?: string; + email?: string; + avatar_url?: string; +}; + +export const updateProfile = async ({ + full_name, + email, + avatar_url, +}: updateProfileProps): Promise> => { + try { + if ( + full_name === undefined && + email === undefined && + avatar_url === undefined + ) + throw new Error('No profile data provided'); + + const userResponse = await getUser(); + if (!userResponse.success || userResponse.data === undefined) + throw new Error('User not found'); + + const supabase = createClient(); + const { data, error } = await supabase + .from('profiles') + .update({ + ...(full_name !== undefined && { full_name }), + ...(email !== undefined && { email }), + ...(avatar_url !== undefined && { avatar_url }), + }) + .eq('id', userResponse.data.id) + .select() + .single(); + if (error) throw error; + return { + success: true, + data: data as Profile, + }; + } catch (error) { + return { + success: false, + error: + error instanceof Error + ? error.message + : 'Unknown error updating profile', + }; + } +}; diff --git a/src/lib/hooks/resizeImage.ts b/src/lib/hooks/resizeImage.ts deleted file mode 100644 index 1a4df2f..0000000 --- a/src/lib/hooks/resizeImage.ts +++ /dev/null @@ -1,59 +0,0 @@ -'use client' - -export type resizeImageProps = { - file: File, - options?: { - maxWidth?: number, - maxHeight?: number, - quality?: number, - } -}; - -export const resizeImage = async ({ - file, - options = {}, -}: resizeImageProps): Promise => { - const { - maxWidth = 800, - maxHeight = 800, - quality = 0.8, - } = options; - return new Promise((resolve) => { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = (event) => { - const img = new Image(); - img.src = event.target?.result as string; - img.onload = () => { - let width = img.width; - let height = img.height; - if (width > height) { - if (width > maxWidth) { - height = Math.round((height * maxWidth / width)); - width = maxWidth; - } - } else if (height > maxHeight) { - width = Math.round((width * maxHeight / height)); - height = maxHeight; - } - const canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - const ctx = canvas.getContext('2d'); - ctx?.drawImage(img, 0, 0, width, height); - canvas.toBlob( - (blob) => { - if (!blob) return; - const resizedFile = new File([blob], file.name, { - type: 'image/jpeg', - lastModified: Date.now(), - }); - resolve(resizedFile); - }, - 'image/jpeg', - quality - ); - }; - }; - }); -}; diff --git a/src/lib/hooks/storage.ts b/src/lib/hooks/storage.ts new file mode 100644 index 0000000..6ac9c77 --- /dev/null +++ b/src/lib/hooks/storage.ts @@ -0,0 +1,265 @@ +'use client'; + +import { createClient } from '@/utils/supabase'; +import type { Result } from './index'; + +export type GetStorageProps = { + bucket: string; + url: string; + seconds?: number; + transform?: { + width?: number; + height?: number; + quality?: number; + format?: 'origin'; + resize?: 'cover' | 'contain' | 'fill'; + }; + download?: boolean | string; +}; + +export type UploadStorageProps = { + bucket: string; + path: string; + file: File; + options?: { + cacheControl?: string; + contentType?: string; + }; +}; + +export type ReplaceStorageProps = { + bucket: string; + path: string; + file: File; + options?: { + cacheControl?: string; + contentType?: string; + }; +}; + +export type resizeImageProps = { + file: File, + options?: { + maxWidth?: number, + maxHeight?: number, + quality?: number, + } +}; + +export const getSignedUrl = async ({ + bucket, + url, + seconds = 3600, + transform = {}, + download = false, +}: GetStorageProps): Promise> => { + try { + const supabase = createClient(); + const { data, error } = await supabase.storage + .from(bucket) + .createSignedUrl(url, seconds, { + download, + transform, + }); + + if (error) throw error; + if (!data?.signedUrl) throw new Error('No signed URL returned'); + + return { success: true, data: data.signedUrl }; + } catch (error) { + return { + success: false, + error: + error instanceof Error + ? error.message + : 'Unknown error getting signed URL', + }; + } +} + +export const getPublicUrl = async ({ + bucket, + url, + transform = {}, + download = false, +}: GetStorageProps): Promise> => { + try { + const supabase = createClient(); + const { data } = supabase.storage + .from(bucket) + .getPublicUrl(url, { + download, + transform, + }); + + if (!data?.publicUrl) throw new Error('No public URL returned'); + + return { success: true, data: data.publicUrl }; + } catch (error) { + return { + success: false, + error: + error instanceof Error + ? error.message + : 'Unknown error getting public URL', + }; + } +} + +export const uploadFile = async ({ + bucket, + path, + file, + options = {}, +}: UploadStorageProps): Promise> => { + try { + const supabase = createClient(); + const { data, error } = await supabase.storage + .from(bucket) + .upload(path, file, options); + + if (error) throw error; + if (!data?.path) throw new Error('No path returned from upload'); + + return { success: true, data: data.path }; + } catch (error) { + return { + success: false, + error: + error instanceof Error ? error.message : 'Unknown error uploading file', + }; + } +} + +export const replaceFile = async ({ + bucket, + path, + file, + options = {}, +}: ReplaceStorageProps): Promise> => { + try { + const supabase = createClient(); + const { data, error } = await supabase.storage + .from(bucket) + .update(path, file, { + ...options, + upsert: true, + }); + if (error) throw error; + if (!data?.path) throw new Error('No path returned from upload'); + return { success: true, data: data.path }; + } catch (error) { + return { + success: false, + error: + error instanceof Error ? error.message : 'Unknown error replacing file', + }; + } +}; + +// Add a helper to delete files +export const deleteFile = async ({ + bucket, + path, +}: { + bucket: string; + path: string[]; +}): Promise> => { + try { + const supabase = createClient(); + const { error } = await supabase.storage.from(bucket).remove(path); + + if (error) throw error; + + return { success: true, data: null }; + } catch (error) { + return { + success: false, + error: + error instanceof Error ? error.message : 'Unknown error deleting file', + }; + } +} + +// Add a helper to list files in a bucket +export const listFiles = async ({ + bucket, + path = '', + options = {}, +}: { + bucket: string; + path?: string; + options?: { + limit?: number; + offset?: number; + sortBy?: { column: string; order: 'asc' | 'desc' }; + }; +}): Promise>> => { + try { + const supabase = createClient(); + const { data, error } = await supabase.storage + .from(bucket) + .list(path, options); + + if (error) throw error; + if (!data) throw new Error('No data returned from list operation'); + + return { success: true, data }; + } catch (error) { + console.error('Could not list files!', error); + return { + success: false, + error: + error instanceof Error ? error.message : 'Unknown error listing files', + }; + } +} + +export const resizeImage = async ({ + file, + options = {}, +}: resizeImageProps): Promise => { + const { + maxWidth = 800, + maxHeight = 800, + quality = 0.8, + } = options; + return new Promise((resolve) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = (event) => { + const img = new Image(); + img.src = event.target?.result as string; + img.onload = () => { + let width = img.width; + let height = img.height; + if (width > height) { + if (width > maxWidth) { + height = Math.round((height * maxWidth / width)); + width = maxWidth; + } + } else if (height > maxHeight) { + width = Math.round((width * maxHeight / height)); + height = maxHeight; + } + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d'); + ctx?.drawImage(img, 0, 0, width, height); + canvas.toBlob( + (blob) => { + if (!blob) return; + const resizedFile = new File([blob], file.name, { + type: 'imgage/jpeg', + lastModified: Date.now(), + }); + resolve(resizedFile); + }, + 'image/jpeg', + quality + ); + }; + }; + }); +}; diff --git a/src/lib/hooks/useFileUpload.ts b/src/lib/hooks/useFileUpload.ts index c8209e0..aee695b 100644 --- a/src/lib/hooks/useFileUpload.ts +++ b/src/lib/hooks/useFileUpload.ts @@ -1,11 +1,15 @@ 'use client' import { useState, useRef } from 'react'; -import { deleteFile, replaceFile, uploadFile } from '@/lib/actions'; +import { replaceFile, uploadFile } from '@/lib/hooks'; import { toast } from 'sonner'; import { useAuth } from '@/components/context/auth'; import { resizeImage } from '@/lib/hooks'; +export type Replace = + | { replace: true, path: string } + | false; + export type uploadToStorageProps = { file: File; bucket: string; @@ -15,7 +19,7 @@ export type uploadToStorageProps = { maxHeight?: number; quality?: number; }; - prevPath?: string | null; + replace?: Replace; }; export const useFileUpload = () => { @@ -28,25 +32,16 @@ export const useFileUpload = () => { bucket, resize = false, options = {}, - prevPath = null, + replace = false, }: uploadToStorageProps) => { try { if (!isAuthenticated) throw new Error('User is not authenticated'); setIsUploading(true); - if (prevPath !== null) { - const deleteResult = await deleteFile({ - bucket, - path: [...prevPath], - }); - if (!deleteResult.success) { - console.error('Error deleting file:', deleteResult.error); - throw new Error(deleteResult.error || `Failed to delete ${prevPath}`); - } else console.log('Delete sucessful!') - console.log('Deleted file path: ', deleteResult.data) + if (replace) { const updateResult = await replaceFile({ bucket, - prevPath: prevPath, + path: replace.path, file, options: { contentType: file.type, @@ -74,7 +69,6 @@ export const useFileUpload = () => { path: fileName, file: fileToUpload, options: { - upsert: true, contentType: file.type, }, });