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

Task list table #1

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions web/icons/pers.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions web/icons/sun.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx",
"preview": "vite preview",
"update-upstream": "node scripts/setup.js git@github.com:Migracode-Barcelona/task-tracker.git"
"update-upstream": "node scripts/setup.js https://github.com/Migracode-Barcelona/task-tracker.git"
},
"dependencies": {
"react": "^18.3.1",
Expand Down
40 changes: 39 additions & 1 deletion web/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
import { useState } from 'react';
import { TaskList } from './components/domains/task/TaskList/TaskList';
import { TaskForm } from './components/domains/task/TaskForm/TaskForm';

function App() {
const [tasks, setTasks] = useState([
{
title: 'Re-work UI/UX',
priority: 'Low',
releaseDate: '12/05/2025',
assignedTo: 'Said, Rachael',
projectName: 'Time App',
},
{
title: 'Dark mode toggle',
priority: 'High',
releaseDate: '09/03/2025',
assignedTo: 'Umair, Precious',
projectName: 'ASA Darkmode Feature',
},
{
title: 'Accessibility checks',
priority: 'Medium',
releaseDate: '15/04/2025',
assignedTo: 'Michael, Ricardo',
projectName: 'Time App',
},
{
title: 'Notification integration',
priority: 'High',
releaseDate: '11/03/2025',
assignedTo: 'Ebtesam, Deborah',
projectName: 'Time App',
},
]);

function createTask(newTask) {
setTasks([...tasks, newTask]);
}

return (
<>
<TaskList />
<TaskList taskItems={tasks} />
<TaskForm handleClick={createTask} />
</>
);
}
Expand Down
72 changes: 72 additions & 0 deletions web/src/components/domains/task/TaskForm/TaskForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useState } from 'react';
import styles from './TaskForm.module.css';
import { PropTypes } from 'prop-types';

function TaskForm({ handleClick }) {
const [taskTitle, setTaskTitle] = useState('');
const [taskProject, setTaskProject] = useState('');

function submitTask() {
if (!taskTitle.trim() || !taskProject.trim()) {
alert('Please enter both title and project name.');
return;
}

const newTask = {
title: taskTitle,
priority: 'Medium',
releaseDate: new Date().toLocaleDateString(),
assignedTo: 'Unassigned',
projectName: taskProject,
};

handleClick(newTask);
setTaskTitle('');
setTaskProject('');
}

return (
<form className={styles.formWrapper}>
<h1 className={styles.headingStyle}>New Task</h1>
<fieldset className={styles.fieldsetStyle}>
{/* Task title */}
<label htmlFor="taskTitle" className={styles.taskLabelStyle}>
Title
<input
type="text"
id="taskTitle"
className={styles.taskInputStyle}
value={taskTitle}
onChange={(e) => setTaskTitle(e.target.value)}
required
/>
</label>

{/* Project name */}
<label htmlFor="taskProject" className={styles.taskLabelStyle}>
Project
<input
type="text"
id="taskProject"
className={styles.taskInputStyle}
value={taskProject}
onChange={(e) => setTaskProject(e.target.value)}
required
/>
</label>
</fieldset>
<input
type="button"
value="Add task"
className={styles.formButton}
onClick={submitTask}
/>
</form>
);
}

export { TaskForm };

TaskForm.propTypes = {
handleClick: PropTypes.func.isRequired,
};
41 changes: 41 additions & 0 deletions web/src/components/domains/task/TaskForm/TaskForm.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.formWrapper {
background-color: var(--light-grey);
display: flex;
flex-direction: column;
justify-content: center;
align-items: right;
padding: 40px;
gap: 10px;
border-radius: 10px;
margin: 50px;
}

.fieldsetStyle {
display: flex;
flex-wrap: wrap;
border: none;
gap: 40px;
}

.taskLabelStyle {
flex-grow: 1;
display: flex;
flex-direction: column;
}

.taskInputStyle {
border-radius: 7px;
border: 2px solid black;
padding: 5px;
margin-top: 7px;
}

.formButton {
text-align: center;
border-radius: 15px;
width: fit-content;
padding: 5px;
background-color: var(--light-blue);
margin-top: 10px;
padding: 10px;
}
20 changes: 20 additions & 0 deletions web/src/components/domains/task/TaskItem/PersIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const MyIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none">
<g
stroke="#000"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
clipPath="url(#a)"
>
<path d="M14.167 17.5v-1.667a3.333 3.333 0 0 0-3.334-3.333H4.167a3.333 3.333 0 0 0-3.334 3.333V17.5M7.5 9.167a3.333 3.333 0 1 0 0-6.667 3.333 3.333 0 0 0 0 6.667ZM19.167 17.5v-1.667a3.333 3.333 0 0 0-2.5-3.225M13.333 2.608a3.333 3.333 0 0 1 0 6.459" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h20v20H0z" />
</clipPath>
</defs>
</svg>
);

