Skip to content

Commit d2830b4

Browse files
committed
TasksList and TaskForm components added
1 parent d5a9bb3 commit d2830b4

File tree

8 files changed

+219
-102
lines changed

8 files changed

+219
-102
lines changed

public/index.html

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,28 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="utf-8" />
5-
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6-
<meta name="viewport" content="width=device-width, initial-scale=1" />
7-
<meta name="theme-color" content="#000000" />
8-
<meta
9-
name="description"
10-
content="Web site created using create-react-app"
11-
/>
12-
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13-
<!--
14-
manifest.json provides metadata used when your web app is installed on a
15-
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16-
-->
17-
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18-
<!--
19-
Notice the use of %PUBLIC_URL% in the tags above.
20-
It will be replaced with the URL of the `public` folder during the build.
21-
Only files inside the `public` folder can be referenced from the HTML.
223

23-
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24-
work correctly both with client-side routing and a non-root public URL.
25-
Learn how to configure a non-root public URL by running `npm run build`.
26-
-->
27-
<title>React App</title>
28-
</head>
29-
<body>
30-
<noscript>You need to enable JavaScript to run this app.</noscript>
31-
<div id="root"></div>
32-
<!--
33-
This HTML file is a template.
34-
If you open it directly in the browser, you will see an empty page.
4+
<head>
5+
<meta charset="utf-8" />
6+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1" />
8+
<meta name="theme-color" content="#000000" />
9+
<meta name="description" content="Web site created using create-react-app" />
10+
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
11+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
12+
<title>TypeScript Tasks App</title>
3513

36-
You can add webfonts, meta tags, or analytics to this file.
37-
The build step will place the bundled scripts into the <body> tag.
14+
<!-- GOOGLE FONTS -->
15+
<link rel="preconnect" href="https://fonts.googleapis.com">
16+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
17+
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@100;200;300;400;500;600;700;800&display=swap"
18+
rel="stylesheet">
19+
</head>
3820

39-
To begin the development, run `npm start` or `yarn start`.
40-
To create a production bundle, use `npm run build` or `yarn build`.
41-
-->
42-
</body>
43-
</html>
21+
<body>
22+
<noscript>You need to enable JavaScript to run this app.</noscript>
23+
<div id="root"></div>
24+
25+
26+
</body>
27+
28+
</html>

src/App.css

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,3 @@
11
.App {
2-
text-align: center;
3-
}
4-
5-
.App-logo {
6-
height: 40vmin;
7-
pointer-events: none;
8-
}
9-
10-
@media (prefers-reduced-motion: no-preference) {
11-
.App-logo {
12-
animation: App-logo-spin infinite 20s linear;
13-
}
14-
}
15-
16-
.App-header {
17-
background-color: #282c34;
18-
min-height: 100vh;
19-
display: flex;
20-
flex-direction: column;
21-
align-items: center;
22-
justify-content: center;
23-
font-size: calc(10px + 2vmin);
24-
color: white;
25-
}
26-
27-
.App-link {
28-
color: #61dafb;
29-
}
30-
31-
@keyframes App-logo-spin {
32-
from {
33-
transform: rotate(0deg);
34-
}
35-
to {
36-
transform: rotate(360deg);
37-
}
38-
}
2+
padding: 1rem;
3+
}

src/App.tsx

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,53 @@
1-
import React from 'react';
2-
import logo from './logo.svg';
1+
import React, { useState } from 'react';
2+
33
import './App.css';
44

