Skip to content

Commit

Permalink
lock interactions (#579)
Browse files Browse the repository at this point in the history
* add comments to results page

* disable leave group

* disable voting on comments page
  • Loading branch information
diegoalzate authored Jun 3, 2024
1 parent 392e1af commit 24a9b59
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 103 deletions.
2 changes: 0 additions & 2 deletions packages/berlin/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,6 @@ const router = (queryClient: QueryClient) =>
loader: ({ params }) =>
redirectToCycleIfOpen(queryClient, params.eventId, params.cycleId),
path: ':cycleId/results',
loader: ({ params }) =>
redirectToCycleIfOpen(queryClient, params.eventId, params.cycleId),
Component: Results,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ function GroupCard({ userToGroup, theme, onLeaveGroup }: GroupCardProps) {
<Body>No secret</Body>
)}
<Dialog
trigger={<Button $alignSelf="flex-start">Leave</Button>}
trigger={
<Button disabled $alignSelf="flex-start">
Leave
</Button>
}
title="Are you sure?"
description={`This action cannot be undone. This will remove you from group ${userToGroup.group.name}.`}
onActionClick={() => onLeaveGroup(userToGroup.id)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import IconButton from '../../icon-button';

// Styled Components
import { Card } from './ResultsTable.styled';
import { useNavigate } from 'react-router-dom';

type ResultsTableProps = {
$expanded: boolean;
eventId?: string;
cycleId?: string;
option: {
optionTitle: string;
pluralityScore: string;
Expand All @@ -35,9 +38,9 @@ type ResultsTableProps = {
onClick: () => void;
};

function ResultsTable({ $expanded, option, onClick }: ResultsTableProps) {
function ResultsTable({ $expanded, option, onClick, cycleId, eventId }: ResultsTableProps) {
const theme = useAppStore((state) => state.theme);

const navigate = useNavigate();
const formattedQuadraticScore = useMemo(() => {
const score = parseFloat(option.quadraticScore);
return score % 1 === 0 ? score.toFixed(0) : score.toFixed(3);
Expand All @@ -54,6 +57,10 @@ function ResultsTable({ $expanded, option, onClick }: ResultsTableProps) {
enabled: !!option.id,
});

const handleCommentsClick = () => {
navigate(`/events/${eventId}/cycles/${cycleId}/options/${option.id}`);
};

return (
<Card
$expanded={$expanded}
Expand Down Expand Up @@ -85,6 +92,16 @@ function ResultsTable({ $expanded, option, onClick }: ResultsTableProps) {
<Body>
<Bold>Voter affiliations:</Bold> {option.listOfGroupNames.join(', ')}
</Body>
<Body>
<IconButton
$padding={0}
$color="secondary"
icon={{ src: `/icons/comments-${theme}.svg`, alt: 'Comments icon' }}
onClick={handleCommentsClick}
$width={24}
$height={24}
/>
</Body>
</FlexColumn>
</Card>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/berlin/src/pages/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ function AccountForm({
icon={{ src: `/icons/add-${theme}.svg`, alt: 'Add icon' }}
/>
</FlexColumn>
<Button type="submit" disabled={isSubmitting}>
<Button type="submit" disabled={isSubmitting || true}>
Submit
</Button>
</FlexColumn>
Expand Down
178 changes: 85 additions & 93 deletions packages/berlin/src/pages/Comments.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
// React and third-party libraries
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { useEffect, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
import { useMemo, useState } from 'react';

// API
import {
fetchOption,
postVotes,
fetchUserVotes,
fetchComments,
postComment,
fetchOptionUsers,
} from 'api';
import { fetchOption, fetchComments, postComment, fetchOptionUsers } from 'api';

// Hooks
import useUser from '../hooks/useUser';
// import useUser from '../hooks/useUser';

// Utils
import {
handleSaveVotes,
handleAvailableHearts,
handleLocalUnVote,
handleLocalVote,
} from '../utils/voting';
// import {
// handleSaveVotes,
// handleAvailableHearts,
// handleLocalUnVote,
// handleLocalVote,
// } from '../utils/voting';

// Store
import { useAppStore } from '../store';
Expand All @@ -41,17 +33,17 @@ import CommentsTable from '../components/tables/comment-table';
import CommentsColumns from '../components/columns/comments-columns';
import IconButton from '../components/icon-button';
import Textarea from '../components/textarea';
import { INITIAL_HEARTS } from '../utils/constants';
// import { INITIAL_HEARTS } from '../utils/constants';

type LocalUserVotes = { optionId: string; numOfVotes: number }[];
// type LocalUserVotes = { optionId: string; numOfVotes: number }[];

function Comments() {
const theme = useAppStore((state) => state.theme);
const queryClient = useQueryClient();
const { cycleId, optionId } = useParams();
const { user } = useUser();
const [localUserVotes, setLocalUserVotes] = useState<LocalUserVotes>([]);
const [localOptionHearts, setLocalOptionHearts] = useState(0);
const { optionId } = useParams();
// const { user } = useUser();
// const [localUserVotes, setLocalUserVotes] = useState<LocalUserVotes>([]);
// const [localOptionHearts, setLocalOptionHearts] = useState(0);
const [comment, setComment] = useState('');
const [sortOrder, setSortOrder] = useState('desc'); // 'asc' for ascending, 'desc' for descending

Expand All @@ -61,16 +53,16 @@ function Comments() {
enabled: !!optionId,
});

const availableHearts =
useAppStore((state) => state.availableHearts[option?.questionId || '']) ?? INITIAL_HEARTS;
const setAvailableHearts = useAppStore((state) => state.setAvailableHearts);
// const availableHearts =
// useAppStore((state) => state.availableHearts[option?.questionId || '']) ?? INITIAL_HEARTS;
// const setAvailableHearts = useAppStore((state) => state.setAvailableHearts);

const { data: userVotes } = useQuery({
queryKey: ['votes', cycleId],
queryFn: () => fetchUserVotes(cycleId || ''),
enabled: !!user?.id && !!cycleId,
retry: false,
});
// const { data: userVotes } = useQuery({
// queryKey: ['votes', cycleId],
// queryFn: () => fetchUserVotes(cycleId || ''),
// enabled: !!user?.id && !!cycleId,
// retry: false,
// });

const { data: optionUsers } = useQuery({
queryKey: ['option', optionId, 'users'],
Expand Down Expand Up @@ -99,19 +91,19 @@ function Comments() {
});
}, [comments, sortOrder]);

useEffect(() => {
if (optionId) {
const sumOfAllVotes = userVotes?.reduce((acc, option) => acc + option.numOfVotes, 0) || 0;
const hearts = userVotes?.find((option) => optionId === option.optionId)?.numOfVotes || 0;
setLocalOptionHearts(hearts);
setLocalUserVotes([{ optionId: optionId, numOfVotes: hearts }]);
// update the available hearts
setAvailableHearts({
questionId: option?.questionId ?? '',
hearts: Math.max(0, INITIAL_HEARTS - sumOfAllVotes),
});
}
}, [optionId, userVotes, setAvailableHearts, option?.questionId]);
// useEffect(() => {
// if (optionId) {
// const sumOfAllVotes = userVotes?.reduce((acc, option) => acc + option.numOfVotes, 0) || 0;
// const hearts = userVotes?.find((option) => optionId === option.optionId)?.numOfVotes || 0;
// setLocalOptionHearts(hearts);
// setLocalUserVotes([{ optionId: optionId, numOfVotes: hearts }]);
// // update the available hearts
// setAvailableHearts({
// questionId: option?.questionId ?? '',
// hearts: Math.max(0, INITIAL_HEARTS - sumOfAllVotes),
// });
// }
// }, [optionId, userVotes, setAvailableHearts, option?.questionId]);

const { mutate: mutateComments } = useMutation({
mutationFn: postComment,
Expand All @@ -122,51 +114,51 @@ function Comments() {
},
});

const handleVoteWrapper = (optionId: string) => {
if (availableHearts === 0) {
toast.error('No hearts left to give');
return;
}

setLocalOptionHearts((prevLocalOptionHearts) => prevLocalOptionHearts + 1);
setLocalUserVotes((prevLocalUserVotes) => handleLocalVote(optionId, prevLocalUserVotes));
setAvailableHearts({
questionId: option?.questionId ?? '',
hearts: handleAvailableHearts(availableHearts, 'vote'),
});
};

const handleUnVoteWrapper = (optionId: string) => {
if (availableHearts === INITIAL_HEARTS) {
toast.error('No votes to left to remove');
return;
}

setLocalOptionHearts((prevLocalOptionHearts) => Math.max(0, prevLocalOptionHearts - 1));
setLocalUserVotes((prevLocalUserVotes) => handleLocalUnVote(optionId, prevLocalUserVotes));
setAvailableHearts({
questionId: option?.questionId ?? '',
hearts: handleAvailableHearts(availableHearts, 'unVote'),
});
};

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 handleVoteWrapper = (optionId: string) => {
// if (availableHearts === 0) {
// toast.error('No hearts left to give');
// return;
// }

// setLocalOptionHearts((prevLocalOptionHearts) => prevLocalOptionHearts + 1);
// setLocalUserVotes((prevLocalUserVotes) => handleLocalVote(optionId, prevLocalUserVotes));
// setAvailableHearts({
// questionId: option?.questionId ?? '',
// hearts: handleAvailableHearts(availableHearts, 'vote'),
// });
// };

// const handleUnVoteWrapper = (optionId: string) => {
// if (availableHearts === INITIAL_HEARTS) {
// toast.error('No votes to left to remove');
// return;
// }

// setLocalOptionHearts((prevLocalOptionHearts) => Math.max(0, prevLocalOptionHearts - 1));
// setLocalUserVotes((prevLocalUserVotes) => handleLocalUnVote(optionId, prevLocalUserVotes));
// setAvailableHearts({
// questionId: option?.questionId ?? '',
// hearts: handleAvailableHearts(availableHearts, 'unVote'),
// });
// };

// 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 handlePostComment = () => {
if (optionId && comment) {
Expand All @@ -183,7 +175,7 @@ function Comments() {
<FlexColumn $gap="2rem">
<BackButton />
<FlexColumn>
<FlexRow style={{ maxWidth: '4rem' }}>
{/* <FlexRow style={{ maxWidth: '4rem' }}>
<FlexColumn $gap="-4px" style={{ maxWidth: '1rem' }}>
<IconButton
$padding={0}
Expand All @@ -205,7 +197,7 @@ function Comments() {
/>
</FlexColumn>
<Subtitle>{localOptionHearts}</Subtitle>
</FlexRow>
</FlexRow> */}
<Subtitle>{option?.optionTitle}</Subtitle>
<Body>{option?.optionSubTitle}</Body>
<Body>
Expand All @@ -218,7 +210,7 @@ function Comments() {
)}
</Body>
</FlexColumn>
<Button onClick={handleSaveVoteWrapper}>Save votes</Button>
{/* <Button onClick={handleSaveVoteWrapper}>Save votes</Button> */}
<Form>
<Textarea
label="Leave a comment:"
Expand Down
4 changes: 3 additions & 1 deletion packages/berlin/src/pages/PublicGroupRegistration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ function PublicGroupRegistration() {
/>
)}
/>
<Button type="submit">Join group</Button>
<Button disabled type="submit">
Join group
</Button>
</Form>
</FlexColumn>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/berlin/src/pages/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ function RegisterForm(props: {
/>
))}
</Form>
<Button onClick={handleSubmit(onSubmit)} disabled={isSubmitting || isPending}>
<Button onClick={handleSubmit(onSubmit)} disabled={isSubmitting || isPending || true}>
Save
</Button>
</FlexColumn>
Expand Down
2 changes: 2 additions & 0 deletions packages/berlin/src/pages/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ function Results() {
key={option.id}
$expanded={expandedIndex === index}
option={option}
cycleId={cycleId}
eventId={eventId}
onClick={() => setExpandedIndex(expandedIndex === index ? null : index)}
/>
))}
Expand Down
10 changes: 8 additions & 2 deletions packages/berlin/src/pages/SecretGroupRegistration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ function SecretGroupRegistration() {
open={isDialogOpen}
onOpenChange={setIsDialogOpen}
trigger={
<Button style={{ marginTop: 'auto' }} onClick={() => setIsDialogOpen(true)}>
<Button
disabled
style={{ marginTop: 'auto' }}
onClick={() => setIsDialogOpen(true)}
>
{groups.create.buttonText}
</Button>
}
Expand Down Expand Up @@ -174,7 +178,9 @@ function SecretGroupRegistration() {
errors={errors?.secret?.message ? [errors.secret.message] : []}
required
/>
<Button type="submit">{groups.join.buttonText}</Button>
<Button disabled type="submit">
{groups.join.buttonText}
</Button>
</Form>
</FlexColumn>
</FlexRowToColumn>
Expand Down

0 comments on commit 24a9b59

Please sign in to comment.