diff --git a/Readme.md b/Readme.md index ed84ec5c..9675f0a1 100644 --- a/Readme.md +++ b/Readme.md @@ -1,148 +1,24 @@ -# Creando una Red Social +# Life Style: Creando una red social -Bienvenida a tu primer proyecto del track de Frontend en Laboratoria. +Lifestyle está dirigido a hombres y mujeres de 25-35 años principalmente que tienen una vida sana y activa y/o desean tenerla. Esta aplicación gratuita está diseñada para que los usuarios interesados en el tema puedan mejorar su estilo de vida y que también personas desde principiantes a expertas en el tema compartan su conocimiento sobre temas saludables. -En este proyecto construirás una red social, cuya temáticas dejaremos a tu elección. +### Prototipo de baja fidelidad (sketch) -Aquí algunas ideas para inspirarte: + -- Alimentación -- Feminismo -- Educación -- Salud -- Energías Renovables +### Prototipo de alta fidelidad -Las **caraterísticas técnicas** de tu aplicación serán las siguientes: -- Debe ser una Single-Page Application [SPA](https://dzone.com/articles/how-single-page-web-applications-actually-work) ([versión traducida](https://dzone.com/articles/how-single-page-web-applications-actually-work)) -- Debe ser diseñada con un enfoque [mobile first](https://darwindigital.com/mobile-first-versus-responsive-web-design/) ([versión traducida](https://translate.google.com/translate?hl=&sl=auto&tl=es&u=https%3A%2F%2Fdarwindigital.com%2Fmobile-first-versus-responsive-web-design)) -- Debe permitir la persintencia de datos - -Para implementar tu aplicación usarás *HTML5*, *CCS3* o *SASS*, *Vanilla JavaScript(ES6+)*, *Firebase* o *LocalStogarge* + + + + -## Objetivo +### Demo Lifestyle + + + -El objetivo de este proyecto es construir una Red Social, Single-Page Application (SPA), responsiva en la que podamos escribir, leer, actualizar y eliminar datos. - -Para ello deberás poner en juego tu creatividad para generar ideas que lleven a una solución original y valiosa del problema, trabajando en equipo buscando feedback constante. - -En otras palabras, seguirás afianzando todo lo aprendido en el Common Core, pero en particular verás : - -### Planificación - -* Te recomendamos utilizar *projects*, *issues* y *milestones* de GitHub para gestionar la planificación de tu proyecto. Estos recursos serán la fuente de organización de tu equipo y a través de estas herramientas tus coaches podrán ver el avance del proyecto y darte feedback. - -* Escribir, de manera colaborativa, las **Definiciones de terminado** y **Criterios de Aceptación** por cada **Historia de usuario** que te daremos para este proyecto y que se deberán ver reflejadas en tu planificación. - -* **Priorizar** la implementación de tus funcionalidades, en función al esfuerzo que demandan en relación al valor que le aportan al usuario, y ejecutar en equipo todas las historias de usuario dentro del tiempo estimado para cada sprint y que finalmente se vean reflejadas en publicaciones completamentamente funcionales al final de cada sprint. - -* Adquirir la disciplina de la completitud, terminando una historia de usuario antes de pasar a la siguiente (es decir, que cumple con *Definición de Terminado* y *Criterios de Aceptación* contemplando todos los puntos que son objetivos de aprendizaje para este proyecto). - -### Desarrollo frontend - -#### Arquitectura de la aplicación - -- Diseñar la arquitectura de tu aplicación, modularizando tu código a través de *es modules* ([`import`](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Sentencias/import) y [`export`](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Sentencias/export)) - -- Familiarizarte con el patrón modelo - vista - controlador ([MVC](https://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador)). - -#### Tecnologías HTML5 y CSS3/SASS - -* Aplicar HTML5 semántico en tu proyecto. -* Aplicar y reforzar los conceptos fundamentales de CSS3. -* Implementar selectores de clase evitando la redundancia de estilos en CCS3. -* Utilizar `flexbox` para lograr un diseño `mobile first`, implementando un layout que te permita crear un diseño adaptativo para **mobile y desktop** - -A continuación te proporcionamos el layout (diseño) de la vista mobile y desktop que deberás replicar visualmente y cuyo contenido, colores y fuentes de texto, dejaremos a tu elección. - -* Vista mobile - - ![mobile](https://user-images.githubusercontent.com/32286663/56174616-ec9f6100-5fb8-11e9-9edb-d5ef7c251d9c.png) - -* Vista Desktop - - ![desktop](https://user-images.githubusercontent.com/32286663/56174626-fcb74080-5fb8-11e9-8854-26e8d9c4e25f.png) - -#### JavaScript (ES6+) - -* Utilizar modulos de ES6 para poder modularizar tu código JavaScript. -* Reforzar tu conocimiento sobre el uso de Template literals (Template strings). -* Reforzar tu conocimiento de la manipulacion de los elementos del DOM a traves JavaScript. -* Implementar un sistema de rutas para cambiar de una vista a otra de manera dinámica (SPA). -* Testear la lógica de tu aplicación, con Jest cuidando que el coverage pase el 90% de statements (sentencias), functions (funciones), lines (líneas), y branches (ramas). - -### Persistencia de datos - -En los proyectos anteriores solo has consumido (leído) datos, por ejemplo, a través de un archivo `json` o utilizando `fetch`. - -En este proyecto diseñarás la estructura de esos datos, la forma de consultarlos, actualizarlos, modificarlos y eliminarlos según los requerimiento del usuario. Para llevarlo a cabo utilizaras `Firestore` de `Firebase` o `LocalStogarge` una `Web Storage API` - -#### Firebase - -El objetivo de usar Firestore en este proyecto, es que aprendes a manejar y persistir datos a traves de una base de datos no relacional, en tiempo real y puedas implementar operaciones CRUD (Creación, Lectura, Actualización y eliminación) de datos. - -## Consideraciones generales del proyecto - -* Este proyecto debe ser desarrollado en equipos de trabajo de 3 integrantes. - -* La duración propuesta del proyecto es **3 sprints**, con una duración de una semana cada uno. - -* Te daremos las **historias de usuario** con el fin de presentarte los requerimientos y funcionalidades que desea el usuario final. - -* La **planificación es vital**, para ello te recomendamos utilizar el flujo de trabajo colaborativo que nos ofrecen los projects de GitHub, para que puedas **escribir tus definiciones de terminado** y **criterios de aceptación** por cada historia de usuario con el objetivo que determinen, en equipo, **qué hacer** en el sprint y **cómo se realizará**. - -* Para que todas las miembros de tu equipo puedan lograr los objetivos de aprendizaje, deberán determinar cuál será la estrategia de desarrollo que utilizarán: división por sub-historias, pair programming, code reviews, etc. - -## Restricciones Técnicas - -* Debes utilizar `flexbox` o `CSSGrid` para posicionar tus elementos. Si está permitido el uso de frameworks de CCS (bootstrap), y de componentes flotantes. - -* Ya te damos un diseño (layout) de la vista mobile y desktop, queremos que lo repliques a nivel *pixel perfect*, el contenido, paleta de colores y fuentes, depende de la temática que van a elegir como equipo. La implementación de ese layout deberá formar parte de la *definición de terminado* de tus historias de usuario. - -* Los test son **fundamentales** y deberán formar parte de tu definición de terminado, te recomendamos que comiences a implementarlos desde el comienzo. - -## Historias de Usuario - -* Como usuario nuevo debo poder crear una cuenta con email y password válidos para poder iniciar sesion e ingresar a la red social. - -* Como usuario nuevo debo poder tener la opción de iniciar sesión con mi cuenta de Google o Facebook para ingresar a la red social sin necesidad de crear una cuenta de email válido. - -* Como usuario loggeado debo poder crear, guardar, modificar en el mismo lugar (in place) y eliminar una publicación (post) privada o pública, que puede ser una frase o una imagen. - -* Como usuario loggeado debo poder ver todos los posts públicos y privados que he creado hasta ese momento, desde el más reciente hasta el más antiguo, así como la opción de poder cambiar la configuración de privacidad de mis post. - -* Yo como usuario loggeado, puedo dar like y llevar un conteo de likes en mi publicación así como poder escribir, guardar, editar o eliminar un comentario en mi publicación. - -* Al final debo poder ingresar a la red social y poder visualizar los datos de mi perfil creado o editarlos. - -* Te dejamos un ejemplo de cómo definir criterios de aceptación y definiciones de terminado para una H.U. Si se te complica definirlas o no tienes idea de que considerar para cada H.U. es de gran ayuda revisar redes sociales como `facebok`, `twitter`, `instagram`, `devopedia` o la red social que más te guste y puedas evaluar qué consideran en cada funcionalidad para darla como terminada y aceptada. - - > Como usuario nuevo debo poder crear una cuenta con email y password para - > poder iniciar sesion. Por otro lado, necesito también tener la opción de - > iniciar sesión con mi cuenta de Google o Facebook. - > - > **Criterios de aceptación** - > - Si el mail o password no es válido, al momento de logearme, debo poder - > ver un mensaje de error. - > - Debe ser visible si hay algún mensaje de error. - > - Debo poder ver esta página de creación en Móviles y desktop (responsive). - > - No debe necesitar recargar la página para crear una cuenta (SPA). - > - > **Definición de terminado** - > - La funcionalidad cumple satisface los criterios de aceptación. - > - La funcionalidad tiene _test unitarios_. - > - El diseño visual corresponde al prototipo de alta fidelidad. - > - El código de esta funcionalidad recibió code review. - > - La funcionalidad esta desplegada y pública para ser probada. - > - La funcionalidad fue probada manualmente. - > - Se hicieron pruebas de usuabilidad y se implementó el feedback si se - > consideró necesario. - -## Objetivos de aprendizaje - -Antes de empezar el proyecto, recuerda agregar tus objetivos de aprendizaje pendientes de tu proyecto -anterior en la siguiente sección. - -### Objetivos de aprendizajes pendientes +### Objetivos de aprendizaje Edith Ortiz Cortés ### HTML y CSS @@ -153,24 +29,24 @@ anterior en la siguiente sección. ### DOM y Web APIs -* [ ] [Manipulación dinámica del DOM](https://developer.mozilla.org/es/docs/Referencia_DOM_de_Gecko/Introducci%C3%B3n) +* ☑ [Manipulación dinámica del DOM](https://developer.mozilla.org/es/docs/Referencia_DOM_de_Gecko/Introducci%C3%B3n) * [ ] [History API](https://developer.mozilla.org/es/docs/DOM/Manipulando_el_historial_del_navegador) -* [ ] [`localStorage`] +* ☑ [`localStorage`] ### Javascript * [ ] [Uso de callbacks](https://developer.mozilla.org/es/docs/Glossary/Callback_function) -* [ ] [Consumo de Promesas](https://scotch.io/tutorials/javascript-promises-for-dummies#toc-consuming-promises) -* [ ] Uso ES modules +* ☑ [Consumo de Promesas](https://scotch.io/tutorials/javascript-promises-for-dummies#toc-consuming-promises) +* ☑ Uso ES modules ([`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) | [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)) ### Firebase -* [ ] [Firestore](https://firebase.google.com/docs/firestore) -* [ ] [Firebase Auth](https://firebase.google.com/docs/auth/web/start) +* ☑ [Firestore](https://firebase.google.com/docs/firestore) +* ☑ [Firebase Auth](https://firebase.google.com/docs/auth/web/start) * [ ] [Firebase security rules](https://firebase.google.com/docs/rules) -* [ ] [Uso de onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) +* ☑ [Uso de onSnapshot](https://firebase.google.com/docs/firestore/query-data/listen) | [onAuthStateChanged](https://firebase.google.com/docs/auth/web/start#set_an_authentication_state_observer_and_get_user_data) ### Testing @@ -181,92 +57,19 @@ anterior en la siguiente sección. ### Colaboración en Github -* [ ] Branches -* [ ] Pull Requests +* ☑ Branches +* ☑ Pull Requests * [ ] Tags ### Organización en Github -* [ ] Projects -* [ ] Issues -* [ ] Labels -* [ ] Milestones +* ☑ Projects +* ☑ Issues +* ☑ Labels +* ☑ Milestones ### Buenas prácticas de desarrollo * [ ] Modularización * [ ] Nomenclatura / Semántica -* [ ] Linting - -*** - -## Recursos - -### Mobile first - -El concepto de [_mobile first_](https://www.mediaclick.es/blog/diseno-web-responsive-design-y-la-importancia-del-mobile-first/) -hace referencia a un proceso de diseño y desarrollo donde partimos de cómo se ve -y cómo funciona la aplicación en un dispositivo móvil primero, y más adelante se -ve como adaptar la aplicación a pantallas progresivamente grandes y -características específicas del entorno desktop. Esto es en contraposición al -modelo tradicional, donde primero se diseñaban los websites (o webapps) para -desktop y después se trataba de _arrugar_ el diseño para que entre en pantallas -más chicas. La clave acá es asegurarse de que desde el principio diseñan usando -la vista _responsive_ de las herramientas de desarrollador (developer tools) del -navegador. De esa forma, partimos de cómo se ve y comporta la aplicación en una -pantalla y entorno móvil. - -### Múltiples vistas - -En proyectos anteriores nuestras aplicaciones habían estado compuestas de una -sola _vista_ principal (una sóla _página_). En este proyecto se introduce la -necesidad de tener que dividir nuestra interfaz en varias _vistas_ o _páginas_ -y ofrecer una manera de navegar entre ellas. - -### Escritura de datos - -En los proyectos anteriores hemos consumido (leído) datos, pero todavía no -habíamos escrito datos (salvar cambios, crear datos, borrar, ...). En este -proyecto tendrás que crear (salvar) nuevos datos, así como leer, actualizar y -modificar datos existentes. Estos datos se podrán guardar de forma remota -usando [Firestore](https://firebase.google.com/docs/firestore) o de forma -local utilizando`localStorage`. - -### Autenticación y autorización - -Hasta el momento, los proyectos han sido pensados como recursos públicos, donde todos -los usuarios compartían un mismo rol y la misma información. - -En este proyecto tendrás que diferenciar la información a mostrar y modificar, -dependiendo de la identidad del usuario. -De la misma manera deberás crear reglar de autorización para el acceso a los -datos. - -Para esto utilizaras respectivamente -[`Firebase authentication`](https://firebase.google.com/docs/auth/) y -[`Firestore security rules`](https://firebase.google.com/docs/firestore/security/get-started) - -### CSS - -En este proyecto queremos que ganes confianza y experiencia con CSS profesional, -por eso usarás [`flexbox`](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) -para posicionar tus elementos. - -Recuerda que no puedes usar frameworks CSS, sólo *vanilla css* o [*sass*](https://sass-lang.com/). - -### Otras: - -* [Pildora SPA](https://www.loom.com/share/fa63a8ad0e9a43428222c15b6f6613d3) -* [Repositorio de pildora de SPA](https://github.com/betsyvies/bootcamp-spa) -* [Pildora de mock Firebase](https://www.youtube.com/watch?v=06myVn41OTY&t=1s) -* [Repositorio de pildora de mock Firebase](https://github.com/Danielalab/2018-2-Testing) -* [Pildora MVC](https://github.com/merunga/todomvc-vanillajs) -* [Modulos: Export](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Sentencias/export) -* [Modulos: Import](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Sentencias/import) -* [Diseño web, responsive design y la importancia del mobile first - Media Click](https://www.mediaclick.es/blog/diseno-web-responsive-design-y-la-importancia-del-mobile-first/) -* [Mobile First: el enfoque actual del diseño web móvil - 1and1](https://www.1and1.es/digitalguide/paginas-web/diseno-web/mobile-first-la-nueva-tendencia-del-diseno-web/) -* [Mobile First - desarrolloweb.com](https://desarrolloweb.com/articulos/mobile-first-responsive.html) -* [Mobile First - ZURB](https://zurb.com/word/mobile-first) -* [Mobile First Is NOT Mobile Only - Nielsen Norman Group](https://www.nngroup.com/articles/mobile-first-not-mobile-only/) - -*** +* [ ] Linting \ No newline at end of file diff --git a/_mocks_/firebase-mock.js b/_mocks_/firebase-mock.js new file mode 100644 index 00000000..3afcd5cc --- /dev/null +++ b/_mocks_/firebase-mock.js @@ -0,0 +1,21 @@ +const firestoreMock = () => { + return { + collection: (nameCollection) =>{ + return { + add: (objData) => { + return new Promise((resolve) => { + resolve('Hola!') + }) + } + } + } + } +} + +const firebase = { + firestore: firestoreMock +} + +export default jest.fn(() => { + return firebase; +}) \ No newline at end of file diff --git a/images/demo.PNG b/images/demo.PNG new file mode 100644 index 00000000..f2d07fc1 Binary files /dev/null and b/images/demo.PNG differ diff --git a/images/demo2.PNG b/images/demo2.PNG new file mode 100644 index 00000000..d11f52bf Binary files /dev/null and b/images/demo2.PNG differ diff --git a/images/demo3.PNG b/images/demo3.PNG new file mode 100644 index 00000000..4687c6ae Binary files /dev/null and b/images/demo3.PNG differ diff --git a/images/proboceto.PNG b/images/proboceto.PNG new file mode 100644 index 00000000..39f967b2 Binary files /dev/null and b/images/proboceto.PNG differ diff --git a/images/protalta.PNG b/images/protalta.PNG new file mode 100644 index 00000000..e2c4e7f0 Binary files /dev/null and b/images/protalta.PNG differ diff --git a/images/protalta2.PNG b/images/protalta2.PNG new file mode 100644 index 00000000..c005dfb9 Binary files /dev/null and b/images/protalta2.PNG differ diff --git a/images/protalta3.PNG b/images/protalta3.PNG new file mode 100644 index 00000000..a233d6b3 Binary files /dev/null and b/images/protalta3.PNG differ diff --git a/images/protalta4.PNG b/images/protalta4.PNG new file mode 100644 index 00000000..c84c3a0f Binary files /dev/null and b/images/protalta4.PNG differ diff --git a/package.json b/package.json index 9a365577..54cd991e 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,6 @@ ], "license": "MIT", "scripts": { - "htmlhint": "htmlhint dist/*.html ", - "eslint": "eslint --ext .js src/ test/", - "stylelint": "stylelint --aei src/**/*.css", - "pretest": "npm run htmlhint && npm run eslint && npm run stylelint", "test": "jest --coverage", "start": "serve src/" }, @@ -28,9 +24,13 @@ "eslint-plugin-jest": "^22.1.2", "htmlhint": "^0.11.0", "jest": "^24.8.0", + "mock-cloud-firestore": "^0.12.0", "regenerator-runtime": "^0.13.1", "serve": "^11.0.2", "stylelint": "^10.1.0", "stylelint-config-recommended": "^2.2.0" + }, + "dependencies": { + "https-localhost": "^4.5.2" } -} \ No newline at end of file +} diff --git a/src/example.js b/src/example.js deleted file mode 100644 index 52d2c7ea..00000000 --- a/src/example.js +++ /dev/null @@ -1,3 +0,0 @@ -export const example = () => { - // aquí tu código -} \ No newline at end of file diff --git a/src/images/browser.png b/src/images/browser.png new file mode 100644 index 00000000..1c96e24c Binary files /dev/null and b/src/images/browser.png differ diff --git a/src/images/camera.png b/src/images/camera.png new file mode 100644 index 00000000..ce1e4704 Binary files /dev/null and b/src/images/camera.png differ diff --git a/src/images/comment.png b/src/images/comment.png new file mode 100644 index 00000000..b6db1915 Binary files /dev/null and b/src/images/comment.png differ diff --git a/src/images/edit.png b/src/images/edit.png new file mode 100644 index 00000000..6f8fba75 Binary files /dev/null and b/src/images/edit.png differ diff --git a/src/images/facebook.png b/src/images/facebook.png new file mode 100644 index 00000000..ad6e9e68 Binary files /dev/null and b/src/images/facebook.png differ diff --git a/src/images/gmail.png b/src/images/gmail.png new file mode 100644 index 00000000..ba182765 Binary files /dev/null and b/src/images/gmail.png differ diff --git a/src/images/grayHeart.png b/src/images/grayHeart.png new file mode 100644 index 00000000..b8c676dc Binary files /dev/null and b/src/images/grayHeart.png differ diff --git a/src/images/logOut.png b/src/images/logOut.png new file mode 100644 index 00000000..871b7e39 Binary files /dev/null and b/src/images/logOut.png differ diff --git a/src/images/logo.png b/src/images/logo.png new file mode 100644 index 00000000..126d7a68 Binary files /dev/null and b/src/images/logo.png differ diff --git a/src/images/logoLifestyle.png b/src/images/logoLifestyle.png new file mode 100644 index 00000000..13f928f8 Binary files /dev/null and b/src/images/logoLifestyle.png differ diff --git a/src/images/logoWhite.png b/src/images/logoWhite.png new file mode 100644 index 00000000..4448b966 Binary files /dev/null and b/src/images/logoWhite.png differ diff --git a/src/images/plusImage.png b/src/images/plusImage.png new file mode 100644 index 00000000..13498d87 Binary files /dev/null and b/src/images/plusImage.png differ diff --git a/src/images/redHeart.png b/src/images/redHeart.png new file mode 100644 index 00000000..3c6b1c34 Binary files /dev/null and b/src/images/redHeart.png differ diff --git a/src/images/whiteHeart.png b/src/images/whiteHeart.png new file mode 100644 index 00000000..ea451868 Binary files /dev/null and b/src/images/whiteHeart.png differ diff --git a/src/images/xGreen.png b/src/images/xGreen.png new file mode 100644 index 00000000..ea80c559 Binary files /dev/null and b/src/images/xGreen.png differ diff --git a/src/images/xRed.png b/src/images/xRed.png new file mode 100644 index 00000000..77f04cb3 Binary files /dev/null and b/src/images/xRed.png differ diff --git a/src/index.html b/src/index.html index bb6937cc..2c1ca8e4 100644 --- a/src/index.html +++ b/src/index.html @@ -4,9 +4,37 @@ - Document + + lifestyle - +
+ +
+
+
+
+ +
+ + + + + + + \ No newline at end of file diff --git a/src/index.js b/src/index.js index 35868bab..64cc10c2 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,37 @@ -import { example } from './example.js'; +import singIn from './login.js'; +import profile from './profile.js'; +import welcomeView from './welcome.js'; +import showOupladWindow from './uopladContent.js'; +let btns= document.querySelectorAll('.btnNav'); -example(); +function router(root) { + singIn(); + switch(root){ + case 'profile': + profile(); + break; + case 'welcome': + welcomeView(); + break; + case 'oupladContent': + showOupladWindow(); + break; + } +} + +// btns.forEach(btn => btn.onclick= e => router(e.target.id)) +// Your web app's Firebase configuration +const firebaseConfig = { + apiKey: 'AIzaSyBuxP-xlUpYjWc5KNNt6q0hKbsxc8L4cE4', + authDomain: 'cdmx009-f4cac.firebaseapp.com', + databaseURL: 'https://cdmx009-f4cac.firebaseio.com', + projectId: 'cdmx009-f4cac', + storageBucket: 'cdmx009-f4cac.appspot.com', + messagingSenderId: '206411662308', + appId: '1:206411662308:web:8c3266d5640e307ca57df1', + measurementId: 'G-L6NB5984DB', +}; +// Initialize Firebase +firebase.initializeApp(firebaseConfig); +firebase.firestore(); +window.addEventListener('load', router); diff --git a/src/login.js b/src/login.js new file mode 100644 index 00000000..f375f8fe --- /dev/null +++ b/src/login.js @@ -0,0 +1,79 @@ +import showOupladWindow from './uopladContent.js' +import welcomeView from './welcome.js' +import profile from './profile.js' +import { showRegisterWindow } from './register.js' +let content= document.querySelector(".root"); +let staticMenu= document.querySelector("#staticMenu"); +let btnOut= document.querySelector("#out"); + +function singIn (){ + btnOut.style.display="none"; + staticMenu.style.display= "none"; + content.innerHTML=''; + let profileView= ` +
+
+ +
+ +
+ +
+ +
+

