file attachments - WIP

This commit is contained in:
Philipinho
2024-01-08 09:56:10 +01:00
parent e594074fda
commit e1bb2632b8
27 changed files with 616 additions and 49 deletions
+4 -1
View File
@@ -1,11 +1,14 @@
import React from 'react';
import { Avatar } from '@mantine/core';
interface UserAvatarProps extends React.ComponentProps<typeof Avatar> {
interface UserAvatarProps {
avatarUrl: string;
name: string;
color?: string;
size?: string;
radius?: string;
style?: any;
component?: any;
}
export const UserAvatar = React.forwardRef<HTMLInputElement, UserAvatarProps>(
@@ -18,20 +18,21 @@ function RecentChanges() {
return (
<div>
{data.map((page) => (
{data
.map((page) => (
<div key={page.id}>
<UnstyledButton component={Link} to={`/p/${page.id}`}
className={classes.page} p="xs">
<Group wrap="nowrap">
<Stack gap="xs" style={{ flex: 1 }}>
<Text fw={500} size="sm">
<Text fw={500} size="md" lineClamp={1}>
{page.title || 'Untitled'}
</Text>
</Stack>
<Text c="dimmed" size="xs">
{format(new Date(page.createdAt), 'PPP')}
<Text c="dimmed" size="xs" fw={500}>
{format(new Date(page.updatedAt), 'PP')}
</Text>
</Group>
</UnstyledButton>
@@ -3,11 +3,15 @@ import AccountNameForm from '@/features/settings/account/settings/components/acc
import ChangeEmail from '@/features/settings/account/settings/components/change-email';
import ChangePassword from '@/features/settings/account/settings/components/change-password';
import { Divider } from '@mantine/core';
import AccountAvatar from '@/features/settings/account/settings/components/account-avatar';
export default function AccountSettings() {
return (
<>
<AccountAvatar />
<AccountNameForm />
<Divider my="lg" />
@@ -0,0 +1,64 @@
import { focusAtom } from 'jotai-optics';
import { currentUserAtom } from '@/features/user/atoms/current-user-atom';
import { useState } from 'react';
import { useAtom } from 'jotai';
import { UserAvatar } from '@/components/ui/user-avatar';
import { FileButton, Button, Text, Popover, Tooltip } from '@mantine/core';
import { uploadAvatar } from '@/features/user/services/user-service';
const userAtom = focusAtom(currentUserAtom, (optic) => optic.prop('user'));
export default function AccountAvatar() {
const [isLoading, setIsLoading] = useState(false);
const [currentUser] = useAtom(currentUserAtom);
const [, setUser] = useAtom(userAtom);
const [file, setFile] = useState<File | null>(null);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const handleFileChange = async (selectedFile: File) => {
if (!selectedFile) {
return;
}
if (previewUrl) {
URL.revokeObjectURL(previewUrl);
}
setFile(selectedFile);
setPreviewUrl(URL.createObjectURL(selectedFile));
try {
setIsLoading(true);
const upload = await uploadAvatar(selectedFile);
console.log(upload);
} catch (err) {
console.log(err);
} finally {
setIsLoading(false);
}
};
return (
<>
<FileButton onChange={handleFileChange} accept="image/png,image/jpeg">
{(props) => (
<Tooltip label="Change photo"
position="bottom"
>
<UserAvatar
{...props}
component="button"
radius="xl"
size="60px"
avatarUrl={previewUrl || currentUser.user.avatarUrl}
name={currentUser.user.name}
style={{ cursor: 'pointer' }}
/>
</Tooltip>
)}
</FileButton>
</>
);
}
@@ -63,15 +63,15 @@ function ChangePasswordForm() {
<PasswordInput
label="Current password"
name="current"
placeholder="Enter your password"
placeholder="Enter your current password"
variant="filled"
mb="md"
{...form.getInputProps('password')}
{...form.getInputProps('current')}
/>
<PasswordInput
label="New password"
placeholder="Enter your password"
placeholder="Enter your new password"
variant="filled"
mb="md"
{...form.getInputProps('password')}
@@ -11,8 +11,20 @@ export async function getUserInfo(): Promise<ICurrentUserResponse> {
return req.data as ICurrentUserResponse;
}
export async function updateUser(data: Partial<IUser>) {
export async function updateUser(data: Partial<IUser>): Promise<IUser> {
const req = await api.post<IUser>('/user/update', data);
return req.data as IUser;
}
export async function uploadAvatar(file: File) {
const formData = new FormData();
formData.append('avatar', file);
const req = await api.post('/attachments/upload/avatar', formData, {
headers: {
'Content-Type': 'multipart/form-data',
}
});
return req.data;
}