From 0f5092d6519ae18504b2b16653298039eec479bd Mon Sep 17 00:00:00 2001 From: Robert Istok Date: Wed, 28 Jun 2017 19:16:42 +0300 Subject: [PATCH] Better component separation --- .../Conversation/elements/Discussion.js | 71 ++------------- .../Messages/Conversation/elements/Message.js | 81 +++++++++++++++++ client/src/components/Messages/index.js | 1 + client/src/components/Schedule/Table/Table.js | 31 +------ .../Schedule/Table/elements/Column.js | 69 ++------------- .../Schedule/Table/elements/InfoColumn.js | 36 ++++++++ .../Schedule/Table/elements/Week.js | 86 +++++++++++++++++++ client/src/components/common/Thread.js | 10 +-- package.json | 5 +- server/models/user.js | 10 +++ yarn.lock | 4 + 11 files changed, 246 insertions(+), 158 deletions(-) create mode 100644 client/src/components/Messages/Conversation/elements/Message.js create mode 100644 client/src/components/Schedule/Table/elements/InfoColumn.js create mode 100644 client/src/components/Schedule/Table/elements/Week.js diff --git a/client/src/components/Messages/Conversation/elements/Discussion.js b/client/src/components/Messages/Conversation/elements/Discussion.js index 9c78012..ab0511b 100644 --- a/client/src/components/Messages/Conversation/elements/Discussion.js +++ b/client/src/components/Messages/Conversation/elements/Discussion.js @@ -2,8 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; -import { formatTime } from '../../../../utils/timestamp'; -import { formatMultiLineText } from '../../../../utils/style-utils'; +import Message from './Message'; const Discussion = (props) => { const { selectedConversation, loggedInUser, fields } = props; @@ -16,30 +15,17 @@ const Discussion = (props) => { p => p._id !== loggedInUser._id ); - const renderMessage = (m) => { - let sender; - if (m.sender === partner._id) { - sender = `${partner.firstname} ${partner.lastname}`; - } else { - sender = 'Me'; - } - - return ( - - - {sender} - {formatTime(m.timestamp, true)} - - {formatMultiLineText(m.text)} - - ); - }; - if (!selectedConversation) return null; return ( - {selectedConversation.messages.map(renderMessage)} + {selectedConversation.messages.map(message => ( + + ))} ); }; @@ -66,45 +52,4 @@ const Wrapper = styled.div` width: 100%; `; -const Info = styled.div` - display: flex; - margin-bottom: 3px; -`; - -const MessageWrapper = styled.div` - display: flex; - flex: none; - flex-direction: column; - justify-content: center; - background-color: e2edff; - align-self: ${props => props.self === true ? 'flex-end' : 'flex-start'} - margin: 10px 20px; - max-width: 80%; -`; - -const Partner = styled.div` - margin-left: 5px; - margin-right: 15px; - font-size: 13px; - color: rgba(0, 0, 0, 0.7); -`; - -const Timestamp = styled.div` - color: rgba(0, 0, 0, .40) - font-size: 11px; - margin-right: 5px; - margin-left: auto; -`; - -const Message = styled.div` - width: 100%; - display: flex; - flex-direction: column; - padding: 5px 10px; - border-radius: 7px; - background-color: ${props => props.self === true ? '#f1f0f0' : props.theme.primary}; - color: ${props => props.self === true ? props.theme.black : props.theme.white}; - justify-content: center; -`; - export default Discussion; diff --git a/client/src/components/Messages/Conversation/elements/Message.js b/client/src/components/Messages/Conversation/elements/Message.js new file mode 100644 index 0000000..18b3f31 --- /dev/null +++ b/client/src/components/Messages/Conversation/elements/Message.js @@ -0,0 +1,81 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; + +import { formatTime } from '../../../../utils/timestamp'; +import { formatMultiLineText } from '../../../../utils/style-utils'; + +const Message = (props) => { + const { partner } = props; + + const sender = props.sender === partner._id + ? `${partner.firstname} ${partner.lastname}` + : 'Me'; + + const selfMessage = sender === 'Me'; + + return ( + + + {sender} + {formatTime(props.timestamp, true)} + + {formatMultiLineText(props.text)} + + ); +}; + +const { string, shape } = PropTypes; +Message.propTypes = { + timestamp: string.isRequired, + partner: shape({ + _id: string.isRequired, + firstname: string.isRequired, + lastname: string.isRequired + }).isRequired, + sender: string.isRequired, + text: string.isRequired +}; + +const Info = styled.div` + display: flex; + margin-bottom: 3px; +`; + +const Wrapper = styled.div` + display: flex; + flex: none; + flex-direction: column; + justify-content: center; + background-color: e2edff; + align-self: ${props => props.self === true ? 'flex-end' : 'flex-start'} + margin: 10px 20px; + max-width: 80%; +`; + +const Partner = styled.div` + margin-left: 5px; + margin-right: 15px; + font-size: 13px; + color: rgba(0, 0, 0, 0.7); +`; + +const Timestamp = styled.div` + color: rgba(0, 0, 0, .40) + font-size: 11px; + margin-right: 5px; + margin-left: auto; +`; + +const Text = styled.div` + width: 100%; + display: flex; + flex-direction: column; + padding: 5px 10px; + border-radius: 7px; + background-color: ${props => props.self === true ? '#f1f0f0' : props.theme.primary}; + color: ${props => props.self === true ? props.theme.black : props.theme.white}; + justify-content: center; +`; + +export default Message; diff --git a/client/src/components/Messages/index.js b/client/src/components/Messages/index.js index 1f18c06..ce7b8e9 100644 --- a/client/src/components/Messages/index.js +++ b/client/src/components/Messages/index.js @@ -37,6 +37,7 @@ const MessageaContainer = () => ( const Wrapper = styled.div` display: flex; height: calc(100vh - 120px); + max-height: 600px; max-width: 100%; overflow: auto; border: 1px solid rgba(0, 0, 0, .10); diff --git a/client/src/components/Schedule/Table/Table.js b/client/src/components/Schedule/Table/Table.js index 42c7e6d..f44a58d 100644 --- a/client/src/components/Schedule/Table/Table.js +++ b/client/src/components/Schedule/Table/Table.js @@ -2,9 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; +import InfoColumn from './elements/InfoColumn'; import Column from './elements/Column'; -import { DAYS, HOURS } from '../../../utils/constants'; -import { media } from '../../../utils/style-utils'; +import { DAYS } from '../../../utils/constants'; const Table = (props) => { const { schedule, handleCellClick } = props; @@ -12,12 +12,7 @@ const Table = (props) => { return ( - - Day - Semigroup - Week - {HOURS.map(h => {h.text})} - + {DAYS.map(d => ( props.theme.separator}; - height: 40px; - font-weight: ${props => props.annotation && 'bolder'}; -`; - export default Table; diff --git a/client/src/components/Schedule/Table/elements/Column.js b/client/src/components/Schedule/Table/elements/Column.js index 4bfc77c..b60a072 100644 --- a/client/src/components/Schedule/Table/elements/Column.js +++ b/client/src/components/Schedule/Table/elements/Column.js @@ -3,19 +3,9 @@ import PropTypes from 'prop-types'; import styled from 'styled-components'; import moment from 'moment'; -import { HOURS } from '../../../../utils/constants'; -import ScheduleItem from './ScheduleItem'; +import Week from './Week'; import { media } from '../../../../utils/style-utils'; -const findSchedule = ({ scheduleList, hour, week, semigroup }) => - scheduleList.find( - scheduleItem => - hour.key >= scheduleItem.when.from && - hour.key < scheduleItem.when.from + scheduleItem.when.duration && - [0, parseInt(week, 10)].includes(scheduleItem.when.frequency) && - ['0', semigroup].includes(scheduleItem.whom.semigroup) - ); - const Column = (props) => { const { day, week, semigroup, handleCellClick, scheduleList } = props; @@ -36,29 +26,14 @@ const Column = (props) => { {weeks.map(week => ( - - {`W${week}`} - {HOURS.map((hour, index) => { - const schedule = findSchedule({ - scheduleList, - hour, - week, - semigroup - }); - const key = `${day.text + week + semigroup + hour + index}`; - - return ( - - ); - })} - + ))} @@ -164,30 +139,4 @@ const GroupNumber = styled.div` border-left: ${props => props.theme.separator}; `; -const Week = styled.div` - display: flex; - flex-direction: column; - justify-content: space-around; - width: 100%; - text-align: center; - - &:first-child { - border-right: ${props => props.theme.separator}; - } - - &:last-child { - border-right: 0px; - } -`; - -const WeekNumber = styled.div` - border-bottom: ${props => props.theme.separator}; - height: 40px; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - font-weight: bold; -`; - export default Column; diff --git a/client/src/components/Schedule/Table/elements/InfoColumn.js b/client/src/components/Schedule/Table/elements/InfoColumn.js new file mode 100644 index 0000000..0fdbee5 --- /dev/null +++ b/client/src/components/Schedule/Table/elements/InfoColumn.js @@ -0,0 +1,36 @@ +import React from 'react'; +import styled from 'styled-components'; + +import { HOURS } from '../../../../utils/constants'; +import { media } from '../../../../utils/style-utils'; + +const InfoColumn = () => ( + + Day + Semigroup + Week + {HOURS.map(h => {h.text})} + +); + +const Wrapper = styled.div` + display: flex; + flex-direction: column; + min-width: 8vw; + + ${media.tablet` + display: none + `} +`; + +const Info = styled.div` + display: flex; + align-items: center; + justify-content: center; + text-align: center; + border-bottom: ${props => props.theme.separator}; + height: 40px; + font-weight: ${props => props.annotation && 'bolder'}; +`; + +export default InfoColumn; diff --git a/client/src/components/Schedule/Table/elements/Week.js b/client/src/components/Schedule/Table/elements/Week.js new file mode 100644 index 0000000..6ed110b --- /dev/null +++ b/client/src/components/Schedule/Table/elements/Week.js @@ -0,0 +1,86 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; + +import { HOURS } from '../../../../utils/constants'; +import ScheduleItem from './ScheduleItem'; + +const findSchedule = ({ scheduleList, hour, week, semigroup }) => + scheduleList.find( + scheduleItem => + hour.key >= scheduleItem.when.from && + hour.key < scheduleItem.when.from + scheduleItem.when.duration && + [0, parseInt(week, 10)].includes(scheduleItem.when.frequency) && + ['0', semigroup].includes(scheduleItem.whom.semigroup) + ); + +const Week = (props) => { + const { week, semigroup, scheduleList, handleCellClick, day } = props; + + return ( + + {`W${week}`} + {HOURS.map((hour, index) => { + const schedule = findSchedule({ + scheduleList, + hour, + week, + semigroup + }); + const key = `${day.text + week + semigroup + hour + index}`; + + return ( + + ); + })} + + ); +}; + +const { string, func, shape, arrayOf } = PropTypes; +Week.propTypes = { + handleCellClick: func, + week: string.isRequired, + semigroup: string.isRequired, + day: shape({ + text: string.isRequired, + key: string.isRequired, + value: string.isRequired + }).isRequired, + scheduleList: arrayOf(shape({ _id: string.isRequired })) +}; + +const Wrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: space-around; + width: 100%; + text-align: center; + + &:first-child { + border-right: ${props => props.theme.separator}; + } + + &:last-child { + border-right: 0px; + } +`; + +const Number = styled.div` + border-bottom: ${props => props.theme.separator}; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + font-weight: bold; +`; + +export default Week; diff --git a/client/src/components/common/Thread.js b/client/src/components/common/Thread.js index 537e48f..c33f7cd 100644 --- a/client/src/components/common/Thread.js +++ b/client/src/components/common/Thread.js @@ -19,9 +19,9 @@ class Thread extends Component { } shouldComponentUpdate(nextProps) { - return JSON.stringify(nextProps.messages[0]) !== - JSON.stringify(this.props.messages[0]) || - nextProps.location !== this.props.location; + return nextProps.messages[0]._id !== this.props.messages[0]._id || + nextProps.location.pathname.split('/')[2] === nextProps._id || + this.props.location.pathname.split('/')[2] === this.props._id; } onClick() { @@ -31,7 +31,7 @@ class Thread extends Component { customOnClickhandler, readMessages, _id: id, - selectedConversation: { _id: selectedConversationID } + selectedConversation } = this.props; if (customOnClickhandler !== undefined) { @@ -39,7 +39,7 @@ class Thread extends Component { } changeSearchterm(''); - if (selectedConversationID !== id) { + if (selectedConversation !== null && selectedConversation._id !== id) { selectConversation(id); } readMessages(id); diff --git a/package.json b/package.json index 2c8bf50..fb7583f 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "license": "MIT", "engines": { "node": "7.4.0", - "npm": "4.0.5", - "yarn": "0.24.6" + "npm": "4.0.5", + "yarn": "0.24.6" }, "dependencies": { "concurrently": "^3.4.0", @@ -29,6 +29,7 @@ "eslint-plugin-import": "^2.2.0", "eslint-plugin-jsx-a11y": "^5.0.1", "eslint-plugin-react": "^7.0.1", + "prettier": "^1.5.2", "prettier-eslint": "^6.1.0", "prettier-eslint-cli": "^3.4.2" } diff --git a/server/models/user.js b/server/models/user.js index 6bc84e1..1d34ceb 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -3,6 +3,9 @@ import mongoose, { Schema } from 'mongoose'; import bcrypt from 'bcrypt-nodejs'; +import Student from './student'; +import Teacher from './teacher'; + const UserSchema = new Schema({ username: { type: String, @@ -55,6 +58,13 @@ UserSchema.methods.comparePassword = function checkPassword( }); }; +UserSchema.methods.getFullName = function getFullName() { + if (this.type === 'admin') return 'BigBoss'; + const Model = this.type === 'teacher' ? Teacher : Student; + + return Model.findOne({ _id: this._id }).populate('firstname lastname '); +}; + const User = mongoose.model('user', UserSchema); export default User; diff --git a/yarn.lock b/yarn.lock index 874ab1a..b40f64a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1280,6 +1280,10 @@ prettier@^1.0.2: jest-validate "19.0.0" minimist "1.2.0" +prettier@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.5.2.tgz#7ea0751da27b93bfb6cecfcec509994f52d83bb3" + pretty-format@^19.0.0: version "19.0.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"