O inicia sesión con:

+
+ + +
+ +
` + content.innerHTML= profileView; + // staticMenu.remove(); + document.querySelector("#btnRegister").addEventListener('click', showRegisterWindow); + document.querySelector("#profile").addEventListener('click', profile); + let btnFacebook= document.querySelector("#loginFacebook"); + btnFacebook.onclick= authFacebook; + function authFacebook () { + let provider= new firebase.auth.FacebookAuthProvider(); + firebase.auth().signInWithPopup(provider).then(function(result){ + alert("Éxito"); + welcomeView(); + console.log(result); + }) + .catch(function(error){ + alert("Error"); + console.log(error); + }) + } + let btnGmail= document.querySelector("#loginGmail"); + btnGmail.onclick= authGmail; + function authGmail () { + let provider = new firebase.auth.GoogleAuthProvider(); + firebase.auth().signInWithPopup(provider).then(function(result) { + let token = result.credential.accessToken; + console.log(token); + let user = result.user; + console.log(user); + welcomeView(); + }).catch(function(error) { + let errorCode = error.code; + console.log(errorCode); + let errorMessage = error.message; + console.log(errorMessage); + let email = error.email; + console.log(email); + let credential = error.credential; + console.log(credential); + }); + } + let user = firebase.auth().currentUser; + if (user != null){ + console.log(user);} + } + +export default singIn; \ No newline at end of file diff --git a/src/profile.js b/src/profile.js new file mode 100644 index 00000000..1fabf5b8 --- /dev/null +++ b/src/profile.js @@ -0,0 +1,57 @@ +import {modal} from './welcome.js' +let content= document.querySelector(".root"); + + +function profile () { + content.innerHTML=''; + let user = firebase.auth().currentUser; + let dataBase= firebase.firestore(); + if (user != null) { + let infoUser= ` +
${user.displayName}
+
+ +
` + content.innerHTML=infoUser; + dataBase.collection("posts").where("id", "==", user.uid).orderBy("date","desc") + .onSnapshot(function(snapshot){ + let changes= snapshot.docChanges(); + console.log(changes); + changes.forEach(change =>{ + let section= document.createElement("section"); + section.classList.add("containerProfile"); + let button= document.createElement("button"); + button.classList.add("btnsPosts"); + let link= change.doc.data().img; + let img= document.createElement("img"); + img.src= link; + img.id = change.doc.id; + img.setAttribute('data-title',change.doc.data().title); + img.setAttribute('data-description', change.doc.data().description); + img.setAttribute('data-user', change.doc.data().user); + button.appendChild(img); + section.appendChild(button); + content.appendChild(section); + content.removeChild(section); + }); + let modalRoot= document.querySelector("#modalRoot"); + let btnsPosts= document.querySelectorAll(".btnsPosts"); + btnsPosts.forEach(btn=> btn.onclick = e => { + modalRoot.style.display= "block"; + let value= e.target.id; + // console.log(value); + let link = e.target.getAttribute('src'); + let title= e.target.getAttribute('data-title'); + let description= e.target.getAttribute('data-description'); + let user= e.target.getAttribute('data-user'); + modal(value, link, title, description, user); + }); + }) + // .catch(function(error) { + // console.log("Error getting documents: ", error); + // }); + + } +} + +export default profile; \ No newline at end of file diff --git a/src/register.js b/src/register.js new file mode 100644 index 00000000..683e906e --- /dev/null +++ b/src/register.js @@ -0,0 +1,66 @@ +const content = document.querySelector(".root"); +const footer= document.querySelector("footer"); + + +export function showRegisterWindow (){ + content.innerHTML=''; + const render= ` +
+
Registrate
+
+
+
+
+ +
+ +
+ `; + content.innerHTML= render; + const renderFooter= ` +
+ +
` + footer.innerHTML= renderFooter; + const data= document.querySelector(".form"); + getData(data); +} + +function getData (form){ + form.addEventListener('submit', (e) => { + e.preventDefault(); + const userName= form['signUpUser'].value; + const email= form['signUpEmail'].value; + const password= form['signUpPassword'].value; + console.log(userName, email, password); + createNewUser(email, password, userName); + }) +} + +function createNewUser(email, password, userName){ + const dataBase= firebase.firestore(); + firebase.auth().createUserWithEmailAndPassword(email, password).then ((function(result){ + console.log(result); + let user = firebase.auth().currentUser; + console.log(user); + dataBase.collection("users").add({ + user: userName, + id: user.uid, + email: email, + }) + .then(function(docRef) { + console.log("Document written with ID: ", docRef.id); + }) + .catch(function(error) { + console.error("Error adding document: ", error); + }); +})) + .catch(function(error) { + // Handle Errors here. + var errorCode = error.code; + var errorMessage = error.message; + console.log(errorCode); + console.log(errorMessage); + // ... + }); +} \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 00000000..8b7ca093 --- /dev/null +++ b/src/style.css @@ -0,0 +1,336 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body{ + font-family: 'Roboto', sans-serif; + background: #f6f6f6; + justify-content: center; + color: #686868; +} + +main { + display: flex; + justify-content: center; +} + +.root{ + width: 375px; + height: 664px; + /*Flexbox*/ + display: flex; + flex-direction: column; +} + +footer{ + position: relative; + display: flex; + justify-content: center; +} + +.menu { + background-color: #8dffb7; + width: 375px; + height: 60px; +} + +header{ + /*Flexbox*/ + display: flex; + justify-content: center; +} + +#header { + background-color: transparent; + width: 375px; + height: 90px; + flex-direction: row-reverse; +} + +#out { + background-color: transparent; + border: none; + width: 50px; + height: 50px; + /*Flexbox*/ +} + +.nav{ + display: flex; + justify-content: flex-start; +} + +.btnNav{ + background-color: transparent; + border: none; + margin-top: 10px; + margin-right: 2px; +} + +#welcome{ + margin-left: 15px; + margin-right: 160px; +} + +#profile { + width: 45px; + height: 45px; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; + background: white; + margin-right: 5px; + margin-left: 10px; + /*Flexbox*/ +} + +#previewImage { + width: 283px; + height: 283px; + border: #8dffb7 8px solid; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; + background: transparent; + /*Flex*/ +} + +#previewImage img { + width: 100%; + height: 100%; + border-radius: 100%; +} + +#divFile { + position: relative; + padding: 10px; + width: 60px; + height: 60px; +} + +#addImage { + position: absolute; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + width: 100%; + height: 100%; + opacity: 0; +} + +#labelImage { + position: relative; +} + +#tittle { + height: 25px; +} + +#description { + height: 50px; +} + +.containerPosts{ + display: flex; +} + +.containerPosts button{ + /* flex-grow: 2; */ + padding: 10px; +} + +.containerProfile{ + display: flex; +} + +.containerProfile button{ + /* flex-grow: 2; */ + padding: 10px; +} + +.btnsPosts { + width: 129px; + height: 129px; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; + background: transparent; + border: none; + margin-right: 60px; +} + +.btnsPosts img{ + width: 100%; + height: 100%; + border-radius: 100%; +} + +#contentImg{ + width: 308px; + height: 308px; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; + background: transparent; + /*Flex*/ + } + + #contentImg img{ + width: 100%; + height: 100%; + border-radius: 100%; + } + + #imgUserProfile{ + width: 80px; + height: 80px; + } + +/* Modal window */ + +.modal { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(255, 255, 255, 0.8); + } + + .modalContent { + position: relative; + /* background-color: #fefefe; */ + margin: 15% auto; + padding: 20px; + width: 375px; + } + + .close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + } + + .close:hover, + .close:focus { + color: black; + text-decoration: none; + cursor: pointer; + } + + /* DROPDOWN MENU */ +.btnOptions { + color:#686868; + padding: 16px; + font-size: 16px; + border: none; + cursor: pointer; + background-color: #8dffb7; + } + + .btnOptions:focus { + background-color: #aaa; + } + + .dropdown { + position: relative; + display: inline-block; + } + + .dropdownContent { + display: none; + position: absolute; + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; + } + + .dropdownContent button { + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; + background-color: transparent; + border: none; + } + + /* LOGIN SECTION */ + +.container{ + display: flex; + flex-direction: column; + align-items: center; + width: 365px; +} + +#logotype { + margin-top: 15px; + margin-bottom: 30px; + height: 157px; +} + +#containerBtns{ + flex-direction: row; +} + +.authSocial { + width: 50px; + height: 50px; +} + +.btnFbGmail { + background-color: transparent; + border: none; +} + +.container input{ + width: 300px; + height: 30px; + border: none; + border-bottom: 1px solid #888; + background-color: transparent; + margin-bottom: 30px; +} + +.buttons{ + width: 284px; + height: 46px; + border: none; + border-radius: 23px; + background-color: #8dffb7; + color: rgb(83, 83, 83); + margin-bottom: 25px; +} + +.container p { + margin-bottom: 30px; +} + +#btnRegister { + margin-top: 140px; + background-color: transparent; + border: none; + border-top: 1px solid #888; + padding: 15px; + width: 280px; + font-weight: bold; + color: #686868; + text-align: left; +} + +/* welcome window */ + +/* profile window */ + +#flexImage{ + display: flex; + justify-content: flex-end; + flex-direction: row-reverse; +} diff --git a/src/tests.js b/src/tests.js new file mode 100644 index 00000000..b691112f --- /dev/null +++ b/src/tests.js @@ -0,0 +1,14 @@ +export const addComent = (text) => +firebase.firestore().collection('comments').add ({ + commit: text +}) + +export const getComments = (callback) => + firebase.firestore().collection('comments') + .onSnapshot((querySnapshot) => { + const data = []; + querySnapshot.forEach((doc) => { + data.push({ id: doc.id, ...doc.data() }) + }); + callback(data); + }); \ No newline at end of file diff --git a/src/uopladContent.js b/src/uopladContent.js new file mode 100644 index 00000000..d2faa068 --- /dev/null +++ b/src/uopladContent.js @@ -0,0 +1,96 @@ +import profile from './profile.js'; + +import welcomeView from './welcome.js'; + +document.querySelector("#oupladContent").addEventListener('click', showOupladWindow); +const content = document.querySelector(".root"); +let header= document.querySelector(".header"); +let staticMenu= document.querySelector("#staticMenu"); + + + function showOupladWindow (){ + let url; + content.innerHTML= ''; + let oupladView= ` +
+
+ + +
+
+ Título +
+ +
+ Descripción +
+ +
+ +
+
` + content.innerHTML= oupladView; + // let out= document.querySelector('#out'); + // out.onclick= singIn; + let preview= document.querySelector("#previewImage"); + let inputFile= document.querySelector("#addImage"); + inputFile.onchange= (e) => { + let file= e.target.files[0]; + firebase.storage().ref("publications").child(file.name).put(file) + .then (snap =>{ + return snap.ref.getDownloadURL(); + }) + .then(link => { + url= link; + let img= document.createElement('img'); + img.src= link; + preview.appendChild(img); + // post.onclick= welcomeView; + }) + let publishBtn= document.querySelector("#toPost"); + publishBtn.onclick= (e) => { + let user = firebase.auth().currentUser; + console.log(user); + let post = { + user: user.displayName, + id: user.uid, + title: tittle.value, + description: description.value, + img: url, + date: new Date(), + } + newPublication(post) + .then(accept =>{ + console.log(accept); + //write window + profile(); + }) + .catch(error => { + console.log(error) + }) + } + } + let dataBase= firebase.firestore(); +let postsNew= dataBase.collection('posts'); +function newPublication(post ={user:"Edith", title: "hola", description:"Cómo están??", date: Date.now()}) { + return postsNew.add(post); + // .then +} +// postsNew.onSnapshot(snap =>{ +// let textarea= document.querySelector("#test"); +// textarea.innerHTML= ''; +// snap.forEach( doc =>{ +// let div = `
+//

