diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f673a71 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5502 +} \ No newline at end of file diff --git a/README.md b/README.md index fe12fa3..58f8e53 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Creando una Red Social +# Red Social para Mujeres Latinas en el Exterior ## Índice diff --git a/package.json b/package.json index 1d89e14..4cc83da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "social-network", "private": true, + "type": "module", "version": "1.0.0", "description": "Social Network @ Laboratoria", "main": "src/index.html", @@ -17,21 +18,21 @@ "pretest": "npm run htmlhint && npm run eslint && npm run stylelint", "test": "jest --coverage", "dev": "vite dev src", - "start": "npm run dev", + "start": "serve src/ -s", "build": "vite build", "preview": "vite preview" }, "devDependencies": { "@babel/preset-env": "^7.19.4", "eslint": "^8.3.0", - "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-base": "^14.2.1", "eslint-plugin-import": "^2.18.2", "eslint-plugin-jest": "^25.3.0", "htmlhint": "^1.0.0", - "jest": "^27.0.1", + "jest": "^23.6.0", "regenerator-runtime": "^0.13.1", - "stylelint": "^14.1.0", - "stylelint-config-recommended": "^6.0.0", + "stylelint": "^15.9.0", + "stylelint-config-recommended": "^12.0.0", "vite": "^3.1.0" }, "engines": { @@ -41,5 +42,17 @@ "createdAt": "2023-06-06T21:37:46.504Z", "version": "6.3.0", "commit": "a942adeb868f1fe54b86e34cc4fc4ddb0601700d" + }, + "directories": { + "test": "test" + }, + "repository": { + "type": "git", + "url": "1" + }, + "author": "Roxi-Erika-Tatiana", + "dependencies": { + "@firebase/util": "^1.9.3", + "firebase": "^9.23.0" } -} \ No newline at end of file +} diff --git a/src/components/Feed.js b/src/components/Feed.js new file mode 100644 index 0000000..a7cd635 --- /dev/null +++ b/src/components/Feed.js @@ -0,0 +1,532 @@ +import { onSnapshot } from 'firebase/firestore'; +import { + savePost, + showPosts, + deletePost, + getDataAuthor, + updateLikePost, + getUserByUserID, + updatePost, + getPost, +} from '../firebase/firebase.js'; +import { auth } from '../firebase/config.js'; + +export const Feed = () => { + // ---------------------------HEAD---------------------- + + const headFeed = document.createElement('head'); + const titleHeadFeed = document.createElement('title'); + titleHeadFeed.innerText = 'WarmiFeed'; + headFeed.appendChild(titleHeadFeed); + + const divFeedPrincipal = document.createElement('div'); + divFeedPrincipal.className = 'feed-container colorwhite'; + + // ---------------------------HEADER--------------------- + + const headerFeed = document.createElement('header'); + headerFeed.className = 'colorbackpink'; + divFeedPrincipal.appendChild(headerFeed); + + const headerContainer = document.createElement('div'); + headerContainer.className = 'header-container'; + headerFeed.appendChild(headerContainer); + + const brand = document.createElement('img'); + brand.className = 'logo'; + brand.src = '../img/icon-logo.png'; + brand.alt = 'logo'; + + const brandHorizontal = document.createElement('img'); + brandHorizontal.className = 'logo-horizontal'; + brandHorizontal.src = '../img/logo-feed.png'; + brandHorizontal.alt = 'logo'; + + const iconHideMenu = document.createElement('button'); + iconHideMenu.className = 'icon-hide-menu'; + + const iconMenuCelphone = document.createElement('img'); + iconMenuCelphone.src = '../img/icon-menu-celphone.svg'; + + const inputSearchBar = document.createElement('input'); + inputSearchBar.setAttribute('type', 'search'); + inputSearchBar.className = 'input-search-bar'; + inputSearchBar.placeholder = 'Buscar'; + + const userNameHed = document.createElement('p'); + userNameHed.className = 'user-name-header'; + const pictureProfile = document.createElement('img'); + pictureProfile.className = 'user-image colorlightblue'; + + const userLocalStorage = JSON.parse(localStorage.getItem('userCredentials')); + getUserByUserID(userLocalStorage.userID).then((user) => { + userNameHed.innerText = user.username; + pictureProfile.src = user.picture; + console.log(user.picture); + }); + // Fin del header + + headerContainer.appendChild(brand); + headerContainer.appendChild(brandHorizontal); + headerContainer.appendChild(iconHideMenu); + iconHideMenu.appendChild(iconMenuCelphone); + headerContainer.appendChild(inputSearchBar); + headerContainer.appendChild(userNameHed); + headerContainer.appendChild(pictureProfile); + + // -------------------MAIN(whole content)--------------- + + const centeredMainDiv = document.createElement('div'); + centeredMainDiv.className = 'centered-main'; + divFeedPrincipal.appendChild(centeredMainDiv); + + const flexItemLeftDiv = document.createElement('div'); + flexItemLeftDiv.className = 'flex-item-left'; + + const flexItemRightDiv = document.createElement('div'); + flexItemRightDiv.className = 'flex-item-right'; + + // ---------------------ASIDE(left)-------------------- + const asideElement = document.createElement('aside'); + + const trendingContainerDiv = document.createElement('div'); + trendingContainerDiv.className = 'trending-container'; + + const trendyTitleDiv = document.createElement('div'); + const trendyTitleH2 = document.createElement('h2'); + trendyTitleH2.className = 'trendy-title colorbackpink'; + trendyTitleH2.textContent = 'Tendencias'; + trendyTitleDiv.appendChild(trendyTitleH2); + trendingContainerDiv.appendChild(trendyTitleDiv); + + const hashTagsDiv = document.createElement('div'); + const hashTagsH3 = document.createElement('h3'); + hashTagsH3.textContent = 'Hashtags'; + const hashTagTemplateP = document.createElement('p'); + hashTagTemplateP.className = 'hashtag-template'; + const seeAllHashTagsA = document.createElement('a'); + seeAllHashTagsA.textContent = 'ver todos'; + hashTagsDiv.appendChild(hashTagsH3); + hashTagsDiv.appendChild(hashTagTemplateP); + hashTagsDiv.appendChild(seeAllHashTagsA); + trendingContainerDiv.appendChild(hashTagsDiv); + hashTagTemplateP.textContent = '#mercadillolatino'; + + const groupsDiv = document.createElement('div'); + const groupsH3 = document.createElement('h3'); + groupsH3.textContent = 'Grupos'; + const groupContainerDiv = document.createElement('div'); + groupContainerDiv.className = 'group-container'; + const groupImg = document.createElement('img'); + groupImg.className = 'group-img colorlightblue'; + const groupTitleP = document.createElement('p'); + groupTitleP.className = 'group-title'; + groupTitleP.textContent = 'inglés básico para principiantes'; + groupContainerDiv.appendChild(groupImg); + groupContainerDiv.appendChild(groupTitleP); + const seeAllGroupsA = document.createElement('a'); + seeAllGroupsA.textContent = 'ver todos'; + groupsDiv.appendChild(groupsH3); + groupsDiv.appendChild(groupContainerDiv); + groupsDiv.appendChild(seeAllGroupsA); + trendingContainerDiv.appendChild(groupsDiv); + + const conversationsDiv = document.createElement('div'); + + const conversationsH3 = document.createElement('h3'); + conversationsH3.textContent = 'Conversaciones'; + + const conversationContainerDiv = document.createElement('div'); + conversationContainerDiv.className = 'conversation-container'; + + const conversationContentDiv = document.createElement('div'); + conversationContentDiv.className = 'conversation-content'; + + const conversationImg = document.createElement('img'); + conversationImg.className = 'conversation-img colorlightblue'; + conversationImg.src = '../img/istockphoto-1323400501-612x612.jpg'; + + const textContainerDiv = document.createElement('div'); + textContainerDiv.className = 'text-container'; + + const conversationNameP = document.createElement('p'); + conversationNameP.className = 'conversation-name'; + conversationNameP.textContent = 'Jennifer Heredia'; + + const conversationPostP = document.createElement('p'); + conversationPostP.className = 'conversation-post'; + conversationPostP.textContent = 'Algun consejo para las que queremos irnos de viaje a Grecia?'; + + const conversationActions = document.createElement('div'); + conversationActions.className = 'conversation-actions'; + + const conversationImg1 = document.createElement('img'); + conversationImg1.className = 'messages-icon'; + conversationImg1.src = '/img/chat-square-dots-fill.svg'; + conversationImg1.alt = 'message-icon-for-comment'; + + const conversationImg2 = document.createElement('img'); + conversationImg2.className = 'heart-icon'; + conversationImg2.src = '/img/heart-fill-white.svg'; + conversationImg2.alt = 'heart-icon-for-likes'; + + const seeAllConversationsA = document.createElement('a'); + seeAllConversationsA.textContent = 'ver todos'; + + conversationsDiv.appendChild(conversationsH3); + conversationsDiv.appendChild(conversationContainerDiv); + conversationsDiv.appendChild(seeAllConversationsA); + + conversationContainerDiv.appendChild(conversationContentDiv); + conversationContentDiv.appendChild(conversationImg); + conversationContentDiv.appendChild(textContainerDiv); + textContainerDiv.appendChild(conversationNameP); + textContainerDiv.appendChild(conversationPostP); + + conversationContainerDiv.appendChild(conversationActions); + conversationActions.appendChild(conversationImg1); + conversationActions.appendChild(conversationImg2); + + trendingContainerDiv.appendChild(conversationsDiv); + + const newsDiv = document.createElement('div'); + const news = document.createElement('h3'); + news.textContent = 'Noticias'; + + const newsContainer = document.createElement('div'); + newsContainer.className = 'news-container'; + + const newsContent = document.createElement('div'); + newsContent.className = 'news-content'; + + const newsText = document.createElement('p'); + newsText.className = 'news-text text-plus'; + newsText.innerText = 'LABORATORIA expande sus puertas a Asuncion, Ciudad de Panama, La Paz, Montevideo y San Jose!'; + + const newsImg = document.createElement('img'); + newsImg.className = 'news-img'; + newsImg.src = '../img/ED6FEYGGQNFGDM36CZVBK3WALE.webp'; + newsImg.alt = 'message-icon-for-comment'; + + const conversationsActions = document.createElement('div'); + conversationsActions.className = 'conversation-actions'; + + const messagesIcon = document.createElement('img'); + messagesIcon.className = 'messages-icon'; + messagesIcon.src = '/img/chat-square-dots-fill.svg'; + messagesIcon.alt = 'heart-icon-for-likes'; + + const heartIcon = document.createElement('img'); + heartIcon.className = 'heart-icon'; + heartIcon.src = '/img/heart-fill-white.svg'; + heartIcon.alt = 'heart-icon-for-likes'; + newsContent.appendChild(newsText); + newsContent.appendChild(newsImg); + + const seeAllNews = document.createElement('a'); + seeAllNews.innerText = 'ver todos'; + + conversationsActions.appendChild(messagesIcon); + conversationsActions.appendChild(heartIcon); + + newsContainer.appendChild(newsContent); + newsContainer.appendChild(conversationsActions); + + newsDiv.appendChild(news); + newsDiv.appendChild(newsContainer); + newsDiv.appendChild(seeAllNews); + + trendingContainerDiv.appendChild(newsDiv); + + asideElement.appendChild(trendingContainerDiv); + + flexItemLeftDiv.appendChild(asideElement); + + // ------------------USER SECTION (right)--------------------- + const mainElement = document.createElement('main'); + + const userPostContainerDiv = document.createElement('form'); + userPostContainerDiv.className = 'user-post-container'; + + const textareaElement = document.createElement('textarea'); + textareaElement.className = 'user-post colorwhite'; + textareaElement.id = 'db-post-content'; + textareaElement.placeholder = 'Crea un post'; + textareaElement.required = true; + + const userPostBtnsContainerDiv = document.createElement('div'); + userPostBtnsContainerDiv.className = 'user-post-btns-conatiner'; + + const btnInsertPhoto = document.createElement('button'); + btnInsertPhoto.className = 'btn-insert-photo colorlightblue'; + btnInsertPhoto.type = 'button'; + const photoIconImg = document.createElement('img'); + photoIconImg.className = 'photo-icon'; + photoIconImg.src = '../img/camara-icon.svg'; + photoIconImg.alt = 'camera-icon'; + btnInsertPhoto.appendChild(photoIconImg); + + const btnPost = document.createElement('button'); + btnPost.className = 'btn-post colorbackpink'; + btnPost.textContent = 'publicar'; + btnPost.type = 'submit'; + + const feedContainer = document.createElement('div'); + feedContainer.className = 'timeline-container'; + + // --------------------------INICIO---Footer + const footerFeed = document.createElement('footer'); + footerFeed.className = 'colorgray'; + divFeedPrincipal.appendChild(footerFeed); + + const footerFirstRow = document.createElement('div'); + footerFirstRow.className = 'footer-first-row'; + footerFeed.appendChild(footerFirstRow); + + const footerSecondRow = document.createElement('div'); + footerSecondRow.className = 'footer-second-row'; + footerFeed.appendChild(footerSecondRow); + + const information = document.createElement('p'); + information.textContent = 'Información'; + + const help = document.createElement('p'); + help.textContent = 'Ayuda'; + + const privacy = document.createElement('p'); + privacy.textContent = 'Privacidad'; + + const conditions = document.createElement('p'); + conditions.textContent = 'Condiciones'; + + const complaint = document.createElement('p'); + complaint.textContent = 'Denuncias'; + + footerFirstRow.appendChild(information); + footerFirstRow.appendChild(help); + footerFirstRow.appendChild(privacy); + footerFirstRow.appendChild(conditions); + footerFirstRow.appendChild(complaint); + + const spanish = document.createElement('p'); + + spanish.textContent = 'Español (España)'; + const laboratoria = document.createElement('p'); + laboratoria.textContent = '© 2023 LABORATORIA'; + + footerSecondRow.appendChild(spanish); + footerSecondRow.appendChild(laboratoria); + + userPostContainerDiv.appendChild(textareaElement); + + userPostBtnsContainerDiv.appendChild(btnInsertPhoto); + userPostBtnsContainerDiv.appendChild(btnPost); + userPostContainerDiv.appendChild(userPostBtnsContainerDiv); + + mainElement.appendChild(userPostContainerDiv); + mainElement.appendChild(feedContainer); + + flexItemRightDiv.appendChild(mainElement); + centeredMainDiv.appendChild(flexItemLeftDiv); + centeredMainDiv.appendChild(flexItemRightDiv); + + // -------------------------------------------------------------- + // INICIO DE FUNCIONES A BOTONES E INTERACCIONES EN FEED + // -------------------------------------------------------------- + + /* +|-----------------------------------------| +| Create a post (visual) | +|-----------------------------------------| + */ + async function addPostToFeed(container, postRef, post) { + const author = await getDataAuthor(post.author); + + const userPublishedPost = document.createElement('div'); + userPublishedPost.className = 'user-published-post'; + + const userPublishedPostDiv = document.createElement('div'); + userPublishedPostDiv.className = 'user-published-post-div'; + userPublishedPost.appendChild(userPublishedPostDiv); + + const userPublishedPostContent = document.createElement('div'); + userPublishedPostContent.className = 'user-published-post-content'; + userPublishedPostDiv.appendChild(userPublishedPostContent); + + const conversationImg3 = document.createElement('img'); + conversationImg3.className = 'conversation-img colorlightblue'; + conversationImg3.src = author.picture; + userPublishedPostContent.appendChild(conversationImg3); + + const userPublishedPostTextContent = document.createElement('div'); + userPublishedPostTextContent.className = 'user-published-post-text-content'; + userPublishedPostContent.appendChild(userPublishedPostTextContent); + + const textContentUpperRow = document.createElement('div'); + textContentUpperRow.className = 'text-content-upper-row'; + userPublishedPostTextContent.appendChild(textContentUpperRow); + + const userPublishedPostTitle = document.createElement('p'); + userPublishedPostTitle.className = 'user-published-post-title'; + userPublishedPostTitle.textContent = author.username; + textContentUpperRow.appendChild(userPublishedPostTitle); + + const userPublishedPostEdit = document.createElement('p'); + userPublishedPostEdit.className = 'user-published-post-edit'; + userPublishedPostEdit.textContent = '...'; + textContentUpperRow.appendChild(userPublishedPostEdit); + // + const PostEditButtons = document.createElement('ul'); + PostEditButtons.className = 'edit-post-option-container colorwhite'; + + const editButton = document.createElement('li'); + editButton.className = 'edit-post-option'; + editButton.textContent = 'editar'; + + const eraseButton = document.createElement('li'); + eraseButton.className = 'edit-post-option two'; + eraseButton.textContent = 'eliminar'; + + const reportButton = document.createElement('li'); + reportButton.className = 'edit-post-option three'; + reportButton.textContent = 'Reportar'; + /* +|--------------------------------------------------------| +| Delete and edit buttons only por user author | +|--------------------------------------------------------| + */ + if (auth.currentUser.email === author.email) { + userPublishedPostEdit.appendChild(PostEditButtons); + PostEditButtons.appendChild(editButton); + PostEditButtons.appendChild(eraseButton); + } else { + userPublishedPostEdit.appendChild(PostEditButtons); + PostEditButtons.appendChild(reportButton); + reportButton.addEventListener('click', async () => { + // eslint-disable-next-line no-alert + (window.confirm('Reporte enviado, Gracias por ayudarnos a ser una mejor comunidad')); + }); + } + /* +|-----------------------------------------| +| Delete posts button | +|-----------------------------------------| + */ + eraseButton.addEventListener('click', async () => { + function alerta() { + // eslint-disable-next-line no-alert + if (window.confirm('Confirme el borrado del Post')) { + deletePost(postRef.id); + userPublishedPost.parentElement.removeChild(userPublishedPost); + // .then(() => { + console.log('Post eliminado'); + // }).catch((error) => { + // const errorCode = error.code; + // const errorMessage = error.Message; + // console.log(errorCode, errorMessage); + // }); + } + } + alerta(); + }); + + /* +|-----------------------------------------| +| Edit posts button | +|-----------------------------------------| +*/ + let oldPost; + editButton.addEventListener('click', async () => { + oldPost = await getPost(postRef.id); + textareaElement.value = oldPost.text; + btnPost.innerText = 'actualizar'; + userPostContainerDiv.addEventListener('submit', async (e) => { + e.preventDefault(); + if (btnPost.textContent === 'actualizar') { + const newtext = textareaElement.value; + await updatePost(postRef.id, newtext); + const postDocument = await getDataAuthor(postRef); + await addPostToFeed(feedContainer, postRef, postDocument); + + userPostContainerDiv.reset(); + btnPost.innerText = 'publicar'; + userPublishedPost.parentElement.removeChild(userPublishedPost); + } + }); + }); + + const userPublishedPostText = document.createElement('p'); + userPublishedPostText.className = 'user-published-post-text'; + userPublishedPostText.textContent = post.text; + userPublishedPostTextContent.appendChild(userPublishedPostText); + + const userPublishedPostActions = document.createElement('div'); + userPublishedPostActions.className = 'user-published-post-actions'; + userPublishedPostDiv.appendChild(userPublishedPostActions); + + const messagesIcon3 = document.createElement('img'); + messagesIcon3.className = 'messages-icon'; + messagesIcon3.src = '/img/chat-square-dots-fill.svg'; + messagesIcon3.alt = 'message-icon-for-comment'; + userPublishedPostActions.appendChild(messagesIcon3); + + const heartIcon3 = document.createElement('img'); + heartIcon3.className = 'heart-icon'; + heartIcon3.src = '/img/heart-fill-white.svg'; + heartIcon3.alt = 'heart-icon-for-likes'; + userPublishedPostActions.appendChild(heartIcon3); + + const likesCounter = document.createElement('span'); + likesCounter.className = 'likes-counter'; + likesCounter.innerText = ` ${post.liked_by.length} `; + userPublishedPostActions.appendChild(likesCounter); + + heartIcon3.addEventListener('click', async () => { + const freshPost = await getDataAuthor(postRef); + const heartIcon4 = await updateLikePost(postRef, freshPost); + heartIcon3.src = heartIcon4; + }); + + // Necesario para recibir actualizaciones automáticamente desde firebase, cuando el post cambie + onSnapshot(postRef, (freshPostDocument) => { + const freshPost = freshPostDocument.data(); + likesCounter.innerText = ` ${freshPost.liked_by.length} `; + if (freshPost.liked_by.length === 0) { + likesCounter.innerText = ''; + } + }); + + container.prepend(userPublishedPost); + } + + /* +|-----------------------------------------| +| Show posts from firestore into feed | +|-----------------------------------------| + */ + window.addEventListener('DOMContentLoaded', async () => { + const TimelinePosts = await showPosts(); + + TimelinePosts.forEach((postDocument) => { + const post = postDocument.data(); + addPostToFeed(feedContainer, postDocument.ref, post); + }); + }); + + /* +|-----------------------------------------| +| Save new post from user to firestore | +|-----------------------------------------| + */ + userPostContainerDiv.addEventListener('submit', async (e) => { + e.preventDefault(); + if (btnPost.textContent === 'publicar') { + const postRef = await savePost(textareaElement.value); + const postDocument = await getDataAuthor(postRef); + await addPostToFeed(feedContainer, postRef, postDocument); + + userPostContainerDiv.reset(); + } + }); + return divFeedPrincipal; +}; diff --git a/src/components/Login.js b/src/components/Login.js new file mode 100644 index 0000000..fc5b343 --- /dev/null +++ b/src/components/Login.js @@ -0,0 +1,181 @@ +import { signIn, signInGoogle } from '../firebase/firebase.js'; + +export const Login = () => { + // creando el elemento div que contiene todo el Login + const loginDiv = document.createElement('div'); + loginDiv.className = 'container'; + + // lado izquierdo (ilustracion en este caso) + const loginUpLeftDiv = document.createElement('section'); + loginUpLeftDiv.className = 'transition-div'; + + const loginLeftDivHeader = document.createElement('div'); + loginLeftDivHeader.className = 'transition-header'; + + const logo = document.createElement('img'); + logo.src = 'img/Logo.png'; + logo.className = 'Logo'; + logo.alt = 'vertical-logo'; + + const brandDescription = document.createElement('p'); + brandDescription.innerText = 'Warmi es la primera red social para mujeres latinas que viven fuera de sus paises de origen'; + brandDescription.className = 'warmi-summary'; + + const subTitle = document.createElement('h2'); + subTitle.innerText = '¿Nueva en Warmi?'; + subTitle.className = 'smaller-subtitle'; + + const transparentBtn = document.createElement('button'); + transparentBtn.innerHTML = 'registrate'; + transparentBtn.className = 'btn transparent'; + + const illustrationContainer = document.createElement('div'); + illustrationContainer.className = 'illustration-container'; + + const illustration = document.createElement('img'); + illustration.src = 'img/illustration-homepage.png'; + illustration.className = 'illustration'; + illustration.alt = 'girls-illustration'; + + // lado derecho (formulario en este caso) + const loginUpRightDiv = document.createElement('section'); + loginUpRightDiv.className = 'forms-container'; + + const formContainer = document.createElement('div'); + formContainer.className = 'signin'; + + const formSignIn = document.createElement('form'); + formSignIn.className = 'sign-in-form'; + formSignIn.action = '#'; + + const title = document.createElement('h2'); + title.innerText = 'Bienvenida!'; + title.className = 'title'; + + const formSubTitle = document.createElement('h3'); + formSubTitle.innerText = 'Inicia sesión con tu usuario registrado'; + formSubTitle.className = 'subtitle'; + + const inputFieldEmail = document.createElement('div'); + inputFieldEmail.className = 'input-field'; + + const iconEmail = document.createElement('i'); + iconEmail.className = 'fas fa-envelope'; + + const email = document.createElement('input'); + email.type = 'email'; + email.className = 'mail-register'; + email.placeholder = 'Ingresa tu email'; + email.name = 'Mail'; + email.required = true; + + inputFieldEmail.appendChild(iconEmail); + inputFieldEmail.appendChild(email); + + const inputFieldPss1 = document.createElement('div'); + inputFieldPss1.className = 'input-field'; + + const iconPassword1 = document.createElement('i'); + iconPassword1.className = 'fas fa-lock'; + + const password1 = document.createElement('input'); + password1.type = 'password'; + password1.className = 'password-register'; + password1.placeholder = 'Ingresa tu contraseña'; + password1.name = 'Password'; + password1.required = true; + + inputFieldPss1.appendChild(iconPassword1); + inputFieldPss1.appendChild(password1); + + const btnContainer = document.createElement('section'); + const submitBtn = document.createElement('input'); + submitBtn.type = 'submit'; + submitBtn.className = 'btn'; + submitBtn.value = 'Iniciar sesión'; + + const recoverPasswordLink = document.createElement('a'); + recoverPasswordLink.className = 'link'; + recoverPasswordLink.innerHTML = '¿Olvidaste tu contraseña?'; + + btnContainer.appendChild(submitBtn); + btnContainer.appendChild(recoverPasswordLink); + + const socialText = document.createElement('p'); + socialText.className = 'social-text'; + socialText.textContent = 'ingresa con:'; + + const socialMediaDiv = document.createElement('div'); + socialMediaDiv.className = 'social-media'; + + const googleLink = document.createElement('a'); + googleLink.href = '#'; + googleLink.className = 'social-icon'; + const googleIcon = document.createElement('img'); + googleIcon.src = 'img/google.png'; + + googleIcon.className = 'googleIcon'; + googleLink.appendChild(googleIcon); + + // const appleLink = document.createElement('a'); + // appleLink.href = '#'; + // appleLink.className = 'social-icon'; + // const appleIcon = document.createElement('i'); + // appleIcon.className = 'fab fa-apple'; + // appleLink.appendChild(appleIcon); + + // const microsoftLink = document.createElement('a'); + // microsoftLink.href = '#'; + // microsoftLink.className = 'social-icon'; + // const microsoftIcon = document.createElement('i'); + // microsoftIcon.className = 'fab fa-microsoft'; + // microsoftLink.appendChild(microsoftIcon); + + socialMediaDiv.appendChild(googleLink); + // socialMediaDiv.appendChild(appleLink); + // socialMediaDiv.appendChild(microsoftLink); + + // lado izquierdo + loginDiv.appendChild(loginUpLeftDiv); + loginUpLeftDiv.appendChild(loginLeftDivHeader); + loginLeftDivHeader.appendChild(logo); + loginLeftDivHeader.appendChild(brandDescription); + loginLeftDivHeader.appendChild(subTitle); + loginLeftDivHeader.appendChild(transparentBtn); + loginUpLeftDiv.appendChild(illustrationContainer); + illustrationContainer.appendChild(illustration); + // lado derecho + loginDiv.appendChild(loginUpRightDiv); + loginUpRightDiv.appendChild(formContainer); + formContainer.appendChild(formSignIn); + formSignIn.appendChild(title); + formSignIn.appendChild(formSubTitle); + formSignIn.appendChild(inputFieldEmail); + formSignIn.appendChild(inputFieldPss1); + formSignIn.appendChild(btnContainer); + formSignIn.appendChild(socialText); + formSignIn.appendChild(socialMediaDiv); + + // re direccionando a recuperacion de contraseña + recoverPasswordLink.addEventListener('click', () => { + window.location.assign('/recoverPassword'); + }); + + transparentBtn.addEventListener('click', () => { + window.location.assign('/register'); + }); + + // evento que va a guardar el registro del usuario + submitBtn.addEventListener('click', (e) => { + e.preventDefault(); + const user = { + email: formSignIn.elements.Mail.value, + password: formSignIn.elements.Password.value, + }; + signIn(user); + }); + + googleLink.addEventListener('click', signInGoogle); + + return loginDiv; +}; diff --git a/src/components/RecoverPassword.js b/src/components/RecoverPassword.js new file mode 100644 index 0000000..5c05580 --- /dev/null +++ b/src/components/RecoverPassword.js @@ -0,0 +1,110 @@ +// import { resetPassword } from '../firebase/firebase.js'; +export const RecoverPassword = () => { + // creando el elemento div que contiene todo el registro + const recoverPasswordDiv = document.createElement('div'); + recoverPasswordDiv.className = 'container'; + + // lado izquierdo (ilustracion en este caso) + const rPUpLeftDiv = document.createElement('section'); + rPUpLeftDiv.className = 'transition-div'; + + const rPLeftDivHeader = document.createElement('div'); + rPLeftDivHeader.className = 'transition-header'; + + const logo = document.createElement('img'); + logo.src = 'img/Logo.png'; + logo.className = 'Logo'; + logo.alt = 'vertical-logo'; + + const brandDescription = document.createElement('p'); + brandDescription.innerText = 'Warmi es la primera red social para mujeres latinas que viven fuera de sus paises de origen'; + brandDescription.className = 'warmi-summary'; + + const subTitle = document.createElement('p'); + subTitle.innerText = '¿Nueva en Warmi?'; + subTitle.className = 'smaller-subtitle'; + + const transparentBtn = document.createElement('button'); + transparentBtn.innerHTML = 'registrate'; + transparentBtn.className = 'btn transparent'; + + const illustrationContainer = document.createElement('div'); + illustrationContainer.className = 'illustration-container'; + + const illustration = document.createElement('img'); + illustration.src = 'img/illustration-homepage.png'; + illustration.className = 'illustration'; + illustration.alt = 'girls-illustration'; + + recoverPasswordDiv.appendChild(rPUpLeftDiv); + rPUpLeftDiv.appendChild(rPLeftDivHeader); + rPLeftDivHeader.appendChild(logo); + rPLeftDivHeader.appendChild(brandDescription); + rPLeftDivHeader.appendChild(subTitle); + rPLeftDivHeader.appendChild(transparentBtn); + rPUpLeftDiv.appendChild(illustrationContainer); + illustrationContainer.appendChild(illustration); + + // lado derecho + const rPRightDiv = document.createElement('section'); + rPRightDiv.className = 'forms-container'; + + const formContainer = document.createElement('div'); + formContainer.className = 'signin-signup'; + + const formSignIn = document.createElement('form'); + formSignIn.className = 'sign-in-form'; + formSignIn.action = '#'; + + const title = document.createElement('h2'); + title.innerText = '¿Olvidaste tu contraseña?'; + title.className = 'title'; + + const formSubTitle = document.createElement('h3'); + formSubTitle.innerText = '¡Nosotras te ayudamos!'; + formSubTitle.className = 'subtitle'; + + const inputFieldEmail = document.createElement('div'); + inputFieldEmail.className = 'input-field'; + + const iconEmail = document.createElement('i'); + iconEmail.className = 'fas fa-envelope'; + + const email = document.createElement('input'); + email.type = 'email'; + email.className = 'mail-register'; + email.placeholder = 'Ingresa tu email'; + email.name = 'Mail'; + email.required = true; + + inputFieldEmail.appendChild(iconEmail); + inputFieldEmail.appendChild(email); + + const sendRecoveryPasswordButton = document.createElement('input'); + sendRecoveryPasswordButton.type = 'submit'; + sendRecoveryPasswordButton.value = 'Enviar enlace de recuperación'; + sendRecoveryPasswordButton.className = 'btn-save'; + + const labelForSendMessage = document.createElement('label'); + labelForSendMessage.textContent = 'Te enviaremos un enlace de recuperacion a tu correo electrónico'; + labelForSendMessage.className = 'support-text'; + + // lado derecho + recoverPasswordDiv.appendChild(rPRightDiv); + rPRightDiv.appendChild(formContainer); + formContainer.appendChild(formSignIn); + formSignIn.appendChild(title); + formSignIn.appendChild(formSubTitle); + formSignIn.appendChild(inputFieldEmail); + formSignIn.appendChild(sendRecoveryPasswordButton); + formSignIn.appendChild(labelForSendMessage); + + return recoverPasswordDiv; +}; + +// evento que envia el correo para cambio de contraseña +// sendRecoveryPasswordButton.addEventListener('click', (e) =>{ +// e.preventDefault(); +// const userEmail = formSignUp.elements.Mail.value; +// resetPassword(userEmail); +// }); diff --git a/src/components/Register.js b/src/components/Register.js new file mode 100644 index 0000000..e4a071e --- /dev/null +++ b/src/components/Register.js @@ -0,0 +1,261 @@ +import { signUp } from '../firebase/firebase.js'; + +export const Register = () => { + // creando el elemento div que contiene todo el registro + const signUpDiv = document.createElement('div'); + signUpDiv.className = 'signup'; + + // lado derecho (ilustracion en este caso) + const loginUpRightDiv = document.createElement('section'); + loginUpRightDiv.className = 'transition-div2'; + + const loginLeftDivHeader = document.createElement('div'); + loginLeftDivHeader.className = 'transition-header2'; + + const logo = document.createElement('img'); + logo.src = 'img/Logo.png'; + logo.className = 'Logo'; + logo.alt = 'vertical-logo'; + + const subTitle = document.createElement('h2'); + subTitle.innerText = '¿Estas registrado?'; + subTitle.className = 'smaller-subtitle'; + + const brandDescription = document.createElement('p'); + brandDescription.innerText = 'Warmi es la primera red social para mujeres latinas que viven fuera de sus paises de origen'; + brandDescription.className = 'warmi-summary'; + + const transparentBtn = document.createElement('button'); + transparentBtn.innerHTML = 'iniciar sesión '; + transparentBtn.className = 'btn transparent'; + + // lado izquierdo (formulario de registro en este caso) + const formSignUp = document.createElement('form'); + formSignUp.className = 'sign-up-form'; + formSignUp.action = '#'; + + const title = document.createElement('h3'); + title.className = 'title'; + title.textContent = 'Crea tu cuenta'; + + const subtitle = document.createElement('h4'); + subtitle.className = 'subtitle'; + subtitle.textContent = 'Con esta cuenta podrás conectar con otras mujeres latinas que se encuentran alrededor del mundo'; + + const closer = document.createElement('div'); + closer.className = 'closer'; + + // --------------------name--------------------- + // creando input de nombre usuario dentro de un div con un icon + const inputFieldName = document.createElement('div'); + inputFieldName.className = 'input-field-short'; + // Crear el segundo elemento i con clase "fas fa-user" + const iconName = document.createElement('i'); + iconName.className = 'fas fa-user'; + + // Crear el segundo input con tipo "text", clase "username-register" + // placeholder "Ingresa tu usuario", y nombre "Username" + const userName1 = document.createElement('input'); + userName1.type = 'text'; + userName1.className = 'name-register'; + userName1.placeholder = 'Nombre'; + userName1.id = 'Name'; + userName1.name = 'Name'; + userName1.required = true; + + // Agregar el icono al segundo div de campo de entrada + inputFieldName.appendChild(iconName); + inputFieldName.appendChild(userName1); + + // --------------------lastname--------------------- + // creando input de nombre usuario dentro de un div con un icon + const inputFieldLastName = document.createElement('div'); + inputFieldLastName.className = 'input-field-short'; + + // Crear el segundo elemento i con clase "fas fa-user" + const iconLastName = document.createElement('i'); + iconLastName.className = 'fas fa-user'; + + // Crear el segundo input con tipo "text", clase "username-register" + // placeholder "Ingresa tu usuario", y nombre "Username" + const userLastName = document.createElement('input'); + userLastName.type = 'text'; + userLastName.className = 'lastName-register'; + userLastName.placeholder = 'Apellidos'; + userLastName.name = 'Lastname'; + userLastName.required = true; + + // Agregar el icono al segundo div de campo de entrada + inputFieldLastName.appendChild(iconLastName); + inputFieldLastName.appendChild(userLastName); + closer.appendChild(inputFieldName); + closer.appendChild(inputFieldLastName); + + // --------------------username--------------------- + // creando input de nombre usuario dentro de un div con un icon + const inputFieldUserName = document.createElement('div'); + inputFieldUserName.className = 'input-field'; + + // Crear el segundo elemento i con clase "fas fa-user" + const iconUserName = document.createElement('i'); + iconUserName.className = 'fas fa-user'; + + // Crear el segundo input con tipo "text", clase "username-register" + // placeholder "Ingresa tu usuario", y nombre "Username" + const userName = document.createElement('input'); + userName.type = 'text'; + userName.className = 'username-register'; + userName.placeholder = 'Ingresa tu usuario'; + userName.name = 'Username'; + userName.required = true; + + // Agregar el icono al segundo div de campo de entrada + inputFieldUserName.appendChild(iconUserName); + inputFieldUserName.appendChild(userName); + + // --------------------------mail----------------------------------- + // creando input de email dentro de un div con un icon + const inputFieldEmail = document.createElement('div'); + inputFieldEmail.className = 'input-field'; + + const iconEmail = document.createElement('i'); + iconEmail.className = 'fas fa-envelope'; + + const email = document.createElement('input'); + email.type = 'email'; + email.className = 'mail-register'; + email.placeholder = 'Ingresa tu email'; + email.name = 'Mail'; + email.required = true; + + inputFieldEmail.appendChild(iconEmail); + inputFieldEmail.appendChild(email); + // ----------------------------------------------------------------- + // creando input de contraseña dentro de un div con un icon + const closer1 = document.createElement('div'); + closer1.className = 'closer'; + + const inputFieldPss1 = document.createElement('div'); + inputFieldPss1.className = 'input-field-short'; + + const iconPassword1 = document.createElement('i'); + iconPassword1.className = 'fas fa-lock'; + + const password1 = document.createElement('input'); + password1.type = 'password'; + password1.className = 'password-register'; + password1.placeholder = 'Contraseña'; + password1.name = 'Password'; + password1.required = true; + + inputFieldPss1.appendChild(iconPassword1); + inputFieldPss1.appendChild(password1); + + // creando input de contraseña dos dentro de un div con un icon + const inputFieldPss2 = document.createElement('div'); + inputFieldPss2.className = 'input-field-short'; + + const iconPassword2 = document.createElement('i'); + iconPassword2.className = 'fas fa-lock'; + + const password2 = document.createElement('input'); + password2.type = 'password'; + password2.className = 'password-register'; + password2.placeholder = 'Confirmar'; + password2.name = 'Password'; + password2.required = true; + + inputFieldPss2.appendChild(iconPassword2); + inputFieldPss2.appendChild(password2); + closer1.appendChild(inputFieldPss1); + closer1.appendChild(inputFieldPss2); + // crear label de subscripción + const labelNews = document.createElement('label'); + labelNews.setAttribute('for', 'subscribeNews'); + + // Crear el input checkbox para la suscripción a noticias + const suscribe = document.createElement('input'); + suscribe.type = 'checkbox'; + suscribe.id = 'subscribeNews'; + suscribe.value = 'newsletter'; + suscribe.name = 'subscribe'; + suscribe.required = true; + + // Crear el texto para la suscripción a noticias + const textReceiveNews = document.createTextNode('Deseo recibir noticias y novedades de Warmi a mi correo'); + + labelNews.appendChild(suscribe); + labelNews.appendChild(textReceiveNews); + + // Crear el elemento label para las políticas y condiciones + const labelCond = document.createElement('label'); + labelCond.setAttribute('for', 'conditions'); + + // Crear el input checkbox para las políticas y condiciones + const inputCond = document.createElement('input'); + inputCond.type = 'checkbox'; + inputCond.id = 'conditions'; + inputCond.value = 'conditions'; + inputCond.name = 'conditions'; + inputCond.required = true; + + // Crear el texto para las políticas y condiciones + const labelPolitics = document.createTextNode('Estoy de acuerdo con las políticas y condiciones'); + + // Crear el elemento de enlace para leer más + const linkConditions = document.createElement('a'); + linkConditions.href = '/src/conditions.html'; + linkConditions.className = 'link1'; + linkConditions.textContent = 'Leer aquí'; + + labelCond.appendChild(inputCond); + labelCond.appendChild(labelPolitics); + labelCond.appendChild(linkConditions); + + // Crear el elemento input para el botón de enviar + const submitBtn = document.createElement('input'); + submitBtn.type = 'submit'; + submitBtn.className = 'btn'; + submitBtn.value = 'Crear mi cuenta'; + + // append child de cada elemento agregado al form + formSignUp.appendChild(title); + formSignUp.appendChild(subtitle); + formSignUp.appendChild(closer); + formSignUp.appendChild(inputFieldUserName); + formSignUp.appendChild(inputFieldEmail); + formSignUp.appendChild(closer1); + formSignUp.appendChild(labelCond); + formSignUp.appendChild(labelNews); + formSignUp.appendChild(submitBtn); + + signUpDiv.appendChild(loginUpRightDiv); + loginUpRightDiv.appendChild(loginLeftDivHeader); + loginLeftDivHeader.appendChild(logo); + loginLeftDivHeader.appendChild(subTitle); + loginLeftDivHeader.appendChild(brandDescription); + loginLeftDivHeader.appendChild(transparentBtn); + signUpDiv.appendChild(formSignUp); + + // evento que va a guardar el registro del usuario + submitBtn.addEventListener('click', async (e) => { + e.preventDefault(); + + const user = { + + name: formSignUp.elements.Name.value, + lastName: formSignUp.elements.Lastname.value, + email: formSignUp.elements.Mail.value, + username: formSignUp.elements.Username.value, + password: formSignUp.elements.Password[0].value, + }; + await signUp(user); + }); + + transparentBtn.addEventListener('click', (e) => { + e.preventDefault(); + window.location.assign('/login'); + }); + + return signUpDiv; +}; diff --git a/src/firebase/config.js b/src/firebase/config.js new file mode 100644 index 0000000..ad88c07 --- /dev/null +++ b/src/firebase/config.js @@ -0,0 +1,29 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from 'firebase/app'; +// importamps desde fireestore ese codigo //++ +import { getFirestore } from 'firebase/firestore'; +import { + getAuth, GoogleAuthProvider, +} from 'firebase/auth'; +// import { getAnalytics } from "firebase/analytics"; +// TODO: Add SDKs for Firebase products that you want to use +// https://firebase.google.com/docs/web/setup#available-libraries + +// Your web app's Firebase configuration +// For Firebase JS SDK v7.20.0 and later, measurementId is optional +const firebaseConfig = { + apiKey: 'AIzaSyDzcfa3MBIp2IA3cuOBKZntaHv9-0BqeI8', + authDomain: 'dev008-social-network.firebaseapp.com', + projectId: 'dev008-social-network', + storageBucket: 'dev008-social-network.appspot.com', + messagingSenderId: '813514052859', + appId: '1:813514052859:web:cf928bd795e4eb761d0c5e', + measurementId: 'G-N70CK0BGX8', +}; + +// Initialize Firebase +export const app = initializeApp(firebaseConfig); +export const auth = getAuth(app); +// inicialize firestore +export const db = getFirestore(app); +export const googleProvider = new GoogleAuthProvider(); diff --git a/src/firebase/firebase.js b/src/firebase/firebase.js new file mode 100644 index 0000000..95c5213 --- /dev/null +++ b/src/firebase/firebase.js @@ -0,0 +1,260 @@ +import { + signInWithPopup, + signInWithEmailAndPassword, + createUserWithEmailAndPassword, + browserLocalPersistence, + setPersistence, +} from 'firebase/auth'; +import { + setDoc, + doc, + collection, + addDoc, + deleteDoc, + updateDoc, + getDocs, + query, + orderBy, + /* + serverTimestamp, + */ + getDoc, + arrayUnion, + arrayRemove, + onSnapshot, +} from 'firebase/firestore'; +import { + auth, + googleProvider, + db, +} from './config.js'; + +/* +|-----------------------------------------| +| Register - SignUp | +|-----------------------------------------| +*/ +export const signUp = async (user) => { + try { + const firebaseUser = await createUserWithEmailAndPassword(auth, user.email, user.password); + + await setDoc(doc(db, 'users', firebaseUser.user.uid), { + first_name: user.name, + last_name: user.lastName, + username: user.username, + email: user.email, + picture: '', + }); + window.location.assign('/login'); + window.alert('Registro exitoso'); + } catch (error) { + window.alert(`register error: ${error.message}`); + } +}; + +// export const getUser = async (email) => new Promise((resolve, reject) => { +// const user = []; +// const usersRef = collection(db, 'users'); +// const q = query(usersRef, where('email', '==', email)); +// getDocs(q) +// .then((querySnapshot) => { +// querySnapshot.forEach((doc) => { +// user.push(doc.data()); +// return doc.data(); +// }); +// console.log(user); +// resolve(user[0]); +// }).catch((error) => { +// reject(error); +// }); +// }); +/* +|-----------------------------------------| +| Loguin - signInGoogle | +|-----------------------------------------| +*/ +export const signInGoogle = async () => { + try { + await setPersistence(auth, browserLocalPersistence); + const userCredentials = await signInWithPopup(auth, googleProvider); + await setDoc(doc(db, 'users', userCredentials.user.uid), { + first_name: userCredentials.user.displayName, + last_name: '', + username: userCredentials.user.displayName, + email: userCredentials.user.email, + picture: userCredentials.user.photoURL, + }); + localStorage.setItem('userCredentials', JSON.stringify({ + userID: userCredentials.user.uid, + username: userCredentials.user.displayName, + picture: userCredentials.user.photoURL, + })); + window.location.assign('/feed'); + window.alert('Ingreso Exitoso'); + } catch (error) { + window.alert(`google login error: ${error.message}`); + } +}; + +/* +|-----------------------------------------| +| Loguin - signIn | +|-----------------------------------------| +*/ +export const signIn = async (user) => { + try { + await setPersistence(auth, browserLocalPersistence); + const userCredentials = await signInWithEmailAndPassword(auth, user.email, user.password); + + console.log(userCredentials); + localStorage.setItem('userCredentials', JSON.stringify({ + email: userCredentials.user.email, + userID: userCredentials.user.uid, + })); + window.location.assign('/feed'); + window.alert('Ingreso Exitoso'); + } catch (error) { + window.alert(`login error: ${error.message}`); + } +}; +/* +|-----------------------------------------| +| POST - savePost | +|-----------------------------------------| +*/ +export const savePost = async (text) => ( + addDoc(collection(db, 'post'), { + text, + author: doc(db, '/users', auth.currentUser.uid), + timeline: Date.now(), + liked_by: [], + }) +); +/* +|-----------------------------------------| +| POST - showPosts | +|-----------------------------------------| +*/ +export const showPosts = async () => getDocs(query(collection(db, 'post'), orderBy('timeline', 'asc'))); +/* +|-----------------------------------------| +| POST - updatePost | +|-----------------------------------------| +*/ +export const updatePost = (postId, Newpost) => { + const user = auth.currentUser.uid; + const postRef = doc(db, 'post', postId); + updateDoc(postRef, { text: Newpost, timeline: Date.now() }) + .then(() => { + console.log('Post actualizado ', postId); + console.log('del Usuario', user); + }) + .catch((error) => { + console.error('Error al editar el post:', error); + }); +}; +/* +|-----------------------------------------| +| POST - getPost | +|-----------------------------------------| +*/ +export const getPost = (postID) => { + const postRef = doc(db, 'post', postID); + return new Promise((resolve, reject) => { + getDoc(postRef) + .then((post) => { + resolve(post.data()); + }) + .catch((error) => { + console.error('Error al traer el post:', error); + reject(error); + }); + }); +}; +/* +|---------------------------------------------| +| POST - updateLikePost | +|---------------------------------------------| +*/ +export const updateLikePost = async (postRef, freshPost) => { + const userRef = doc(db, 'users', auth.currentUser.uid); + const userAlreadyLiked = freshPost.liked_by.find((lover) => lover.path === userRef.path); + if (userAlreadyLiked) { + await updateDoc(postRef, { + liked_by: arrayRemove(userRef), + }); + + return '/img/heart-fill-white.svg'; + } await updateDoc(postRef, + { liked_by: arrayUnion(userRef) }); + return '/img/heart-fill-custom.svg'; +}; +/* +|-----------------------------------------| +| POST - deletePost | +|-----------------------------------------| +*/ +export const deletePost = (post) => { + const user = auth.currentUser.uid; + const postRef = doc(db, 'post', post); + deleteDoc(postRef) + .then(() => { + console.log('Post eliminado', post); + console.log('del Usuario', user); + }) + .catch((error) => { + console.error('Error al eliminar el post:', error); + }); +}; + +/* +|----------------------------------------------| +| POST - get data author | +|----------------------------------------------| +*/ +/* eslint-disable */ +export const getDataAuthor = (ref) => { + return new Promise((resolve, reject) => { + getDoc(ref) + .then((authorDocument) => { + resolve(authorDocument.data()); + }) + .catch((error) => { + reject(error); + }); + }); +}; +/* eslint-enable */ +/* +|-----------------------------------------| +| Recover password | +|-----------------------------------------| +*/ +// export const resetPassword = (email) => { +// sendPasswordResetEmail(auth, email) +// .then((userEmail) => { +// console.log('se envio un correo para cambiar contraseña!'); + +// }) +// .catch((error) => { +// const errorCode = error.code; +// const errorMessage = error.message; +// console.log(errorCode, errorMessage); + +// return error; +// }); +// }; + +export const listenPost = (addPost) => { + onSnapshot( + collection(db, 'post'), + (querySnapshot) => { + querySnapshot.forEach((document) => { + addPost(document.data()); + }); + }, + ); +}; + +export const getUserByUserID = (userid) => getDoc(doc(db, 'users', userid)) + .then((user) => user.data()); diff --git a/src/img/ED6FEYGGQNFGDM36CZVBK3WALE.webp b/src/img/ED6FEYGGQNFGDM36CZVBK3WALE.webp new file mode 100644 index 0000000..bffee3f Binary files /dev/null and b/src/img/ED6FEYGGQNFGDM36CZVBK3WALE.webp differ diff --git a/src/img/Logo.png b/src/img/Logo.png new file mode 100644 index 0000000..cdfcdb9 Binary files /dev/null and b/src/img/Logo.png differ diff --git a/src/img/camara-icon.svg b/src/img/camara-icon.svg new file mode 100644 index 0000000..638ea84 --- /dev/null +++ b/src/img/camara-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/img/chat-square-dots-fill.svg b/src/img/chat-square-dots-fill.svg new file mode 100644 index 0000000..7a9e0e3 --- /dev/null +++ b/src/img/chat-square-dots-fill.svg @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/src/img/chat-svgrepo-com.svg b/src/img/chat-svgrepo-com.svg new file mode 100644 index 0000000..97c9e3a --- /dev/null +++ b/src/img/chat-svgrepo-com.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/img/google.png b/src/img/google.png new file mode 100644 index 0000000..0200d2f Binary files /dev/null and b/src/img/google.png differ diff --git a/src/img/heart-fill-custom.svg b/src/img/heart-fill-custom.svg new file mode 100644 index 0000000..c888936 --- /dev/null +++ b/src/img/heart-fill-custom.svg @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/src/img/heart-fill-white.svg b/src/img/heart-fill-white.svg new file mode 100644 index 0000000..29783fe --- /dev/null +++ b/src/img/heart-fill-white.svg @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/src/img/heart-svgrepo-com.svg b/src/img/heart-svgrepo-com.svg new file mode 100644 index 0000000..17918cd --- /dev/null +++ b/src/img/heart-svgrepo-com.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/img/icon-logo.png b/src/img/icon-logo.png new file mode 100644 index 0000000..8174091 Binary files /dev/null and b/src/img/icon-logo.png differ diff --git a/src/img/icon-menu-celphone.svg b/src/img/icon-menu-celphone.svg new file mode 100644 index 0000000..99b2fe7 --- /dev/null +++ b/src/img/icon-menu-celphone.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/img/illustration-homepage.png b/src/img/illustration-homepage.png new file mode 100644 index 0000000..90d2271 Binary files /dev/null and b/src/img/illustration-homepage.png differ diff --git a/src/img/istockphoto-1323400501-612x612.jpg b/src/img/istockphoto-1323400501-612x612.jpg new file mode 100644 index 0000000..3dc6f65 Binary files /dev/null and b/src/img/istockphoto-1323400501-612x612.jpg differ diff --git a/src/img/logo-feed.png b/src/img/logo-feed.png new file mode 100644 index 0000000..e040bea Binary files /dev/null and b/src/img/logo-feed.png differ diff --git a/src/img/logotipo-de-apple.png b/src/img/logotipo-de-apple.png new file mode 100644 index 0000000..31fa44e Binary files /dev/null and b/src/img/logotipo-de-apple.png differ diff --git a/src/img/outlook.png b/src/img/outlook.png new file mode 100644 index 0000000..9f4811b Binary files /dev/null and b/src/img/outlook.png differ diff --git a/src/img/woman .png b/src/img/woman .png new file mode 100644 index 0000000..ba581a7 Binary files /dev/null and b/src/img/woman .png differ diff --git a/src/index.html b/src/index.html index 788db3c..9ade28e 100644 --- a/src/index.html +++ b/src/index.html @@ -1,12 +1,19 @@ - - - - - - - Document - - - - + + + + + + + + Warmi + + + + +
+ + \ No newline at end of file diff --git a/src/lib/index.js b/src/lib/index.js deleted file mode 100644 index d193089..0000000 --- a/src/lib/index.js +++ /dev/null @@ -1,6 +0,0 @@ -// aqui exportaras las funciones que necesites - -export const myFunction = () => { - // aqui tu codigo - console.log('Hola mundo!'); -}; diff --git a/src/main.js b/src/main.js index ac27e91..0d0ffa9 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,33 @@ -// Este es el punto de entrada de tu aplicacion - -import { myFunction } from './lib/index.js'; - -myFunction(); +import { Register } from './components/Register.js'; +import { Login } from './components/Login.js'; +import { RecoverPassword } from './components/RecoverPassword.js'; +import { Feed } from './components/Feed.js'; + +const rootDiv = document.getElementById('root'); + +const ProtectedRoute = (route) => { + console.log('Protected route'); + return route; +}; + +const routes = { + '/': Login, + '/login': Login, + '/register': Register, + '/recoverPassword': RecoverPassword, + '/feed': ProtectedRoute(Feed), +}; + +export const onNavigate = (pathname) => { + console.log(pathname); + window.history.pushState({}, pathname, window.location.origin + pathname); + rootDiv.appendChild(routes[pathname]()); +}; + +const component = routes[window.location.pathname]; + +window.onpopstate = () => { + rootDiv.appendChild(component()); +}; + +rootDiv.appendChild(component()); diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..d8b96e5 --- /dev/null +++ b/src/styles.css @@ -0,0 +1,1312 @@ +@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700;800&display=swap"); + +html, +body { + margin: 0; + width: 100%; + height: 100%; + background-color: #FAFAFA; +} + +body, +input { + font-family: "Poppins", sans-serif; +} + +#root { + margin: 0; + width: 100%; + height: 100%; +} + +/*pantalla login +/*contenedor izquierdo*/ +.transition-div { + height: 100%; + background-color: #FF728D; + display: flex; + flex-direction: column; + align-content: space-around; + text-align: center; +} + +.transition-header { + align-self: center; + justify-content: end; + margin-top: auto; + width: 60%; + height: auto; + +} + +.Logo { + align-self: center; + width: 178px; +} + +.warmi-summary { + font-size: 16px; + color: #f0f0f0; + +} + +.smaller-subtitle { + font-size: 18px; + color: #f0f0f0; + font-weight: bold; + +} + +.illustration-container { + display: flex; + margin-top: auto; +} + +.illustration { + width: 100%; + display: flex; +} + +.btn.transparent { + margin: 0; + background: none; + border: 2px solid #fff; + font-weight: 600; + font-size: 0.8rem; +} + +/*contenedor izquierdo*/ +.container { + width: 100%; + background-color: #fff; + height: 100%; + display: grid; + grid-template-columns: 50% 50%; +} + +/*contenedor derecho*/ +.forms-container { + display: flex; + flex-direction: column; + align-content: center; + justify-content: center; + text-align: center; + width: 100%; + height: 100%; +} + +.signin { + display: grid; + grid-template-columns: 1fr; +} + +form { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 0rem 5rem; + transition: all 0.2s 0.7s; + overflow: hidden; + grid-column: 1 / 2; + grid-row: 1 / 2; +} + +.title { + font-size: 32px; + color: #444; + margin-bottom: 10px; +} + +.subtitle { + font-size: 1rem; + margin-bottom: 10px; + color: #8C8C8C; + +} + +label { + color: #8C8C8C; +} + +.input-field { + max-width: 400px; + width: 100%; + background-color: #f0f0f0; + margin: 10px 0; + height: 52px; + border-radius: 55px; + display: grid; + grid-template-columns: 15% 85%; + padding: 0 0.4rem; +} + +.input-field i { + text-align: center; + line-height: 55px; + color: #acacac; + transition: 0.5s; + font-size: 1.1rem; +} + +.messages-icon1 img { + width: 1%; + color: #acacac; +} + +.messages-icon2 img { + width: 1%; + color: #acacac; +} + + +.input-field input { + font-size: 16px; + background: none; + outline: none; + border: none; + line-height: 1; + color: #333; +} + +.input-field input::placeholder { + color: #aaa; + font-weight: 600; + font-size: 1rem; +} + +/************************************************/ +.input-field-short { + max-width: 185px; + width: 100%; + background-color: #f0f0f0; + margin: 10px 0; + height: 52px; + border-radius: 55px; + display: grid; + grid-template-columns: 15% 85%; + align-items: center; + margin-right: 10px; + padding: 0 0.4rem; +} + +.closer { + display: flex; +} + +.input-field-short i { + text-align: center; + line-height: 55px; + color: #acacac; + transition: 0.5s; + font-size: 1.1rem; +} + +.input-field-short input { + font-size: 16px; + background: none; + outline: none; + border: none; + line-height: 1; + color: #333; +} + +.input-field-short input::placeholder { + color: #aaa; + font-weight: 600; + font-size: 1rem; +} + +.social-text { + padding: 0.7rem 0; + font-size: 16px; +} + +.social-media { + display: flex; + justify-content: center; +} + +.social-icon { + height: 46px; + width: 46px; + display: flex; + justify-content: center; + align-items: center; + margin: 0 0.45rem; + color: #333; + border-radius: 50%; + border: 1px solid #333; + text-decoration: none; + font-size: 1.1rem; + transition: 0.3s; +} + +.googleIcon { + width: 40px; +} + +.social-icon:hover { + color: #EF2684; + border-color: #EF2684; +} + +.btn { + width: 180px; + background-color: #FF728D; + border: none; + outline: none; + height: 50px; + border-radius: 49px; + color: #fff; + text-transform: uppercase; + font-weight: 600; + margin: 15px 0; + cursor: pointer; + transition: 0.5s; +} + +.btn:hover { + background-color: #EF2684; +} + +.link { + text-decoration: none; + font-style: normal; + font-weight: 700; + font-size: 15px; + line-height: 18px; + color: #FF728D; + display: inline-block; + margin-left: 10px; + cursor: pointer; +} + +.btn-save { + width: 375px; + background-color: #FF728D; + border: none; + outline: none; + height: 49px; + border-radius: 49px; + color: #fff; + text-transform: uppercase; + font-weight: 600; + margin: 10px 0; + cursor: pointer; + transition: 0.5s; +} + +.support-text { + width: 375px; + margin-top: 20px; +} + +/*pantalla registro */ + +.signup { + width: 100%; + background-color: #fff; + height: 100%; + display: grid; + grid-template-columns: 50% 50%; +} + +.transition-div2 { + height: 100%; + background-color: #FF728D; + display: flex; + flex-direction: column; + align-content: space-around; + text-align: center; +} + +.transition-header2 { + align-self: center; + justify-content: center; + margin-top: 38%; + width: 60%; + height: auto; + +} + +/* responsive*/ +@media (max-width: 870px) { + .container-singup { + min-height: 800px; + display: grid; + grid-template-columns: 50% 50%; + } + + /*contenedor izquierdo*/ + + .transition-header-trasition-header2 { + width: 70%; + } + + .Logo { + width: 170px; + } + + .warmi-summary { + font-size: 12px; + } + + .smaller-subtitle { + color: #f0f0f0; + font-size: 16px; + } + + /*contenedor derecho*/ + + form { + + transition: all 0.2s 0.7s; + overflow: hidden; + grid-column: 1 / 2; + grid-row: 1 / 2; + } + + .title { + font-size: 26px; + margin-bottom: 5px; + } + + .subtitle { + font-size: 14px; + margin-bottom: 5px; + } + + .input-field { + max-width: 280px; + margin: 7px 0; + height: 50px; + display: grid; + grid-template-columns: 15% 85%; + padding: 0 0.4rem; + } + + .input-field i { + display: flex; + justify-content: center; + line-height: auto; + font-size: 15px; + } + + .input-field input { + line-height: 1; + } + + .input-field input::placeholder { + color: #aaa; + font-weight: 600; + font-size: 14px; + } + + .social-text { + font-size: 14px; + } + + .social-media { + display: flex; + justify-content: center; + } + + .social-icon { + height: 40px; + width: 40px; + display: flex; + justify-content: center; + align-items: center; + margin: 0 5px; + border: 1px solid #333; + text-decoration: none; + font-size: 19px; + transition: 0.3s; + } + + .btn { + width: 160px; + height: 45px; + border-radius: 49px; + margin: 10px 0; + cursor: pointer; + transition: 0.5s; + } + + .solid { + font-size: 12px; + } + + .link { + text-decoration: none; + font-style: normal; + font-weight: 700; + font-size: 15px; + line-height: 18px; + color: #FF728D; + display: inline-block; + } + + .btn.transparent { + margin: 0; + background: none; + border: 2px solid #fff; + height: 41px; + font-weight: 600; + font-size: 0.8rem; + } +} + +@media (max-width: 654px) { + .container { + grid-template-columns: 100%; + grid-template-rows: auto auto; + } + + /* arriba*/ + .transition-div { + height: auto; + background-color: #FF728D; + display: flex; + flex-direction: column; + align-content: space-around; + text-align: center; + } + + .signup { + display: flex; + flex-direction: column; + } + + .transition-div2 { + height: auto; + background-color: #FF728D; + display: flex; + flex-direction: column; + align-content: space-around; + text-align: center; + } + + .transition-header { + align-self: center; + justify-content: center; + padding: 10% 0px; + width: 70%; + } + + .transition-header2 { + width: 60%; + height: auto; + align-self: center; + justify-content: center; + padding: 10% 10px; + margin-top: 10%; + } + + label { + font-size: small; + } + + .Logo { + width: 100px; + } + + .warmi-summary { + font-size: 12px; + } + + .smaller-subtitle { + font-size: 14px; + } + + .illustration-container { + display: flex; + margin-top: auto; + } + + .illustration { + width: 100%; + display: flex; + } + + .btn.transparent { + height: 35px; + font-weight: 600; + font-size: 12px; + } + + /*abajo*/ + .forms-container { + padding: 10px 0px; + } + + form { + padding: 0px 10%; + } + + .title { + font-size: 22px; + margin-bottom: 8px; + } + + .subtitle { + font-size: 12px; + margin-bottom: 8px; + } + + .input-field { + background-color: #f0f0f0; + margin: 10px 0; + height: 50px; + display: grid; + } + + .input-field i { + font-size: 15px; + } + + .input-field input::placeholder { + font-size: 15px; + } + + .link { + font-size: 15px; + line-height: 18px; + } + + .social-icon { + font-size: 22px; + } + + .btn { + width: 160px; + height: 45px; + text-transform: uppercase; + font-weight: 600; + margin: 10px 0; + cursor: pointer; + transition: 0.5s; + } + + .solid { + font-size: 13px; + } +} + + + +/*****************************************************FEED******/ +/*design colors*/ +.colorbackpink { + background-color: #FF728D; +} + +.colorwhite { + background-color: #FAFAFA; +} + +.colorlightblue { + background-color: #1BC1E2; +} + +.colorgray { + background-color: #B6B6B6; +} + +.feed-container { + display: flex; + flex-direction: column; + height: 100%; +} + + +/* header */ +header { + height: 80px; + display: flex; + padding: 0px 5px; +} + +.header-container { + display: flex; + flex-direction: row; + align-items: center; + width: 100%; +} + +.logo { + height: 24px; + width: 39px; +} + +.logo-horizontal { + display: none; +} + +.icon-hide-menu { + border: none; + background: none; + cursor: pointer; + margin-left: 2px; + margin-right: 12px; +} + +.input-search-bar { + margin-right: auto; + padding-left: 10px; + height: 25px; + width: 200px; + border: 0; + border-radius: 50px; + font-size: 12px; + font-weight: 600; +} + +.input-search-bar::placeholder { + color: #B6B6B6; +} + +.user-name-header { + margin-top: 0px; + margin-bottom: 0px; + margin-left: auto; + font-size: 16px; + color: #FAFAFA; + display: none; +} + +.user-image { + height: 40px; + width: 40px; + border-radius: 50%; + margin-left: 10px; + cursor: pointer; +} + +/*aside*/ +aside { + display: none; +} + +/* main */ +main { + display: flex; + justify-content: center; + flex-direction: column; +} + +.user-post-container { + border: 1px solid #B6B6B6; + border-radius: 15px; + padding: 0px; + margin-top: 10px; + display: grid; + align-self: center; + grid-template-columns: 100%; + grid-template-rows: 2fr 1fr; + width: 85%; + height: fit-content; +} + +.user-post { + font-family: "Poppins", sans-serif; + box-sizing: border-box; + margin: 0px; + resize: none; + padding: 15px 15px; + border: none; + border-radius: 15px; + height: 110px; + width: 100%; + font-weight: 600; + font-size: 14px; +} + +.user-post::placeholder { + color: #B6B6B6; +} + +.user-post-btns-conatiner { + padding-bottom: 5px; + padding-right: 10px; + width: auto; + margin-left: auto; + align-items: center; + display: flex; + height: fit-content; +} + +.btn-insert-photo { + height: auto; + border: none; + border-radius: 7px; + outline: none; + padding: 8px; + cursor: pointer; + transition: 0.5s; +} + +.btn-insert-photo:hover { + background-color: #EF2684; +} + +.btn-post { + border: none; + border-radius: 12px; + outline: none; + padding: 9px; + font-size: 13px; + color: #FAFAFA; + font-weight: 600; + margin-left: 5px; + cursor: pointer; + transition: 0.5s; +} + +.btn-post:hover { + background-color: #EF2684; +} + +.timeline-container { + display: flex; + justify-content: center; + flex-direction: column; + width: 100%; + height: fit-content; +} + +.user-published-post { + border: 1px solid #B6B6B6; + border-radius: 15px; + margin-top: 20px; + align-self: center; + display: flex; + flex-direction: column; + width: 83%; + height: fit-content; +} + +.user-published-post-div { + padding: 10px 10px 5px 10px; +} + +.user-published-post-content { + display: flex; + padding-bottom: 5px; + width: 100%; +} + +.conversation-img { + display: flex; + border-radius: 20px; + width: 40px; + height: 40px; + object-fit: cover; +} + +.user-published-post-text-content { + display: flex; + flex-direction: column; + margin-left: 10px; + width: 100%; +} + +.text-content-upper-row { + height: 25px; + display: flex; + flex-direction: row; + padding-right: 5px; + align-items: center; +} + +.user-published-post-title { + margin: 0px; + font-weight: 600; +} + +.user-published-post-edit { + margin-top: 0; + margin-left: auto; + margin-bottom: 20px; + font-size: 25px; + display: inline; + position: relative; + align-self: center; + color: #504f4f; + cursor: pointer; +} + +.edit-post-option-container { + border: 1px solid #B6B6B6; + padding: 0px; + border-radius: 10px; + display: none; + flex-direction: column; + align-items: center; + text-align: center; + position: absolute; + top: 12px; + left: -5px; + width: 65px; + height: fit-content; +} + +.user-published-post-edit:hover .edit-post-option-container { + display: list-item; + list-style: none; +} + +.edit-post-option { + width: 55px; + list-style: none; + font-size: 13px; + padding: 5px 5px 5px 5px; +} + +.edit-post-option:hover { + border-radius: 8px 8px 0px 0px; + background-color: #B6B6B6; + color: #FAFAFA; +} + +.two { + border-top: 1px solid #B6B6B6; +} + +.two:hover { + border-radius: 0px 0px 8px 8px; +} + +.three:hover { + color: #EF2684; + background-color: #FAFAFA; + border-radius: 9px 9px 9px 9px; +} + +.user-published-post-text { + font-size: 13px; + hyphens: auto; + margin: 0px; + padding-top: 5px; + padding-bottom: 2px; + width: 100%; +} + +.user-published-post-actions { + display: flex; + height: 15px; + align-items: center; +} + +.heart-icon, +.messages-icon1, +.messages-icon2 { + width: 20px; + margin-left: 10px; + cursor: pointer; +} + +.likes-counter { + font-size: 13px; + margin-left: 3px; + padding: 0px; + color: #B6B6B6; +} + +.messages-icon { + width: 20px; + margin-left: auto; + cursor: pointer; +} + +footer { + padding: 40px 0px; + display: flex; + flex-direction: column; + justify-content: center; + align-content: center; + margin-top: 100px; + height: fit-content; + width: 100%; +} + +.footer-first-row { + display: flex; + justify-content: center; +} + +.footer-second-row { + display: flex; + justify-content: center; + margin-top: 20px; +} + +.footer-first-row p, +.footer-second-row p { + justify-content: center; + margin: auto 2%; + display: inline-flex; + font-size: 11px; + color: #FAFAFA; +} + + +@media (min-width: 500px) { + .user-name-header { + display: block; + } + + .centered-main { + margin-bottom: 90px; + } + + .logo { + display: none; + height: 24px; + width: 39px; + } + + .logo-horizontal { + display: block; + width: 90px; + + } + + .icon-hide-menu { + border: none; + background: none; + margin-left: 4px; + } + + .input-search-bar { + width: 35%; + height: 28px; + font-size: 14px; + } + + .user-published-post { + width: 85%; + } + + @media (min-width: 700px) { + .header-container { + padding: 0px 20px; + } + + .user-image { + width: 40px; + height: 40px; + } + + .centered-main { + justify-content: center; + display: flex; + align-content: center; + margin-top: 20px; + } + + .flex-item-left { + height: auto; + margin-right: 20px; + } + + aside { + color: #252525; + grid-area: aside; + display: flex; + justify-content: center; + width: auto; + } + + .flex-item-right { + flex-direction: column; + justify-content: center; + align-items: center; + width: 60%; + } + + .trendy-title { + margin-top: 0px; + } + + main { + width: 100%; + margin-right: 0px; + padding-right: 0px; + + } + + .user-post-container { + margin: 0px; + width: 100%; + } + + .user-post { + box-sizing: border-box; + resize: none; + padding: 10px 10px; + border: none; + border-radius: 15px; + height: 110px; + width: 100%; + font-weight: 600; + font-size: 15px; + outline: none; + } + + /* template del post de un usuario en feed*/ + .user-published-post { + padding: 0px; + width: 100%; + margin-top: 10px; + } + + .user-published-post-text-content { + margin-left: 10px; + } + + .user-published-post-actions { + padding-bottom: 0px; + } + + /*header*/ + + .logo-horizontal { + display: block; + width: 100px; + margin-right: auto; + } + + .icon-hide-menu { + display: none; + border: none; + background: none; + } + + .input-search-bar { + width: 40%; + font-size: 14px; + justify-self: center; + } + + .trending-container { + width: 200px; + margin-left: auto; + } + + h2 { + color: #FAFAFA; + font-size: 14px; + padding: 10px; + border-radius: 10px; + } + + h3 { + font-size: 13px; + margin-bottom: 10px; + margin-top: 0px; + font-weight: 600; + } + + aside div div { + display: grid; + row-gap: 0px; + } + + aside div div a { + color: #1BC1E2; + cursor: pointer; + text-decoration-line: underline; + font-size: 12px; + margin-left: auto; + margin-top: 10px; + } + + /*template trending #*/ + .hashtag-template { + margin: 0px; + color: #FF728D; + font-size: 13px; + } + + /*template trending groups*/ + .group-container { + display: flex; + flex-direction: row; + overflow: hidden; + } + + .group-img { + width: 15px; + height: 15px; + } + + .group-title { + margin: 0px; + font-size: 13px; + margin-left: 3px; + } + + /*template trending conversations*/ + .conversation-container, + .news-container { + display: flex; + flex-direction: column; + border: 1px solid #B6B6B6; + border-radius: 10px; + padding-top: 6px; + padding-left: 6px; + padding-right: 6px; + } + + .conversation-content, + .news-content { + display: flex; + padding-bottom: 5px; + } + + .conversation-img { + display: flex; + border-radius: 20px; + width: 30px; + height: 30px; + object-fit: cover; + } + + .text-container { + display: flex; + flex-direction: column; + margin: 0px; + padding-left: 6px; + padding-bottom: 6px; + } + + .conversation-name { + margin: 2px 0px; + font-size: 13px; + font-weight: bold; + + } + + .conversation-post, + .news-text { + margin: 0px 0px; + font-size: 12px; + hyphens: auto; + } + + .conversation-actions { + border-top: 1px solid #B6B6B6; + padding: 3px 0px; + display: flex; + flex-direction: row; + } + + .heart-icon { + width: 15px; + margin-left: 10px; + cursor: pointer; + } + + .messages-icon { + width: 15px; + margin-left: auto; + cursor: pointer; + } + + /*template noticias*/ + .news-img { + height: 100%; + width: 40%; + object-fit: cover; + margin-left: 2px; + border-radius: 0px 5px 5px 0px; + } + + .text-plus { + width: 60%; + } + } + + @media (min-width: 1000px) { + .header-container { + justify-content: center; + align-content: center; + } + + .input-search-bar { + justify-self: center; + width: 50%; + } + + .centered-main { + justify-content: center; + display: flex; + align-content: center; + margin-top: 30px; + margin-bottom: 100px; + } + + .flex-item-left { + height: auto; + margin-right: 20px; + } + + aside { + width: auto; + } + + .flex-item-right { + flex-direction: column; + justify-content: center; + align-items: center; + width: 60%; + } + + .trendy-title { + margin-top: 0px; + } + + main { + width: 100%; + margin-right: 0px; + padding-right: 0px; + + } + + .user-post-container { + margin: 0px; + width: 100%; + } + + .user-post { + box-sizing: border-box; + resize: none; + padding: 10px 10px; + border: none; + border-radius: 15px; + height: 110px; + width: 100%; + font-weight: 600; + font-size: 15px; + outline: none; + } + } + + @media (min-width: 1125px) { + .header-container { + padding: 0px 30px; + } + + .flex-item-right { + width: fit-content; + } + + .user-post-container, + .user-published-post { + width: 680px; + } + + } +} \ No newline at end of file diff --git a/stylelint.config.js b/stylelint.config.cjs similarity index 100% rename from stylelint.config.js rename to stylelint.config.cjs diff --git a/test/index.spec.js b/test/index.spec.js index 91f11a3..24bd242 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,8 +1,205 @@ // importamos la funcion que vamos a testear -import { myFunction } from '../src/lib/index'; +import { + signUp, + signIn, + savePost, + showPosts, + /* + signInGoogle, + getUser, + savePost, +*/ -describe('myFunction', () => { - it('debería ser una función', () => { - expect(typeof myFunction).toBe('function'); +} from '../src/firebase/firebase.js'; + +// Importa las dependencias que necesites, como `jest`, `mocks`, etc. + +describe('signUp', () => { + it('debería registrar correctamente un usuario', async () => { + // Crea un objeto de usuario de prueba + const user = { + name: 'Roxi', + lastName: 'Ochoa García', + username: 'cam125', + email: 'cam@gmail.com', + password: '123456', + }; + + // Crea mocks para las funciones y objetos externos que se utilizan dentro de la función signUp + const auth = { + createUserWithEmailAndPassword: jest.fn().mockResolvedValue({ user: { uid: 'userId' } }), + }; + const db = { + doc: jest.fn(), + setDoc: jest.fn(), + }; + const window = { + location: { assign: jest.fn() }, + alert: jest.fn(), + }; + + // Ejecuta la función signUp + await signUp(user, auth, db, window); + + // Verifica que las funciones hayan sido llamadas con los argumentos correctos + expect(auth.createUserWithEmailAndPassword).toHaveBeenCalledWith(user.email, user.password); + expect(db.doc).toHaveBeenCalledWith(db, 'users', 'userId'); + expect(db.setDoc).toHaveBeenCalledWith({ + first_name: user.name, + last_name: user.lastName, + username: user.username, + email: user.email, + }); + expect(window.location.assign).toHaveBeenCalledWith('/login'); + expect(window.alert).toHaveBeenCalledWith('Registro exitoso'); + }); + + it('debería manejar correctamente un error', async () => { + // Crea un objeto de usuario de prueba + const user = { + name: 'Roxi', + lastName: 'Ochoa García', + username: 'cam125', + email: 'cam@example.com', + password: '123456', + }; + + // Crea mocks para las funciones y objetos externos que se utilizan dentro de la función signUp + const auth = { + createUserWithEmailAndPassword: jest.fn().mockRejectedValue(new Error('Error en el registro')), + }; + const db = { + doc: jest.fn(), + setDoc: jest.fn(), + }; + const consoleSpy = jest.spyOn(console, 'log'); + + // Ejecuta la función signUp + await signUp(user, auth, db); + + // Verifica que la función createUserWithEmailAndPassword + // haya sido llamada con los argumentos correctos + expect(auth.createUserWithEmailAndPassword).toHaveBeenCalledWith(user.email, user.password); + + // Verifica que la función console.log haya sido llamada con el error + expect(consoleSpy).toHaveBeenCalledWith({ error: new Error('Error en el registro') }); + }); +}); + +// signIn + +// Importa las dependencias que necesites, como `jest`, `mocks`, etc. + +describe('signIn', () => { + it('debería realizar el inicio de sesión correctamente', async () => { + // Crea un objeto de usuario de prueba + const user = { + email: 'cam@gmail.com', + password: 'password123', + }; + + // Crea mocks para las funciones y objetos externos que se utilizan dentro de la función signIn + const auth = { + signInWithEmailAndPassword: jest.fn().mockResolvedValue({ /* datos del usuario */ }), + }; + const localStorageMock = { + setItem: jest.fn(), + }; + const window = { + location: { assign: jest.fn() }, + alert: jest.fn(), + }; + + // Ejecuta la función signIn + await signIn(user, auth, localStorageMock, window); + + // Verifica que las funciones hayan sido llamadas con los argumentos correctos + expect(auth.signInWithEmailAndPassword).toHaveBeenCalledWith(user.email, user.password); + expect(localStorageMock.setItem).toHaveBeenCalledWith( + 'userCredentials', + JSON.stringify({ /* datos del usuario */ }), + ); + expect(window.location.assign).toHaveBeenCalledWith('/feed'); + expect(window.alert).toHaveBeenCalledWith('Ingreso Exitoso'); + }); + + it('debería manejar correctamente un error', async () => { + // Crea un objeto de usuario de prueba + const user = { + email: 'cam@google.com', + password: 'password123', + }; + + // Crea mocks para las funciones y objetos externos que se utilizan dentro de la función signIn + const auth = { + signInWithEmailAndPassword: jest.fn().mockRejectedValue(new Error('Error en el inicio de sesión')), + }; + const consoleSpy = jest.spyOn(console, 'log'); + + // Ejecuta la función signIn + await signIn(user, auth); + + // Verifica que la función signInWithEmailAndPassword + // haya sido llamada con los argumentos correctos + expect(auth.signInWithEmailAndPassword).toHaveBeenCalledWith(user.email, user.password); + + // Verifica que la función console.log haya sido llamada con el error + expect(consoleSpy).toHaveBeenCalledWith(new Error('Error en el inicio de sesión')); + }); +}); +// ---------------------------probar post +// save post +describe('savePost', () => { + it('debería guardar correctamente un post', async () => { + // Crea los datos de prueba + const text = 'Este es un nuevo post'; + const name = 'Roxi Ochoa'; + + // Crea mocks para las funciones y objetos externos + // que se utilizan dentro de la función savePost + const db = { + collection: jest.fn(), + addDoc: jest.fn().mockResolvedValue(), + }; + const dateNowMock = jest.spyOn(Date, 'now').mockReturnValue(1625918400000); // 10 de julio de 2021 + + // Ejecuta la función savePost + await savePost(text, name, db); + + // Verifica que las funciones hayan sido llamadas con los argumentos correctos + expect(db.collection).toHaveBeenCalledWith(db, 'post'); + expect(db.addDoc).toHaveBeenCalledWith({ + text, + name, + timeline: 1625918400000, // 10 de julio de 2021 + }); + + // Restaura el comportamiento original de Date.now + dateNowMock.mockRestore(); + }); +}); +// mostrar post +describe('showPosts', () => { + it('debería obtener correctamente los posts', async () => { + // Crea mocks para las funciones y objetos externos + // que se utilizan dentro de la función showPosts + const db = { + collection: jest.fn(), + query: jest.fn(), + orderBy: jest.fn(), + getDocs: jest.fn().mockResolvedValue(/* datos de prueba */), + }; + + // Ejecuta la función showPosts + const result = await showPosts(db); + + // Verifica que las funciones hayan sido llamadas con los argumentos correctos + expect(db.collection).toHaveBeenCalledWith(db, 'post'); + expect(db.query).toHaveBeenCalledWith(/* parámetros del query */); + expect(db.orderBy).toHaveBeenCalledWith('timeline', 'asc'); + expect(db.getDocs).toHaveBeenCalled(); + + // Verifica que la función devuelva el resultado esperado + expect(result).toEqual(/* datos de prueba */); }); });