Skip to content

Commit

Permalink
Merge pull request #186 from UoaWDCC/VPS-165/roles-for-scenes-ui
Browse files Browse the repository at this point in the history
VPS-165/roles for scenes UI
  • Loading branch information
itsatulbox authored May 27, 2024
2 parents 4e48534 + d488008 commit 4a29841
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 21 deletions.
10 changes: 9 additions & 1 deletion backend/src/routes/api/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
getGroupByScenarioId,
} from "../../db/daos/groupDao";

import { updateRoleList } from "../../db/daos/scenarioDao";
import { retrieveRoleList, updateRoleList } from "../../db/daos/scenarioDao";
import Group from "../../db/models/group";

const router = Router();
Expand Down Expand Up @@ -109,4 +109,12 @@ router.post("/:scenarioId", async (req, res) => {
res.status(HTTP_OK).json(output);
});

router.get("/:scenarioId/roleList", async (req, res) => {
const { scenarioId } = req.params;

const roleList = await retrieveRoleList(scenarioId);

res.status(HTTP_OK).json(roleList);
});

export default router;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export default function CustomCheckBoxStyles() {
"&.Mui-checked": {
color: "#0080a7",
},
paddingLeft: "0.75em",
paddingRight: "0.75em",
},
});
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { InputAdornment } from "@material-ui/core";
import {
InputLabel,
InputAdornment,
FormControl,
FormControlLabel,
Select,
Checkbox,
Typography,
} from "@material-ui/core";
import TextField from "@material-ui/core/TextField";
import { withStyles } from "@material-ui/core/styles";
import { useContext } from "react";
import { useContext, useState } from "react";
import ScenarioContext from "context/ScenarioContext";
import SceneContext from "../../../../context/SceneContext";

import styles from "../../../../styling/CanvasSideBar.module.scss";
import CustomInputLabelStyles from "./CustomPropertyInputStyles/CustomInputLabelStyles";
import CustomCheckBoxStyles from "./CustomPropertyInputStyles/CustomCheckBoxStyles";