${doc.data().user}

+//

${doc.data().id}

+//

${doc.data().description}

+// +//
` +// let nodo = document.createElement('div'); +// nodo.innerHTML = div; +// textarea.appendChild(nodo); +// }) +// }) +}; + +export default showOupladWindow; \ No newline at end of file diff --git a/src/welcome.js b/src/welcome.js new file mode 100644 index 00000000..f9a2ad23 --- /dev/null +++ b/src/welcome.js @@ -0,0 +1,175 @@ +import showOupladWindow from './uopladContent.js' +import profile from './profile.js' +import singIn from './login.js'; + +document.querySelector("#profile").addEventListener('click', welcomeView); +let content= document.querySelector(".root"); +let header= document.querySelector(".header"); +let staticMenu= document.querySelector("#staticMenu"); +let btnOut= document.querySelector("#out"); + + +function welcomeView (){ + btnOut.style.display="block"; + staticMenu.style.display= "block"; + content.innerHTML= ''; + let user = firebase.auth().currentUser; + if (user != null) { + let infoUser= ` +
+
¡Bienvenida ${user.displayName}!
+
` + content.innerHTML=infoUser;} + let dataBase= firebase.firestore(); + dataBase.collection("posts").orderBy("date","desc").onSnapshot(function(snapshot){ + let changes= snapshot.docChanges(); + console.log(changes); + changes.forEach(change=>{ + let section= document.createElement("section"); + section.classList.add("containerPosts"); + let button= document.createElement("button"); + button.classList.add("btnsPosts"); + let img= document.createElement("img"); + img.src= change.doc.data().img; + img.id = change.doc.id; + img.setAttribute('data-title',change.doc.data().title); + img.setAttribute('data-description', change.doc.data().description); + img.setAttribute('data-user', change.doc.data().user) + button.appendChild(img); + section.appendChild(button); + content.appendChild(section); + }) + let modalRoot= document.querySelector("#modalRoot"); + let btnsPosts= document.querySelectorAll(".btnsPosts"); + btnsPosts.forEach(btn=> btn.onclick = e => { + modalRoot.style.display= "block"; + let value= e.target.id; + let link = e.target.getAttribute('src'); + let title= e.target.getAttribute('data-title'); + let description= e.target.getAttribute('data-description'); + let user= e.target.getAttribute('data-user'); + modal(value, link, title, description, user); + }); + }) +} + +export function modal(id, link, title, description, user){ + let dataBase= firebase.firestore(); + console.log("si me esá detectando el click"); + id; + modalRoot.innerHTML=''; + let contentModal= ` +
+
+ × +
+ +
+

