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
16,482 changes: 183 additions & 16,299 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@
"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",
"redux-devtools-extension": "^2.13.9",
"typescript": "^4.9.5",
"web-vitals": "^3.1.1"
},
"scripts": {
Expand All @@ -32,5 +40,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {

}
}
23 changes: 16 additions & 7 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import {Provider} from "react-redux";
import { Routes, Route } from "react-router-dom";
import './App.css';
import PaginaInicio from "./paginas/Inicio.pagina";
import PaginaFavoritos from "./paginas/Favoritos.pagina";
import PaginaDetalle from "./paginas/Detalle.pagina";
import Encabezado from "./componentes/layout/encabezado.componente";
import { store } from './redux/store';

function App() {



return (
<div className="App">
<div className="App">
<Provider store={store}>
<Encabezado />
<Routes>
<Route path="/" element={<PaginaInicio />} />
<Route path="favoritos" element={<PaginaFavoritos />} />
<Route path="detalle" element={<PaginaDetalle />} />
</Routes>
<Routes>
<Route path="/" element={<PaginaInicio />} />
<Route path="favoritos" element={<PaginaFavoritos />} />
<Route path="detalle" element={<PaginaDetalle />} />
</Routes>
</Provider>

</div>

);
}

Expand Down
11 changes: 10 additions & 1 deletion src/componentes/botones/boton-favorito.componente.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useAppDispatch } from '../../redux/hooks';
import { agregaFavorito } from '../slice/rickySlice';
import './boton-favorito.css';
/**
* Boton que indica si un elemento es favorito o no, y da la posibilidad de marcarlo/desmarcarlo
Expand All @@ -8,9 +10,16 @@ import './boton-favorito.css';
* @returns un JSX element
*/
const BotonFavorito = ({esFavorito, onClick}) => {

const dispatch= useAppDispatch();
const src = esFavorito ? "/imagenes/star-filled.png" : "/imagenes/star.png"

return <div className="boton-favorito">

const handleClick=(personaje)=>{
dispatch(agregaFavorito(personaje))
}

return <div className="boton-favorito" onClick={()=>handleClick(onClick)}>
<img src={src} alt={"favorito"} />
</div>
}
Expand Down
19 changes: 0 additions & 19 deletions src/componentes/paginacion/paginacion.componente.jsx

This file was deleted.

38 changes: 38 additions & 0 deletions src/componentes/paginacion/paginacion.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEffect, useState } from 'react';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { busqueda, fetchCharacter, getCharacterByName } from '../slice/rickySlice';
import './paginacion.css';


/**
* Componente que contiene los botones para paginar
*
* Deberás agregar las propiedades necesarias para que funcione correctamente
*
*
* @returns un JSX element
*/
const Paginacion = () => {

const personaje= useAppSelector(state => state.personaje)
const [page, setPage]= useState(1)
const dispatch = useAppDispatch()
const [buscarPersonaje, setBuscarPersonaje] = useState("")

useEffect(() => {
dispatch(fetchCharacter(page))
}, [page])

const cambiarPagina=()=>{
setPage(page-1)
/* dispatch(busqueda(personaje.busqueda))
dispatch(getCharacterByName(personaje.busqueda)) */
}

return <div className="paginacion">
<button disabled={page ===1? true:false} className={"primary"} onClick={cambiarPagina}>Anterior</button>
<button disabled={false} className={"primary"} onClick={() => setPage(page+1)}>Siguiente</button>
</div>
}

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

This file was deleted.

26 changes: 26 additions & 0 deletions src/componentes/personajes/filtros.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useState } from 'react';
import './filtros.css';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { busqueda, getCharacterByName} from '../slice/rickySlice';

const Filtros = () => {

/*const [buscarPersonaje, setBuscarPersonaje] = useState("")*/
const dispatch= useAppDispatch()
const inputValue= useAppSelector(state=> state.personaje.busqueda)

const [buscarPersonaje, setBuscarPersonaje] = useState("")

const buscar=(e:{target:{value:string}})=>{
dispatch(busqueda(e.target.value))
dispatch(getCharacterByName(e.target.value))
setBuscarPersonaje(e.target.value)
}
console.log(buscarPersonaje)
return <div className="filtros">
<label form="nombre">Filtrar por nombre:</label>
<input type="text" placeholder="Rick, Morty, Beth, Alien, ...etc" name="nombre" value={buscarPersonaje} onChange={buscar}/>
</div>
}

export default Filtros;
21 changes: 16 additions & 5 deletions src/componentes/personajes/grilla-personajes.componente.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import './grilla-personajes.css';
import TarjetaPersonaje from './tarjeta-personaje.componente';

