From 8bd5f0d17a82a3b6186b96513c1a027eeadbcf5b Mon Sep 17 00:00:00 2001 From: shay Date: Tue, 31 May 2022 04:51:40 +0200 Subject: [PATCH 1/5] feat: set user country --- pages/api/users/[userId]/index.tsx | 18 +- pages/settings.tsx | 14 +- pages/users/[id].tsx | 75 ++++- .../20220530165004_init/migration.sql | 5 + .../20220531000450_init/migration.sql | 2 + prisma/schema.prisma | 2 +- utility/countries.ts | 288 ++++++++++++++++++ 7 files changed, 388 insertions(+), 16 deletions(-) create mode 100644 prisma/migrations/20220530165004_init/migration.sql create mode 100644 prisma/migrations/20220531000450_init/migration.sql create mode 100644 utility/countries.ts diff --git a/pages/api/users/[userId]/index.tsx b/pages/api/users/[userId]/index.tsx index 20e2fa6..05b9f60 100644 --- a/pages/api/users/[userId]/index.tsx +++ b/pages/api/users/[userId]/index.tsx @@ -8,11 +8,10 @@ import { BadRequest, InternalError, NoContent, Unauthenticated } from "../../../ const DeleteUserRoute = async (req: NextApiRequest, res: NextApiResponse) => { const session = await getSession({ req }); if (!session?.user) return Unauthenticated(res); + const id = (session.user as ModifiedSession).id; // Delete all bios & the user themself if (req.method === "DELETE") { - const id = (session.user as ModifiedSession).id; - try { await prisma.user.delete({ where: { id } }); return NoContent(res); @@ -25,6 +24,21 @@ const DeleteUserRoute = async (req: NextApiRequest, res: NextApiResponse) => { console.error(e); return InternalError(res); } + } else if (req.method === "PATCH") { + try { + await prisma.user.update({ where: { id }, data: { + country: req.body.country, + } }); + return NoContent(res); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError) { + if (e.code === "P2025") { + return BadRequest(res, "The specified user does not exist."); + } + } + console.error(e); + return InternalError(res); + } } }; diff --git a/pages/settings.tsx b/pages/settings.tsx index 72fce37..0b1826f 100644 --- a/pages/settings.tsx +++ b/pages/settings.tsx @@ -66,8 +66,18 @@ const SettingsPage: NextPage = ({ user }) => { -

Settings

-

todo

+

You

+

Global profile settings that affect all of your bios.

+
+ +

Destructive

+ +
+ + + + + +
+ )}
-

{user.name}

+

+ {user.name} + {user.country && !isInUserEditingMode && ( + + {countries[user.country].emoji} + + )} + {isInUserEditingMode && ( + + )} +

