Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/judge form #66

Merged
merged 16 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.container {
display: flex;
flex-direction: column;
}
53 changes: 53 additions & 0 deletions app/(pages)/judges/_components/ScoringForm/ScoringForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use client';
import { useState } from 'react';
import styles from './ScoringForm.module.scss';
import TeamBlock from './ScoringSubComponents/TeamBlock';
import ScoringInput from './ScoringSubComponents/ScoreInput';
import Comments from './ScoringSubComponents/Comments';

export default function ScoringForm() {
const generalScoreNames = [
'Social Good',
'Technical Complexity',
'Design',
'Creativity',
'Presentation',
];

/* retrieve these from backend */
const trackScoreNames = [
'Best Social Hack',
'Best Beginner Hack',
'Best Design Hack',
'Best Usage of MongoDB',
];

// prefils the map with all the categories and sets the scores to -1 to
// assist in error handling

const initialCategoryScores = new Map();
[...generalScoreNames, ...trackScoreNames].forEach((category) => {
initialCategoryScores.set(category, -1);
});

const [categoryScores, setCategoryScores] = useState(initialCategoryScores);

return (
<div className={styles.container}>
<TeamBlock />
<ScoringInput
inputNameHeader="Overall Scoring"
inputScoreNames={generalScoreNames}
categoryScores={categoryScores}
setCategoryScores={setCategoryScores}
/>
<ScoringInput
inputNameHeader="Specific Tracks"
inputScoreNames={trackScoreNames}
categoryScores={categoryScores}
setCategoryScores={setCategoryScores}
/>
<Comments categoryScores={categoryScores} />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.commentContainer {
display: flex;
flex-direction: column;
background-color: #CEE7F4;
align-items: center;
width: 100%;
.commentTitle {
width: 91%;
color: #000;
font-family: "Proxima Nova";
font-size: 32px;
font-style: normal;
font-weight: 600;
line-height: normal;
margin-top: 64px;
margin-bottom: 7px;
}

.commentDescription {
width: 91%;
color: #000;
font-family: "DM Sans";
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: normal;
margin-bottom: 15.5px;
}
.commentBox {
width: 91%;
height: 170px;
margin-bottom: 48px;
padding: 15.5px;
resize: none;
border-radius: 7.748px;
background: #FFF;
}
.submitButton {
width: 91%;
height: 46px;
margin-bottom: 7px;

color: #173A52;
font-family: "Proxima Nova";
font-size: 18px;
font-style: normal;
font-weight: 700;
line-height: normal;
letter-spacing: 0.36px;

border-radius: 15.497px;
border: 2px solid #FFC370;
background: #FFC53D;
}
.submitButtonDone {
width: 91%;
height: 46px;
margin-bottom: 7px;

color: #173A52;
font-family: "Proxima Nova";
font-size: 18px;
font-style: normal;
font-weight: 700;
line-height: normal;
letter-spacing: 0.36px;

border-radius: 15.497px;
border: 2px solid #F6D995;
background: #F6D995;
}
.submitDescription {
width: 91%;
color: #000;
font-family: "DM Sans";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
text-align: center;
margin-bottom: 64px;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use client';
import styles from './Comments.module.scss';
import { useState } from 'react';

interface CommentsProps {
categoryScores: Map<string, number>;
}

export default function Comments({ categoryScores }: CommentsProps) {
const [commentText, setCommentText] = useState('');
const [commentSubmitted, setCommentSubmitted] = useState(false);

const hasNegativeScores = (scoresMap: Map<string, number>) => {
let hasNegativeScore = false;
scoresMap.forEach((score) => {
if (score === -1) {
hasNegativeScore = true;
}
});
return hasNegativeScore;
};

const onCommentType = (e: any) => {
setCommentText(e.target.value);
};

const onSubmitComment = () => {
if (hasNegativeScores(categoryScores)) {
alert('Some categories are not scored. Please score all of them.');
} else {
setCommentSubmitted(true);

/* send scores to backend */
console.log(categoryScores);
console.log(commentText);
}
};

return (
<div className={styles.commentContainer}>
<h2 className={styles.commentTitle}>Comments</h2>
<p className={styles.commentDescription}>
Comments help us for deciding tiebreakers. If there was an exceptional
project or one you’re suspicious of cheating, write it here!
</p>
<textarea
className={styles.commentBox}
value={commentText}
onChange={onCommentType}
placeholder="Write a comment here..."
></textarea>
<button
className={
commentSubmitted ? styles.submitButtonDone : styles.submitButton
}
onClick={onSubmitComment}
disabled={commentSubmitted}
>
{commentSubmitted ? 'Submitted' : 'Submit Score'}
</button>
<p className={styles.submitDescription}>
Once submitted, results cannot be changed.
</p>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.inputContainer {
display: flex;
flex-direction: column;
align-items: center;
background-color: #CEE7F4;
gap: 20px;

.scoringTitle {
width: 91%;
color: #000;
font-family: "Proxima Nova";
font-size: 32px;
font-style: normal;
font-weight: 600;
line-height: normal;
margin-top: 42px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Dispatch, SetStateAction } from 'react';
import styles from './ScoreInput.module.scss';
import ScoringCard from './ScoringCard/ScoringCard';

interface ScoringInputProps {
inputNameHeader: string;
inputScoreNames: string[];
categoryScores: Map<string, number>;
setCategoryScores: Dispatch<SetStateAction<Map<string, number>>>;
}

export default function ScoringInput({
inputNameHeader,
inputScoreNames,
categoryScores,
setCategoryScores,
}: ScoringInputProps) {
return (
<div className={styles.inputContainer}>
<h2 className={styles.scoringTitle}>{inputNameHeader} </h2>
{inputScoreNames.map((category, index) => (
<ScoringCard
categoryName={category}
index={index + 1}
key={index}
categoryScores={categoryScores}
setCategoryScores={setCategoryScores}
/>
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap');

.scoringCard {
display: flex;
flex-direction: column;
background-color: #FFFFFF;
gap: 20px;
width: 92%;
border-radius: 4px;
padding: 10px;
padding-top: 20px;
padding-bottom: 24px;

.categoryName {
color: #000;
font-family: "DM Sans";
font-size: 18px;
font-style: normal;
font-weight: 400;
line-height: normal;
align-self: flex-start;
margin-left: 10px;
}
.scoringCircleContainer {
display: flex;
gap: 10px;
justify-content: space-around;

.scoringCircle {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
border-radius: 50%; /* Make the border radius half of the width/height to create a circle */
border: 2px solid black;
}
.scoringCircleFilled {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
border-radius: 50%; /* Make the border radius half of the width/height to create a circle */
border: 2px solid black;
color: white;
background-color: #005271;
font-family: 'DM Sans', sans-serif;
}
.scoringCircle:hover {
border: 3px solid #005271;;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use client';
import { Dispatch, SetStateAction, useState } from 'react';
import styles from './ScoringCard.module.scss';

interface ScoringCardProps {
categoryName: string;
index: number;
categoryScores: Map<string, number>;
setCategoryScores: Dispatch<SetStateAction<Map<string, number>>>;
}
export default function ScoringCard({
categoryName,
index,
categoryScores,
setCategoryScores,
}: ScoringCardProps) {
const scores = [1, 2, 3, 4, 5];

const [pickedScore, setPickedScore] = useState(-1);

const enterChoice = (index: number) => {
return () => {
setPickedScore(index);

const updatedMap = new Map(categoryScores);
updatedMap.set(categoryName, index + 1);
setCategoryScores(updatedMap);
};
};
return (
<div className={styles.scoringCard}>
<h2 className={styles.categoryName}>{`${index}. ${categoryName}`}</h2>
<div className={styles.scoringCircleContainer}>
{scores.map((score, index) => (
<div
key={index}
className={
index == pickedScore
? styles.scoringCircleFilled
: styles.scoringCircle
}
onClick={enterChoice(index)}
>
{score}
</div>
))}
</div>
</div>
);
}
Loading