Skip to content

Commit

Permalink
Candidate Decider - Hide Latency from Listeners through Frontend Stat…
Browse files Browse the repository at this point in the history
…e Updates (#495)

* wip

* Add Ability to Edit Candidate Decider Instance (#491)

* wip

* prettier and fix typo

* remove leads from list

* limit height of modal height to 60% of viewport height and make scrollable

* Remove Extraneous } in ShoutoutsAPI call (#493)

* remove extraneous } in shoutoutsapi request

* remove console.logs in api.ts

* update frontend state for ratings

* [bot] Automatically pull latest data from IDOL backend (#494)

* add support for comments

* remove unused useEffect

* add save button

* pr feedback

---------

Co-authored-by: Cornell DTI GitHub Bot <57517424+dti-github-bot@users.noreply.github.com>
  • Loading branch information
andrew032011 and dti-github-bot authored Sep 26, 2023
1 parent c84e1cb commit 60cda01
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@
.showOtherVotes {
margin-left: 1%;
}

.previousNextButtonContainer {
margin-right: 0.5% !important;
}
78 changes: 70 additions & 8 deletions frontend/src/components/Candidate-Decider/CandidateDecider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { Button, Dropdown, Checkbox } from 'semantic-ui-react';
import CandidateDeciderAPI from '../../API/CandidateDeciderAPI';
import ResponsesPanel from './ResponsesPanel';
Expand All @@ -18,7 +18,7 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => {
const [showOtherVotes, setShowOtherVotes] = useState<boolean>(false);

const userInfo = useSelf();
const instance = useCandidateDeciderInstance(uuid);
const [instance, setInstance] = useCandidateDeciderInstance(uuid);

const getRating = () => {
const rating = instance.candidates[currentCandidate].ratings.find(
Expand All @@ -36,6 +36,17 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => {
return '';
};

const [currentRating, setCurrentRating] = useState<Rating>(0);
const [currentComment, setCurrentComment] = useState<string>('');

useEffect(() => {
if (instance.candidates[currentCandidate]) {
setCurrentRating(getRating());
setCurrentComment(getComment());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentCandidate, instance.candidates]);

const next = () => {
if (currentCandidate === instance.candidates.length - 1) return;
setCurrentCandidate((prev) => prev + 1);
Expand All @@ -48,10 +59,52 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => {

const handleRatingChange = (id: number, rating: Rating) => {
CandidateDeciderAPI.updateRating(instance.uuid, id, rating);
if (userInfo) {
setInstance((instance) => ({
...instance,
candidates: instance.candidates.map((candidate) =>
candidate.id === id
? {
...candidate,
ratings: candidate.ratings.find(
(currRating) => currRating.reviewer.email === userInfo.email
)
? candidate.ratings.map((currRating) =>
currRating.reviewer.email === userInfo.email
? { rating, reviewer: userInfo }
: currRating
)
: [...candidate.ratings, { rating, reviewer: userInfo }]
}
: candidate
)
}));
}
};

const handleCommentChange = (id: number, comment: string) => {
CandidateDeciderAPI.updateComment(instance.uuid, id, comment);
if (userInfo) {
setInstance((instance) => ({
...instance,
candidates: instance.candidates.map((candidate) =>
candidate.id === id
? {
...candidate,
comments: candidate.comments.find(
(currComment) => currComment.reviewer.email === userInfo.email
)
? candidate.comments.map((currComment) =>
currComment.reviewer.email === userInfo.email
? { comment, reviewer: userInfo }
: currComment
)
: [...candidate.comments, { comment, reviewer: userInfo }]
}
: candidate
)
}));
}
};

return instance.candidates.length === 0 ? (
Expand All @@ -76,7 +129,7 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => {
onChange={(_, data) => setCurrentCandidate(data.value as number)}
/>
<span className={styles.ofNum}>of {instance.candidates.length}</span>
<Button.Group>
<Button.Group className={styles.previousNextButtonContainer}>
<Button basic color="blue" disabled={currentCandidate === 0} onClick={previous}>
PREVIOUS
</Button>
Expand All @@ -89,6 +142,16 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => {
NEXT
</Button>
</Button.Group>
<Button
className="ui blue button"
disabled={currentComment === getComment() && currentRating === getRating()}
onClick={() => {
handleRatingChange(currentCandidate, currentRating);
handleCommentChange(currentCandidate, currentComment);
}}
>
Save
</Button>
<Checkbox
className={styles.showOtherVotes}
toggle
Expand All @@ -100,11 +163,10 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => {
<ResponsesPanel
headers={instance.headers}
responses={instance.candidates[currentCandidate].responses}
handleRatingChange={handleRatingChange}
rating={getRating()}
currentCandidate={currentCandidate}
handleCommentChange={handleCommentChange}
comment={getComment()}
currentComment={currentComment}
setCurrentComment={setCurrentComment}
currentRating={currentRating}
setCurrentRating={setCurrentRating}
/>
</div>
<div className={styles.progressContainer}>
Expand Down
80 changes: 27 additions & 53 deletions frontend/src/components/Candidate-Decider/ResponsesPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { useEffect, useState } from 'react';
import { Form, Radio, Button } from 'semantic-ui-react';
import { Dispatch, SetStateAction } from 'react';
import { Form, Radio } from 'semantic-ui-react';
import styles from './ResponsesPanel.module.css';

type Props = {
headers: string[];
responses: string[];
rating: Rating;
handleRatingChange: (id: number, rating: Rating) => void;
comment: string;
handleCommentChange: (id: number, comment: string) => void;
currentCandidate: number;
currentRating: Rating;
setCurrentRating: Dispatch<SetStateAction<Rating>>;
currentComment: string;
setCurrentComment: Dispatch<SetStateAction<string>>;
};

const ratings = [
Expand All @@ -24,11 +23,10 @@ const ratings = [
const ResponsesPanel: React.FC<Props> = ({
headers,
responses,
rating,
handleRatingChange,
currentCandidate,
handleCommentChange,
comment
currentRating,
setCurrentRating,
currentComment,
setCurrentComment
}) => (
<div>
<Form>
Expand All @@ -40,17 +38,13 @@ const ResponsesPanel: React.FC<Props> = ({
name="rating-group"
value={rt.value}
color={rt.color}
checked={rt.value === rating}
onChange={() => handleRatingChange(currentCandidate, rt.value as Rating)}
checked={rt.value === currentRating}
onClick={() => setCurrentRating(rt.value as Rating)}
/>
</Form.Field>
))}
</Form.Group>
<CommentEditor
handleCommentChange={handleCommentChange}
comment={comment}
currentCandidate={currentCandidate}
/>
<CommentEditor currentComment={currentComment} setCurrentComment={setCurrentComment} />
</Form>
{headers.map((header, i) => (
<div key={i} className={styles.questionResponseContainer}>
Expand All @@ -62,40 +56,20 @@ const ResponsesPanel: React.FC<Props> = ({
);

type CommentEditorProps = {
comment: string;
handleCommentChange: (id: number, comment: string) => void;
currentCandidate: number;
currentComment: string;
setCurrentComment: Dispatch<SetStateAction<string>>;
};

const CommentEditor: React.FC<CommentEditorProps> = ({
handleCommentChange,
comment,
currentCandidate
}) => {
const [currentComment, setCurrentComment] = useState<string>(comment);

useEffect(() => setCurrentComment(comment), [comment]);

return (
<div>
<Form.Group inline>
<Form.Input
className="fifteen wide field"
placeholder={'Comment...'}
onChange={(_, data) => setCurrentComment(data.value)}
value={currentComment}
/>
<Button
className="ui blue button"
onClick={() => {
handleCommentChange(currentCandidate, currentComment);
setCurrentComment('');
}}
>
Save
</Button>
</Form.Group>
</div>
);
};
const CommentEditor: React.FC<CommentEditorProps> = ({ currentComment, setCurrentComment }) => (
<div>
<Form.Group inline>
<Form.Input
className="fifteen wide field"
placeholder={'Comment...'}
onChange={(_, data) => setCurrentComment(data.value)}
value={currentComment}
/>
</Form.Group>
</div>
);
export default ResponsesPanel;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, Dispatch, SetStateAction } from 'react';
import { onSnapshot, doc, collection, getDoc, DocumentReference } from 'firebase/firestore';
import { db } from '../../firebase';

Expand Down Expand Up @@ -28,7 +28,9 @@ export type DBCandidateDeciderInstance = {
readonly authorizedRoles: Role[];
isOpen: boolean;
};
const useCandidateDeciderInstance = (uuid: string): CandidateDeciderInstance => {
const useCandidateDeciderInstance = (
uuid: string
): [CandidateDeciderInstance, Dispatch<SetStateAction<CandidateDeciderInstance>>] => {
const [instance, setInstance] = useState<CandidateDeciderInstance>(blankInstance);

useEffect(() => {
Expand Down Expand Up @@ -67,7 +69,7 @@ const useCandidateDeciderInstance = (uuid: string): CandidateDeciderInstance =>
return unsubscribe;
}, [uuid]);

return instance;
return [instance, setInstance];
};

const blankInstance: CandidateDeciderInstance = {
Expand Down

0 comments on commit 60cda01

Please sign in to comment.