diff --git a/src/data/dataset.js b/src/data/dataset.js index 632aabb3..9a0d6bd6 100644 --- a/src/data/dataset.js +++ b/src/data/dataset.js @@ -1,4 +1,4 @@ -export const characters = [ +export default [ { "id": "daphne-bridgerton", "name": "Daphne Bridgerton", diff --git a/src/index.html b/src/index.html index cbbf4283..4e89d607 100644 --- a/src/index.html +++ b/src/index.html @@ -1,11 +1,13 @@ - - - - - - -
- - - + + + + + Dataverse Chat + + +
+
+ + + \ No newline at end of file diff --git a/src/index.js b/src/index.js index e90a3b48..391b970c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,49 +1,29 @@ -import { Home } from './views/home'; -import { ApiKey } from './views/ApiKey'; -import { ChatIndividual } from './views/chatIndividual'; -import { Error } from './views/error'; +import home from './views/home.js'; +import ApiKey from './views/ApiKey.js'; +import chatIndividual from './views/chatIndividual.js'; +import PageError from './views/PageError.js'; import { setRootEl, setRoutes, onURLChange } from './router.js'; -import { CharacterList } from './components/CharacterList.js'; -import { Statistics } from './components/Statistics.js'; + +const prueba = document.getElementById('root'); const routes = { - '/': Home, - '/apikey': ApiKey, - '/chat': ChatIndividual, - '/error': Error + "/": home, + "/ApiKey": ApiKey, + "/chatIndividual": chatIndividual, + "/PageError": PageError, }; setRoutes(routes); window.addEventListener("DOMContentLoaded", () => { - setRootEl(document.getElementById('root')); + setRootEl(prueba); onURLChange(window.location); }); -window.addEventListener('popstate', () => { +window.addEventListener("popstate", () => { onURLChange(window.location); }); -// Function to handle filtering and sorting in SPA -function handleFiltersAndSorting() { - const familyFilter = document.querySelector('#family-filter').value; - const sortFilter = document.querySelector('#alfabetico').value; - - const characterList = CharacterList({ familyFilter, sortFilter }); - document.getElementById('root').appendChild(characterList); -} - -document.querySelector('#family-filter').addEventListener('change', handleFiltersAndSorting); -document.querySelector('#alfabetico').addEventListener('change', handleFiltersAndSorting); - -document.querySelector('#calcularEstadisticas').addEventListener('click', () => { - const characters = getCharacters(); - const stats = Statistics({ characters }); - document.getElementById('resultado-estadisticas').innerHTML = ''; - document.getElementById('resultado-estadisticas').appendChild(stats); -}); - - /* TODO: 1.- Definir rutas en router. diff --git a/src/lib/dataFunction.js b/src/lib/dataFunction.js index e69de29b..81bbbcfb 100644 --- a/src/lib/dataFunction.js +++ b/src/lib/dataFunction.js @@ -0,0 +1,52 @@ +export const filterData = (data, filterBy, value) => { + return data.filter(character => + character.facts[filterBy].toLowerCase() === value.toLowerCase() + ); +}; + + +export const sortData = (data, sortBy, sortOrder) => { + // exportamos la función para ordenar personajes por nombre + //data:array de objeto(personajes),sortBy:campo del objeto,sortOrder: asc-des + const sortedCharacters = [...data]; + //crea un nuevo array(copia)que contiene todos los elementos del array + return sortedCharacters.sort((a, b) => { + //compara cada par de elementos y luego retorna el array ordenado. + if (sortOrder === 'asc') { + //si es excatamente igual se ordena de forma ascendente + return a[sortBy].localeCompare(b[sortBy]); + //método de las cadenas de texto en JS que compara dos cadenas de texto + } else if (sortOrder === 'des') { + //ademas si ... + return b[sortBy].localeCompare(a[sortBy]); + //comparacion a la inversa (desendente) + + } + }); +}; + +export const computeStats = (data) => { + return data.reduce((estadisticas, character) => { + // Función para calcular estadísticas usando reduce + const sitSentimental = character.facts.sitSentimental.toLowerCase(); + //accede a la propiedad sitSentimental de un objeto character + //y almacena el resultado en la constante sitSentimental + + if (sitSentimental.includes("casad")) { + estadisticas.casados++; + } else if (sitSentimental.includes("solter")) { + estadisticas.solteros++; + } else if (sitSentimental.includes("viud")) { + estadisticas.viudos++; + } else if (sitSentimental.includes("amante")) { + estadisticas.amantes++; + } + return estadisticas; + }, { + casados: 0, + solteros: 0, + viudos: 0, + amantes: 0 + //contador con el que inicializan los contadores + }); +}; \ No newline at end of file diff --git a/src/main.js b/src/main.js index 5e55ce97..7888c01a 100644 --- a/src/main.js +++ b/src/main.js @@ -1,2 +1,2 @@ -import { ApiKey } from './views/ApiKey'; -//marcia nos dijo que colocaramos el import aquí \ No newline at end of file +// import { ApiKey } from './views/ApiKey'; +//marcia nos dijo que colocaramos el import aquí... \ No newline at end of file diff --git a/src/router.js b/src/router.js index 778e632c..82c04d1c 100644 --- a/src/router.js +++ b/src/router.js @@ -1,58 +1,23 @@ +let rootEl; -let ROUTES = {}; -let rootEl = null; - -// Función para establecer el elemento raíz donde se renderizan las vistas -export const setRootEl = (el) => { +export function setRootEl(el) { rootEl = el; } -// Función para establecer las rutas -export const setRoutes = (routes) => { - if (typeof routes !== 'object') { - throw new Error('Las rutas deben ser un objeto'); - } - if (!routes['/error']) { - throw new Error('Las rutas deben definir una ruta /error'); - } - ROUTES = routes; -}; - -// Función para convertir los parámetros de búsqueda en un objeto -const queryStringToObject = (queryString) => { - const params = new URLSearchParams(queryString); - const obj = {}; - for (const [key, value] of params.entries()) { - obj[key] = value; - } - return obj; -} - -// Función para renderizar la vista basada en la ruta -const renderView = (pathname, props = {}) => { - if (rootEl) { - rootEl.innerHTML = ''; // Limpiar el elemento raíz - // Obtener la vista correspondiente o la vista de error - const View = ROUTES[pathname] || ROUTES['/error']; - // Renderizar la vista pasando los props - const viewEl = View(props); - rootEl.appendChild(viewEl); // Agregar la vista al DOM - } +export function setRoutes(routes) { + window.routes = routes; } -// Función para navegar a una nueva ruta -export const navigateTo = (pathname, props = {}) => { - // Actualizar el historial - window.history.pushState({}, '', pathname); - // Renderizar la vista correspondiente - renderView(pathname, props); +export function onURLChange(location) { + const path = location.pathname; + const route = window.routes[path] || window.routes['/error']; + const view = route(); + + rootEl.innerHTML = ''; // Limpia el contenedor antes de agregar la nueva vista + rootEl.appendChild(view); } -// Función para manejar cambios en la URL -export const onURLChange = (location) => { - const pathname = location.pathname; - // Convertir los parámetros de búsqueda en objeto - const searchParams = queryStringToObject(location.search); - // Renderizar la vista basada en la ruta y los parámetros de búsqueda - renderView(pathname, searchParams); +export function navigateTo(path) { + window.history.pushState({}, path, window.location.origin + path); + onURLChange(window.location); } diff --git a/src/views/ApiKey.js b/src/views/ApiKey.js index 97f65dba..b0406605 100644 --- a/src/views/ApiKey.js +++ b/src/views/ApiKey.js @@ -1,7 +1,13 @@ //Crea un nuevo elemento div,le asigna texto como su contenido // y devuelve ese div para que se pueda utilizar en otras partes -export function ApiKey(props) { +export function ApiKey() { const viewEl = document.createElement('div'); - viewEl.textContent = '¡Este es el Api Key!'; + viewEl.innerHTML = ` +

Configuración de API Key

+

Ingresa tu clave API para acceder al chat.

+ + + `; return viewEl; } +export default ApiKey; \ No newline at end of file diff --git a/src/views/PageError.js b/src/views/PageError.js new file mode 100644 index 00000000..5470a990 --- /dev/null +++ b/src/views/PageError.js @@ -0,0 +1,7 @@ +export function PageError() { // exportamos la función ErrorPage que devuelve un elemento HTML + const viewEl = document.createElement('div'); // Creamos un contenedor para la vista de error + viewEl.innerHTML = '

Error 404

¡Página no encontrada!

'; // Establecemos el contenido de la vista + return viewEl; // Retornamos el elemento creado +} +export default PageError; + diff --git a/src/views/chatIndividual.js b/src/views/chatIndividual.js index b1235c49..1068278b 100644 --- a/src/views/chatIndividual.js +++ b/src/views/chatIndividual.js @@ -1,6 +1,12 @@ -export function ChatIndividual(props) { +export function chatIndividual() { const viewEl = document.createElement('div'); - viewEl.textContent = '¡Este es el chatINdividual!'; + viewEl.innerHTML = ` +

Chat Individual

+

Aquí puedes chatear con un personaje seleccionado.

+
+ +
+ `; return viewEl; } - +export default chatIndividual; diff --git a/src/views/error.js b/src/views/error.js deleted file mode 100644 index 85933e9a..00000000 --- a/src/views/error.js +++ /dev/null @@ -1,6 +0,0 @@ -export function Error(props) { - const viewEl = document.createElement('div'); - viewEl.textContent = '¡Este es el error!'; - return viewEl; -} - diff --git a/src/views/home.js b/src/views/home.js index 38e2a56f..7ae0f41a 100644 --- a/src/views/home.js +++ b/src/views/home.js @@ -1,5 +1,9 @@ -export function Home(props) { +export function home() { const viewEl = document.createElement('div'); - viewEl.textContent = '¡Este es el home!'; + viewEl.innerHTML = ` +

Bienvenido al Dataverse Chat

+

Explora y conéctate con otros personajes.

+ `; return viewEl; } +export default home; \ No newline at end of file diff --git a/test/dataFunction.spec.js b/test/dataFunction.spec.js new file mode 100644 index 00000000..c69983c9 --- /dev/null +++ b/test/dataFunction.spec.js @@ -0,0 +1,50 @@ +// test/dataFunctions.spec.js +import data from '../src/data/dataset.js'; //importamos el dataset +import { filterData } from '../src/lib/dataFunction.js'; +import { sortData } from '../src/lib/dataFunction.js'; +import { computeStats } from '../src/lib/dataFunction.js'; + +describe('filterData', () => { + it('returns characters from the Bridgerton family', () => { + const result = filterData(data, 'familia', 'Bridgerton'); // Filtra la familia "Bridgerton": Utiliza filterData para obtener todos los personajes que pertenecen a la familia "Bridgerton". + const expectedCharacters = data.filter(character => character.facts.familia === 'Bridgerton'); // Esto filtra el dataset original para obtener el array de personajes que coinciden con la familia "Bridgerton" y compara con el resultado de filterData + expect(result).toEqual(expectedCharacters); // Compara ambos resultados + }); + + it('returns an empty array if no characters match the family', () => { //Filtra la familia "Featherington": Similar a la primera prueba, pero busca personajes de la familia "Featherington". + const result = filterData(data, 'familia', 'Featherington'); + const expectedCharacters = data.filter(character => character.facts.familia === 'Featherington'); //Si ningún personaje coincide con la familia, se espera que la función retorne un array vacío. + + expect(result).toEqual(expectedCharacters); + }); +}); + +const getExpectedSortedData = (data, order) => { + return [...data].sort((a, b) => { + if (order === 'asc') return a.name.localeCompare(b.name); + if (order === 'des') return b.name.localeCompare(a.name); + }); +}; + +describe('sortData', () => { + test('should sort data by name in ascending order', () => { + expect(sortData(data, 'name', 'asc')).toEqual(getExpectedSortedData(data, 'asc')); + }); + + test('should sort data by name in descending order', () => { + expect(sortData(data, 'name', 'des')).toEqual(getExpectedSortedData(data, 'des')); + }); +}); + +describe('computeStats', () => { + test('should compute correct statistics for sentiment status', () => { + const result = computeStats(data); + const expected = { + casados: 13, + solteros: 5, + viudos: 4, + amantes: 2, + }; + expect(result).toEqual(expected); + }); +}); \ No newline at end of file