From b48a493883a248e9efb61e22ce7cdf134b0670a2 Mon Sep 17 00:00:00 2001 From: hanabi Date: Sun, 20 Nov 2022 09:39:56 -0500 Subject: [PATCH 1/2] fix(frontend): fix user page title wonky hydration --- frontend/pages/u/[user]/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/u/[user]/index.tsx b/frontend/pages/u/[user]/index.tsx index c4ddce8..120422c 100644 --- a/frontend/pages/u/[user]/index.tsx +++ b/frontend/pages/u/[user]/index.tsx @@ -30,7 +30,7 @@ export default function Index({ user }: Props) { return ( <> - @{user.username} - pronouns.cc + {`@${user.username} - pronouns.cc`} {isMeUser && (
From f51a1329da82e42073834184822f98edc16d8c2c Mon Sep 17 00:00:00 2001 From: hanabi Date: Sun, 20 Nov 2022 10:04:53 -0500 Subject: [PATCH 2/2] refactor: user page code adjustments --- frontend/components/FieldCard.tsx | 64 ------- frontend/pages/u/[user]/index.tsx | 299 +++++++++++++++++------------- 2 files changed, 167 insertions(+), 196 deletions(-) delete mode 100644 frontend/components/FieldCard.tsx diff --git a/frontend/components/FieldCard.tsx b/frontend/components/FieldCard.tsx deleted file mode 100644 index 12846aa..0000000 --- a/frontend/components/FieldCard.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { - HeartFill, - HandThumbsUp, - HandThumbsDown, - People, - EmojiLaughing, -} from "react-bootstrap-icons"; -import BlueLink from "./BlueLink"; - -import Card from "./Card"; -import type { Field } from "../lib/types"; - -function linkPronoun(input: string) { - if (input.includes(" ") || input.split("/").length !== 5) - return {input}; - - const [sub, obj, possDet, possPro, reflexive] = input.split("/"); - - return ( - - - {sub}/{obj}/{possDet} - - - ); -} - -export default function FieldCard({ - field, - draggable, -}: { - field: Field; - draggable?: boolean; -}) { - return ( - - {field.favourite?.map((entry) => ( -

- {linkPronoun(entry)} -

- ))} - {field.okay && field.okay.length !== 0 && ( -

- {field.okay!.join(", ")} -

- )} - {field.jokingly && field.jokingly.length !== 0 && ( -

- {field.jokingly!.join(", ")} -

- )} - {field.friends_only && field.friends_only.length !== 0 && ( -

- {field.friends_only!.join(", ")} -

- )} - {field.avoid && field.avoid.length !== 0 && ( -

- {field.avoid!.join(", ")} -

- )} -
- ); -} diff --git a/frontend/pages/u/[user]/index.tsx b/frontend/pages/u/[user]/index.tsx index 120422c..ef8ce0c 100644 --- a/frontend/pages/u/[user]/index.tsx +++ b/frontend/pages/u/[user]/index.tsx @@ -1,16 +1,11 @@ import { GetServerSideProps } from "next"; import Head from "next/head"; import fetchAPI from "../../../lib/fetch"; -import { Name, Pronoun, User, WordStatus } from "../../../lib/types"; -import FieldCard from "../../../components/FieldCard"; -import Card from "../../../components/Card"; +import { Field, Name, Pronoun, User, WordStatus } from "../../../lib/types"; import ReactMarkdown from "react-markdown"; -import Image from "next/image"; import { userState } from "../../../lib/state"; import { useRecoilValue } from "recoil"; -import Link from "next/link"; import FallbackImage from "../../../components/FallbackImage"; -import { ReactNode } from "react"; import { EmojiLaughing, HandThumbsDown, @@ -19,150 +14,41 @@ import { People, } from "react-bootstrap-icons"; import BlueLink from "../../../components/BlueLink"; +import React from "react"; +import Card from "../../../components/Card"; interface Props { user: User; } export default function Index({ user }: Props) { - const isMeUser = useRecoilValue(userState)?.id === user.id; - return ( <> {`@${user.username} - pronouns.cc`} - {isMeUser && ( -
- - You are currently viewing your{" "} - public profile. - -
- Edit your profile -
- )} +
-
- {user.avatar_urls && user.avatar_urls.length !== 0 && ( - - )} -
- {user.display_name && ( -

{user.display_name}

- )} -

- @{user.username} -

- {user.bio && ( - - {user.bio} - - )} - {user.links?.length && ( -
- {user.links.map((link, index) => ( - - {link} - - ))} -
- )} -
-
- {user.names?.length > 0 && ( -
- {user.names.map((name, index) => ( - - ))} -
- )} - {user.pronouns?.length > 0 && ( -
- {user.pronouns.map((pronoun, index) => ( - - ))} -
- )} -
- {user.fields?.map((field, index) => ( - - ))} +
+ +
+ + +
); } -const entryIcon = (status: WordStatus) => { - let icon: ReactNode; - - switch (status) { - case WordStatus.Favourite: - icon = ; - break; - case WordStatus.Okay: - icon = ; - break; - case WordStatus.Jokingly: - icon = ; - break; - case WordStatus.FriendsOnly: - icon = ; - break; - case WordStatus.Avoid: - icon = ; - break; - } - - return icon; -}; - -function NameEntry(props: { name: Name }) { - const { name } = props; - - return ( -

- {entryIcon(name.status)} {name.name} -

- ); -} - -function PronounEntry(props: { pronoun: Pronoun }) { - const { pronoun } = props; - - return ( -

- {entryIcon(pronoun.status)}{" "} - {pronoun.display_text ?? - pronoun.pronouns.split("/").slice(0, 2).join("/")} -

- ); -} - export const getServerSideProps: GetServerSideProps = async (context) => { try { const user = await fetchAPI(`/users/${context.params!.user}`); @@ -174,3 +60,152 @@ export const getServerSideProps: GetServerSideProps = async (context) => { return { notFound: true }; } }; + +function IsOwnPageNotice({ user }: { user: User }) { + const isThisMyPage = useRecoilValue(userState)?.id === user.id; + return ( + isThisMyPage || true ? ( +
+ You are currently viewing your public profile. +
+ Edit your profile +
+ ) : <> + ); +} + +function UserAvatar({ user }: { user: User }) { + return ( + user.avatar_urls && user.avatar_urls.length !== 0 ? ( + + ) : <> + ); +} + +function UserInfo({ user }: { user: User }) { + const { display_name, username, bio, links } = user; + return ( +
+ {/* display name */} + {display_name && ( +

{display_name}

+ )} + {/* username */} +

+ @{username} +

+ {/* bio */} + {bio && ( + + {bio} + + )} + {/* links */} + {links?.length && ( +
+ {links.map((link, index) => ( + + {link} + + ))} +
+ )} +
+ ); +} + +function LabelList({ source }: { source: Name[] | Pronoun[] }) { + return ( + source?.length > 0 ? ( +
+ {source.map((label, index) => ( + + ))} +
+ ) : <> + ); +} + +function LabelStatusIcon({ status }: { status: WordStatus }) { + return React.createElement( + { + [WordStatus.Favourite]: HeartFill, + [WordStatus.Okay]: HandThumbsUp, + [WordStatus.Jokingly]: EmojiLaughing, + [WordStatus.FriendsOnly]: People, + [WordStatus.Avoid]: HandThumbsDown, + }[status], + { className: 'inline' } + ); +} + +function LabelsLine({ labels }: { labels: Name[] | Pronoun[] }) { + if (labels.length === 0) return <>; + const status = labels[0].status; + const text = labels + .map(label => + 'name' in label + ? label.name + : label.display_text ?? label.pronouns.split('/').slice(0, 2).join('/')) + .join(', '); + return ( +

+ {text} +

+ ); +} + +function LabelLine({ label }: { label: Name | Pronoun }) { + return ; +} + +function FieldCardGrid({ fields }: { fields: Field[] }) { + return ( +
+ {fields?.map((field, index) => ( + + ))} +
+ ); +} + +const fieldEntryStatus: { [key in string]: WordStatus } = { + favourite: WordStatus.Favourite, + okay: WordStatus.Okay, + jokingly: WordStatus.Jokingly, + friends_only: WordStatus.FriendsOnly, + avoid: WordStatus.Avoid, +}; + +function FieldCard({ + field, + draggable, +}: { + field: Field; + draggable?: boolean; +}) { + return ( + + {Object.entries(fieldEntryStatus).map(([statusName, status], i) => + ({ name, status }))} /> + )} + + ); +}