Add Front-End for Comments/Ratings and half Subjects

front
TBS093A 2020-01-13 23:40:40 +01:00
commit 21c6bffdeb
44 changed files with 2387 additions and 0 deletions

View File

@ -0,0 +1,18 @@
import React from 'react'
import { connect } from 'react-redux'
import '../../styles/index.scss'
const AdminPanel = ({ user }) => {
return (
<div>
</div>
)
}
const mapStateToProps = state => ({
user: state.user,
})
export default connect(mapStateToProps, null)(AdminPanel)

View File

@ -0,0 +1,19 @@
import React from 'react'
import { connect } from 'react-redux'
import '../../styles/index.scss'
const IndexExchange = ({ user }) => {
return (
<div>
</div>
)
}
const mapStateToProps = state => ({
user: state.user,
})
export default connect(mapStateToProps,null)(IndexExchange)

View File

@ -0,0 +1,75 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux'
import { getCommentRatings, updateComment } from '../../stores/comments/duck/operations'
import { refreshSubjectComments } from '../../stores/subjects/duck/operations'
import actions from '../../stores/subjects/duck/actions'
import '../../styles/indexForum.scss'
const ForumCommentUpdate = ({
user,
subjects, refreshSubjectComments, deactivate,
comment, comments, updateComment, getCommentRatings,
thisComment }) => {
const updateCommentTextArea = React.createRef()
const updateOldComment = (event) => {
event.preventDefault()
if ( updateCommentTextArea.current.value !== '' ) {
let commentData = {
id: comment.id,
token: user.token,
text: updateCommentTextArea.current.value
}
updateCommentTextArea.current.value = ''
updateComment(commentData)
}
}
const [commentText, setCommentText] = useState(0)
if ( thisComment.isActive === true && thisComment.comment_id === comment.id) {
return (
<div className='forumFormComment'>
<form onSubmit={ updateOldComment }>
<textarea
name='addCommentText'
placeholder={ comment.text }
ref={ updateCommentTextArea }
cols='150'
maxLength='1000'
onChange={ e => setCommentText( e.target.value.length ) }>
</textarea>
<p>{commentText}/1000</p>
<button>
Update Comment
</button>
</form>
</div>
)
} else {
return (
<div className='forumHiddenDiv'>
</div>
)
}
}
const mapStateToProps = state => ({
user: state.user,
subjects: state.subjects,
comments: state.comments
})
const mapDispatchToProps = dispatch => ({
updateComment: comments => dispatch( updateComment(comments) ),
getCommentRatings: comments => dispatch( getCommentRatings(comments) ),
refreshSubjectComments: subjects => dispatch( refreshSubjectComments(subjects) ),
deactivate: () => dispatch( actions.deactivate() )
})
export default connect(mapStateToProps, mapDispatchToProps)(ForumCommentUpdate)

View File

@ -0,0 +1,149 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux'
import { getCommentRatings, addComment, deleteComment } from '../../stores/comments/duck/operations'
import { refreshSubjectComments } from '../../stores/subjects/duck/operations'
import actions from '../../stores/subjects/duck/actions'
import '../../styles/indexForum.scss'
import ForumRatings from './forumRatings'
import ForumCommentUpdate from './forumCommentUpdate'
const ForumComments = ({
user,
subjects, refreshSubjectComments, deactivate,
comments, addComment, deleteComment, getCommentRatings }) => {
useEffect( () => { getCommentRatings(subjects.commentsList) }, [])
const [updateFormDiv, setUpdateFormDiv] = useState( { isActive: false, comment_id: -1 } )
const [formDiv, setFormDiv] = useState(false)
const addCommentTextArea = React.createRef()
const updateCommentTextArea = React.createRef()
const addNewComment = (event) => {
event.preventDefault()
if ( addCommentTextArea.current.value !== '' ) {
let newComment = {
text: addCommentTextArea.current.value,
subject_id: subjects.actualSubjectID,
user_id: user.id,
token: user.token
}
addCommentTextArea.current.value = ''
addComment(newComment)
setFormDiv( !formDiv )
let actualSubject = {
id: subjects.actualSubjectID
}
refreshSubjectComments(actualSubject)
}
}
const deleteOldComment = (commentID) => {
let delComment = {
id: commentID,
token: user.token
}
deleteComment(delComment)
let actualSubject = {
id: subjects.actualSubjectID
}
refreshSubjectComments(actualSubject)
}
const [commentText, setCommentText] = useState(0)
return (
<div>
<div className='forumTitle'>
<p>Subject:</p>
<p>{subjects.actualSubjectName}</p>
<button onClick={ () => deactivate() }>
Back to subjects
</button>
<p>author {subjects.actualSubjectAuthor}</p>
</div>
<div className='forumItemsList'>
{ subjects.commentsList.map( comment =>
<div>
<div
className={comment.author_privilige === 3 ? 'forumListComment adminDivColor' :
(comment.author_privilige === 2 ? 'forumListComment moderDivColor' : 'forumListComment') }
key={comment.id}>
<div className='commentAvatar'>
<img src={comment.author_avatar} />
<p>{comment.author}</p>
{ ( user.id === comment.user_id || user.privilige > 1 ) ? (
<div>
<button onClick={ () => setUpdateFormDiv( { isActive: !updateFormDiv.isActive, comment_id: comment.id } ) }>
{ updateFormDiv.isActive ? 'Close Edit' : 'Edit Comment'}
</button>
{ subjects.commentsList[0].id === comment.id ?
(
<div></div>
) : (
<button onClick={ () => deleteOldComment(comment.id) }>
Delete Comment
</button>
) }
</div>
) : (
<div></div>
) }
</div>
<div className='commentText'>
<p>{comment.text}</p>
</div>
<div className='commentRating'>
<ForumRatings comment={comment} />
</div>
</div>
<ForumCommentUpdate comment={comment} thisComment={updateFormDiv} />
</div>
) }
</div>
<div className={ formDiv === true ? 'forumFormComment' : 'forumHiddenDiv' }>
<form onSubmit={ addNewComment }>
<textarea
name='addCommentText'
placeholder='Write a comment'
ref={addCommentTextArea}
cols='150'
maxLength='1000'
onChange={ e => setCommentText( e.target.value.length )}>
</textarea>
<p>{commentText}/1000</p>
<button>
Add Comment
</button>
</form>
</div>
<div className='forumFoot'>
<button onClick={ () => setFormDiv( !formDiv ) }>
{ formDiv === true ? 'Close Add Comment' : 'Add Comment' }
</button>
</div>
</div>
)
}
const mapStateToProps = state => ({
user: state.user,
subjects: state.subjects,
comments: state.comments
})
const mapDispatchToProps = dispatch => ({
addComment: comments => dispatch( addComment(comments) ),
deleteComment: comments => dispatch( deleteComment(comments) ),
getCommentRatings: comments => dispatch( getCommentRatings(comments) ),
refreshSubjectComments: subjects => dispatch( refreshSubjectComments(subjects) ),
deactivate: () => dispatch( actions.deactivate() )
})
export default connect(mapStateToProps, mapDispatchToProps)(ForumComments)

