diff --git a/staff/daniel-guillen/socialcode/app/components/Component.js b/staff/daniel-guillen/socialcode/app/components/Component.js
new file mode 100644
index 000000000..3da1c66e3
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/Component.js
@@ -0,0 +1,60 @@
+class Component {
+ constructor(tagNameOrContainer = 'div') {
+ if (typeof tagNameOrContainer === 'string')
+ this.container = document.createElement(tagNameOrContainer)
+ else if (tagNameOrContainer instanceof HTMLElement || tagNameOrContainer instanceof HTMLDocument)
+ this.container = tagNameOrContainer
+ else
+ throw new Error('tagNameOrContainer is not a tagName or container')
+
+ this.children = []
+ }
+
+ add(child) {
+ if (!(child instanceof Component)) throw new TypeError('child is not component')
+
+ this.children.push(child)
+
+ this.container.appendChild(child.container)
+ }
+
+ remove(child) {
+ if (!(child instanceof Component)) throw new TypeError('child is not component')
+
+ const index = this.children.indexOf(child)
+
+ if (index > -1)
+ this.children.splice(index, 1)
+
+ if (this.container.contains(child.container))
+ this.container.removeChild(child.container)
+ }
+
+ setText(text) {
+ this.container.innerText = text
+ }
+
+ setId(id) {
+ this.container.id = id
+ }
+
+ addClass(clazz) {
+ this.container.classList.add(clazz)
+ }
+
+ removeClass(clazz) {
+ this.container.classList.remove(clazz)
+ }
+
+ onClick(listener) {
+ this.container.addEventListener('click', listener)
+ }
+
+ onKeyDown(listener) {
+ this.container.addEventListener('keydown', listener)
+ }
+
+ onKeyUp(listener) {
+ this.container.addEventListener('keyup', listener)
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/Post.js b/staff/daniel-guillen/socialcode/app/components/Post.js
new file mode 100644
index 000000000..2abd1b0d6
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/Post.js
@@ -0,0 +1,22 @@
+class Post extends Component {
+ constructor(post) {
+ super('article')
+
+ const authorTitle = new Component('p')
+ authorTitle.setText(post.author)
+
+ const postTitle = new Component('h2')
+ postTitle.setText(post.title)
+
+ const postImage = new Image
+ postImage.setUrl(post.image)
+
+ const postText = new Component('p')
+ postText.setText(post.text)
+
+ this.add(authorTitle)
+ this.add(postTitle)
+ this.add(postImage)
+ this.add(postText)
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Button.css b/staff/daniel-guillen/socialcode/app/components/core/Button.css
new file mode 100644
index 000000000..d45aa1b0b
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Button.css
@@ -0,0 +1,6 @@
+.Button {
+ padding: .4rem;
+ background-color: transparent;
+ font-size: 1rem;
+ border: 1px solid var(--first-color);
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Button.js b/staff/daniel-guillen/socialcode/app/components/core/Button.js
new file mode 100644
index 000000000..6acbefc57
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Button.js
@@ -0,0 +1,11 @@
+class Button extends Component {
+ constructor() {
+ super('button')
+
+ this.addClass('Button')
+ }
+
+ setType(type) {
+ this.container.type = type
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Field.css b/staff/daniel-guillen/socialcode/app/components/core/Field.css
new file mode 100644
index 000000000..708f5849b
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Field.css
@@ -0,0 +1,5 @@
+.Field {
+ display: flex;
+ flex-direction: column;
+ margin: .25rem 0;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Field.js b/staff/daniel-guillen/socialcode/app/components/core/Field.js
new file mode 100644
index 000000000..201360e2f
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Field.js
@@ -0,0 +1,28 @@
+class Field extends Component {
+ constructor(id, type, text) {
+ super('div')
+
+ this.addClass('Field')
+
+ const label = new Label
+ label.setText(text)
+ label.setFor(id)
+
+ const input = new Input
+ input.setId(id)
+ input.setType(type)
+
+ this.add(label)
+ this.add(input)
+ }
+
+ setPlaceholder(placeholder) {
+ this.children[1].setPlaceholder(placeholder)
+ }
+
+ getValue() {
+ const input = this.children[1]
+
+ return input.getValue()
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Form.css b/staff/daniel-guillen/socialcode/app/components/core/Form.css
new file mode 100644
index 000000000..379cad316
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Form.css
@@ -0,0 +1,5 @@
+.Form {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Form.js b/staff/daniel-guillen/socialcode/app/components/core/Form.js
new file mode 100644
index 000000000..62377cef5
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Form.js
@@ -0,0 +1,15 @@
+class Form extends Component {
+ constructor() {
+ super('form')
+
+ this.addClass('Form')
+ }
+
+ onSubmit(listener) {
+ this.container.addEventListener('submit', listener)
+ }
+
+ clear() {
+ this.container.reset()
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Heading.js b/staff/daniel-guillen/socialcode/app/components/core/Heading.js
new file mode 100644
index 000000000..093dde937
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Heading.js
@@ -0,0 +1,5 @@
+class Heading extends Component {
+ constructor(level) {
+ super('h' + level)
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Image.css b/staff/daniel-guillen/socialcode/app/components/core/Image.css
new file mode 100644
index 000000000..d1abcb0ea
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Image.css
@@ -0,0 +1,3 @@
+.Image {
+ width: 100%;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Image.js b/staff/daniel-guillen/socialcode/app/components/core/Image.js
new file mode 100644
index 000000000..70988c875
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Image.js
@@ -0,0 +1,15 @@
+class Image extends Component {
+ constructor() {
+ super('img')
+
+ this.addClass('Image')
+ }
+
+ setUrl(url) {
+ this.container.src = url
+ }
+
+ setAltText(altText) {
+ this.container.alt = altText
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Input.css b/staff/daniel-guillen/socialcode/app/components/core/Input.css
new file mode 100644
index 000000000..6c09b66f6
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Input.css
@@ -0,0 +1,6 @@
+.Input {
+ padding: .4rem;
+ background-color: transparent;
+ font-size: 1rem;
+ border: 1px solid var(--first-color);
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Input.js b/staff/daniel-guillen/socialcode/app/components/core/Input.js
new file mode 100644
index 000000000..9b6509cd7
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Input.js
@@ -0,0 +1,19 @@
+class Input extends Component {
+ constructor() {
+ super('input')
+
+ this.addClass('Input')
+ }
+
+ setType(type) {
+ this.container.type = type
+ }
+
+ setPlaceholder(placeholder) {
+ this.container.placeholder = placeholder
+ }
+
+ getValue() {
+ return this.container.value
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Label.js b/staff/daniel-guillen/socialcode/app/components/core/Label.js
new file mode 100644
index 000000000..4bbf3b03e
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Label.js
@@ -0,0 +1,9 @@
+class Label extends Component {
+ constructor() {
+ super('label')
+ }
+
+ setFor(id) {
+ this.container.htmlFor = id
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/Link.js b/staff/daniel-guillen/socialcode/app/components/core/Link.js
new file mode 100644
index 000000000..7f074dce8
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/Link.js
@@ -0,0 +1,15 @@
+class Link extends Component {
+ constructor() {
+ super('a')
+
+ this.setUrl('')
+ }
+
+ setUrl(url) {
+ this.container.href = url
+ }
+
+ setTarget(target) {
+ this.container.target = target
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/SubmitButton.css b/staff/daniel-guillen/socialcode/app/components/core/SubmitButton.css
new file mode 100644
index 000000000..4452ec3b8
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/SubmitButton.css
@@ -0,0 +1,3 @@
+.SubmitButton {
+ margin: .5rem 0;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/core/SubmitForm.js b/staff/daniel-guillen/socialcode/app/components/core/SubmitForm.js
new file mode 100644
index 000000000..6cfc25781
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/core/SubmitForm.js
@@ -0,0 +1,10 @@
+class SubmitButton extends Button {
+ constructor(text) {
+ super()
+
+ this.addClass('SubmitButton')
+
+ this.setType('submit')
+ this.setText(text)
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/library/FormWithFeedback.css b/staff/daniel-guillen/socialcode/app/components/library/FormWithFeedback.css
new file mode 100644
index 000000000..0e7015959
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/library/FormWithFeedback.css
@@ -0,0 +1,11 @@
+.FormWithFeedback {
+ padding: 1rem;
+}
+
+.FormWithFeedback .Feedback {
+ color: tomato;
+}
+
+.FormWithFeedback .Feedback.success {
+ color: greenyellow;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/components/library/FormWithFeedback.js b/staff/daniel-guillen/socialcode/app/components/library/FormWithFeedback.js
new file mode 100644
index 000000000..f36bb7f88
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/components/library/FormWithFeedback.js
@@ -0,0 +1,30 @@
+class FormWithFeedback extends Form {
+ constructor() {
+ super()
+
+ this.addClass('FormWithFeedback')
+
+ const feedbackPanel = new Component('p')
+ feedbackPanel.addClass('Feedback')
+
+ this.feedbackPanel = feedbackPanel
+ }
+
+ setFeedback(message, level) {
+ if (level === 'success')
+ this.feedbackPanel.addClass('success')
+
+ this.feedbackPanel.setText(message)
+
+ this.add(this.feedbackPanel)
+ }
+
+ clear() {
+ super.clear()
+
+ this.feedbackPanel.setText('')
+ this.feedbackPanel.removeClass('success')
+
+ this.remove(this.feedbackPanel)
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/data.js b/staff/daniel-guillen/socialcode/app/data.js
new file mode 100644
index 000000000..194c90029
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/data.js
@@ -0,0 +1,53 @@
+const data = {}
+
+data.findUser = callback => {
+ const usersJson = localStorage.users
+
+ if (!usersJson) usersJson = '[]'
+
+ const users = JSON.parse(usersJson)
+
+ const user = users.find(callback)
+
+ return user
+}
+
+data.insertUser = user => {
+ let usersJson = localStorage.users
+
+ if (!usersJson) usersJson = '[]'
+
+ const users = JSON.parse(usersJson)
+
+ users.push(user)
+
+ usersJson = JSON.stringify(users)
+
+ localStorage.users = usersJson
+}
+
+data.findPosts = callback => {
+ const postsJson = localStorage.posts
+
+ if (!postsJson) postsJson = '[]'
+
+ const posts = JSON.parse(postsJson)
+
+ const filtered = posts.filter(callback)
+
+ return filtered
+}
+
+data.insertPost = post => {
+ let postsJson = localStorage.posts
+
+ if (!postsJson) postsJson = '[]'
+
+ const posts = JSON.parse(postsJson)
+
+ posts.push(post)
+
+ postsJson = JSON.stringify(posts)
+
+ localStorage.posts = postsJson
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/errors.js b/staff/daniel-guillen/socialcode/app/errors.js
new file mode 100644
index 000000000..432cf244c
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/errors.js
@@ -0,0 +1,28 @@
+/* La clase `...Error` extiende la clase `Error` en JavaScript y establece su propia propiedad de nombre en
+el nombre del constructor. */
+
+class ContentError extends Error {
+ constructor(message) {
+ super(message)
+
+ //this.name = ContentError.name
+ this.name = this.constructor.name
+ }
+}
+
+
+class MatchError extends Error {
+ constructor(message) {
+ super(message)
+
+ this.name = this.constructor.name
+ }
+}
+
+class DuplicityError extends Error {
+ constructor(message) {
+ super(message)
+
+ this.name = this.constructor.name
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/global.css b/staff/daniel-guillen/socialcode/app/global.css
new file mode 100644
index 000000000..2743e592f
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/global.css
@@ -0,0 +1,17 @@
+
+@import url('https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap');
+
+:root {
+ --first-color: white;
+ --second-color: rgb(28, 27, 27);
+}
+
+* {
+ font-family: "Pixelify Sans";
+ color: var(--first-color);
+}
+
+body {
+ background-color: var(--second-color);
+ margin: 0;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/home/components/CreatePostForm.js b/staff/daniel-guillen/socialcode/app/home/components/CreatePostForm.js
new file mode 100644
index 000000000..ff8016c75
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/home/components/CreatePostForm.js
@@ -0,0 +1,41 @@
+class CreatePostForm extends FormWithFeedback {
+ constructor() {
+ super()
+
+ this.addClass('CreatePostForm')
+
+ const titleField = new Field('title', 'text', 'Title')
+ titleField.setPlaceholder('title')
+
+ const imageField = new Field('image', 'text', 'Image')
+ imageField.setPlaceholder('image')
+
+ const descriptionField = new Field('description', 'text', 'Description')
+ descriptionField.setPlaceholder('description')
+
+ const submitButton = new SubmitButton('Create')
+
+ this.add(titleField)
+ this.add(imageField)
+ this.add(descriptionField)
+ this.add(submitButton)
+ }
+
+ getTitle() {
+ const titleField = this.children[0]
+
+ return titleField.getValue()
+ }
+
+ getImage() {
+ const imageField = this.children[1]
+
+ return imageField.getValue()
+ }
+
+ getDescription() {
+ const descriptionField = this.children[2]
+
+ return descriptionField.getValue()
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/home/components/Post.js b/staff/daniel-guillen/socialcode/app/home/components/Post.js
new file mode 100644
index 000000000..203d9a8e2
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/home/components/Post.js
@@ -0,0 +1,26 @@
+class Post extends Component {
+ constructor(post) {
+ super('article')
+
+ const authorTitle = new Component('p')
+ authorTitle.setText(post.author)
+
+ const postTitle = new Component('h2')
+ postTitle.setText(post.title)
+
+ const postImage = new Image
+ postImage.setUrl(post.image)
+
+ const postDescription = new Component('p')
+ postDescription.setText(post.description)
+
+ const postDate = new Component('time')
+ postDate.setText(post.date)
+
+ this.add(authorTitle)
+ this.add(postTitle)
+ this.add(postImage)
+ this.add(postDescription)
+ this.add(postDate)
+ }
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/home/index.css b/staff/daniel-guillen/socialcode/app/home/index.css
new file mode 100644
index 000000000..94927e6d9
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/home/index.css
@@ -0,0 +1,30 @@
+.View {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: 4rem 2rem;
+}
+
+.Header {
+ display: flex;
+ gap: 1rem;
+ width: 100%;
+ justify-content: right;
+ position: fixed;
+ top: 0;
+ padding: .5rem;
+ box-sizing: border-box;
+ border-bottom: 1px solid var(--first-color);
+ background-color: var(--second-color);
+}
+
+.Footer {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ position: fixed;
+ bottom: 0;
+ padding: .5rem 0;
+ border-top: 1px solid var(--first-color);
+ background-color: var(--second-color);
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/home/index.html b/staff/daniel-guillen/socialcode/app/home/index.html
new file mode 100644
index 000000000..9e170e3e1
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/home/index.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ SOCIAL CODE - Welcome
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/home/index.js b/staff/daniel-guillen/socialcode/app/home/index.js
new file mode 100644
index 000000000..791889b9e
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/home/index.js
@@ -0,0 +1,73 @@
+if (!logic.isUserLoggedIn())
+ location.href = '../login'
+
+const view = new Component(document.body)
+view.addClass('View')
+
+const header = new Component('header')
+header.addClass('Header')
+view.add(header)
+
+const userName = logic.getUserName()
+
+const usernameTitle = new Heading(3)
+usernameTitle.setText(userName)
+header.add(usernameTitle)
+
+const logoutButton = new Button
+logoutButton.setText('Logout')
+
+logoutButton.onClick(() => {
+ logic.logoutUser()
+
+ location.href = '../login'
+})
+
+header.add(logoutButton)
+
+const main = new Component('main')
+view.add(main)
+
+const postList = new Component('section')
+main.add(postList)
+
+const posts = logic.getAllPosts()
+
+posts.forEach(post => {
+ const post2 = new Post(post)
+
+ postList.add(post2)
+})
+const createPostForm = new CreatePostForm
+
+createPostForm.onSubmit(event => {
+ event.preventDefault()
+
+ const title = createPostForm.getTitle()
+ const image = createPostForm.getImage()
+ const description = createPostForm.getDescription()
+
+ try {
+ logic.createPost(title, image, description)
+
+ // TODO dismount create post form from main
+ // TODO refresh post list
+ } catch (error) {
+ if (error instanceof ContentError)
+ createPostForm.setFeedback(error.message + ', please, correct it')
+ else
+ createPostForm.setFeedback('sorry, there was an error, please try again later')
+ }
+})
+
+
+// TODO mount create post form when clicking on plus button
+main.add(createPostForm)
+
+const footer = new Component('footer')
+footer.addClass('Footer')
+view.add(footer)
+
+const addPostButton = new Button
+addPostButton.setText('+')
+footer.add(addPostButton)
diff --git a/staff/daniel-guillen/socialcode/app/logic.js b/staff/daniel-guillen/socialcode/app/logic.js
new file mode 100644
index 000000000..5324c94a8
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/logic.js
@@ -0,0 +1,120 @@
+const logic = {}
+
+/* Estas expresiones regulares se utilizan para la validación en el proceso de
+registro de usuario en el formulario proporcionado. */
+const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+const USERNAME_REGEX = /^[\w-]+$/
+const PASSWORD_REGEX = /^[\w-$%&=\[\]\{\}\<\>\(\)]{4,}$/
+
+const NAME_REGEX = /^[a-zA-Z=\[\]\{\}\<\>\(\)]{1,}$/
+
+/* La función `logic.registerUser` es responsable de registrar un nuevo usuario en el sistema.
+Se necesita completar correctamente campos como `nombre`, `apellido`, `correo electrónico`,
+`nombre de usuario`, `contraseña` y `repetir contraseña`.
+De lo contrario mandara un aviso o error mediante un Feedback dentro del Form */
+logic.registerUser = (name, surname, email, username, password, passwordRepeat) => {
+ if (!NAME_REGEX.test(name))
+ throw new ContentError('Name is not valid ⛔')
+
+ if (!NAME_REGEX.test(surname))
+ throw new ContentError('Surname is not valid ⛔')
+
+ if (!EMAIL_REGEX.test(email))
+ throw new ContentError('Email is not valid ⛔')
+
+ if (!USERNAME_REGEX.test(username))
+ throw new ContentError('Username is not valid ⛔')
+
+ if (!PASSWORD_REGEX.test(password))
+ throw new ContentError('Password is not valid ⛔')
+
+ if (password !== passwordRepeat)
+ throw new MatchError('Passwords don\'t match 😵')
+
+ const user = data.findUser(user => user.email === email || user.username === username)
+
+ if (user)
+ throw new DuplicityError('User already exists ⛔')
+
+ user = {
+ name: name,
+ surname: surname,
+ email: email,
+ username: username,
+ password: password
+ }
+
+ data.insertUser(user)
+}
+
+/* La función `logic.loginUser` es responsable de manejar el proceso de inicio de sesión de un usuario.
+Se necesita completar correctamente dos campos, "nombre de usuario" y "contraseña". Aquí hay un desglose de lo que hace: */
+logic.loginUser = (username, password) => {
+ if (!USERNAME_REGEX.test(username))
+ throw new ContentError('username is not valid ⛔')
+
+ if (!PASSWORD_REGEX.test(password))
+ throw new ContentError('password is not valid ⛔')
+
+ const user = data.findUser(user => user.username === username)
+
+ if (!user)
+ throw new MatchError('user not found 🔎')
+
+ if (user.password !== password)
+ throw new MatchError('wrong password 😵')
+
+ sessionStorage.username = username
+}
+
+/* `logic.isUserLoggedIn = () => !!sessionStorage.username` es una función que verifica si un usuario está
+actualmente conectado. Devuelve "verdadero" si hay un valor almacenado en "sessionStorage.username",
+indicando que un usuario ha iniciado sesión.
+Los dobles signos de exclamación `!!` se utilizan para convertir el valor
+a un booleano, asegurando que la función devuelva "verdadero" si el usuario ha iniciado sesión o "falso"
+si el usuario no ha iniciado sesión. */
+logic.isUserLoggedIn = () => !!sessionStorage.username
+
+/* esta función es responsable de cerrar la sesión de un usuario. Cuando se llama a esta función, se elimina
+la clave `username` del objeto `sessionStorage`, desconectando al usuario eliminando su información de sesión almacenada.
+Esta acción borra los datos de la sesión del usuario, indicando que ya no están conectados. */
+logic.logoutUser = () => delete sessionStorage.username
+
+/* La función `logic.getUserName` recupera el nombre del usuario actualmente conectado. 1º encuentra el objeto de usuario
+en el almacenamiento de datos cuyo nombre de usuario coincide con el nombre de usuario almacenado en el `sessionStorage`.
+Luego, devuelve el nombre de ese usuario. Esta función es útil para mostrar el nombre del usuario que inició sesión
+en la interfaz de usuario o en un lugar determinado de app. */
+logic.getUserName = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ return user.name
+}
+
+/* La función `logic.getAllPosts` recupera todas las publicaciones del almacenamiento de datos.
+Llama a la función `data.findPosts` con una función de devolución de llamada que siempre devuelve verdadero, recupera
+todos los mensajes. Luego, invierte el orden de las publicaciones usando el método "inverso" antes de regresar a ellos.
+Esto garantiza que las publicaciones se muestren en orden cronológico inverso, más recientes primero. */
+logic.getAllPosts = () => {
+ const posts = data.findPosts(() => true)
+
+ return posts.reverse()
+}
+
+/* La función `logic.createPost` es responsable de crear una nueva publicación en el sistema, es necesario tres
+parámetros: `título`, `imagen` y `descripción`. */
+
+logic.createPost = (title, image, description) => {
+ if (typeof title !== 'string' || !title.length || title.length > 50) throw new ContentError('title is not valid ⛔')
+ if (typeof image !== 'string' || !image.startsWith('http')) throw new ContentError('image is not valid ⛔')
+ if (typeof description !== 'string' || !description.length || description.length > 200) throw new ContentError('description is not valid ⛔')
+
+ const post = {
+ author: sessionStorage.username,
+ title,
+ image,
+ description,
+ date: new Date().toISOString()
+ }
+
+ data.insertPost(post)
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/login/LoginForm.js b/staff/daniel-guillen/socialcode/app/login/LoginForm.js
new file mode 100644
index 000000000..c329d9149
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/login/LoginForm.js
@@ -0,0 +1,58 @@
+class LoginForm extends FormWithFeedback {
+ constructor() {
+ super()
+
+ this.addClass('LoginForm')
+
+ const usernameField = new Field('username', 'text', 'Username')
+ usernameField.setPlaceholder('username')
+
+ const passwordField = new Field('password', 'password', 'Password')
+ passwordField.setPlaceholder('password')
+
+ const submitButton = new SubmitButton('Login')
+
+ //const feedbackPanel = new Component('p')
+ //feedbackPanel.addClass('Feedback')
+
+ //this.feedbackPanel = feedbackPanel
+
+ this.add(usernameField)
+ this.add(passwordField)
+ this.add(submitButton)
+ //this.add(this.feedbackPanel)
+ }
+
+ getUsername() {
+ const usernameField = this.children[0]
+
+ return usernameField.getValue()
+ }
+
+ getPassword() {
+ const passwordField = this.children[1]
+
+ return passwordField.getValue()
+ }
+ /* setFeedback(message, level) {
+ //const feedbackPanel = this.children[this.children.length - 1]
+
+ if (level === 'success')
+ feedbackPanel.addClass('success')
+
+ this.feedbackPanel.setText(message)
+
+ this.add(this.feedbackPanel)
+ }
+
+ clear() {
+ super.clear()
+
+ //const feedbackPanel = this.children[this.children.length - 1]
+
+ this.feedbackPanel.setText('')
+ this.feedbackPanel.removeClass('success')
+
+ this.remove(this.feedbackPanel)
+ } */
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/login/index.css b/staff/daniel-guillen/socialcode/app/login/index.css
new file mode 100644
index 000000000..968ff685b
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/login/index.css
@@ -0,0 +1,5 @@
+.View {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/login/index.html b/staff/daniel-guillen/socialcode/app/login/index.html
new file mode 100644
index 000000000..c24516253
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/login/index.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ SOCIAL CODE - Login
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/login/index.js b/staff/daniel-guillen/socialcode/app/login/index.js
new file mode 100644
index 000000000..d101146c3
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/login/index.js
@@ -0,0 +1,53 @@
+if (logic.isUserLoggedIn())
+ location.href = '../home'
+
+const view = new Component(document.body)
+view.addClass('View')
+
+const title = new Heading(1)
+title.setText('Welcome - Login')
+
+/* Cuando se envía el formulario, se recupera el nombre de usuario y la contraseña ingresados en los campos del loginForm,
+se inicia sesión con usuario utilizando la función `logic.loginUser` si las credenciales proporcionadas son correctas.
+Si los datos introducidos en los campos no son validos se lanzan avisos o errores mediante Feedback dentro de Form */
+const loginForm = new LoginForm
+loginForm.onSubmit(event => {
+ event.preventDefault()
+
+ const username = loginForm.getUsername()
+ const password = loginForm.getPassword()
+
+ try {
+ logic.loginUser(username, password)
+
+ loginForm.clear()
+
+ loginForm.setFeedback('User successfully logged in 🎉', 'success')
+
+ setTimeout(() => location.href = '../home', 1000)
+ } catch (error) {
+ if (error instanceof ContentError){
+ loginForm.setFeedback(error.message + ', please, correct it 👌')
+ }
+ else if (error instanceof MatchError){
+ loginForm.setFeedback('wrong credentials 😵')
+ }
+ else{
+ loginForm.setFeedback('😵 Sorry, there was an error, please try again later ⏳')
+ }
+ //setTimeout(() => loginForm.setFeedback(""), 4000,)
+ }
+})
+
+
+const registerLink = new Link
+registerLink.setText('Register')
+registerLink.onClick(event => {
+ event.preventDefault()
+
+ setTimeout(() => location.href = '../register', 500)
+})
+
+view.add(title)
+view.add(loginForm)
+view.add(registerLink)
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/register/RegisterForm.js b/staff/daniel-guillen/socialcode/app/register/RegisterForm.js
new file mode 100644
index 000000000..033dcc803
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/register/RegisterForm.js
@@ -0,0 +1,102 @@
+/* Este fragmento de código define una class llamada "RegisterForm" que extiende "FormWithFeedback". Adentro
+el constructor de `RegisterForm`, inicializa varios campos del formulario como nombre, apellido, correo electrónico,
+nombre de usuario, contraseña y repetir contraseña utilizando la class `Field`. A cada Field se le asigna un tipo,
+etiqueta y valor de marcador de posición. Además, se crea un botón de envío utilizando `SubmitButton`. */
+class RegisterForm extends FormWithFeedback {
+ constructor() {
+ super()
+
+ this.addClass('RegisterForm')
+
+ const nameField = new Field('name', 'text', 'Name')
+ nameField.setPlaceholder('name')
+
+ const surnameField = new Field('surname', 'text', 'Surname')
+ surnameField.setPlaceholder('surname')
+
+ const emailField = new Field('email', 'email', 'E-mail')
+ emailField.setPlaceholder('name@example.com')
+
+ const usernameField = new Field('username', 'text', 'Username')
+ usernameField.setPlaceholder('username')
+
+ const passwordField = new Field('password', 'password', 'Password')
+ passwordField.setPlaceholder('password')
+
+ const passwordRepeatField = new Field('repassword', 'password', 'Password repeat')
+ passwordRepeatField.setPlaceholder('repeat password')
+
+ const submitButton = new SubmitButton('Register')
+
+ //const feedbackPanel = new Component('p')
+ //feedbackPanel.addClass('Feedback')
+
+ //this.feedbackPanel = feedbackPanel
+
+ this.add(nameField)
+ this.add(surnameField)
+ this.add(emailField)
+ this.add(usernameField)
+ this.add(passwordField)
+ this.add(passwordRepeatField)
+ this.add(submitButton)
+ //this.add(feedbackPanel)
+ }
+
+ getName() {
+ const nameField = this.children[0]
+
+ return nameField.getValue()
+ }
+
+ getSurname() {
+ const surnameField = this.children[1]
+
+ return surnameField.getValue()
+ }
+
+ getEmail() {
+ const emailField = this.children[2]
+
+ return emailField.getValue()
+ }
+
+ getUsername() {
+ const usernameField = this.children[3]
+
+ return usernameField.getValue()
+ }
+
+ getPassword() {
+ const passwordField = this.children[4]
+
+ return passwordField.getValue()
+ }
+
+ getPasswordRepeat() {
+ const passwordFieldRepeat = this.children[5]
+
+ return passwordFieldRepeat.getValue()
+ }
+ /*setFeedback(message, level) {
+ //const feedbackPanel = this.children[this.children.length - 1]
+
+ if (level === 'success')
+ feedbackPanel.addClass('success')
+
+ this.feedbackPanel.setText(message)
+
+ this.add(this.feedbackPanel)
+ }
+
+ clear() {
+ super.clear()
+
+ //const feedbackPanel = this.children[this.children.length - 1]
+
+ this.feedbackPanel.setText('')
+ this.feedbackPanel.removeClass('success')
+
+ this.remove(this.feedbackPanel)
+ } */
+}
diff --git a/staff/daniel-guillen/socialcode/app/register/index.css b/staff/daniel-guillen/socialcode/app/register/index.css
new file mode 100644
index 000000000..968ff685b
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/register/index.css
@@ -0,0 +1,5 @@
+.View {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/register/index.html b/staff/daniel-guillen/socialcode/app/register/index.html
new file mode 100644
index 000000000..3568ca2c1
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/register/index.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ SOCIAL CODE - Register
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/daniel-guillen/socialcode/app/register/index.js b/staff/daniel-guillen/socialcode/app/register/index.js
new file mode 100644
index 000000000..4853ab873
--- /dev/null
+++ b/staff/daniel-guillen/socialcode/app/register/index.js
@@ -0,0 +1,64 @@
+/* Se comprueba si el usuario ya está conectado. Si el usuario ha iniciado sesión, lo redirigirá a la página de 'home'.
+Esta es una práctica común en las aplicaciones web para redirigir automáticamente a los usuarios.
+a una página específica si ya están logueados.*/
+if (logic.isUserLoggedIn())
+ location.href = '../home'
+
+const view = new Component(document.body)
+view.addClass('View')
+
+const title = new Heading(1)
+title.setText('Welcome - Register')
+title.onClick(() => alert('By clicking on this title you wont get anything 😒'))
+
+/* Aqui se maneja el envío de un formulario de registro.
+Cuando se envía el formulario, evita el comportamiento de envío de formulario por defecto,
+se recupera los valores de entrada de los campos del formulario (nombre, apellido, correo electrónico, nombre de usuario, contraseña, contraseñaRepeat)
+para hacer el guardado con la funcion en logic 'registerUser' si son validos se redirige a 'login'
+sino se recibira avisos o errores mediante Feedbacks dentro del Form */
+const registerForm = new RegisterForm
+registerForm.onSubmit(event => {
+ event.preventDefault()
+
+ const name = registerForm.getName()
+ const surname = registerForm.getSurname()
+ const email = registerForm.getEmail()
+ const username = registerForm.getUsername()
+ const password = registerForm.getPassword()
+ const passwordRepeat = registerForm.getPasswordRepeat()
+
+ try {
+ logic.registerUser(name, surname, email, username, password, passwordRepeat)
+
+ registerForm.clear()
+
+ registerForm.setFeedback('user successfully registered 🎉', 'success')
+
+ setTimeout(() => location.href = '../login', 1000)
+ } catch (error) {
+ if (error instanceof ContentError) {
+ registerForm.setFeedback(error.message + ', please, correct it 👌')
+ }
+ else if (error instanceof MatchError) {
+ registerForm.setFeedback(error.message + ', please, retype them 👌')
+ }
+ else if (error instanceof DuplicityError) {
+ registerForm.setFeedback(error.message + ', please, enter new one 👌')
+ }
+ else {
+ registerForm.setFeedback('😵 Sorry, there was an error, please try again later ⏳')
+ }
+ setTimeout(() => registerForm.setFeedback(""), 4000)
+}})
+
+const loginLink = new Link
+loginLink.setText('Login')
+loginLink.onClick(event => {
+ event.preventDefault()
+
+ setTimeout(() => location.href = '../login', 500)
+})
+
+view.add(title)
+view.add(registerForm)
+view.add(loginLink)
\ No newline at end of file