diff --git a/app/components/play/GroupMembers.tsx b/app/components/play/GroupMembers.tsx index eb5762c46..0b776b2df 100644 --- a/app/components/play/GroupMembers.tsx +++ b/app/components/play/GroupMembers.tsx @@ -2,6 +2,7 @@ import type { LookingLoaderDataGroup } from "~/routes/play/looking"; import { layoutIcon } from "~/utils"; import { oldSendouInkUserProfile } from "~/utils/urls"; import { Avatar } from "../Avatar"; +import { Popover } from "../Popover"; import { WeaponImage } from "../WeaponImage"; export function GroupMembers({ @@ -88,6 +89,9 @@ function Contents({ members }: { members: LookingLoaderDataGroup["members"] }) { ))}{" "} )} +
+ {member.miniBio && {member.miniBio}} +
); })} diff --git a/app/constants.ts b/app/constants.ts index 1b7e04f00..c738f7660 100644 --- a/app/constants.ts +++ b/app/constants.ts @@ -22,6 +22,8 @@ export const MMR_TOPX_VISIBILITY_CUTOFF = 50; export const LFG_AMOUNT_OF_STAGES_TO_GENERATE = 7; +export const MINI_BIO_MAX_LENGTH = 280; + export const CLOSE_MMR_LIMIT = 250; export const BIT_HIGHER_MMR_LIMIT = 750; diff --git a/app/core/play/utils.ts b/app/core/play/utils.ts index 825d6c63c..bef7ab29e 100644 --- a/app/core/play/utils.ts +++ b/app/core/play/utils.ts @@ -178,11 +178,14 @@ export function otherGroupsForResponse({ ownGroup.ranked && group.ranked && lookingForMatch ? undefined : group.members.map((m) => { - const { skill, ...rest } = m.user; - return { - ...rest, - MMR: skillArrayToMMR(skill), + miniBio: m.user.miniBio ?? undefined, + discordAvatar: m.user.discordAvatar, + discordId: m.user.discordId, + discordName: m.user.discordName, + id: m.user.id, + captain: m.captain, + MMR: skillArrayToMMR(m.user.skill), }; }), ranked: ranked(), diff --git a/app/models/User.server.ts b/app/models/User.server.ts index 0a355683e..f5a86f714 100644 --- a/app/models/User.server.ts +++ b/app/models/User.server.ts @@ -19,3 +19,13 @@ export function findTrusters(userId: string) { export function findById(userId: string) { return db.user.findUnique({ where: { id: userId } }); } + +export function update({ + userId, + miniBio, +}: { + userId: string; + miniBio: Nullable; +}) { + return db.user.update({ where: { id: userId }, data: { miniBio } }); +} diff --git a/app/routes/play.tsx b/app/routes/play.tsx index 2381fdd8a..cbbc7a2d0 100644 --- a/app/routes/play.tsx +++ b/app/routes/play.tsx @@ -35,12 +35,7 @@ export default function PlayLayoutPage() { )} {user && ( - + Settings )} diff --git a/app/routes/play/looking.tsx b/app/routes/play/looking.tsx index 4f07dc363..33ca73d1d 100644 --- a/app/routes/play/looking.tsx +++ b/app/routes/play/looking.tsx @@ -219,6 +219,7 @@ export type LookingLoaderDataGroup = { weapons?: string[]; peakXP?: number; peakLP?: number; + miniBio?: string; })[]; MMRRelation?: "LOWER" | "BIT_LOWER" | "CLOSE" | "BIT_HIGHER" | "HIGHER"; ranked?: boolean; @@ -264,12 +265,14 @@ export const loader: LoaderFunction = async ({ context }) => { ownGroup: { id: ownGroup.id, members: ownGroupWithMembers.members.map((m) => { - const { skill, ...rest } = m.user; - return { - ...rest, + miniBio: m.user.miniBio ?? undefined, + discordAvatar: m.user.discordAvatar, + discordId: m.user.discordId, + discordName: m.user.discordName, + id: m.user.id, captain: m.captain, - MMR: skillArrayToMMR(skill), + MMR: skillArrayToMMR(m.user.skill), }; }), ranked: ownGroup.ranked ?? undefined, diff --git a/app/routes/play/match.$id.tsx b/app/routes/play/match.$id.tsx index 28c9a22a9..6a7b93e80 100644 --- a/app/routes/play/match.$id.tsx +++ b/app/routes/play/match.$id.tsx @@ -58,9 +58,7 @@ export const meta: MetaFunction = ({ title: data?.isOwnMatch ? makeTitle( `vs. ${listToUserReadableString( - data.groups[1].members.map( - (u) => `${u.discordName}#${u.discordDiscriminator}` - ) + data.groups[1].members.map((u) => u.discordName) )}` ) : "Match", diff --git a/app/routes/play/settings.tsx b/app/routes/play/settings.tsx index 1bec9b48c..f58e33d6a 100644 --- a/app/routes/play/settings.tsx +++ b/app/routes/play/settings.tsx @@ -1,3 +1,106 @@ +import clsx from "clsx"; +import * as React from "react"; +import { + ActionFunction, + Form, + json, + LinksFunction, + MetaFunction, + useLoaderData, + useTransition, +} from "remix"; +import { Button } from "~/components/Button"; +import { MINI_BIO_MAX_LENGTH } from "~/constants"; +import styles from "~/styles/play-settings.css"; +import { + falsyToNull, + makeTitle, + parseRequestFormData, + requireUser, +} from "~/utils"; +import * as User from "~/models/User.server"; +import { z } from "zod"; + +export const meta: MetaFunction = () => { + return { + title: makeTitle("SendouQ settings"), + }; +}; + +export const links: LinksFunction = () => { + return [{ rel: "stylesheet", href: styles }]; +}; + +const settingsActionSchema = z.object({ + miniBio: z.preprocess( + falsyToNull, + z.string().max(MINI_BIO_MAX_LENGTH).nullable() + ), +}); + +export const action: ActionFunction = async ({ request, context }) => { + const user = requireUser(context); + const data = await parseRequestFormData({ + request, + schema: settingsActionSchema, + }); + + await User.update({ userId: user.id, miniBio: data.miniBio }); + + return null; +}; + +export type SettingsLoaderData = { + miniBio?: string; +}; + +export const loader: ActionFunction = async ({ context }) => { + const user = requireUser(context); + + const { miniBio } = (await User.findById(user.id)) ?? {}; + + return json({ miniBio: miniBio ?? undefined }); +}; + export default function PlaySettingsPage() { - return

Coming SOON

; + const data = useLoaderData(); + const transition = useTransition(); + const [miniBio, setMiniBio] = React.useState(data.miniBio ?? ""); + + return ( +
+
+ +
+ Include any information here that is useful for others to decide if + they should group up with you. Especially anything that gives an idea + about your current skill level. +
+