Skip to content
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ Describe how you approached to problem, and what tools and techniques you used t

## View it live

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
https://peppy-stroopwafel-0a74de.netlify.app/
2 changes: 1 addition & 1 deletion code/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"parser": "@babel/eslint-parser",
"requireConfigFile": false,
"sourceType": "module",
"ecmaVersion": 2017,
"ecmaVersion": 2021,
"ecmaFeatures": {
"jsx": true,
"experimentalObjectRestSpread": true,
Expand Down
513 changes: 494 additions & 19 deletions code/package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
"private": true,
"dependencies": {
"@babel/eslint-parser": "^7.18.9",
"@reduxjs/toolkit": "^1.9.4",
"eslint": "^8.21.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-responsive-carousel": "^3.2.23",
"styled-components": "^5.3.9"
},
"scripts": {
"start": "react-scripts start",
Expand Down
12 changes: 12 additions & 0 deletions code/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Pacifico&display=swap" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,900;1,100;1,200;1,500&family=Pacifico&display=swap" rel="stylesheet">
<meta property="og:title" content="MellowList" />
<meta property="og:description" content="Get in the zone and conquer your to-do list" />
<meta property="og:url" content="https://peppy-stroopwafel-0a74de.netlify.app/" />
<meta property="og:type" content="website" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that you added meta data :D



<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Expand Down
Binary file added code/public/lofigirl.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 47 additions & 5 deletions code/src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,51 @@
import React from 'react';
// src/App.js
import React from 'react'
import { Provider } from 'react-redux'
import { combineReducers, configureStore } from '@reduxjs/toolkit'
import { projects } from 'reducers/projects'
import styled from 'styled-components';
import AddTask from './components/AddTask'
import { tasks } from './reducers/tasks'
import TaskList from './components/TaskList'
import AddProject from './components/AddProject'
import ProjectList from './components/ProjectList'
import TaskCounter from './components/TaskCounter'
import CompleteAllButton from './components/CompleteAllButton'
import Playlist from './components/Playlist';
import { playlist } from './reducers/playlist';

const reducer = combineReducers({
tasks: tasks.reducer,
projects: projects.reducer,
playlist: playlist.reducer
})

const store = configureStore({ reducer })

const AppWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 5px 20px;
gap:1rem;
background-color: #0f1029;
`;

export const App = () => {
return (
<div>
Find me in src/app.js!
</div>
);
<Provider store={store}>
<Playlist />
<AppWrapper>
<h1>MellowList</h1>
<img src={`${process.env.PUBLIC_URL}/lofigirl.gif`} alt="lofi girl gif" />
<AddProject />
<ProjectList />
<AddTask />
<TaskList />
<CompleteAllButton />
<TaskCounter />
</AppWrapper>
</Provider>
)
}
65 changes: 65 additions & 0 deletions code/src/components/AddProject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { addProject } from '../reducers/projects';

const Form = styled.form`
display: flex;
align-items: center;
`;

const Input = styled.input`
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 5px;
margin-right: 1em;
color:#0f1029;
width:250px;
font-family: 'Montserrat', sans-serif;
font-weight:400;
font-size: 16px;
`;

const Button = styled.button`
background-color: #b8b4ba;
color: white;
padding: 0.5em 1em;
border: none;
border-radius: 5px;
cursor: pointer;
font-family: 'Montserrat', sans-serif;
font-weight:400;
font-size: 16px;

&:hover {
background-color:#586535
;
}
`;

const AddProject = () => {
const [input, setInput] = useState('')
const dispatch = useDispatch()

const handleSubmit = (e) => {
e.preventDefault()
if (input.trim()) {
dispatch(addProject({ name: input.trim() }))
setInput('')
}
}

return (
<Form onSubmit={handleSubmit}>
<Input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add a new project" />
<Button type="submit">Add</Button>
</Form>

)
}

export default AddProject
145 changes: 145 additions & 0 deletions code/src/components/AddTask.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/* eslint-disable no-case-declarations */
/* eslint-disable no-use-before-define */
// src/components/AddTask.js
import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import styled from 'styled-components';
import { addTask } from '../reducers/tasks'

// eslint-disable-next-line no-lone-blocks
{ /* const capitalize = (stringToCapitalise) => {
return stringToCapitalise.charAt(0).toUpperCase() + stringToCapitalise.slice(1);
} */ }

const Form = styled.form`
display: flex;
flex-direction: column;
gap: 1em;
`;

const Select = styled.select`
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 5px;
font-family: 'Montserrat', sans-serif;
font-weight:400;
font-size: 16px;
color: #878894;

`;

const Input = styled.input`
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 5px;
width: 300px;
color: #2d2e38;
color: #a0a0b4;
font-family: 'Montserrat', sans-serif;
font-weight:400;
font-size: 16px;
`;

const Button = styled.button`

padding: 0.5em 1em;
border: none;
border-radius: 8px;
cursor: pointer;
background-color: #b8b4ba;
color:white;
font-size:16px;


&:hover {
background-color: #4d5d3e;
}
`;

const AddTask = () => {
const [input, setInput] = useState('')
const [selectedProject, setSelectedProject] = useState('')
const [selectedDate, setSelectedDate] = useState('today')
const [selectedDueDate, setSelectedDueDate] = useState('')
const dispatch = useDispatch()
const projectList = useSelector((state) => state.projects)

const handleSubmit = (e) => {
e.preventDefault()
if (input.trim() && selectedProject) {
const dueDate = getDueDate(selectedDate)
dispatch(addTask({
text: input.trim(),
complete: false,
projectId: parseInt(selectedProject, 10),
dueDate
}))
setInput('')
setSelectedProject('')
setSelectedDate('today')
setSelectedDueDate('')
}
}

const getDueDate = (date) => {
switch (date) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use case of switch / case

case 'tomorrow':
const tomorrow = new Date()
tomorrow.setDate(tomorrow.getDate() + 1)
return tomorrow.toISOString()
case 'later':
const later = new Date()
later.setDate(later.getDate() + 7)
return later.toISOString()
default:
return new Date().toISOString()
}
}

return (
<Form onSubmit={handleSubmit}>
<Select
value={selectedProject}
onChange={(e) => setSelectedProject(e.target.value)}>
<option value="">Select a project</option>
{projectList.map((project) => (
<option key={project.id} value={project.id}>
{project.name}
</option>
))}
</Select>
<Input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add a new task" />
<Select
value={selectedDate}
onChange={(e) => setSelectedDate(e.target.value)}>
<option value="today">Today</option>
<option value="tomorrow">Tomorrow</option>
<option value="later">Later this week</option>
</Select>
{selectedDate === 'later' && (
<div>
<input
type="date"
value={selectedDueDate}
onChange={(e) => setSelectedDueDate(e.target.value)} />
<Button type="button" onClick={() => setSelectedDate('custom')}>Cancel</Button>
</div>
)}
{selectedDate === 'custom' && (
<div>
<input
type="date"
value={selectedDueDate}
onChange={(e) => setSelectedDueDate(e.target.value)} />
</div>
)}
<Button type="submit">Add</Button>
</Form>
)
}

export default AddTask
39 changes: 39 additions & 0 deletions code/src/components/CompleteAllButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { completeAll } from '../reducers/tasks';

const Button = styled.button`
background-color: #878894;
padding: 0.5em 1em;
border: none;
border-radius: 10px;
cursor: pointer;
width:200px;
color:white;
font-family: 'Montserrat', sans-serif;
font-weight:400;
font-size: 16px;
margin-bottom: 20px;


&:hover {
background-color:#586535 ;
}
`;

const CompleteAllButton = () => {
const dispatch = useDispatch();

const handleClick = () => {
dispatch(completeAll());
};

return (
<Button type="button" onClick={handleClick}>
Complete All
</Button>
);
};

export default CompleteAllButton;
34 changes: 34 additions & 0 deletions code/src/components/Playlist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { useSelector } from 'react-redux';
import styled from 'styled-components';

const PlaylistContainer = styled.div`
display: flex;
align-items: center;
justify-content: center;
background-color: #301f48;
padding: 10px;
color: white;

`;

const PlaylistLink = styled.a`
color: white;
text-decoration: underline;
margin-left: 10px;
`;

const Playlist = () => {
const { name, link } = useSelector((state) => state.playlist);

return (
<PlaylistContainer>
<span>{name}</span>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to add css rule to display: none on smaller screen-sizes for a more clean look

<PlaylistLink href={link} target="_blank" rel="noopener noreferrer">
Get in the zone and conquer your to-do list.
</PlaylistLink>
</PlaylistContainer>
);
};

export default Playlist;
Loading