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
318 changes: 309 additions & 9 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.9.2",
"@types/node": "^18.13.0",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/react-redux": "^7.1.25",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.8.1",
"react-scripts": "^5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^3.1.1"
},
"scripts": {
Expand Down
File renamed without changes.
18 changes: 0 additions & 18 deletions src/componentes/botones/boton-favorito.componente.jsx

This file was deleted.

41 changes: 41 additions & 0 deletions src/componentes/botones/boton-favorito.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import './boton-favorito.css';
import { useAppDispatch, useAppSelector } from '../../store';
import { ADD_FAVORITOS } from '../../store/characters/slice';
import { ICharacter } from '../../interfaces/character.interface';
/**
* Boton que indica si un elemento es favorito o no, y da la posibilidad de marcarlo/desmarcarlo
*
* Deberás tipar las propiedades si usas este componente
*
*
* @returns un JSX element
*/
export interface IBotonFavorito {
isFavorite: boolean;
source: string
id: number
}

const BotonFavorito = ({isFavorite, id, name, image }: ICharacter) => {
const dispatch = useAppDispatch()
useAppSelector((state) => state.characters)



/**
* Disparador de Agregar a favoritos
* @author 'Carmen Vargas'
* @return {Array} un array de favoritos
*/
const addFavorito = () => {
console.log('Botón Favorito ON CLICK');
dispatch(ADD_FAVORITOS( {isFavorite, id, name, image} ));
}
const src = isFavorite ? "/imagenes/star-filled.png" : "/imagenes/star.png"
return <div className="boton-favorito">
<img src={src} alt={"favorito"} onClick={addFavorito} />
</div>
}

export default BotonFavorito;
22 changes: 0 additions & 22 deletions src/componentes/episodios/tarjeta-episodio.componente.jsx

This file was deleted.

27 changes: 27 additions & 0 deletions src/componentes/episodios/tarjeta-episodio.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import './tarjeta-episodio.css';

/**
* Tarjeta para cada episodio dentro de la vista de personaje.
*
* Deberás agregar las propiedades necesarias para mostrar los datos de los episodios
*
*
* @returns un JSX element
*/
export interface IEpisodio {
nombre: string;
numeroDeEpisodio: string;
fechaDeLanzamiento: Date;
}
const TarjetaEpisodio = ({nombre,numeroDeEpisodio,fechaDeLanzamiento}: IEpisodio) => {
const dateString = fechaDeLanzamiento.toLocaleDateString()
return <div className="tarjeta-episodio">
<h4>{nombre}</h4>
<div>
<span>{numeroDeEpisodio}</span>
<span> Lanzado el:{dateString}</span>
</div>
</div>
}

export default TarjetaEpisodio;
19 changes: 0 additions & 19 deletions src/componentes/paginacion/paginacion.componente.jsx

This file was deleted.

35 changes: 35 additions & 0 deletions src/componentes/paginacion/paginacion.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import './paginacion.css';
import { useAppDispatch, useAppSelector } from '../../store';

import { GET_CHARACTERS } from '../../store/characters/thunk';

/**
* Componente que contiene los botones para paginar
*
* Deberás agregar las propiedades necesarias para que funcione correctamente
*
*
* @returns un JSX element
*/
export interface IPaginacion {
pageValue: number
}

const Paginacion = () => {
const dispatch = useAppDispatch()
const {nextPage, prevPage} = useAppSelector((state)=> state.characters)

const handelNextPage = () =>{
dispatch(GET_CHARACTERS(nextPage))
}
const handelPrevPage = () =>{
dispatch(GET_CHARACTERS(prevPage))
}
return <div className="paginacion">

<button onClick={handelPrevPage} disabled={!prevPage} className={"primary"}>Anterior</button>
<button onClick={handelNextPage} disabled={!nextPage} className={"primary"}>Siguiente</button>
</div>
}

export default Paginacion;
11 changes: 0 additions & 11 deletions src/componentes/personajes/filtros.componente.jsx

This file was deleted.

45 changes: 45 additions & 0 deletions src/componentes/personajes/filtros.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useRef, useEffect } from 'react';
import './filtros.css';
import { useAppDispatch } from '../../store';
import { IFiltros } from './personaje.interface';
import { GET_CHARACTERS, GET_CHARACTERS_FILTER } from '../../store/characters/thunk';



