diff --git a/packages/api/src/types/OptionUsersType.ts b/packages/api/src/types/OptionUsersType.ts
index 8c5a2fa9..b2d844a4 100644
--- a/packages/api/src/types/OptionUsersType.ts
+++ b/packages/api/src/types/OptionUsersType.ts
@@ -1,11 +1,23 @@
-import { GetGroupsResponse } from './GroupType';
-import { GetUserResponse } from './UserType';
-
export type GetOptionUsersResponse = {
optionId: string;
registrationId: string | null;
userId: string | null;
- user: GetUserResponse | null;
+ user: {
+ id: string;
+ username: string;
+ firstName: string;
+ lastName: string;
+ } | null;
groupId: string | null;
- group: GetGroupsResponse | null;
+ group: {
+ id: null;
+ users:
+ | {
+ id: string;
+ username: string;
+ firstName: string;
+ lastName: string;
+ }[]
+ | null;
+ } | null;
};
diff --git a/packages/berlin/src/components/header/Header.tsx b/packages/berlin/src/components/header/Header.tsx
index 1123443e..f51d1675 100644
--- a/packages/berlin/src/components/header/Header.tsx
+++ b/packages/berlin/src/components/header/Header.tsx
@@ -113,14 +113,14 @@ function Header() {
)
);
})}
+
+ My proposals
+
Agenda
>
)}
-
- My proposals
-
navigate('/account')}
diff --git a/packages/berlin/src/components/option-card/OptionCard.tsx b/packages/berlin/src/components/option-card/OptionCard.tsx
index 70d32669..d46d441b 100644
--- a/packages/berlin/src/components/option-card/OptionCard.tsx
+++ b/packages/berlin/src/components/option-card/OptionCard.tsx
@@ -12,9 +12,9 @@ type OptionCardProps = {
option: QuestionOption;
numOfVotes: number;
onVote: () => void;
- onUnvote: () => void;
+ onUnVote: () => void;
};
-function OptionCard({ option, numOfVotes, onVote, onUnvote }: OptionCardProps) {
+function OptionCard({ option, numOfVotes, onVote, onUnVote }: OptionCardProps) {
const { eventId, cycleId } = useParams();
const theme = useAppStore((state) => state.theme);
const navigate = useNavigate();
@@ -67,7 +67,7 @@ function OptionCard({ option, numOfVotes, onVote, onUnvote }: OptionCardProps) {
$padding={0}
$color="secondary"
icon={{ src: `/icons/downvote-${theme}.svg`, alt: 'Downvote arrow' }}
- onClick={onUnvote}
+ onClick={onUnVote}
$width={16}
$height={16}
disabled={numOfVotes === 0}
diff --git a/packages/berlin/src/pages/Comments.tsx b/packages/berlin/src/pages/Comments.tsx
index d0541b95..b0c376bb 100644
--- a/packages/berlin/src/pages/Comments.tsx
+++ b/packages/berlin/src/pages/Comments.tsx
@@ -11,14 +11,19 @@ import {
fetchUserVotes,
fetchComments,
postComment,
- // fetchOptionUsers,
+ fetchOptionUsers,
} from 'api';
// Hooks
import useUser from '../hooks/useUser';
// Utils
-import { handleSaveVotes, handleUnvote, handleVote } from '../utils/voting';
+import {
+ handleSaveVotes,
+ handleAvailableHearts,
+ handleLocalUnVote,
+ handleLocalVote,
+} from '../utils/voting';
// Types
import { ResponseUserVotesType } from '../types/CycleType';
@@ -40,15 +45,16 @@ import CommentsColumns from '../components/columns/comments-columns';
import IconButton from '../components/icon-button';
import Textarea from '../components/textarea';
+type LocalUserVotes = ResponseUserVotesType | { optionId: string; numOfVotes: number }[];
+
function Comments() {
const theme = useAppStore((state) => state.theme);
const queryClient = useQueryClient();
const { cycleId, optionId } = useParams();
const { user } = useUser();
- const { availableHearts, setAvailableHearts } = useAppStore((state) => state);
- const [localUserVotes, setLocalUserVotes] = useState<
- ResponseUserVotesType | { optionId: string; numOfVotes: number }[]
- >([]);
+ const availableHearts = useAppStore((state) => state.availableHearts);
+ const setAvailableHearts = useAppStore((state) => state.setAvailableHearts);
+ const [localUserVotes, setLocalUserVotes] = useState([]);
const [localOptionHearts, setLocalOptionHearts] = useState(0);
const [comment, setComment] = useState('');
const [sortOrder, setSortOrder] = useState('desc'); // 'asc' for ascending, 'desc' for descending
@@ -66,17 +72,17 @@ function Comments() {
retry: false,
});
- // const { data: optionUsers } = useQuery({
- // queryKey: ['optionUsers', optionId],
- // queryFn: () => fetchOptionUsers(optionId || ''),
- // enabled: !!optionId,
- // });
+ const { data: optionUsers } = useQuery({
+ queryKey: ['option', optionId, 'users'],
+ queryFn: () => fetchOptionUsers(optionId || ''),
+ enabled: !!optionId,
+ });
const { data: comments } = useQuery({
- queryKey: ['comments', optionId],
+ queryKey: ['option', optionId, 'comments'],
queryFn: () => fetchComments({ optionId: optionId || '' }),
enabled: !!optionId,
- refetchInterval: 5000, // Poll every 5 seconds
+ // refetchInterval: 5000, // Poll every 5 seconds
});
const sortedComments = useMemo(() => {
@@ -97,52 +103,45 @@ function Comments() {
}
}, [optionId, userVotes]);
- const { mutate: mutateVotes } = useMutation({
- mutationFn: postVotes,
- onSuccess: (body) => {
- if (body?.errors?.length) {
- toast.error(`Failed to save votes, ${body?.errors[0].message}`);
- } else if (body?.data.length) {
- queryClient.invalidateQueries({ queryKey: ['votes', cycleId] });
- // this is to update the plural scores in each option
- queryClient.invalidateQueries({ queryKey: ['cycles', cycleId] });
- toast.success('Votes saved successfully!');
- }
- },
- });
-
const { mutate: mutateComments } = useMutation({
mutationFn: postComment,
onSuccess: (body) => {
if (body?.value) {
- queryClient.invalidateQueries({ queryKey: ['comments', optionId] });
+ queryClient.invalidateQueries({ queryKey: ['option', optionId, 'comments'] });
}
},
});
const handleVoteWrapper = (optionId: string) => {
setLocalOptionHearts((prevLocalOptionHearts) => prevLocalOptionHearts + 1);
- handleVote(optionId, availableHearts, setAvailableHearts, setLocalUserVotes);
+ setLocalUserVotes((prevLocalUserVotes) => handleLocalVote(optionId, prevLocalUserVotes));
+ setAvailableHearts(handleAvailableHearts(availableHearts, 'vote'));
};
- const handleUnvoteWrapper = (optionId: string) => {
+ const handleUnVoteWrapper = (optionId: string) => {
setLocalOptionHearts((prevLocalOptionHearts) => Math.max(0, prevLocalOptionHearts - 1));
- handleUnvote(optionId, availableHearts, setAvailableHearts, setLocalUserVotes);
+ setLocalUserVotes((prevLocalUserVotes) => handleLocalUnVote(optionId, prevLocalUserVotes));
+ setAvailableHearts(handleAvailableHearts(availableHearts, 'unVote'));
};
- const handleSaveVotesWrapper = () => {
+ const { mutate: mutateVotes } = useMutation({
+ mutationFn: postVotes,
+ onSuccess: (body) => {
+ if (body?.errors?.length) {
+ toast.error(`Failed to save votes, ${body?.errors[0].message}`);
+ } else if (body?.data.length) {
+ queryClient.invalidateQueries({ queryKey: ['votes', cycleId] });
+ // this is to update the plural scores in each option
+ queryClient.invalidateQueries({ queryKey: ['cycles', cycleId] });
+ toast.success('Votes saved successfully!');
+ }
+ },
+ });
+
+ const handleSaveVoteWrapper = () => {
handleSaveVotes(userVotes, localUserVotes, mutateVotes);
};
- const votesAreDifferent = useMemo(() => {
- if (localUserVotes && userVotes) {
- return (
- localUserVotes[0]?.numOfVotes !==
- userVotes?.find((vote) => vote.optionId === optionId)?.numOfVotes
- );
- }
- }, [localUserVotes, optionId, userVotes]);
-
const handlePostComment = () => {
if (optionId && comment) {
mutateComments({ questionOptionId: optionId, value: comment });
@@ -173,7 +172,7 @@ function Comments() {
$padding={0}
$color="secondary"
icon={{ src: `/icons/downvote-${theme}.svg`, alt: 'Downvote arrow' }}
- onClick={() => handleUnvoteWrapper(option?.id ?? '')}
+ onClick={() => handleUnVoteWrapper(option?.id ?? '')}
$width={16}
$height={16}
disabled={localOptionHearts === 0}
@@ -183,17 +182,18 @@ function Comments() {
{option?.optionTitle}
{option?.optionSubTitle}
- {/*
- Lead author: {option?.user} [// TODO]
-
- Co-authors: [// TODO]
- */}
+ Lead author: {optionUsers?.user?.firstName} {optionUsers?.user?.lastName}
+
+ Co-authors:{' '}
+ {optionUsers.group.users.map((user) => `${(user.firstName, user.lastName)}`)}
+