diff --git a/app/client/fragments.tsx b/app/client/fragments.tsx index 3e65d51..4d9b582 100644 --- a/app/client/fragments.tsx +++ b/app/client/fragments.tsx @@ -7,6 +7,16 @@ export const sessionFragment = gql` } `; +export const userFragment = gql` + fragment User on User { + id + username + description + createdAt + updatedAt + } +`; + export const bookFragment = gql` fragment Book on Book { id diff --git a/app/client/hooks/useUserOneQuery.tsx b/app/client/hooks/useUserOneQuery.tsx index ca9ba64..7e7b68b 100644 --- a/app/client/hooks/useUserOneQuery.tsx +++ b/app/client/hooks/useUserOneQuery.tsx @@ -1,7 +1,14 @@ import { ApolloError, ApolloQueryResult, gql, OperationVariables, useQuery } from '@apollo/client'; import { UserOneQuery } from '@generated/types'; +import { userFragment } from '../fragments'; -export function useUserOneQuery({ id, skip }: { id?: string; skip?: boolean }): { +export function useUserOneQuery({ + input, + skip +}: { + readonly input: { readonly id: string } | { readonly username: string }; + readonly skip?: boolean; +}): { data: UserOneQuery | undefined; loading: boolean; error: ApolloError | undefined; @@ -10,7 +17,7 @@ export function useUserOneQuery({ id, skip }: { id?: string; skip?: boolean }): ) => Promise>; } { const { data, loading, error, refetch } = useQuery(query, { - variables: { id }, + variables: { input }, skip }); return { @@ -22,12 +29,10 @@ export function useUserOneQuery({ id, skip }: { id?: string; skip?: boolean }): } const query = gql` - query UserOne($id: ID!) { - userOne(id: $id) { - id - username - createdAt - updatedAt + query UserOne($input: UserOneInput!) { + userOne(input: $input) { + ...User } } + ${userFragment} `; diff --git a/app/client/pages/profile/$username.tsx b/app/client/pages/profile/$username.tsx index ef20109..7e97e6b 100644 --- a/app/client/pages/profile/$username.tsx +++ b/app/client/pages/profile/$username.tsx @@ -1,5 +1,8 @@ -import {Stack} from '@chakra-ui/react'; -import {createFileRoute} from '@tanstack/react-router'; +import { Avatar } from '@app/client/components/ui/avatar'; +import { toFormattedDate } from '@app/client/helpers'; +import { useUserOneQuery } from '@app/client/hooks/useUserOneQuery'; +import { Card, Heading, HStack, SkeletonCircle, SkeletonText, Stack, Text } from '@chakra-ui/react'; +import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/profile/$username')({ component: RouteComponent @@ -7,5 +10,67 @@ export const Route = createFileRoute('/profile/$username')({ function RouteComponent() { const { username } = Route.useParams(); - return {`Hello, "${username}"!`}; + + const { data } = useUserOneQuery({ + input: { + username + } + }); + + if (data == null) return ; + + return ( + + + + ); +} + +function UserOverview({ + user +}: { + readonly user: { + readonly id: string; + readonly username: string; + readonly description?: string | null; + readonly createdAt: string; + }; +}) { + return ( + + + + + + {user.username} + + + + joined: + {toFormattedDate({ value: user.createdAt })} + + + + + + {user.description ?? 'No user description =('} + + + + ); +} + +function UserOverviewSkeleton() { + return ( + + + + + + + + + + + ); } diff --git a/app/server/graphql/resolvers/userOneResolver.ts b/app/server/graphql/resolvers/userOneResolver.ts index e08cc1f..e52031b 100644 --- a/app/server/graphql/resolvers/userOneResolver.ts +++ b/app/server/graphql/resolvers/userOneResolver.ts @@ -5,9 +5,17 @@ import { toUserSchema } from './mappers/userMapper'; export async function UserOneResolver( _: any, - { id }: QueryUserOneArgs, + { input }: QueryUserOneArgs, { identity }: IdentityContext ): Promise { - const model = await prisma.user.findUniqueOrThrow({ where: { id } }); + if (input.id == null && input.username == null) throw new Error('Invalid user input.'); + if (input.id != null && input.username != null) throw new Error('Invalid user input.'); + + const model = await prisma.user.findUniqueOrThrow({ + where: { + id: input.id != null ? input.id : undefined, + username: input.username != null ? input.username : undefined + } + }); return toUserSchema(model); } diff --git a/app/server/graphql/schema.graphql b/app/server/graphql/schema.graphql index 8aa55d3..98d8886 100644 --- a/app/server/graphql/schema.graphql +++ b/app/server/graphql/schema.graphql @@ -3,7 +3,7 @@ scalar JSON type Query { identity: Identity! - userOne(id: ID!): User! + userOne(input: UserOneInput!): User! bookOne(id: ID!): Book! bookMany(input: BookManyInput!): BookManyOutput! bookChapterOne(id: ID!): BookChapter! @@ -58,6 +58,11 @@ type User { updatedAt: String! } +input UserOneInput { + id: ID + username: String +} + input PaginationFilterInput { terms: String offset: Int