{isCurrentUser && } {badges.map((b) => ( diff --git a/prisma/migrations/20220530165004_init/migration.sql b/prisma/migrations/20220530165004_init/migration.sql new file mode 100644 index 0000000..3d9908c --- /dev/null +++ b/prisma/migrations/20220530165004_init/migration.sql @@ -0,0 +1,5 @@ +-- DropForeignKey +ALTER TABLE "Bio" DROP CONSTRAINT "Bio_authorId_fkey"; + +-- AddForeignKey +ALTER TABLE "Bio" ADD CONSTRAINT "Bio_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20220531000450_init/migration.sql b/prisma/migrations/20220531000450_init/migration.sql new file mode 100644 index 0000000..e4e83f3 --- /dev/null +++ b/prisma/migrations/20220531000450_init/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "country" VARCHAR(2); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b10c93e..0e56d91 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -14,7 +14,7 @@ model User { defaultBio Bio? @relation(fields: [defaultBioId], references: [id], name: "DefaultBio") defaultBioId Int? @unique bios Bio[] @relation("BioAuthor") - + country String? @db.VarChar(2) } model Bio { diff --git a/utility/countries.ts b/utility/countries.ts new file mode 100644 index 0000000..af6cb36 --- /dev/null +++ b/utility/countries.ts @@ -0,0 +1,288 @@ +const codePoints: Record = { + A: 0x1f1e6, + B: 0x1f1e7, + C: 0x1f1e8, + D: 0x1f1e9, + E: 0x1f1ea, + F: 0x1f1eb, + G: 0x1f1ec, + H: 0x1f1ed, + I: 0x1f1ee, + J: 0x1f1ef, + K: 0x1f1f0, + L: 0x1f1f1, + M: 0x1f1f2, + N: 0x1f1f3, + O: 0x1f1f4, + P: 0x1f1f5, + Q: 0x1f1f6, + R: 0x1f1f7, + S: 0x1f1f8, + T: 0x1f1f9, + U: 0x1f1fa, + V: 0x1f1fb, + W: 0x1f1fc, + X: 0x1f1fd, + Y: 0x1f1fe, + Z: 0x1f1ff, +}; + +const countries: Record> = { + AF: { name: "Afghanistan", emoji: "" }, + AX: { name: "Ă…land Islands", emoji: "" }, + AL: { name: "Albania", emoji: "" }, + DZ: { name: "Algeria", emoji: "" }, + AS: { name: "American Samoa", emoji: "" }, + AD: { name: "AndorrA", emoji: "" }, + AO: { name: "Angola", emoji: "" }, + AI: { name: "Anguilla", emoji: "" }, + AQ: { name: "Antarctica", emoji: "" }, + AG: { name: "Antigua and Barbuda", emoji: "" }, + AR: { name: "Argentina", emoji: "" }, + AM: { name: "Armenia", emoji: "" }, + AW: { name: "Aruba", emoji: "" }, + AU: { name: "Australia", emoji: "" }, + AT: { name: "Austria", emoji: "" }, + AZ: { name: "Azerbaijan", emoji: "" }, + BS: { name: "Bahamas", emoji: "" }, + BH: { name: "Bahrain", emoji: "" }, + BD: { name: "Bangladesh", emoji: "" }, + BB: { name: "Barbados", emoji: "" }, + BY: { name: "Belarus", emoji: "" }, + BE: { name: "Belgium", emoji: "" }, + BZ: { name: "Belize", emoji: "" }, + BJ: { name: "Benin", emoji: "" }, + BM: { name: "Bermuda", emoji: "" }, + BT: { name: "Bhutan", emoji: "" }, + BO: { name: "Bolivia", emoji: "" }, + BA: { name: "Bosnia and Herzegovina", emoji: "" }, + BW: { name: "Botswana", emoji: "" }, + BV: { name: "Bouvet Island", emoji: "" }, + BR: { name: "Brazil", emoji: "" }, + IO: { name: "British Indian Ocean Territory", emoji: "" }, + BN: { name: "Brunei Darussalam", emoji: "" }, + BG: { name: "Bulgaria", emoji: "" }, + BF: { name: "Burkina Faso", emoji: "" }, + BI: { name: "Burundi", emoji: "" }, + KH: { name: "Cambodia", emoji: "" }, + CM: { name: "Cameroon", emoji: "" }, + CA: { name: "Canada", emoji: "" }, + CV: { name: "Cape Verde", emoji: "" }, + KY: { name: "Cayman Islands", emoji: "" }, + CF: { name: "Central African Republic", emoji: "" }, + TD: { name: "Chad", emoji: "" }, + CL: { name: "Chile", emoji: "" }, + CN: { name: "China", emoji: "" }, + CX: { name: "Christmas Island", emoji: "" }, + CC: { name: "Cocos (Keeling) Islands", emoji: "" }, + CO: { name: "Colombia", emoji: "" }, + KM: { name: "Comoros", emoji: "" }, + CG: { name: "Congo", emoji: "" }, + CD: { name: "Congo, The Democratic Republic of the", emoji: "" }, + CK: { name: "Cook Islands", emoji: "" }, + CR: { name: "Costa Rica", emoji: "" }, + CI: { name: "Cote D'Ivoire", emoji: "" }, + HR: { name: "Croatia", emoji: "" }, + CU: { name: "Cuba", emoji: "" }, + CY: { name: "Cyprus", emoji: "" }, + CZ: { name: "Czech Republic", emoji: "" }, + DK: { name: "Denmark", emoji: "" }, + DJ: { name: "Djibouti", emoji: "" }, + DM: { name: "Dominica", emoji: "" }, + DO: { name: "Dominican Republic", emoji: "" }, + EC: { name: "Ecuador", emoji: "" }, + EG: { name: "Egypt", emoji: "" }, + SV: { name: "El Salvador", emoji: "" }, + GQ: { name: "Equatorial Guinea", emoji: "" }, + ER: { name: "Eritrea", emoji: "" }, + EE: { name: "Estonia", emoji: "" }, + ET: { name: "Ethiopia", emoji: "" }, + FK: { name: "Falkland Islands (Malvinas)", emoji: "" }, + FO: { name: "Faroe Islands", emoji: "" }, + FJ: { name: "Fiji", emoji: "" }, + FI: { name: "Finland", emoji: "" }, + FR: { name: "France", emoji: "" }, + GF: { name: "French Guiana", emoji: "" }, + PF: { name: "French Polynesia", emoji: "" }, + TF: { name: "French Southern Territories", emoji: "" }, + GA: { name: "Gabon", emoji: "" }, + GM: { name: "Gambia", emoji: "" }, + GE: { name: "Georgia", emoji: "" }, + DE: { name: "Germany", emoji: "" }, + GH: { name: "Ghana", emoji: "" }, + GI: { name: "Gibraltar", emoji: "" }, + GR: { name: "Greece", emoji: "" }, + GL: { name: "Greenland", emoji: "" }, + GD: { name: "Grenada", emoji: "" }, + GP: { name: "Guadeloupe", emoji: "" }, + GU: { name: "Guam", emoji: "" }, + GT: { name: "Guatemala", emoji: "" }, + GG: { name: "Guernsey", emoji: "" }, + GN: { name: "Guinea", emoji: "" }, + GW: { name: "Guinea-Bissau", emoji: "" }, + GY: { name: "Guyana", emoji: "" }, + HT: { name: "Haiti", emoji: "" }, + HM: { name: "Heard Island and Mcdonald Islands", emoji: "" }, + VA: { name: "Holy See (Vatican City State)", emoji: "" }, + HN: { name: "Honduras", emoji: "" }, + HK: { name: "Hong Kong", emoji: "" }, + HU: { name: "Hungary", emoji: "" }, + IS: { name: "Iceland", emoji: "" }, + IN: { name: "India", emoji: "" }, + ID: { name: "Indonesia", emoji: "" }, + IR: { name: "Iran, Islamic Republic Of", emoji: "" }, + IQ: { name: "Iraq", emoji: "" }, + IE: { name: "Ireland", emoji: "" }, + IM: { name: "Isle of Man", emoji: "" }, + IL: { name: "Israel", emoji: "" }, + IT: { name: "Italy", emoji: "" }, + JM: { name: "Jamaica", emoji: "" }, + JP: { name: "Japan", emoji: "" }, + JE: { name: "Jersey", emoji: "" }, + JO: { name: "Jordan", emoji: "" }, + KZ: { name: "Kazakhstan", emoji: "" }, + KE: { name: "Kenya", emoji: "" }, + KI: { name: "Kiribati", emoji: "" }, + KP: { name: "Korea, Democratic People'S Republic of", emoji: "" }, + KR: { name: "Korea, Republic of", emoji: "" }, + KW: { name: "Kuwait", emoji: "" }, + KG: { name: "Kyrgyzstan", emoji: "" }, + LA: { name: "Lao People'S Democratic Republic", emoji: "" }, + LV: { name: "Latvia", emoji: "" }, + LB: { name: "Lebanon", emoji: "" }, + LS: { name: "Lesotho", emoji: "" }, + LR: { name: "Liberia", emoji: "" }, + LY: { name: "Libyan Arab Jamahiriya", emoji: "" }, + LI: { name: "Liechtenstein", emoji: "" }, + LT: { name: "Lithuania", emoji: "" }, + LU: { name: "Luxembourg", emoji: "" }, + MO: { name: "Macao", emoji: "" }, + MK: { name: "Macedonia, The Former Yugoslav Republic of", emoji: "" }, + MG: { name: "Madagascar", emoji: "" }, + MW: { name: "Malawi", emoji: "" }, + MY: { name: "Malaysia", emoji: "" }, + MV: { name: "Maldives", emoji: "" }, + ML: { name: "Mali", emoji: "" }, + MT: { name: "Malta", emoji: "" }, + MH: { name: "Marshall Islands", emoji: "" }, + MQ: { name: "Martinique", emoji: "" }, + MR: { name: "Mauritania", emoji: "" }, + MU: { name: "Mauritius", emoji: "" }, + YT: { name: "Mayotte", emoji: "" }, + MX: { name: "Mexico", emoji: "" }, + FM: { name: "Micronesia, Federated States of", emoji: "" }, + MD: { name: "Moldova, Republic of", emoji: "" }, + MC: { name: "Monaco", emoji: "" }, + MN: { name: "Mongolia", emoji: "" }, + MS: { name: "Montserrat", emoji: "" }, + MA: { name: "Morocco", emoji: "" }, + MZ: { name: "Mozambique", emoji: "" }, + MM: { name: "Myanmar", emoji: "" }, + NA: { name: "Namibia", emoji: "" }, + NR: { name: "Nauru", emoji: "" }, + NP: { name: "Nepal", emoji: "" }, + NL: { name: "Netherlands", emoji: "" }, + AN: { name: "Netherlands Antilles", emoji: "" }, + NC: { name: "New Caledonia", emoji: "" }, + NZ: { name: "New Zealand", emoji: "" }, + NI: { name: "Nicaragua", emoji: "" }, + NE: { name: "Niger", emoji: "" }, + NG: { name: "Nigeria", emoji: "" }, + NU: { name: "Niue", emoji: "" }, + NF: { name: "Norfolk Island", emoji: "" }, + MP: { name: "Northern Mariana Islands", emoji: "" }, + NO: { name: "Norway", emoji: "" }, + OM: { name: "Oman", emoji: "" }, + PK: { name: "Pakistan", emoji: "" }, + PW: { name: "Palau", emoji: "" }, + PS: { name: "Palestinian Territory, Occupied", emoji: "" }, + PA: { name: "Panama", emoji: "" }, + PG: { name: "Papua New Guinea", emoji: "" }, + PY: { name: "Paraguay", emoji: "" }, + PE: { name: "Peru", emoji: "" }, + PH: { name: "Philippines", emoji: "" }, + PN: { name: "Pitcairn", emoji: "" }, + PL: { name: "Poland", emoji: "" }, + PT: { name: "Portugal", emoji: "" }, + PR: { name: "Puerto Rico", emoji: "" }, + QA: { name: "Qatar", emoji: "" }, + RE: { name: "Reunion", emoji: "" }, + RO: { name: "Romania", emoji: "" }, + RU: { name: "Russian Federation", emoji: "" }, + RW: { name: "RWANDA", emoji: "" }, + SH: { name: "Saint Helena", emoji: "" }, + KN: { name: "Saint Kitts and Nevis", emoji: "" }, + LC: { name: "Saint Lucia", emoji: "" }, + PM: { name: "Saint Pierre and Miquelon", emoji: "" }, + VC: { name: "Saint Vincent and the Grenadines", emoji: "" }, + WS: { name: "Samoa", emoji: "" }, + SM: { name: "San Marino", emoji: "" }, + ST: { name: "Sao Tome and Principe", emoji: "" }, + SA: { name: "Saudi Arabia", emoji: "" }, + SN: { name: "Senegal", emoji: "" }, + CS: { name: "Serbia and Montenegro", emoji: "" }, + SC: { name: "Seychelles", emoji: "" }, + SL: { name: "Sierra Leone", emoji: "" }, + SG: { name: "Singapore", emoji: "" }, + SK: { name: "Slovakia", emoji: "" }, + SI: { name: "Slovenia", emoji: "" }, + SB: { name: "Solomon Islands", emoji: "" }, + SO: { name: "Somalia", emoji: "" }, + ZA: { name: "South Africa", emoji: "" }, + GS: { name: "South Georgia and the South Sandwich Islands", emoji: "" }, + ES: { name: "Spain", emoji: "" }, + LK: { name: "Sri Lanka", emoji: "" }, + SD: { name: "Sudan", emoji: "" }, + SR: { name: "Suriname", emoji: "" }, + SJ: { name: "Svalbard and Jan Mayen", emoji: "" }, + SZ: { name: "Swaziland", emoji: "" }, + SE: { name: "Sweden", emoji: "" }, + CH: { name: "Switzerland", emoji: "" }, + SY: { name: "Syrian Arab Republic", emoji: "" }, + TW: { name: "Taiwan, Province of China", emoji: "" }, + TJ: { name: "Tajikistan", emoji: "" }, + TZ: { name: "Tanzania, United Republic of", emoji: "" }, + TH: { name: "Thailand", emoji: "" }, + TL: { name: "Timor-Leste", emoji: "" }, + TG: { name: "Togo", emoji: "" }, + TK: { name: "Tokelau", emoji: "" }, + TO: { name: "Tonga", emoji: "" }, + TT: { name: "Trinidad and Tobago", emoji: "" }, + TN: { name: "Tunisia", emoji: "" }, + TR: { name: "Turkey", emoji: "" }, + TM: { name: "Turkmenistan", emoji: "" }, + TC: { name: "Turks and Caicos Islands", emoji: "" }, + TV: { name: "Tuvalu", emoji: "" }, + UG: { name: "Uganda", emoji: "" }, + UA: { name: "Ukraine", emoji: "" }, + AE: { name: "United Arab Emirates", emoji: "" }, + GB: { name: "United Kingdom", emoji: "" }, + US: { name: "United States", emoji: "" }, + UM: { name: "United States Minor Outlying Islands", emoji: "" }, + UY: { name: "Uruguay", emoji: "" }, + UZ: { name: "Uzbekistan", emoji: "" }, + VU: { name: "Vanuatu", emoji: "" }, + VE: { name: "Venezuela", emoji: "" }, + VN: { name: "Viet Nam", emoji: "" }, + VG: { name: "Virgin Islands, British", emoji: "" }, + VI: { name: "Virgin Islands, U.S.", emoji: "" }, + WF: { name: "Wallis and Futuna", emoji: "" }, + EH: { name: "Western Sahara", emoji: "" }, + YE: { name: "Yemen", emoji: "" }, + ZM: { name: "Zambia", emoji: "" }, + ZW: { name: "Zimbabwe", emoji: "" }, +}; + +Object.keys(countries).forEach((code) => { + // We do this just so we don't have to hardcode every code *and* every + // emoji, because the emojis are just the codes except that they use a + // special unicode char. + const codeSplit = code.split(""); + let emoji: number[] = []; + codeSplit.forEach((part) => { + emoji.push(codePoints[part]); + }); + countries[code].emoji = String.fromCodePoint(...emoji); +}); + +export default countries; From b22b552078a141fb591f2b356d7d5f8e2dd3c481 Mon Sep 17 00:00:00 2001 From: shay Date: Tue, 31 May 2022 16:00:32 +0200 Subject: [PATCH 2/5] feat: validate country --- pages/api/users/[userId]/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pages/api/users/[userId]/index.tsx b/pages/api/users/[userId]/index.tsx index 05b9f60..a6aafcf 100644 --- a/pages/api/users/[userId]/index.tsx +++ b/pages/api/users/[userId]/index.tsx @@ -4,14 +4,15 @@ import prisma from "../../../../lib/prisma"; import { Prisma } from "@prisma/client"; import { ModifiedSession } from "../../../../types/session"; import { BadRequest, InternalError, NoContent, Unauthenticated } from "../../../../utility/http"; +import countries from "../../../../utility/countries" const DeleteUserRoute = async (req: NextApiRequest, res: NextApiResponse) => { const session = await getSession({ req }); if (!session?.user) return Unauthenticated(res); const id = (session.user as ModifiedSession).id; - // Delete all bios & the user themself if (req.method === "DELETE") { + // Delete all bios & the user themself try { await prisma.user.delete({ where: { id } }); return NoContent(res); @@ -25,6 +26,10 @@ const DeleteUserRoute = async (req: NextApiRequest, res: NextApiResponse) => { return InternalError(res); } } else if (req.method === "PATCH") { + // Update the user + if (req.body.country && !Object.keys(countries).includes(req.body.country)) { + return BadRequest(res, "Invalid country code."); + } try { await prisma.user.update({ where: { id }, data: { country: req.body.country, From 6b1d370d2d217cb863ce185f786a53cf8fb9fdce Mon Sep 17 00:00:00 2001 From: shay Date: Tue, 31 May 2022 16:16:17 +0200 Subject: [PATCH 3/5] refactor: rename `DeleteUserRoute` --- pages/api/users/[userId]/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/users/[userId]/index.tsx b/pages/api/users/[userId]/index.tsx index a6aafcf..00b84f5 100644 --- a/pages/api/users/[userId]/index.tsx +++ b/pages/api/users/[userId]/index.tsx @@ -6,7 +6,7 @@ import { ModifiedSession } from "../../../../types/session"; import { BadRequest, InternalError, NoContent, Unauthenticated } from "../../../../utility/http"; import countries from "../../../../utility/countries" -const DeleteUserRoute = async (req: NextApiRequest, res: NextApiResponse) => { +const UserRoute = async (req: NextApiRequest, res: NextApiResponse) => { const session = await getSession({ req }); if (!session?.user) return Unauthenticated(res); const id = (session.user as ModifiedSession).id; @@ -47,4 +47,4 @@ const DeleteUserRoute = async (req: NextApiRequest, res: NextApiResponse) => { } }; -export default DeleteUserRoute; +export default UserRoute; From c6541d43ebb5a49b2c783e1836c85d3afe590e39 Mon Sep 17 00:00:00 2001 From: shay Date: Sat, 4 Jun 2022 00:30:50 +0200 Subject: [PATCH 4/5] refactor: flag positioning trickery --- pages/users/[id].tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pages/users/[id].tsx b/pages/users/[id].tsx index 47e6268..e773a21 100644 --- a/pages/users/[id].tsx +++ b/pages/users/[id].tsx @@ -158,12 +158,7 @@ const UserPage: NextPage = ({ user, bio }) => {

- {user.name} - {user.country && !isInUserEditingMode && ( - - {countries[user.country].emoji} - - )} + {user.name} {isInUserEditingMode && ( )}

+ {user.country && !isInUserEditingMode && ( + + {countries[user.country].emoji} + + )} {isCurrentUser && } {badges.map((b) => ( From 631d30b613fc973d54af254134ea3b2d7f69b3a2 Mon Sep 17 00:00:00 2001 From: shay Date: Sat, 4 Jun 2022 01:03:07 +0200 Subject: [PATCH 5/5] refactor: properly resolve `main` conflict --- pages/users/[id].tsx | 164 +++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 84 deletions(-) diff --git a/pages/users/[id].tsx b/pages/users/[id].tsx index d49ef71..d31b703 100644 --- a/pages/users/[id].tsx +++ b/pages/users/[id].tsx @@ -16,7 +16,6 @@ import Button from "../../components/button"; import { DeNullishFilter, TruncateText } from "../../utility/utils"; import { UserFlairs } from "../../components/profile/flairs"; import countries from "../../utility/countries"; -import Link from "next/link"; import { toast } from "react-toastify"; export const getServerSideProps: GetServerSideProps = async (ctx) => { @@ -156,91 +155,88 @@ const UserPage: NextPage = ({ user, bio }) => {
-
- -
- -
-
- {`${user.name}'s - {isCurrentUser && !isInUserEditingMode && ( - <> -
- -
-
- - - - - -
- - )} -
-
-
-
-

- 15 ? 'text-xl truncate' : 'text-2xl'} font-bold ${isInUserEditingMode ? "mr-2": ""}`}>{user.name} - {isInUserEditingMode && ( - { + const country = e.currentTarget.selectedOptions[0]?.value; + if (!country || country === "null") return; - await fetch(`/api/users/${user.id}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ country }), - }) - }} - > - - {Object.keys(countries).map(code => ( - - ))} - - )} -

- {user.country && !isInUserEditingMode && ( - - {countries[user.country].emoji} - - )} - {isCurrentUser && } + await fetch(`/api/users/${user.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ country }), + }) + }} + > + + {Object.keys(countries).map(code => ( + + ))} + + )} + + {user.country && !isInUserEditingMode && ( + + {countries[user.country].emoji} + + )} + {isCurrentUser && } +
+
+
+ {badges.map((b) => ( + + ))} +
+ +
+
- -
-
- {badges.map((b) => ( - - ))} -
-
- -
-
-
{isInEditingMode ? (