From e170da46d73980167966bff9b97f08c4a0c05135 Mon Sep 17 00:00:00 2001 From: Javier Romera Claros Date: Fri, 25 Oct 2024 18:49:44 +0200 Subject: [PATCH] implement comments functions; refactor functions #168 --- .../src/components/functional/AddComment.css | 16 ++++ .../src/components/functional/AddComment.jsx | 34 ++++++++ .../src/components/functional/Comment.css | 15 ++++ .../src/components/functional/Comment.jsx | 34 ++++++++ .../src/components/functional/CommentItem.css | 5 -- .../src/components/functional/CommentItem.jsx | 13 --- .../src/components/functional/Comments.css | 4 - .../src/components/functional/Comments.jsx | 63 ++++++++------ .../src/components/functional/Header.jsx | 28 +++--- .../functional/{PostItem.css => Post.css} | 2 +- .../src/components/functional/Post.jsx | 85 +++++++++++++++++++ .../src/components/functional/PostItem.jsx | 62 -------------- .../src/components/functional/PostList.jsx | 53 ------------ .../functional/{PostList.css => Posts.css} | 2 +- .../src/components/functional/Posts.jsx | 84 ++++++++++++++++++ .../src/components/functional/index.js | 10 ++- .../src/components/library/PasswordInput.jsx | 15 ++-- .../unsocial/src/logic/addComment.js | 25 ++++++ .../unsocial/src/logic/createComment.js | 21 ----- .../unsocial/src/logic/createPost.js | 6 +- .../unsocial/src/logic/deletePost.js | 18 +++- .../unsocial/src/logic/getComments.js | 23 +++-- .../unsocial/src/logic/getPosts.js | 2 + .../unsocial/src/logic/helpers/index.js | 5 ++ .../unsocial/src/logic/helpers/validate.js | 49 +++++++++++ .../javier-romera/unsocial/src/logic/index.js | 6 +- .../unsocial/src/logic/isUserLoggedIn.js | 4 +- .../unsocial/src/logic/loginUser.js | 16 ++-- .../unsocial/src/logic/logoutUser.js | 4 +- .../unsocial/src/logic/registerUser.js | 31 ++----- .../unsocial/src/logic/removeComment.js | 24 ++++++ .../unsocial/src/logic/toggleLikePost.js | 4 +- .../unsocial/src/view/CreatePost.jsx | 42 ++++----- .../javier-romera/unsocial/src/view/Home.jsx | 8 +- .../javier-romera/unsocial/src/view/Login.jsx | 50 ++++++----- .../unsocial/src/view/Register.jsx | 62 +++++++------- 36 files changed, 587 insertions(+), 338 deletions(-) create mode 100644 staff/javier-romera/unsocial/src/components/functional/AddComment.css create mode 100644 staff/javier-romera/unsocial/src/components/functional/AddComment.jsx create mode 100644 staff/javier-romera/unsocial/src/components/functional/Comment.css create mode 100644 staff/javier-romera/unsocial/src/components/functional/Comment.jsx delete mode 100644 staff/javier-romera/unsocial/src/components/functional/CommentItem.css delete mode 100644 staff/javier-romera/unsocial/src/components/functional/CommentItem.jsx rename staff/javier-romera/unsocial/src/components/functional/{PostItem.css => Post.css} (98%) create mode 100644 staff/javier-romera/unsocial/src/components/functional/Post.jsx delete mode 100644 staff/javier-romera/unsocial/src/components/functional/PostItem.jsx delete mode 100644 staff/javier-romera/unsocial/src/components/functional/PostList.jsx rename staff/javier-romera/unsocial/src/components/functional/{PostList.css => Posts.css} (97%) create mode 100644 staff/javier-romera/unsocial/src/components/functional/Posts.jsx create mode 100644 staff/javier-romera/unsocial/src/logic/addComment.js delete mode 100644 staff/javier-romera/unsocial/src/logic/createComment.js create mode 100644 staff/javier-romera/unsocial/src/logic/helpers/index.js create mode 100644 staff/javier-romera/unsocial/src/logic/helpers/validate.js create mode 100644 staff/javier-romera/unsocial/src/logic/removeComment.js diff --git a/staff/javier-romera/unsocial/src/components/functional/AddComment.css b/staff/javier-romera/unsocial/src/components/functional/AddComment.css new file mode 100644 index 00000000..ec014074 --- /dev/null +++ b/staff/javier-romera/unsocial/src/components/functional/AddComment.css @@ -0,0 +1,16 @@ +.Form { + gap: 10px; + + .Field { + width: 90%; + } + + textarea { + width: 100%; + } + + .send-button { + width: 75px; + margin: 0; + } +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/AddComment.jsx b/staff/javier-romera/unsocial/src/components/functional/AddComment.jsx new file mode 100644 index 00000000..dc330401 --- /dev/null +++ b/staff/javier-romera/unsocial/src/components/functional/AddComment.jsx @@ -0,0 +1,34 @@ +import { Button, Form, Field } from '../library' + +import logic from '../../logic' + +import './AddComment.css' + +export default ({ postId, onAdded }) => { + const handleSubmit = event => { + event.preventDefault() + + const form = event.target + + const { text: { value: text } } = form + + try { + logic.addComment(postId, text) + + form.reset() + + onAdded() + } catch (error) { + alert(error.message) + console.error(error) + } + } + + return
+ + + + + +
+} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/Comment.css b/staff/javier-romera/unsocial/src/components/functional/Comment.css new file mode 100644 index 00000000..2d20384f --- /dev/null +++ b/staff/javier-romera/unsocial/src/components/functional/Comment.css @@ -0,0 +1,15 @@ +.Comment { + p { + padding-right: 0; + } + + .username-delete { + display: flex; + justify-content: space-between; + } + + .remove-comment { + width: 26px; + border: 0; + } +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/Comment.jsx b/staff/javier-romera/unsocial/src/components/functional/Comment.jsx new file mode 100644 index 00000000..97fe87a2 --- /dev/null +++ b/staff/javier-romera/unsocial/src/components/functional/Comment.jsx @@ -0,0 +1,34 @@ +import { Button } from '../library' + +import logic from '../../logic' + +import getElapsedTime from "../../utils/getElapsedTime" + +import './Comment.css' + +export default ({ postId, comment: { id, author, text, date }, onRemoved }) => { + + const handleRemove = () => { + if (confirm('Delete comment?')) + try { + logic.removeComment(postId, id) + + onRemoved() + } catch (error) { + alert(error.message) + console.error(error) + } + } + + return
  • +
    +
    {author.username}
    + + {logic.getUserId() === author.id && } +
    + +

    {text}

    + + +
  • +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/CommentItem.css b/staff/javier-romera/unsocial/src/components/functional/CommentItem.css deleted file mode 100644 index b1d22b1b..00000000 --- a/staff/javier-romera/unsocial/src/components/functional/CommentItem.css +++ /dev/null @@ -1,5 +0,0 @@ -.CommentItem { - p { - padding-right: 0; - } -} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/CommentItem.jsx b/staff/javier-romera/unsocial/src/components/functional/CommentItem.jsx deleted file mode 100644 index dcd994b6..00000000 --- a/staff/javier-romera/unsocial/src/components/functional/CommentItem.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import getUserUsername from "../../logic/getUserUsername" -import getElapsedTime from "../../utils/getElapsedTime" - -import './CommentItem.css' - -export default props => { - const { id: { author, text, date } } = props - return
  • -
    {getUserUsername(author)}
    -

    {text}

    - -
  • -} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/Comments.css b/staff/javier-romera/unsocial/src/components/functional/Comments.css index 00fa56af..58f0c6c6 100644 --- a/staff/javier-romera/unsocial/src/components/functional/Comments.css +++ b/staff/javier-romera/unsocial/src/components/functional/Comments.css @@ -13,10 +13,6 @@ margin: 1rem 0; } - textarea { - width: 100%; - } - p, time { padding-left: .5rem; diff --git a/staff/javier-romera/unsocial/src/components/functional/Comments.jsx b/staff/javier-romera/unsocial/src/components/functional/Comments.jsx index c5dc1e6f..76e8c4eb 100644 --- a/staff/javier-romera/unsocial/src/components/functional/Comments.jsx +++ b/staff/javier-romera/unsocial/src/components/functional/Comments.jsx @@ -1,20 +1,20 @@ import { Component } from 'react' import { Button, Form } from '../library' +import AddComment from './AddComment' + import './Comments.css' import logic from '../../logic' -import CommentItem from './CommentItem' +import Comment from './Comment' export default class extends Component { constructor(props) { super(props) - const { postId } = props - let comments try { - comments = logic.getComments(postId) + comments = logic.getComments(props.postId) } catch (error) { alert(error.message) console.error(error) @@ -23,31 +23,46 @@ export default class extends Component { this.state = { comments } } - render() { - return
    - -
    { - event.preventDefault() + onAdded = () => { + try { + const comments = logic.getComments(this.props.postId) - try { - logic.createComment(logic.getUserId(), event.target['text-area'].value, this.props.postId) + this.setState({ comments }) - event.target['text-area'].value = "" + this.props.onAdded() + } catch (error) { + alert(error.message) + console.error(error) + } + } - const comments = logic.getComments(this.props.postId) + onRemoved = () => { + try { + const comments = logic.getComments(this.props.postId) - this.setState({ comments }) - } catch (error) { - alert(error.message) + this.setState({ comments }) - console.error(error) - } - }}> - - -
    + this.props.onRemoved() + } catch (error) { + alert(error.message) + console.error(error) + } + } + + render() { + return
    +
      + {this.state.comments.map(comment => + )} +
    +
    } } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/Header.jsx b/staff/javier-romera/unsocial/src/components/functional/Header.jsx index 8e22960f..1bcb1b39 100644 --- a/staff/javier-romera/unsocial/src/components/functional/Header.jsx +++ b/staff/javier-romera/unsocial/src/components/functional/Header.jsx @@ -5,35 +5,35 @@ import { Anchor, Button } from '../library' import logic from '../../logic' export default ({ view, onHomeClick, onLoggedOut }) => { - // let name let username if (logic.isUserLoggedIn()) try { - // name = logic.getUserName() username = logic.getUserUsername() } catch (error) { alert(error.message) console.error(error) } - return
    -

    {view === 'new-post' ? { - event.preventDefault() + const handleHomeClick = event => { + event.preventDefault() + + onHomeClick() + } + + const handleLogout = () => { + logic.logoutUser() - onHomeClick() - }}>laicosnU : "laicosnU"}

    + onLoggedOut() + } + + return
    +

    {view === 'new-post' ? laicosnU : "laicosnU"}

    {logic.isUserLoggedIn() &&

    {username}

    } - {logic.isUserLoggedIn() && } + {logic.isUserLoggedIn() && }
    } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/PostItem.css b/staff/javier-romera/unsocial/src/components/functional/Post.css similarity index 98% rename from staff/javier-romera/unsocial/src/components/functional/PostItem.css rename to staff/javier-romera/unsocial/src/components/functional/Post.css index 519750f6..f5f2dca9 100644 --- a/staff/javier-romera/unsocial/src/components/functional/PostItem.css +++ b/staff/javier-romera/unsocial/src/components/functional/Post.css @@ -1,4 +1,4 @@ -.PostItem { +.Post { .post-header { display: flex; justify-content: space-between; diff --git a/staff/javier-romera/unsocial/src/components/functional/Post.jsx b/staff/javier-romera/unsocial/src/components/functional/Post.jsx new file mode 100644 index 00000000..2ff41f06 --- /dev/null +++ b/staff/javier-romera/unsocial/src/components/functional/Post.jsx @@ -0,0 +1,85 @@ +import { Button } from '../library' +import Comments from './Comments' + +import logic from '../../logic' + +import getElapsedTime from '../../utils/getElapsedTime' + +import { Component } from 'react' + +import './Post.css' + +export default class extends Component { + constructor(props) { + super(props) + + this.state = { view: null } + } + + handleLikeClick = () => { + try { + logic.toggleLikePost(this.props.post.id) + + this.props.onLiked() + } catch (error) { + alert(error.message) + console.error(error) + } + } + + handleDeleteClick = () => { + if (confirm('Are you sure you want to delete this post?')) { + logic.deletePost(this.props.post.id) + + this.props.onDeleted() + } + } + + handleCommentsClick = () => { + this.setState({ view: this.state.view ? null : 'comments' }) + } + + handleViewCommentsShow = () => { + this.setState({ view: 'comments' }) + } + + handleViewCommentsHide = () => { + this.setState({ view: null }) + } + + render() { + const { post: { id, author, image, text, date, liked, likedBy, comments }, onCommentAdded, onCommentRemoved, } = this.props + + return
    +
    +

    {author.username}

    + + {logic.getUserId() === author.id && } +
    + + + +
    + + + {likedBy.length} + + + {comments} +
    + +

    {text}

    + + {this.state.view === 'comments' && } + + {this.state.view === 'comments' &&

    Hide comments

    } + + {this.state.view !== 'comments' &&

    View comments...

    } + + +
    + } +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/PostItem.jsx b/staff/javier-romera/unsocial/src/components/functional/PostItem.jsx deleted file mode 100644 index 9261db82..00000000 --- a/staff/javier-romera/unsocial/src/components/functional/PostItem.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import { Button } from '../library' - -import logic from '../../logic' - -import './PostItem.css' -import getElapsedTime from '../../utils/getElapsedTime' -import { Component } from 'react' -import Comments from './Comments' -import getComments from '../../logic/getComments' - -export default class extends Component { - constructor(props) { - super(props) - - this.state = { view: null } - } - - render() { - const { item: { id, author, image, text, date, liked, likedBy }, onLikeClicked, onDeletedPost, } = this.props - - return
    -
    -

    {author.username}

    - - {logic.getUserId() === author.id && } -
    - - - -
    - - - {likedBy.length} - - -
    - -

    {text}

    - - {this.state.view === 'comments' && } - - {this.state.view !== 'comments' &&

    { - this.setState({ view: 'comments' }) - }}>View comments...

    } - - -
    - } -} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/PostList.jsx b/staff/javier-romera/unsocial/src/components/functional/PostList.jsx deleted file mode 100644 index f5e1a302..00000000 --- a/staff/javier-romera/unsocial/src/components/functional/PostList.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Component } from 'react' - -import './PostList.css' - -import logic from '../../logic' - -import PostItem from './PostItem' - -export default class extends Component { - constructor(props) { - super(props) - - let posts - - try { - posts = logic.getPosts() - } catch (error) { - alert(error.message) - console.error(error) - } - - this.state = { posts } - } - - render() { - return
    - {this.state.posts.map(post => { - try { - const posts = logic.getPosts() - - this.setState({ posts }) - } catch (error) { - alert(error.message) - - console.error(error) - } - }} - - onLikeClicked={() => { - try { - const posts = logic.getPosts() - - this.setState({ posts }) - } catch (error) { - alert(error.message) - - console.error(error) - } - }} />)} -
    - } -} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/PostList.css b/staff/javier-romera/unsocial/src/components/functional/Posts.css similarity index 97% rename from staff/javier-romera/unsocial/src/components/functional/PostList.css rename to staff/javier-romera/unsocial/src/components/functional/Posts.css index 212a626f..4f177eb6 100644 --- a/staff/javier-romera/unsocial/src/components/functional/PostList.css +++ b/staff/javier-romera/unsocial/src/components/functional/Posts.css @@ -1,4 +1,4 @@ -.PostList { +.Posts { background-color: var(--back-color); display: flex; flex-direction: column; diff --git a/staff/javier-romera/unsocial/src/components/functional/Posts.jsx b/staff/javier-romera/unsocial/src/components/functional/Posts.jsx new file mode 100644 index 00000000..2c25f291 --- /dev/null +++ b/staff/javier-romera/unsocial/src/components/functional/Posts.jsx @@ -0,0 +1,84 @@ +import { Component } from 'react' + +import logic from '../../logic' + +import Post from './Post' + +import './Posts.css' + +export default class extends Component { + constructor(props) { + super(props) + + let posts + + try { + posts = logic.getPosts() + } catch (error) { + alert(error.message) + console.error(error) + } + + this.state = { posts } + } + + handleLiked = () => { + try { + const posts = logic.getPosts() + + this.setState({ posts }) + } catch (error) { + alert(error.message) + console.error(error) + } + } + + handleDeleted = () => { + try { + const posts = logic.getPosts() + + this.setState({ posts }) + } catch (error) { + alert(error.message) + console.error(error) + } + } + + handleCommentAdded = () => { + try { + const posts = logic.getPosts() + + this.setState({ posts }) + } catch (error) { + alert(error.message) + console.error(error) + } + } + + handleCommentRemoved = () => { + try { + const posts = logic.getPosts() + + this.setState({ posts }) + } catch (error) { + alert(error.message) + console.error(error) + } + } + + render() { + return
    + {this.state.posts.map(post => )} +
    + } +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/functional/index.js b/staff/javier-romera/unsocial/src/components/functional/index.js index 28f5867f..fde2c131 100644 --- a/staff/javier-romera/unsocial/src/components/functional/index.js +++ b/staff/javier-romera/unsocial/src/components/functional/index.js @@ -1,13 +1,15 @@ import Header from './Header' import Footer from './Footer' -import PostList from './PostList' -import PostItem from './PostItem' +import Posts from './Posts' +import Post from './Post' import Comments from './Comments' +import Comment from './Comment' export { Header, Footer, - PostList, - PostItem, + Posts, + Post, Comments, + Comment, } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/components/library/PasswordInput.jsx b/staff/javier-romera/unsocial/src/components/library/PasswordInput.jsx index 017ab2d2..f4705a88 100644 --- a/staff/javier-romera/unsocial/src/components/library/PasswordInput.jsx +++ b/staff/javier-romera/unsocial/src/components/library/PasswordInput.jsx @@ -1,5 +1,7 @@ import { Component } from 'react' +import Input from './Input' + export default class extends Component { constructor(props) { super(props) @@ -7,14 +9,15 @@ export default class extends Component { this.state = { type: 'password', status: '🔐' } } + handleToggleClick = () => this.setState({ + status: this.state.status === '😌' ? '😳' : '😌', + type: this.state.type === 'password' ? 'text' : 'password' + }) + render() { return
    - - this.setState({ - type: this.state.type === 'password' ? 'text' : 'password', - status: this.state.status === '🔐' ? '🔓' : '🔐' - })}> + + {this.state.status}
    diff --git a/staff/javier-romera/unsocial/src/logic/addComment.js b/staff/javier-romera/unsocial/src/logic/addComment.js new file mode 100644 index 00000000..9b12f4c6 --- /dev/null +++ b/staff/javier-romera/unsocial/src/logic/addComment.js @@ -0,0 +1,25 @@ +import { validate } from './helpers' + +import uuid from "../data/uuid" + +export default (postId, text) => { + validate.id(postId, 'postId') + validate.text(text) + if (text.length < 5) throw new Error('Comment is too short') + if (text.length > 100) throw new Error('Comment is too long') + + const posts = JSON.parse(localStorage.posts) + + const post = posts.find(({ id }) => id === postId) + + if (!post) throw new Error('post not found') + + post.comments.push({ + id: uuid(), + author: sessionStorage.loggedInUserId, + text, + date: new Date + }) + + localStorage.posts = JSON.stringify(posts) +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/createComment.js b/staff/javier-romera/unsocial/src/logic/createComment.js deleted file mode 100644 index 7e81097f..00000000 --- a/staff/javier-romera/unsocial/src/logic/createComment.js +++ /dev/null @@ -1,21 +0,0 @@ -import uuid from "../data/uuid" - -export default (loggedUser, text, postId) => { - if (text.length < 6) { throw new Error('Comment is too short') } - const posts = JSON.parse(localStorage.posts) - - const index = posts.findIndex(element => { - return element.id === postId - }) - - const comment = { - id: uuid(), - author: loggedUser, - text: text, - date: new Date - } - - posts[index].comments.push(comment) - - localStorage.posts = JSON.stringify(posts) -} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/createPost.js b/staff/javier-romera/unsocial/src/logic/createPost.js index b60574f1..0a9d8959 100644 --- a/staff/javier-romera/unsocial/src/logic/createPost.js +++ b/staff/javier-romera/unsocial/src/logic/createPost.js @@ -1,8 +1,10 @@ +import { validate } from './helpers' + import uuid from '../data/uuid' export default (image, text) => { - if (typeof image !== 'string') throw new Error('invalid image') - if (typeof text !== 'string') throw new Error('invalid text') + validate.image(image) + validate.text(text) const posts = JSON.parse(localStorage.posts) diff --git a/staff/javier-romera/unsocial/src/logic/deletePost.js b/staff/javier-romera/unsocial/src/logic/deletePost.js index 588fb363..f93d980e 100644 --- a/staff/javier-romera/unsocial/src/logic/deletePost.js +++ b/staff/javier-romera/unsocial/src/logic/deletePost.js @@ -1,9 +1,19 @@ -export default (postId) => { +import { validate } from './helpers' + +export default postId => { + validate.id(postId, 'postId') + const posts = JSON.parse(localStorage.posts) - const index = posts.findIndex(element => { - return element.id === postId - }) + const index = posts.findIndex(({ id }) => id === postId) + + if (index < 0) throw new Error('post not found') + + const post = posts[index] + + const { author } = post + + if (author !== sessionStorage.loggedInUserId) throw new Error('user is not author of post') posts.splice(index, 1) diff --git a/staff/javier-romera/unsocial/src/logic/getComments.js b/staff/javier-romera/unsocial/src/logic/getComments.js index 5a6504fa..2a1c0fce 100644 --- a/staff/javier-romera/unsocial/src/logic/getComments.js +++ b/staff/javier-romera/unsocial/src/logic/getComments.js @@ -1,11 +1,24 @@ -export default (postId) => { +import { validate } from './helpers' + +export default postId => { + validate.id(postId, 'postId') + const posts = JSON.parse(localStorage.posts) + const users = JSON.parse(localStorage.users) + + const post = posts.find(({ id }) => id === postId) + + if (!post) throw new Error('post not found') + + const { comments } = post + + comments.forEach(comment => { + const { author: authorId } = comment - const index = posts.findIndex(post => { - return post.id === postId - }) + const { username } = users.find(({ id }) => id === authorId) - const comments = posts[index].comments + comment.author = { id: authorId, username } + }); return comments } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/getPosts.js b/staff/javier-romera/unsocial/src/logic/getPosts.js index cf50b47a..185af4a8 100644 --- a/staff/javier-romera/unsocial/src/logic/getPosts.js +++ b/staff/javier-romera/unsocial/src/logic/getPosts.js @@ -12,6 +12,8 @@ export default () => { post.author = { id: authorId, username } post.liked = post.likedBy.includes(loggedInUserId) + + post.comments = post.comments.length }); return posts.toReversed() diff --git a/staff/javier-romera/unsocial/src/logic/helpers/index.js b/staff/javier-romera/unsocial/src/logic/helpers/index.js new file mode 100644 index 00000000..86321637 --- /dev/null +++ b/staff/javier-romera/unsocial/src/logic/helpers/index.js @@ -0,0 +1,5 @@ +import validate from './validate' + +export { + validate +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/helpers/validate.js b/staff/javier-romera/unsocial/src/logic/helpers/validate.js new file mode 100644 index 00000000..73214b43 --- /dev/null +++ b/staff/javier-romera/unsocial/src/logic/helpers/validate.js @@ -0,0 +1,49 @@ +const validateName = name => { + if (typeof name !== 'string') throw new Error('invalid name') + if (name.length < 2) throw new Error('invalid name length') +} + +const validateEmail = email => { + if (typeof email !== 'string') throw new Error('invalid email') + if (!/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(email)) throw new Error('invalid e-mail') +} + +const validateUsername = username => { + if (typeof username !== 'string') throw new Error('invalid username') + if (username.length < 4 || username.length > 12) throw new Error('invalid username length') +} + +const validatePassword = password => { + if (typeof password !== 'string') throw new Error('invalid password') + if (password.length < 8) throw new Error('invalid password length') +} + +const validatePasswordsMatch = (password, passwordRepeat) => { + if (typeof passwordRepeat !== 'string') throw new Error('invalid password repeat') + if (password !== passwordRepeat) throw new Error('passwords do not match') +} + +const validateImage = image => { + if (typeof image !== 'string') throw new Error('invalid image') +} + +const validateText = text => { + if (typeof text !== 'string') throw new Error('invalid text') +} + +const validateId = (id, explain = 'id') => { + if (typeof id !== 'string') throw new Error(`invalid ${explain}`) +} + +const validate = { + name: validateName, + email: validateEmail, + username: validateUsername, + password: validatePassword, + passwordsMatch: validatePasswordsMatch, + image: validateImage, + text: validateText, + id: validateId +} + +export default validate \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/index.js b/staff/javier-romera/unsocial/src/logic/index.js index 8f8b58f3..248eeac9 100644 --- a/staff/javier-romera/unsocial/src/logic/index.js +++ b/staff/javier-romera/unsocial/src/logic/index.js @@ -12,7 +12,8 @@ import toggleLikePost from './toggleLikePost' import deletePost from './deletePost' import getComments from './getComments' -import createComment from './createComment' +import addComment from './addComment' +import removeComment from './removeComment' const logic = { registerUser, @@ -29,7 +30,8 @@ const logic = { deletePost, getComments, - createComment, + addComment, + removeComment, } export default logic \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/isUserLoggedIn.js b/staff/javier-romera/unsocial/src/logic/isUserLoggedIn.js index bd23957a..24756f19 100644 --- a/staff/javier-romera/unsocial/src/logic/isUserLoggedIn.js +++ b/staff/javier-romera/unsocial/src/logic/isUserLoggedIn.js @@ -1,3 +1 @@ -export default () => { - return sessionStorage.loggedInUserId !== undefined -} \ No newline at end of file +export default () => sessionStorage.loggedInUserId !== undefined \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/loginUser.js b/staff/javier-romera/unsocial/src/logic/loginUser.js index 1e54f6e9..0cc897ab 100644 --- a/staff/javier-romera/unsocial/src/logic/loginUser.js +++ b/staff/javier-romera/unsocial/src/logic/loginUser.js @@ -1,20 +1,14 @@ +import { validate } from './helpers' + export default (username, password) => { - if (typeof username !== 'string') throw new Error('invalid username') - if (username.length < 4 || username.length > 12) { - throw new Error('invalid username length') - } - if (typeof password !== 'string') throw new Error('invalid password') - if (password.length < 8) { - throw new Error('invalid password length') - } + validate.username(username) + validate.password(password) const users = JSON.parse(localStorage.users) const user = users.find(user => user.username === username && user.password === password) - if (user === undefined) { - throw new Error('cagaste') - } + if (user === undefined) throw new Error('cagaste') sessionStorage.loggedInUserId = user.id } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/logoutUser.js b/staff/javier-romera/unsocial/src/logic/logoutUser.js index 4f87632f..71bda0f1 100644 --- a/staff/javier-romera/unsocial/src/logic/logoutUser.js +++ b/staff/javier-romera/unsocial/src/logic/logoutUser.js @@ -1,3 +1 @@ -export default () => { - delete sessionStorage.loggedInUserId -} \ No newline at end of file +export default () => delete sessionStorage.loggedInUserId \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/registerUser.js b/staff/javier-romera/unsocial/src/logic/registerUser.js index 7c8c70f1..e7c149e8 100644 --- a/staff/javier-romera/unsocial/src/logic/registerUser.js +++ b/staff/javier-romera/unsocial/src/logic/registerUser.js @@ -1,34 +1,19 @@ +import { validate } from './helpers' + import uuid from '../data/uuid' export default (name, email, username, password, confirmpassword) => { - if (typeof name !== 'string') throw new Error('invalid name') - if (name.length < 2) { - throw new Error('invalid name length') - } - if (typeof email !== 'string') throw new Error('invalid email') - if (!/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(email)) { - throw new Error('invalid e-mail') - } - if (typeof username !== 'string') throw new Error('invalid username') - if (username.length < 4 || username.length > 12) { - throw new Error('invalid username length') - } - if (typeof password !== 'string') throw new Error('invalid password') - if (password.length < 8) { - throw new Error('invalid password length') - } - if (typeof confirmpassword !== 'string') throw new Error('invalid password confirmation') - if (password !== confirmpassword) { // Comprobar que confirm password tiene el mismo valor que password - throw new Error('passwords do not match') - } + validate.name(name) + validate.email(email) + validate.username(username) + validate.password(password) + validate.passwordsMatch(passwordsMatch) const users = JSON.parse(localStorage.users) let user = users.find(user => user.username === username || user.email === email) - if (user !== undefined) { - throw new Error('user already exists') - } + if (user !== undefined) throw new Error('user already exists') user = { id: uuid(), name: name, email: email, username: username, password: password } diff --git a/staff/javier-romera/unsocial/src/logic/removeComment.js b/staff/javier-romera/unsocial/src/logic/removeComment.js new file mode 100644 index 00000000..d4c3e7d1 --- /dev/null +++ b/staff/javier-romera/unsocial/src/logic/removeComment.js @@ -0,0 +1,24 @@ +import { validate } from './helpers' + +export default (postId, commentId) => { + validate.id(postId, 'postId') + validate.id(commentId, 'commentId') + + const posts = JSON.parse(localStorage.posts) + + const post = posts.find(({ id }) => id === postId) + + const { comments } = post + + const index = comments.findIndex(({ id }) => id === commentId) + + if (index < 0) throw new Error('comment not found') + + const { author } = comments[index] + + if (author !== sessionStorage.loggedInUserId) throw new Error('user is not author of comment') + + comments.splice(index, 1) + + localStorage.posts = JSON.stringify(posts) +} \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/logic/toggleLikePost.js b/staff/javier-romera/unsocial/src/logic/toggleLikePost.js index 624cf12d..17340fff 100644 --- a/staff/javier-romera/unsocial/src/logic/toggleLikePost.js +++ b/staff/javier-romera/unsocial/src/logic/toggleLikePost.js @@ -1,5 +1,7 @@ +import { validate } from './helpers' + export default (postId) => { - if (typeof postId !== 'string') throw new Error('invalid postId') + validate.id(postId, 'postId') const posts = JSON.parse(localStorage.posts) diff --git a/staff/javier-romera/unsocial/src/view/CreatePost.jsx b/staff/javier-romera/unsocial/src/view/CreatePost.jsx index 3d87908d..60c244f9 100644 --- a/staff/javier-romera/unsocial/src/view/CreatePost.jsx +++ b/staff/javier-romera/unsocial/src/view/CreatePost.jsx @@ -1,32 +1,34 @@ -import './CreatePost.css' - import logic from '../logic' import { Form, Field, Label, Input, Button } from '../components/library' +import './CreatePost.css' + export default ({ onCreated }) => { - return
    -

    Create Post

    + const handleSubmit = event => { + event.preventDefault() + + const { target: form } = event -
    { - event.preventDefault() + const { + image: { value: image }, + text: { value: text } + } = form - const { target: form } = event + try { + logic.createPost(image, text) - const { - image: { value: image }, - text: { value: text } - } = form + onCreated() + } catch (error) { + alert(error.message) + console.error(error) + } + } - try { - logic.createPost(image, text) + return
    +

    Create Post

    - onCreated() - } catch (error) { - alert(error.message) - console.error(error) - } - }}> + @@ -39,5 +41,5 @@ export default ({ onCreated }) => { -
    + } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/view/Home.jsx b/staff/javier-romera/unsocial/src/view/Home.jsx index d711f013..b5fdc3b8 100644 --- a/staff/javier-romera/unsocial/src/view/Home.jsx +++ b/staff/javier-romera/unsocial/src/view/Home.jsx @@ -1,8 +1,8 @@ -import './Home.css' - import { Component } from 'react' -import { PostList } from '../components/functional' +import { Posts } from '../components/functional' + +import './Home.css' export default class extends Component { constructor(props) { @@ -12,7 +12,7 @@ export default class extends Component { } render() { return
    - {this.state.view === 'list' && } + {this.state.view === 'list' && }
    } } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/view/Login.jsx b/staff/javier-romera/unsocial/src/view/Login.jsx index ce2d62a2..37e74ae2 100644 --- a/staff/javier-romera/unsocial/src/view/Login.jsx +++ b/staff/javier-romera/unsocial/src/view/Login.jsx @@ -1,30 +1,38 @@ -import './Login.css' - import logic from '../logic' import { Anchor, Form, Label, Input, Field, Button } from '../components/library' -export default (props) => { - return
    -

    Login

    +import './Login.css' + +export default props => { + const handleSubmit = event => { + event.preventDefault() -
    { - event.preventDefault() + const { target: { username: { value: username }, password: { value: password } } } = event - const { target: { username: { value: username }, password: { value: password } } } = event + try { + logic.loginUser(username, password) - try { - logic.loginUser(username, password) + event.target.reset() - event.target.reset() + props.onLoggedIn() + } catch (error) { + alert(error.message) + console.error(error) + event.target.password.value = "" + } + } - props.onLoggedIn() - } catch (error) { - alert(error.message) - console.error(error) - event.target.password.value = "" - } - }}> + const handleRegisterClick = event => { + event.preventDefault() + + props.onRegisterClick() + } + + return
    +

    Login

    + + @@ -37,10 +45,6 @@ export default (props) => { - { - event.preventDefault() - - props.onRegisterClick() - }}>Register + Register
    } \ No newline at end of file diff --git a/staff/javier-romera/unsocial/src/view/Register.jsx b/staff/javier-romera/unsocial/src/view/Register.jsx index 51bb0074..699c7d68 100644 --- a/staff/javier-romera/unsocial/src/view/Register.jsx +++ b/staff/javier-romera/unsocial/src/view/Register.jsx @@ -1,37 +1,45 @@ -import './Register.css' - import logic from '../logic' import { Anchor, Form, Label, Input, Field, Button } from '../components/library' -export default (props) => { - return
    -

    Register

    +import './Register.css' + +export default props => { + const handleSubmit = event => { + event.preventDefault() -
    { - event.preventDefault() + const { target: form } = event - const { target: form } = event + const { + name: { value: name }, + email: { value: email }, + username: { value: username }, + password: { value: password }, + passwordRepeat: { value: passwordRepeat } + } = form - const { - name: { value: name }, - email: { value: email }, - username: { value: username }, - password: { value: password }, - passwordRepeat: { value: passwordRepeat } - } = form + try { + logic.registerUser(name, email, username, password, passwordRepeat) - try { - logic.registerUser(name, email, username, password, passwordRepeat) + form.reset() - form.reset() + props.onRegistered() + } catch (error) { + alert(error.message) + console.error(error) + } + } - props.onRegistered() - } catch (error) { - alert(error.message) - console.error(error) - } - }}> + const handleLoginClick = event => { + event.preventDefault() + + props.onLoginClick() + } + + return
    +

    Register

    + + @@ -59,10 +67,6 @@ export default (props) => { - { - event.preventDefault() - - props.onLoginClick() - }}>Login + Login
    } \ No newline at end of file