View File

@ -0,0 +1,186 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux'
import { getCommentRatings, addRatingComment, updateRatingComment } from '../../stores/comments/duck/operations'
import actions from '../../stores/subjects/duck/actions'
import '../../styles/forumRatings.scss'
const ForumRatings = ({
user, subjects, deactivate,
comments, getCommentRatings,
addRatingComment, updateRatingComment,
comment }) => {
useEffect( () => { getCommentRatings(subjects.commentsList) }, [])
let commentRatingsAvg = (commentID) => {
for (let comment in Object.entries(subjects.commentsList)) {
if (commentID === subjects.commentsList[comment].id)
return parseInt(subjects.commentsList[comment].ratings_avg.value__avg)
}
}
let getUserRating = (commentID) => {
let userRating = 0
for (let comment = 0; comment < comments.ratingsCommentList.length; comment++)
for (let rating = 0; rating < comments.ratingsCommentList[comment].length; rating++) {
if ((+comments.ratingsCommentList[comment][rating].user_id) === (+user.id)) {
if ((+comments.ratingsCommentList[comment][rating].comment_id) === (+commentID)) {
userRating = comments.ratingsCommentList[comment][rating].value
return userRating
}
}
}
return 0
}
let getRatingID = (commentID) => {
let userRatingID = 0
for (let comment = 0; comment < comments.ratingsCommentList.length; comment++)
for (let rating = 0; rating < comments.ratingsCommentList[comment].length; rating++) {
if ((+comments.ratingsCommentList[comment][rating].user_id) === (+user.id)) {
if ((+comments.ratingsCommentList[comment][rating].comment_id) === (+commentID)) {
userRatingID = comments.ratingsCommentList[comment][rating].id
return userRatingID
}
}
}
return -1
}
const [newRatingValue, setValue] = useState(0)
const changeRatingValue = (event, commentID) => {
let ratingDiv = document.getElementById('rate' + commentID)
let divYPositionOnPage = ratingDiv.getBoundingClientRect().top + 72
let yPosition = event.screenY - divYPositionOnPage
if ( yPosition > 200 ) {
setValue(5)
}
else if ( yPosition > 150 && yPosition < 200 ) {
setValue(4)
}
else if ( yPosition > 100 && yPosition < 150 ) {
setValue(3)
}
else if ( yPosition > 50 && yPosition < 150 ) {
setValue(2)
}
else if ( yPosition > 0 && yPosition < 50 ) {
setValue(1)
}
}
const [updateRating, setUpdate] = useState(false)
const updateUserRating = () => {
const data = {
'id': getRatingID(comment.id),
'value': newRatingValue,
'token': user.token
}
updateRatingComment(data)
setUpdate(false)
getCommentRatings(subjects.commentsList)
}
const addUserRating = () => {
const data = {
'user_id': user.id,
'comment_id': comment.id,
'value': newRatingValue,
'token': user.token
}
addRatingComment(data)
getCommentRatings(subjects.commentsList)
}
if ( getUserRating(comment.id) === 0 ) {
return (
<div>
<div
onClick={ () => addUserRating() }
onMouseOver={ event => changeRatingValue(event, comment.id) }
className='rating'>
<p>{ getUserRating(comment.id) === 0 ? newRatingValue : getUserRating(comment.id) }</p>
<div
id={'rate' + comment.id}
className={'ratingValue ratingValue' + ( getUserRating(comment.id) === 0 ? newRatingValue : getUserRating(comment.id))}>
<div className='ratingStick'></div>
</div>
</div>
<div className='rating'>
<p>{ commentRatingsAvg(comment.id) }</p>
<div className={'ratingValue ratingValue' + commentRatingsAvg(comment.id) }>
<div className='ratingStick'></div>
</div>
</div>
</div>
)
}
else if ( updateRating === false && getUserRating(comment.id) > 0 ) {
return (
<div>
<div
onClick={ () => setUpdate( !updateRating ) }
onMouseOver={ event => changeRatingValue(event, comment.id) }
className='rating'>
<p>{ getUserRating(comment.id) === 0 ? newRatingValue : getUserRating(comment.id) }</p>
<div
id={'rate' + comment.id}
className={'ratingValue ratingValue' + ( getUserRating(comment.id) === 0 ? newRatingValue : getUserRating(comment.id))}>
<div className='ratingStick'></div>
</div>
</div>
<div className='rating'>
<p>{ commentRatingsAvg(comment.id) }</p>
<div className={'ratingValue ratingValue' + commentRatingsAvg(comment.id) }>
<div className='ratingStick'></div>
</div>
</div>
</div>
)
}
else if ( updateRating === true ) {
return (
<div>
<div
onClick={ () => updateUserRating() }
onMouseOver={ event => changeRatingValue(event, comment.id) }
className='rating'>
<p>{ newRatingValue }</p>
<div
id={'rate' + comment.id}
className={'ratingValue ratingValue' + newRatingValue }>
<div className='ratingStick'></div>
</div>
</div>
<div className='rating'>
<p>{ commentRatingsAvg(comment.id) }</p>
<div className={'ratingValue ratingValue' + commentRatingsAvg(comment.id) }>
<div className='ratingStick'></div>
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => ({
user: state.user,
subjects: state.subjects,
comments: state.comments
})
const mapDispatchToProps = dispatch => ({
getCommentRatings: comments => dispatch( getCommentRatings(comments) ),
addRatingComment: comments => dispatch( addRatingComment(comments) ),
updateRatingComment: comments => dispatch( updateRatingComment(comments) ),
deactivate: () => dispatch( actions.deactivate() )
})
export default connect(mapStateToProps, mapDispatchToProps)(ForumRatings)

View File

@ -0,0 +1,148 @@
import React, { useState } from 'react'
import { connect } from 'react-redux'
import { refreshThreadSubjects } from '../../stores/threads/duck/operations'
import { getSubjectComments, addSubject } from '../../stores/subjects/duck/operations'
import { addComment } from '../../stores/comments/duck/operations'
import actions from '../../stores/threads/duck/actions'
import '../../styles/indexForum.scss'
import ForumComments from './forumComments'
const ForumSubjects = ({
user,
threads, deactivate,
subjects, addSubject, getSubjectComments,
comments, addComment }) => {
const [formDiv, setFormDiv] = useState(false)
const addSubjectTitle = React.createRef()
const addSubjectComment = React.createRef()
const addNewSubject = (event) => {
event.preventDefault()
if ( addSubjectTitle.current.value !== '' && addSubjectComment.current.value !== '' ) {
let newSubject = {
name: addSubjectTitle.current.value,
user_id: user.id,
thread_id: threads.actualThreadID,
comment: {
text: addSubjectComment.current.value,
user_id: user.id,
token: user.token
},
token: user.token
}
addSubject(newSubject)
addSubjectComment.current.value = ''
addSubjectTitle.current.value = ''
}
}
const [commentText, setCommentText] = useState(0)
const [titleText, setTitleText] = useState(0)
if (threads.isActive === true && subjects.isActive === false) {
return (
<div>
<div className='forumTitle'>
<p>Subjects in thread:</p>
<p>{threads.actualThreadName} </p>
<button onClick={ () => deactivate() }>
Back to Threads
</button>
<p>moderator {threads.actualThreadModerator}</p>
</div>
<div className='forumItemsList'>
{ threads.subjectsList.map( subject =>
<div
className={subject.author_privilige === 3 ? 'forumListItem adminDivColor' :
(subject.author_privilige === 2 ? 'forumListItem moderDivColor' : 'forumListItem') }
key={subject.id}>
<p onClick={ () => getSubjectComments(subject) }>
{subject.name}
</p>
<div></div>
{ (user.id === subject.user_id ||
user.id === threads.actualThreadModeratorID ||
user.privilige === 3) ? (
<div>
<button>
Edit Title
</button>
<button>
Delete Subject
</button>
<img src={subject.author_avatar} />
<p>{subject.author}</p>
</div>
) : (
<div>
<img src={subject.author_avatar} />
<p>{subject.author}</p>
</div>
)
}
</div>
) }
</div>
<div className={ formDiv === true ? 'forumFormSubject' : 'forumHiddenDiv' }>
<form onSubmit={addNewSubject}>
<input
name='addSubjectTitle'
placeholder='Write a subject title'
ref={addSubjectTitle}
maxLength='30'
onChange={ e => setTitleText(e.target.value.length) }>
</input>
<textarea
name='addCommentText'
placeholder='Write a first comment'
cols='150'
ref={addSubjectComment}
maxLength='1000'
onChange={ e => setCommentText(e.target.value.length) }>
</textarea>
<p>Title: {titleText}/30</p>
<p>Comment: {commentText}/1000</p>
<button>
Add Subject
</button>
</form>
</div>
<div className='forumFoot'>
<button onClick={ () => setFormDiv( !formDiv ) }>
{ formDiv === true ? 'Close Add Subject' : 'Add Subject' }
</button>
</div>
</div>
)
}
else if (threads.isActive === true && subjects.isActive === true) {
return (
<div>
<ForumComments />
</div>
)
}
}
const mapStateToProps = state => ({
user: state.user,
threads: state.threads,
subjects: state.subjects,
comments: state.comments
})
const mapDispatchToProps = dispatch => ({
refreshThreadSubjects: threads => dispatch( refreshThreadSubjects(threads) ),
getSubjectComments: subjects => dispatch( getSubjectComments(subjects) ),
addSubject: subjects => dispatch( addSubject(subjects) ),
addComment: comments => dispatch( addComment(comments) ),
deactivate: () => dispatch( actions.deactivate() )
})
export default connect(mapStateToProps, mapDispatchToProps)(ForumSubjects)

View File

@ -0,0 +1,71 @@
import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import { getAllThreads, getThreadSubjects } from '../../stores/threads/duck/operations'
import '../../styles/indexForum.scss'
import ForumSubjects from './forumSubjects'
const IndexForum = ({ user, threads, getAllThreads, getThreadSubjects }) => {
useEffect( () => { getAllThreads() }, [] )
if (threads.isActive === false) {
return (
<div>
<div className='indexForumMarginTop'>
</div>
<div className='indexForum'>
<div className='forumTitle'>
<p>Forum:</p>
<p>Threads</p>
<p>Forum about BTC exchange</p>
</div>
<div className='forumItemsList'>
{ threads.threadsList.map( thread =>
<div
className={thread.moderator_privilige === 3 ? 'forumListItem adminDivColor' :
(thread.moderator_privilige === 2 ? 'forumListItem moderDivColor' : 'forumListItem') }
key={thread.id}
onClick={ () => getThreadSubjects(thread) }>
<p>{thread.name}</p>
<p>moderator: {thread.moderator}</p>
</div>
) }
</div>
<div className='forumFoot'>
Foot
</div>
</div>
<div className='indexForumMarginTop'>
</div>
</div>
)
}
else if (threads.isActive === true) {
return (
<div>
<div className='indexForumMarginTop'>
</div>
<div className='indexForum'>
<ForumSubjects />
</div>
<div className='indexForumMarginTop'>
</div>
</div>
)
}
}
const mapStateToProps = state => ({
user: state.user,
threads: state.threads
})
const mapDispatchToProps = dispatch => ({
getAllThreads: () => dispatch( getAllThreads() ),
getThreadSubjects: thread => dispatch( getThreadSubjects(thread) )
})
export default connect(mapStateToProps, mapDispatchToProps)(IndexForum)

View File

@ -0,0 +1,28 @@
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { getSubjectsThread } from '../stores/subjects/duck/operations'
import '../styles/index.scss'
const Index = ({subjects, getSubjectsThread}) =>{
useEffect( () => { getSubjectsThread() }, [])
return <ul>
{subjects.list.map(subject => <li>{subject}</li>)}
</ul>
}
// do odczytu globalnego state'a
const mapStateToProps = state => ({
subjects: state.subjects
})
// do modyfikacji globalnego state'a
const mapDispatchToProps = dispatch => ({
getSubjectsThread: () => dispatch( getSubjectsThread() )
})
export default connect(mapStateToProps, mapDispatchToProps)(Index)

View File

@ -0,0 +1,28 @@
import React from 'react'
import { connect } from 'react-redux'
import actions from '../stores/subjects/duck/actions'
const IndexForm = (props) => {
const subjectInput = React.createRef()
const addSubject = (event) => {
event.preventDefault()
props.add(subjectInput.current.value)
subjectInput.current.value = ''
}
return (
<form onSubmit={addSubject}>
<input ref={subjectInput} />
<button type='submit'>Add Subject</button>
</form>
)
}
const mapDispatchToProps = dispatch => ({
add: subject => dispatch(actions.add(subject))
})
export default connect(null, mapDispatchToProps)(IndexForm)

View File

@ -0,0 +1,324 @@
import React from 'react'
import { connect } from 'react-redux'
// Operations Redux
import { createSession, deleteSession, updateSession, registerUser } from '../stores/user/duck/operations'
// Actions Redux
import actions from '../stores/movements/duck/actions'
// Styles
import '../styles/index.scss'
// Components
import MenuBar from './menuBar/menuBar'
import Exchange from './exchange/indexExchange'
import Forum from './forum/indexForum'
import AdminPanel from './admin/adminPanel'
// Images / Videos
import VideoEx from '../images/stockExchange.mp4'
import BtcLogo from '../images/BtcLogo.png'
import ForumLogo from '../images/ForumLogo.png'
const IndexInterface = ({
user, movements,
createSession, deleteSession, updateSession, registerUser,
setRegister, setEdit, setForum, setExchange, setAdminPanel, resetMovements}) => {
const loginInput = React.createRef()
const passwordInput = React.createRef()
const userLogin = (event) => {
event.preventDefault()
let userInput = {
login: loginInput.current.value,
password: passwordInput.current.value
}
loginInput.current.value = ''
passwordInput.current.value = ''
createSession(userInput)
}
const userLogout = (event) => {
event.preventDefault()
let userToken = {
token: user.token
}
deleteSession(userToken)
}
const loginRegister = React.createRef()
const passOneRegister = React.createRef()
const passTwoRegister = React.createRef()
const emailRegister = React.createRef()
const userRegister = (event) => {
event.preventDefault()
if (passOneRegister.current.value === passTwoRegister.current.value) {
let userRegister = {
login: loginRegister.current.value,
password: passOneRegister.current.value,
email: emailRegister.current.value
}
registerUser(userRegister)
}
loginRegister.current.value = ''
passOneRegister.current.value = ''
passTwoRegister.current.value = ''
emailRegister.current.value = ''
}
const loginUpdate = React.createRef()
const passOldOneUpdate = React.createRef()
const passOldTwoUpdate = React.createRef()
const passNewUpdate = React.createRef()
const emailUpdate = React.createRef()
const avatarUpdate = React.createRef()
const userUpdate = (event) => {
event.preventDefault()
if ( passOldOneUpdate.current.value === passOldTwoUpdate.current.value ) {
let userUpdate = {
id: user.id,
login: loginUpdate.current.value === '' ? user.login : loginUpdate.current.value,
passwordOld: passOldOneUpdate.current.value,
passwordNew: passNewUpdate.current.value === '' ? passOldOneUpdate.current.value : passNewUpdate.current.value,
email: emailUpdate.current.value === '' ? user.email : emailUpdate.current.value,
avatar: avatarUpdate.current.value === '' ? user.avatar : avatarUpdate.current.value,
token: user.token
}
updateSession(userUpdate)
}
loginUpdate.current.value = ''
passOldOneUpdate.current.value = ''
passOldTwoUpdate.current.value = ''
passNewUpdate.current.value = ''
emailUpdate.current.value = ''
avatarUpdate.current.value = ''
}
if (user.isActive === false && movements.register === false && movements.exchange === false){
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div className="interface">
<div className='exchangeBtt' onClick={ () => setExchange() }>
<img src={BtcLogo} />
</div>
<div className='emptySpace'>
</div>
<div className='loginForm'>
<form onSubmit={userLogin}>
<input type='text' placeholder='Account' ref={loginInput}/>
<input type='password' placeholder='Password' ref={passwordInput}/>
<br /><br />
<button>
Log in
</button>
</form>
<form>
<button onClick={ () => setRegister() }>
Register
</button>
</form>
</div>
</div>
</div>
)
}
else if (movements.register === true) {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div className="interface">
<div className='oneDivForm'>
<form onSubmit={userRegister}>
<input type='text' placeholder='Login' ref={loginRegister} />
<input type='password' placeholder='Password' ref={passOneRegister}/>
<input type='password' placeholder='Replace Password' ref={passTwoRegister}/>
<input type='text' placeholder='E-mail' ref={emailRegister}/>
<br /><br />
<button>
Register
</button>
</form>
<button onClick={ () => resetMovements() }>
Back
</button>
</div>
</div>
</div>
)
}
else if (movements.edit === true) {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div className="interface">
<div className='oneDivForm'>
<form onSubmit={userUpdate}>
Login:
<input type='text' placeholder={user.login} ref={loginUpdate}/>
Old Password
<input type='password' placeholder='Password' ref={passOldOneUpdate}/>
<input type='password' placeholder='Replace Password' ref={passOldTwoUpdate}/>
New Password
<input type='password' placeholder='New Password' ref={passNewUpdate}/>
E-mail:
<input type='text' placeholder={user.email} ref={emailUpdate}/>
Avatar URL:
<input type='text' placeholder={user.avatar} ref={avatarUpdate}/>
<br /><br />
<button>
Update
</button>
</form>
<button onClick={ () => resetMovements() }>
Back
</button>
</div>
</div>
</div>
)
}
else if (movements.exchange === true) {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div>
<MenuBar />
<Exchange />
</div>
</div>
)
}
else if (movements.forum === true) {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div>
<MenuBar />
<Forum />
</div>
</div>
)
}
else if (movements.adminPanel === true) {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video >
<div>
<MenuBar />
<AdminPanel />
</div>
</div>
)
}
else if (user.privilige === 3) {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div className="interface">
<div className='exchangeBtt' onClick={ () => setExchange() }>
<img src={BtcLogo} />
</div>
<div className='forumBtt' onClick={ () => setForum() }>
<img src={ForumLogo} />
</div>
<div className='loginForm'>
<form>
<p>Welcome</p>
<p>{user.login}</p>
<br />
</form>
<button onClick={ () => setAdminPanel() }>
Admin Panel
</button>
<button onClick={ () => setEdit() }>
Edit Account
</button>
<form onSubmit={userLogout}>
<button>
Log out
</button>
</form>
</div>
</div>
</div>
)
}
else {
return (
<div className='indexView'>
<video id='indexVideo' autoPlay muted loop>
<source src={VideoEx} type="video/mp4" />
</video>
<div className="interface">
<div className='exchangeBtt' onClick={ () => setExchange() }>
<img src={BtcLogo} />
</div>
<div className='forumBtt' onClick={ () => setForum() }>
<img src={ForumLogo} />
</div>
<div className='loginForm'>
<form>
<p>Welcome</p>
<p>{user.login}</p>
<br />
</form>
<button onClick={ () => setEdit()}>
Edit Account
</button>
<form onSubmit={userLogout}>
<button>
Log out
</button>
</form>
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => ({
user: state.user,
movements: state.movements
})
const mapDispatchToProps = dispatch => ({
createSession: user => dispatch( createSession(user) ),
deleteSession: user => dispatch( deleteSession(user) ),
updateSession: user => dispatch( updateSession(user) ),
registerUser: user => dispatch( registerUser(user) ),
setRegister: movements => dispatch( actions.register() ),
setEdit: movements => dispatch( actions.editAccount() ),
setExchange: movements => dispatch( actions.exchange() ),
setForum: movements => dispatch( actions.forum() ),
setAdminPanel: movements => dispatch( actions.adminPanel() ),
resetMovements: movements => dispatch( actions.reset() )
})
export default connect(mapStateToProps, mapDispatchToProps)(IndexInterface)

View File

@ -0,0 +1,69 @@
import React, { useState } from 'react'
import { connect } from 'react-redux'
import { deleteSession } from '../../stores/user/duck/operations'
import actions from '../../stores/movements/duck/actions'
import '../../styles/menuBar.scss'
import BtcLogo from '../../images/BtcLogo.png'
const MenuBar = ({ user, movements, resetMovements, deleteSession }) => {
const [menuActive, setActivity] = useState(false)
const userLogout = (event) => {
event.preventDefault()
let userToken = {
token: user.token
}
resetMovements()
deleteSession(userToken)
}
if (user.isActive === true) {
return (
<div className={ menuActive === true ? 'menuBarActive' : 'menuBar' }>
<img src={BtcLogo} onClick={ () => setActivity( !menuActive ) } />
<div>
<button onClick={ () => resetMovements() }>
Back to Home
</button>
<form onSubmit={userLogout}>
<button>
Log out
</button>
</form>
<p>{user.login}</p>
<p>{user.email}</p>
</div>
</div>
)
}
else {
return (
<div className={ menuActive === true ? 'menuBarActive' : 'menuBar' }>
<img src={BtcLogo} onClick={ () => setActivity( !menuActive ) } />
<div>
<button onClick={ () => resetMovements() }>
Back to Home
</button>
<p>Welcome Guest!</p>
</div>
</div>
)
}
}
const mapStateToProps = state => ({
user: state.user,
movements: state.movements
})
const mapDispatchToProps = dispatch => ({
deleteSession: user => dispatch( deleteSession(user) ),
resetMovements: movements => dispatch( actions.reset() )
})
export default connect(mapStateToProps, mapDispatchToProps)(MenuBar)

16
src/pages/index.js 100644
View File

@ -0,0 +1,16 @@
import React from "react";
import IndexInterface from "../components/indexInterface"
import store from "../stores/store";
import { Provider } from "react-redux";
import '../styles/general.scss'
const IndexPage = () => (
<Provider store={store}>
<IndexInterface />
</Provider>
)
export default IndexPage

View File

@ -0,0 +1,9 @@
import types from './types'
const getRatingsComment = item => ({
type: types.GET_COMMENTS_RATINGS, item
})
export default {
getRatingsComment
}

View File

@ -0,0 +1,5 @@
import commentReducer from './reducers'
export { default as commentTypes } from './types'
export { default as commentActions } from './actions'
export default commentReducer

View File

@ -0,0 +1,87 @@
import actions from './actions'
const fetchRatingsComment = async (comment) => {
const response = await
fetch ('http://localhost:8001/index/comment/' + comment.id + '/rating', {
method: 'GET',
credentials: 'same-origin'
});
return response.json()
}
const fetchAddRating = async (data) => {
fetch ('http://localhost:8001/index/comment/' + data.comment_id + '/rating', {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify(data)
})
}
const fetchUpdateRating = async (rating) => {
fetch ('http://localhost:8001/index/rating/' + rating.id, {
method: 'PUT',
credentials: 'same-origin',
body: JSON.stringify(rating)
})
}
export const getCommentRatings = (data) =>
async (dispatch) => {
let ratings = []
for(let x = 0; x < data.length; x++) {
const rating = await fetchRatingsComment(data[x])
for(let y = 0; y < rating.length; y++)
rating[y].userRating = 0
ratings[x] = rating
}
dispatch( actions.getRatingsComment(ratings) )
}
export const addRatingComment = (data) =>
async (dispatch) => {
await fetchAddRating(data)
}
export const updateRatingComment = (data) =>
async (dispatch) => {
await fetchUpdateRating(data)
}
const fetchAddComment = async (data) => {
fetch ('http://localhost:8001/index/subject/' + data.subject_id + '/comment', {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify(data)
})
}
const fetchUpdateComment = async (data) => {
fetch ('http://localhost:8001/index/comment/' + data.id, {
method: 'PUT',
credentials: 'same-origin',
body: JSON.stringify(data)
})
}
const fetchDeleteComment = async (data) => {
fetch ('http://localhost:8001/index/comment/' + data.id, {
method: 'Delete',
credentials: 'same-origin',
body: JSON.stringify(data)
})
}
export const addComment = (data) =>
async (dispatch) => {
await fetchAddComment(data)
}
export const updateComment = (data) =>
async (dispatch) => {
await fetchUpdateComment(data)
}
export const deleteComment = (data) =>
async (dispatch) => {
await fetchDeleteComment(data)
}

View File

@ -0,0 +1,19 @@
import types from './types'
const INITIAL_STATE = {
ratingsCommentList: [],
}
function commentReducer(state = INITIAL_STATE, action) {
switch(action.type) {
case types.GET_COMMENTS_RATINGS:
return {
...state,
ratingsCommentList: action.item
}
default:
return state;
}
}
export default commentReducer

View File

@ -0,0 +1,5 @@
const GET_COMMENTS_RATINGS = 'GET_COMMENTS_RATINGS'
export default {
GET_COMMENTS_RATINGS
}

View File

@ -0,0 +1,34 @@
import types from './types'
const register = item => ({
type: types.REGISTER, item
})
const editAccount = item => ({
type: types.EDIT_ACCOUNT, item
})
const adminPanel = item => ({
type: types.ADMIN_PANEL, item
})
const exchange = item => ({
type: types.EXCHANGE, item
})
const forum = item => ({
type: types.FORUM, item
})
const reset = item => ({
type: types.RESET, item
})
export default {
register,
editAccount,
adminPanel,
exchange,
forum,
reset,
}

View File

@ -0,0 +1,5 @@
import movementsReducer from './reducers'
export { default as movemetsTypes } from './types'
export { default as movementsActions } from './actions'
export default movementsReducer

View File

@ -0,0 +1,66 @@
import types from './types'
const INITIAL_STATE = {
forum: false,
exchange: false,
edit: false,
register: false,
adminPanel: false,
}
const movementsReducer = (state = INITIAL_STATE, action) => {
switch(action.type) {
case types.EXCHANGE:
return {
exchange: true,
forum: false,
edit: false,
register: false,
adminPanel: false
}
case types.FORUM:
return {
forum: true,
exchange: false,
edit: false,
register: false,
adminPanel: false
}
case types.REGISTER:
return {
register: true,
forum: false,
exchange: false,
edit: false,
adminPanel: false
}
case types.EDIT_ACCOUNT:
return {
edit: true,
forum: false,
exchange: false,
register: false,
adminPanel: false
}
case types.ADMIN_PANEL:
return {
adminPanel: true,
edit: false,
forum: false,
exchange: false,
register: false
}
case types.RESET:
return {
edit: false,
forum: false,
exchange: false,
register: false,
adminPanel: false
}
default:
return state;
}
}
export default movementsReducer

View File

@ -0,0 +1,15 @@
const REGISTER = 'REGISTER'
const EDIT_ACCOUNT = 'EDIT_ACCOUNT'
const FORUM = 'FORUM'
const EXCHANGE = 'EXCHANGE'
const RESET = 'RESET'
const ADMIN_PANEL = 'ADMIN_PANEL'
export default {
REGISTER,
EDIT_ACCOUNT,
FORUM,
EXCHANGE,
RESET,
ADMIN_PANEL
}

View File

@ -0,0 +1,16 @@
import { combineReducers } from 'redux'
import movementsReducer from './movements/duck'
import commentReducer from './comments/duck'
import subjectReducer from './subjects/duck'
import threadReducer from './threads/duck'
import userReducer from './user/duck'
const rootReducer = combineReducers({
user: userReducer,
threads: threadReducer,
subjects: subjectReducer,
comments: commentReducer,
movements: movementsReducer
})
export default rootReducer

View File

@ -0,0 +1,10 @@
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from './reducers'
import thunk from 'redux-thunk'
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)))
window.store = store
export default store