Expand All @@ -9,13 +10,23 @@ import TarjetaPersonaje from './tarjeta-personaje.componente';
*
* @returns un JSX element
*/
const GrillaPersonajes = () => {
const GrillaPersonajes = ({personajes}) => {

/*const personaje= useAppSelector(state => state.personaje)*/

return <div className="grilla-personajes">
<TarjetaPersonaje />
<TarjetaPersonaje />
<TarjetaPersonaje />
return (

<div className="grilla-personajes">
{ personajes?.map((personaje)=>{
return <TarjetaPersonaje
personaje= {personaje}
key= {personaje.id}/>
}
)
}

</div>
)
}

export default GrillaPersonajes;
38 changes: 30 additions & 8 deletions src/componentes/personajes/tarjeta-personaje.componente.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import BotonFavorito from '../botones/boton-favorito.componente';
import './tarjeta-personaje.css';

import { fetchCharacter } from '../slice/rickySlice';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { useState } from 'react';
import { agregaFavorito } from '../slice/rickySlice';
/**
* Tarjeta para cada personaje dentro de la grilla de personajes.
*
Expand All @@ -9,15 +12,34 @@ import './tarjeta-personaje.css';
*
* @returns un JSX element
*/
const TarjetaPersonaje = () => {
const TarjetaPersonaje = (props) => {
const personaje= useAppSelector(state => state.personaje)
/* const [favorito, setFavorito] = useState(false)*/
const favorito = useAppSelector(state => state.personaje.favoritos)
const dispatch= useAppDispatch();

const isFavorite= favorito.find((item)=>item.id=== props.personaje.id)

return <div className="tarjeta-personaje">
<img src="https://rickandmortyapi.com/api/character/avatar/1.jpeg" alt="Rick Sanchez"/>
<div className="tarjeta-personaje-body">
<span>Rick Sanchez</span>
<BotonFavorito esFavorito={false} />
</div>
return (
<div className="tarjeta-personaje">

{
<div className="tarjeta-personaje">
<img src={props.personaje.image}/>
<div className="tarjeta-personaje-body">
<span>{props.personaje.name}</span>
<BotonFavorito
esFavorito={!isFavorite? false:true}
onClick={props.personaje}/>
</div>
</div>

}


</div>
)
}


export default TarjetaPersonaje;
4 changes: 3 additions & 1 deletion src/componentes/personajes/tarjeta-personaje.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
font-size: 16px;
font-weight: 500;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}

96 changes: 96 additions & 0 deletions src/componentes/slice/rickySlice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { createAsyncThunk, createSlice} from '@reduxjs/toolkit';

interface Personaje{
id: number,
name: string,
status: string,
species: string,
type: string,
gender: string,
origin: {
name: string,
url: string
},
location: {
name: string,
url: string
},
image: string,
episode: string[],
url: string,
created: string
}

interface initialType{
personajes: Personaje[]
loading: boolean
busqueda: string
favoritos:Personaje[]
}



export const fetchCharacter= createAsyncThunk(
'personajes/list',
async (page: number) =>{
const response = await fetch(`https://rickandmortyapi.com/api/character/?page=${page}&limit=20`)
const parseRes = await response.json()

return parseRes.results
}
)

export const getCharacterByName= createAsyncThunk(
'personajes/byName',
async (name: string) =>{
const response = await fetch(`https://rickandmortyapi.com/api/character/?name=${name}`)
const parseRes = await response.json()

return parseRes.results
}
)

const initialState: initialType = {
personajes: [],
loading: false,
busqueda:"",
favoritos:[]
}


const characterSlice = createSlice({
name: 'personajes',
initialState,
reducers: {
busqueda:(state, action)=>{
state.busqueda= action.payload
},
agregaFavorito:(state, action)=>{
if(!state.favoritos.find(item => item.id === action.payload.id)){
state.favoritos.push(action.payload)
}else{
state.favoritos = state.favoritos.filter(item => item.id !== action.payload.id)
}

}
},
extraReducers: (builder) => {
builder
.addCase(fetchCharacter.pending, (state) => {
state.loading= true
})
.addCase(fetchCharacter.fulfilled, (state, action) => {
state.loading= false
state.personajes= action.payload
})
.addCase(getCharacterByName.fulfilled, (state, action) => {
state.loading=false
state.personajes=action.payload
}
)
},
})

export default characterSlice.reducer

export const {busqueda, agregaFavorito} = characterSlice.actions
Loading