diff --git a/staff/fabian-romero/playground/ponies/app/.DS_Store b/staff/fabian-romero/playground/ponies/app/.DS_Store
index c91c9f306..5008ddfcf 100644
Binary files a/staff/fabian-romero/playground/ponies/app/.DS_Store and b/staff/fabian-romero/playground/ponies/app/.DS_Store differ
diff --git a/staff/fabian-romero/playground/ponies/app/data/index.mjs b/staff/fabian-romero/playground/ponies/app/data/index.mjs
index bd96abdb3..f3a4a2cb2 100644
--- a/staff/fabian-romero/playground/ponies/app/data/index.mjs
+++ b/staff/fabian-romero/playground/ponies/app/data/index.mjs
@@ -5,6 +5,7 @@ import findUser from './findUser.mjs'
import insertPost from './insertPost.mjs'
import insertUser from './insertUser.mjs'
import updatePost from './updatePost.mjs'
+import updateUser from './updateUser.mjs'
const data = {
deletePost,
@@ -13,7 +14,8 @@ const data = {
findUser,
insertPost,
insertUser,
- updatePost
+ updatePost,
+ updateUser
}
export default data
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/data/updateUser.mjs b/staff/fabian-romero/playground/ponies/app/data/updateUser.mjs
new file mode 100644
index 000000000..1c6aea7a5
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/data/updateUser.mjs
@@ -0,0 +1,13 @@
+function updateUser(condition, user) {
+ const users = localStorage.user !== undefined ? JSON.parse(localStorage.users) : []
+
+ const index = users.findIndex(condition)
+
+ if (index > -1) {
+ user.splice(index, 1, user)
+
+ localStorage.users = JSON.stringify(users)
+ }
+}
+
+export default updateUser
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/getAllFavPosts.mjs b/staff/fabian-romero/playground/ponies/app/logic/getAllFavPosts.mjs
new file mode 100644
index 000000000..f5da06342
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/logic/getAllFavPosts.mjs
@@ -0,0 +1,20 @@
+import data from '../data/index.mjs'
+
+const getAllFavPosts = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const posts = data.findPosts(post => user.favs.includes(post.id))
+
+ posts.forEach(post => {
+ post.fav = user.favs.includes(post.id)
+ post.like = post.likes.includes(sessionStorage.username)
+ })
+
+ return posts.reverse()
+
+}
+
+export default getAllFavPosts
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/getAllFollowingUserPost.mjs b/staff/fabian-romero/playground/ponies/app/logic/getAllFollowingUserPost.mjs
new file mode 100644
index 000000000..997b9b48c
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/logic/getAllFollowingUserPost.mjs
@@ -0,0 +1,23 @@
+import data from '../data/index.mjs'
+
+const getAllFollowingUserPosts = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('User not found')
+
+ const posts = data.findPosts(post => user.following.includes(post.author))
+
+ posts.forEach((post) => {
+ post.fav = user.favs.includes(post.id)
+ post.like = post.likes.includes(sessionStorage.username)
+ post.author = {
+ username: post.author,
+ following: user.following.includes(post.author)
+ }
+ })
+
+ return posts.reverse()
+}
+
+export default getAllFollowingUserPosts
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.mjs b/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.mjs
index 3719a5b8e..6e4337c24 100644
--- a/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.mjs
+++ b/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.mjs
@@ -1,7 +1,21 @@
import data from '../data/index.mjs'
const getAllPosts = () => {
- const posts = data.findPosts(post => true)
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const posts = data.findPosts(() => true)
+
+ posts.forEach(post => {
+ post.fav = user.favs.includes(post.id)
+ post.like = post.likes.includes(sessionStorage.username)
+ post.author = {
+ username: post.author,
+ following: user.includes(post.author)
+ }
+ })
return posts.reverse()
}
diff --git a/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.test.mjs b/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.test.mjs
new file mode 100644
index 000000000..b1ebc569b
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/logic/getAllPosts.test.mjs
@@ -0,0 +1,10 @@
+import getAllFavPosts from './getAllFavPosts.mjs'
+
+console.info('TEST getAllFavPosts')
+console.info('CASE get all fav posts from fabito ')
+
+sessionStorage.username = 'fabito'
+
+const favs = getAllFavPosts()
+
+console.log(favs)
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/index.mjs b/staff/fabian-romero/playground/ponies/app/logic/index.mjs
index 154a2acfd..9893b14b5 100644
--- a/staff/fabian-romero/playground/ponies/app/logic/index.mjs
+++ b/staff/fabian-romero/playground/ponies/app/logic/index.mjs
@@ -8,6 +8,9 @@ import toggleLikePost from './toggleLikePost.mjs'
import updatePostCaption from './updatePostCaption.mjs'
import createPost from './creatPost.mjs'
import deletePost from './deletePost.mjs'
+import toggleFavPost from './toggleFavPost.mjs'
+import getAllFavPosts from './getAllFavPosts.mjs'
+import toggleFollowUser from './toggleFollowUser.mjs'
const logic = {
getAllPosts,
@@ -19,7 +22,10 @@ const logic = {
toggleLikePost,
updatePostCaption,
createPost,
- deletePost
+ deletePost,
+ toggleFavPost,
+ getAllFavPosts,
+ toggleFollowUser
}
export default logic
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/registerUser.mjs b/staff/fabian-romero/playground/ponies/app/logic/registerUser.mjs
index 33a8d70bd..69675cb38 100644
--- a/staff/fabian-romero/playground/ponies/app/logic/registerUser.mjs
+++ b/staff/fabian-romero/playground/ponies/app/logic/registerUser.mjs
@@ -36,7 +36,8 @@ const registerUser = (name, surname, email, username, password, passwordRepeat)
surname: surname,
email: email,
username: username,
- password: password
+ password: password,
+ favs: []
}
data.insertUser(user)
diff --git a/staff/fabian-romero/playground/ponies/app/logic/test.html b/staff/fabian-romero/playground/ponies/app/logic/test.html
new file mode 100644
index 000000000..079526ebc
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/logic/test.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ TEST logic
+
+
+
+ TEST logic
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/toggleFavPost.mjs b/staff/fabian-romero/playground/ponies/app/logic/toggleFavPost.mjs
new file mode 100644
index 000000000..b7ed4f862
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/logic/toggleFavPost.mjs
@@ -0,0 +1,26 @@
+import data from '../data/index.mjs'
+
+function toggleFavPost(postId) {
+ if (postId.trim().length === 0) throw new Error('invalid postId')
+
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const post = data.findPost(post => post.id === postId)
+
+ if (post === null)
+ throw new Error('post not found')
+
+ const index = user.fav.indexOf(postId)
+
+ if (index < 0)
+ user.favs.push(postId)
+ else
+ user.favs.splice(index, 1)
+
+ data.updateUser(user => user.username === sessionStorage.username, user)
+}
+
+export default toggleFavPost
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/logic/toggleFollowUser.mjs b/staff/fabian-romero/playground/ponies/app/logic/toggleFollowUser.mjs
new file mode 100644
index 000000000..bef369217
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/logic/toggleFollowUser.mjs
@@ -0,0 +1,27 @@
+import data from '../data/index.mjs'
+
+function toggleFollowUser(username) {
+
+ if (!username.trim().length) throw new Error('Invalid username')
+
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (!user)
+ throw new Error('User not found')
+
+ const following = data.findUser(user => user.username === username)
+
+ if (!following)
+ throw new Error('Following user not found')
+
+ const index = user.following.indexOf(username)
+
+ if (index < 0)
+ user.following.push(username)
+ else
+ user.following.splice(index, 1)
+
+ data.updateUser(user => user.username === sessionStorage.username, user)
+}
+
+export default toggleFollowUser
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/Component.mjs b/staff/fabian-romero/playground/ponies/app/view/Component.mjs
index 764367526..8f1901070 100644
--- a/staff/fabian-romero/playground/ponies/app/view/Component.mjs
+++ b/staff/fabian-romero/playground/ponies/app/view/Component.mjs
@@ -17,6 +17,20 @@ class Component {
this.container.removeChild(child.container)
}
+ has(child) {
+ if (!(child instanceof Component))
+ throw new TypeError('child is not a Component')
+
+ const children = this.container.children
+ for (let i = 0; i < children.length; i++) {
+ const childrenContainer = children[i]
+
+ if (childrenContainer === child.container) return true
+ }
+
+ return false
+ }
+
setText(text) {
if (typeof text !== 'string')
throw new TypeError('text is not a string')
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/component/FavPostList.mjs b/staff/fabian-romero/playground/ponies/app/view/home/component/FavPostList.mjs
new file mode 100644
index 000000000..d8c909281
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/view/home/component/FavPostList.mjs
@@ -0,0 +1,65 @@
+import Component from '../../Component.mjs'
+import Post from './Post.mjs'
+
+import logic from '../../../logic/index.mjs'
+
+class FavPostList extends Component {
+ constructor() {
+ super(document.createElement('section'))
+
+ this.setClassName('post-list')
+ }
+
+ clearPosts() {
+ for (let i = this.container.children.length - 1; i > -1; i--) {
+ const child = this.container.children[i]
+
+ this.container.removeChild(child)
+ }
+ }
+
+ listPosts() {
+ try {
+ const posts = logic.getAllFavPosts()
+
+ const self = this
+
+ posts.forEach(_post => {
+ const post = new Post(_post)
+
+ post.onPostDeleted(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onPostCaptionEdited(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onPostLikeToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onPostFavToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onUserFollowToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ self.add(post)
+ })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+}
+
+export default FavPostList
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/component/FollowingUserPostList.mjs b/staff/fabian-romero/playground/ponies/app/view/home/component/FollowingUserPostList.mjs
new file mode 100644
index 000000000..cb428509b
--- /dev/null
+++ b/staff/fabian-romero/playground/ponies/app/view/home/component/FollowingUserPostList.mjs
@@ -0,0 +1,65 @@
+import Component from '../../Component.mjs'
+import Post from './Post.mjs'
+
+import logic from '../../../logic/index.mjs'
+
+class FollowingUserPostList extends Component {
+ constructor() {
+ super(document.createElement('section'))
+
+ this.setClassName('post-list')
+ }
+
+ clearPosts() {
+ for (let i = this.container.children.length - 1; i > -1; i--) {
+ const child = this.container.children[i]
+
+ this.container.removeChild(child)
+ }
+ }
+
+ listPosts() {
+ try {
+ const posts = logic.getAllFollowingUserPosts()
+
+ const self = this
+
+ posts.forEach(_post => {
+ const post = new Post(_post)
+
+ post.onPostDeleted(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onPostCaptionEdited(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onPostLikeToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onPostFavToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onFollowUserToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ self.add(post)
+ })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+}
+
+export default FollowingUserPostList
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/component/Header.mjs b/staff/fabian-romero/playground/ponies/app/view/home/component/Header.mjs
index 3a4ff77ae..ee74603cc 100644
--- a/staff/fabian-romero/playground/ponies/app/view/home/component/Header.mjs
+++ b/staff/fabian-romero/playground/ponies/app/view/home/component/Header.mjs
@@ -16,13 +16,31 @@ class Header extends Component {
try {
const name = logic.getUserName()
- userName.setText('Hello, ' + name + '!')
+ userName.setText('Hello, ' + name + '!β¨')
} catch (error) {
console.error(error)
alert(error.message)
}
+ const self = this
+
+ const homeButton = new Button
+ homeButton.setText('π ')
+ this.add(homeButton)
+
+ homeButton.onClick(() => self.onHomeClickCallback())
+
+ const followsButton = new Button
+ followsButton.setText('π¦')
+ this.add(followsButton)
+
+ const favsButton = new Button
+ favsButton.setText('π³οΈβπ')
+ this.add(favsButton)
+
+ favsButton.onClick(() => self.onFavsClickCallback())
+
const logoutButton = new Button
logoutButton.setClassName('logout-button')
logoutButton.setText('Logout')
@@ -40,6 +58,14 @@ class Header extends Component {
}
})
}
+
+ onHomeClick(callback) {
+ this.onHomeClickCallback = callback
+ }
+
+ onFavsClick(callback) {
+ this.onHomeClickCallback = callback
+ }
}
export default Header
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/component/Post.mjs b/staff/fabian-romero/playground/ponies/app/view/home/component/Post.mjs
index 4a52fc9b8..9adb3aa3c 100644
--- a/staff/fabian-romero/playground/ponies/app/view/home/component/Post.mjs
+++ b/staff/fabian-romero/playground/ponies/app/view/home/component/Post.mjs
@@ -16,10 +16,32 @@ class Post extends Component {
super(document.createElement('article'))
this.setClassName('post')
+ const top = new Component(document.createElement('div'))
+ top.setClassName('post__top')
+ this.add(top)
+
const postAuthorTitle = new Heading(3)
postAuthorTitle.setClassName('post__author')
- postAuthorTitle.setText(post.author)
- this.add(postAuthorTitle)
+ postAuthorTitle.setText(post.author.username)
+ top.add(postAuthorTitle)
+
+ const self = this
+
+ const followButton = new Button
+ followButton.setText(post.author.following ? 'π¦' : 'π΄')
+ top.add(followButton)
+
+ followButton.onClick(() => {
+ try {
+ logic.toggleFollowUser(post.author.username) // { username: ..., following: true | false }
+
+ self.onUserFollowToggledCallback()
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ })
const postImage = new Image
postImage.setClassName('post__image')
@@ -31,14 +53,12 @@ class Post extends Component {
postCaptionText.setText(post.caption)
this.add(postCaptionText)
- const self = this
-
const postActionButtons = new Component(document.createElement('div'))
postActionButtons.setClassName('post__actions')
this.add(postActionButtons)
const postToggleLikeButton = new Button
- postToggleLikeButton.setText((post.likes.includes(logic.getUserUsername()) ? 'β€οΈ' : 'π€') + ' ' + post.likes.length + ' like' + (post.likes.length === 1 ? '' : 's'))
+ postToggleLikeButton.setText((post.like ? 'β€οΈ' : 'π€') + ' ' + post.likes.length + ' like' + (post.likes.length === 1 ? '' : 's'))
postActionButtons.add(postToggleLikeButton)
postToggleLikeButton.onClick(() => {
@@ -53,9 +73,25 @@ class Post extends Component {
}
})
- if (post.author === logic.getUserUsername()) {
+ const postToggleFavButton = new Button
+ postToggleFavButton.setText(post.fav ? 'π³οΈβπ' : 'π³οΈ')
+ postActionButtons.add(postToggleFavButton)
+
+ postToggleFavButton.onClick(() => {
+ try {
+ logic.toggleFavPost(post.id)
+
+ self.onPostFavToggledCallback()
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ })
+
+ if (post.author.username === logic.getUserUsername()) {
const postDeleteButton = new Button
- postDeleteButton.setText('Delete')
+ postDeleteButton.setText('ποΈ')
postActionButtons.add(postDeleteButton)
postDeleteButton.onClick(() => {
@@ -80,11 +116,16 @@ class Post extends Component {
})
const editButton = new Button
- editButton.setText('Edit')
+ editButton.setText('π')
postActionButtons.add(editButton)
+ let editCaptionForm
+
editButton.onClick(() => {
- const editCaptionForm = new Form
+ //if (editCaptionForm && self.has(editCaptionForm)) return
+ if (editCaptionForm) return
+
+ editCaptionForm = new Form
self.add(editCaptionForm)
const editCaptionLabel = new Label
@@ -106,7 +147,12 @@ class Post extends Component {
editCaptionCancelButton.setType('button')
editCaptionForm.add(editCaptionCancelButton)
- editCaptionCancelButton.onClick(() => self.remove(editCaptionForm))
+ // editCaptionCancelButton.onClick(() => self.remove(editCaptionForm))
+ editCaptionCancelButton.onClick(() => {
+ self.remove(editCaptionForm)
+
+ editCaptionForm = undefined
+ })
editCaptionForm.onSubmit(event => {
event.preventDefault()
@@ -116,22 +162,18 @@ class Post extends Component {
logic.updatePostCaption(post.id, newCaption)
- //self.container.removeChild(editCaptionForm.container)
self.remove(editCaptionForm)
- // self.clearPosts()
- // self.listPosts()
+ editCaptionForm = undefined
+
self.onPostCaptionEditedCallback()
} catch (error) {
console.error(error)
alert(error.message)
- if (error.message === 'post not found') {
- // self.clearPosts()
- // self.listPosts()
+ if (error.message === 'post not found')
self.onPostCaptionEditedCallback()
- }
}
})
})
@@ -154,6 +196,14 @@ class Post extends Component {
onPostLikeToggled(callback) {
this.onPostLikeToggledCallback = callback
}
+
+ onPostFavToggled(callback) {
+ this.onPostFavToggledCallback = callback
+ }
+
+ onUserFollowToggled(callback) {
+ this.onUserFollowToggledCallback = callback
+ }
}
export default Post
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/component/PostList.mjs b/staff/fabian-romero/playground/ponies/app/view/home/component/PostList.mjs
index 3eb140496..a098f9469 100644
--- a/staff/fabian-romero/playground/ponies/app/view/home/component/PostList.mjs
+++ b/staff/fabian-romero/playground/ponies/app/view/home/component/PostList.mjs
@@ -42,6 +42,16 @@ class PostList extends Component {
self.listPosts()
})
+ post.onPostFavToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
+ post.onUserFollowToggled(() => {
+ self.clearPosts()
+ self.listPosts()
+ })
+
self.add(post)
})
} catch (error) {
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/index.html b/staff/fabian-romero/playground/ponies/app/view/home/index.html
index 5dfc844ae..606180a74 100644
--- a/staff/fabian-romero/playground/ponies/app/view/home/index.html
+++ b/staff/fabian-romero/playground/ponies/app/view/home/index.html
@@ -6,7 +6,9 @@
Home
-
+
+
+
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/index.mjs b/staff/fabian-romero/playground/ponies/app/view/home/index.mjs
index 55975cdc7..334558c3f 100644
--- a/staff/fabian-romero/playground/ponies/app/view/home/index.mjs
+++ b/staff/fabian-romero/playground/ponies/app/view/home/index.mjs
@@ -1,13 +1,60 @@
import Component from '../Component.mjs'
-import Header from './component/Header.mjs'
-import PostList from './component/PostList.mjs'
-import Footer from './component/Footer.mjs'
-
+import Header from './components/Header.mjs'
+import PostList from './components/PostList.mjs'
+import FavPostList from './components/FavPostList.mjs'
+import Footer from './components/Footer.mjs'
+import FollowingUserPostList from './components/FollowingUserPostList.mjs'
const home = new Component(document.body)
const header = new Header
home.add(header)
+header.onHomeClick(() => {
+ if (!body.has(postList)) {
+ if (favPostList && body.has(favPostList))
+ body.remove(favPostList)
+ else if (followingPostList && body.has(followingPostList))
+ body.remove(followingPostList)
+
+ body.add(postList)
+
+ postList.clearPosts()
+ postList.listPosts()
+ }
+})
+
+let favPostList
+
+header.onFavsClick(() => {
+ if (!favPostList || !body.has(favPostList)) {
+ if (body.has(postList))
+ body.remove(postList)
+ else if (followingPostList && body.has(followingPostList))
+ body.remove(followingPostList)
+
+ favPostList = new FavPostList
+ body.add(favPostList)
+
+ favPostList.listPosts()
+ }
+})
+
+let followingPostList
+
+header.onFollowingClick(() => {
+ if (!followingPostList || !body.has(followingPostList)) {
+ if (body.has(postList))
+ body.remove(postList)
+ else if (favPostList && body.has(favPostList))
+ favPostList && body.remove(favPostList)
+
+ followingPostList = new FollowingUserPostList
+ body.add(followingPostList)
+
+ followingPostList.listPosts()
+ }
+})
+
const body = new Component(document.createElement('main'))
body.setClassName('view main')
home.add(body)
@@ -23,4 +70,4 @@ home.add(footer)
footer.onPostCreated(() => {
postList.clearPosts()
postList.listPosts()
-})
+})
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/home/style.css b/staff/fabian-romero/playground/ponies/app/view/home/style.css
index e462ac85f..e6f114f6e 100644
--- a/staff/fabian-romero/playground/ponies/app/view/home/style.css
+++ b/staff/fabian-romero/playground/ponies/app/view/home/style.css
@@ -1,3 +1,9 @@
+body {
+ font-family: Verdana, Geneva, Tahoma, sans-serif;
+
+}
+
+
.view {
display: flex;
flex-direction: column;
@@ -28,23 +34,30 @@
font-size: smaller;
}
+
.post-list {
display: flex;
flex-direction: column;
+ width: 80%;
+ max-width: 500px;
gap: 1rem;
- box-sizing: content-box;
+ box-sizing: border-box;
}
-
-
.post {
- border: 1px solid #9C27B0;
- box-shadow: 0px 1px 4px 2px rgb(249 216)
+ border: 1px solid #d900ff;
+ box-shadow: 3px 2px 6px 2px rgb(249 216)
}
+.post__top {
+ display: flex;
+ margin: 0 .5rem;
+ align-items: center;
+ gap: .5rem;
+}
.post__author {
- margin: .5rem;
+ /*height: .5rem;*/
}
.post__image {
@@ -57,6 +70,8 @@
.post__actions {
margin: .5rem;
+ display: flex;
+ gap: .5rem;
}
.post__time {
@@ -78,10 +93,14 @@
background-color: white;
box-sizing: border-box;
box-shadow: 0px 1px 1px lightgray;
+ /*pride*/
+ background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
}
+
.header__user-name {
- margin: 0;
+ margin: 1px;
+ color: aliceblue;
}
.main {
@@ -99,6 +118,9 @@
background-color: white;
padding: .5rem 0;
box-shadow: 0px -1px 1px lightgray;
+ /*pride*/
+ background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
+
}
.create-post-section {
@@ -124,14 +146,4 @@
display: flex;
justify-content: center;
gap: 1rem;
-}
-
-.heart {
- height: 20px;
- width: 20px;
-}
-
-.heart-button {
- background-color: transparent;
- border: none;
}
\ No newline at end of file
diff --git a/staff/fabian-romero/playground/ponies/app/view/login/index.html b/staff/fabian-romero/playground/ponies/app/view/login/index.html
index 7cee8997f..d79f188ea 100644
--- a/staff/fabian-romero/playground/ponies/app/view/login/index.html
+++ b/staff/fabian-romero/playground/ponies/app/view/login/index.html
@@ -5,6 +5,9 @@
Login
+
+
diff --git a/staff/fabian-romero/playground/ponies/app/view/login/style.css b/staff/fabian-romero/playground/ponies/app/view/login/style.css
index 21eb8b2d9..da0ab628e 100644
--- a/staff/fabian-romero/playground/ponies/app/view/login/style.css
+++ b/staff/fabian-romero/playground/ponies/app/view/login/style.css
@@ -1,3 +1,10 @@
+body {
+ background: #f3d7fa;
+ box-sizing: border-box;
+ height: 100%;
+
+}
+
.view {
display: flex;
flex-direction: column;
diff --git a/staff/fabian-romero/playground/ponies/app/view/register/index.html b/staff/fabian-romero/playground/ponies/app/view/register/index.html
index 6af6048d4..5169e6aff 100644
--- a/staff/fabian-romero/playground/ponies/app/view/register/index.html
+++ b/staff/fabian-romero/playground/ponies/app/view/register/index.html
@@ -5,6 +5,9 @@
Register
+
+
diff --git a/staff/fabian-romero/playground/ponies/app/view/register/style.css b/staff/fabian-romero/playground/ponies/app/view/register/style.css
index 21eb8b2d9..da0ab628e 100644
--- a/staff/fabian-romero/playground/ponies/app/view/register/style.css
+++ b/staff/fabian-romero/playground/ponies/app/view/register/style.css
@@ -1,3 +1,10 @@
+body {
+ background: #f3d7fa;
+ box-sizing: border-box;
+ height: 100%;
+
+}
+
.view {
display: flex;
flex-direction: column;
diff --git a/staff/fabian-romero/react/ponies/app/.DS_Store b/staff/fabian-romero/react/ponies/app/.DS_Store
new file mode 100644
index 000000000..5008ddfcf
Binary files /dev/null and b/staff/fabian-romero/react/ponies/app/.DS_Store differ
diff --git a/staff/fabian-romero/react/ponies/app/data/deletePost.mjs b/staff/fabian-romero/react/ponies/app/data/deletePost.mjs
new file mode 100644
index 000000000..c84dd19fd
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/deletePost.mjs
@@ -0,0 +1,13 @@
+function deletePost(condition) {
+ const posts = localStorage.posts !== undefined ? JSON.parse(localStorage.posts) : []
+
+ const postIndex = posts.findIndex(condition)
+
+ if (postIndex > -1) {
+ posts.splice(postIndex, 1)
+
+ localStorage.posts = JSON.stringify(posts)
+ }
+}
+
+export default deletePost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/findPost.mjs b/staff/fabian-romero/react/ponies/app/data/findPost.mjs
new file mode 100644
index 000000000..d48a190de
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/findPost.mjs
@@ -0,0 +1,9 @@
+function findPost(condition) {
+ const posts = localStorage.posts !== undefined ? JSON.parse(localStorage.posts) : []
+
+ const post = posts.find(condition)
+
+ return post || null
+}
+
+export default findPost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/findPosts.mjs b/staff/fabian-romero/react/ponies/app/data/findPosts.mjs
new file mode 100644
index 000000000..e06dd1e3e
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/findPosts.mjs
@@ -0,0 +1,9 @@
+function findPosts(condition) {
+ const posts = localStorage.posts !== undefined ? JSON.parse(localStorage.posts) : []
+
+ const foundPosts = posts.filter(condition)
+
+ return foundPosts
+}
+
+export default findPosts
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/findUser.mjs b/staff/fabian-romero/react/ponies/app/data/findUser.mjs
new file mode 100644
index 000000000..7b1e9baab
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/findUser.mjs
@@ -0,0 +1,9 @@
+function findUser(condition) {
+ const users = localStorage.users !== undefined ? JSON.parse(localStorage.users) : []
+
+ const user = users.find(condition)
+
+ return user || null
+}
+
+export default findUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/index.mjs b/staff/fabian-romero/react/ponies/app/data/index.mjs
new file mode 100644
index 000000000..f3a4a2cb2
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/index.mjs
@@ -0,0 +1,21 @@
+import deletePost from './deletePost.mjs'
+import findPost from './findPost.mjs'
+import findPosts from './findPosts.mjs'
+import findUser from './findUser.mjs'
+import insertPost from './insertPost.mjs'
+import insertUser from './insertUser.mjs'
+import updatePost from './updatePost.mjs'
+import updateUser from './updateUser.mjs'
+
+const data = {
+ deletePost,
+ findPost,
+ findPosts,
+ findUser,
+ insertPost,
+ insertUser,
+ updatePost,
+ updateUser
+}
+
+export default data
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/insertPost.mjs b/staff/fabian-romero/react/ponies/app/data/insertPost.mjs
new file mode 100644
index 000000000..0a6bc00dc
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/insertPost.mjs
@@ -0,0 +1,9 @@
+function insertPost(post) {
+ const posts = localStorage.posts !== undefined ? JSON.parse(localStorage.posts) : []
+
+ posts.push(post)
+
+ localStorage.posts = JSON.stringify(posts)
+}
+
+export default insertPost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/insertUser.mjs b/staff/fabian-romero/react/ponies/app/data/insertUser.mjs
new file mode 100644
index 000000000..5eb356d3c
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/insertUser.mjs
@@ -0,0 +1,9 @@
+function insertUser(user) {
+ const users = localStorage.users !== undefined ? JSON.parse(localStorage.users) : []
+
+ users.push(user)
+
+ localStorage.users = JSON.stringify(users)
+}
+
+export default insertUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/updatePost.mjs b/staff/fabian-romero/react/ponies/app/data/updatePost.mjs
new file mode 100644
index 000000000..e8fdaa17d
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/updatePost.mjs
@@ -0,0 +1,13 @@
+function updatePost(condition, post) {
+ const posts = localStorage.posts !== undefined ? JSON.parse(localStorage.posts) : []
+
+ const index = posts.findIndex(condition)
+
+ if (index > -1) {
+ posts.splice(index, 1, post)
+
+ localStorage.posts = JSON.stringify(posts)
+ }
+}
+
+export default updatePost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/data/updateUser.mjs b/staff/fabian-romero/react/ponies/app/data/updateUser.mjs
new file mode 100644
index 000000000..bd7a0ca59
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/data/updateUser.mjs
@@ -0,0 +1,13 @@
+function updateUser(condition, user) {
+ const users = localStorage.users !== undefined ? JSON.parse(localStorage.users) : []
+
+ const index = users.findIndex(condition)
+
+ if (index > -1) {
+ users.splice(index, 1, user)
+
+ localStorage.users = JSON.stringify(users)
+ }
+}
+
+export default updateUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/createPost.mjs b/staff/fabian-romero/react/ponies/app/logic/createPost.mjs
new file mode 100644
index 000000000..ff01cfaa4
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/createPost.mjs
@@ -0,0 +1,21 @@
+import data from '../data/index.mjs'
+
+import generateId from '../util/generateId.mjs'
+
+const createPost = (image, caption) => {
+ if (!image.startsWith('http'))
+ throw new Error('invalid image')
+
+ const post = {
+ id: generateId(),
+ image: image,
+ caption: caption,
+ author: sessionStorage.username,
+ date: new Date().toISOString(),
+ likes: []
+ }
+
+ data.insertPost(post)
+}
+
+export default createPost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/deletePost.mjs b/staff/fabian-romero/react/ponies/app/logic/deletePost.mjs
new file mode 100644
index 000000000..77a135435
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/deletePost.mjs
@@ -0,0 +1,13 @@
+import data from '../data/index.mjs'
+
+const deletePost = postId => {
+ if (postId.trim().length === 0) throw new Error('invalid postId')
+
+ const post = data.findPost(post => post.id === postId)
+
+ if (post === null) throw new Error('post not found')
+
+ data.deletePost(post => post.id === postId)
+}
+
+export default deletePost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/getAllFavPosts.mjs b/staff/fabian-romero/react/ponies/app/logic/getAllFavPosts.mjs
new file mode 100644
index 000000000..c417f0832
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/getAllFavPosts.mjs
@@ -0,0 +1,23 @@
+import data from '../data/index.mjs'
+
+const getAllFavPosts = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const posts = data.findPosts(post => user.favs.includes(post.id))
+
+ posts.forEach(post => {
+ post.fav = user.favs.includes(post.id)
+ post.like = post.likes.includes(sessionStorage.username)
+ post.author = {
+ username: post.author,
+ following: user.following.includes(post.author)
+ }
+ })
+
+ return posts.reverse()
+}
+
+export default getAllFavPosts
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/getAllFollowingUserPost.mjs b/staff/fabian-romero/react/ponies/app/logic/getAllFollowingUserPost.mjs
new file mode 100644
index 000000000..ef981f82d
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/getAllFollowingUserPost.mjs
@@ -0,0 +1,23 @@
+import data from '../data/index.mjs'
+
+const getAllFollowingUserPosts = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const posts = data.findPosts(post => user.following.includes(post.author))
+
+ posts.forEach(post => {
+ post.fav = user.favs.includes(post.id)
+ post.like = post.likes.includes(sessionStorage.username)
+ post.author = {
+ username: post.author,
+ following: user.following.includes(post.author)
+ }
+ })
+
+ return posts.reverse()
+}
+
+export default getAllFollowingUserPosts
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/getAllPosts.mjs b/staff/fabian-romero/react/ponies/app/logic/getAllPosts.mjs
new file mode 100644
index 000000000..35145714e
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/getAllPosts.mjs
@@ -0,0 +1,23 @@
+import data from '../data/index.mjs'
+
+const getAllPosts = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const posts = data.findPosts(() => true)
+
+ posts.forEach(post => {
+ post.fav = user.favs.includes(post.id)
+ post.like = post.likes.includes(sessionStorage.username)
+ post.author = {
+ username: post.author,
+ following: user.following.includes(post.author)
+ }
+ })
+
+ return posts.reverse()
+}
+
+export default getAllPosts
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/getUserName.mjs b/staff/fabian-romero/react/ponies/app/logic/getUserName.mjs
new file mode 100644
index 000000000..11619b67e
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/getUserName.mjs
@@ -0,0 +1,12 @@
+import data from '../data/index.mjs'
+
+const getUserName = () => {
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ return user.name
+}
+
+export default getUserName
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/getUserUsername.mjs b/staff/fabian-romero/react/ponies/app/logic/getUserUsername.mjs
new file mode 100644
index 000000000..8e33b442d
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/getUserUsername.mjs
@@ -0,0 +1,3 @@
+const getUserUsername = () => sessionStorage.username
+
+export default getUserUsername
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/index.mjs b/staff/fabian-romero/react/ponies/app/logic/index.mjs
new file mode 100644
index 000000000..01f7f20f5
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/index.mjs
@@ -0,0 +1,33 @@
+import getAllPosts from './getAllPosts.mjs'
+import getUserName from './getUserName.mjs'
+import getUserUsername from './getUserUsername.mjs'
+import loginUser from './loginUser.mjs'
+import logoutUser from './logoutUser.mjs'
+import registerUser from './registerUser.mjs'
+import toggleLikePost from './toggleLikePost.mjs'
+import updatePostCaption from './updatePostCaption.mjs'
+import createPost from './createPost.mjs'
+import deletePost from './deletePost.mjs'
+import toggleFavPost from './toggleFavPost.mjs'
+import getAllFavPosts from './getAllFavPosts.mjs'
+import toggleFollowUser from './toggleFollowUser.mjs'
+import getAllFollowingUserPosts from './getAllFollowingUserPosts.mjs'
+
+const logic = {
+ getAllPosts,
+ getUserName,
+ getUserUsername,
+ loginUser,
+ logoutUser,
+ registerUser,
+ toggleLikePost,
+ updatePostCaption,
+ createPost,
+ deletePost,
+ toggleFavPost,
+ getAllFavPosts,
+ toggleFollowUser,
+ getAllFollowingUserPosts
+}
+
+export default logic
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/loginUser.mjs b/staff/fabian-romero/react/ponies/app/logic/loginUser.mjs
new file mode 100644
index 000000000..fef8bd485
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/loginUser.mjs
@@ -0,0 +1,21 @@
+import data from '../data/index.mjs'
+
+const loginUser = (username, password) => {
+ if (username.trim().length < 4)
+ throw new Error('invalid username')
+
+ if (password.trim().length < 8)
+ throw new Error('invalid password')
+
+ const user = data.findUser(user => user.username === username)
+
+ if (user === null)
+ throw new Error('username does not exist')
+
+ if (user.password !== password)
+ throw new Error('wrong password')
+
+ sessionStorage.username = username
+}
+
+export default loginUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/logoutUser.mjs b/staff/fabian-romero/react/ponies/app/logic/logoutUser.mjs
new file mode 100644
index 000000000..5aea75604
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/logoutUser.mjs
@@ -0,0 +1,3 @@
+const logoutUser = () => delete sessionStorage.username
+
+export default logoutUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/registerUser.mjs b/staff/fabian-romero/react/ponies/app/logic/registerUser.mjs
new file mode 100644
index 000000000..8dda61596
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/registerUser.mjs
@@ -0,0 +1,47 @@
+import data from '../data/index.mjs'
+
+const EMAIL_REGEX = /^[a-z0-9._]+@[a-z0-9.-]{3,63}\.[a-z]{2,10}$/
+
+const registerUser = (name, surname, email, username, password, passwordRepeat) => {
+ if (name.trim() === '')
+ throw new Error('invalid name')
+
+ if (surname.trim().length < 2)
+ throw new Error('invalid surname')
+
+ if (!EMAIL_REGEX.test(email))
+ throw new Error('invalid email')
+
+ if (username.trim().length < 4)
+ throw new Error('invalid username')
+
+ if (password.trim().length < 8)
+ throw new Error('invalid password')
+
+ if (password !== passwordRepeat)
+ throw new Error('passwords do not match')
+
+ let user = data.findUser(user => user.email === email)
+
+ if (user !== null)
+ throw new Error('email already exists')
+
+ user = data.findUser(user => user.username === username)
+
+ if (user !== null)
+ throw new Error('username already exists')
+
+ user = {
+ name: name,
+ surname: surname,
+ email: email,
+ username: username,
+ password: password,
+ favs: [],
+ following: []
+ }
+
+ data.insertUser(user)
+}
+
+export default registerUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/toggleFavPost.mjs b/staff/fabian-romero/react/ponies/app/logic/toggleFavPost.mjs
new file mode 100644
index 000000000..e015ccc0c
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/toggleFavPost.mjs
@@ -0,0 +1,26 @@
+import data from '../data/index.mjs'
+
+function toggleFavPost(postId) {
+ if (postId.trim().length === 0) throw new Error('invalid postId')
+
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (user === null)
+ throw new Error('user not found')
+
+ const post = data.findPost(post => post.id === postId)
+
+ if (post === null)
+ throw new Error('post not found')
+
+ const index = user.favs.indexOf(postId)
+
+ if (index < 0)
+ user.favs.push(postId)
+ else
+ user.favs.splice(index, 1)
+
+ data.updateUser(user => user.username === sessionStorage.username, user)
+}
+
+export default toggleFavPost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/toggleFollowUser.mjs b/staff/fabian-romero/react/ponies/app/logic/toggleFollowUser.mjs
new file mode 100644
index 000000000..90b2c90a5
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/toggleFollowUser.mjs
@@ -0,0 +1,24 @@
+import data from '../data/index.mjs'
+
+function toggleFollowUser(username) {
+ if (!username.trim().length) throw new Error('invalid username')
+
+ const user = data.findUser(user => user.username === sessionStorage.username)
+
+ if (!user) throw new Error('user not found')
+
+ const following = data.findUser(user => user.username === username)
+
+ if (!following) throw new Error('following user not found')
+
+ const index = user.following.indexOf(username)
+
+ if (index < 0)
+ user.following.push(username)
+ else
+ user.following.splice(index, 1)
+
+ data.updateUser(user => user.username === sessionStorage.username, user)
+}
+
+export default toggleFollowUser
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/toggleLikePost.mjs b/staff/fabian-romero/react/ponies/app/logic/toggleLikePost.mjs
new file mode 100644
index 000000000..5d2974aa1
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/toggleLikePost.mjs
@@ -0,0 +1,21 @@
+import data from '../data/index.mjs'
+
+function toggleLikePost(postId) {
+ if (postId.trim().length === 0) throw new Error('invalid postId')
+
+ const post = data.findPost(post => post.id === postId)
+
+ if (post === null)
+ throw new Error('post not found')
+
+ const index = post.likes.indexOf(sessionStorage.username)
+
+ if (index < 0)
+ post.likes.push(sessionStorage.username)
+ else
+ post.likes.splice(index, 1)
+
+ data.updatePost(post => post.id === postId, post)
+}
+
+export default toggleLikePost
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/logic/updatePostCaption.mjs b/staff/fabian-romero/react/ponies/app/logic/updatePostCaption.mjs
new file mode 100644
index 000000000..06345e3d4
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/logic/updatePostCaption.mjs
@@ -0,0 +1,15 @@
+import data from '../data/index.mjs'
+
+const updatePostCaption = (postId, newCaption) => {
+ if (postId.trim().length === 0) throw new Error('invalid postId')
+
+ const post = data.findPost(post => post.id === postId)
+
+ if (post === null) throw new Error('post not found')
+
+ post.caption = newCaption
+
+ data.updatePost(post => post.id === postId, post)
+}
+
+export default updatePostCaption
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/util/formatTime.mjs b/staff/fabian-romero/react/ponies/app/util/formatTime.mjs
new file mode 100644
index 000000000..a8fef6866
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/util/formatTime.mjs
@@ -0,0 +1,37 @@
+function formatTime(date) {
+ var seconds = Math.round((Date.now() - date.getTime()) / 1000)
+
+ if (seconds < 60)
+ return seconds + ' second' + (seconds === 1 ? '' : 's')
+
+ var minutes = Math.round(seconds / 60)
+
+ if (minutes < 60)
+ return minutes + ' minute' + (minutes === 1 ? '' : 's')
+
+ var hours = Math.round(minutes / 60)
+
+ if (hours < 24)
+ return hours + ' hour' + (hours === 1 ? '' : 's')
+
+ var days = Math.round(hours / 24)
+
+ if (days < 7)
+ return days + ' day' + (days === 1 ? '' : 's')
+
+ var weeks = Math.round(days / 7)
+
+ if (weeks < 4)
+ return weeks + ' week' + (weeks === 1 ? '' : 's')
+
+ var months = Math.round(weeks / 4)
+
+ if (months < 12)
+ return months + ' month' + (months === 1 ? '' : 's')
+
+ var years = Math.round(months / 12)
+
+ return years + ' year' + (years === 1 ? '' : 's')
+}
+
+export default formatTime
diff --git a/staff/fabian-romero/react/ponies/app/util/generateId.mjs b/staff/fabian-romero/react/ponies/app/util/generateId.mjs
new file mode 100644
index 000000000..137ba3c8e
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/util/generateId.mjs
@@ -0,0 +1,9 @@
+function generateId() {
+ var id10 = Math.random().toString().slice(2) + Date.now().toString()
+
+ var id36 = Math.round(+id10 / 1000000000000).toString(36)
+
+ return id36
+}
+
+export default generateId
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/Component.mjs b/staff/fabian-romero/react/ponies/app/view/Component.mjs
new file mode 100644
index 000000000..8f1901070
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/Component.mjs
@@ -0,0 +1,63 @@
+class Component {
+ constructor(container) {
+ this.container = container
+ }
+
+ add(child) {
+ if (!(child instanceof Component))
+ throw new TypeError('child is not a Component')
+
+ this.container.appendChild(child.container)
+ }
+
+ remove(child) {
+ if (!(child instanceof Component))
+ throw new TypeError('child is not a Component')
+
+ this.container.removeChild(child.container)
+ }
+
+ has(child) {
+ if (!(child instanceof Component))
+ throw new TypeError('child is not a Component')
+
+ const children = this.container.children
+ for (let i = 0; i < children.length; i++) {
+ const childrenContainer = children[i]
+
+ if (childrenContainer === child.container) return true
+ }
+
+ return false
+ }
+
+ setText(text) {
+ if (typeof text !== 'string')
+ throw new TypeError('text is not a string')
+
+ this.container.innerText = text
+ }
+
+ setBackgroundColor(color) {
+ if (typeof color !== 'string')
+ throw new TypeError('color is not a string')
+
+ this.container.style.backgroundColor = color
+ }
+
+ setColor(color) {
+ if (typeof color !== 'string')
+ throw new TypeError('color is not a string')
+
+ this.container.style.color = color
+ }
+
+ setClassName(className) {
+ if (typeof className !== 'string')
+ throw new TypeError('className is not a string')
+
+ this.container.className = className
+ }
+}
+
+export default Component
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Button.mjs b/staff/fabian-romero/react/ponies/app/view/components/Button.mjs
new file mode 100644
index 000000000..09515bbb2
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Button.mjs
@@ -0,0 +1,17 @@
+import Component from '../Component.mjs'
+
+class Button extends Component {
+ constructor() {
+ super(document.createElement('button'))
+ }
+
+ onClick(callback) {
+ this.container.onclick = callback
+ }
+
+ setType(type) {
+ this.container.type = type
+ }
+}
+
+export default Button
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Form.mjs b/staff/fabian-romero/react/ponies/app/view/components/Form.mjs
new file mode 100644
index 000000000..3729ed846
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Form.mjs
@@ -0,0 +1,13 @@
+import Component from '../Component.mjs'
+
+class Form extends Component {
+ constructor(selector) {
+ super(selector ? document.querySelector(selector) : document.createElement('form'))
+ }
+
+ onSubmit(callback) {
+ this.container.onsubmit = callback
+ }
+}
+
+export default Form
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Heading.mjs b/staff/fabian-romero/react/ponies/app/view/components/Heading.mjs
new file mode 100644
index 000000000..8a49d242d
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Heading.mjs
@@ -0,0 +1,9 @@
+import Component from '../Component.mjs'
+
+class Heading extends Component {
+ constructor(level) {
+ super(document.createElement(`h${level}`))
+ }
+}
+
+export default Heading
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Image.mjs b/staff/fabian-romero/react/ponies/app/view/components/Image.mjs
new file mode 100644
index 000000000..4a9647a5b
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Image.mjs
@@ -0,0 +1,13 @@
+import Component from '../Component.mjs'
+
+class Image extends Component {
+ constructor() {
+ super(document.createElement('img'))
+ }
+
+ setUrl(url) {
+ this.container.src = url
+ }
+}
+
+export default Image
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Input.mjs b/staff/fabian-romero/react/ponies/app/view/components/Input.mjs
new file mode 100644
index 000000000..70643bf30
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Input.mjs
@@ -0,0 +1,21 @@
+import Component from '../Component.mjs'
+
+class Input extends Component {
+ constructor() {
+ super(document.createElement('input'))
+ }
+
+ setId(id) {
+ this.container.id = id
+ }
+
+ setValue(value) {
+ this.container.value = value
+ }
+
+ getValue() {
+ return this.container.value
+ }
+}
+
+export default Input
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Label.mjs b/staff/fabian-romero/react/ponies/app/view/components/Label.mjs
new file mode 100644
index 000000000..26e69b3f4
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Label.mjs
@@ -0,0 +1,17 @@
+import Component from '../Component.mjs'
+
+class Label extends Component {
+ constructor() {
+ super(document.createElement('label'))
+ }
+
+ setFor(id) {
+ this.container.htmlFor = id
+ }
+
+ getFor() {
+ return this.container.htmlFor
+ }
+}
+
+export default Label
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Link.mjs b/staff/fabian-romero/react/ponies/app/view/components/Link.mjs
new file mode 100644
index 000000000..236c43488
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Link.mjs
@@ -0,0 +1,13 @@
+import Component from '../Component.mjs'
+
+class Link extends Component {
+ constructor(selector) {
+ super(document.querySelector(selector))
+ }
+
+ onClick(callback) {
+ this.container.onclick = callback
+ }
+}
+
+export default Link
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/components/Paragraph.mjs b/staff/fabian-romero/react/ponies/app/view/components/Paragraph.mjs
new file mode 100644
index 000000000..d7065f2df
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/components/Paragraph.mjs
@@ -0,0 +1,9 @@
+import Component from '../Component.mjs'
+
+class Paragraph extends Component {
+ constructor() {
+ super(document.createElement('p'))
+ }
+}
+
+export default Paragraph
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/component/FavPostList.jsx b/staff/fabian-romero/react/ponies/app/view/home/component/FavPostList.jsx
new file mode 100644
index 000000000..911001c3c
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/component/FavPostList.jsx
@@ -0,0 +1,60 @@
+import logic from "../../../logic/index.mjs"
+
+const { Component } = React
+
+import Post from './Post.jsx'
+
+class FavPostList extends Component {
+ constructor() {
+ super()
+
+
+ FavPostList() {
+
+ try {
+ const posts = logic.getAllFavPosts()
+
+ const self = this
+
+ posts.forEach(_post => {
+ const post = new Post(_post)
+
+ post.onPostDeleted(() => {
+ self.clearPost()
+ self.listPost()
+ })
+
+ post.ondPostCaptionEdited(() => {
+ self.clearPost()
+ self.listPost()
+ })
+
+ post.onPostLikeToggled(() => {
+ self.clearPost()
+ self.listPost()
+ })
+
+ post.onPostFavToggled(() => {
+ self.clearPost()
+ self.listPost()
+ })
+
+ self.add(post)
+ })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+ }
+
+ render() {
+ return
+ {this.state.posts.map(post => )}
+
+
+ }
+}
+
+export default FavPostList
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/component/Footer.jsx b/staff/fabian-romero/react/ponies/app/view/home/component/Footer.jsx
new file mode 100644
index 000000000..def3a9ef2
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/component/Footer.jsx
@@ -0,0 +1,81 @@
+import logic from "../../../logic/index.mjs"
+
+const { Component } = React // esto es lo primero que se hace la clase y esta formula
+
+class Footer extends Component {
+ constructor() {
+ console.debug('footer -> constructor')
+ super()
+
+ this.state = { createPostVisible: false }
+ }
+
+ handleCreatePostClick() {
+ console.debug('Footer -> handleCreatePostClick')
+
+ this.setState({ createPostVisible: true }) // como se llegΓ³ a esta conclusion?? // seState provoca una act de este estado y de forma asoncronnai esto repinta... // preguntar mejor
+ }
+
+ handleCancelCreatePostClick() { // cuando y por quΓ© se usan estas cosas ?
+ console.debug('Footer -> handleCancelCreatePostCLick')
+
+ this.setState({ createPostVisible: false }) // cuando se cuando se usa state o el otro?
+ }
+
+ handleCreatePostSubmit(event) { //se crea info en internet para subir un post
+ console.debug('Footer -> handleCreatePostSubmit')
+
+ event.preventDefault()
+
+ const form = event.target
+
+ const postImageInput = form['post-image-input'] // aqui accedemos al input
+ const postCaptionInput = form['post-caption-input']
+
+ const postImage = postImageInput.value // aqui recogemos los valores, usuarios y datos...
+ const postCaption = postCaptionInput.value
+
+ try {
+ logic.createPost(postImage, postCaption)
+
+ this.setState({ createPostVisible: false })
+
+ this.props.onPostCreated() // cuando le pasas una propiedad del padre al hijo.. quieres que la "funcion padre" se entere de los cambios. y esta info se esta renderizando en el index
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ render() {
+ console.debug('Footer -> render')
+
+ return
+ }
+}
+
+export default Footer
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/component/Header.jsx b/staff/fabian-romero/react/ponies/app/view/home/component/Header.jsx
new file mode 100644
index 000000000..bbdbb4286
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/component/Header.jsx
@@ -0,0 +1,54 @@
+import logic from '../../../logic/index.mjs'
+
+const { Component } = React
+
+class Header extends Component {
+ constructor() {
+ console.debug('Header -> constructor')
+
+ super()
+
+ try {
+ const name = logic.getUserName()
+
+ this.state = { name } // guardo aqui el nombre de la persona para que luego en render me lo pinte
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handleLogout() {
+ console.debug('Header -> handleLogout')
+
+ try {
+ logic.logoutUser()
+
+ location.href = '../login'
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ // state.name = es aqui cuando me pinta el nombre del usuario
+ render() {
+ console.debug('Header -> render')
+
+ return
+ }
+}
+
+export default Header
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/component/Post.jsx b/staff/fabian-romero/react/ponies/app/view/home/component/Post.jsx
new file mode 100644
index 000000000..96954298f
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/component/Post.jsx
@@ -0,0 +1,173 @@
+import logic from '../../../logic/index.mjs'
+
+import formatTime from '../../../util/formatTime.mjs'
+
+const { Component } = React
+
+class Post extends Component {
+ constructor() {
+ console.debug('Post -> constructor')
+
+ super()
+
+ this.state = { editPostVisible: false } // esto se hace para crear el estado de si se edita o no
+ }
+
+ handleDeletePostClick() { //aqui va el click porque es el "evento que hace este boton.. un click"
+ if (confirm('Delete post?'))
+ try {
+ logic.deletePost(this.props.post.id)
+
+ this.props.onPostDeleted()
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+
+ componentWillUnmount() {
+ console.debug('post -> componentWillUnmount')
+ //buscar para ue se usa ciclo de vida del componente
+ }
+
+ handleEditPostClick() {
+ console.debug('post -> handleEditPost')
+
+ this.setState({ editPostVisible: true })
+
+ }
+
+ handleCancelEditPostClick() {
+ console.debug('Post -> handleCancelEditPostClick')
+
+ this.setState({ editPostVisible: false })
+ }
+
+ handleEditpostSubmit(event) {
+ console.debug('Post -> handleCancelEditPostClick')
+
+ event.preventDefault()
+
+ const form = event.target
+
+ const editCaptionInput = form['edit-caption-input']
+
+ const newCaption = editCaptionInput.value
+
+ try {
+ logic.updatePostCaption(this.props.post.id, newCaption)
+
+ this.setState({ editPostVisible: false })
+
+ this.props.onPostEdited()
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handleLikePostClick() {
+ console.debug('Post -> handleLikePostClick')
+
+ try {
+ logic.toggleLikePost(this.props.post.id) // aqui esto porque es propuedad de js
+
+ this.props.onPostLiked()
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+
+ }
+
+ handleFavPostClick() {
+ console.debug('Post -> handleFavPostClick')
+
+ try {
+ logic.toggleFavPost(this.props.post.id) // esto viene de la logica de toggle
+
+ this.props.onPostFavorited() // aqui se pone el nombre que le puse en postlistrender
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handleFollowUserClick() {
+ console.debug('Post -> handleFollowUserClick')
+
+ try {
+ logic.toggleFollowUser(this.props.post.author.username) // esta logica es la que adjuntamos del archivo anterior post.js
+
+ this.props.onFollowedUser()
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+
+
+ render() {
+ console.debug('Post -> render')
+
+ const { post } = this.props // para poder acceder a los datos de otro archivo ( en este caso de post list)
+ // falta me canizar los demas botones que se mecanizan en postlist, por eso uso props para traerlos aqui
+
+ return
+
+
{post.author.username}
+
+
+
+
+
+
+
+
+ {post.caption}
+
+
+
+
+
+
+
+
+
+
+ {post.author.username === logic.getUserUsername() && <>
+
+
+
+ >}
+
+
+
+
+
+
+
+
+
+
+
+
+ {this.state.editPostVisible && }
+
+ }
+}
+export default Post
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/component/PostList.jsx b/staff/fabian-romero/react/ponies/app/view/home/component/PostList.jsx
new file mode 100644
index 000000000..86f5c2165
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/component/PostList.jsx
@@ -0,0 +1,118 @@
+import logic from '../../../logic/index.mjs'
+
+const { Component } = React
+
+import Post from './Post.jsx'
+
+class PostList extends Component {
+ constructor() {
+ console.debug('PostList -> contructor')
+
+ super()
+
+ try {
+ const posts = logic.getAllPosts()
+
+ this.state = { posts } // inicializar los post lo llamamos, se contruye y luego en render lo pinta y me devulve todo el DOM
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ componentWillReceiveProps(newProps) {
+ console.debug('PostList -> componentWillReceiveProps', newProps, this.props) // esto es una funcuon que tengo que saber que hace ciclo de vida del componente
+ // react lo llama cuando detecta que cambia un prop
+ //se puede implementar a demanda y me dice que voy a recibir nuevos props (newProps)
+ // new props
+
+ if (newProps.refreshStamp !== this.props.refreshStamp)
+ try {
+ const posts = logic.getAllPosts()
+
+ this.setState({ posts })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handlePostDeleted() {// aqui llamo a la logica de deleted dentro del post list abajo
+ try {
+ const posts = logic.getAllPosts()
+
+ this.setState({ posts })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handlePostEdited() { // aqui llamo a la logica de edited dentro del post list abajo
+ try {
+ const posts = logic.getAllPosts()
+
+ this.setState({ posts })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handlePostLiked() {
+
+ try {
+ const posts = logic.getAllPosts()
+
+ this.setState({ posts })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handlePostFavorited() {
+
+
+ try {
+ const posts = logic.getAllPosts()
+
+ this.setState({ posts })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ handleFollowedUser() {
+
+ try {
+ const posts = logic.getAllPosts() // esta logica es la misma de arriba
+
+ this.setState({ posts })
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+
+
+ render() {
+ console.debug('PostList -> render')
+
+ return
+ {this.state.posts.map(post => )}
+
+ }
+}
+
+export default PostList
diff --git a/staff/fabian-romero/react/ponies/app/view/home/index.html b/staff/fabian-romero/react/ponies/app/view/home/index.html
new file mode 100644
index 000000000..1b7d6a199
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/index.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+ Home Page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/index.jsx b/staff/fabian-romero/react/ponies/app/view/home/index.jsx
new file mode 100644
index 000000000..0bb1d74a3
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/index.jsx
@@ -0,0 +1,40 @@
+import Header from './component/Header'
+import PostList from './component/PostList'
+import Footer from './component/Footer'
+
+const Component = React.Component
+
+class Home extends Component {
+ constructor() {
+ console.debug('Home -> contructor')
+
+ super()
+
+ this.state = { refreshStamp: null }
+ }
+
+ handlePostCreated() {
+ console.debug('Home -> handlePostCreated')
+
+ this.setState({ refreshStamp: Date.now() }) // esto es para que postList se refresque.
+ }
+
+ // siempre tiene que estar contenido en algun contenedor(abajo en el render) si no, no sabe que esta devolviendo
+
+ render() {
+ console.debug('Home -> render')
+
+ return <>
+
+
+
+
+
+
+
+ >
+ }
+}
+
+const root = ReactDOM.createRoot(document.getElementById('root'))
+root.render()
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/home/style.css b/staff/fabian-romero/react/ponies/app/view/home/style.css
new file mode 100644
index 000000000..1b20c56fd
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/home/style.css
@@ -0,0 +1,159 @@
+body {
+ font-family: Verdana, Geneva, Tahoma, sans-serif;
+
+}
+
+
+.view {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ font-size: 1.1rem;
+}
+
+.form {
+ display: flex;
+ flex-direction: column;
+ gap: .5rem;
+ min-width: 80%;
+}
+
+.form__field {
+ display: flex;
+ flex-direction: column;
+ gap: .2rem;
+
+}
+
+.form__input {
+ font-size: inherit;
+}
+
+.form__button {
+ font-size: smaller;
+}
+
+
+.post-list {
+ display: flex;
+ flex-direction: column;
+ width: 85%;
+ max-width: 500px;
+ gap: 1rem;
+ box-sizing: border-box;
+}
+
+.post {
+ border: 1px solid #ffff00;
+ box-shadow: 3px 1px 9px 0px #ff000045;
+}
+
+.post__top {
+ display: flex;
+ margin: 0 .5rem;
+ align-items: center;
+ gap: .5rem;
+}
+
+.post__author {
+ /*height: .5rem;*/
+}
+
+.post__image {
+ width: 100%;
+}
+
+.post__caption {
+ margin: .5rem;
+}
+
+.post__actions {
+ margin: .5rem;
+ display: flex;
+ gap: .5rem;
+}
+
+.post__time {
+ display: block;
+ margin: .5rem;
+ color: silver;
+ font-size: .9rem;
+}
+
+h3 {
+ display: flex;
+ font-size: medium;
+ margin-block-start: 1em;
+ margin-block-end: 1em;
+ margin-inline-start: 4px;
+ margin-inline-end: 4px;
+ font-weight: revert-layer;
+ unicode-bidi: isolate;
+}
+
+button {
+ /* hacer algo con los botones*/
+}
+
+.header {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ display: flex;
+ justify-content: right;
+ align-items: center;
+ gap: 1rem;
+ background-color: white;
+ box-sizing: border-box;
+ box-shadow: 0px 1px 1px lightgray;
+ /*pride*/
+ background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
+}
+
+
+.header__user-name {
+ margin: 1px;
+ color: aliceblue;
+}
+
+.main {
+ margin-top: 3.5rem;
+ margin-bottom: 3rem;
+}
+
+.footer {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ background-color: white;
+ padding: .5rem 0;
+ box-shadow: 0px -1px 1px lightgray;
+ /*pride*/
+ background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet, red);
+
+}
+
+.create-post-section {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ background-color: white;
+ padding: .5rem;
+ box-sizing: border-box;
+}
+
+.create-post-section__title {
+ margin: .5rem 0;
+}
+
+.create-post-section__buttons {
+ display: flex;
+ justify-content: center;
+ gap: 1rem;
+}
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/login/index.html b/staff/fabian-romero/react/ponies/app/view/login/index.html
new file mode 100644
index 000000000..cb11a0d93
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/login/index.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/login/index.jsx b/staff/fabian-romero/react/ponies/app/view/login/index.jsx
new file mode 100644
index 000000000..bf2a96413
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/login/index.jsx
@@ -0,0 +1,62 @@
+import logic from '../../logic/index.mjs'
+
+const Component = React.Component
+
+class Login extends Component {
+ constructor() {
+ super()
+ }
+
+ handleRegisterClick(event) {
+ event.preventDefault()
+
+ location.href = '../register'
+ }
+
+ handleLoginSubmit(event) {
+ event.preventDefault()
+
+ const form = event.target
+
+ const usernameInput = form['username-input']
+ const passwordInput = form['password-input']
+
+ const username = usernameInput.value
+ const password = passwordInput.value
+
+ try {
+ logic.loginUser(username, password)
+
+ location.href = '../home'
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ render() {
+ return
+ Login
+
+
+
+ Register
+
+ }
+}
+
+const root = ReactDOM.createRoot(document.getElementById('root'))
+root.render()
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/login/style.css b/staff/fabian-romero/react/ponies/app/view/login/style.css
new file mode 100644
index 000000000..da0ab628e
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/login/style.css
@@ -0,0 +1,35 @@
+body {
+ background: #f3d7fa;
+ box-sizing: border-box;
+ height: 100%;
+
+}
+
+.view {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ font-size: 1.1rem;
+}
+
+.form {
+ display: flex;
+ flex-direction: column;
+ gap: .5rem;
+ min-width: 80%;
+}
+
+.form__field {
+ display: flex;
+ flex-direction: column;
+ gap: .2rem
+}
+
+.form__input {
+ font-size: inherit;
+}
+
+.form__button {
+ font-size: inherit;
+}
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/register/index.html b/staff/fabian-romero/react/ponies/app/view/register/index.html
new file mode 100644
index 000000000..fe54e12c8
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/register/index.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+ Register
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/register/index.jsx b/staff/fabian-romero/react/ponies/app/view/register/index.jsx
new file mode 100644
index 000000000..b4a021052
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/register/index.jsx
@@ -0,0 +1,100 @@
+import logic from '../../logic/index.mjs'
+
+const Component = React.Component
+
+class Register extends Component {
+ constructor() {
+ super()
+ }
+
+ handleLoginClick(event) {
+ event.preventDefault()// evita que la pagina se recargue y envie informacion
+
+ location.href = '../login'
+ }
+
+ handleRegisterSubmit(event) {
+ event.preventDefault()
+
+ const form = event.target // llega al evento del dom, donde se provova el evento, en este caso DOM es submit. el evento es el formulario
+ // en html es el dom se usan las comillas dobles " "
+
+ const nameInput = form['name-input']
+ const surnameInput = form['surname-input']
+ const emailInput = form['email-input']
+ const usernameInput = form['username-input']
+ const passwordInput = form['password-input']
+ const passwordRepeatInput = form['password-repeat-input']
+
+ // cuando tenemos input que tienen id, es un input que tiene propiedad, como si fuera una propiedad del formulario
+
+ const name = nameInput.value
+ const surname = surnameInput.value
+ const email = emailInput.value
+ const username = usernameInput.value
+ const password = passwordInput.value
+ const passwordRepeat = passwordRepeatInput.value
+
+ //coje el valor de cada input
+
+ try {
+ logic.registerUser(name, surname, email, username, password, passwordRepeat)
+
+ location.href = '../login'
+
+ alert('user successfully registered')
+ } catch (error) {
+ console.error(error)
+
+ alert(error.message)
+ }
+ }
+
+ // verifica si hay errores
+
+ render() { // es pintar, espera que le devuelvas el DOM. la imagne.
+ //las clases son las del css
+ return
+ Register
+
+
+
+ Login
+
+ }
+}
+
+const root = ReactDOM.createRoot(document.getElementById('root'))
+root.render()
\ No newline at end of file
diff --git a/staff/fabian-romero/react/ponies/app/view/register/style.css b/staff/fabian-romero/react/ponies/app/view/register/style.css
new file mode 100644
index 000000000..da0ab628e
--- /dev/null
+++ b/staff/fabian-romero/react/ponies/app/view/register/style.css
@@ -0,0 +1,35 @@
+body {
+ background: #f3d7fa;
+ box-sizing: border-box;
+ height: 100%;
+
+}
+
+.view {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ font-size: 1.1rem;
+}
+
+.form {
+ display: flex;
+ flex-direction: column;
+ gap: .5rem;
+ min-width: 80%;
+}
+
+.form__field {
+ display: flex;
+ flex-direction: column;
+ gap: .2rem
+}
+
+.form__input {
+ font-size: inherit;
+}
+
+.form__button {
+ font-size: inherit;
+}
\ No newline at end of file