From 143687f14d2e91390a4d2a917f4fb6c79476721c Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Fri, 10 Nov 2023 16:22:31 +0100 Subject: [PATCH 1/3] introduce Dialog component --- src/components/Dialog/Dialog.tsx | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/components/Dialog/Dialog.tsx diff --git a/src/components/Dialog/Dialog.tsx b/src/components/Dialog/Dialog.tsx new file mode 100644 index 00000000..1434ff08 --- /dev/null +++ b/src/components/Dialog/Dialog.tsx @@ -0,0 +1,30 @@ +import {Dialog as MuiDialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from '@mui/material' +import {FC, ReactNode} from 'react' + +type DialogProps = { + open: boolean + close: () => void + title?: ReactNode + contentText?: ReactNode + actions?: ReactNode +} + +// inspired by: https://mui.com/material-ui/react-dialog/#alerts +export const Dialog: FC = ({open, close, title, contentText, actions}) => { + return ( + + {title && {title}} + {contentText && ( + + {contentText} + + )} + {actions && {actions}} + + ) +} From fab58a5e8bd34b25f8598d860100f72db3d2debe Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Fri, 10 Nov 2023 16:52:32 +0100 Subject: [PATCH 2/3] comment deletion functionality --- src/components/Clickable/Clickable.tsx | 8 +- src/components/Problems/Discussion.tsx | 131 +++++++++++++++---------- src/types/api/personal.ts | 1 + 3 files changed, 85 insertions(+), 55 deletions(-) diff --git a/src/components/Clickable/Clickable.tsx b/src/components/Clickable/Clickable.tsx index 86503fbf..e4aa1571 100644 --- a/src/components/Clickable/Clickable.tsx +++ b/src/components/Clickable/Clickable.tsx @@ -4,20 +4,20 @@ import {ButtonHTMLAttributes, ComponentProps, FC, ReactNode} from 'react' import styles from './Clickable.module.scss' -interface ButtonProps { +type ButtonProps = { onClick?: () => void disabled?: boolean children: ReactNode - type?: ButtonHTMLAttributes['type'] -} +} & Pick, 'type' | 'autoFocus'> -export const Button: FC = ({children, onClick, disabled, type}) => { +export const Button: FC = ({children, onClick, disabled, type, autoFocus}) => { return ( diff --git a/src/components/Problems/Discussion.tsx b/src/components/Problems/Discussion.tsx index f5eacb47..94bc5603 100644 --- a/src/components/Problems/Discussion.tsx +++ b/src/components/Problems/Discussion.tsx @@ -4,10 +4,12 @@ import clsx from 'clsx' import {FC, useState} from 'react' import {Comment, CommentState} from '@/types/api/competition' +import {Profile} from '@/types/api/personal' import {AuthContainer} from '@/utils/AuthContainer' import {useHasPermissions} from '@/utils/useHasPermissions' import {Button} from '../Clickable/Clickable' +import {Dialog} from '../Dialog/Dialog' import {Loading} from '../Loading/Loading' import styles from './Discussion.module.scss' import {SideContainer} from './SideContainer' @@ -23,25 +25,26 @@ export const Discussion: FC = ({problemId, problemNumber, close const [commentText, setCommentText] = useState('') const [hiddenResponseText, setHiddenResponseText] = useState('') const [hiddenResponseDialogId, sethiddenResponseDialogId] = useState(-1) + const [deleteDialogId, setDeleteDialogId] = useState() const queryKey = ['competition', 'problem', problemId, 'comments'] const {data: commentsData, isLoading: commentsIsLoading} = useQuery({ queryKey, queryFn: () => axios.get(`/api/competition/problem/${problemId}/comments`), }) - const comments = commentsData?.data.map((comment) => ({ - id: comment.id, - can_edit: comment.edit_allowed, - text: comment.text, - state: comment.state, - hidden_response: comment.hidden_response, - posted_by: comment.posted_by_name, - })) + const comments = commentsData?.data const {hasPermissions} = useHasPermissions() const {isAuthed} = AuthContainer.useContainer() + const {data} = useQuery({ + queryKey: ['personal', 'profiles', 'myprofile'], + queryFn: () => axios.get(`/api/personal/profiles/myprofile`), + enabled: isAuthed, + }) + const userId = data?.data.id + const queryClient = useQueryClient() const invalidateCommentsAndCount = async () => { @@ -77,7 +80,7 @@ export const Discussion: FC = ({problemId, problemNumber, close }, }) - const {mutate: deleteComment} = useMutation({ + const {mutate: confirmDeleteComment} = useMutation({ mutationFn: (id: number) => axios.delete(`/api/competition/comment/${id}`), onSuccess: () => { invalidateCommentsAndCount() @@ -91,57 +94,83 @@ export const Discussion: FC = ({problemId, problemNumber, close setHiddenResponseText(e.currentTarget.value) } + const close = () => setDeleteDialogId(undefined) + const agree = () => { + deleteDialogId !== undefined ? confirmDeleteComment(deleteDialogId) : undefined + close() + } + return ( + {/* delete comment dialog */} + + + + + } + />
{commentsIsLoading && } {comments && - comments.map((comment) => ( -
-
-
{comment.posted_by}
-
-
{comment.text}
- {comment.hidden_response && ( - <> -
-
Vedúci:
+ comments.map((comment) => { + const isPostedByMe = userId === comment.posted_by + + return ( +
+
+
{comment.posted_by_name}
+
+
{comment.text}
+ {comment.hidden_response && ( + <> +
+
Vedúci:
+
+
{comment.hidden_response}
+ + )} + {comment.state === CommentState.WaitingForReview &&
* komentár čaká na schválenie
} + {comment.state === CommentState.Hidden &&
* tento komentár nie je verejný
} + {hiddenResponseDialogId === comment.id ? ( +
+