Skip to content
This repository was archived by the owner on Jun 7, 2019. It is now read-only.

07 Agregar el componente ListTile

Fabian Larrañaga edited this page May 28, 2018 · 13 revisions

Obtenemos la información del board de la API

Inicializamos el estado del componente src/components/Board.js, el cual va a tener el nombre del board y sus listas asociadas:

import React, { Component } from 'react';

class Board extends Component {
  // ####### Agregar: COMIENZO bloque
  constructor(props) {
    super(props);
    this.state = { name: "", lists: [] };
    this.boardId = this.props.match.params.boardId;
  }
  // ####### Agregar: FIN bloque
  
  render() {
    return (
      ...

Luego, obtenemos la información del board desde nuestra API, y actualizamos el estado del componente:

class Board extends Component {
  constructor(props) {
    super(props);
    this.state = { name: "", lists: [] };
    this.boardId = this.props.match.params.boardId;
  }

  // ####### Agregar: COMIENZO bloque
  componentDidMount() {
    fetch(`/boards/${this.boardId}`).then(res => res.json()).then((board) => {
      this.setState({
        name: board.name,
        lists: board.lists
      });
    });
  }
  // ####### Agregar: FIN bloque

  render() {
    return (
      ...

Sustituímos el nombre del board utilizando el estado que seteamos previamente a partir de la API

  render() {
    return (
      <div className="Board">
        <div className="Board-content">
          <div className="Board-header">
            <span className="Board-header-btn">
-             Workshop
+             {this.state.name}
            </span>
          </div>

Invocamos el futuro componente ListTile

Editamos el archivo src/components/Board.js, invocando el futuro componente. Para esto, primero debemos importar el componente:

  import React, { Component } from 'react';
+ import ListTile from './ListTile';

Y luego, lo invocamos, pasándole el nombre de cada board en particular:

<div className="Board-canvas">
  <div className="Board-canvas-content">
+   {
+     this.state.lists.map((list) => {
+       return <ListTile id={list.id} name={list.name} key={list.id} boardId={this.boardId} cards={list.cards}/>
+     })
+   }
-   <div className="ListTile">
-     <div className="ListTile-content">
-       <div className="ListTile-header">
-         <div className="ListTile-header-title">
-           To Do
-         </div>
-       </div>
-       <div className="ListTile-cards">
-         <div className="CardTile">
-           <div className="CardTile-details">
-             <span className="CardTile-title">Create Wiki</span>
-            </div>
-         </div>
-         <div className="CardTile">
-           <div className="CardTile-details">
-             <span className="CardTile-title">Setup VM</span>
-           </div>
-         </div>
-       </div>
-       <a className="ListTile-add-card">Add a card…</a>
-     </div>
-   </div>
    <div className="NewList">
      <a className="NewList-placeholder">Add a list…</a>
    </div>
  </div>
</div>

Agregamos el componente ListTile

Creamos el archivo src/components/ListTile.js, cuyo contenido debería ser el siguiente:

import React, { Component } from 'react';

class ListTile extends Component {
  render() {
    return (
      <div className="ListTile">
        <div className="ListTile-content">
          <div className="ListTile-header">
            <div className="ListTile-header-title">
              {this.props.name}
            </div>
          </div>
          <div className="ListTile-cards">
            <div className="CardTile">
              <div className="CardTile-details">
                <span className="CardTile-title">Create Wiki</span>
              </div>
            </div>
            <div className="CardTile">
              <div className="CardTile-details">
                <span className="CardTile-title">Setup VM</span>
              </div>
            </div>
          </div>
          <a className="ListTile-add-card">Add a card…</a>
        </div>
      </div>
    );
  }
}

export default ListTile;

Probamos en el browser:

wye-trello-board-lists

Formulario de creación de Cards

A continuación, vamos a agregar un formulario a nuestras listas, que nos permita agregar nuevas tarjetas a cada una de ellas.

Para ello, primero modificaremos nuestro componente para renderizar dicho formulario:

<div className="ListTile">
  <div className="ListTile-content">
    <div className="ListTile-header">
      <div className="ListTile-header-title">
        {this.props.name}
      </div>
    </div>
    <div className="ListTile-cards">
      <div className="CardTile">
        <div className="CardTile-details">
          <span className="CardTile-title">Create Wiki</span>
        </div>
      </div>
      <div className="CardTile">
        <div className="CardTile-details">
          <span className="CardTile-title">Setup VM</span>
        </div>
      </div>
+     <div>
+       <form>
+         <textarea className="ListTile-composer"></textarea>
+         <input className="ListTile-composer-add" type="submit" value="Add"/>
+         <div className="ListTile-composer-close"></div>
+       </form>
+     </div>
    </div>
    <a className="ListTile-add-card">Add a card…</a>
  </div>
</div>

Deberíamos ver lo siguiente:

wye-trello-board-create-card

Ahora, vamos a actualizar nuestro componente para que se muestre o el formulario de agregar una nueva tarjeta, o el link que habilitaría dicho formulario. Para esto, definiremos una propiedad en nuestro componente para indicar si se está agregando o no una nueva tarjeta:

class ListTile extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      composing: false,
+      newCardText: ''
+    };
+  }
+
+  toggleComposer = () => {
+    this.setState(prevState => ({
+      composing: !prevState.composing
+    }));
+  }
+
   render() {
     return (
       <div className="ListTile">
         <div className="ListTile-content">
           <div className="ListTile-header">
             <div className="ListTile-header-title">
               {this.props.name}
             </div>
             </div>
             <div className="ListTile-cards">
               <div className="CardTile">
                 <div className="CardTile-details">
                   <span className="CardTile-title">Create Wiki</span>
                 </div>
               </div>
               <div className="CardTile">
                 <div className="CardTile-details">
                   <span className="CardTile-title">Setup VM</span>
                 </div>
               </div>
+              {this.state.composing &&
                 <div>
                   <form>
                     <textarea className="ListTile-composer"></textarea>
                     <input className="ListTile-composer-add" type="submit" value="Add"/>
-                    <div className="ListTile-composer-close"></div>
+                    <div className="ListTile-composer-close" onClick={this.toggleComposer}></div>
                   </form>
                 </div>
+               }
             </div>
-              <a className="ListTile-add-card">Add a card…</a>
+            {!this.state.composing &&
+              <a className="ListTile-add-card" onClick={this.toggleComposer}>Add a card…</a>
+             }
           </div>
         </div>
       );
     }

Finalmente, implementamos el método que realmente agrega la nueva tarjeta a nuestra lista, una vez presionado el botón "Add":

class ListTile extends Component {
  constructor(props) {
    super(props);
    this.state = {
+     cards: props.cards,
      composing: false,
      newCardText: ''
    };
  }

  toggleComposer = () => {
    this.setState(prevState => ({
      composing: !prevState.composing
    }));
  }

+ newCardTextChange = (e) => {
+   this.setState({
+     newCardText: e.target.value
+   });
+ }
+
+ handleSubmit = (e) => {
+   e.preventDefault();
+
+   fetch(`/boards/${this.props.boardId}/lists/${this.props.id}/cards`, {
+     method: 'POST',
+     headers: {
+       'Accept': 'application/json',
+       'Content-Type': 'application/json',
+     },
+     body: JSON.stringify({
+       card: {
+         text: this.state.newCardText
+       }
+     }),
+   }).then((response) => {
+     if (!response.ok) {
+       throw Error(response.statusText);
+     }
+     return response;
+   }).then((response) => {
+     return response.json();
+   }).then((card) => {
+     this.toggleComposer();
+     this.setState(prevState => ({
+       cards: [...prevState.cards, card],
+       newCardText: ''
+     }))
+   }).catch((error) => {
+     console.log(error);
+   });
+ }
+
  render() {
    return (
      <div className="ListTile">
        <div className="ListTile-content">
          <div className="ListTile-header">
            <div className="ListTile-header-title">
              {this.props.name}
            </div>
          </div>
          <div className="ListTile-cards">
            <div className="CardTile">
              <div className="CardTile-details">
                <span className="CardTile-title">Create Wiki</span>
              </div>
            </div>
            <div className="CardTile">
              <div className="CardTile-details">
                <span className="CardTile-title">Setup VM</span>
              </div>
            </div>
            {this.state.composing &&
              <div>
-               <form>
+               <form onSubmit={this.handleSubmit}>
-                 <textarea className="ListTile-composer"></textarea>
+                 <textarea className="ListTile-composer" value={this.state.newCardText} onChange={this.newCardTextChange}></textarea>
                  <input className="ListTile-composer-add" type="submit" value="Add"/>
                  <div className="ListTile-composer-close" onClick={this.toggleComposer}></div>
                </form>
              </div>
            }
          </div>
          {!this.state.composing &&
            <a className="ListTile-add-card" onClick={this.toggleComposer}>Add a card…</a>
          }
        </div>
      </div>
    );
  }
}

Cargar las Cards dinámicamente

Hasta ahora, las tarjetas que vemos en nuestras listas son siempre las mismas. Vamos a modificar nuestro componente para que obtenga las tarjetas del board desde la API.

+ {
+   this.state.cards.map((card) => {
+     return (
+       <div className="CardTile" key={card.id}>
+         <div className="CardTile-details">
+           <span className="CardTile-title">{card.text}</span>
+         </div>
+       </div>
+     )
+   })
+ }
- <div className="CardTile">
-   <div className="CardTile-details">
-     <span className="CardTile-title">Create Wiki</span>
-   </div>
- </div>
- <div className="CardTile">
-   <div className="CardTile-details">
-     <span className="CardTile-title">Setup VM</span>
-   </div>
- </div>

Commit en git

git add -A
git commit -m "Componentizar las listas"

Siguiente: 8. Componentizar las tarjetas

Clone this wiki locally