Skip to content

Commit

Permalink
Merge branch 'develop' into 120-listview-cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
gilles-arnout authored May 6, 2024
2 parents 8d0f070 + 56af7ac commit 5e8060c
Show file tree
Hide file tree
Showing 20 changed files with 510 additions and 477 deletions.
4 changes: 2 additions & 2 deletions frontend/__test__/project/edit/Conditions.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {render, screen} from "@testing-library/react";
import React from "react";
import Condtions from "@app/[locale]/components/project_components/conditions";
import Conditions from "@app/[locale]/components/project_components/conditions";
import getTranslations from "../../translations";

jest.mock('react-i18next', () => ({
Expand All @@ -12,7 +12,7 @@ describe('Conditions', () => {
const translations = await getTranslations();

const {getByText: getByText_en, getByDisplayValue, queryAllByRole} = render(
<Condtions
<Conditions
conditions={['First', 'Second']}
setConditions={jest.fn()}
translations={translations.en}
Expand Down
10 changes: 5 additions & 5 deletions frontend/app/[locale]/components/AddProjectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ const AddProjectButton = ({course_id}: EditCourseButtonProps) => {
sx={{
margin: '10px'
}}
onClick={async () => {
const project_id = await addProject(course_id);
window.location.href = `/project/${project_id}/edit`;
}}
href={`/course/${course_id}/add_project/`}
>
<Typography
variant="subtitle1"
sx={{
color: 'secondary.contrastText',
display: 'inline-block',
whiteSpace: 'nowrap',
width: 'fit-content',
}}
>
{t("add_project")}
<Typography>
{t("add_project")}
</Typography>
</Typography>
</Button>
)
Expand Down
107 changes: 107 additions & 0 deletions frontend/app/[locale]/components/general/ItemsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"use client"

import {IconButton, List, ListItem, ListItemText, TextField, Typography, Button} from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import React, {useState} from "react";
import Box from "@mui/material/Box";

interface ItemsListProps {
items: string[],
setItems: (value: (((prevState: any[]) => any[]) | any[])) => void,
input_placeholder: string,
empty_list_placeholder:string,
button_text: string
}

const ItemsList = ({items, setItems, input_placeholder, empty_list_placeholder, button_text}: ItemsListProps) => {
const [newItem, setNewItem] = useState('')
const [noInput, setNoInput] = useState(false)

const handleDelete = (index: number) => {
const newFields = [...items];
newFields.splice(index, 1);
setItems(newFields);
}

const addNewFile = () => {
if (newItem !== '') {
const newItems = [...items];
newItems.push(newItem)
setItems(newItems);
setNewItem('');
setNoInput(false);
console.log(items);
} else {
setNoInput(true);
}
}

return (
<Box>
{items.length === 0 ? (
<Typography variant={"body1"} color={"text.disabled"} sx={{padding: 1}}>{empty_list_placeholder}</Typography>
) : (
<List
sx={{
width: '100%',
maxWidth: 360,
bgcolor: 'background.paper',
maxHeight: 150,
overflow: 'auto',
}}
>
{items.map((field, index) => (
<ListItem
key={index}
secondaryAction={
<IconButton
edge="end"
aria-label="delete"
onClick={() => handleDelete(index)}
>
<DeleteIcon />
</IconButton>
}
>
<ListItemText
primary={field}
/>
</ListItem>
))}
</List>
)
}
<Box
display={'flex'}
flexDirection={'row'}
justifyContent={'flex-start'}
>
<TextField
value={newItem}
onChange={(event) => setNewItem(event.target.value)}
variant="outlined"
size="small"
error={noInput}
placeholder={input_placeholder}
sx={{
width: 'fit-content',
}}
/>
<Button
onClick={() => addNewFile()}
variant={'contained'}
color={'secondary'}
sx={{
width: 'fit-content',
color: 'secondary.contrastText',
marginX: 1
}}
>
<Typography>{button_text}</Typography>
</Button>
</Box>
</Box>
);
}

export default ItemsList
22 changes: 17 additions & 5 deletions frontend/app/[locale]/components/project_components/assignment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,43 @@ import Box from "@mui/material/Box";
import {TextField} from "@mui/material";
import React from "react";
import '../../project/[project_id]/edit/project_styles.css';
import {useTranslation} from "react-i18next";

interface AssignmentProps {
isAssignmentEmpty: boolean,
setDescription: (value: (((prevState: string) => string) | string)) => void,
description: string,
translations: { t: any; resources: any; locale: any; i18nNamespaces: string[]; }
}

function Assignment({isAssignmentEmpty, setDescription, description, translations}: AssignmentProps) {
function Assignment({isAssignmentEmpty, setDescription, description}: AssignmentProps) {
const {t} = useTranslation();

return (
<div>
<Typography variant="h5" className={"typographyStyle"}>
{translations.t("assignment")}
{t("assignment")}
</Typography>
<Box>
<Box
marginTop={1}
>
<TextField
variant="outlined"
multiline={true}
rows={4}
error={isAssignmentEmpty}
label={t("assignment")}
onChange={(event: any) => setDescription(event.target.value)}
value={description}
helperText={isAssignmentEmpty ? translations.t("assignment_required") : ""}
helperText={isAssignmentEmpty ? t("assignment_required") : ""}
size="small"
fullWidth={true}
sx={{
overflowY: 'auto',
height: '100%',
}}
/>
</Box>

</div>
)
}
Expand Down
41 changes: 14 additions & 27 deletions frontend/app/[locale]/components/project_components/conditions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,25 @@ import Tooltip from "@mui/material/Tooltip";
import React from "react";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import Box from "@mui/material/Box";
import {TextField} from "@mui/material";
import {useTranslation} from "react-i18next";
import ItemsList from "@app/[locale]/components/general/ItemsList";

interface ConditionsProps {
conditions: string[],
setConditions: (value: (((prevState: string[]) => string[]) | string[])) => void,
translations: { t: any; resources: any; locale: any; i18nNamespaces: string[]; }
}

function Conditions({conditions, setConditions, translations}: ConditionsProps) {
const handleConditionsChange = (index: number, event: any) => {
const newConditions = [...conditions];
newConditions[index] = event.target.value;
setConditions(newConditions);
function Conditions({conditions, setConditions}: ConditionsProps) {
const {t} = useTranslation();

if (index === conditions.length - 1 && event.target.value !== '') {
setConditions([...newConditions, '']);
} else if (event.target.value === '' && index < conditions.length - 1) {
newConditions.splice(index, 1);
setConditions(newConditions);
}
}
console.log(conditions)

return <div>
<Typography variant="h5" className={"typographyStyle"}>
{translations.t("conditions")}
{t("conditions")}
<Tooltip title={
<Typography variant="body1" className={"conditionsText"}>
{translations.t("conditions_info").split('\n').map((line: string, index: number) => (
{t("conditions_info").split('\n').map((line: string, index: number) => (
<React.Fragment key={index}>
{line}
<br/>
Expand All @@ -42,17 +33,13 @@ function Conditions({conditions, setConditions, translations}: ConditionsProps)
</Tooltip>
</Typography>
<Box className={"conditionsBox"}>
{conditions.map((condition, index) => (
<TextField
key={index}
variant="outlined"
className={"conditionsSummation"}
value={condition}
onChange={(event) => handleConditionsChange(index, event)}
margin={'normal'}
size="small"
/>
))}
<ItemsList
items={conditions}
setItems={setConditions}
input_placeholder={t("conditions_example")}
empty_list_placeholder={t("no_conditions")}
button_text={t("add")}
/>
</Box>
</div>;
}
Expand Down
47 changes: 31 additions & 16 deletions frontend/app/[locale]/components/project_components/deadline.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import dayjs from "dayjs";
import {Box} from "@mui/material";
import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider";
import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs";
import {DateCalendar} from "@mui/x-date-pickers/DateCalendar";
import {TimePicker} from "@mui/x-date-pickers";
import { renderTimeViewClock } from '@mui/x-date-pickers/timeViewRenderers';
import React from "react";

interface DeadlineProps {
Expand All @@ -13,22 +15,35 @@ interface DeadlineProps {
}

function Deadline({deadline, setDeadline, hasDeadline}: DeadlineProps) {
return <LocalizationProvider dateAdapter={AdapterDayjs}>
<DateCalendar
value={deadline}
onChange={(event) => setDeadline(event)}
minDate={dayjs()}
disabled={!hasDeadline}
/>
<TimePicker
value={deadline}
onChange={(event) => {
if (event != null) setDeadline(event)
}}
disabled={!hasDeadline}
/>

</LocalizationProvider>;
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Box
display={"flex"}
flexDirection={"column"}
alignItems={"center"}
justifyContent={"center"}
width={"100%"}
>
<DateCalendar
value={deadline}
onChange={(event) => setDeadline(event)}
minDate={dayjs()}
disabled={!hasDeadline}
/>
<TimePicker
value={deadline}
onChange={(event) => {
if (event != null) setDeadline(event)
}}
disabled={!hasDeadline}
viewRenderers={{
hours: renderTimeViewClock,
minutes: renderTimeViewClock,
}}
/>
</Box>
</LocalizationProvider>
);
}

export default Deadline;
Loading

0 comments on commit 5e8060c

Please sign in to comment.