${user}

+
+

${title}

+
+
+ +
+
+

${description}

+
+
+
` + modalRoot.innerHTML=contentModal; + let btnSpan= document.getElementsByClassName("close")[0]; + btnSpan.onclick= () => modalRoot.style.display="none"; + document.querySelector("#btnOptions").onclick= showDropDownContent; + let dropdownMenu= document.querySelector("#myDropdown"); + function showDropDownContent(){ + dropdownMenu.style.display="block"; + } + window.onclick = function(event) { + if (event.target == dropdownMenu) { + dropdownMenu.style.display = "none"; + } + } + let btnDelete= document.querySelector("#btnDelete"); + console.log(btnDelete); + btnDelete.onclick= deletePosts; + function deletePosts(e){ + let id= e.target.getAttribute("data-id"); + let file= e.target.link; + console.log(file); + dataBase.collection("posts").doc(id).delete().then(function() { + console.log("Document successfully deleted!"); + let storage = firebase.storage(); + let storageRef = storage.ref(); + let desertRef = storageRef.child('publications/' + file.name); + desertRef.delete().then(function() { + console.log("listo!") + modalRoot.style.display="none"; + }).catch(function(error) { + console.log(error); + }); + }).catch(function(error) { + console.error("Error removing document: ", error); + }); + + } + let contentTitle= document.querySelector("#contentTitle"); + let contentDescription= document.querySelector("#contentDescription"); + let btnEdit= document.querySelector("#btnEdit"); + btnEdit.onclick=editPosts; + function editPosts(e){ + let titleOriginal= document.querySelector("#title"); + let descriptionOriginal= document.querySelector("#description"); + titleOriginal.style.display="none"; + descriptionOriginal.style.display="none"; + let newTitle= ` + ` + let newDescrition=` + + ` + contentTitle.innerHTML= newTitle; + contentDescription.innerHTML= newDescrition; + let id= e.target.getAttribute("data-id"); + let saveBtn= document.querySelector("#saveBtn"); + let nodeTitle= document.querySelector("#title"); + let nodeDescription= document.querySelector("#description"); + saveBtn.onclick= saveChangesInPost; + + function saveChangesInPost(){ + dataBase.collection("posts").doc(id).update({ + title: nodeTitle.value, + description: nodeDescription.value + }) + .then(function() { + console.log("Document successfully updated!"); + nodeTitle.style.display="none"; + nodeDescription.style.display="none"; + let resultTitle= ` +

