diff --git a/packages/concordia-app/public/locales/en/translation.json b/packages/concordia-app/public/locales/en/translation.json index 341d528..803805b 100644 --- a/packages/concordia-app/public/locales/en/translation.json +++ b/packages/concordia-app/public/locales/en/translation.json @@ -2,6 +2,9 @@ "board.header.no.topics.message": "There are no topics yet!", "board.sub.header.no.topics.guest": "Sign up and be the first to post.", "board.sub.header.no.topics.user": "Be the first to post.", + "post.create.form.send.button": "Post", + "post.form.content.field.placeholder": "Message", + "post.form.subject.field.placeholder": "Subject", "post.list.row.author.pre": "Post by", "post.list.row.post.id": "#{{id}}", "register.card.header": "Sign Up", diff --git a/packages/concordia-app/src/components/PostCreate/index.jsx b/packages/concordia-app/src/components/PostCreate/index.jsx new file mode 100644 index 0000000..124696c --- /dev/null +++ b/packages/concordia-app/src/components/PostCreate/index.jsx @@ -0,0 +1,159 @@ +import React, { + memo, useCallback, useEffect, useState, +} from 'react'; +import { + Button, Feed, Form, Icon, Image, Input, TextArea, +} from 'semantic-ui-react'; +import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import determineKVAddress from '../../utils/orbitUtils'; +import { USER_DATABASE } from '../../constants/OrbitDatabases'; +import { FETCH_USER_DATABASE } from '../../redux/actions/peerDbReplicationActions'; +import { USER_PROFILE_PICTURE } from '../../constants/UserDatabaseKeys'; +import { breeze } from '../../redux/store'; +import './styles.css'; + +const { orbit } = breeze; + +const PostCreate = (props) => { + const { id: postId, initialPostSubject } = props; + const [postSubject, setPostSubject] = useState(initialPostSubject); + const [postContent, setPostContent] = useState(''); + const [userProfilePictureUrl, setUserProfilePictureUrl] = useState(); + const [posting, setPosting] = useState(false); + const userAddress = useSelector((state) => state.user.address); + const users = useSelector((state) => state.orbitData.users); + const dispatch = useDispatch(); + const { t } = useTranslation(); + + useEffect(() => { + if (userAddress) { + determineKVAddress({ orbit, dbName: USER_DATABASE, userAddress }) + .then((userOrbitAddress) => { + const userFound = users + .find((user) => user.id === userOrbitAddress); + + if (userFound) { + setUserProfilePictureUrl(userFound[USER_PROFILE_PICTURE]); + } else { + dispatch({ + type: FETCH_USER_DATABASE, + orbit, + dbName: USER_DATABASE, + userAddress, + }); + } + }) + .catch((error) => { + console.error('Error during determination of key-value DB address:', error); + }); + } + }, [dispatch, userAddress, users]); + + const handleInputChange = useCallback((event) => { + if (posting) { + return; + } + + switch (event.target.name) { + case 'postSubject': + setPostSubject(event.target.value); + break; + case 'postContent': + setPostContent(event.target.value); + break; + default: + break; + } + }, [posting]); + + const savePost = useCallback(() => { + if (postSubject === '' || postContent === '') { + return; + } + + setPosting(true); + }, [postContent, postSubject]); + + return ( + + + + {userProfilePictureUrl + ? ( + + ) + : ( + + )} + + + + + + + {t('post.list.row.post.id', { id: postId })} + + + + + + + + + + + + + + {t('post.create.form.send.button')} + + + + + + + + + + + ); +}; + +PostCreate.propTypes = { + id: PropTypes.number.isRequired, + initialPostSubject: PropTypes.string.isRequired, +}; + +export default memo(PostCreate); diff --git a/packages/concordia-app/src/components/PostCreate/styles.css b/packages/concordia-app/src/components/PostCreate/styles.css new file mode 100644 index 0000000..3006cee --- /dev/null +++ b/packages/concordia-app/src/components/PostCreate/styles.css @@ -0,0 +1,17 @@ +.post-profile-picture { + margin: 5px 0 0 0; +} + +.post-summary-meta-index { + float: right; + font-size: 12px; + opacity: 0.4; +} + +.post-summary-meta-date { + float: right !important; +} + +.subject-input { + min-width: 300px; +} diff --git a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx index 374d55a..0fff102 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx @@ -26,7 +26,7 @@ const PostListRow = (props) => { const [postAuthor, setPostAuthor] = useState(null); const [timeAgo, setTimeAgo] = useState(null); const [postSubject, setPostSubject] = useState(null); - const [postMessage, setPostMessage] = useState(null); + const [postContent, setPostContent] = useState(null); const [postAuthorMeta, setPostAuthorMeta] = useState(null); const userAddress = useSelector((state) => state.user.address); const posts = useSelector((state) => state.orbitData.posts); @@ -67,7 +67,7 @@ const PostListRow = (props) => { if (postFound) { setPostSubject(postFound[POST_SUBJECT]); - setPostMessage(postFound[POST_CONTENT]); + setPostContent(postFound[POST_CONTENT]); } }, [postId, posts]); @@ -130,11 +130,11 @@ const PostListRow = (props) => { : } - {postMessage} + {postContent} - ), [loading, postAuthor, postAuthorMeta, postId, postMessage, postSubject, t, timeAgo]); + ), [loading, postAuthor, postAuthorMeta, postId, postContent, postSubject, t, timeAgo]); }; PostListRow.defaultProps = { diff --git a/packages/concordia-app/src/index.jsx b/packages/concordia-app/src/index.jsx index 0e89763..4f21227 100644 --- a/packages/concordia-app/src/index.jsx +++ b/packages/concordia-app/src/index.jsx @@ -5,6 +5,7 @@ import App from './App'; import store from './redux/store'; import * as serviceWorker from './utils/serviceWorker'; import LoadingScreen from './components/LoadingScreen'; +import './assets/css/index.css'; render( }> diff --git a/packages/concordia-app/src/layouts/MainLayout/index.jsx b/packages/concordia-app/src/layouts/MainLayout/index.jsx index 6236c70..597ca73 100644 --- a/packages/concordia-app/src/layouts/MainLayout/index.jsx +++ b/packages/concordia-app/src/layouts/MainLayout/index.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import MainLayoutMenu from './MainLayoutMenu'; +import './styles.css'; const MainLayout = (props) => { const { children } = props; diff --git a/packages/concordia-app/src/layouts/MainLayout/styles.css b/packages/concordia-app/src/layouts/MainLayout/styles.css new file mode 100644 index 0000000..042b794 --- /dev/null +++ b/packages/concordia-app/src/layouts/MainLayout/styles.css @@ -0,0 +1,3 @@ +#main-layout { + height: 100%; +} \ No newline at end of file diff --git a/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx b/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx index f3f0ea7..224f11b 100644 --- a/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx +++ b/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx @@ -22,7 +22,7 @@ const TopicCreate = (props) => { const transactionStack = useSelector((state) => state.transactionStack); const transactions = useSelector((state) => state.transactions); const [subjectInput, setSubjectInput] = useState(''); - const [messageInput, setMessageInput] = useState(''); + const [contentInput, setContentInput] = useState(''); const [topicSubjectInputEmptySubmit, setTopicSubjectInputEmptySubmit] = useState(false); const [topicMessageInputEmptySubmit, setTopicMessageInputEmptySubmit] = useState(false); const [createTopicCacheSendStackId, setCreateTopicCacheSendStackId] = useState(''); @@ -40,8 +40,8 @@ const TopicCreate = (props) => { case 'subjectInput': setSubjectInput(event.target.value); break; - case 'messageInput': - setMessageInput(event.target.value); + case 'contentInput': + setContentInput(event.target.value); break; default: break; @@ -75,7 +75,7 @@ const TopicCreate = (props) => { .then(() => postsDb .put(postId, { [POST_SUBJECT]: subjectInput, - [POST_CONTENT]: messageInput, + [POST_CONTENT]: contentInput, }, { pin: true })) .then(() => { history.push(`/topics/${topicId}`); @@ -85,7 +85,7 @@ const TopicCreate = (props) => { }); } } - }, [createTopicCacheSendStackId, history, messageInput, posting, subjectInput, transactionStack, transactions]); + }, [createTopicCacheSendStackId, history, contentInput, posting, subjectInput, transactionStack, transactions]); const validateAndPost = useCallback(() => { if (subjectInput === '') { @@ -93,14 +93,14 @@ const TopicCreate = (props) => { return; } - if (messageInput === '') { + if (contentInput === '') { setTopicMessageInputEmptySubmit(true); return; } setPosting(true); setCreateTopicCacheSendStackId(createTopic.cacheSend(...[], { from: account })); - }, [account, messageInput, subjectInput]); + }, [account, contentInput, subjectInput]); return ( @@ -125,11 +125,11 @@ const TopicCreate = (props) => { { + {topicSubject !== null && postIds !== null && ( + + )} ); }; diff --git a/packages/concordia-app/src/views/Topic/TopicView/styles.css b/packages/concordia-app/src/views/Topic/TopicView/styles.css index 8cd3cd2..a8015fc 100644 --- a/packages/concordia-app/src/views/Topic/TopicView/styles.css +++ b/packages/concordia-app/src/views/Topic/TopicView/styles.css @@ -1,3 +1,11 @@ +#topic-container { + height: 100%; +} + +#topic-grid { + height: 100%; +} + #author-placeholder { width: 150px !important; } @@ -9,4 +17,4 @@ #date-placeholder { width: 150px !important; margin: 0 auto; -} \ No newline at end of file +}