added profile description editing, fixed light theme and viewer caching

This commit is contained in:
lnn0q 2025-06-17 21:46:40 +03:00
parent 58a211663a
commit c8f68b7486
10 changed files with 187 additions and 18 deletions

View file

@ -24,7 +24,7 @@ export function BookChapterCard({
refetchQueries: [bookChapterListQuery, bookChapterQuery]
});
return (
<Card.Root width="100%" variant="elevated">
<Card.Root width="100%" variant="elevated" bg={{ _light: 'gray.100' }}>
<Card.Body paddingX={4} paddingY={2}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Box>

View file

@ -1,6 +1,6 @@
import { Button, Card, Stack, Text, Wrap } from '@chakra-ui/react';
import isHotkey from 'is-hotkey';
import React, { KeyboardEvent, MouseEvent, useCallback, useMemo } from 'react';
import React, { KeyboardEvent, MouseEvent, useCallback, useEffect, useMemo } from 'react';
import { createEditor, Descendant, Editor, Element as SlateElement, Transforms } from 'slate';
import { withHistory } from 'slate-history';
import {

View file

@ -19,7 +19,7 @@ export function WorkingListCard({
reviewsTotal
}: BookOne) {
return (
<Card.Root width="100%" variant="elevated">
<Card.Root width="100%" variant="elevated" bg={{ _light: 'gray.100' }}>
<Card.Body>
<Stack>
<Stack direction={'row'} justifyContent="space-between">

View file

@ -6,9 +6,21 @@ import { ColorModeProvider, type ColorModeProviderProps } from './color-mode';
export function Provider(props: ColorModeProviderProps) {
const system = createSystem(defaultConfig, {
theme: {
tokens: {}
tokens: {
colors: {
cyan: {
400: {
value: {
base: '#0c5c72',
_dark: '#67e8f9'
} as any // todo: find a better way to overwrite it
}
}
}
}
}
});
return (
<ChakraProvider value={system}>
<Theme colorPalette="cyan">

View file

@ -1,8 +1,26 @@
import { gql } from '@apollo/client';
import { Avatar } from '@app/client/components/ui/avatar';
import { userFragment } from '@app/client/fragments';
import { toFormattedDate } from '@app/client/helpers';
import { useIdentity } from '@app/client/hooks/identity';
import { useToastMutation } from '@app/client/hooks/useToastMutation';
import { useUserOneQuery } from '@app/client/hooks/useUserOneQuery';
import { Card, Heading, HStack, SkeletonCircle, SkeletonText, Stack, Text } from '@chakra-ui/react';
import {
Box,
Button,
Card,
Heading,
HStack,
Icon,
SkeletonCircle,
SkeletonText,
Stack,
Text,
Textarea
} from '@chakra-ui/react';
import { UserProfileUpdateMutation } from '@generated/types';
import { createFileRoute } from '@tanstack/react-router';
import { useState } from 'react';
export const Route = createFileRoute('/profile/$username')({
component: RouteComponent
@ -36,6 +54,16 @@ function UserOverview({
readonly createdAt: string;
};
}) {
const identity = useIdentity();
const { update: userUpdate } = useToastMutation<UserProfileUpdateMutation>({
mutation: userUpdateMutation,
successMsg: 'Profile updated successfully!'
});
const [isEditMode, setIsEditMode] = useState<boolean>(false);
const [description, setDescription] = useState<string>(user.description ?? '');
return (
<Stack width={{ base: '100%', md: '80%' }} maxWidth="840px" gap={3}>
<Stack direction="row" alignItems="start">
@ -45,17 +73,92 @@ function UserOverview({
{user.username}
</Heading>
<Stack direction="row">
<Text fontWeight="bold">joined:</Text>
<Text color="fg.muted">{toFormattedDate({ value: user.createdAt })}</Text>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Stack direction="row">
<Text fontWeight="bold">joined:</Text>
<Text color="fg.muted">{toFormattedDate({ value: user.createdAt })}</Text>
</Stack>
{identity != null && isEditMode && (
<Stack>
<Stack direction="row" alignItems="center" justifyContent="end" gap={1}>
<Button
size="sm"
height={6}
bg="green.500"
padding={0}
onClick={async () => {
await userUpdate({
variables: {
input: {
id: user.id,
description
}
}
});
identity.refetch();
setIsEditMode(false);
}}
>
<Icon>
<i className="nf nf-fa-check" />
</Icon>
</Button>
<Button
size="sm"
height={6}
bg="red.500"
padding={0}
onClick={async () => {
setDescription(user.description ?? '');
setIsEditMode(false);
}}
>
<Icon>
<i className="nf nf-fa-close" />
</Icon>
</Button>
</Stack>
</Stack>
)}
{!isEditMode && identity?.data.id === user.id && (
<Button
size="sm"
height={6}
padding={0}
onClick={() => {
setIsEditMode(true);
}}
>
<Icon>
<i className="nf nf-fa-edit" />
</Icon>
</Button>
)}
</Stack>
</Stack>
</Stack>
<Card.Root variant="subtle" width="100%">
<Card.Body paddingX="3" paddingY="1">
<Text>{user.description ?? 'No user description =('}</Text>
</Card.Body>
</Card.Root>
{isEditMode ? (
<Stack width="100%" borderRadius="md" position="relative">
<Textarea
variant="subtle"
placeholder="Tell us about yourself!"
resize="none"
maxLength={700}
maxLines={10}
fontSize="md"
autoresize
value={description}
onChange={event => setDescription(event.target.value)}
/>
</Stack>
) : (
<Card.Root variant="subtle" width="100%">
<Card.Body paddingX="3" paddingY="1">
<Text>{user.description ?? 'No user description =('}</Text>
</Card.Body>
</Card.Root>
)}
</Stack>
);
}
@ -74,3 +177,12 @@ function UserOverviewSkeleton() {
</Stack>
);
}
const userUpdateMutation = gql`
mutation UserProfileUpdate($input: UserUpdateInput!) {
userUpdate(input: $input) {
...User
}
}
${userFragment}
`;

View file

@ -28,7 +28,7 @@ function BookChapterView({
}) {
const { data } = useQuery<BookChapterViewQuery>(bookChapterQuery, {
variables: { id: chapterId },
fetchPolicy: 'cache-and-network'
fetchPolicy: 'no-cache'
});
const { data: navigationData } = useQuery<BookChapterViewNavigationQuery>(