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

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.2",
"react-router-dom": "^6.8.1",
"react-scripts": "^5.0.1",
"typescript": "^4.9.5",
"web-vitals": "^3.1.1"
},
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import './boton-favorito.css';
import { BotonFavoritoProps } from '../../interfaces/interfaces';
/**
* 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
*/
const BotonFavorito = ({esFavorito, onClick}) => {


const BotonFavorito = ({esFavorito, onClick}: BotonFavoritoProps) => {
const src = esFavorito ? "/imagenes/star-filled.png" : "/imagenes/star.png"

return <div className="boton-favorito">
Expand Down
19 changes: 0 additions & 19 deletions src/componentes/paginacion/paginacion.componente.jsx

This file was deleted.

24 changes: 24 additions & 0 deletions src/componentes/paginacion/paginacion.componente.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

import { IPagination } from '../../interfaces/interfaces';
import { DECREMENT_PAGE, INCREMENT_PAGE } from '../../store/slice/pagination/paginationSlice';
import { useAppDispatch } from '../../store/store';
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 = ({page}:IPagination) => {
const dispatch = useAppDispatch();

return <div className="paginacion">
<button onClick={()=>dispatch(DECREMENT_PAGE())} className={"primary"}>Anterior</button>
<button onClick={()=>dispatch(INCREMENT_PAGE())} className={"primary"}>Siguiente</button>
</div>
}

export default Paginacion;
4 changes: 2 additions & 2 deletions src/componentes/personajes/filtros.componente.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import './filtros.css';
const Filtros = () => {

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

export default Filtros;
export default Filtros;
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const TarjetaPersonaje = () => {
<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} />
<BotonFavorito esFavorito ={false} />
</div>
</div>
}
Expand Down
18 changes: 11 additions & 7 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { store } from "./store/store";

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

// If you want to start measuring performance in your app, pass a function
Expand Down
63 changes: 63 additions & 0 deletions src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
export interface BotonFavoritoProps
{
esFavorito: boolean,
onClick?: () => void

}

export interface Welcome {
info: infoApi;
results: Icharacter[];
}

export interface infoApi {
count: number;
pages: number;
next: string;
prev: string;
}

export interface Icharacter {
id: number;
name: string;
status: Status;
species: string;
type: string;
gender: Gender;
origin: Location;
location: Location;
image: string;
episode: string[];
url: string;
created: Date;
}

export enum Gender {
Female = "Female",
Male = "Male",
Unknown = "unknown",
}

export interface Location {
name: string;
url: string;
}

export enum Status {
Alive = "Alive",
Dead = "Dead",
Unknown = "unknown",
}

export interface characterState
{
dataCharacter: Icharacter[],
loading: boolean,
Error:string | null
}


export interface IPagination {
page: number
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "./Detalle.css";
import BotonFavorito from "../componentes/botones/boton-favorito.componente";
import TarjetaEpisodio from "../componentes/episodios/tarjeta-episodio.componente";
import { BotonFavoritoProps } from '../interfaces/interfaces';

/**
* Esta es la pagina de detalle. Aqui se puede mostrar la vista sobre el personaje seleccionado junto con la lista de episodios en los que aparece
Expand All @@ -26,7 +27,7 @@ const PaginaDetalle = () => {
<p>Planeta: Earth</p>
<p>Genero: Male</p>
</div>
<BotonFavorito esFavorito={false} />
<BotonFavorito esFavorito={false} />
</div>
</div>
<h4>Lista de episodios donde apareció el personaje</h4>
Expand Down
15 changes: 13 additions & 2 deletions src/paginas/Inicio.pagina.jsx → src/paginas/Inicio.pagina.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import Filtros from "../componentes/personajes/filtros.componente"
import GrillaPersonajes from "../componentes/personajes/grilla-personajes.componente"
import Paginacion from "../componentes/paginacion/paginacion.componente";
import { useAppDispatch, useAppSelector } from "../store/store";
import { GET_CHARACTERS } from "../store/slice/character/thunksCharacter";
import { useEffect } from "react";

/**
* Esta es la pagina principal. Aquí se debera ver el panel de filtros junto con la grilla de personajes.
Expand All @@ -11,15 +14,23 @@ import Paginacion from "../componentes/paginacion/paginacion.componente";
* @returns la pagina de inicio
*/
const PaginaInicio = () => {
const dispatch = useAppDispatch()
const{value:pageValue} = useAppSelector((state) => state.pages)
const{dataCharacter} = useAppSelector((state) => state.characters)

useEffect(() => {
dispatch(GET_CHARACTERS({data:pageValue, parameter: 'page'}))
},[pageValue])

return <div className="container">
<div className="actions">
<h3>Catálogo de Personajes</h3>
<button className="danger">Test Button</button>
</div>
<Filtros />
<Paginacion />
<Paginacion page={pageValue} />
<GrillaPersonajes />
<Paginacion />
<Paginacion page={pageValue}/>
</div>
}

Expand Down
36 changes: 36 additions & 0 deletions src/store/slice/character/characterSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { Icharacter, characterState } from "../../../interfaces/interfaces";
import { GET_CHARACTERS } from "./thunksCharacter";

const inicialState: characterState = {
dataCharacter: [],
loading: true,
Error: null,
};

export const characterSlice = createSlice({
name: "character",
initialState: inicialState,

reducers: {},

extraReducers: (builder) => {
builder.addCase(GET_CHARACTERS.pending, (state) => {
state.loading = true;
})

builder.addCase(GET_CHARACTERS.fulfilled, (state, action) => {
state.dataCharacter = action.payload;
state.loading = false;
})

builder.addCase(GET_CHARACTERS.rejected, (state, action) => {
state.loading = false;
state.Error = action.error.message ?? 'Se ha presentado un error en la petición'
})
},

});

const charactersReducer = characterSlice.reducer;
export default charactersReducer;
34 changes: 34 additions & 0 deletions src/store/slice/character/thunksCharacter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import { Icharacter } from "../../../interfaces/interfaces";

export const GET_CHARACTERS = createAsyncThunk
(
'character/GET_CHARACTERS',
async ({data, parameter}: {data:number | string; parameter:string})=>
{
try
{
const dataCharacter = await fetch(`https://rickandmortyapi.com/api/character/?${parameter}=${data}`);
const dataResponseCharacter = await dataCharacter.json();
const dataResulsCharacter = dataResponseCharacter.results;
return dataResulsCharacter;
}


catch(error)
{
console.error("Error en la petición:", error);


}


}
);

export const GET_CHARACTER_BY_ID = createAsyncThunk('character/GET_CHARACTERS',async (id:number): Promise<Icharacter[]> => {
const dataResulsCharacter = await fetch(`https://rickandmortyapi.com/api/character/${id}`)
const dataResponseCharacter = await dataResulsCharacter.json();
return dataResponseCharacter;

})
31 changes: 31 additions & 0 deletions src/store/slice/pagination/paginationSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import { createSlice } from '@reduxjs/toolkit';
import React from 'react'

export type paginationSlice = {
value : number,
}

const initialState : paginationSlice ={
value:0
}

export const paginationSlice = createSlice({
name : 'page',
initialState: initialState,
reducers : {
INCREMENT_PAGE : (state) => {
state.value += 1;
},
DECREMENT_PAGE : (state) => {
state.value -= 1;
},

}
});

const paginationReducer = paginationSlice.reducer;

export const {INCREMENT_PAGE, DECREMENT_PAGE} = paginationSlice.actions;

export default paginationReducer;
24 changes: 24 additions & 0 deletions src/store/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { configureStore } from "@reduxjs/toolkit";
import charactersReducer from "./slice/character/characterSlice";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import paginationReducer from "./slice/pagination/paginationSlice";


export const store = configureStore
({
reducer:
{
pages:paginationReducer,
characters:charactersReducer,
},
});

type RootState = ReturnType<typeof store.getState>;
type AppDispatch = typeof store.dispatch;

type DispatchFunc=()=>AppDispatch

export const useAppDispatch:DispatchFunc = useDispatch
export const useAppSelector:TypedUseSelectorHook<RootState> = useSelector;

export default store;