const Filtros = ({name, setName, urlBase}: IFiltros) => {
const ref = useRef<HTMLInputElement| null>(null)
const dispatch = useAppDispatch()

const deleteFilter = ()=>{
if (!ref.current) return
ref.current.value = ''
dispatch(GET_CHARACTERS(urlBase))

}


const filterByName = () => {
if (!ref.current) return
setName(ref.current.value)
if (name?.trim === null) {
ref.current.value = ''
return
}
console.log(name)
dispatch(GET_CHARACTERS_FILTER({name}))

}

useEffect(() => {
if(name === null){
deleteFilter()
}
}, [name]);

return <div className="filtros">
<label htmlFor="nombre">Filtrar por nombre:</label>
<input type="text" ref={ref} placeholder="Rick, Morty, Beth, Alien, ...etc" name="nombre" onChange={filterByName}/>
</div>
}

export default Filtros;
21 changes: 0 additions & 21 deletions src/componentes/personajes/grilla-personajes.componente.jsx

This file was deleted.

42 changes: 42 additions & 0 deletions src/componentes/personajes/grilla-personajes.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useAppSelector } from '../../store';
import './grilla-personajes.css';
import TarjetaPersonaje from './tarjeta-personaje.componente';
import { IGrillaPersonajes } from './personaje.interface';




/**
* Grilla de personajes para la pagina de inicio
*
* Deberás agregar las funciones necesarias para mostrar y paginar los personajes
*
*
* @returns un JSX element
*/
const GrillaPersonajes = ({initialCharacters} : IGrillaPersonajes) => {

const {isError, isLoading, listFavoritos} = useAppSelector((state) => state.characters)
// Crea una copia de la lista de favoritos con los IDs de los personajes
const favoritosIds = listFavoritos.map(character => character.id);

// Mapea los personajes iniciales y establece esFavorito en true si están en la lista de favoritos
const charactersWithFavoritos = initialCharacters.map(character => ({
...character,
isFavorite: favoritosIds.includes(character.id),
}));

return <div className="grilla-personajes">

{isLoading ? <p>Loading...</p> :

charactersWithFavoritos?.map(character =>

<TarjetaPersonaje name={character.name} image={character.image} key={character.id} id={character.id} isFavorite={character.isFavorite} />
)}
{ isError && <p>{isError}</p>}

</div>
}

export default GrillaPersonajes;
13 changes: 13 additions & 0 deletions src/componentes/personajes/personaje.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ICharacter } from "../../interfaces/character.interface";

export interface IFiltros{
name: string | null,
setName: (name: string | null )=> void
urlBase: string
}



export interface IGrillaPersonajes{
initialCharacters: ICharacter[]
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import BotonFavorito from '../botones/boton-favorito.componente';
import './tarjeta-personaje.css';
import { ICharacter } from '../../interfaces/character.interface';


/**
* Tarjeta para cada personaje dentro de la grilla de personajes.
*
* Deberás agregar las propiedades necesarias para mostrar los datos de los personajes
*
*
* @returns un JSX element
* @returns un JSX element
*/
const TarjetaPersonaje = () => {

const TarjetaPersonaje = ({name, image, isFavorite, id}: ICharacter) => {
return <div className="tarjeta-personaje">
<img src="https://rickandmortyapi.com/api/character/avatar/1.jpeg" alt="Rick Sanchez"/>
<img src={image} alt={name}/>
<div className="tarjeta-personaje-body">
<span>Rick Sanchez</span>
<BotonFavorito esFavorito={false} />
<span>{name}</span>
<BotonFavorito isFavorite={isFavorite} id={id} name={name} image={image}/>
</div>
</div>
}
Expand Down
20 changes: 12 additions & 8 deletions src/index.jsx → src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import './index.css';
import App from './App';
import { Provider } from "react-redux";
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom";
import store from "./store";
import App from "./App";



ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>,
document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
reportWebVitals();
Loading