Skip to content

Commit

Permalink
fixed fetching and started on designing
Browse files Browse the repository at this point in the history
  • Loading branch information
MadsNyl committed Nov 15, 2023
1 parent c2521a2 commit f393d24
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 321 deletions.
14 changes: 7 additions & 7 deletions src/api/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import {
PaginationResponse,
Picture,
PublicRegistration,
Reaction,
ReactionMutate,
Registration,
RequestResponse,
ShortLink,
Expand Down Expand Up @@ -100,7 +102,6 @@ export const USERS_ENDPOINT = 'users';
export const WARNINGS_ENDPOINT = 'warnings';
export const EMOJI_ENDPOINT = 'emojis';


export default {
// Auth
createUser: (item: UserCreate) => IFetch<RequestResponse>({ method: 'POST', url: `${USERS_ENDPOINT}/`, data: item, withAuth: false }),
Expand Down Expand Up @@ -180,12 +181,11 @@ export default {
putNewsItem: (id: number, item: NewsRequired) => IFetch<News>({ method: 'PUT', url: `${NEWS_ENDPOINT}/${String(id)}/`, data: item }),
deleteNewsItem: (id: number) => IFetch<RequestResponse>({ method: 'DELETE', url: `${NEWS_ENDPOINT}/${String(id)}/` }),

// Emojis
addEmoji: (emoji: string, newsId: number, userId?: User['user_id']) =>
IFetch<RequestResponse>({ method: 'POST', url: `${EMOJI_ENDPOINT}/reactions/`, data: { user: userId, emoji: emoji, content_type: 'news', object_id: newsId } }),
deleteEmoji: (reaction_id: string) => IFetch<RequestResponse>({ method: 'DELETE', url: `${EMOJI_ENDPOINT}/reactions/${reaction_id}/` }),
changeEmoji: (reaction_id: string, emoji: string, newsId: number, userId?: User['user_id']) =>
IFetch<RequestResponse>({ method: 'PUT', url: `${EMOJI_ENDPOINT}/reactions/${reaction_id}/`, data: { emoji: emoji } }),
// EmojiReactions
createReaction: (item: ReactionMutate) => IFetch<Reaction>({ method: 'POST', url: `${EMOJI_ENDPOINT}/reactions/`, data: item }),
deleteReaction: (reactionId: Reaction['reaction_id']) => IFetch<RequestResponse>({ method: 'DELETE', url: `${EMOJI_ENDPOINT}/reactions/${reactionId}/` }),
updateReaction: (reactionId: Reaction['reaction_id'], item: ReactionMutate) =>
IFetch<Reaction>({ method: 'PUT', url: `${EMOJI_ENDPOINT}/reactions/${reactionId}/`, data: item }),

// User
getUserData: (userId?: User['user_id']) => IFetch<User>({ method: 'GET', url: `${USERS_ENDPOINT}/${userId || ME_ENDPOINT}/` }),
Expand Down
122 changes: 4 additions & 118 deletions src/components/miscellaneous/NewsListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import { formatDate, urlEncode } from 'utils';
import '../../assets/css/popover.css';
import { useMutation, useQuery, useQueryClient } from 'react-query';

Check warning on line 10 in src/components/miscellaneous/NewsListItem.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

`react-query` import should occur before import of `react-router-dom`

Check warning on line 10 in src/components/miscellaneous/NewsListItem.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'useMutation' is defined but never used


import { News, Reaction } from 'types';

import { addReaction, changeReaction, deleteReaction, useAddReaction, useChangeReaction, useDeleteReaction} from 'hooks/Emojis';
import { useNewsById} from 'hooks/News';
import { useNewsById } from 'hooks/News';
import { useSnackbar } from 'hooks/Snackbar';
import { useUser } from 'hooks/User';

import Paper from 'components/layout/Paper';
Expand All @@ -35,23 +34,14 @@ const EmojiPaper = styled(Paper)(({ theme }) => ({
const NewsListItem = ({ news, sx }: NewsListItemProps) => {
const user = useUser();
const { data: newsDetails, isLoading: newsDetailsLoading } = useNewsById(news.id);
console.log(newsDetails);

const addReaction = useAddReaction(news.id);
const editReaction = useChangeReaction(news.id);
const deleteReaction = useDeleteReaction(news.id);
const showSnackbar = useSnackbar();

const showEmojiPaper = !newsDetailsLoading && newsDetails?.emojis_allowed;
const anchorRef = React.useRef(null);

const [openEmojiList, setOpenEmojiList] = useState(false);
const [popoverMode, setPopoverMode] = useState<'ALL_REACTIONS' | 'EMOJI_LIST'>('EMOJI_LIST');


const onEmojiClick = (emojiData: EmojiClickData, event: MouseEvent) => {
const clickedEmoji = emojiData.emoji;
handleEmojiClick(clickedEmoji);
};

const groupedReactions: Record<string, number> =
newsDetails?.reactions?.reduce((acc, reaction) => {
Expand All @@ -78,33 +68,6 @@ const NewsListItem = ({ news, sx }: NewsListItemProps) => {
setOpenEmojiList(false);
};

const handleEmojiClick = (clickedEmoji: string) => {

const userReaction = user.data?.user_id ? newsDetails?.reactions?.find((r) => r.user === user.data?.user_id) : undefined;

if (userReaction) {
const editReactionHandler = () => editReaction.mutate({ reaction_id: userReaction.reaction_id, emoji: clickedEmoji, userId: user.data?.user_id });
editReactionHandler();
} else {
const addReactionHandler = () => addReaction.mutate({emoji: clickedEmoji, userId: user.data?.user_id});
addReactionHandler();
}

setOpenEmojiList(false);
};

const editEmoji = (reaction_id: string, emoji: string, user_id: any) => {
const editReactionHandler = () => editReaction.mutate({ reaction_id: reaction_id, emoji: emoji, userId: user.data?.user_id });
editReactionHandler();
};

const deleteEmoji = (reaction_id: string) => {
const deleteReactionHandler = () => deleteReaction.mutate(reaction_id);
deleteReactionHandler();
};



return (
<Box sx={{ height: 'fit-content', overflow: 'hidden', ...sx }}>
<ButtonBase
Expand Down Expand Up @@ -152,45 +115,6 @@ const NewsListItem = ({ news, sx }: NewsListItemProps) => {
{news.header}
</Typography>
</Paper>
{showEmojiPaper && (
<Stack sx={{ maxWidth: '1000px', marginLeft: 'auto', display: 'flex', flexDirection: 'row-reverse' }}>
<EmojiPaper>
{top5Reactions.map((emoji, index) => {
const userReactionWithThisEmoji = user.data?.user_id
? newsDetails?.reactions?.find((r) => r.user === user.data?.user_id && r.emoji === emoji)
: undefined;
return (
<span
key={index}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
if (userReactionWithThisEmoji) {
if (emoji === userReactedEmoji) {
deleteEmoji(userReactionWithThisEmoji.reaction_id);
} else {
editEmoji(userReactionWithThisEmoji.reaction_id, emoji, user.data?.user_id);
}
} else {
handleEmojiClick(emoji);
}
}}
style={{
cursor: 'pointer',
backgroundColor: emoji === userReactedEmoji ? 'grey' : 'transparent',
boxShadow: emoji === userReactedEmoji ? '0px 2px 5px rgba(0, 0, 0, 0.1)' : 'none',
padding: '5px',
borderRadius: '4px',
marginRight: '5px',
zIndex: 1000,
}}>
{emoji} {groupedReactions[emoji]}
</span>
);
})}
</EmojiPaper>
</Stack>
)}
</div>
</ButtonBase>
<Popover
Expand All @@ -217,45 +141,7 @@ const NewsListItem = ({ news, sx }: NewsListItemProps) => {
transformOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}>
<Grid container spacing={1}>
{popoverMode === 'EMOJI_LIST' && <EmojiPicker onEmojiClick={onEmojiClick} />}
{popoverMode === 'ALL_REACTIONS' &&
top5Reactions.map((emoji, index) => (
<Grid
item
key={index}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
const userReactionWithThisEmoji = user.data?.user_id
? newsDetails?.reactions?.find((r) => r.user === user.data?.user_id && r.emoji === emoji)
: undefined;
if (userReactionWithThisEmoji) {
if (emoji === userReactedEmoji) {
deleteEmoji(userReactionWithThisEmoji.reaction_id);
} else {
editEmoji(userReactionWithThisEmoji.reaction_id, emoji, user.data?.user_id);
}
} else {
handleEmojiClick(emoji);
}
}}
style={{
textAlign: 'center',
cursor: 'pointer',
backgroundColor: emoji === userReactedEmoji ? 'grey' : 'transparent',
boxShadow: emoji === userReactedEmoji ? '0px 2px 5px rgba(0, 0, 0, 0.1)' : 'none',
padding: '5px',
borderRadius: '4px',
marginRight: '5px',
}}
xs={1}>
{emoji} {groupedReactions[emoji]}
</Grid>
))}
</Grid>
</Popover>
}}></Popover>
</Box>
</Box>
);
Expand Down
193 changes: 193 additions & 0 deletions src/components/miscellaneous/ReactionHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import AddIcon from '@mui/icons-material/Add';
import { Box, Button, Container, Popover, PopoverVirtualElement, Stack, styled, Typography } from '@mui/material';
import EmojiPicker, { EmojiClickData } from 'emoji-picker-react';
import { MouseEvent, useRef, useState } from 'react';

import { News, Reaction } from 'types';

import { useCreateReaction, useDeleteReaction, useUpdateReaction } from 'hooks/EmojiReaction';
import { useSnackbar } from 'hooks/Snackbar';
import { useUser } from 'hooks/User';

import Paper from 'components/layout/Paper';

const EmojiPaper = styled(Paper)(({ theme }) => ({
padding: '8px',
borderRadius: '8px',
backgroundColor: theme.palette.background.paper,
}));

export type ReactionHandlerProps = {
data: News;
};

export const EmojiShowcase = ({ data }: ReactionHandlerProps) => {
const user = useUser();
const showSnackbar = useSnackbar();

const deleteReaction = useDeleteReaction(data.id);
const createReaction = useCreateReaction();

const handleDelete = (reaction_id: string) => {
deleteReaction.mutate(reaction_id, {
onSuccess: () => {
showSnackbar('Reaksjon fjernet', 'success');
},
onError: (e) => {
showSnackbar(e.detail, 'error');
},
});
};

const handleCreate = (emoji: string) => {
createReaction.mutate(
{ emoji: emoji, content_type: 'news', object_id: data.id },
{
onSuccess: () => {
showSnackbar('Reaksjon lagt til', 'success');
},
onError: (e) => {
showSnackbar(e.detail, 'error');
},
},
);
};

const emojiCollections: Record<string, number> = {};

data?.reactions?.forEach((r) => {
emojiCollections[r.emoji] = (emojiCollections[r.emoji] || 0) + 1;
});

const topEmojiCollections = Object.entries(emojiCollections)
.sort((a, b) => b[1] - a[1])
.filter((entry, _index, arr) => entry[1] === arr[0][1])
.map((entry) => ({
emoji: entry[0],
count: entry[1],
}));

const hasReaction = user.data?.user_id ? data?.reactions?.find((r) => r.user === user.data?.user_id) : null;

return (
<Stack direction='row' spacing={1}>
{topEmojiCollections.map((emoji, index) => {
const userReaction = user.data?.user_id ? data?.reactions?.find((r) => r.user === user.data?.user_id && r.emoji === emoji.emoji) : null;

if (!hasReaction) {
return (
<Button key={index} onClick={() => handleCreate(emoji.emoji)} variant='text'>
<Stack direction='row' key={index} spacing={0.5}>
<Typography>{emoji.emoji}</Typography>
<Typography fontSize={12}>{emoji.count}</Typography>
</Stack>
</Button>
);
}
if (userReaction) {
return (
<Button key={index} onClick={() => handleDelete(userReaction.reaction_id)} variant='outlined'>
<Stack direction='row' key={index} spacing={0.5}>
<Typography>{emoji.emoji}</Typography>
<Typography fontSize={12}>{emoji.count}</Typography>
</Stack>
</Button>
);
}

return (
<Stack direction='row' key={index} padding={1} spacing={0.5}>
<Typography>{emoji.emoji}</Typography>
<Typography fontSize={12}>{emoji.count}</Typography>
</Stack>
);
})}
</Stack>
);
};

export const EmojiPickerHandler = ({ data }: ReactionHandlerProps) => {
const user = useUser();
const showSnackbar = useSnackbar();

const createReaction = useCreateReaction();
const updateReaction = useUpdateReaction();

const [anchor, setAnchor] = useState<null | HTMLElement>(null);

const openPopover = (event: MouseEvent<HTMLButtonElement>) => {
setAnchor(event.currentTarget);
};

const closePopover = () => setAnchor(null);

const handleEmojiPick = (emoji: EmojiClickData) => {
const userReaction = user.data?.user_id ? data?.reactions?.find((r) => r.user === user.data?.user_id) : null;

if (userReaction) {
updateReaction.mutate(
{ reaction_id: userReaction.reaction_id, emoji: emoji.emoji, content_type: 'news', object_id: data.id },
{
onSuccess: () => {
showSnackbar('Reaksjon oppdatert', 'success');
closePopover();
},
onError: (e) => {
showSnackbar(e.detail, 'error');
closePopover();
},
},
);
} else {
createReaction.mutate(
{ emoji: emoji.emoji, content_type: 'news', object_id: data.id },
{
onSuccess: () => {
showSnackbar('Reaksjon lagt til', 'success');
closePopover();
},
onError: (e) => {
showSnackbar(e.detail, 'error');
closePopover();
},
},
);
}
};

return (
<Container>
<Button onClick={openPopover} variant='outlined'>
<AddIcon />
</Button>

<Popover
anchorEl={anchor}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
onClose={closePopover}
open={Boolean(anchor)}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}>
<EmojiPicker onEmojiClick={handleEmojiPick} />
</Popover>
</Container>
);
};

export const ReactionHandler = ({ data }: ReactionHandlerProps) => {
return (
<Stack alignItems='center' direction='row' spacing={1}>
{data.reactions?.length ? (
<EmojiPaper>
<EmojiShowcase data={data} />
</EmojiPaper>
) : null}
<EmojiPickerHandler data={data} />
</Stack>
);
};
Loading

0 comments on commit f393d24

Please sign in to comment.