5-
function App() {
5+
import { TaskForm } from './components/TaskForm/TaskForm';
6+
import { TasksList } from './components/TasksList/TasksList';
7+
8+
const initialState = [
9+
{
10+
id: 1,
11+
title: 'Primera tarea',
12+
description: 'Primera descripción',
13+
done: true
14+
},
15+
{
16+
id: 2,
17+
title: 'Segunda tarea',
18+
description: 'Segunda descripción',
19+
done: false
20+
},
21+
{
22+
id: 3,
23+
title: 'Tercera tarea',
24+
description: 'Tercera descripción',
25+
done: false
26+
}
27+
]
28+
29+
interface ITask {
30+
id: number
31+
title: string,
32+
description: string,
33+
done: boolean
34+
}
35+
36+
function App(): JSX.Element {
37+
const [tasksList, setTasksList] = useState<ITask[]>(initialState);
38+
39+
const addTask = (task: ITask) => {
40+
// const newTasks: ITask[] = [ ...tasksList, { ...task, created: 123}] Da error porque el objeto no coincide con el que se le está pasando
41+
42+
setTasksList([ ...tasksList, task ])
43+
}
44+
645
return (
7-
<div className="App">
8-
<header className="App-header">
9-
<img src={logo} className="App-logo" alt="logo" />
10-
<p>
11-
Edit <code>src/App.tsx</code> and save to reload.
12-
</p>
13-
<a
14-
className="App-link"
15-
href="https://reactjs.org"
16-
target="_blank"
17-
rel="noopener noreferrer"
18-
>
19-
Learn React
20-
</a>
21-
</header>
46+
<div className="container">
47+
<div className="App">
48+
<TaskForm addTask={addTask} />
49+
<TasksList tasks={tasksList} />
50+
</div>
2251
</div>
2352
);
2453
}

src/components/TaskForm/TaskForm.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
form {
2+
padding: 1rem;
3+
4+
background: rgb(236, 236, 236);
5+
6+
display: flex;
7+
flex-direction: column;
8+
align-items: center;
9+
justify-content: center;
10+
}
11+
12+
.form-control {
13+
margin: 10px 0;
14+
}

src/components/TaskForm/TaskForm.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React, { useState } from 'react'
2+
3+
import './TaskForm.css'
4+
5+
type FormElement = React.FormEvent<HTMLFormElement>;
6+
7+
export const TaskForm = (props: any) => {
8+
const [form, setForm] = useState<object>({});
9+
10+
const handleInputChange = (e: any) => {
11+
setForm({
12+
...form,
13+
[e.target.name]: e.target.value
14+
});
15+
};
16+
17+
const handleSubmit = (e: FormElement) => {
18+
e.preventDefault();
19+
20+
props.addTask(form)
21+
}
22+
23+
return (
24+
<form onSubmit={(e) => handleSubmit(e)}>
25+
<input
26+
type="text"
27+
name="title"
28+
className="form-control"
29+
placeholder="Write a title"
30+
onChange={(e) => handleInputChange(e)}
31+
/>
32+
33+
<input
34+
type="text"
35+
name="description"
36+
className="form-control"
37+
placeholder="Write a description"
38+
onChange={(e) => handleInputChange(e)}
39+
/>
40+
41+
<button type="submit" >Save Task</button>
42+
</form>
43+
)
44+
}

src/components/TasksList/TaskList.css

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.tasks-container {
2+
width: 100%;
3+
4+
display: grid;
5+
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
6+
gap: 1rem;
7+
}
8+
9+
.card {
10+
padding: 1.5rem;
11+
12+
background: rgb(255, 255, 255);
13+
box-shadow: rgba(0, 0, 0, 0.02) 0px 1px 3px 0px, rgba(27, 31, 35, 0.15) 0px 0px 0px 1px;
14+
15+
display: flex;
16+
flex-direction: column;
17+
align-items: flex-start;
18+
justify-content: center;
19+
}
20+
21+
.card__title {
22+
font-size: 22px;
23+
font-weight: 600;
24+
}
25+
26+
.card__description {
27+
font-size: 18px;
28+
font-weight: 300;
29+
}
30+
31+
.card__status {
32+
padding: 8px;
33+
border-radius: 10px;
34+
}
35+
36+
.card__status.success {
37+
background: rgba(20, 136, 20, 0.233);
38+
}
39+
40+
.card__status.pending {
41+
background: rgba(151, 136, 86, 0.301);
42+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react'
2+
3+
import './TaskList.css'
4+
5+
export const TasksList = (props: any) => {
6+
7+
8+
return (
9+
<div>
10+
<h2>TasksList</h2>
11+
<div className="tasks-container">
12+
{
13+
props.tasks.map((task: any) => (
14+
<div className="card" key={task.id}>
15+
<h3 className="card__title" >{task.title}</h3>
16+
<p className="card__description">{task.description}</p>
17+
<span
18+
className={`card__status ${task.done ? 'success' : 'pending'}`}
19+
>
20+
{ task.done ? 'Hecha' : 'Pendiente'}
21+
</span>
22+
</div>
23+
))
24+
}
25+
</div>
26+
</div>
27+
)
28+
}

src/index.css

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1-
body {
1+
:root {
2+
--primary-font: 'Roboto Slab', serif;
3+
}
4+
5+
* {
26
margin: 0;
3-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4-
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5-
sans-serif;
6-
-webkit-font-smoothing: antialiased;
7-
-moz-osx-font-smoothing: grayscale;
7+
padding: 0;
8+
box-sizing: border-box;
9+
10+
font-family: var(--primary-font);
811
}
912

10-
code {
11-
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12-
monospace;
13+
.container {
14+
width: 70%;
15+
margin: auto;
1316
}
17+
18+
input,
19+
button {
20+
padding: 1rem;
21+
outline: none;
22+
border: 1px solid rgba(0, 0, 0, 0.329);
23+
}

0 commit comments

Comments
 (0)