View File

@ -0,0 +1,19 @@
import types from './types'
const getSubjectComments = item => ({
type: types.GET_SUBJECT_COMMENTS, item
})
const activate = item => ({
type: types.ACTIVATE, item
})
const deactivate = item => ({
type: types.DEACTIVATE, item
})
export default {
getSubjectComments,
activate,
deactivate
}

View File

@ -0,0 +1,5 @@
import subjectReducer from './reducers'
export { default as subjectTypes } from './types'
export { default as subjectActions } from './actions'
export default subjectReducer

View File

@ -0,0 +1,68 @@
import actions from './actions'
const fetchSubjectComments = async (subject) => {
const response = await
fetch('http://localhost:8001/index/subject/' + subject.id + '/comment', {
method: 'GET',
credentials: 'same-origin'
});
return response.json()
}
export const getSubjectComments = (data) =>
async (dispatch) => {
const comments = await fetchSubjectComments(data)
dispatch( actions.activate(data) )
dispatch( actions.getSubjectComments(comments) )
}
export const refreshSubjectComments = (data) =>
async (dispatch) => {
const comments = await fetchSubjectComments(data)
dispatch( actions.getSubjectComments(comments) )
}
const fetchAddSubject = async (data) => {
const response = await
fetch('http://localhost:8001/index/thread/' + data.thread_id + '/subject', {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify(data)
});
return response.json()
}
export const addSubject = (data) =>
async (dispatch) => {
const comments = await fetchAddSubject(data)
}
const fetchPutSubject = async (data) => {
const response = await
fetch('http://localhost:8001/index/subject/' + data.id, {
method: 'PUT',
credentials: 'same-origin',
body: JSON.stringify(data)
});
return response.json()
}
export const putSubject = (data) =>
async (dispatch) => {
const comments = await fetchPutSubject(data)
}
const fetchDeleteSubject = async (data) => {
const response = await
fetch('http://localhost:8001/index/subject/' + data.id, {
method: 'DELETE',
credentials: 'same-origin',
body: JSON.stringify(data)
});
return response.json()
}
export const deleteSubject = (data) =>
async (dispatch) => {
const comments = await fetchDeleteSubject(data)
}