${title}

` + let resultDescrip= ` +

${description}

` + contentTitle.innerHTML= resultTitle; + contentDescription.innerHTML= resultDescrip; + }) + .catch(function(error) { + // The document probably doesn't exist. + console.error("Error updating document: ", error); + }); + } + } + btnOut.onclick= singIn; +} + + + +export default welcomeView; \ No newline at end of file diff --git a/test/comments.spec.js b/test/comments.spec.js new file mode 100644 index 00000000..a278dd96 --- /dev/null +++ b/test/comments.spec.js @@ -0,0 +1,38 @@ +// import mockFirebase from '../_mocks_/firebase-mock.js' +// global.firebase = mockFirebase(); +import MockFirebase from 'mock-cloud-firestore'; + +const fixtureData = { + __collection__: { + comments: { + __doc__: { + abc123: { + commit: 'primera prueba de comentario', + }, + abc125: { + commit: 'segunda prueba de comentario', + } + } + } + } + }; + +global.firebase= new MockFirebase(fixtureData, { isNaiveSnapshotListenerEnabled: true }); + +import {addComent, getComments} from '../src/tests.js' + +describe('addComent', () =>{ + it('Must be able to upload coment', (done) => { + return addComent('Hola!').then((data) => { + const callback = (commits) => { + // console.log(commits); + const result = commits.find((element) => { + return element.commit === 'Hola!'; + }) + expect(result.commit).toBe('Hola!'); + done() + } + getComments(callback) + }) + }) +}) \ No newline at end of file diff --git a/test/example.spec.js b/test/example.spec.js index 1aca05e9..6714e274 100644 --- a/test/example.spec.js +++ b/test/example.spec.js @@ -1,7 +1,7 @@ -import { example } from '../src/example.js'; +// import { example } from '../src/example.js'; -describe('example', () => { - it('debería ser una función', () => { - expect(typeof example).toBe('function'); - }); -}); \ No newline at end of file +// describe('example', () => { +// it('debería ser una función', () => { +// expect(typeof example).toBe('function'); +// }); +// }); \ No newline at end of file