diff --git a/.gitignore b/.gitignore index 2306282..a87bdfa 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ next-env.d.ts /cloudinary-images +.obsidian \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 754092f..c4dd6f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@react-email/tailwind": "^0.0.12", "@vercel/analytics": "^1.1.0", "argon2": "^0.31.1", + "classnames": "^2.5.1", "cloudinary": "^1.41.0", "cookie": "^0.5.0", "date-fns": "^2.30.0", @@ -37,7 +38,7 @@ "passport-local": "^1.0.0", "pino": "^8.14.1", "react": "^18.2.0", - "react-daisyui": "^4.1.2", + "react-daisyui": "^5.0.0", "react-dom": "^18.2.0", "react-email": "^1.9.5", "react-hook-form": "^7.45.2", @@ -62,10 +63,9 @@ "@types/passport-local": "^1.0.35", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", - "@types/sparkpost": "^2.1.5", "@vercel/fetch": "^7.0.0", "autoprefixer": "^10.4.14", - "daisyui": "^3.9.2", + "daisyui": "^4.7.2", "dotenv-cli": "^7.2.1", "eslint": "^8.51.0", "eslint-config-airbnb-base": "15.0.0", @@ -80,8 +80,8 @@ "prettier-plugin-jsdoc": "^1.0.2", "prettier-plugin-tailwindcss": "^0.5.7", "prisma": "^5.7.0", - "tailwindcss": "^3.3.3", - "tailwindcss-animate": "^1.0.6", + "tailwindcss": "^3.4.1", + "tailwindcss-animated": "^1.0.1", "ts-node": "^10.9.1", "typescript": "^5.3.2" } @@ -2108,12 +2108,6 @@ "@types/responselike": "^1.0.0" } }, - "node_modules/@types/caseless": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.3.tgz", - "integrity": "sha512-ZD/NsIJYq/2RH+hY7lXmstfp/v9djGt9ah+xRQ3pcgR79qiKsG4pLl25AI7IcXxVO8dH9GiBE5rAknC0ePntlw==", - "dev": true - }, "node_modules/@types/connect": { "version": "3.4.36", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", @@ -2375,32 +2369,6 @@ "@types/react": "*" } }, - "node_modules/@types/request": { - "version": "2.48.9", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.9.tgz", - "integrity": "sha512-4mi2hYsvPAhe8RXjk5DKB09sAUzbK68T2XjORehHdWyxFoX2zUnfi1VQ5wU4Md28H/5+uB4DkxY9BS4B87N/0A==", - "dev": true, - "dependencies": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, - "node_modules/@types/request/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/@types/responselike": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", @@ -2448,22 +2416,6 @@ "@types/node": "*" } }, - "node_modules/@types/sparkpost": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@types/sparkpost/-/sparkpost-2.1.6.tgz", - "integrity": "sha512-lqimYaHi52iIJBge6XZBvLFGBjlZgSlsvUsARALgaYLpsUriPhayYKc8fyP5dgHmjJ6ClumP3BQHYT5Vbci6ew==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/request": "*" - } - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz", - "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", - "dev": true - }, "node_modules/@types/unist": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", @@ -3618,9 +3570,9 @@ } }, "node_modules/classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, "node_modules/cli-cursor": { "version": "3.1.0", @@ -3714,11 +3666,6 @@ "color-support": "bin.js" } }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3882,16 +3829,23 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/culori": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz", + "integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/daisyui": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.9.4.tgz", - "integrity": "sha512-fvi2RGH4YV617/6DntOVGcOugOPym9jTGWW2XySb5ZpvdWO4L7bEG77VHirrnbRUEWvIEVXkBpxUz2KFj0rVnA==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.7.2.tgz", + "integrity": "sha512-9UCss12Zmyk/22u+JbkVrHHxOzFOyY17HuqP5LeswI4hclbj6qbjJTovdj2zRy8cCH6/n6Wh0lTLjriGnyGh0g==", "dependencies": { - "colord": "^2.9", "css-selector-tokenizer": "^0.8", - "postcss": "^8", - "postcss-js": "^4", - "tailwindcss": "^3.1" + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" }, "engines": { "node": ">=16.9.0" @@ -8694,11 +8648,11 @@ } }, "node_modules/react-daisyui": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/react-daisyui/-/react-daisyui-4.1.2.tgz", - "integrity": "sha512-Sx8ziaxKDe/59bw+UxTFOoDSJEuA8iGhgmMbzSAtnhaaZPP20kluHG+1/wY5mBSxfcAuk6oI8fqKcJRp55WzPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-daisyui/-/react-daisyui-5.0.0.tgz", + "integrity": "sha512-j1cugAxALmIbihycGBh7P9H3UXrfsvqu84qM6O55l7nOKST43IjUkZjmNav/7s0ZaUpa9Y+52mFchUb2zvon1A==", "peerDependencies": { - "daisyui": "^3.0.22", + "daisyui": "^4.4.6", "react": ">=16", "react-dom": ">=16", "tailwindcss": ">=3.2.7" @@ -9969,19 +9923,19 @@ "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" }, "node_modules/tailwindcss": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", - "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -10004,13 +9958,13 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss-animate": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", - "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "node_modules/tailwindcss-animated": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tailwindcss-animated/-/tailwindcss-animated-1.0.1.tgz", + "integrity": "sha512-u5wusj89ZwP8I+s8WZlaAd7aZTWBN/XEG6QgMKpkIKmAf3xP1A6WYf7oYIKmGaB10UAQaSqWopi/i1ozzZEs8Q==", "dev": true, "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" + "tailwindcss": ">=3.1.0" } }, "node_modules/tailwindcss/node_modules/arg": { @@ -12221,12 +12175,6 @@ "@types/responselike": "^1.0.0" } }, - "@types/caseless": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.3.tgz", - "integrity": "sha512-ZD/NsIJYq/2RH+hY7lXmstfp/v9djGt9ah+xRQ3pcgR79qiKsG4pLl25AI7IcXxVO8dH9GiBE5rAknC0ePntlw==", - "dev": true - }, "@types/connect": { "version": "3.4.36", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", @@ -12487,31 +12435,6 @@ "@types/react": "*" } }, - "@types/request": { - "version": "2.48.9", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.9.tgz", - "integrity": "sha512-4mi2hYsvPAhe8RXjk5DKB09sAUzbK68T2XjORehHdWyxFoX2zUnfi1VQ5wU4Md28H/5+uB4DkxY9BS4B87N/0A==", - "dev": true, - "requires": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - }, - "dependencies": { - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - } - } - }, "@types/responselike": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", @@ -12559,22 +12482,6 @@ "@types/node": "*" } }, - "@types/sparkpost": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@types/sparkpost/-/sparkpost-2.1.6.tgz", - "integrity": "sha512-lqimYaHi52iIJBge6XZBvLFGBjlZgSlsvUsARALgaYLpsUriPhayYKc8fyP5dgHmjJ6ClumP3BQHYT5Vbci6ew==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/request": "*" - } - }, - "@types/tough-cookie": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz", - "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", - "dev": true - }, "@types/unist": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", @@ -13368,9 +13275,9 @@ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" }, "classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, "cli-cursor": { "version": "3.1.0", @@ -13438,11 +13345,6 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, - "colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -13573,16 +13475,20 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "culori": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz", + "integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==" + }, "daisyui": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.9.4.tgz", - "integrity": "sha512-fvi2RGH4YV617/6DntOVGcOugOPym9jTGWW2XySb5ZpvdWO4L7bEG77VHirrnbRUEWvIEVXkBpxUz2KFj0rVnA==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.7.2.tgz", + "integrity": "sha512-9UCss12Zmyk/22u+JbkVrHHxOzFOyY17HuqP5LeswI4hclbj6qbjJTovdj2zRy8cCH6/n6Wh0lTLjriGnyGh0g==", "requires": { - "colord": "^2.9", "css-selector-tokenizer": "^0.8", - "postcss": "^8", - "postcss-js": "^4", - "tailwindcss": "^3.1" + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" } }, "damerau-levenshtein": { @@ -16918,9 +16824,9 @@ } }, "react-daisyui": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/react-daisyui/-/react-daisyui-4.1.2.tgz", - "integrity": "sha512-Sx8ziaxKDe/59bw+UxTFOoDSJEuA8iGhgmMbzSAtnhaaZPP20kluHG+1/wY5mBSxfcAuk6oI8fqKcJRp55WzPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-daisyui/-/react-daisyui-5.0.0.tgz", + "integrity": "sha512-j1cugAxALmIbihycGBh7P9H3UXrfsvqu84qM6O55l7nOKST43IjUkZjmNav/7s0ZaUpa9Y+52mFchUb2zvon1A==", "requires": {} }, "react-dom": { @@ -17861,19 +17767,19 @@ "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" }, "tailwindcss": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", - "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", "requires": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -17896,10 +17802,10 @@ } } }, - "tailwindcss-animate": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", - "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "tailwindcss-animated": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tailwindcss-animated/-/tailwindcss-animated-1.0.1.tgz", + "integrity": "sha512-u5wusj89ZwP8I+s8WZlaAd7aZTWBN/XEG6QgMKpkIKmAf3xP1A6WYf7oYIKmGaB10UAQaSqWopi/i1ozzZEs8Q==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 15272cc..433f928 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@react-email/tailwind": "^0.0.12", "@vercel/analytics": "^1.1.0", "argon2": "^0.31.1", + "classnames": "^2.5.1", "cloudinary": "^1.41.0", "cookie": "^0.5.0", "date-fns": "^2.30.0", @@ -36,13 +37,14 @@ "lodash": "^4.17.21", "mapbox-gl": "^2.15.0", "multer": "^1.4.5-lts.1", + "next": "^14.0.3", "next-cloudinary": "^5.10.0", "next-connect": "^1.0.0-next.3", - "next": "^14.0.3", - "passport-local": "^1.0.0", "passport": "^0.6.0", + "passport-local": "^1.0.0", "pino": "^8.14.1", - "react-daisyui": "^4.1.2", + "react": "^18.2.0", + "react-daisyui": "^5.0.0", "react-dom": "^18.2.0", "react-email": "^1.9.5", "react-hook-form": "^7.45.2", @@ -51,7 +53,6 @@ "react-intersection-observer": "^9.5.2", "react-map-gl": "^7.1.2", "react-responsive-carousel": "^3.2.23", - "react": "^18.2.0", "swr": "^2.2.0", "theme-change": "^2.5.0", "zod": "^3.21.4" @@ -66,28 +67,27 @@ "@types/multer": "^1.4.7", "@types/node": "^20.4.2", "@types/passport-local": "^1.0.35", - "@types/react-dom": "^18.2.7", "@types/react": "^18.2.15", - "@types/sparkpost": "^2.1.5", + "@types/react-dom": "^18.2.7", "@vercel/fetch": "^7.0.0", "autoprefixer": "^10.4.14", - "daisyui": "^3.9.2", + "daisyui": "^4.7.2", "dotenv-cli": "^7.2.1", + "eslint": "^8.51.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-next": "^13.5.4", "eslint-config-prettier": "^9.0.0", "eslint-plugin-react": "^7.33.2", - "eslint": "^8.51.0", "generate-password": "^1.7.1", "onchange": "^7.1.0", "postcss": "^8.4.26", + "prettier": "^3.0.0", "prettier-plugin-jsdoc": "^1.0.2", "prettier-plugin-tailwindcss": "^0.5.7", - "prettier": "^3.0.0", "prisma": "^5.7.0", - "tailwindcss-animate": "^1.0.6", - "tailwindcss": "^3.3.3", + "tailwindcss": "^3.4.1", + "tailwindcss-animated": "^1.0.1", "ts-node": "^10.9.1", "typescript": "^5.3.2" }, diff --git a/public/background.jpg b/public/background.jpg new file mode 100644 index 0000000..27841d8 Binary files /dev/null and b/public/background.jpg differ diff --git a/src/components/Account/AccountInfo.tsx b/src/components/Account/AccountInfo.tsx index 63cf7c5..35b0a82 100644 --- a/src/components/Account/AccountInfo.tsx +++ b/src/components/Account/AccountInfo.tsx @@ -1,5 +1,4 @@ -import validateEmailRequest from '@/requests/User/validateEmailRequest'; -import validateUsernameRequest from '@/requests/validateUsernameRequest'; +import validateUsernameRequest from '@/requests/users/profile/validateUsernameRequest'; import { BaseCreateUserSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas'; import { Switch } from '@headlessui/react'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -7,7 +6,7 @@ import { Dispatch, FC, useContext } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import UserContext from '@/contexts/UserContext'; -import sendEditUserRequest from '@/requests/User/sendEditUserRequest'; + import createErrorToast from '@/util/createErrorToast'; import { toast } from 'react-hot-toast'; import { AccountPageAction, AccountPageState } from '@/reducers/accountPageReducer'; @@ -15,6 +14,7 @@ import FormError from '../ui/forms/FormError'; import FormInfo from '../ui/forms/FormInfo'; import FormLabel from '../ui/forms/FormLabel'; import FormTextInput from '../ui/forms/FormTextInput'; +import { sendEditUserRequest, validateEmailRequest } from '@/requests/users/auth'; interface AccountInfoProps { pageState: AccountPageState; @@ -36,7 +36,7 @@ const AccountInfo: FC = ({ pageState, dispatch }) => { .refine( async (email) => { if (user!.email === email) return true; - return validateEmailRequest(email); + return validateEmailRequest({ email }); }, { message: 'Email is already taken.' }, ), diff --git a/src/components/Account/Security.tsx b/src/components/Account/Security.tsx index f9e0b79..e363595 100644 --- a/src/components/Account/Security.tsx +++ b/src/components/Account/Security.tsx @@ -4,10 +4,11 @@ import { SubmitHandler, useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { UpdatePasswordSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas'; -import sendUpdatePasswordRequest from '@/requests/User/sendUpdatePasswordRequest'; + import { AccountPageState, AccountPageAction } from '@/reducers/accountPageReducer'; import toast from 'react-hot-toast'; import createErrorToast from '@/util/createErrorToast'; +import { sendUpdatePasswordRequest } from '@/requests/users/auth'; import FormError from '../ui/forms/FormError'; import FormInfo from '../ui/forms/FormInfo'; import FormLabel from '../ui/forms/FormLabel'; diff --git a/src/components/Account/UpdateProfileLink.tsx b/src/components/Account/UpdateProfileLink.tsx index e8c941a..e354a5b 100644 --- a/src/components/Account/UpdateProfileLink.tsx +++ b/src/components/Account/UpdateProfileLink.tsx @@ -5,7 +5,7 @@ import { FaArrowRight } from 'react-icons/fa'; const UpdateProfileLink: React.FC = () => { return ( -
+
diff --git a/src/components/Account/UserPosts.tsx b/src/components/Account/UserPosts.tsx index 5149649..65b3661 100644 --- a/src/components/Account/UserPosts.tsx +++ b/src/components/Account/UserPosts.tsx @@ -8,11 +8,9 @@ const UserPosts: FC = () => {
- - Beers - - Breweries - + + Beers + Breweries diff --git a/src/components/BeerById/BeerCommentForm.tsx b/src/components/BeerById/BeerCommentForm.tsx index ce7d752..a1bf202 100644 --- a/src/components/BeerById/BeerCommentForm.tsx +++ b/src/components/BeerById/BeerCommentForm.tsx @@ -1,5 +1,3 @@ -import sendCreateBeerCommentRequest from '@/requests/BeerComment/sendCreateBeerCommentRequest'; - import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -11,7 +9,8 @@ import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPost import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import toast from 'react-hot-toast'; import createErrorToast from '@/util/createErrorToast'; -import CommentForm from '../ui/CommentForm'; +import { sendCreateBeerCommentRequest } from '@/requests/comments/beer-comment'; +import CommentForm from '../Comments/CommentForm'; interface BeerCommentFormProps { beerPost: z.infer; @@ -34,11 +33,7 @@ const BeerCommentForm: FunctionComponent = ({ ) => { const loadingToast = toast.loading('Posting a new comment...'); try { - await sendCreateBeerCommentRequest({ - content: data.content, - rating: data.rating, - beerPostId: beerPost.id, - }); + await sendCreateBeerCommentRequest({ body: data, beerPostId: beerPost.id }); reset(); toast.remove(loadingToast); toast.success('Comment posted successfully.'); diff --git a/src/components/BeerById/BeerPostCommentsSection.tsx b/src/components/BeerById/BeerPostCommentsSection.tsx index 5f83c91..d2cee4a 100644 --- a/src/components/BeerById/BeerPostCommentsSection.tsx +++ b/src/components/BeerById/BeerPostCommentsSection.tsx @@ -6,11 +6,15 @@ import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPostComments'; import { useRouter } from 'next/router'; -import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; + +import { + deleteBeerPostCommentRequest, + editBeerPostCommentRequest, +} from '@/requests/comments/beer-comment'; import BeerCommentForm from './BeerCommentForm'; -import LoadingComponent from './LoadingComponent'; -import CommentsComponent from '../ui/CommentsComponent'; +import CommentLoadingComponent from '../Comments/CommentLoadingComponent'; +import CommentsComponent from '../Comments/CommentsComponent'; interface BeerPostCommentsSectionProps { beerPost: z.infer; @@ -28,29 +32,6 @@ const BeerPostCommentsSection: FC = ({ beerPost }) const commentSectionRef: MutableRefObject = useRef(null); - const handleDeleteRequest = async (id: string) => { - const response = await fetch(`/api/beer-comments/${id}`, { method: 'DELETE' }); - - if (!response.ok) { - throw new Error('Failed to delete comment.'); - } - }; - - const handleEditRequest = async ( - id: string, - data: z.infer, - ) => { - const response = await fetch(`/api/beer-comments/${id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content: data.content, rating: data.rating }), - }); - - if (!response.ok) { - throw new Error('Failed to update comment.'); - } - }; - return (
@@ -72,7 +53,7 @@ const BeerPostCommentsSection: FC = ({ beerPost }) */ isLoading ? (
- +
) : ( = ({ beerPost }) setSize={setSize} size={size} mutate={mutate} - handleDeleteRequest={handleDeleteRequest} - handleEditRequest={handleEditRequest} + handleDeleteCommentRequest={(id) => { + return deleteBeerPostCommentRequest({ + commentId: id, + beerPostId: beerPost.id, + }); + }} + handleEditCommentRequest={(id, data) => { + return editBeerPostCommentRequest({ + body: data, + commentId: id, + beerPostId: beerPost.id, + }); + }} /> ) } diff --git a/src/components/BeerById/BeerPostLikeButton.tsx b/src/components/BeerById/BeerPostLikeButton.tsx index 4ecad09..5ab4fdc 100644 --- a/src/components/BeerById/BeerPostLikeButton.tsx +++ b/src/components/BeerById/BeerPostLikeButton.tsx @@ -3,7 +3,7 @@ import useCheckIfUserLikesBeerPost from '@/hooks/data-fetching/beer-likes/useChe import { FC, useEffect, useState } from 'react'; import useGetBeerPostLikeCount from '@/hooks/data-fetching/beer-likes/useBeerPostLikeCount'; -import sendBeerPostLikeRequest from '@/requests/BeerPostLike/sendBeerPostLikeRequest'; +import sendBeerPostLikeRequest from '@/requests/likes/beer-post-like/sendBeerPostLikeRequest'; import LikeButton from '../ui/LikeButton'; const BeerPostLikeButton: FC<{ diff --git a/src/components/BeerById/BeerRecommendations.tsx b/src/components/BeerById/BeerRecommendations.tsx index 96d0887..e6c48ad 100644 --- a/src/components/BeerById/BeerRecommendations.tsx +++ b/src/components/BeerById/BeerRecommendations.tsx @@ -1,10 +1,11 @@ import Link from 'next/link'; -import { FC, MutableRefObject, useRef } from 'react'; +import { FC } from 'react'; import { useInView } from 'react-intersection-observer'; import { z } from 'zod'; import useBeerRecommendations from '@/hooks/data-fetching/beer-posts/useBeerRecommendations'; import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; import debounce from 'lodash/debounce'; + import BeerRecommendationLoadingComponent from './BeerRecommendationLoadingComponent'; const BeerRecommendationsSection: FC<{ @@ -28,10 +29,8 @@ const BeerRecommendationsSection: FC<{ }, }); - const beerRecommendationsRef: MutableRefObject = useRef(null); - return ( -
+
<>
@@ -54,6 +53,7 @@ const BeerRecommendationsSection: FC<{
diff --git a/src/components/BeerStyleById/BeerStyleCommentForm.tsx b/src/components/BeerStyleById/BeerStyleCommentForm.tsx index 7e9f0e4..829ee33 100644 --- a/src/components/BeerStyleById/BeerStyleCommentForm.tsx +++ b/src/components/BeerStyleById/BeerStyleCommentForm.tsx @@ -10,8 +10,8 @@ import createErrorToast from '@/util/createErrorToast'; import BeerStyleQueryResult from '@/services/posts/beer-style-post/schema/BeerStyleQueryResult'; import useBeerStyleComments from '@/hooks/data-fetching/beer-style-comments/useBeerStyleComments'; -import sendCreateBeerStyleCommentRequest from '@/requests/BeerStyleComment/sendCreateBeerStyleCommentRequest'; -import CommentForm from '../ui/CommentForm'; +import { sendCreateBeerStyleCommentRequest } from '@/requests/comments/beer-style-comment'; +import CommentForm from '../Comments/CommentForm'; interface BeerCommentFormProps { beerStyle: z.infer; @@ -35,8 +35,7 @@ const BeerStyleCommentForm: FunctionComponent = ({ const loadingToast = toast.loading('Posting a new comment...'); try { await sendCreateBeerStyleCommentRequest({ - content: data.content, - rating: data.rating, + body: { content: data.content, rating: data.rating }, beerStyleId: beerStyle.id, }); reset(); diff --git a/src/components/BeerStyleById/BeerStyleCommentSection.tsx b/src/components/BeerStyleById/BeerStyleCommentSection.tsx index 5716327..aa597c9 100644 --- a/src/components/BeerStyleById/BeerStyleCommentSection.tsx +++ b/src/components/BeerStyleById/BeerStyleCommentSection.tsx @@ -3,12 +3,15 @@ import UserContext from '@/contexts/UserContext'; import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; import { useRouter } from 'next/router'; -import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import BeerStyleQueryResult from '@/services/posts/beer-style-post/schema/BeerStyleQueryResult'; import useBeerStyleComments from '@/hooks/data-fetching/beer-style-comments/useBeerStyleComments'; -import LoadingComponent from '../BeerById/LoadingComponent'; -import CommentsComponent from '../ui/CommentsComponent'; +import { + sendDeleteBeerStyleCommentRequest, + sendEditBeerStyleCommentRequest, +} from '@/requests/comments/beer-style-comment'; +import CommentLoadingComponent from '../Comments/CommentLoadingComponent'; +import CommentsComponent from '../Comments/CommentsComponent'; import BeerStyleCommentForm from './BeerStyleCommentForm'; interface BeerStyleCommentsSectionProps { @@ -27,31 +30,6 @@ const BeerStyleCommentsSection: FC = ({ beerStyle const commentSectionRef: MutableRefObject = useRef(null); - const handleDeleteRequest = async (id: string) => { - const response = await fetch(`/api/beer-style-comments/${id}`, { - method: 'DELETE', - }); - - if (!response.ok) { - throw new Error('Failed to delete comment.'); - } - }; - - const handleEditRequest = async ( - id: string, - data: z.infer, - ) => { - const response = await fetch(`/api/beer-style-comments/${id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content: data.content, rating: data.rating }), - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - }; - return (
@@ -73,7 +51,7 @@ const BeerStyleCommentsSection: FC = ({ beerStyle */ isLoading ? (
- +
) : ( = ({ beerStyle setSize={setSize} size={size} mutate={mutate} - handleDeleteRequest={handleDeleteRequest} - handleEditRequest={handleEditRequest} + handleDeleteCommentRequest={(id) => { + return sendDeleteBeerStyleCommentRequest({ + beerStyleId: beerStyle.id, + commentId: id, + }); + }} + handleEditCommentRequest={(id, data) => { + return sendEditBeerStyleCommentRequest({ + beerStyleId: beerStyle.id, + commentId: id, + body: data, + }); + }} /> ) } diff --git a/src/components/BeerStyleById/BeerStyleLikeButton.tsx b/src/components/BeerStyleById/BeerStyleLikeButton.tsx index 0d31c14..1e9f841 100644 --- a/src/components/BeerStyleById/BeerStyleLikeButton.tsx +++ b/src/components/BeerStyleById/BeerStyleLikeButton.tsx @@ -2,7 +2,7 @@ import { FC, useEffect, useState } from 'react'; import useGetBeerPostLikeCount from '@/hooks/data-fetching/beer-likes/useBeerPostLikeCount'; import useCheckIfUserLikesBeerStyle from '@/hooks/data-fetching/beer-style-likes/useCheckIfUserLikesBeerPost'; -import sendBeerStyleLikeRequest from '@/requests/BeerStyleLike/sendBeerStyleLikeRequest'; +import sendBeerStyleLikeRequest from '@/requests/likes/beer-style-like/sendBeerStyleLikeRequest'; import LikeButton from '../ui/LikeButton'; const BeerStyleLikeButton: FC<{ diff --git a/src/components/BreweryById/BreweryCommentForm.tsx b/src/components/BreweryById/BreweryCommentForm.tsx index 162302c..1ef4cbc 100644 --- a/src/components/BreweryById/BreweryCommentForm.tsx +++ b/src/components/BreweryById/BreweryCommentForm.tsx @@ -6,9 +6,9 @@ import { FC } from 'react'; import { useForm, SubmitHandler } from 'react-hook-form'; import toast from 'react-hot-toast'; import { z } from 'zod'; -import sendCreateBreweryCommentRequest from '@/requests/BreweryComment/sendCreateBreweryCommentRequest'; +import sendCreateBreweryCommentRequest from '@/requests/comments/brewery-comment/sendCreateBreweryCommentRequest'; import createErrorToast from '@/util/createErrorToast'; -import CommentForm from '../ui/CommentForm'; +import CommentForm from '../Comments/CommentForm'; interface BreweryCommentFormProps { breweryPost: z.infer; diff --git a/src/components/BreweryById/BreweryCommentsSection.tsx b/src/components/BreweryById/BreweryCommentsSection.tsx index e7b6c2e..7da4df5 100644 --- a/src/components/BreweryById/BreweryCommentsSection.tsx +++ b/src/components/BreweryById/BreweryCommentsSection.tsx @@ -2,11 +2,14 @@ import UserContext from '@/contexts/UserContext'; import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; import { FC, MutableRefObject, useContext, useRef } from 'react'; import { z } from 'zod'; -import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import useBreweryPostComments from '@/hooks/data-fetching/brewery-comments/useBreweryPostComments'; -import LoadingComponent from '../BeerById/LoadingComponent'; -import CommentsComponent from '../ui/CommentsComponent'; +import { + sendDeleteBreweryPostCommentRequest, + sendEditBreweryPostCommentRequest, +} from '@/requests/comments/brewery-comment'; +import CommentLoadingComponent from '../Comments/CommentLoadingComponent'; +import CommentsComponent from '../Comments/CommentsComponent'; import BreweryCommentForm from './BreweryCommentForm'; interface BreweryBeerSectionProps { @@ -30,31 +33,6 @@ const BreweryCommentsSection: FC = ({ breweryPost }) => const commentSectionRef: MutableRefObject = useRef(null); - const handleDeleteRequest = async (commentId: string) => { - const response = await fetch(`/api/brewery-comments/${commentId}`, { - method: 'DELETE', - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - }; - - const handleEditRequest = async ( - commentId: string, - data: z.infer, - ) => { - const response = await fetch(`/api/brewery-comments/${commentId}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content: data.content, rating: data.rating }), - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - }; - return (
@@ -75,7 +53,7 @@ const BreweryCommentsSection: FC = ({ breweryPost }) => */ isLoading ? (
- +
) : ( = ({ breweryPost }) => size={size} commentSectionRef={commentSectionRef} mutate={mutate} - handleDeleteRequest={handleDeleteRequest} - handleEditRequest={handleEditRequest} + handleDeleteCommentRequest={(id) => { + return sendDeleteBreweryPostCommentRequest({ + breweryPostId: breweryPost.id, + commentId: id, + }); + }} + handleEditCommentRequest={(commentId, data) => { + return sendEditBreweryPostCommentRequest({ + breweryPostId: breweryPost.id, + commentId, + body: { content: data.content, rating: data.rating }, + }); + }} /> ) } diff --git a/src/components/BreweryIndex/BreweryPostLikeButton.tsx b/src/components/BreweryIndex/BreweryPostLikeButton.tsx index c52c263..46534ec 100644 --- a/src/components/BreweryIndex/BreweryPostLikeButton.tsx +++ b/src/components/BreweryIndex/BreweryPostLikeButton.tsx @@ -1,6 +1,6 @@ import useCheckIfUserLikesBreweryPost from '@/hooks/data-fetching/brewery-likes/useCheckIfUserLikesBreweryPost'; import useGetBreweryPostLikeCount from '@/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount'; -import sendBreweryPostLikeRequest from '@/requests/BreweryPostLike/sendBreweryPostLikeRequest'; +import sendBreweryPostLikeRequest from '@/requests/likes/brewery-post-like/sendBreweryPostLikeRequest'; import { FC, useState } from 'react'; import LikeButton from '../ui/LikeButton'; diff --git a/src/components/BreweryPost/CreateBreweryPostForm.tsx b/src/components/BreweryPost/CreateBreweryPostForm.tsx index 4b1d2b6..cc473a1 100644 --- a/src/components/BreweryPost/CreateBreweryPostForm.tsx +++ b/src/components/BreweryPost/CreateBreweryPostForm.tsx @@ -1,5 +1,5 @@ -import sendUploadBreweryImagesRequest from '@/requests/BreweryImage/sendUploadBreweryImageRequest'; -import sendCreateBreweryPostRequest from '@/requests/BreweryPost/sendCreateBreweryPostRequest'; +import sendUploadBreweryImagesRequest from '@/requests/images/brewery-image/sendUploadBreweryImageRequest'; + import CreateBreweryPostSchema from '@/services/posts/brewery-post/schema/CreateBreweryPostSchema'; import UploadImageValidationSchema from '@/services/schema/ImageSchema/UploadImageValidationSchema'; import createErrorToast from '@/util/createErrorToast'; @@ -27,6 +27,7 @@ import FormSegment from '../ui/forms/FormSegment'; import FormTextArea from '../ui/forms/FormTextArea'; import FormTextInput from '../ui/forms/FormTextInput'; import Button from '../ui/forms/Button'; +import { sendCreateBreweryPostRequest } from '@/requests/posts/brewery-post'; const AddressAutofill = dynamic( // @ts-expect-error @@ -225,7 +226,7 @@ const CreateBreweryPostForm: FC<{ if (!(data.images instanceof FileList)) { return; } - const breweryPost = await sendCreateBreweryPostRequest(data); + const breweryPost = await sendCreateBreweryPostRequest({ body: data }); await sendUploadBreweryImagesRequest({ breweryPost, images: data.images }); await router.push(`/breweries/${breweryPost.id}`); toast.remove(loadingToast); @@ -249,13 +250,9 @@ const CreateBreweryPostForm: FC<{ autoComplete="off" > - - - Information - - - Location - + + Information + Location diff --git a/src/components/BeerBreweryComments/CommentCardBody.tsx b/src/components/Comments/CommentCardBody.tsx similarity index 76% rename from src/components/BeerBreweryComments/CommentCardBody.tsx rename to src/components/Comments/CommentCardBody.tsx index 2c57d4d..74c0e0a 100644 --- a/src/components/BeerBreweryComments/CommentCardBody.tsx +++ b/src/components/Comments/CommentCardBody.tsx @@ -3,28 +3,26 @@ import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResu import { FC, useState } from 'react'; import { useInView } from 'react-intersection-observer'; import { z } from 'zod'; -import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; + import CommentContentBody from './CommentContentBody'; import EditCommentBody from './EditCommentBody'; import UserAvatar from '../Account/UserAvatar'; +import { HandleDeleteCommentRequest, HandleEditCommentRequest } from './types'; interface CommentCardProps { comment: z.infer; mutate: ReturnType['mutate']; ref?: ReturnType['ref']; - handleDeleteRequest: (id: string) => Promise; - handleEditRequest: ( - id: string, - data: z.infer, - ) => Promise; + handleDeleteCommentRequest: HandleDeleteCommentRequest; + handleEditCommentRequest: HandleEditCommentRequest; } const CommentCardBody: FC = ({ comment, mutate, ref, - handleDeleteRequest, - handleEditRequest, + handleDeleteCommentRequest, + handleEditCommentRequest, }) => { const [inEditMode, setInEditMode] = useState(false); @@ -44,8 +42,8 @@ const CommentCardBody: FC = ({ comment={comment} mutate={mutate} setInEditMode={setInEditMode} - handleDeleteRequest={handleDeleteRequest} - handleEditRequest={handleEditRequest} + handleDeleteCommentRequest={handleDeleteCommentRequest} + handleEditCommentRequest={handleEditCommentRequest} /> )}
diff --git a/src/components/BeerBreweryComments/CommentCardDropdown.tsx b/src/components/Comments/CommentCardDropdown.tsx similarity index 100% rename from src/components/BeerBreweryComments/CommentCardDropdown.tsx rename to src/components/Comments/CommentCardDropdown.tsx diff --git a/src/components/BeerBreweryComments/CommentContentBody.tsx b/src/components/Comments/CommentContentBody.tsx similarity index 87% rename from src/components/BeerBreweryComments/CommentContentBody.tsx rename to src/components/Comments/CommentContentBody.tsx index adb35c4..b1d6f42 100644 --- a/src/components/BeerBreweryComments/CommentContentBody.tsx +++ b/src/components/Comments/CommentContentBody.tsx @@ -7,6 +7,8 @@ import Link from 'next/link'; import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; import { z } from 'zod'; +import { useInView } from 'react-intersection-observer'; +import classNames from 'classnames'; import CommentCardDropdown from './CommentCardDropdown'; interface CommentContentBodyProps { @@ -17,9 +19,16 @@ interface CommentContentBodyProps { const CommentContentBody: FC = ({ comment, setInEditMode }) => { const { user } = useContext(UserContext); const timeDistance = useTimeDistance(new Date(comment.createdAt)); + const [ref, inView] = useInView({ triggerOnce: true }); return ( -
+
diff --git a/src/components/ui/CommentForm.tsx b/src/components/Comments/CommentForm.tsx similarity index 88% rename from src/components/ui/CommentForm.tsx rename to src/components/Comments/CommentForm.tsx index f091cd6..62102f0 100644 --- a/src/components/ui/CommentForm.tsx +++ b/src/components/Comments/CommentForm.tsx @@ -8,12 +8,12 @@ import type { UseFormSetValue, UseFormWatch, } from 'react-hook-form'; -import FormError from './forms/FormError'; -import FormInfo from './forms/FormInfo'; -import FormLabel from './forms/FormLabel'; -import FormSegment from './forms/FormSegment'; -import FormTextArea from './forms/FormTextArea'; -import Button from './forms/Button'; +import FormError from '../ui/forms/FormError'; +import FormInfo from '../ui/forms/FormInfo'; +import FormLabel from '../ui/forms/FormLabel'; +import FormSegment from '../ui/forms/FormSegment'; +import FormTextArea from '../ui/forms/FormTextArea'; +import Button from '../ui/forms/Button'; interface Comment { content: string; diff --git a/src/components/BeerBreweryComments/CommentLoadingCardBody.tsx b/src/components/Comments/CommentLoadingCardBody.tsx similarity index 91% rename from src/components/BeerBreweryComments/CommentLoadingCardBody.tsx rename to src/components/Comments/CommentLoadingCardBody.tsx index b662594..ca5800d 100644 --- a/src/components/BeerBreweryComments/CommentLoadingCardBody.tsx +++ b/src/components/Comments/CommentLoadingCardBody.tsx @@ -1,6 +1,6 @@ const CommentLoadingCardBody = () => { return ( -
+
diff --git a/src/components/BeerById/LoadingComponent.tsx b/src/components/Comments/CommentLoadingComponent.tsx similarity index 56% rename from src/components/BeerById/LoadingComponent.tsx rename to src/components/Comments/CommentLoadingComponent.tsx index fc2dca4..4d55920 100644 --- a/src/components/BeerById/LoadingComponent.tsx +++ b/src/components/Comments/CommentLoadingComponent.tsx @@ -1,12 +1,12 @@ import { FC } from 'react'; import Spinner from '../ui/Spinner'; -import CommentLoadingCardBody from '../BeerBreweryComments/CommentLoadingCardBody'; +import CommentLoadingCardBody from './CommentLoadingCardBody'; -interface LoadingComponentProps { +interface CommentLoadingComponentProps { length: number; } -const LoadingComponent: FC = ({ length }) => { +const CommentLoadingComponent: FC = ({ length }) => { return ( <> {Array.from({ length }).map((_, i) => ( @@ -19,4 +19,4 @@ const LoadingComponent: FC = ({ length }) => { ); }; -export default LoadingComponent; +export default CommentLoadingComponent; diff --git a/src/components/ui/CommentsComponent.tsx b/src/components/Comments/CommentsComponent.tsx similarity index 70% rename from src/components/ui/CommentsComponent.tsx rename to src/components/Comments/CommentsComponent.tsx index 20253aa..18a0d4d 100644 --- a/src/components/ui/CommentsComponent.tsx +++ b/src/components/Comments/CommentsComponent.tsx @@ -6,53 +6,46 @@ import { useInView } from 'react-intersection-observer'; import useBeerPostComments from '@/hooks/data-fetching/beer-comments/useBeerPostComments'; import useBreweryPostComments from '@/hooks/data-fetching/brewery-comments/useBreweryPostComments'; -import NoCommentsCard from '../BeerById/NoCommentsCard'; -import LoadingComponent from '../BeerById/LoadingComponent'; -import CommentCardBody from '../BeerBreweryComments/CommentCardBody'; +import useBeerStyleComments from '@/hooks/data-fetching/beer-style-comments/useBeerStyleComments'; +import NoCommentsCard from './NoCommentsCard'; +import CommentLoadingComponent from './CommentLoadingComponent'; +import CommentCardBody from './CommentCardBody'; +import { HandleDeleteCommentRequest, HandleEditCommentRequest } from './types'; + +type HookReturnType = ReturnType< + typeof useBeerPostComments | typeof useBreweryPostComments | typeof useBeerStyleComments +>; interface CommentsComponentProps { + comments: HookReturnType['comments']; + isAtEnd: HookReturnType['isAtEnd']; + isLoadingMore: HookReturnType['isLoadingMore']; + mutate: HookReturnType['mutate']; + setSize: HookReturnType['setSize']; + size: HookReturnType['size']; commentSectionRef: MutableRefObject; + handleDeleteCommentRequest: HandleDeleteCommentRequest; + handleEditCommentRequest: HandleEditCommentRequest; pageSize: number; - size: ReturnType['size']; - setSize: ReturnType< - typeof useBeerPostComments | typeof useBreweryPostComments - >['setSize']; - comments: ReturnType< - typeof useBeerPostComments | typeof useBreweryPostComments - >['comments']; - isAtEnd: ReturnType< - typeof useBeerPostComments | typeof useBreweryPostComments - >['isAtEnd']; - isLoadingMore: ReturnType< - typeof useBeerPostComments | typeof useBreweryPostComments - >['isLoadingMore']; - mutate: ReturnType< - typeof useBeerPostComments | typeof useBreweryPostComments - >['mutate']; - handleDeleteRequest: (id: string) => Promise; - handleEditRequest: ( - id: string, - data: { content: string; rating: number }, - ) => Promise; } const CommentsComponent: FC = ({ - commentSectionRef, comments, + commentSectionRef, + handleDeleteCommentRequest, + handleEditCommentRequest, isAtEnd, isLoadingMore, + mutate, pageSize, setSize, size, - mutate, - handleDeleteRequest, - handleEditRequest, }) => { const { ref: penultimateCommentRef } = useInView({ threshold: 0.1, /** - * When the last comment comes into view, call setSize from useBeerPostComments to - * load more comments. + * When the last comment comes into view, call setSize from the comment fetching hook + * to load more comments. */ onChange: (visible) => { if (!visible || isAtEnd) return; @@ -79,8 +72,8 @@ const CommentsComponent: FC = ({
); @@ -91,7 +84,7 @@ const CommentsComponent: FC = ({ * If there are more comments to load, show a loading component with a * skeleton loader and a loading spinner. */ - !!isLoadingMore && + !!isLoadingMore && } { diff --git a/src/components/BeerBreweryComments/EditCommentBody.tsx b/src/components/Comments/EditCommentBody.tsx similarity index 82% rename from src/components/BeerBreweryComments/EditCommentBody.tsx rename to src/components/Comments/EditCommentBody.tsx index e638baf..6c278dd 100644 --- a/src/components/BeerBreweryComments/EditCommentBody.tsx +++ b/src/components/Comments/EditCommentBody.tsx @@ -14,6 +14,9 @@ import FormInfo from '../ui/forms/FormInfo'; import FormLabel from '../ui/forms/FormLabel'; import FormSegment from '../ui/forms/FormSegment'; import FormTextArea from '../ui/forms/FormTextArea'; +import { HandleDeleteCommentRequest, HandleEditCommentRequest } from './types'; +import { useInView } from 'react-intersection-observer'; +import classNames from 'classnames'; interface EditCommentBodyProps { comment: z.infer; @@ -22,19 +25,16 @@ interface EditCommentBodyProps { mutate: ReturnType< typeof useBeerPostComments | typeof useBreweryPostComments >['mutate']; - handleDeleteRequest: (id: string) => Promise; - handleEditRequest: ( - id: string, - data: z.infer, - ) => Promise; + handleDeleteCommentRequest: HandleDeleteCommentRequest; + handleEditCommentRequest: HandleEditCommentRequest; } const EditCommentBody: FC = ({ comment, setInEditMode, mutate, - handleDeleteRequest, - handleEditRequest, + handleDeleteCommentRequest, + handleEditCommentRequest, }) => { const { register, handleSubmit, formState, setValue, watch } = useForm< z.infer @@ -51,7 +51,7 @@ const EditCommentBody: FC = ({ const loadingToast = toast.loading('Deleting comment...'); setIsDeleting(true); try { - await handleDeleteRequest(comment.id); + await handleDeleteCommentRequest(comment.id); await mutate(); toast.remove(loadingToast); toast.success('Deleted comment.'); @@ -68,7 +68,7 @@ const EditCommentBody: FC = ({ try { setInEditMode(true); - await handleEditRequest(comment.id, data); + await handleEditCommentRequest(comment.id, data); await mutate(); toast.remove(loadingToast); toast.success('Comment edits submitted successfully.'); @@ -80,8 +80,18 @@ const EditCommentBody: FC = ({ } }; + const disableForm = isSubmitting || isDeleting; + + const [ref, inView] = useInView({ triggerOnce: true }); + return ( -
+
@@ -95,7 +105,7 @@ const EditCommentBody: FC = ({ placeholder="Comment" rows={2} error={!!errors.content?.message} - disabled={isSubmitting || isDeleting} + disabled={disableForm} />
@@ -114,8 +124,8 @@ const EditCommentBody: FC = ({ ))} @@ -125,7 +135,7 @@ const EditCommentBody: FC = ({ diff --git a/src/components/BeerById/NoCommentsCard.tsx b/src/components/Comments/NoCommentsCard.tsx similarity index 100% rename from src/components/BeerById/NoCommentsCard.tsx rename to src/components/Comments/NoCommentsCard.tsx diff --git a/src/components/Comments/types/index.ts b/src/components/Comments/types/index.ts new file mode 100644 index 0000000..597d37d --- /dev/null +++ b/src/components/Comments/types/index.ts @@ -0,0 +1,12 @@ +import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +type APIResponse = z.infer; + +export type HandleEditCommentRequest = ( + id: string, + data: z.infer, +) => Promise; + +export type HandleDeleteCommentRequest = (id: string) => Promise; diff --git a/src/components/CreateBeerPostForm.tsx b/src/components/CreateBeerPostForm.tsx index fdba62f..3b21043 100644 --- a/src/components/CreateBeerPostForm.tsx +++ b/src/components/CreateBeerPostForm.tsx @@ -1,18 +1,20 @@ +import { FunctionComponent } from 'react'; +import router from 'next/router'; import { zodResolver } from '@hookform/resolvers/zod'; import { BeerStyle } from '@prisma/client'; -import router from 'next/router'; -import { FunctionComponent } from 'react'; +import toast from 'react-hot-toast'; import { useForm, SubmitHandler, FieldError } from 'react-hook-form'; import { z } from 'zod'; + import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; import CreateBeerPostValidationSchema from '@/services/posts/beer-post/schema/CreateBeerPostValidationSchema'; -import sendCreateBeerPostRequest from '@/requests/BeerPost/sendCreateBeerPostRequest'; import UploadImageValidationSchema from '@/services/schema/ImageSchema/UploadImageValidationSchema'; -import sendUploadBeerImagesRequest from '@/requests/BeerImage/sendUploadBeerImageRequest'; - -import toast from 'react-hot-toast'; import createErrorToast from '@/util/createErrorToast'; + +import { sendCreateBeerPostRequest } from '@/requests/posts/beer-post'; +import sendUploadBeerImagesRequest from '@/requests/images/beer-image/sendUploadBeerImageRequest'; + import Button from './ui/forms/Button'; import FormError from './ui/forms/FormError'; import FormInfo from './ui/forms/FormInfo'; @@ -53,7 +55,16 @@ const CreateBeerPostForm: FunctionComponent = ({ try { const loadingToast = toast.loading('Creating beer post...'); - const beerPost = await sendCreateBeerPostRequest(data); + const beerPost = await sendCreateBeerPostRequest({ + body: { + name: data.name, + description: data.description, + abv: data.abv, + ibu: data.ibu, + }, + breweryId: data.breweryId, + styleId: data.styleId, + }); await sendUploadBeerImagesRequest({ beerPost, images: data.images }); await router.push(`/beers/${beerPost.id}`); toast.dismiss(loadingToast); diff --git a/src/components/EditBeerPostForm.tsx b/src/components/EditBeerPostForm.tsx index 63727a8..c735de3 100644 --- a/src/components/EditBeerPostForm.tsx +++ b/src/components/EditBeerPostForm.tsx @@ -6,10 +6,13 @@ import { z } from 'zod'; import { useForm, SubmitHandler } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; -import deleteBeerPostRequest from '@/requests/BeerPost/deleteBeerPostRequest'; import EditBeerPostValidationSchema from '@/services/posts/beer-post/schema/EditBeerPostValidationSchema'; -import sendEditBeerPostRequest from '@/requests/BeerPost/sendEditBeerPostRequest'; + import createErrorToast from '@/util/createErrorToast'; +import { + sendEditBeerPostRequest, + sendDeleteBeerPostRequest, +} from '@/requests/posts/beer-post'; import Button from './ui/forms/Button'; import FormError from './ui/forms/FormError'; import FormInfo from './ui/forms/FormInfo'; @@ -35,7 +38,15 @@ const EditBeerPostForm: FC = ({ previousValues }) => { const onSubmit: SubmitHandler = async (data) => { try { const loadingToast = toast.loading('Editing beer post...'); - await sendEditBeerPostRequest(data); + await sendEditBeerPostRequest({ + beerPostId: data.id, + body: { + name: data.name, + abv: data.abv, + ibu: data.ibu, + description: data.description, + }, + }); await router.push(`/beers/${data.id}`); toast.success('Edited beer post.'); toast.dismiss(loadingToast); @@ -48,7 +59,7 @@ const EditBeerPostForm: FC = ({ previousValues }) => { const onDelete = async () => { try { const loadingToast = toast.loading('Deleting beer post...'); - await deleteBeerPostRequest(previousValues.id); + await sendDeleteBeerPostRequest({ beerPostId: previousValues.id }); toast.dismiss(loadingToast); await router.push('/beers'); toast.success('Deleted beer post.'); diff --git a/src/components/EditBreweryPostForm.tsx b/src/components/EditBreweryPostForm.tsx new file mode 100644 index 0000000..4837be9 --- /dev/null +++ b/src/components/EditBreweryPostForm.tsx @@ -0,0 +1,106 @@ +import EditBreweryPostValidationSchema from '@/services/posts/brewery-post/schema/EditBreweryPostValidationSchema'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { useRouter } from 'next/router'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { FC, useState } from 'react'; +import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; +import { + sendDeleteBreweryPostRequest, + sendEditBreweryPostRequest, +} from '@/requests/posts/brewery-post'; +import FormError from './ui/forms/FormError'; +import FormInfo from './ui/forms/FormInfo'; +import FormLabel from './ui/forms/FormLabel'; +import FormSegment from './ui/forms/FormSegment'; +import FormTextArea from './ui/forms/FormTextArea'; +import FormTextInput from './ui/forms/FormTextInput'; + +interface EditBreweryPostFormProps { + breweryPost: z.infer; +} +const EditBreweryPostForm: FC = ({ breweryPost }) => { + const router = useRouter(); + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm>({ + resolver: zodResolver(EditBreweryPostValidationSchema), + defaultValues: { + name: breweryPost.name, + description: breweryPost.description, + id: breweryPost.id, + dateEstablished: breweryPost.dateEstablished, + }, + }); + + const [isDeleting, setIsDeleting] = useState(false); + + const onSubmit = async (data: z.infer) => { + await sendEditBreweryPostRequest({ breweryPostId: breweryPost.id, body: data }); + await router.push(`/breweries/${breweryPost.id}`); + }; + + const handleDelete = async () => { + setIsDeleting(true); + await sendDeleteBreweryPostRequest({ breweryPostId: breweryPost.id }); + await router.push('/breweries'); + }; + + return ( + +
+ + Name + {errors.name?.message} + + + + + + + Description + {errors.description?.message} + + + + +
+ +
+ + +
+ + ); +}; + +export default EditBreweryPostForm; diff --git a/src/components/Login/LoginForm.tsx b/src/components/Login/LoginForm.tsx index 1c7fec9..282cea0 100644 --- a/src/components/Login/LoginForm.tsx +++ b/src/components/Login/LoginForm.tsx @@ -1,4 +1,3 @@ -import sendLoginUserRequest from '@/requests/User/sendLoginUserRequest'; import LoginValidationSchema from '@/services/users/auth/schema/LoginValidationSchema'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/router'; @@ -15,6 +14,7 @@ import FormLabel from '../ui/forms/FormLabel'; import FormSegment from '../ui/forms/FormSegment'; import FormTextInput from '../ui/forms/FormTextInput'; import Button from '../ui/forms/Button'; +import { sendLoginUserRequest } from '@/requests/users/auth'; type LoginT = z.infer; const LoginForm = () => { @@ -47,7 +47,7 @@ const LoginForm = () => { }; return ( -
+
username diff --git a/src/components/RegisterUserForm.tsx b/src/components/RegisterUserForm.tsx index 588338e..835f677 100644 --- a/src/components/RegisterUserForm.tsx +++ b/src/components/RegisterUserForm.tsx @@ -1,4 +1,3 @@ -import sendRegisterUserRequest from '@/requests/User/sendRegisterUserRequest'; import { CreateUserValidationSchemaWithUsernameAndEmailCheck } from '@/services/users/auth/schema/CreateUserValidationSchemas'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/router'; @@ -9,6 +8,7 @@ import { z } from 'zod'; import createErrorToast from '@/util/createErrorToast'; import toast from 'react-hot-toast'; +import { sendRegisterUserRequest } from '@/requests/users/auth'; import Button from './ui/forms/Button'; import FormError from './ui/forms/FormError'; import FormInfo from './ui/forms/FormInfo'; @@ -44,13 +44,9 @@ const RegisterUserForm: FC = () => { } }; return ( - -
-
+ +
+
First name @@ -63,7 +59,7 @@ const RegisterUserForm: FC = () => { type="text" formValidationSchema={register('firstName')} error={!!errors.firstName} - placeholder="first name" + placeholder="John" />
@@ -80,13 +76,13 @@ const RegisterUserForm: FC = () => { type="text" formValidationSchema={register('lastName')} error={!!errors.lastName} - placeholder="last name" + placeholder="Doe" />
-
+
email @@ -99,7 +95,7 @@ const RegisterUserForm: FC = () => { type="email" formValidationSchema={register('email')} error={!!errors.email} - placeholder="email" + placeholder="john.doe@example.com" />
@@ -115,13 +111,13 @@ const RegisterUserForm: FC = () => { type="text" formValidationSchema={register('username')} error={!!errors.username} - placeholder="username" + placeholder="johndoe" />
-
+
password @@ -155,26 +151,28 @@ const RegisterUserForm: FC = () => {
- - Date of birth - {errors.dateOfBirth?.message} - - - - -
- +
+ + Date of birth + {errors.dateOfBirth?.message} + + + +
+
+ +
); }; diff --git a/src/components/UserPage/UserFollowButton.tsx b/src/components/UserPage/UserFollowButton.tsx index 1f1dc58..f2eb28e 100644 --- a/src/components/UserPage/UserFollowButton.tsx +++ b/src/components/UserPage/UserFollowButton.tsx @@ -1,7 +1,8 @@ import useFollowStatus from '@/hooks/data-fetching/user-follows/useFollowStatus'; import useGetUsersFollowedByUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowedByUser'; import useGetUsersFollowingUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowingUser'; -import sendUserFollowRequest from '@/requests/UserFollow/sendUserFollowRequest'; +import { sendUserFollowRequest } from '@/requests/users/auth'; + import GetUserSchema from '@/services/users/auth/schema/GetUserSchema'; import { FC, useState } from 'react'; import { FaUserCheck, FaUserPlus } from 'react-icons/fa'; @@ -25,7 +26,7 @@ const UserFollowButton: FC = ({ const onClick = async () => { try { setIsLoading(true); - await sendUserFollowRequest(user.id); + await sendUserFollowRequest({ userId: user.id }); await Promise.all([ mutateFollowStatus(), mutateFollowerCount(), diff --git a/src/components/ui/Layout.tsx b/src/components/ui/Layout.tsx index 8358a7e..6e1a8b6 100644 --- a/src/components/ui/Layout.tsx +++ b/src/components/ui/Layout.tsx @@ -3,13 +3,10 @@ import Navbar from './Navbar'; const Layout: FC<{ children: ReactNode }> = ({ children }) => { return ( -
+
-
- {children} -
+ {children}
); }; - export default Layout; diff --git a/src/components/ui/Navbar.tsx b/src/components/ui/Navbar.tsx index 675a8ca..f1287fd 100644 --- a/src/components/ui/Navbar.tsx +++ b/src/components/ui/Navbar.tsx @@ -1,11 +1,13 @@ import useMediaQuery from '@/hooks/utilities/useMediaQuery'; import useNavbar from '@/hooks/utilities/useNavbar'; -import useTheme from '@/hooks/utilities/useTheme'; +// import useTheme from '@/hooks/utilities/useTheme'; import Link from 'next/link'; -import { FC } from 'react'; -import { MdDarkMode, MdLightMode } from 'react-icons/md'; -import { GiHamburgerMenu } from 'react-icons/gi'; +import { FC, useRef } from 'react'; +// import { MdDarkMode, MdLightMode } from 'react-icons/md'; + +import { FaBars } from 'react-icons/fa'; +import classNames from 'classnames'; const DesktopLinks: FC = () => { const { pages, currentURL } = useNavbar(); @@ -19,8 +21,8 @@ const DesktopLinks: FC = () => { {page.name} @@ -35,24 +37,44 @@ const DesktopLinks: FC = () => { const MobileLinks: FC = () => { const { pages } = useNavbar(); + + const drawerRef = useRef(null); return (
-
- -
    - {pages.map((page) => ( -
  • - - {page.name} - -
  • - ))} -
+
+ +
+ +
+
+
); @@ -61,17 +83,30 @@ const MobileLinks: FC = () => { const Navbar = () => { const isDesktopView = useMediaQuery('(min-width: 1024px)'); - const { theme, setTheme } = useTheme(); + const { currentURL } = useNavbar(); + const backgroundIsTransparent = + currentURL === '/' || currentURL === '/login' || currentURL === '/register'; + + const isOnHomePage = currentURL === '/'; + + // const { theme, setTheme } = useTheme(); return ( -
+
- - The Biergarten App - + {isOnHomePage ? null : ( + + The Biergarten App + + )}
-
@@ -96,7 +131,7 @@ const Navbar = () => { )}
-
+
*/}
{isDesktopView ? : }
); diff --git a/src/controllers/comments/beer-comments/index.ts b/src/controllers/comments/beer-comments/index.ts index 7ca8dbc..b56cd62 100644 --- a/src/controllers/comments/beer-comments/index.ts +++ b/src/controllers/comments/beer-comments/index.ts @@ -24,9 +24,9 @@ export const checkIfBeerCommentOwner = async ( res: NextApiResponse>, next: NextHandler, ) => { - const { id } = req.query; + const { commentId } = req.query; const user = req.user!; - const comment = await getBeerPostCommentByIdService({ beerPostCommentId: id }); + const comment = await getBeerPostCommentByIdService({ beerPostCommentId: commentId }); if (!comment) { throw new ServerError('Comment not found', 404); @@ -43,9 +43,9 @@ export const editBeerPostComment = async ( req: EditAndCreateCommentRequest, res: NextApiResponse>, ) => { - const { id } = req.query; + const { commentId } = req.query; - await editBeerPostCommentByIdService({ body: req.body, beerPostCommentId: id }); + await editBeerPostCommentByIdService({ body: req.body, beerPostCommentId: commentId }); res.status(200).json({ success: true, @@ -58,9 +58,9 @@ export const deleteBeerPostComment = async ( req: CommentRequest, res: NextApiResponse>, ) => { - const { id } = req.query; + const { commentId } = req.query; - await deleteBeerCommentByIdService({ beerPostCommentId: id }); + await deleteBeerCommentByIdService({ beerPostCommentId: commentId }); res.status(200).json({ success: true, @@ -73,7 +73,7 @@ export const createBeerPostComment = async ( req: EditAndCreateCommentRequest, res: NextApiResponse>, ) => { - const beerPostId = req.query.id; + const beerPostId = req.query.postId; const newBeerComment = await createBeerPostCommentService({ body: req.body, @@ -93,7 +93,7 @@ export const getAllBeerPostComments = async ( req: GetAllCommentsRequest, res: NextApiResponse>, ) => { - const beerPostId = req.query.id; + const beerPostId = req.query.postId; // eslint-disable-next-line @typescript-eslint/naming-convention const { page_size, page_num } = req.query; diff --git a/src/controllers/comments/beer-style-comments/index.ts b/src/controllers/comments/beer-style-comments/index.ts index 9365c0c..7179fc3 100644 --- a/src/controllers/comments/beer-style-comments/index.ts +++ b/src/controllers/comments/beer-style-comments/index.ts @@ -25,10 +25,12 @@ export const checkIfBeerStyleCommentOwner = async < res: NextApiResponse>, next: NextHandler, ) => { - const { id } = req.query; + const { commentId } = req.query; const user = req.user!; - const beerStyleComment = await findBeerStyleCommentById({ beerStyleCommentId: id }); + const beerStyleComment = await findBeerStyleCommentById({ + beerStyleCommentId: commentId, + }); if (!beerStyleComment) { throw new ServerError('Beer style comment not found.', 404); @@ -49,7 +51,7 @@ export const editBeerStyleComment = async ( res: NextApiResponse>, ) => { await updateBeerStyleCommentById({ - beerStyleCommentId: req.query.id, + beerStyleCommentId: req.query.commentId, body: req.body, }); @@ -64,9 +66,9 @@ export const deleteBeerStyleComment = async ( req: CommentRequest, res: NextApiResponse>, ) => { - const { id } = req.query; + const { commentId } = req.query; - await deleteBeerStyleCommentById({ beerStyleCommentId: id }); + await deleteBeerStyleCommentById({ beerStyleCommentId: commentId }); res.status(200).json({ success: true, @@ -81,7 +83,7 @@ export const createComment = async ( ) => { const newBeerStyleComment = await createNewBeerStyleComment({ body: req.body, - beerStyleId: req.query.id, + beerStyleId: req.query.postId, userId: req.user!.id, }); @@ -97,7 +99,7 @@ export const getAll = async ( req: GetAllCommentsRequest, res: NextApiResponse>, ) => { - const beerStyleId = req.query.id; + const beerStyleId = req.query.postId; // eslint-disable-next-line @typescript-eslint/naming-convention const { page_size, page_num } = req.query; diff --git a/src/controllers/comments/brewery-comments/index.ts b/src/controllers/comments/brewery-comments/index.ts index 103dca9..cfe0b27 100644 --- a/src/controllers/comments/brewery-comments/index.ts +++ b/src/controllers/comments/brewery-comments/index.ts @@ -25,9 +25,9 @@ export const checkIfBreweryCommentOwner = async < res: NextApiResponse>, next: NextHandler, ) => { - const { id } = req.query; + const { commentId } = req.query; const user = req.user!; - const comment = await getBreweryCommentById({ breweryCommentId: id }); + const comment = await getBreweryCommentById({ breweryCommentId: commentId }); if (!comment) { throw new ServerError('Comment not found', 404); @@ -44,10 +44,10 @@ export const editBreweryPostComment = async ( req: EditAndCreateCommentRequest, res: NextApiResponse>, ) => { - const { id } = req.query; + const { commentId } = req.query; - const updated = updateBreweryCommentById({ - breweryCommentId: id, + const updated = await updateBreweryCommentById({ + breweryCommentId: commentId, body: req.body, }); @@ -63,9 +63,9 @@ export const deleteBreweryPostComment = async ( req: CommentRequest, res: NextApiResponse>, ) => { - const { id } = req.query; + const { commentId } = req.query; - await deleteBreweryCommentByIdService({ breweryCommentId: id }); + await deleteBreweryCommentByIdService({ breweryCommentId: commentId }); res.status(200).json({ success: true, @@ -78,7 +78,7 @@ export const createComment = async ( req: EditAndCreateCommentRequest, res: NextApiResponse>, ) => { - const breweryPostId = req.query.id; + const breweryPostId = req.query.postId; const user = req.user!; @@ -100,7 +100,7 @@ export const getAll = async ( req: GetAllCommentsRequest, res: NextApiResponse>, ) => { - const breweryPostId = req.query.id; + const breweryPostId = req.query.postId; // eslint-disable-next-line @typescript-eslint/naming-convention const { page_size, page_num } = req.query; diff --git a/src/controllers/comments/types/index.ts b/src/controllers/comments/types/index.ts index f56f153..9968ba2 100644 --- a/src/controllers/comments/types/index.ts +++ b/src/controllers/comments/types/index.ts @@ -3,7 +3,7 @@ import CreateCommentValidationSchema from '@/services/schema/CommentSchema/Creat import { z } from 'zod'; export interface CommentRequest extends UserExtendedNextApiRequest { - query: { id: string }; + query: { postId: string; commentId: string }; } export interface EditAndCreateCommentRequest extends CommentRequest { @@ -11,5 +11,5 @@ export interface EditAndCreateCommentRequest extends CommentRequest { } export interface GetAllCommentsRequest extends UserExtendedNextApiRequest { - query: { id: string; page_size: string; page_num: string }; + query: { postId: string; page_size: string; page_num: string }; } diff --git a/src/controllers/images/beer-images/index.ts b/src/controllers/images/beer-images/index.ts index 0a1d5c1..bc6a003 100644 --- a/src/controllers/images/beer-images/index.ts +++ b/src/controllers/images/beer-images/index.ts @@ -20,7 +20,7 @@ export const processBeerImageData = async ( } const beerImages = await addBeerImagesService({ - beerPostId: req.query.id, + beerPostId: req.query.postId, userId: user!.id, body, files, diff --git a/src/controllers/images/brewery-images/index.ts b/src/controllers/images/brewery-images/index.ts index a7a4a3c..24453d6 100644 --- a/src/controllers/images/brewery-images/index.ts +++ b/src/controllers/images/brewery-images/index.ts @@ -18,7 +18,7 @@ export const processBreweryImageData = async ( } const breweryImages = await addBreweryImagesService({ - breweryPostId: req.query.id, + breweryPostId: req.query.postId, userId: user!.id, body, files, diff --git a/src/controllers/images/types/index.ts b/src/controllers/images/types/index.ts index 8d4b308..d79a389 100644 --- a/src/controllers/images/types/index.ts +++ b/src/controllers/images/types/index.ts @@ -4,7 +4,7 @@ import { z } from 'zod'; export interface UploadImagesRequest extends UserExtendedNextApiRequest { files?: Express.Multer.File[]; - query: { id: string }; + query: { postId: string }; body: z.infer; } diff --git a/src/controllers/likes/beer-posts-likes/index.ts b/src/controllers/likes/beer-posts-likes/index.ts index 0211164..2215978 100644 --- a/src/controllers/likes/beer-posts-likes/index.ts +++ b/src/controllers/likes/beer-posts-likes/index.ts @@ -2,7 +2,7 @@ import { UserExtendedNextApiRequest } from '@/config/auth/types'; import ServerError from '@/config/util/ServerError'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { NextApiResponse, NextApiRequest } from 'next'; +import { NextApiResponse } from 'next'; import { z } from 'zod'; import { getBeerPostById } from '@/services/posts/beer-post'; @@ -19,9 +19,9 @@ export const sendBeerPostLikeRequest = async ( res: NextApiResponse>, ) => { const user = req.user!; - const id = req.query.id as string; + const { postId } = req.query; - const beer = await getBeerPostById({ beerPostId: id }); + const beer = await getBeerPostById({ beerPostId: postId }); if (!beer) { throw new ServerError('Could not find a beer post with that id.', 404); } @@ -53,12 +53,12 @@ export const sendBeerPostLikeRequest = async ( }; export const getBeerPostLikeCount = async ( - req: NextApiRequest, + req: LikeRequest, res: NextApiResponse>, ) => { - const id = req.query.id as string; + const { postId } = req.query; - const likeCount = await getBeerPostLikeCountService({ beerPostId: id }); + const likeCount = await getBeerPostLikeCountService({ beerPostId: postId }); res.status(200).json({ success: true, diff --git a/src/controllers/likes/beer-style-likes/index.ts b/src/controllers/likes/beer-style-likes/index.ts index fd2499d..85a8403 100644 --- a/src/controllers/likes/beer-style-likes/index.ts +++ b/src/controllers/likes/beer-style-likes/index.ts @@ -1,7 +1,7 @@ import ServerError from '@/config/util/ServerError'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { NextApiResponse, NextApiRequest } from 'next'; +import { NextApiResponse } from 'next'; import { z } from 'zod'; import { UserExtendedNextApiRequest } from '@/config/auth/types'; import { @@ -18,9 +18,9 @@ export const sendBeerStyleLikeRequest = async ( res: NextApiResponse>, ) => { const user = req.user!; - const { id } = req.query; + const { postId } = req.query; - const beerStyle = await getBeerStyleByIdService({ beerStyleId: id }); + const beerStyle = await getBeerStyleByIdService({ beerStyleId: postId }); if (!beerStyle) { throw new ServerError('Could not find a beer style with that id.', 404); } @@ -48,11 +48,11 @@ export const sendBeerStyleLikeRequest = async ( }; export const getBeerStyleLikeCountRequest = async ( - req: NextApiRequest, + req: LikeRequest, res: NextApiResponse>, ) => { - const id = req.query.id as string; - const likeCount = await getBeerStyleLikeCountService({ beerStyleId: id }); + const { postId } = req.query; + const likeCount = await getBeerStyleLikeCountService({ beerStyleId: postId }); res.status(200).json({ success: true, diff --git a/src/controllers/likes/brewery-post-likes/index.ts b/src/controllers/likes/brewery-post-likes/index.ts index 6eeb790..af4374f 100644 --- a/src/controllers/likes/brewery-post-likes/index.ts +++ b/src/controllers/likes/brewery-post-likes/index.ts @@ -1,4 +1,3 @@ -import { UserExtendedNextApiRequest } from '@/config/auth/types'; import ServerError from '@/config/util/ServerError'; import { @@ -9,17 +8,18 @@ import { } from '@/services/likes/brewery-post-like'; import { getBreweryPostByIdService } from '@/services/posts/brewery-post'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { NextApiResponse, NextApiRequest } from 'next'; +import { NextApiResponse } from 'next'; import { z } from 'zod'; +import { LikeRequest } from '../types'; export const sendBreweryPostLikeRequest = async ( - req: UserExtendedNextApiRequest, + req: LikeRequest, res: NextApiResponse>, ) => { - const id = req.query.id! as string; + const { postId } = req.query; const user = req.user!; - const breweryPost = await getBreweryPostByIdService({ breweryPostId: id }); + const breweryPost = await getBreweryPostByIdService({ breweryPostId: postId }); if (!breweryPost) { throw new ServerError('Could not find a brewery post with that id', 404); @@ -53,12 +53,12 @@ export const sendBreweryPostLikeRequest = async ( }; export const getBreweryPostLikeCount = async ( - req: NextApiRequest, + req: LikeRequest, res: NextApiResponse>, ) => { - const id = req.query.id! as string; + const { postId } = req.query; - const breweryPost = await getBreweryPostByIdService({ breweryPostId: id }); + const breweryPost = await getBreweryPostByIdService({ breweryPostId: postId }); if (!breweryPost) { throw new ServerError('Could not find a brewery post with that id', 404); } @@ -76,14 +76,14 @@ export const getBreweryPostLikeCount = async ( }; export const getBreweryPostLikeStatus = async ( - req: UserExtendedNextApiRequest, + req: LikeRequest, res: NextApiResponse>, ) => { const user = req.user!; - const id = req.query.id as string; + const { postId } = req.query; const liked = await findBreweryPostLikeService({ - breweryPostId: id, + breweryPostId: postId, likedById: user.id, }); diff --git a/src/controllers/likes/types/index.ts b/src/controllers/likes/types/index.ts index 424a4e4..8efc87b 100644 --- a/src/controllers/likes/types/index.ts +++ b/src/controllers/likes/types/index.ts @@ -1,5 +1,5 @@ import { UserExtendedNextApiRequest } from '@/config/auth/types'; export interface LikeRequest extends UserExtendedNextApiRequest { - query: { id: string }; + query: { postId: string }; } diff --git a/src/controllers/posts/beer-posts/index.ts b/src/controllers/posts/beer-posts/index.ts index 76cacf7..0e8bda5 100644 --- a/src/controllers/posts/beer-posts/index.ts +++ b/src/controllers/posts/beer-posts/index.ts @@ -28,9 +28,9 @@ export const checkIfBeerPostOwner = async { const { user, query } = req; - const { id } = query; + const { postId } = query; - const beerPost = await getBeerPostById({ beerPostId: id }); + const beerPost = await getBeerPostById({ beerPostId: postId }); if (!beerPost) { throw new ServerError('Beer post not found', 404); @@ -47,7 +47,7 @@ export const editBeerPost = async ( req: EditBeerPostRequest, res: NextApiResponse>, ) => { - await editBeerPostByIdService({ beerPostId: req.query.id, body: req.body }); + await editBeerPostByIdService({ beerPostId: req.query.postId, body: req.body }); res.status(200).json({ message: 'Beer post updated successfully', @@ -57,9 +57,9 @@ export const editBeerPost = async ( }; export const deleteBeerPost = async (req: BeerPostRequest, res: NextApiResponse) => { - const { id } = req.query; + const { postId } = req.query; - const deleted = await deleteBeerPostByIdService({ beerPostId: id }); + const deleted = await deleteBeerPostByIdService({ beerPostId: postId }); if (!deleted) { throw new ServerError('Beer post not found', 404); } @@ -75,9 +75,9 @@ export const getBeerPostRecommendations = async ( req: GetBeerRecommendationsRequest, res: NextApiResponse>, ) => { - const { id } = req.query; + const { postId } = req.query; - const beerPost = await getBeerPostById({ beerPostId: id }); + const beerPost = await getBeerPostById({ beerPostId: postId }); if (!beerPost) { throw new ServerError('Beer post not found', 404); diff --git a/src/controllers/posts/beer-posts/types/index.ts b/src/controllers/posts/beer-posts/types/index.ts index a1b5977..d4bed49 100644 --- a/src/controllers/posts/beer-posts/types/index.ts +++ b/src/controllers/posts/beer-posts/types/index.ts @@ -5,7 +5,7 @@ import { NextApiRequest } from 'next'; import { z } from 'zod'; export interface BeerPostRequest extends UserExtendedNextApiRequest { - query: { id: string }; + query: { postId: string }; } export interface EditBeerPostRequest extends BeerPostRequest { @@ -17,7 +17,7 @@ export interface GetAllBeerPostsRequest extends NextApiRequest { } export interface GetBeerRecommendationsRequest extends BeerPostRequest { - query: { id: string; page_num: string; page_size: string }; + query: { postId: string; page_num: string; page_size: string }; } export interface CreateBeerPostRequest extends UserExtendedNextApiRequest { diff --git a/src/controllers/posts/breweries/index.ts b/src/controllers/posts/breweries/index.ts index 4e5cdfd..3f1001c 100644 --- a/src/controllers/posts/breweries/index.ts +++ b/src/controllers/posts/breweries/index.ts @@ -167,9 +167,9 @@ export const checkIfBreweryPostOwner = async ( next: NextHandler, ) => { const user = req.user!; - const { id } = req.query; + const { postId } = req.query; - const breweryPost = await getBreweryPostByIdService({ breweryPostId: id }); + const breweryPost = await getBreweryPostByIdService({ breweryPostId: postId }); if (!breweryPost) { throw new ServerError('Brewery post not found', 404); } @@ -187,10 +187,10 @@ export const editBreweryPost = async ( ) => { const { body, - query: { id }, + query: { postId }, } = req; - await updateBreweryPostService({ breweryPostId: id, body }); + await updateBreweryPostService({ breweryPostId: postId, body }); res.status(200).json({ message: 'Brewery post updated successfully', @@ -203,8 +203,8 @@ export const deleteBreweryPost = async ( req: BreweryPostRequest, res: NextApiResponse, ) => { - const { id } = req.query; - const deleted = await deleteBreweryPostService({ breweryPostId: id }); + const { postId } = req.query; + const deleted = await deleteBreweryPostService({ breweryPostId: postId }); if (!deleted) { throw new ServerError('Brewery post not found', 404); diff --git a/src/controllers/posts/breweries/types/index.ts b/src/controllers/posts/breweries/types/index.ts index 85dd30a..2524b36 100644 --- a/src/controllers/posts/breweries/types/index.ts +++ b/src/controllers/posts/breweries/types/index.ts @@ -14,7 +14,7 @@ export interface CreateBreweryPostRequest extends UserExtendedNextApiRequest { } export interface BreweryPostRequest extends UserExtendedNextApiRequest { - query: { id: string }; + query: { postId: string }; } export interface EditBreweryPostRequest extends BreweryPostRequest { diff --git a/src/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount.ts b/src/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount.ts index c2ba167..7391410 100644 --- a/src/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount.ts +++ b/src/hooks/data-fetching/brewery-likes/useGetBreweryPostLikeCount.ts @@ -41,7 +41,7 @@ const useGetBreweryPostLikeCount = (breweryPostId: string) => { error: error as unknown, isLoading, mutate, - likeCount: data as number | undefined, + likeCount: data, }; }; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index a83cc5c..4869202 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -8,7 +8,7 @@ const NotFound: NextPage = () => { 404 Page Not Found -
+

404: Not Found

Sorry, the page you are looking for does not exist. diff --git a/src/pages/api/beer-comments/[id].ts b/src/pages/api/beers/[postId]/comments/[commentId].ts similarity index 84% rename from src/pages/api/beer-comments/[id].ts rename to src/pages/api/beers/[postId]/comments/[commentId].ts index 8acf718..aa30b1d 100644 --- a/src/pages/api/beer-comments/[id].ts +++ b/src/pages/api/beers/[postId]/comments/[commentId].ts @@ -22,14 +22,16 @@ const router = createRouter< router .delete( - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ + querySchema: z.object({ postId: z.string().cuid(), commentId: z.string().cuid() }), + }), getCurrentUser, checkIfBeerCommentOwner, deleteBeerPostComment, ) .put( validateRequest({ - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ postId: z.string().cuid(), commentId: z.string().cuid() }), bodySchema: CreateCommentValidationSchema, }), getCurrentUser, diff --git a/src/pages/api/beers/[id]/comments/index.ts b/src/pages/api/beers/[postId]/comments/index.ts similarity index 81% rename from src/pages/api/beers/[id]/comments/index.ts rename to src/pages/api/beers/[postId]/comments/index.ts index f9bc088..17b0608 100644 --- a/src/pages/api/beers/[id]/comments/index.ts +++ b/src/pages/api/beers/[postId]/comments/index.ts @@ -11,6 +11,7 @@ import { createBeerPostComment, getAllBeerPostComments, } from '@/controllers/comments/beer-comments'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; const router = createRouter< // @TODO: Fix this any type @@ -21,7 +22,7 @@ const router = createRouter< router.post( validateRequest({ bodySchema: CreateCommentValidationSchema, - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ postId: z.string().cuid() }), }), getCurrentUser, createBeerPostComment, @@ -29,11 +30,7 @@ router.post( router.get( validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - page_size: z.coerce.number().int().positive(), - page_num: z.coerce.number().int().positive(), - }), + querySchema: PaginatedQueryResponseSchema.extend({ postId: z.string().cuid() }), }), getAllBeerPostComments, ); diff --git a/src/pages/api/beers/[id]/images/index.ts b/src/pages/api/beers/[postId]/images/index.ts similarity index 100% rename from src/pages/api/beers/[id]/images/index.ts rename to src/pages/api/beers/[postId]/images/index.ts diff --git a/src/pages/api/beers/[id]/index.ts b/src/pages/api/beers/[postId]/index.ts similarity index 90% rename from src/pages/api/beers/[id]/index.ts rename to src/pages/api/beers/[postId]/index.ts index 8a67ec7..f513eaf 100644 --- a/src/pages/api/beers/[id]/index.ts +++ b/src/pages/api/beers/[postId]/index.ts @@ -26,14 +26,14 @@ router .put( validateRequest({ bodySchema: EditBeerPostValidationSchema, - querySchema: z.object({ id: z.string() }), + querySchema: z.object({ postId: z.string() }), }), getCurrentUser, checkIfBeerPostOwner, editBeerPost, ) .delete( - validateRequest({ querySchema: z.object({ id: z.string() }) }), + validateRequest({ querySchema: z.object({ postId: z.string() }) }), getCurrentUser, checkIfBeerPostOwner, deleteBeerPost, diff --git a/src/pages/api/beers/[id]/like/index.ts b/src/pages/api/beers/[postId]/like/index.ts similarity index 85% rename from src/pages/api/beers/[id]/like/index.ts rename to src/pages/api/beers/[postId]/like/index.ts index a6e7eb8..ffbc659 100644 --- a/src/pages/api/beers/[id]/like/index.ts +++ b/src/pages/api/beers/[postId]/like/index.ts @@ -19,12 +19,12 @@ const router = createRouter< router.post( getCurrentUser, - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), sendBeerPostLikeRequest, ); router.get( - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), getBeerPostLikeCount, ); diff --git a/src/pages/api/beers/[id]/like/is-liked.ts b/src/pages/api/beers/[postId]/like/is-liked.ts similarity index 91% rename from src/pages/api/beers/[id]/like/is-liked.ts rename to src/pages/api/beers/[postId]/like/is-liked.ts index aa0f9a3..3146f48 100644 --- a/src/pages/api/beers/[id]/like/is-liked.ts +++ b/src/pages/api/beers/[postId]/like/is-liked.ts @@ -16,7 +16,7 @@ const router = createRouter< router.get( getCurrentUser, - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), checkIfBeerPostIsLiked, ); diff --git a/src/pages/api/beers/[id]/recommendations.ts b/src/pages/api/beers/[postId]/recommendations.ts similarity index 81% rename from src/pages/api/beers/[id]/recommendations.ts rename to src/pages/api/beers/[postId]/recommendations.ts index 15b5d36..65cf82a 100644 --- a/src/pages/api/beers/[id]/recommendations.ts +++ b/src/pages/api/beers/[postId]/recommendations.ts @@ -2,6 +2,7 @@ import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import { getBeerPostRecommendations } from '@/controllers/posts/beer-posts'; import { GetBeerRecommendationsRequest } from '@/controllers/posts/beer-posts/types'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; import { createRouter } from 'next-connect'; @@ -14,11 +15,7 @@ const router = createRouter< router.get( validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - page_num: z.string().regex(/^[0-9]+$/), - page_size: z.string().regex(/^[0-9]+$/), - }), + querySchema: PaginatedQueryResponseSchema.extend({ postId: z.string().cuid() }), }), getBeerPostRecommendations, ); diff --git a/src/pages/api/beers/styles/[id]/beers/index.ts b/src/pages/api/beers/styles/[postId]/beers/index.ts similarity index 82% rename from src/pages/api/beers/styles/[id]/beers/index.ts rename to src/pages/api/beers/styles/[postId]/beers/index.ts index 5d89585..46440b2 100644 --- a/src/pages/api/beers/styles/[id]/beers/index.ts +++ b/src/pages/api/beers/styles/[postId]/beers/index.ts @@ -1,6 +1,7 @@ import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import { getAllBeersByBeerStyle } from '@/controllers/posts/beer-styles'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiRequest, NextApiResponse } from 'next'; @@ -18,11 +19,7 @@ const router = createRouter< router.get( validateRequest({ - querySchema: z.object({ - page_size: z.string().min(1), - page_num: z.string().min(1), - id: z.string().min(1), - }), + querySchema: PaginatedQueryResponseSchema.extend({ postId: z.string().cuid() }), }), getAllBeersByBeerStyle, ); diff --git a/src/pages/api/beer-style-comments/[id].ts b/src/pages/api/beers/styles/[postId]/comments/[commentId].ts similarity index 87% rename from src/pages/api/beer-style-comments/[id].ts rename to src/pages/api/beers/styles/[postId]/comments/[commentId].ts index ec6dc8f..4d7f0b3 100644 --- a/src/pages/api/beer-style-comments/[id].ts +++ b/src/pages/api/beers/styles/[postId]/comments/[commentId].ts @@ -22,7 +22,7 @@ const router = createRouter< router .delete( validateRequest({ - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ postId: z.string().cuid(), commentId: z.string().cuid() }), }), getCurrentUser, checkIfBeerStyleCommentOwner, @@ -30,7 +30,7 @@ router ) .put( validateRequest({ - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ postId: z.string().cuid(), commentId: z.string().cuid() }), bodySchema: CreateCommentValidationSchema, }), getCurrentUser, diff --git a/src/pages/api/beers/styles/[id]/comments/index.ts b/src/pages/api/beers/styles/[postId]/comments/index.ts similarity index 81% rename from src/pages/api/beers/styles/[id]/comments/index.ts rename to src/pages/api/beers/styles/[postId]/comments/index.ts index 174d413..6345d20 100644 --- a/src/pages/api/beers/styles/[id]/comments/index.ts +++ b/src/pages/api/beers/styles/[postId]/comments/index.ts @@ -8,6 +8,7 @@ import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; import { NextApiResponse } from 'next'; import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import { createComment, getAll } from '@/controllers/comments/beer-style-comments'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; const router = createRouter< // I don't want to use any, but I can't figure out how to get the types to work @@ -18,7 +19,7 @@ const router = createRouter< router.post( validateRequest({ bodySchema: CreateCommentValidationSchema, - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ postId: z.string().cuid() }), }), getCurrentUser, createComment, @@ -26,11 +27,7 @@ router.post( router.get( validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - page_size: z.coerce.number().int().positive(), - page_num: z.coerce.number().int().positive(), - }), + querySchema: PaginatedQueryResponseSchema.extend({ postId: z.string().cuid() }), }), getAll, ); diff --git a/src/pages/api/beers/styles/[id]/index.ts b/src/pages/api/beers/styles/[postId]/index.ts similarity index 89% rename from src/pages/api/beers/styles/[id]/index.ts rename to src/pages/api/beers/styles/[postId]/index.ts index c392ab7..1d8cfcc 100644 --- a/src/pages/api/beers/styles/[id]/index.ts +++ b/src/pages/api/beers/styles/[postId]/index.ts @@ -13,7 +13,7 @@ const router = createRouter< >(); router.get( - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), getBeerStyle, ); diff --git a/src/pages/api/beers/styles/[id]/like/index.ts b/src/pages/api/beers/styles/[postId]/like/index.ts similarity index 85% rename from src/pages/api/beers/styles/[id]/like/index.ts rename to src/pages/api/beers/styles/[postId]/like/index.ts index 87ff024..688c83c 100644 --- a/src/pages/api/beers/styles/[id]/like/index.ts +++ b/src/pages/api/beers/styles/[postId]/like/index.ts @@ -20,12 +20,12 @@ const router = createRouter< router.post( getCurrentUser, - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), sendBeerStyleLikeRequest, ); router.get( - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), getBeerStyleLikeCountRequest, ); diff --git a/src/pages/api/beers/styles/[id]/like/is-liked.ts b/src/pages/api/beers/styles/[postId]/like/is-liked.ts similarity index 91% rename from src/pages/api/beers/styles/[id]/like/is-liked.ts rename to src/pages/api/beers/styles/[postId]/like/is-liked.ts index 3289cb6..d4709a7 100644 --- a/src/pages/api/beers/styles/[id]/like/is-liked.ts +++ b/src/pages/api/beers/styles/[postId]/like/is-liked.ts @@ -15,7 +15,7 @@ const router = createRouter< router.get( getCurrentUser, - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), checkIfBeerStyleIsLiked, ); diff --git a/src/pages/api/breweries/[id]/beers/index.ts b/src/pages/api/breweries/[postId]/beers/index.ts similarity index 81% rename from src/pages/api/breweries/[id]/beers/index.ts rename to src/pages/api/breweries/[postId]/beers/index.ts index c50ebe4..62c0564 100644 --- a/src/pages/api/breweries/[id]/beers/index.ts +++ b/src/pages/api/breweries/[postId]/beers/index.ts @@ -2,6 +2,7 @@ import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import { getAllBeersByBrewery } from '@/controllers/posts/breweries'; import { GetAllPostsByConnectedPostId } from '@/controllers/posts/types'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; import { createRouter } from 'next-connect'; @@ -14,11 +15,7 @@ const router = createRouter< router.get( validateRequest({ - querySchema: z.object({ - page_size: z.string().nonempty(), - page_num: z.string().nonempty(), - id: z.string().nonempty(), - }), + querySchema: PaginatedQueryResponseSchema.extend({ postId: z.string().cuid() }), }), getAllBeersByBrewery, ); diff --git a/src/pages/api/brewery-comments/[id].ts b/src/pages/api/breweries/[postId]/comments/[commentId].ts similarity index 87% rename from src/pages/api/brewery-comments/[id].ts rename to src/pages/api/breweries/[postId]/comments/[commentId].ts index 57e13c4..9865356 100644 --- a/src/pages/api/brewery-comments/[id].ts +++ b/src/pages/api/breweries/[postId]/comments/[commentId].ts @@ -24,7 +24,7 @@ const router = createRouter< router .delete( validateRequest({ - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ commentId: z.string().cuid(), postId: z.string().cuid() }), }), getCurrentUser, checkIfBreweryCommentOwner, @@ -32,7 +32,7 @@ router ) .put( validateRequest({ - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ commentId: z.string().cuid(), postId: z.string().cuid() }), bodySchema: CreateCommentValidationSchema, }), getCurrentUser, diff --git a/src/pages/api/breweries/[id]/comments/index.ts b/src/pages/api/breweries/[postId]/comments/index.ts similarity index 81% rename from src/pages/api/breweries/[id]/comments/index.ts rename to src/pages/api/breweries/[postId]/comments/index.ts index 2e0175d..c97b67b 100644 --- a/src/pages/api/breweries/[id]/comments/index.ts +++ b/src/pages/api/breweries/[postId]/comments/index.ts @@ -9,6 +9,7 @@ import { NextApiResponse } from 'next'; import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; import { createComment, getAll } from '@/controllers/comments/brewery-comments'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; const router = createRouter< // I don't want to use any, but I can't figure out how to get the types to work @@ -19,7 +20,7 @@ const router = createRouter< router.post( validateRequest({ bodySchema: CreateCommentValidationSchema, - querySchema: z.object({ id: z.string().cuid() }), + querySchema: z.object({ postId: z.string().cuid() }), }), getCurrentUser, createComment, @@ -27,11 +28,7 @@ router.post( router.get( validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - page_size: z.coerce.number().int().positive(), - page_num: z.coerce.number().int().positive(), - }), + querySchema: PaginatedQueryResponseSchema.extend({ postId: z.string().cuid() }), }), getAll, ); diff --git a/src/pages/api/breweries/[id]/images/index.ts b/src/pages/api/breweries/[postId]/images/index.ts similarity index 100% rename from src/pages/api/breweries/[id]/images/index.ts rename to src/pages/api/breweries/[postId]/images/index.ts diff --git a/src/pages/api/breweries/[id]/index.ts b/src/pages/api/breweries/[postId]/index.ts similarity index 100% rename from src/pages/api/breweries/[id]/index.ts rename to src/pages/api/breweries/[postId]/index.ts diff --git a/src/pages/api/breweries/[id]/like/index.ts b/src/pages/api/breweries/[postId]/like/index.ts similarity index 77% rename from src/pages/api/breweries/[id]/like/index.ts rename to src/pages/api/breweries/[postId]/like/index.ts index 40b6c14..5073764 100644 --- a/src/pages/api/breweries/[id]/like/index.ts +++ b/src/pages/api/breweries/[postId]/like/index.ts @@ -1,4 +1,3 @@ -import { UserExtendedNextApiRequest } from '@/config/auth/types'; import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; @@ -6,6 +5,7 @@ import { sendBreweryPostLikeRequest, getBreweryPostLikeCount, } from '@/controllers/likes/brewery-post-likes'; +import { LikeRequest } from '@/controllers/likes/types'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; @@ -13,18 +13,18 @@ import { createRouter } from 'next-connect'; import { z } from 'zod'; const router = createRouter< - UserExtendedNextApiRequest, + LikeRequest, NextApiResponse> >(); router.post( getCurrentUser, - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), sendBreweryPostLikeRequest, ); router.get( - validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), getBreweryPostLikeCount, ); diff --git a/src/pages/api/breweries/[id]/like/is-liked.ts b/src/pages/api/breweries/[postId]/like/is-liked.ts similarity index 79% rename from src/pages/api/breweries/[id]/like/is-liked.ts rename to src/pages/api/breweries/[postId]/like/is-liked.ts index 4a41897..c169b1b 100644 --- a/src/pages/api/breweries/[id]/like/is-liked.ts +++ b/src/pages/api/breweries/[postId]/like/is-liked.ts @@ -1,8 +1,8 @@ -import { UserExtendedNextApiRequest } from '@/config/auth/types'; import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import { getBreweryPostLikeStatus } from '@/controllers/likes/brewery-post-likes'; +import { LikeRequest } from '@/controllers/likes/types'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; @@ -10,17 +10,13 @@ import { createRouter } from 'next-connect'; import { z } from 'zod'; const router = createRouter< - UserExtendedNextApiRequest, + LikeRequest, NextApiResponse> >(); router.get( getCurrentUser, - validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - }), - }), + validateRequest({ querySchema: z.object({ postId: z.string().cuid() }) }), getBreweryPostLikeStatus, ); diff --git a/src/pages/api/users/[id]/followers.ts b/src/pages/api/users/[id]/followers.ts index 761e1a3..5eaf28f 100644 --- a/src/pages/api/users/[id]/followers.ts +++ b/src/pages/api/users/[id]/followers.ts @@ -2,6 +2,7 @@ import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import { getUserFollowers } from '@/controllers/users/profile'; import { GetUserFollowInfoRequest } from '@/controllers/users/profile/types'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; @@ -15,11 +16,7 @@ const router = createRouter< router.get( validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - page_size: z.string().regex(/^\d+$/), - page_num: z.string().regex(/^\d+$/), - }), + querySchema: PaginatedQueryResponseSchema.extend({ id: z.string().cuid() }), }), getUserFollowers, ); diff --git a/src/pages/api/users/[id]/following.ts b/src/pages/api/users/[id]/following.ts index 9e99111..55ed2c9 100644 --- a/src/pages/api/users/[id]/following.ts +++ b/src/pages/api/users/[id]/following.ts @@ -2,6 +2,7 @@ import { UserExtendedNextApiRequest } from '@/config/auth/types'; import NextConnectOptions from '@/config/nextConnect/NextConnectOptions'; import validateRequest from '@/config/nextConnect/middleware/validateRequest'; import { getUsersFollowed } from '@/controllers/users/profile'; +import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema'; import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; import { NextApiResponse } from 'next'; @@ -19,11 +20,7 @@ const router = createRouter< router.get( validateRequest({ - querySchema: z.object({ - id: z.string().cuid(), - page_size: z.string().regex(/^\d+$/), - page_num: z.string().regex(/^\d+$/), - }), + querySchema: PaginatedQueryResponseSchema.extend({ id: z.string().cuid() }), }), getUsersFollowed, ); diff --git a/src/pages/beers/[id]/index.tsx b/src/pages/beers/[id]/index.tsx index 51b03b0..d949710 100644 --- a/src/pages/beers/[id]/index.tsx +++ b/src/pages/beers/[id]/index.tsx @@ -74,13 +74,9 @@ const BeerByIdPage: NextPage = ({ beerPost }) => {

) : ( - - - Comments - - - Other Beers - + + Comments + Other Beers diff --git a/src/pages/beers/styles/[id]/index.tsx b/src/pages/beers/styles/[id]/index.tsx index 58d96b4..7340161 100644 --- a/src/pages/beers/styles/[id]/index.tsx +++ b/src/pages/beers/styles/[id]/index.tsx @@ -41,11 +41,9 @@ const BeerStyleByIdPage: NextPage = ({ beerStyle }) => {
) : ( - - - Comments - - + + Comments + Beers in this Style diff --git a/src/pages/breweries/[id]/edit.tsx b/src/pages/breweries/[id]/edit.tsx index 5f2c493..e6487c6 100644 --- a/src/pages/breweries/[id]/edit.tsx +++ b/src/pages/breweries/[id]/edit.tsx @@ -1,20 +1,11 @@ -import FormError from '@/components/ui/forms/FormError'; -import FormInfo from '@/components/ui/forms/FormInfo'; -import FormLabel from '@/components/ui/forms/FormLabel'; +import EditBreweryPostForm from '@/components/EditBreweryPostForm'; import FormPageLayout from '@/components/ui/forms/FormPageLayout'; -import FormSegment from '@/components/ui/forms/FormSegment'; -import FormTextArea from '@/components/ui/forms/FormTextArea'; -import FormTextInput from '@/components/ui/forms/FormTextInput'; import { getBreweryPostByIdService } from '@/services/posts/brewery-post'; import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; -import EditBreweryPostValidationSchema from '@/services/posts/brewery-post/schema/EditBreweryPostValidationSchema'; import withPageAuthRequired from '@/util/withPageAuthRequired'; -import { zodResolver } from '@hookform/resolvers/zod'; import { NextPage } from 'next'; import Head from 'next/head'; -import { useRouter } from 'next/router'; -import { useForm } from 'react-hook-form'; import { BiBeer } from 'react-icons/bi'; import { z } from 'zod'; @@ -25,49 +16,6 @@ interface EditPageProps { const EditBreweryPostPage: NextPage = ({ breweryPost }) => { const pageTitle = `Edit \u201c${breweryPost.name}\u201d`; - const router = useRouter(); - const { - register, - handleSubmit, - formState: { errors, isSubmitting }, - } = useForm>({ - resolver: zodResolver(EditBreweryPostValidationSchema), - defaultValues: { - name: breweryPost.name, - description: breweryPost.description, - id: breweryPost.id, - dateEstablished: breweryPost.dateEstablished, - }, - }); - - const onSubmit = async (data: z.infer) => { - const response = await fetch(`/api/breweries/${breweryPost.id}`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - throw new Error('Something went wrong'); - } - - router.push(`/breweries/${breweryPost.id}`); - }; - - const handleDelete = async () => { - const response = await fetch(`/api/breweries/${breweryPost.id}`, { - method: 'DELETE', - }); - - if (!response.ok) { - throw new Error('Something went wrong'); - } - - router.push('/breweries'); - }; - return ( <> @@ -81,59 +29,7 @@ const EditBreweryPostPage: NextPage = ({ breweryPost }) => { backLink={`/breweries/${breweryPost.id}`} backLinkText={`Back to "${breweryPost.name}"`} > - <> -
-
- - Name - {errors.name?.message} - - - - - - - Description - {errors.description?.message} - - - - -
- -
- - - -
-
- + ); diff --git a/src/pages/breweries/[id]/index.tsx b/src/pages/breweries/[id]/index.tsx index a081fe4..19f0faa 100644 --- a/src/pages/breweries/[id]/index.tsx +++ b/src/pages/breweries/[id]/index.tsx @@ -85,11 +85,11 @@ const BreweryByIdPage: NextPage = ({ breweryPost, mapboxToken token={mapboxToken} /> - - + + Comments - + Beers diff --git a/src/pages/index.tsx b/src/pages/index.tsx index b9e9602..cb58ba6 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,4 +1,5 @@ import { NextPage } from 'next'; +import { CldImage } from 'next-cloudinary'; import Head from 'next/head'; const keywords = [ @@ -29,7 +30,7 @@ const keywords = [ 'beer recipes', ]; -const description = `The Biergarten App is an app for beer lovers to share their favourite brews and breweries with like-minded people online.`; +const description = `An app for beer lovers to share their favourite brews and breweries with like-minded people online.`; const Home: NextPage = () => { return ( @@ -39,13 +40,17 @@ const Home: NextPage = () => { - -
-
-

- The Biergarten App -

-

{description}

+
+ +
+

The Biergarten App

+

{description}

diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index f80db46..f254883 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -18,34 +18,32 @@ const LoginPage: NextPage = () => { -
-
- -
-
-
-
- -

Login

-
+
+ + +
+
+ +

Login

+
+
-
- - Don't have an account? - - - Forgot password? - -
+
+ +
+ + Don't have an account? + + + + Forgot your password?{' '} +
diff --git a/src/pages/register/index.tsx b/src/pages/register/index.tsx index d67e25b..4fcde09 100644 --- a/src/pages/register/index.tsx +++ b/src/pages/register/index.tsx @@ -1,10 +1,11 @@ import RegisterUserForm from '@/components/RegisterUserForm'; -import FormPageLayout from '@/components/ui/forms/FormPageLayout'; import useRedirectWhenLoggedIn from '@/hooks/auth/useRedirectIfLoggedIn'; import { NextPage } from 'next'; +import { CldImage } from 'next-cloudinary'; import Head from 'next/head'; -import { BiUser } from 'react-icons/bi'; + +import { FaUserCircle } from 'react-icons/fa'; const RegisterUserPage: NextPage = () => { useRedirectWhenLoggedIn(); @@ -15,14 +16,26 @@ const RegisterUserPage: NextPage = () => { Register User - - - + +
+ + +
+
+ +

Register

+
+
+ +
+
+
); }; diff --git a/src/pages/users/[id].tsx b/src/pages/users/[id].tsx index 170a8ff..0940db9 100644 --- a/src/pages/users/[id].tsx +++ b/src/pages/users/[id].tsx @@ -25,7 +25,7 @@ const UserInfoPage: FC = ({ user }) => { <> -
+
diff --git a/src/pages/users/account/edit-profile.tsx b/src/pages/users/account/edit-profile.tsx index 70703c5..1dc0a1b 100644 --- a/src/pages/users/account/edit-profile.tsx +++ b/src/pages/users/account/edit-profile.tsx @@ -22,8 +22,8 @@ import useGetUsersFollowedByUser from '@/hooks/data-fetching/user-follows/useGet import useGetUsersFollowingUser from '@/hooks/data-fetching/user-follows/useGetUsersFollowingUser'; import UpdateProfileSchema from '@/services/users/auth/schema/UpdateProfileSchema'; -import sendUpdateUserAvatarRequest from '@/requests/Account/sendUpdateUserAvatarRequest'; -import sendUpdateUserProfileRequest from '@/requests/Account/sendUpdateUserProfileRequest'; +import sendUpdateUserAvatarRequest from '@/requests/users/profile/sendUpdateUserAvatarRequest'; +import sendUpdateUserProfileRequest from '@/requests/users/profile/sendUpdateUserProfileRequest'; import Spinner from '@/components/ui/Spinner'; const ProfilePage: NextPage = () => { diff --git a/src/pages/users/account/index.tsx b/src/pages/users/account/index.tsx index 7c6445e..43527aa 100644 --- a/src/pages/users/account/index.tsx +++ b/src/pages/users/account/index.tsx @@ -33,7 +33,7 @@ const AccountPage: NextPage = () => { content="Your account page. Here you can view your account information, change your settings, and view your posts." /> -
+
@@ -48,22 +48,18 @@ const AccountPage: NextPage = () => {
- - - Account - - - Your Posts - + + Account + Your Posts - + - + diff --git a/src/pages/users/current.tsx b/src/pages/users/current.tsx index 2111bbc..2e1c6e1 100644 --- a/src/pages/users/current.tsx +++ b/src/pages/users/current.tsx @@ -22,7 +22,7 @@ const ProtectedPage: NextPage = () => { Hello! | The Biergarten App -
+
{isLoading && } {user && !isLoading && ( <> diff --git a/src/pages/users/forgot-password.tsx b/src/pages/users/forgot-password.tsx index a68adc3..98a914c 100644 --- a/src/pages/users/forgot-password.tsx +++ b/src/pages/users/forgot-password.tsx @@ -12,8 +12,9 @@ import { NextPage } from 'next'; import { SubmitHandler, useForm } from 'react-hook-form'; import toast from 'react-hot-toast'; import { useRouter } from 'next/router'; -import sendForgotPasswordRequest from '@/requests/User/sendForgotPasswordRequest'; + import { FaUserCircle } from 'react-icons/fa'; +import { sendForgotPasswordRequest } from '@/requests/users/auth'; interface ForgotPasswordPageProps {} @@ -29,7 +30,7 @@ const ForgotPasswordPage: NextPage = () => { const onSubmit: SubmitHandler<{ email: string }> = async (data) => { try { const loadingToast = toast.loading('Sending reset link...'); - await sendForgotPasswordRequest(data.email); + await sendForgotPasswordRequest({ email: data.email }); reset(); toast.dismiss(loadingToast); toast.success('Password reset link sent!'); diff --git a/src/requests/BeerComment/sendCreateBeerCommentRequest.ts b/src/requests/BeerComment/sendCreateBeerCommentRequest.ts deleted file mode 100644 index 41dbde3..0000000 --- a/src/requests/BeerComment/sendCreateBeerCommentRequest.ts +++ /dev/null @@ -1,53 +0,0 @@ -import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; -import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; - -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -const BeerCommentValidationSchemaWithId = CreateCommentValidationSchema.extend({ - beerPostId: z.string().cuid(), -}); - -/** - * Sends a POST request to the server to create a new beer comment. - * - * @param data The data to be sent to the server. - * @param data.beerPostId The ID of the beer post to comment on. - * @param data.content The content of the comment. - * @param data.rating The rating of the beer. - * @returns A promise that resolves to the created comment. - * @throws An error if the request fails, the API response is invalid, or the API response - * payload is invalid. - */ -const sendCreateBeerCommentRequest = async ({ - beerPostId, - content, - rating, -}: z.infer) => { - const response = await fetch(`/api/beers/${beerPostId}/comments`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ beerPostId, content, rating }), - }); - if (!response.ok) { - throw new Error(response.statusText); - } - - const data = await response.json(); - - const parsedResponse = APIResponseValidationSchema.safeParse(data); - - if (!parsedResponse.success) { - throw new Error('Invalid API response'); - } - - const parsedPayload = CommentQueryResult.safeParse(parsedResponse.data.payload); - - if (!parsedPayload.success) { - throw new Error('Invalid API response payload'); - } - - return parsedPayload.data; -}; - -export default sendCreateBeerCommentRequest; diff --git a/src/requests/BeerPost/deleteBeerPostRequest.ts b/src/requests/BeerPost/deleteBeerPostRequest.ts deleted file mode 100644 index ea3ee3f..0000000 --- a/src/requests/BeerPost/deleteBeerPostRequest.ts +++ /dev/null @@ -1,29 +0,0 @@ -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; - -/** - * Sends a DELETE request to the server to delete a beer post with the given ID. - * - * @param id The ID of the beer post to delete. - * @returns A Promise that resolves to the parsed API response. - * @throws An error if the response fails or the API response is invalid. - */ -const deleteBeerPostRequest = async (id: string) => { - const response = await fetch(`/api/beers/${id}`, { - method: 'DELETE', - }); - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('Could not successfully parse the response.'); - } - - return parsed; -}; - -export default deleteBeerPostRequest; diff --git a/src/requests/BeerPost/sendCreateBeerPostRequest.ts b/src/requests/BeerPost/sendCreateBeerPostRequest.ts deleted file mode 100644 index 7e36b1f..0000000 --- a/src/requests/BeerPost/sendCreateBeerPostRequest.ts +++ /dev/null @@ -1,67 +0,0 @@ -import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; -import CreateBeerPostValidationSchema from '@/services/posts/beer-post/schema/CreateBeerPostValidationSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -/** - * Sends a POST request to the server to create a new beer post. - * - * @param data Data containing the beer post information to be sent to the server. - * @param abv The alcohol by volume of the beer. - * @param breweryId The ID of the brewery that produces the beer. - * @param description The description of the beer. - * @param ibu The International Bitterness Units of the beer. - * @param name The name of the beer. - * @param styleId The ID of the beer style. - * @returns A Promise that resolves to the created beer post. - * @throws An error if the request fails, the API response is invalid, or the API response - * payload is invalid. - */ -const sendCreateBeerPostRequest = async ({ - abv, - breweryId, - description, - ibu, - name, - styleId, -}: z.infer) => { - const response = await fetch('/api/beers/create', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - abv, - breweryId, - description, - ibu, - name, - styleId, - }), - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('Invalid API response'); - } - - const { payload, success, message } = parsed.data; - - if (!success) { - throw new Error(message); - } - - const parsedPayload = BeerPostQueryResult.safeParse(payload); - - if (!parsedPayload.success) { - throw new Error('Invalid API response payload'); - } - - return parsedPayload.data; -}; - -export default sendCreateBeerPostRequest; diff --git a/src/requests/BeerPost/sendEditBeerPostRequest.ts b/src/requests/BeerPost/sendEditBeerPostRequest.ts deleted file mode 100644 index de58f1d..0000000 --- a/src/requests/BeerPost/sendEditBeerPostRequest.ts +++ /dev/null @@ -1,42 +0,0 @@ -import EditBeerPostValidationSchema from '@/services/posts/beer-post/schema/EditBeerPostValidationSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -/** - * Sends a PUT request to the server to update a beer post. - * - * @param data Data containing the updated beer post information to be sent to the server. - * @param data.abv The updated ABV of the beer. - * @param data.description The updated description of the beer. - * @param data.ibu The updated IBU of the beer. - * @param data.id The ID of the beer post to be updated. - * @param data.name The updated name of the beer. - * @param data.styleId The updated style ID of the beer. - * @throws If the response status is not ok or the API response is not successful. - */ -const sendEditBeerPostRequest = async ({ - abv, - description, - ibu, - id, - name, -}: z.infer) => { - const response = await fetch(`/api/beers/${id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ abv, description, ibu, name, id }), - }); - - if (!response.ok) { - throw new Error(`${response.status}: ${response.statusText}`); - } - - const json = await response.json(); - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error(parsed.error.message); - } -}; - -export default sendEditBeerPostRequest; diff --git a/src/requests/BeerStyleComment/sendCreateBeerStyleCommentRequest.ts b/src/requests/BeerStyleComment/sendCreateBeerStyleCommentRequest.ts deleted file mode 100644 index 89a0cd9..0000000 --- a/src/requests/BeerStyleComment/sendCreateBeerStyleCommentRequest.ts +++ /dev/null @@ -1,53 +0,0 @@ -import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; -import CreateCommentValidationSchema from '@/services/schema/CommentSchema/CreateCommentValidationSchema'; - -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -const BeerStyleCommentValidationSchemaWithId = CreateCommentValidationSchema.extend({ - beerStyleId: z.string().cuid(), -}); - -/** - * Sends a POST request to the server to create a new beer comment. - * - * @param data The data to be sent to the server. - * @param data.beerPostId The ID of the beer post to comment on. - * @param data.content The content of the comment. - * @param data.rating The rating of the beer. - * @returns A promise that resolves to the created comment. - * @throws An error if the request fails, the API response is invalid, or the API response - * payload is invalid. - */ -const sendCreateBeerStyleCommentRequest = async ({ - beerStyleId, - content, - rating, -}: z.infer) => { - const response = await fetch(`/api/beers/styles/${beerStyleId}/comments`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ beerStyleId, content, rating }), - }); - if (!response.ok) { - throw new Error(response.statusText); - } - - const data = await response.json(); - - const parsedResponse = APIResponseValidationSchema.safeParse(data); - - if (!parsedResponse.success) { - throw new Error('Invalid API response'); - } - - const parsedPayload = CommentQueryResult.safeParse(parsedResponse.data.payload); - - if (!parsedPayload.success) { - throw new Error('Invalid API response payload'); - } - - return parsedPayload.data; -}; - -export default sendCreateBeerStyleCommentRequest; diff --git a/src/requests/BreweryPost/sendCreateBreweryPostRequest.ts b/src/requests/BreweryPost/sendCreateBreweryPostRequest.ts deleted file mode 100644 index 5477035..0000000 --- a/src/requests/BreweryPost/sendCreateBreweryPostRequest.ts +++ /dev/null @@ -1,34 +0,0 @@ -import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; -import CreateBreweryPostSchema from '@/services/posts/brewery-post/schema/CreateBreweryPostSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -const sendCreateBreweryPostRequest = async ( - data: z.infer, -) => { - const response = await fetch('/api/breweries/create', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - if (!parsed.success) { - throw new Error('API response parsing failed'); - } - - const parsedPayload = BreweryPostQueryResult.safeParse(parsed.data.payload); - if (!parsedPayload.success) { - throw new Error('API response payload parsing failed'); - } - - return parsedPayload.data; -}; - -export default sendCreateBreweryPostRequest; diff --git a/src/requests/User/sendEditUserRequest.ts b/src/requests/User/sendEditUserRequest.ts deleted file mode 100644 index 1ff9feb..0000000 --- a/src/requests/User/sendEditUserRequest.ts +++ /dev/null @@ -1,35 +0,0 @@ -import GetUserSchema from '@/services/users/auth/schema/GetUserSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -interface SendEditUserRequestArgs { - user: z.infer; - data: { - username: string; - email: string; - firstName: string; - lastName: string; - }; -} - -const sendEditUserRequest = async ({ user, data }: SendEditUserRequestArgs) => { - const response = await fetch(`/api/users/${user!.id}`, { - body: JSON.stringify(data), - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - }); - if (!response.ok) { - throw new Error(response.statusText); - } - - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - if (!parsed.success) { - throw new Error('API response validation failed.'); - } - - return parsed; -}; - -export default sendEditUserRequest; diff --git a/src/requests/User/sendForgotPasswordRequest.ts b/src/requests/User/sendForgotPasswordRequest.ts deleted file mode 100644 index 8bbf962..0000000 --- a/src/requests/User/sendForgotPasswordRequest.ts +++ /dev/null @@ -1,24 +0,0 @@ -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; - -const sendForgotPasswordRequest = async (email: string) => { - const response = await fetch('/api/users/forgot-password', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email }), - }); - - if (!response.ok) { - throw new Error("Something went wrong and we couldn't send the reset link."); - } - - const json = await response.json(); - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error(parsed.error.message); - } - - return parsed.data; -}; - -export default sendForgotPasswordRequest; diff --git a/src/requests/User/sendLoginUserRequest.ts b/src/requests/User/sendLoginUserRequest.ts deleted file mode 100644 index 7be9e64..0000000 --- a/src/requests/User/sendLoginUserRequest.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { BasicUserInfoSchema } from '@/config/auth/types'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; - -const sendLoginUserRequest = async (data: { username: string; password: string }) => { - const response = await fetch('/api/users/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }); - - const json: unknown = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - if (!parsed.success) { - throw new Error('API response validation failed'); - } - - if (!parsed.data.success) { - throw new Error(parsed.data.message); - } - const parsedPayload = BasicUserInfoSchema.safeParse(parsed.data.payload); - if (!parsedPayload.success) { - throw new Error('API response payload validation failed'); - } - - return parsedPayload.data; -}; - -export default sendLoginUserRequest; diff --git a/src/requests/User/sendRegisterUserRequest.ts b/src/requests/User/sendRegisterUserRequest.ts deleted file mode 100644 index 3cb6c11..0000000 --- a/src/requests/User/sendRegisterUserRequest.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CreateUserValidationSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas'; -import GetUserSchema from '@/services/users/auth/schema/GetUserSchema'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -async function sendRegisterUserRequest(data: z.infer) { - const response = await fetch('/api/users/register', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(data), - }); - - const json = await response.json(); - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('API response validation failed.'); - } - - if (!parsed.data.success) { - throw new Error(parsed.data.message); - } - - const parsedPayload = GetUserSchema.safeParse(parsed.data.payload); - - if (!parsedPayload.success) { - throw new Error('API response payload validation failed.'); - } - - return parsedPayload.data; -} - -export default sendRegisterUserRequest; diff --git a/src/requests/User/sendUpdatePasswordRequest.ts b/src/requests/User/sendUpdatePasswordRequest.ts deleted file mode 100644 index d565c30..0000000 --- a/src/requests/User/sendUpdatePasswordRequest.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { UpdatePasswordSchema } from '@/services/users/auth/schema/CreateUserValidationSchemas'; -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -const sendUpdatePasswordRequest = async (data: z.infer) => { - const response = await fetch('/api/users/edit-password', { - body: JSON.stringify(data), - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - }); - - if (!response.ok) { - throw new Error(response.statusText); - } - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('API response validation failed.'); - } - - return parsed.data; -}; - -export default sendUpdatePasswordRequest; diff --git a/src/requests/User/validateEmailRequest.ts b/src/requests/User/validateEmailRequest.ts deleted file mode 100644 index 4e87291..0000000 --- a/src/requests/User/validateEmailRequest.ts +++ /dev/null @@ -1,25 +0,0 @@ -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; -import { z } from 'zod'; - -const validateEmailRequest = async (email: string) => { - const response = await fetch(`/api/users/check-email?email=${email}`); - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - return false; - } - - const parsedPayload = z - .object({ emailIsTaken: z.boolean() }) - .safeParse(parsed.data.payload); - - if (!parsedPayload.success) { - return false; - } - - return !parsedPayload.data.emailIsTaken; -}; - -export default validateEmailRequest; diff --git a/src/requests/UserFollow/sendUserFollowRequest.ts b/src/requests/UserFollow/sendUserFollowRequest.ts deleted file mode 100644 index 30f1347..0000000 --- a/src/requests/UserFollow/sendUserFollowRequest.ts +++ /dev/null @@ -1,16 +0,0 @@ -import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; - -const sendUserFollowRequest = async (userId: string) => { - const response = await fetch(`/api/users/${userId}/follow-user`, { method: 'POST' }); - const json = await response.json(); - - const parsed = APIResponseValidationSchema.safeParse(json); - - if (!parsed.success) { - throw new Error('Invalid API response.'); - } - - return parsed; -}; - -export default sendUserFollowRequest; diff --git a/src/requests/comments/beer-comment/index.ts b/src/requests/comments/beer-comment/index.ts new file mode 100644 index 0000000..cc6863c --- /dev/null +++ b/src/requests/comments/beer-comment/index.ts @@ -0,0 +1,118 @@ +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import { + SendCreateBeerCommentRequest, + SendDeleteBeerPostCommentRequest, + SendEditBeerPostCommentRequest, +} from './types'; + +/** + * Sends an api request to edit a beer post comment. + * + * @param params - The parameters for the request. + * @param params.body - The body of the request. + * @param params.body.content - The content of the comment. + * @param params.body.rating - The rating of the beer. + * @param params.commentId - The id of the comment to edit. + * @param params.beerPostId - The id of the beer post the comment belongs to. + * @returns The JSON response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const editBeerPostCommentRequest: SendEditBeerPostCommentRequest = async ({ + body, + commentId, + beerPostId, +}) => { + const response = await fetch(`/api/beers/${beerPostId}/comments/${commentId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error('Failed to edit comment'); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error(parsed.error.message); + } + + return parsed.data; +}; + +/** + * Sends an api request to delete a beer post comment. + * + * @param params - The parameters for the request. + * @param params.commentId - The id of the comment to delete. + * @param params.beerPostId - The id of the beer post the comment belongs to. + * @returns The JSON response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const deleteBeerPostCommentRequest: SendDeleteBeerPostCommentRequest = async ({ + commentId, + beerPostId, +}) => { + const response = await fetch(`/api/beers/${beerPostId}/comments/${commentId}`, { + method: 'DELETE', + }); + + if (!response.ok) { + throw new Error('Failed to delete comment'); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error(parsed.error.message); + } + + return parsed.data; +}; + +/** + * Send an api request to create a comment on a beer post. + * + * @param params - The parameters for the request. + * @param params.beerPostId - The id of the beer post to create the comment on. + * @param params.body - The body of the request. + * @param params.body.content - The content of the comment. + * @param params.body.rating - The rating of the beer. + * @returns The created comment. + * @throws An error if the request fails or the response is invalid. + */ +export const sendCreateBeerCommentRequest: SendCreateBeerCommentRequest = async ({ + beerPostId, + body: { content, rating }, +}) => { + const response = await fetch(`/api/beers/${beerPostId}/comments`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ beerPostId, content, rating }), + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const data = await response.json(); + const parsedResponse = APIResponseValidationSchema.safeParse(data); + + if (!parsedResponse.success) { + throw new Error('Invalid API response'); + } + + const parsedPayload = CommentQueryResult.safeParse(parsedResponse.data.payload); + + if (!parsedPayload.success) { + throw new Error('Invalid API response payload'); + } + + return parsedPayload.data; +}; + +export default sendCreateBeerCommentRequest; diff --git a/src/requests/comments/beer-comment/types/index.ts b/src/requests/comments/beer-comment/types/index.ts new file mode 100644 index 0000000..45f8d96 --- /dev/null +++ b/src/requests/comments/beer-comment/types/index.ts @@ -0,0 +1,19 @@ +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +export type SendEditBeerPostCommentRequest = (args: { + body: { content: string; rating: number }; + commentId: string; + beerPostId: string; +}) => Promise>; + +export type SendDeleteBeerPostCommentRequest = (args: { + commentId: string; + beerPostId: string; +}) => Promise>; + +export type SendCreateBeerCommentRequest = (args: { + beerPostId: string; + body: { content: string; rating: number }; +}) => Promise>; diff --git a/src/requests/comments/beer-style-comment/index.ts b/src/requests/comments/beer-style-comment/index.ts new file mode 100644 index 0000000..1beded3 --- /dev/null +++ b/src/requests/comments/beer-style-comment/index.ts @@ -0,0 +1,117 @@ +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { + SendCreateBeerStyleCommentRequest, + SendDeleteBeerStyleCommentRequest, + SendEditBeerStyleCommentRequest, +} from './types'; + +/** + * Sends an api request to edit a beer style comment. + * + * @param params - The parameters for the request. + * @param params.body - The body of the request. + * @param params.body.content - The content of the comment. + * @param params.body.rating - The rating of the beer. + * @param params.beerStyleId - The id of the beer style the comment belongs to. + * @param params.commentId - The id of the comment to edit. + * @returns The JSON response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendEditBeerStyleCommentRequest: SendEditBeerStyleCommentRequest = async ({ + commentId, + body: { content, rating }, + beerStyleId, +}) => { + const response = await fetch(`/api/beers/styles/${beerStyleId}/comments/${commentId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ content, rating }), + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error('Invalid API response'); + } + + return parsed.data; +}; + +/** + * Sends an api request to delete a beer style comment. + * + * @param params - The parameters for the request. + * @param params.beerStyleId - The id of the beer style the comment belongs to. + * @param params.commentId - The id of the comment to delete. + * @returns The json response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendDeleteBeerStyleCommentRequest: SendDeleteBeerStyleCommentRequest = + async ({ beerStyleId, commentId }) => { + const response = await fetch( + `/api/beers/styles/${beerStyleId}/comments/${commentId}`, + { + method: 'DELETE', + }, + ); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error('Invalid API response'); + } + + return parsed.data; + }; + +/** + * Sends an api request to create a beer style comment. + * + * @param params - The parameters for the request. + * @param params.body - The body of the request. + * @param params.body.content - The content of the comment. + * @param params.body.rating - The rating of the beer. + * @param params.beerStyleId - The id of the beer style the comment belongs to. + * @returns The created comment. + * @throws An error if the request fails or the response is invalid. + */ +export const sendCreateBeerStyleCommentRequest: SendCreateBeerStyleCommentRequest = + async ({ beerStyleId, body: { content, rating } }) => { + const response = await fetch(`/api/beers/styles/${beerStyleId}/comments`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ beerStyleId, content, rating }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + + const data = await response.json(); + + const parsedResponse = APIResponseValidationSchema.safeParse(data); + + if (!parsedResponse.success) { + throw new Error('Invalid API response'); + } + + const parsedPayload = CommentQueryResult.safeParse(parsedResponse.data.payload); + + if (!parsedPayload.success) { + throw new Error('Invalid API response payload'); + } + + return parsedPayload.data; + }; diff --git a/src/requests/comments/beer-style-comment/types/index.ts b/src/requests/comments/beer-style-comment/types/index.ts new file mode 100644 index 0000000..e9b695a --- /dev/null +++ b/src/requests/comments/beer-style-comment/types/index.ts @@ -0,0 +1,19 @@ +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +export type SendEditBeerStyleCommentRequest = (args: { + body: { content: string; rating: number }; + commentId: string; + beerStyleId: string; +}) => Promise>; + +export type SendDeleteBeerStyleCommentRequest = (args: { + commentId: string; + beerStyleId: string; +}) => Promise>; + +export type SendCreateBeerStyleCommentRequest = (args: { + beerStyleId: string; + body: { content: string; rating: number }; +}) => Promise>; diff --git a/src/requests/comments/brewery-comment/index.ts b/src/requests/comments/brewery-comment/index.ts new file mode 100644 index 0000000..cd3b794 --- /dev/null +++ b/src/requests/comments/brewery-comment/index.ts @@ -0,0 +1,109 @@ +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { + SendCreateBreweryPostCommentRequest, + SendDeleteBreweryPostCommentRequest, + SendEditBreweryPostCommentRequest, +} from './types'; +/** + * Sends an api request to edit a brewery comment. + * + * @param params - The parameters for the request. + * @param params.breweryId - The id of the brewery the comment belongs to. + * @param params.commentId - The id of the comment to edit. + * @param params.body - The body of the request. + * @param params.body.content - The content of the comment. + * @param params.body.rating - The rating of the beer. + */ +export const sendEditBreweryPostCommentRequest: SendEditBreweryPostCommentRequest = + async ({ body: { content, rating }, breweryPostId, commentId }) => { + const response = await fetch( + `/api/breweries/${breweryPostId}/comments/${commentId}`, + { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ content, rating }), + }, + ); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error(parsed.error.message); + } + + return parsed.data; + }; + +/** + * Sends an api request to delete a brewery comment. + * + * @param params - The parameters for the request. + * @param params.breweryId - The id of the brewery the comment belongs to. + * @param params.commentId - The id of the comment to delete. + * @returns The JSON response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendDeleteBreweryPostCommentRequest: SendDeleteBreweryPostCommentRequest = + async ({ breweryPostId, commentId }) => { + const response = await fetch( + `/api/breweries/${breweryPostId}/comments/${commentId}`, + { + method: 'DELETE', + }, + ); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error(parsed.error.message); + } + + return parsed.data; + }; +/** + * Sends an api request to create a brewery comment. + * + * @param params - The parameters for the request. + * @param params.body - The body of the request. + * @param params.body.content - The content of the comment. + * @param params.body.rating - The rating of the beer. + * @param params.breweryId - The id of the brewery the comment belongs to. + * @returns The created comment. + * @throws An error if the request fails or the response is invalid. + */ +export const sendCreateBreweryCommentRequest: SendCreateBreweryPostCommentRequest = + async ({ body: { content, rating }, breweryPostId }) => { + const response = await fetch(`/api/breweries/${breweryPostId}/comments`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ content, rating }), + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const data = await response.json(); + const parsedResponse = APIResponseValidationSchema.safeParse(data); + if (!parsedResponse.success) { + throw new Error('Invalid API response'); + } + + const parsedPayload = CommentQueryResult.safeParse(parsedResponse.data.payload); + if (!parsedPayload.success) { + throw new Error('Invalid API response payload'); + } + + return parsedPayload.data; + }; diff --git a/src/requests/BreweryComment/sendCreateBreweryCommentRequest.ts b/src/requests/comments/brewery-comment/sendCreateBreweryCommentRequest.ts similarity index 100% rename from src/requests/BreweryComment/sendCreateBreweryCommentRequest.ts rename to src/requests/comments/brewery-comment/sendCreateBreweryCommentRequest.ts diff --git a/src/requests/comments/brewery-comment/types/index.ts b/src/requests/comments/brewery-comment/types/index.ts new file mode 100644 index 0000000..be3eac6 --- /dev/null +++ b/src/requests/comments/brewery-comment/types/index.ts @@ -0,0 +1,19 @@ +import CommentQueryResult from '@/services/schema/CommentSchema/CommentQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +export type SendEditBreweryPostCommentRequest = (args: { + body: { content: string; rating: number }; + commentId: string; + breweryPostId: string; +}) => Promise>; + +export type SendDeleteBreweryPostCommentRequest = (args: { + commentId: string; + breweryPostId: string; +}) => Promise>; + +export type SendCreateBreweryPostCommentRequest = (args: { + breweryPostId: string; + body: { content: string; rating: number }; +}) => Promise>; diff --git a/src/requests/BeerImage/sendUploadBeerImageRequest.ts b/src/requests/images/beer-image/sendUploadBeerImageRequest.ts similarity index 100% rename from src/requests/BeerImage/sendUploadBeerImageRequest.ts rename to src/requests/images/beer-image/sendUploadBeerImageRequest.ts diff --git a/src/requests/BreweryImage/sendUploadBreweryImageRequest.ts b/src/requests/images/brewery-image/sendUploadBreweryImageRequest.ts similarity index 100% rename from src/requests/BreweryImage/sendUploadBreweryImageRequest.ts rename to src/requests/images/brewery-image/sendUploadBreweryImageRequest.ts diff --git a/src/requests/BeerPostLike/sendBeerPostLikeRequest.ts b/src/requests/likes/beer-post-like/sendBeerPostLikeRequest.ts similarity index 100% rename from src/requests/BeerPostLike/sendBeerPostLikeRequest.ts rename to src/requests/likes/beer-post-like/sendBeerPostLikeRequest.ts diff --git a/src/requests/BeerStyleLike/sendBeerStyleLikeRequest.ts b/src/requests/likes/beer-style-like/sendBeerStyleLikeRequest.ts similarity index 100% rename from src/requests/BeerStyleLike/sendBeerStyleLikeRequest.ts rename to src/requests/likes/beer-style-like/sendBeerStyleLikeRequest.ts diff --git a/src/requests/BreweryPostLike/sendBreweryPostLikeRequest.ts b/src/requests/likes/brewery-post-like/sendBreweryPostLikeRequest.ts similarity index 100% rename from src/requests/BreweryPostLike/sendBreweryPostLikeRequest.ts rename to src/requests/likes/brewery-post-like/sendBreweryPostLikeRequest.ts diff --git a/src/requests/posts/beer-post/index.ts b/src/requests/posts/beer-post/index.ts new file mode 100644 index 0000000..921bc0b --- /dev/null +++ b/src/requests/posts/beer-post/index.ts @@ -0,0 +1,134 @@ +import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { + SendCreateBeerPostRequest, + SendDeleteBeerPostRequest, + SendEditBeerPostRequest, +} from './types'; + +/** + * Sends a POST request to create a new beer post. + * + * @example + * const beerPost = await sendCreateBeerPostRequest({ + * body: { + * abv: 5.5, + * description: 'A golden delight with a touch of citrus.', + * ibu: 30, + * name: 'Yerb Sunshine Ale', + * }, + * styleId: 'clqmteqxc000008jphoy31wqw', + * breweryId: 'clqmtexfb000108jp3nsg26c6', + * }); + * + * @param data - The data to send in the request. + * @param data.body - The body of the request. + * @param data.body.abv - The ABV of the beer. + * @param data.body.description - The description of the beer. + * @param data.body.ibu - The IBU of the beer. + * @param data.body.name - The name of the beer. + * @param data.styleId - The ID of the style of the beer. + * @param data.breweryId - The ID of the brewery of the beer. + * @returns The created beer post. + * @throws An error if the request fails or the response is invalid. + */ +export const sendCreateBeerPostRequest: SendCreateBeerPostRequest = async ({ + body: { abv, description, ibu, name }, + styleId, + breweryId, +}) => { + const response = await fetch('/api/beers/create', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ abv, description, ibu, name, styleId, breweryId }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('Invalid API response'); + } + const { payload, success, message } = parsed.data; + if (!success) { + throw new Error(message); + } + const parsedPayload = BeerPostQueryResult.safeParse(payload); + if (!parsedPayload.success) { + throw new Error('Invalid API response payload'); + } + return parsedPayload.data; +}; + +/** + * Sends a DELETE request to delete a beer post. + * + * @example + * const response = await sendDeleteBeerPostRequest({ + * beerPostId: 'clqmtexfb000108jp3nsg26c6', + * }); + * + * @param args - The arguments to send in the request. + * @param args.beerPostId - The ID of the beer post to delete. + * @returns The response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendDeleteBeerPostRequest: SendDeleteBeerPostRequest = async ({ + beerPostId, +}) => { + const response = await fetch(`/api/beers/${beerPostId}`, { method: 'DELETE' }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('Could not successfully parse the response.'); + } + return parsed.data; +}; + +/** + * Sends a PUT request to edit a beer post. + * + * @example + * const response = await sendEditBeerPostRequest({ + * beerPostId: 'clqmtexfb000108jp3nsg26c6', + * body: { + * abv: 5.5, + * description: 'A golden delight with a touch of citrus.', + * ibu: 30, + * name: 'Yerb Sunshine Ale', + * }, + * }); + * + * @param args - The arguments to send in the request. + * @param args.beerPostId - The ID of the beer post to edit. + * @param args.body - The body of the request. + * @param args.body.abv - The ABV of the beer. + * @param args.body.description - The description of the beer. + * @param args.body.ibu - The IBU of the beer. + * @param args.body.name - The name of the beer. + * @returns The response from the server. + * @throws An error if the request fails or the response is invalid. + */ +export const sendEditBeerPostRequest: SendEditBeerPostRequest = async ({ + beerPostId, + body: { abv, description, ibu, name }, +}) => { + const response = await fetch(`/api/beers/${beerPostId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ abv, description, ibu, name }), + }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('Invalid API response'); + } + return parsed.data; +}; diff --git a/src/requests/posts/beer-post/types/index.ts b/src/requests/posts/beer-post/types/index.ts new file mode 100644 index 0000000..0fc1d6b --- /dev/null +++ b/src/requests/posts/beer-post/types/index.ts @@ -0,0 +1,31 @@ +import BeerPostQueryResult from '@/services/posts/beer-post/schema/BeerPostQueryResult'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +type BeerPostQueryResultT = z.infer; +type APIResponse = z.infer; + +export type SendCreateBeerPostRequest = (data: { + body: { + abv: number; + description: string; + ibu: number; + name: string; + }; + styleId: string; + breweryId: string; +}) => Promise; + +export type SendDeleteBeerPostRequest = (args: { + beerPostId: string; +}) => Promise; + +export type SendEditBeerPostRequest = (args: { + beerPostId: string; + body: { + abv: number; + description: string; + ibu: number; + name: string; + }; +}) => Promise; diff --git a/src/requests/posts/brewery-post/index.ts b/src/requests/posts/brewery-post/index.ts new file mode 100644 index 0000000..4e5b4c6 --- /dev/null +++ b/src/requests/posts/brewery-post/index.ts @@ -0,0 +1,105 @@ +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; +import { + SendEditBreweryPostRequest, + SendDeleteBreweryPostRequest, + SendCreateBreweryPostRequest, +} from './types'; + +/** + * Sends an api request to edit a brewery post. + * + * @param args - The arguments for the request. + * @param args.body - The body of the request. + * @param args.body.name - The name of the brewery. + * @param args.body.description - The description of the brewery. + * @param args.body.dateEstablished - The date the brewery was established. + * @param args.breweryPostId - The id of the brewery post to edit. + */ +export const sendEditBreweryPostRequest: SendEditBreweryPostRequest = async ({ + body, + breweryPostId, +}) => { + const response = await fetch(`/api/breweries/${breweryPostId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error('Something went wrong'); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error('Something went wrong'); + } + + return parsed.data; +}; + +/** + * Sends an api request to delete a brewery post. + * + * @param args - The arguments for the request. + * @param args.breweryPostId - The id of the brewery post to delete. + */ +export const sendDeleteBreweryPostRequest: SendDeleteBreweryPostRequest = async ({ + breweryPostId, +}) => { + const response = await fetch(`/api/breweries/${breweryPostId}`, { + method: 'DELETE', + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error(parsed.error.message); + } + + return parsed.data; +}; + +/** + * Sends an api request to create a brewery post. + * + * @param args - The arguments for the request. + * @param args.body - The body of the request. + * @param args.body.name - The name of the brewery. + * @param args.body.description - The description of the brewery. + * @param args.body.dateEstablished - The date the brewery was established. + */ +export const sendCreateBreweryPostRequest: SendCreateBreweryPostRequest = async ({ + body, +}) => { + const response = await fetch('/api/breweries/create', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('API response parsing failed'); + } + + const parsedPayload = BreweryPostQueryResult.safeParse(parsed.data.payload); + if (!parsedPayload.success) { + throw new Error('API response payload parsing failed'); + } + + return parsedPayload.data; +}; diff --git a/src/requests/posts/brewery-post/types/index.ts b/src/requests/posts/brewery-post/types/index.ts new file mode 100644 index 0000000..4a3d375 --- /dev/null +++ b/src/requests/posts/brewery-post/types/index.ts @@ -0,0 +1,23 @@ +import BreweryPostQueryResult from '@/services/posts/brewery-post/schema/BreweryPostQueryResult'; +import CreateBreweryPostSchema from '@/services/posts/brewery-post/schema/CreateBreweryPostSchema'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +type APIResponse = z.infer; + +export type SendDeleteBreweryPostRequest = (args: { + breweryPostId: string; +}) => Promise; + +export type SendEditBreweryPostRequest = (args: { + body: { + name: string; + description: string; + dateEstablished: Date; + }; + breweryPostId: string; +}) => Promise; + +export type SendCreateBreweryPostRequest = (args: { + body: z.infer; +}) => Promise>; diff --git a/src/requests/users/auth/index.ts b/src/requests/users/auth/index.ts new file mode 100644 index 0000000..7b8c76a --- /dev/null +++ b/src/requests/users/auth/index.ts @@ -0,0 +1,169 @@ +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { BasicUserInfoSchema } from '@/config/auth/types'; +import GetUserSchema from '@/services/users/auth/schema/GetUserSchema'; +import type { + SendEditUserRequest, + SendForgotPasswordRequest, + SendLoginUserRequest, + SendRegisterUserRequest, + SendUpdatePasswordRequest, + SendUserFollowRequest, + ValidateEmailRequest, +} from './types'; +import { z } from 'zod'; + +export const sendEditUserRequest: SendEditUserRequest = async ({ user, data }) => { + const response = await fetch(`/api/users/${user!.id}`, { + body: JSON.stringify(data), + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error(response.statusText); + } + + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('API response validation failed.'); + } + + return parsed.data; +}; + +export const sendForgotPasswordRequest: SendForgotPasswordRequest = async ({ email }) => { + const response = await fetch('/api/users/forgot-password', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email }), + }); + + if (!response.ok) { + throw new Error("Something went wrong and we couldn't send the reset link."); + } + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error(parsed.error.message); + } + + return parsed.data; +}; + +export const sendLoginUserRequest: SendLoginUserRequest = async ({ + username, + password, +}) => { + const response = await fetch('/api/users/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username, + password, + }), + }); + + const json: unknown = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + if (!parsed.success) { + throw new Error('API response validation failed'); + } + + if (!parsed.data.success) { + throw new Error(parsed.data.message); + } + const parsedPayload = BasicUserInfoSchema.safeParse(parsed.data.payload); + if (!parsedPayload.success) { + throw new Error('API response payload validation failed'); + } + + return parsedPayload.data; +}; + +export const sendRegisterUserRequest: SendRegisterUserRequest = async (data) => { + const response = await fetch('/api/users/register', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + + const json = await response.json(); + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error('API response validation failed.'); + } + + if (!parsed.data.success) { + throw new Error(parsed.data.message); + } + + const parsedPayload = GetUserSchema.safeParse(parsed.data.payload); + + if (!parsedPayload.success) { + throw new Error('API response payload validation failed.'); + } + + return parsedPayload.data; +}; + +export const sendUpdatePasswordRequest: SendUpdatePasswordRequest = async (data) => { + const response = await fetch('/api/users/edit-password', { + body: JSON.stringify(data), + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + }); + + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error('API response validation failed.'); + } + + return parsed.data; +}; + +export const sendUserFollowRequest: SendUserFollowRequest = async ({ userId }) => { + const response = await fetch(`/api/users/${userId}/follow-user`, { method: 'POST' }); + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + throw new Error('Invalid API response.'); + } + + return parsed.data; +}; + +export const validateEmailRequest: ValidateEmailRequest = async ({ email }) => { + const response = await fetch(`/api/users/check-email?email=${email}`); + const json = await response.json(); + + const parsed = APIResponseValidationSchema.safeParse(json); + + if (!parsed.success) { + return false; + } + + const parsedPayload = z + .object({ emailIsTaken: z.boolean() }) + .safeParse(parsed.data.payload); + + if (!parsedPayload.success) { + return false; + } + + return !parsedPayload.data.emailIsTaken; +}; diff --git a/src/requests/users/auth/types/index.ts b/src/requests/users/auth/types/index.ts new file mode 100644 index 0000000..c4d1f9c --- /dev/null +++ b/src/requests/users/auth/types/index.ts @@ -0,0 +1,41 @@ +import { BasicUserInfoSchema } from '@/config/auth/types'; +import { + CreateUserValidationSchema, + UpdatePasswordSchema, +} from '@/services/users/auth/schema/CreateUserValidationSchemas'; +import GetUserSchema from '@/services/users/auth/schema/GetUserSchema'; +import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema'; +import { z } from 'zod'; + +export type SendEditUserRequest = (args: { + user: z.infer; + data: { + username: string; + email: string; + firstName: string; + lastName: string; + }; +}) => Promise>; + +export type SendForgotPasswordRequest = (args: { + email: string; +}) => Promise>; + +export type SendLoginUserRequest = (args: { + username: string; + password: string; +}) => Promise>; + +export type SendRegisterUserRequest = ( + args: z.infer, +) => Promise>; + +export type SendUpdatePasswordRequest = ( + args: z.infer, +) => Promise>; + +export type SendUserFollowRequest = (args: { + userId: string; +}) => Promise>; + +export type ValidateEmailRequest = (args: { email: string }) => Promise; diff --git a/src/requests/Account/sendUpdateUserAvatarRequest.ts b/src/requests/users/profile/sendUpdateUserAvatarRequest.ts similarity index 100% rename from src/requests/Account/sendUpdateUserAvatarRequest.ts rename to src/requests/users/profile/sendUpdateUserAvatarRequest.ts diff --git a/src/requests/Account/sendUpdateUserProfileRequest.ts b/src/requests/users/profile/sendUpdateUserProfileRequest.ts similarity index 100% rename from src/requests/Account/sendUpdateUserProfileRequest.ts rename to src/requests/users/profile/sendUpdateUserProfileRequest.ts diff --git a/src/requests/validateUsernameRequest.ts b/src/requests/users/profile/validateUsernameRequest.ts similarity index 100% rename from src/requests/validateUsernameRequest.ts rename to src/requests/users/profile/validateUsernameRequest.ts diff --git a/src/services/schema/PaginatedQueryResponseSchema.ts b/src/services/schema/PaginatedQueryResponseSchema.ts index 22acabc..a9b880f 100644 --- a/src/services/schema/PaginatedQueryResponseSchema.ts +++ b/src/services/schema/PaginatedQueryResponseSchema.ts @@ -1,8 +1,8 @@ import { z } from 'zod'; const PaginatedQueryResponseSchema = z.object({ - page_num: z.string(), - page_size: z.string(), + page_num: z.string().regex(/^\d+$/), + page_size: z.string().regex(/^\d+$/), }); export default PaginatedQueryResponseSchema; diff --git a/src/services/users/auth/schema/CreateUserValidationSchemas.ts b/src/services/users/auth/schema/CreateUserValidationSchemas.ts index 3d86980..ab3c1bc 100644 --- a/src/services/users/auth/schema/CreateUserValidationSchemas.ts +++ b/src/services/users/auth/schema/CreateUserValidationSchemas.ts @@ -1,5 +1,5 @@ -import validateEmailRequest from '@/requests/User/validateEmailRequest'; -import validateUsernameRequest from '@/requests/validateUsernameRequest'; +import { validateEmailRequest } from '@/requests/users/auth'; +import validateUsernameRequest from '@/requests/users/profile/validateUsernameRequest'; import sub from 'date-fns/sub'; import { z } from 'zod'; @@ -60,7 +60,7 @@ export const CreateUserValidationSchemaWithUsernameAndEmailCheck = email: z .string() .email({ message: 'Email must be a valid email address.' }) - .refine(async (email) => validateEmailRequest(email), { + .refine(async (email) => validateEmailRequest({ email }), { message: 'Email is already taken.', }), username: z diff --git a/tailwind.config.js b/tailwind.config.js index bf6fc8b..c6a3588 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,7 +2,7 @@ const myThemes = { dark: { - primary: 'hsl(227, 25%, 25%)', + primary: 'hsl(227, 10%, 25%)', secondary: 'hsl(255, 9%, 69%)', error: 'hsl(9, 52%, 57%)', accent: 'hsl(316, 96%, 60%)', @@ -12,24 +12,10 @@ const myThemes = { warning: 'hsl(50, 98%, 50%)', 'primary-content': 'hsl(0, 0%, 98%)', 'error-content': 'hsl(0, 0%, 98%)', - 'base-100': 'hsl(227, 20%, 20%)', - 'base-200': 'hsl(227, 20%, 13%)', - 'base-300': 'hsl(227, 20%, 10%)', - }, - light: { - primary: 'hsl(180, 20%, 70%)', - secondary: 'hsl(120, 10%, 70%)', - error: 'hsl(4, 87%, 74%)', - accent: 'hsl(93, 27%, 73%)', - neutral: 'hsl(38, 31%, 91%)', - info: 'hsl(163, 40%, 79%)', - success: 'hsl(93, 27%, 73%)', - warning: 'hsl(40, 76%, 73%)', - 'primary-content': 'hsl(0, 0%, 0%)', - 'error-content': 'hsl(0, 0%, 0%)', - 'base-300': 'hsl(180, 10%, 88%)', - 'base-200': 'hsl(180, 10%, 92%)', - 'base-100': 'hsl(180, 10%, 95%)', + 'base-content': 'hsl(227, 0%, 60%)', + 'base-100': 'hsl(227, 10%, 20%)', + 'base-200': 'hsl(227, 10%, 10%)', + 'base-300': 'hsl(227, 10%, 8%)', }, }; @@ -46,10 +32,9 @@ module.exports = { plugins: [ require('@headlessui/tailwindcss'), require('daisyui'), - require('tailwindcss-animate'), + require('tailwindcss-animated'), require('autoprefixer'), ], - daisyui: { logs: false, themes: [myThemes],