View File

@ -0,0 +1,42 @@
import types from './types'
const INITIAL_STATE = {
commentsList: [],
actualSubjectID: -1,
actualSubjectName: '',
actualSubjectAuthor: '',
actualSubjectAuthorID: -1,
isActive: false
}
const subjectReducer = (state = INITIAL_STATE, action) => {
switch(action.type) {
case types.GET_SUBJECT_COMMENTS:
return {
...state,
commentsList: action.item
}
case types.ACTIVATE:
return {
...state,
actualSubjectID: action.item.id,
actualSubjectName: action.item.name,
actualSubjectAuthor: action.item.author,
actualSubjectAuthorID: action.item.user_id,
isActive: true
}
case types.DEACTIVATE:
return {
...state,
actualSubjectID: -1,
actualSubjectName: '',
actualSubjectAuthor: '',
actualSubjectAuthorID: -1,
isActive: false
}
default:
return state;
}
}
export default subjectReducer

View File

@ -0,0 +1,9 @@
const GET_SUBJECT_COMMENTS = 'GET_SUBJECT_COMMENTS'
const ACTIVATE = 'ACTIVATE'
const DEACTIVATE = 'DEACTIVATE'
export default{
GET_SUBJECT_COMMENTS,
ACTIVATE,
DEACTIVATE
}

