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

Judge voting popup refactoring #107

Merged
merged 2 commits into from
Jul 29, 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
46 changes: 15 additions & 31 deletions client/src/components/Popup.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { twMerge } from 'tailwind-merge';

interface PopupProps {
/* State variable for open/closed */
enabled: boolean;

/* Function to modify the popup state variable */
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;

/* Title Text */
title: string;

/* Submit Text */
submitText: string;

/* On submit function */
onSubmit: () => void;

/* React children, corresponds to the body content */
children?: React.ReactNode;

/* If true, button is red */
red?: boolean;
/* Optional classname style to apply to outer div of popup */
className?: string;
}

/**
* Generic popup component with a backdrop and popup modal. Create a state variable and pass in the variable and setter function.
* Clicking on the backdrop will close the popup.
*/
const Popup = (props: PopupProps) => {
if (!props.enabled) {
return null;
Expand All @@ -32,26 +29,13 @@ const Popup = (props: PopupProps) => {
className="fixed left-0 top-0 z-20 w-screen h-screen bg-black/30"
onClick={() => props.setEnabled(false)}
></div>
<div className="bg-background fixed z-30 left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] py-6 px-10 w-1/3">
<h1 className="text-5xl font-bold mb-2 text-center">{props.title}</h1>
<p className="text-xl">{props.children}</p>
<div className="flex flex-row justify-around">
<button
className=" border-lightest border-2 rounded-full px-6 py-1 mt-4 w-2/5 font-bold text-2xl text-lighter hover:bg-lighter/30 duration-200"
onClick={() => props.setEnabled(false)}
>
Cancel
</button>
<button
className={
'text-white rounded-full px-4 py-2 mt-4 w-2/5 font-bold text-2xl hover:brightness-110 duration-200 ' +
(props.red ? 'bg-error' : 'bg-primary')
}
onClick={props.onSubmit}
>
{props.submitText}
</button>
</div>
<div
className={twMerge(
'bg-background fixed z-30 left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] px-6 py-6 md:px-10 md:w-1/3 w-11/12 flex flex-col',
props.className
)}
>
{props.children}
</div>
</>
);
Expand Down
54 changes: 54 additions & 0 deletions client/src/components/RadioButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { twMerge } from 'tailwind-merge';
import Button from './Button';

export interface RadioOption {
/* Internal value of radio option */
value: string;

/* Display text of radio option */
title: string;

/* Subtitle display text of radio option */
subtitle?: string;
}

interface RadioButtonProps {
/* Radio button content */
option: RadioOption;

/* State variable for selection */
selected: boolean;

/* Function to run on click */
onClick: (e: React.MouseEvent<Element>) => void;

/* Color of the popup -- use colors defined in tailwind config */
color: string;
}

/**
* Component used in a RadioSelect component. The design of this button is so that
* we can have an array of values (hence onClick instead of the state setter function).
* See the RadioSelect component; this component shouldn't be directly used.
*/
const RadioButton = (props: RadioButtonProps) => {
return (
<Button
type="outline"
full
square
className={twMerge(
'flex flex-col items-center py-2 px-4 my-2',
props.selected
? `text-${props.color} bg-${props.color}/10 border-${props.color}`
: 'text-black'
)}
onClick={props.onClick}
>
<h3 className="text-2xl">{props.option.title}</h3>
{props.option.subtitle && <p className="text-lg text-light">{props.option.subtitle}</p>}
</Button>
);
};

export default RadioButton;
39 changes: 39 additions & 0 deletions client/src/components/RadioSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import RadioButton, { RadioOption } from './RadioButton';

interface RadioSelectProps {
/* List of radio button options */
options: RadioOption[];

/* Color of the radio buttons */
color: string;

/* State variable for which option is selected, "value" field of the options */
selected: string;

/* Function to modify the selected state variable */
setSelected: React.Dispatch<React.SetStateAction<string>>;
}

/* Shows a list of buttons, where only one can be selected. */
const RadioSelect = (props: RadioSelectProps) => {
// Function to run when item is selected
const onClick = (i: number) => {
props.setSelected(props.options[i].value);
};

return (
<div>
{props.options.map((v, i) => (
<RadioButton
key={i}
color={props.color}
onClick={onClick.bind(this, i)}
option={v}
selected={props.selected === v.value}
/>
))}
</div>
);
};

export default RadioSelect;
60 changes: 60 additions & 0 deletions client/src/components/TextPopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
interface PopupProps {
/* State variable for open/closed */
enabled: boolean;

/* Function to modify the popup state variable */
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;

/* Title Text */
title: string;

/* Submit Text */
submitText: string;

/* On submit function */
onSubmit: () => void;

/* React children, corresponds to the body content */
children?: React.ReactNode;

/* If true, button is red */
red?: boolean;
}

const TextPopup = (props: PopupProps) => {
if (!props.enabled) {
return null;
}

return (
<>
<div
className="fixed left-0 top-0 z-20 w-screen h-screen bg-black/30"
onClick={() => props.setEnabled(false)}
></div>
<div className="bg-background fixed z-30 left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] py-6 px-10 w-1/3">
<h1 className="text-5xl font-bold mb-2 text-center">{props.title}</h1>
<p className="text-xl">{props.children}</p>
<div className="flex flex-row justify-around">
<button
className=" border-lightest border-2 rounded-full px-6 py-1 mt-4 w-2/5 font-bold text-2xl text-lighter hover:bg-lighter/30 duration-200"
onClick={() => props.setEnabled(false)}
>
Cancel
</button>
<button
className={
'text-white rounded-full px-4 py-2 mt-4 w-2/5 font-bold text-2xl hover:brightness-110 duration-200 ' +
(props.red ? 'bg-error' : 'bg-primary')
}
onClick={props.onSubmit}
>
{props.submitText}
</button>
</div>
</div>
</>
);
};

export default TextPopup;
92 changes: 0 additions & 92 deletions client/src/components/judge/FlagPopup.tsx

This file was deleted.

29 changes: 0 additions & 29 deletions client/src/components/judge/FlagPopupButton.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import Back from '../Back';
import Container from '../Container';
import JuryHeader from '../JuryHeader';

interface InfoPageProps {
interface JudgeInfoPageProps {
/* Title to show */
title: string;

/* Description to show */
description: string;
}

const JudgeInfoPage = (props: InfoPageProps) => {
/**
* Page to display when judging cannot happen. This could be because
* of multiple reasons such as a paused session or no more projects left.
*/
const JudgeInfoPage = (props: JudgeInfoPageProps) => {
return (
<>
<JuryHeader withLogout />
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/judge/Ratings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface RatingsProps {
prior?: { [x: string]: number }; // TODO: wtf is this type
small?: boolean;
update?: boolean;
project: JudgedProject;
project?: JudgedProject;
}

const Ratings = (props: RatingsProps) => {
Expand Down Expand Up @@ -56,7 +56,7 @@ const Ratings = (props: RatingsProps) => {
const scoreRes = props.update
? await putRequest<OkResponse>('/judge/score', 'judge', {
categories: scores,
project: props.project.project_id,
project: props.project?.project_id,
})
: await postRequest<OkResponse>('/judge/score', 'judge', {
categories: scores,
Expand Down
Loading