diff --git a/api/resolvers/user.js b/api/resolvers/user.js index 25e6a11365..8d72d47034 100644 --- a/api/resolvers/user.js +++ b/api/resolvers/user.js @@ -136,6 +136,28 @@ export default { if (id) id = Number(id) return await models.user.findUnique({ where: { id, name } }) }, + userByMention: async (parent, { name, itemId }, { models }) => { + let user = null + if (itemId) { + const mentions = await models.mention.findMany({ + where: { + itemId: Number(itemId) + }, + include: { + user: true, + item: true + } + }) + const matchingMention = mentions.find(mention => mention.user?.name === name) + if (matchingMention) { + user = matchingMention.user + } + } + if (!user) { + user = await models.user.findUnique({ where: { name } }) + } + return user + }, users: async (parent, args, { models }) => await models.user.findMany(), nameAvailable: async (parent, { name }, { models, me }) => { diff --git a/api/typeDefs/user.js b/api/typeDefs/user.js index c41bb2676f..05ebd8a036 100644 --- a/api/typeDefs/user.js +++ b/api/typeDefs/user.js @@ -6,6 +6,7 @@ export default gql` me: User settings: User user(id: ID, name: String): User + userByMention(name: String!, itemId: ID): User users: [User!] nameAvailable(name: String!): Boolean! topUsers(cursor: String, when: String, from: String, to: String, by: String, limit: Limit! = ${LIMIT}): UsersNullable! diff --git a/components/text.js b/components/text.js index d2ac1ab5d7..f464c85bc1 100644 --- a/components/text.js +++ b/components/text.js @@ -130,7 +130,7 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child table: Table, p: P, code: Code, - mention: Mention, + mention: (props) => , sub: Sub, item: Item, footnote: Footnote, @@ -147,7 +147,7 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }, img: TextMediaOrLink, embed: (props) => - }), [outlawed, rel, TextMediaOrLink, topLevel]) + }), [outlawed, rel, TextMediaOrLink, topLevel, itemId]) const carousel = useCarousel() @@ -192,15 +192,17 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child ) }, isEqual) -function Mention ({ children, node, href, name, id }) { +function Mention ({ children, node, href, name, id, itemId }) { return ( - - - {children} - + + {({ user }) => ( + + {children} + + )} ) } diff --git a/components/user-popover.js b/components/user-popover.js index 11d7d65bf7..3ed29acc4f 100644 --- a/components/user-popover.js +++ b/components/user-popover.js @@ -1,6 +1,6 @@ -import { USER } from '@/fragments/users' +import { USER, USER_BY_MENTION } from '@/fragments/users' import errorStyles from '@/styles/error.module.css' -import { useLazyQuery } from '@apollo/client' +import { useLazyQuery, useQuery } from '@apollo/client' import classNames from 'classnames' import Link from 'next/link' import HoverablePopover from './hoverable-popover' @@ -22,7 +22,16 @@ function StackingSince ({ since }) { ) } -export default function UserPopover ({ name, children }) { +export default function UserPopover ({ name, itemId, children }) { + const { data: mentionData, loading: mentionLoading } = useQuery( + USER_BY_MENTION, + { + variables: { name, itemId }, + skip: !itemId, + fetchPolicy: 'cache-first' + } + ) + const [getUser, { loading, data }] = useLazyQuery( USER, { @@ -31,17 +40,25 @@ export default function UserPopover ({ name, children }) { } ) + const resolvedUser = mentionData?.userByMention + const popoverUser = resolvedUser || data?.user + const isLoading = loading || (itemId && mentionLoading && !resolvedUser) + const trigger = + typeof children === 'function' + ? children({ user: popoverUser }) + : children + return ( - : !data.user + : !popoverUser ?

USER NOT FOUND

: ( - - + + )} /> diff --git a/fragments/users.js b/fragments/users.js index a1fa8cf71a..8e4b02e4d6 100644 --- a/fragments/users.js +++ b/fragments/users.js @@ -294,6 +294,14 @@ export const USER = gql` } }` +export const USER_BY_MENTION = gql` + ${USER_FIELDS} + query UserByMention($name: String!, $itemId: ID) { + userByMention(name: $name, itemId: $itemId) { + ...UserFields + } + }` + export const USER_WITH_ITEMS = gql` ${USER_FIELDS} ${ITEM_FIELDS}