View File

@ -0,0 +1,24 @@
import types from './types'
const getAll = item => ({
type: types.GET_ALL_THREADS, item
})
const getThreadSubjects = item => ({
type: types.GET_THREAD_SUBJECTS, item
})
const activate = item => ({
type: types.ACTIVATE_THREAD, item
})
const deactivate = item => ({
type: types.DEACTIVATE_THREAD, item
})
export default {
getAll,
getThreadSubjects,
activate,
deactivate
}

View File

@ -0,0 +1,5 @@
import threadReducer from './reducers'
export { default as threadTypes } from './types'
export { default as threadActions } from './actions'
export default threadReducer

View File

@ -0,0 +1,43 @@
import actions from './actions'
const fetchGetAll = async () => {
const response = await
fetch (
'http://localhost:8001/index/thread', {
method: 'GET',
credential: 'same-origin'
}
)
return response.json()
}
const fetchGetSubjects = async (threadID) => {
const response = await
fetch(
'http://localhost:8001/index/thread/' + threadID + '/subject', {
method: 'GET',
credential: 'same-origin'
}
)
return response.json()
}
export const getAllThreads = () =>
async (dispatch) => {
const allThreads = await fetchGetAll()
dispatch( actions.getAll(allThreads) )
}
export const refreshThreadSubjects = (threadID) =>
async (dispatch) => {
const subjects = await fetchGetSubjects(threadID)
dispatch( actions.getThreadSubjects(subjects) )
}
export const getThreadSubjects = (data) =>
async (dispatch) => {
const subjects = await fetchGetSubjects(data.id)
dispatch( actions.activate(data) )
dispatch( actions.getThreadSubjects(subjects) )
}