export default MyIcon;
20 changes: 20 additions & 0 deletions web/src/components/domains/task/TaskItem/SunIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const MyIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none">
<g
stroke="#000"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
clipPath="url(#a)"
>
<path d="M14.167 15a4.167 4.167 0 1 0-8.334 0M10 7.5V1.667M3.517 8.517 4.7 9.7M.833 15H2.5M17.5 15h1.667M15.3 9.7l1.183-1.183M19.167 18.333H.833M13.333 4.167 10 7.5 6.667 4.167" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h20v20H0z" />
</clipPath>
</defs>
</svg>
);

export default MyIcon;
48 changes: 45 additions & 3 deletions web/src/components/domains/task/TaskItem/TaskItem.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,53 @@
import styles from './TaskItem.module.css';

import PropTypes from 'prop-types';
import SunIcon from './SunIcon';
import PersIcon from './PersIcon';
/*
Please create the <TaskItem /> component following the design from the Figma file.
Please make sure to add styles using CSS Modules.
Add the necessary props to the component.
*/

export function TaskItem(props) {
return <div className={styles.itemWrapper}></div>;
// assigning styling for priorities
export function TaskItem({
title,
priority,
releaseDate,
assignedTo,
projectName,
}) {
const getPriorityClass = () => {
if (priority === 'Low') return `${styles.lowPriority}`;
if (priority === 'Medium') return `${styles.mediumPriority}`;
if (priority === 'High') return `${styles.highPriority}`;
return '';
};

return (
<div className={styles.itemWrapper}>
<div className={`${styles.title}`}>{title}</div>
<div>
<div className={`${styles.priority} ${getPriorityClass()}`}>
{priority}
</div>
</div>
<div className={`${styles.date}`}>
<SunIcon />
<div>{releaseDate}</div>
</div>
<div className={`${styles.assignedTo}`}>
<PersIcon />
<div>{assignedTo}</div>
</div>
<div className={`${styles.project}`}>{projectName}</div>
</div>
);
}

TaskItem.propTypes = {
title: PropTypes.string.isRequired,
priority: PropTypes.string.isRequired,
releaseDate: PropTypes.string.isRequired,
assignedTo: PropTypes.string.isRequired,
projectName: PropTypes.string.isRequired,
};
58 changes: 58 additions & 0 deletions web/src/components/domains/task/TaskItem/TaskItem.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.itemWrapper {
background-color: var(--light-blue);
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 10px;
}

.itemWrapper > div {
width: 25%;
padding-left: 20px;
}

.title {
font-weight: bold;
}

.priority {
text-align: center;
border-radius: 15px;
background-color: var(--light-blue);
width: fit-content;
padding: 5px;
}

.lowPriority {
color: white;
background-color: var(--green);
}

.mediumPriority {
color: white;
background-color: var(--orange);
}

.highPriority {
color: white;
background-color: var(--red);
}

.date {
gap: 5px;
display: flex;
align-items: center;
}

.assignedTo {
gap: 5px;
display: flex;
align-items: center;
}

.project {
font-weight: bold;
}
29 changes: 24 additions & 5 deletions web/src/components/domains/task/TaskList/TaskList.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import { TaskItem } from '../TaskItem/TaskItem';
import styles from './TaskList.module.css';
import PropTypes from 'prop-types';

/*
Please create the <TaskList /> component following the design from the Figma file.
Please make sure to add styles using CSS Modules.
Create a taskItems array and return a list of <TaskItem /> components.
*/

export function TaskList() {
// create some task items here and return one task list for each item you have
const taskItems = [];

return <div className={styles.listWrapper}></div>;
function TaskList({ taskItems }) {
return (
<div className={styles.listWrapper}>
{taskItems.map((task, index) => (
<TaskItem key={index} {...task} />
))}
</div>
);
}

export { TaskList };

TaskList.propTypes = {
taskItems: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string.isRequired,
priority: PropTypes.string.isRequired,
releaseDate: PropTypes.string.isRequired,
assignedTo: PropTypes.string.isRequired,
projectName: PropTypes.string.isRequired,
}),
).isRequired,
};
12 changes: 12 additions & 0 deletions web/src/components/domains/task/TaskList/TaskList.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.listWrapper {
background-color: var(--light-grey);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 40px;
gap: 10px;
border-radius: 10px;
margin-left: 50px;
margin-right: 50px;
}
Loading