161 lines
4.9 KiB
TypeScript
161 lines
4.9 KiB
TypeScript
import { Person } from '@mui/icons-material';
|
|
import {
|
|
Alert,
|
|
Avatar,
|
|
Button,
|
|
Card,
|
|
CardActions,
|
|
CardContent,
|
|
CardHeader,
|
|
Dialog,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogContentText,
|
|
DialogTitle,
|
|
Link as MUILink,
|
|
Snackbar,
|
|
Typography,
|
|
} from '@mui/material';
|
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import { Link } from '@tanstack/react-router';
|
|
import { FC, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import Api from '../../api/Api';
|
|
import { PostAuth, PostNonAuth } from '../../types/Post';
|
|
import convertDate from '../../utils/date';
|
|
import PostEditDialog from '../Dialogs/PostEdit/PostEditDialog';
|
|
import ErrorComponent from '../Error/ErrorComponent';
|
|
|
|
interface Props {
|
|
post: PostNonAuth | PostAuth;
|
|
}
|
|
|
|
const Post: FC<Props> = ({ post }) => {
|
|
const [deleteOpen, setDeleteOpen] = useState(false);
|
|
const [editOpen, setEditOpen] = useState(false);
|
|
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const [error, setError] = useState<any>();
|
|
|
|
const deleteMutation = useMutation({
|
|
mutationFn: (id: number) => {
|
|
return Api.deletePost(id);
|
|
},
|
|
});
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader
|
|
avatar={
|
|
'id' in post.user ? (
|
|
post.user.id !== Api.getAuthenticatedUser()?.id ? (
|
|
<MUILink component={Link} to="/profile/$id" params={{ id: post.user.id }}>
|
|
<Avatar alt={post.user.username} src={`storage/${post.user.image}`}>
|
|
<Person />
|
|
</Avatar>
|
|
</MUILink>
|
|
) : (
|
|
<MUILink component={Link} to="/profile">
|
|
<Avatar alt={post.user.username} src={`storage/${post.user.image}`}>
|
|
<Person />
|
|
</Avatar>
|
|
</MUILink>
|
|
)
|
|
) : (
|
|
<Avatar alt={post.user.username} src={`storage/${post.user.image}`}>
|
|
<Person />
|
|
</Avatar>
|
|
)
|
|
}
|
|
title={
|
|
'id' in post.user ? (
|
|
post.user.id !== Api.getAuthenticatedUser()?.id ? (
|
|
<MUILink component={Link} to="/profile/$id" params={{ id: post.user.id }}>
|
|
{post.user.username}
|
|
</MUILink>
|
|
) : (
|
|
<MUILink component={Link} to="/profile">
|
|
{post.user.username}
|
|
</MUILink>
|
|
)
|
|
) : (
|
|
post.user.username
|
|
)
|
|
}
|
|
subheader={convertDate(post.postedAt)}
|
|
/>
|
|
<CardContent>
|
|
<Typography>
|
|
<span dangerouslySetInnerHTML={{ __html: post.content }} />
|
|
</Typography>
|
|
</CardContent>
|
|
|
|
<CardActions>
|
|
{(Api.isAdmin() || ('id' in post.user && post.user.id === Api.getAuthenticatedUser()?.id)) && (
|
|
<>
|
|
<Button size="small" onClick={() => setEditOpen(true)}>
|
|
{t('Edit')}
|
|
</Button>
|
|
<PostEditDialog post={post as PostAuth} open={editOpen} onClose={() => setEditOpen(false)} />
|
|
</>
|
|
)}
|
|
{Api.isAdmin() && (
|
|
<>
|
|
<Button size="small" color="error" onClick={() => setDeleteOpen(true)}>
|
|
{t('Delete')}
|
|
</Button>
|
|
<Dialog open={deleteOpen} onClose={() => setDeleteOpen(false)}>
|
|
<DialogTitle>{t('Confirm post delete title')}</DialogTitle>
|
|
<DialogContent>
|
|
<DialogContentText>{t('Confirm post delete body', { name: post.user.username })}</DialogContentText>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={() => setDeleteOpen(false)} autoFocus variant="contained">
|
|
{t('No')}
|
|
</Button>
|
|
<Button
|
|
variant="outlined"
|
|
color="error"
|
|
onClick={() => {
|
|
deleteMutation.mutate(post.id, {
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: ['posts'],
|
|
});
|
|
},
|
|
onError: setError,
|
|
});
|
|
setDeleteOpen(false);
|
|
}}
|
|
>
|
|
{t('Yes')}
|
|
</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
</>
|
|
)}
|
|
</CardActions>
|
|
<Snackbar
|
|
open={deleteMutation.isError}
|
|
autoHideDuration={2000}
|
|
onClose={() => {
|
|
deleteMutation.reset();
|
|
}}
|
|
TransitionProps={{
|
|
onExited: () => setError(undefined),
|
|
}}
|
|
>
|
|
<Alert severity="error" variant="filled" sx={{ width: '100%' }}>
|
|
{error && <ErrorComponent error={error} context="delete" color="white" />}
|
|
</Alert>
|
|
</Snackbar>
|
|
<Snackbar open={deleteMutation.isPending} message={t('Deleting')} />
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default Post;
|