View File

@ -0,0 +1,46 @@
import types from './types'
const INITIAL_STATE = {
threadsList: [],
actualThreadID: -1,
actualThreadName: '',
actualThreadModeratorID: -1,
actualThreadModerator: '',
subjectsList: [],
isActive: false
}
const threadReducer = (state = INITIAL_STATE, action) => {
switch(action.type) {
case types.GET_ALL_THREADS:
return {
...state, threadsList: action.item
}
case types.GET_THREAD_SUBJECTS:
return {
...state, subjectsList: action.item
}
case types.ACTIVATE_THREAD:
return {
...state,
actualThreadID: action.item.id,
actualThreadName: action.item.name,
actualThreadModeratorID: action.item.user_id,
actualThreadModerator: action.item.moderator,
isActive: true
}
case types.DEACTIVATE_THREAD:
return {
...state,
actualThreadID: -1,
actualThreadName: '',
actualThreadModeratorID: -1,
actualThreadModerator: '',
isActive: false
}
default:
return state;
}
}
export default threadReducer

View File

@ -0,0 +1,11 @@
const GET_ALL_THREADS = 'GET_ALL_THREADS'
const GET_THREAD_SUBJECTS = 'GET_THREAD_SUBJECTS'
const ACTIVATE_THREAD = 'ACTIVATE_THREAD'
const DEACTIVATE_THREAD = '.DEACTIVATE_THREAD'
export default {
GET_ALL_THREADS,
GET_THREAD_SUBJECTS,
ACTIVATE_THREAD,
DEACTIVATE_THREAD,
}