const CustomInputLabel = CustomInputLabelStyles()(InputLabel);
const CustomCheckBox = CustomCheckBoxStyles()(Checkbox);
const CustomTextField = withStyles({
root: {
marginTop: "0.5em",
Expand All @@ -26,6 +39,50 @@ const CustomTextField = withStyles({
*/
export default function SceneSettings() {
const { currentScene, setCurrentScene } = useContext(SceneContext);
const { roleList } = useContext(ScenarioContext);

const initialSelectedRoles = roleList ? [...roleList] : [];
const [selectedRoles, setSelectedRoles] = useState(initialSelectedRoles);

const initialCheckedState = roleList?.map((role) =>
selectedRoles?.includes(role)
);
const initialAllCheckedState = initialCheckedState?.every(
(checked) => checked
);

const [checked, setChecked] = useState(initialCheckedState);
const [allChecked, setAllChecked] = useState(initialAllCheckedState);

const handleCheckboxChange = (index) => {
const newChecked = [...checked];
newChecked[index] = !checked[index];
setChecked(newChecked);

const isAllChecked = newChecked.every((isChecked) => isChecked);
setAllChecked(isAllChecked);

const updatedSelectedRoles = newChecked.reduce((acc, isChecked, idx) => {
if (isChecked) {
acc.push(roleList[idx]);
}
return acc;
}, []);
setSelectedRoles(updatedSelectedRoles);
};

const handleAllToggle = () => {
const newAllChecked = !allChecked;
setAllChecked(newAllChecked);

const newChecked = newAllChecked
? new Array(roleList.length).fill(true)
: new Array(roleList.length).fill(false);
setChecked(newChecked);

const newSelectedRoles = newAllChecked ? roleList : [];
setSelectedRoles(newSelectedRoles);
};

return (
<>
Expand All @@ -48,7 +105,7 @@ export default function SceneSettings() {
<CustomTextField
label="Scene Timer Duration"
type="number"
value={currentScene?.time || ""}
value={currentScene?.time ?? 0}
fullWidth
onChange={(event) => {
// limiting scene timer duration
Expand All @@ -60,16 +117,63 @@ export default function SceneSettings() {
});
}}
InputProps={{
// seconds adornment appears when there is input
endAdornment: currentScene?.time ? (
endAdornment: (
<InputAdornment position="end">seconds</InputAdornment>
) : null,
),
}}
InputLabelProps={{
// label moves up whenever there is input
shrink: !!currentScene?.time,
shrink: true,
}}
/>
<FormControl fullWidth className={styles.formControl}>
<CustomInputLabel>Scene Role(s)</CustomInputLabel>
<Select
className={styles.selectInput}
MenuProps={{
getContentAnchorEl: null,
}}
multiple
value={selectedRoles}
onChange={(event) => setSelectedRoles(event.target.value)}
renderValue={(selected) =>
selected.length === roleList.length
? "All"
: selected.join(", ")
}
>
{roleList && roleList.length > 0 ? (
<div style={{ display: "flex", flexDirection: "column" }}>
<FormControlLabel
control={
<CustomCheckBox
defaultChecked
checked={allChecked}
onChange={handleAllToggle}
/>
}
label="All"
/>
{roleList.map((role, index) => (
<FormControlLabel
control={
<CustomCheckBox
defaultChecked
checked={checked[index]}
onChange={() => handleCheckboxChange(index)}
/>
}
label={role}
/>
))}
</div>
) : (
<Typography className={styles.menuItem}>
This scenario currently does not accommodate roles. Please
upload a CSV file first under Manage Groups.
</Typography>
)}
</Select>
</FormControl>
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,89 @@ exports[`Scenario Selection page snapshot test 1`] = `
className="MuiFormControl-root MuiTextField-root WithStyles(ForwardRef(TextField))-root-1 MuiFormControl-fullWidth"
>
<label
className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
data-shrink={false}
className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiFormLabel-filled"
data-shrink={true}
>
Scene Timer Duration
</label>
<div
className="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl"
className="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedEnd"
onClick={[Function]}
>
<input
aria-invalid={false}
autoFocus={false}
className="MuiInputBase-input MuiInput-input"
className="MuiInputBase-input MuiInput-input MuiInputBase-inputAdornedEnd"
disabled={false}
onAnimationStart={[Function]}
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
required={false}
type="number"
value={0}
/>
<div
className="MuiInputAdornment-root MuiInputAdornment-positionEnd"
>
<p
className="MuiTypography-root MuiTypography-body1 MuiTypography-colorTextSecondary"
>
seconds
</p>
</div>
</div>
</div>
<div
className="MuiFormControl-root formControl MuiFormControl-fullWidth"
>
<label
className="MuiFormLabel-root MuiInputLabel-root WithStyles(ForwardRef(InputLabel))-root-2 MuiInputLabel-formControl MuiInputLabel-animated"
data-shrink={false}
>
Scene Role(s)
</label>
<div
className="MuiInputBase-root MuiInput-root MuiInput-underline selectInput MuiInputBase-formControl MuiInput-formControl"
onClick={[Function]}
>
<div
aria-haspopup="listbox"
className="MuiSelect-root MuiSelect-select MuiSelect-selectMenu MuiInputBase-input MuiInput-input"
onBlur={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDown={[Function]}
role="button"
tabIndex={0}
>
<span
dangerouslySetInnerHTML={
Object {
"__html": "&#8203;",
}
}
/>
</div>
<input
aria-hidden={true}
className="MuiSelect-nativeInput"
onAnimationStart={[Function]}
onChange={[Function]}
required={false}
tabIndex={-1}
value=""
/>
<svg
aria-hidden={true}
className="MuiSvgIcon-root MuiSelect-icon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M7 10l5 5 5-5z"
/>
</svg>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,89 @@ exports[`Scenario Selection page snapshot test 1`] = `
className="MuiFormControl-root MuiTextField-root WithStyles(ForwardRef(TextField))-root-1 MuiFormControl-fullWidth"
>
<label
className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
data-shrink={false}
className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiFormLabel-filled"
data-shrink={true}
>
Scene Timer Duration
</label>
<div
className="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl"
className="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedEnd"
onClick={[Function]}
>
<input
aria-invalid={false}
autoFocus={false}
className="MuiInputBase-input MuiInput-input"
className="MuiInputBase-input MuiInput-input MuiInputBase-inputAdornedEnd"
disabled={false}
onAnimationStart={[Function]}
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
required={false}
type="number"
value={0}
/>
<div
className="MuiInputAdornment-root MuiInputAdornment-positionEnd"
>
<p
className="MuiTypography-root MuiTypography-body1 MuiTypography-colorTextSecondary"
>
seconds
</p>
</div>
</div>
</div>
<div
className="MuiFormControl-root formControl MuiFormControl-fullWidth"
>
<label
className="MuiFormLabel-root MuiInputLabel-root WithStyles(ForwardRef(InputLabel))-root-2 MuiInputLabel-formControl MuiInputLabel-animated"
data-shrink={false}
>
Scene Role(s)
</label>
<div
className="MuiInputBase-root MuiInput-root MuiInput-underline selectInput MuiInputBase-formControl MuiInput-formControl"
onClick={[Function]}
>
<div
aria-haspopup="listbox"
className="MuiSelect-root MuiSelect-select MuiSelect-selectMenu MuiInputBase-input MuiInput-input"
onBlur={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDown={[Function]}
role="button"
tabIndex={0}
>
<span
dangerouslySetInnerHTML={
Object {
"__html": "&#8203;",
}
}
/>
</div>
<input
aria-hidden={true}
className="MuiSelect-nativeInput"
onAnimationStart={[Function]}
onChange={[Function]}
required={false}
tabIndex={-1}
value=""
/>
<svg
aria-hidden={true}
className="MuiSvgIcon-root MuiSelect-icon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M7 10l5 5 5-5z"
/>
</svg>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 4a29841

Please sign in to comment.