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
+

Hello, {this.state.name}✨!

+ + + + + + + + +
+ } +} + +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 <> +
+ +
+ +
+ +