View File

@ -0,0 +1,14 @@
import types from './types'
const login = item => ({
type: types.LOGIN_USER, item
})
const logout = item => ({
type: types.LOGOUT_USER, item
})
export default {
login,
logout
}

View File

@ -0,0 +1,5 @@
import userReducer from './reducers'
export { default as userTypes } from './types'
export { default as userActions } from './actions'
export default userReducer

View File

@ -0,0 +1,77 @@
import actions from './actions'
var jwtDecode = require('jwt-decode')
const fetchLogin = async (user) => {
const response = await
fetch (
'http://localhost:8001/index/authUser', {
method: 'POST',
credential: 'same-origin',
body: JSON.stringify(user),
})
const json = await response.json()
return json
}
const fetchLogout = async (userToken) => {
fetch (
'http://localhost:8001/index/authUser', {
method: 'DELETE',
credential: 'same-origin',
body: JSON.stringify(userToken),
}
)
}
const fetchUpdate = async (user) => {
fetch (
'http://localhost:8001/index/user/' + user.id, {
method: 'PUT',
credential: 'same-origin',
body: JSON.stringify(user),
})
}
const fetchRegister = async (user) => {
fetch (
'http://localhost:8001/index/user', {
method: 'POST',
credential: 'same-origin',
body: JSON.stringify(user),
}
)
}
export const createSession = (data) =>
async (dispatch) => {
const token = await fetchLogin(data)
let user = jwtDecode(token.token)
let userFull = {
'token': token.token,
'id': user.payload.id,
'login': user.payload.login,
'privilige': user.payload.privilige,
'avatar': user.payload.avatar,
'email': user.payload.email
}
dispatch(actions.login(userFull))
}
export const updateSession = (data) =>
async (dispatch) => {
await fetchUpdate(data)
}
export const deleteSession = (data) =>
async (dispatch) => {
await fetchLogout(data)
dispatch(actions.logout())
}
export const registerUser = (data) =>
async (dispatch) => {
await fetchRegister(data)
}

View File

@ -0,0 +1,34 @@
import types from './types'
const INITIAL_STATE = {
id: -1,
login: '',
email: '',
privilige: '',
avatar: '',
token: '',
isActive: false
}
const userReducer = (state = INITIAL_STATE, action) => {
switch(action.type) {
case types.LOGIN_USER:
return { ...state,
id: action.item.id,
login: action.item.login,
privilige: action.item.privilige,
email: action.item.email,
avatar: action.item.avatar,
token: action.item.token,
isActive: true
}
case types.LOGOUT_USER:
return {
isActive: false
}
default:
return state;
}
}
export default userReducer

View File

@ -0,0 +1,9 @@
const LOGIN_USER = 'LOGIN_USER'
const LOGOUT_USER = 'LOGOUT_USER'
const GET_TOKEN = 'GET_TOKEN'
export default {
LOGIN_USER,
LOGOUT_USER,
GET_TOKEN
}

View File

@ -0,0 +1,91 @@
@mixin center {
top: 50%;
transform: translate(0, 110%);
margin: auto;
}
@mixin inputStyle {
width: 200px;
height: 35px;
margin-top: 5px;
margin-bottom: 5px;
border: 0px;
border-radius: 10px;
font-size: 12pt;
text-align: center;
color: rgba(111,108,106,1);
background-color: rgba(22,28,29,0.6);
}
@mixin buttonStyle {
width: 200px;
height: 35px;
margin-top: 5px;
margin-bottom: 5px;
border: 0px;
border-radius: 10px;
font-size: 12pt;
color: rgba(117,82,29,1);
background-color: rgba(22,28,29,1);
transition-duration: 0.5s;
&:hover {
color: rgba(22,28,29,1);
background-color: rgba(117,82,29,0.7);
transition-duration: 0.1s;
}
&:active {
background-color: rgba(117,82,29,1);
}
}
@mixin fontStyle {
color: rgba(117,82,29,1);
font-size: 20px;
margin-top: 0;
margin-bottom: 10px;
}
@mixin backgroundDivMenubarStyle{
background-color: rgba(22,28,29,0.2);
border-bottom: 1px solid;
border-color: rgba(117,82,29,0.7);
transition-duration: 0.5s;
}
@mixin backgroundDefaultDivStyle {
background-color: rgba(22,28,29,0.4);
border: 1px solid;
border-color: rgba(117,82,29,0.7);
border-radius: 25px;
transition-duration: 0.5s;
}
@mixin backgroundDivButtonStyle {
background-color: rgba(22,28,29,0.2);
border: 1px solid;
border-color: rgba(117,82,29,0.7);
border-radius: 25px;
transition-duration: 0.5s;
&:hover {
background-color: rgba(22,28,29,0.5);
border-radius: 15px;
}
}
.adminDivColor {
background: rgb(36,0,0);
background: linear-gradient(180deg,
rgba(121,9,9,0.1) 10%,
rgba(0,212,255,0) 50%);
}
.moderDivColor {
background: rgb(0,12,36);
background: linear-gradient(180deg,
rgba(9,17,121,0.1) 10%,
rgba(0,212,255,0) 50%);
}

View File

@ -0,0 +1,59 @@
@import 'elements';
@import 'indexForum';
$widthRT: 40px;
.rating {
width: $widthRT;
height: 250px;
margin-left: 40px;
float:left;
}
.ratingStick {
width: 1px;
height: 250px;
background-color: rgba(117,82,29,1);
margin: auto;
}
.ratingValue {
transition-duration: 0.5s;
}
.ratingValue5 {
width: $widthRT;
height: 250px;
background-color: rgba(117,82,29,1);
}
.ratingValue4 {
width: $widthRT;
height: 200px;
background-color: rgba(117,82,29,1);
}
.ratingValue3 {
width: $widthRT;
height: 150px;
background-color: rgba(117,82,29,1);
}
.ratingValue2 {
width: $widthRT;
height: 100px;
background-color: rgba(117,82,29,1);
}
.ratingValue1 {
width: $widthRT;
height: 50px;
background-color: rgba(117,82,29,1);
}
.ratingValue0 {
width: $widthRT;
height: 1px;
background-color: rgba(117,82,29,1);
}

View File

@ -0,0 +1,22 @@
@import 'elements';
body {
margin: 0 auto;
input {
@include inputStyle
}
textarea {
@include inputStyle
text-align: left;
}
button {
@include buttonStyle
}
p {
@include fontStyle
}
}

View File

@ -0,0 +1,102 @@
@import 'elements';
.indexView {
width: 100vw;
height: 100vh;
background-color: rgba(31,34,35,1);
overflow-x: hidden;
}
#indexVideo {
opacity: 0.1;
position: fixed;
margin-bottom: -100vh;
filter: saturate(100%) sepia(100%);
}
.interface {
width: 1030px;
height: 300px;
@include center;
}
@mixin OneDiv {
width: 300px;
height: auto;
padding: 50px;
margin-top: -125px;
margin-right: auto;
margin-left: auto;
@include BigButtonStyle
input {
@include inputStyle
width: 100%;
}
button {
@include buttonStyle
}
}
@mixin DefaultDiv {
width: 200px;
height: 200px;
padding: 50px;
margin-right: 40px;
float: left;
}
@mixin BigButtonStyle {
@include backgroundDivButtonStyle
color: rgba(117,82,29,1);
font-size: 20pt;
text-align: center;
img {
width: 150px;
height: 200px;
opacity: 0.7;
}
&:hover{
img {
opacity: 1;
}
}
}
@mixin BttAndLogin {
@include DefaultDiv
@include BigButtonStyle
}
.oneDivForm {
@include OneDiv
}
.emptySpace {
@include DefaultDiv
}
.exchangeBtt {
@include BttAndLogin;
}
.forumBtt {
@include BttAndLogin;
}
.loginForm {
@include BttAndLogin;
input {
@include inputStyle;
}
button {
@include buttonStyle;
}
}

View File

@ -0,0 +1,242 @@
@import 'elements';
.indexForumMarginTop {
width: 100%;
height: 300px;
}
.indexForum {
@include backgroundDefaultDivStyle
position: relative;
z-index: 0;
width: 1400px;
height: auto;
margin-left: auto;
margin-right: auto;
}
@mixin forumDiv {
width: 91%;
height: 60px;
padding-bottom: 3%;
padding-left: 4.5%;
padding-right: 4.5%;
margin-top: 3%;
margin-left: auto;
margin-right: auto;
}
@mixin gapTopBetweenElements {
border-bottom: 2px dashed;
border-color: rgba(117,82,29,0.7);
}
@mixin gapBetweenItems {
border-bottom: 1px dashed;
border-color: rgba(117,82,29,0.7);
}
@mixin gapBetweenSections {
border-right: 1px dashed;
border-color: rgba(117,82,29,0.7);
}
.forumTitle {
@include forumDiv
@include gapTopBetweenElements
p {
font-size: 50px;
float: left;
margin-right: 50px;
}
button {
float: right;
margin-top: 15px;
}
:last-child{
float: right;
font-size: 20px;
margin-top: 20px;
}
:first-child {
font-size: 20px;
margin-top: 20px;
}
}
.forumItemsList {
@include gapTopBetweenElements
.forumListItem:last-child{
border-bottom: 0px dashed;
}
}
.forumListItem {
width: 90%;
height: 50px;
padding-right: 5%;
padding-left: 5%;
padding-top: 15px;
@include gapBetweenItems
p:first-child {
font-size: 30px;
float: left;
}
p:last-child {
float: right;
padding-top: 10px;
}
div {
float: right;
width: auto;
margin-top: -5px;
img {
width: 30px;
height: 30px;
margin-top: 5px;
margin-right: 20px;
}
button {
float: left;
margin-right: 40px;
}
}
&:last-child{
border-bottom: 0px;
}
&:hover {
background-color: rgba(22,28,29,0.5);
}
}
.forumListComment {
width: 100%;
height: auto;
transition-duration: 0.5s;
display: flex;
@include gapBetweenItems
&:last-child{
border-bottom: 1px;
}
}
.commentAvatar {
width: 20%;
padding: 50px;
padding-bottom: 30px;
text-align: center;
@include gapBetweenSections
img {
width: 200px;
height: 200px;
margin-bottom: 20px;
}
}
.commentText {
width: 47.5%;
height: auto;
padding-top: 20px;
padding-bottom: 20px;
padding-left: 2.5%;
padding-right: 2.5%;
word-wrap: break-word;
@include gapBetweenSections
}
.commentRating {
width: 15%;
height: 100px;
padding-top: 20px;
padding-bottom: 20px;
padding-left: 2.5%;
padding-right: 2.5%;
text-align: center;
}
.forumFormSubject {
@include forumDiv
height: auto;
display: flex;
transition-duration: 0.5s;
@include gapTopBetweenElements
input {
width: 100%;
float: left;
text-align: left;
}
textarea {
width: 100%;
height: 200px;
float: left;
}
button {
float: right;
}
p {
padding-top: 10px;
margin-right: 50px;
float: left;
}
}
.forumFormComment {
@include forumDiv
height: auto;
display: flex;
transition-duration: 0.5s;
@include gapTopBetweenElements
textarea {
width: 100%;
height: 200px;
}
button {
float: right;
}
p {
padding-top: 10px;
margin-right: 50px;
float: left;
}
}
.forumFoot {
@include forumDiv
button {
float: right;
}
}
.forumHiddenDiv {
height: 0px;
display: none;
transition-duration: 0.5s;
}

View File

@ -0,0 +1,58 @@
@import 'elements';
.menuBarActive {
@include backgroundDivMenubarStyle
position: fixed;
width: 100%;
height: 75px;
z-index: 1;
padding-top: 25px;
margin-top: 0px;
button, p {
float: right;
margin-right: 50px;
transition-duration: 0.5s;
}
img {
margin-top: 34px;
margin-left: 150px;
width: 70px;
height: 90px;
position: fixed;
}
p {
padding-top: 10px;
}
}
.menuBar {
@include backgroundDivMenubarStyle
position: fixed;
width: 100%;
height: 75px;
z-index: 1;
padding-top: 25px;
margin-top: -25px;
button, p {
float: right;
margin-right: 50px;
transition-duration: 0.5s;
margin-top: -50px;
}
img {
margin-top: 34px;
margin-left: 150px;
width: 70px;
height: 90px;
position: fixed;
}
p {
padding-top: 10px;
}
}