parent
607d02f340
commit
5915c72411
47 changed files with 3180 additions and 35 deletions
@ -1,13 +1,13 @@ |
|||||||
// import proxy from '../proxy';
|
import proxy from '../proxy'; |
||||||
// export const list =
|
export const list = |
||||||
// (data = {}) =>
|
(data = {}) => |
||||||
// async (dispatch) =>
|
async (dispatch) => |
||||||
// (await proxy.get('message/list', data)).dispatch(dispatch);
|
(await proxy.get('message/list', data)).dispatch(dispatch); |
||||||
// export const send =
|
export const send = |
||||||
// (data = {}) =>
|
(data = {}) => |
||||||
// async (dispatch) =>
|
async (dispatch) => |
||||||
// (await proxy.post('message/send', data)).dispatch(dispatch);
|
(await proxy.post('message/send', data)).dispatch(dispatch); |
||||||
// export const sendKeys =
|
export const sendKeys = |
||||||
// (data = {}) =>
|
(data = {}) => |
||||||
// async (dispatch) =>
|
async (dispatch) => |
||||||
// (await proxy.post('message/sendKeys', data)).dispatch(dispatch);
|
(await proxy.post('message/sendKeys', data)).dispatch(dispatch); |
||||||
|
@ -1,16 +1,16 @@ |
|||||||
// const initialState = {
|
const initialState = { |
||||||
// list: [],
|
list: [], |
||||||
// };
|
}; |
||||||
// export default function chat(state = initialState, action) {
|
export default function chat(state = initialState, action) { |
||||||
// let { type, data } = action;
|
let { type, data } = action; |
||||||
// switch (type) {
|
switch (type) { |
||||||
// case 'message/list':
|
case 'message/list': |
||||||
// return { ...state, list: data };
|
return { ...state, list: data }; |
||||||
// case 'message/send':
|
case 'message/send': |
||||||
// return { ...state, list: [...list, ...data] };
|
return { ...state, list: [...state.list, ...data] }; |
||||||
// case 'message/sendKeys':
|
case 'message/sendKeys': |
||||||
// return { ...state, list: [...list, ...data] };
|
return { ...state, list: [...state.list, ...data] }; |
||||||
// default:
|
default: |
||||||
// return state;
|
return state; |
||||||
// }
|
} |
||||||
// }
|
} |
||||||
|
After Width: | Height: | Size: 682 KiB |
@ -0,0 +1,22 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import { Link } from 'react-router-dom'; |
||||||
|
import moment from 'jalali-moment'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
export default class Chat extends Component { |
||||||
|
render() { |
||||||
|
const { data } = this.props; |
||||||
|
return ( |
||||||
|
<Link to={`/chatroom/${data.id}`} className="chat d-flex"> |
||||||
|
<Avatar src={data.imageUrl} alt={data.name} className={'avatar fontLight'} /> |
||||||
|
<div className="chat__data d-flex flex-column"> |
||||||
|
<h1 className="chat__data--name">{data.name}</h1> |
||||||
|
<p className="chat__data--lastMessage">{data.lastMessage.slice(0, 40) + '...'}</p> |
||||||
|
<span>{data.badge}</span> |
||||||
|
<div>{moment(data.date || new Date()).format('jD/jM hh:mm')}</div> |
||||||
|
</div> |
||||||
|
</Link> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat { |
||||||
|
width: 100%; |
||||||
|
direction: rtl; |
||||||
|
align-items: center; |
||||||
|
margin-bottom: 10px; |
||||||
|
position: relative; |
||||||
|
padding: 0px 0px 0px; |
||||||
|
text-decoration: none; |
||||||
|
.avatar { |
||||||
|
background-color: #b4b4b4; |
||||||
|
width: 55px; |
||||||
|
height: 55px; |
||||||
|
// padding: 5px; |
||||||
|
border-radius: 35px; |
||||||
|
object-fit: cover; |
||||||
|
} |
||||||
|
&__data { |
||||||
|
text-align: right; |
||||||
|
flex: 1; |
||||||
|
justify-content: space-around; |
||||||
|
height: 100%; |
||||||
|
padding: 10px 10px 20px; |
||||||
|
border-bottom: rgba(209, 208, 208, 0.7) solid 1px; |
||||||
|
|
||||||
|
&--name { |
||||||
|
font-size: 18px; |
||||||
|
} |
||||||
|
h1 { |
||||||
|
font-family: numeralMedium; |
||||||
|
font-size: 15px; |
||||||
|
margin: 0; |
||||||
|
font-weight: 600; |
||||||
|
color: #6f7074; |
||||||
|
} |
||||||
|
p { |
||||||
|
font-size: 12px; |
||||||
|
margin: 0; |
||||||
|
max-width: calc(100vw - 100px); |
||||||
|
font-family: numeralLight; |
||||||
|
color: #6f7074; |
||||||
|
} |
||||||
|
span { |
||||||
|
background-color: #25d366; |
||||||
|
min-width: 20px; |
||||||
|
font-size: 11px; |
||||||
|
height: 20px; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
border-radius: 13px; |
||||||
|
position: absolute; |
||||||
|
padding-top: 1px; |
||||||
|
padding: 0 5px; |
||||||
|
left: 20px; |
||||||
|
bottom: 10px; |
||||||
|
color: white; |
||||||
|
} |
||||||
|
div { |
||||||
|
color: rgb(99, 99, 99); |
||||||
|
position: absolute; |
||||||
|
left: 20px; |
||||||
|
font-size: 12px; |
||||||
|
top: 5px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
a{ |
||||||
|
text-decoration: none; |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import {Link} from 'react-router-dom'; |
||||||
|
import { list } from '../../Redux/actions/chat'; |
||||||
|
import { connect } from 'react-redux'; |
||||||
|
import ChatIcon from '@material-ui/icons/Chat'; |
||||||
|
import Chat from './Chat/index'; |
||||||
|
import Navbar from '../Home/Navbar/index'; |
||||||
|
|
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
|
||||||
|
class ChatList extends Component { |
||||||
|
componentDidMount() { |
||||||
|
this.props.list(); |
||||||
|
} |
||||||
|
render() { |
||||||
|
return ( |
||||||
|
<div className="chat-list d-flex flex-column"> |
||||||
|
<Navbar /> |
||||||
|
{this.props.chat_list.map((item, i) => ( |
||||||
|
<Chat key={i} data={item} /> |
||||||
|
))} |
||||||
|
<Link to="/characters" className="chat-list__float d-flex"> |
||||||
|
<ChatIcon fontSize="small" /> |
||||||
|
</Link> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default connect( |
||||||
|
(state) => ({ |
||||||
|
chat_list: state.chat.list || [], |
||||||
|
}), |
||||||
|
{ list } |
||||||
|
)(ChatList); |
||||||
|
|
@ -0,0 +1,26 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-list { |
||||||
|
flex: 1; |
||||||
|
padding: 70px 14px 10px; |
||||||
|
position: relative; |
||||||
|
background: white; |
||||||
|
&__float { |
||||||
|
position: fixed; |
||||||
|
height: 50px; |
||||||
|
width: 50px; |
||||||
|
bottom: 20px; |
||||||
|
left: 20px; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
background-color: #01db38; |
||||||
|
border-radius: 100px; |
||||||
|
|
||||||
|
box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.4); |
||||||
|
& svg { |
||||||
|
color: white; |
||||||
|
width: 25px; |
||||||
|
height: 25px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,171 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import AudioReactRecorder from 'audio-react-recorder'; |
||||||
|
import MicIcon from '@material-ui/icons/Mic'; |
||||||
|
import CheckIcon from '@material-ui/icons/Check'; |
||||||
|
import CloseIcon from '@material-ui/icons/Close'; |
||||||
|
import AttachmentIcon from '@material-ui/icons/Attachment'; |
||||||
|
import TextField from '@material-ui/core/TextField'; |
||||||
|
import SendIcon from '@material-ui/icons/Send'; |
||||||
|
import EmojiEmotions from '@material-ui/icons/EmojiEmotions'; |
||||||
|
import KeyboardIcon from '@material-ui/icons/Keyboard'; |
||||||
|
import PhotoCamera from '@material-ui/icons/PhotoCamera'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
export default class ChatInputs extends Component { |
||||||
|
state = { |
||||||
|
emoji: false, |
||||||
|
}; |
||||||
|
render() { |
||||||
|
const { |
||||||
|
onStop, |
||||||
|
stop, |
||||||
|
start, |
||||||
|
recordState, |
||||||
|
cancel, |
||||||
|
typeText, |
||||||
|
message, |
||||||
|
sendMessage, |
||||||
|
addFile, |
||||||
|
file, |
||||||
|
addcounter, |
||||||
|
} = this.props; |
||||||
|
return ( |
||||||
|
<div className="chat-inputs d-flex flex-row-reverse"> |
||||||
|
<AudioReactRecorder state={recordState} onStop={onStop} /> |
||||||
|
{/* <button onClick={start}>Start</button> |
||||||
|
<button onClick={stop}>Stop</button> |
||||||
|
{ |
||||||
|
recordState ?
|
||||||
|
<ReactAudioPlayer |
||||||
|
src={recordState.url} |
||||||
|
autoPlay |
||||||
|
controls |
||||||
|
/> : null |
||||||
|
} */} |
||||||
|
|
||||||
|
<div className="chat-inputs__voice d-flex flex-row-reverse"> |
||||||
|
<div className="chat-inputs__voice d-flex"> |
||||||
|
{(recordState === null && message === '' && file === null) || |
||||||
|
(recordState && recordState.url && message === '' && file === null) ? ( |
||||||
|
<div className="chat-inputs__voice--icon d-flex" onClick={start}> |
||||||
|
<MicIcon |
||||||
|
style={{ |
||||||
|
color: 'white', |
||||||
|
backgroundColor: '#128c7e', |
||||||
|
width: 50, |
||||||
|
height: 50, |
||||||
|
borderRadius: 30, |
||||||
|
padding: 10, |
||||||
|
}} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{message !== '' || file !== null ? ( |
||||||
|
<div className="chat-inputs__voice--icon d-flex" onClick={() => addcounter()}> |
||||||
|
<SendIcon |
||||||
|
style={{ |
||||||
|
padding: '12px 10px 12px 13px', |
||||||
|
color: 'white', |
||||||
|
backgroundColor: '#128c7e', |
||||||
|
width: 50, |
||||||
|
height: 50, |
||||||
|
borderRadius: 30, |
||||||
|
transform: 'rotate(180deg)', |
||||||
|
}} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{recordState === 'start' ? ( |
||||||
|
<> |
||||||
|
<div className="chat-inputs__voice--icon d-flex mr-2" onClick={cancel}> |
||||||
|
<CloseIcon |
||||||
|
style={{ color: 'red', backgroundColor: 'white', width: 30, height: 30 }} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div className="chat-inputs__voice--icon d-flex" onClick={stop}> |
||||||
|
<CheckIcon |
||||||
|
style={{ color: 'green', backgroundColor: 'white', width: 30, height: 30 }} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{recordState !== 'start' ? ( |
||||||
|
<div className="chat-inputs__box d-flex flex-row-reverse"> |
||||||
|
{message === '' ? ( |
||||||
|
<PhotoCamera |
||||||
|
style={{ |
||||||
|
color: '#aaa', |
||||||
|
marginRight: 0, |
||||||
|
width: 25, |
||||||
|
height: 25, |
||||||
|
margin: '0 3px', |
||||||
|
}} |
||||||
|
/> |
||||||
|
) : null} |
||||||
|
<div className="chat-inputs__box--file"> |
||||||
|
<input type="file" onChange={(e) => addFile(e)} /> |
||||||
|
|
||||||
|
<AttachmentIcon |
||||||
|
style={{ |
||||||
|
color: '#aaa', |
||||||
|
marginRight: 10, |
||||||
|
width: 25, |
||||||
|
height: 25, |
||||||
|
zIndex: 10, |
||||||
|
position: 'absolute', |
||||||
|
top: 0, |
||||||
|
left: 0, |
||||||
|
transform: 'rotate(45deg)', |
||||||
|
}} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
|
||||||
|
<TextField |
||||||
|
id="standard-textarea" |
||||||
|
label="" |
||||||
|
value={message} |
||||||
|
placeholder="یک پیام بنویسید..." |
||||||
|
rowsMax={4} |
||||||
|
onChange={(e) => typeText('text',e.target.value)} |
||||||
|
multiline |
||||||
|
style={{ |
||||||
|
marginRight: 5, |
||||||
|
}} |
||||||
|
/> |
||||||
|
{this.props.parent.state.emoji ? ( |
||||||
|
<KeyboardIcon |
||||||
|
style={{ |
||||||
|
color: '#aaa', |
||||||
|
marginRight: -5, |
||||||
|
width: 25, |
||||||
|
height: 25, |
||||||
|
zIndex: 10, |
||||||
|
position: 'relative', |
||||||
|
bottom: 5, |
||||||
|
alignSelf: 'flex-end', |
||||||
|
}} |
||||||
|
onClick={() => this.props.parent.setState({ emoji: false })} |
||||||
|
/> |
||||||
|
) : ( |
||||||
|
<EmojiEmotions |
||||||
|
style={{ |
||||||
|
color: '#aaa', |
||||||
|
marginRight: -5, |
||||||
|
width: 25, |
||||||
|
height: 25, |
||||||
|
zIndex: 10, |
||||||
|
position: 'relative', |
||||||
|
bottom: 5, |
||||||
|
alignSelf: 'flex-end', |
||||||
|
}} |
||||||
|
onClick={() => this.props.parent.setState({ emoji: true })} |
||||||
|
/> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-inputs { |
||||||
|
border-bottom-right-radius: 40px; |
||||||
|
border-bottom-left-radius: 40px; |
||||||
|
width: 100%; |
||||||
|
padding: 2px 5px 0px; |
||||||
|
align-items: flex-end; |
||||||
|
justify-content: flex-end; |
||||||
|
&__box { |
||||||
|
width: 100%; |
||||||
|
border-radius: 30px; |
||||||
|
background-color: #fff; |
||||||
|
box-shadow: 0 0.4px 1px 0px #aaa; |
||||||
|
// background: rgb(18, 15, 153); |
||||||
|
// background: linear-gradient(90deg, rgba(18, 15, 153, 1) 0%, rgba(105, 9, 121, 1) 60%); |
||||||
|
min-height: 45px; |
||||||
|
margin-left: 10px; |
||||||
|
align-items: center; |
||||||
|
padding: 8px 15px; |
||||||
|
&--file { |
||||||
|
width: 30px; |
||||||
|
height: 30px; |
||||||
|
position: relative; |
||||||
|
align-self: flex-end; |
||||||
|
input[type='file'] { |
||||||
|
opacity: 0; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
z-index: 100; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
} |
||||||
|
// input[type=text]{ |
||||||
|
// flex : 1; |
||||||
|
// background-color: inherit; |
||||||
|
// border : 0px; |
||||||
|
// text-align: right; |
||||||
|
// direction: rtl; |
||||||
|
// color : white; |
||||||
|
// font-size: 14px; |
||||||
|
// &:focus{ |
||||||
|
// outline:none; |
||||||
|
// } |
||||||
|
// &::placeholder{ |
||||||
|
// color : white; |
||||||
|
// } |
||||||
|
// } |
||||||
|
.MuiTextField-root { |
||||||
|
flex: 1; |
||||||
|
border: 0px !important; |
||||||
|
outline: none !important; |
||||||
|
text-align: right; |
||||||
|
textarea { |
||||||
|
text-align: right; |
||||||
|
direction: rtl; |
||||||
|
color: black; |
||||||
|
font-size: 14px; |
||||||
|
font-family: IRANSansNumeralLight; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&__voice { |
||||||
|
&--icon { |
||||||
|
width: 50px; |
||||||
|
height: 50px; |
||||||
|
border-radius: 30px; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
background-color: white; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.audio-react-recorder { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiInput-underline:hover:not(.Mui-disabled):before { |
||||||
|
border-bottom: 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiInput-underline:hover:not(.Mui-disabled):before { |
||||||
|
border-bottom: 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiInput-underline:hover:not(.Mui-disabled):before { |
||||||
|
border-bottom: 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiInput-underline:after { |
||||||
|
border-bottom: 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiInput-underline:before { |
||||||
|
border-bottom: 0px !important; |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import Carousel from 'react-elastic-carousel'; |
||||||
|
import './index.scss'; |
||||||
|
export default function Keyboard({ options, action }) { |
||||||
|
return ( |
||||||
|
<div className="chat-suggest portrait-slider d-flex flex-column"> |
||||||
|
<Carousel itemsToShow={1} isRTL={true} enableTilt={true} showArrows={false}> |
||||||
|
{options.map((row, i) => ( |
||||||
|
<Row row={row} key={i} action={action} /> |
||||||
|
))} |
||||||
|
</Carousel> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const Row = ({ row, action }) => { |
||||||
|
return ( |
||||||
|
<div className="chat-suggest__row d-flex"> |
||||||
|
{row.map((item, i) => ( |
||||||
|
<KeyboardItem item={item} key={i} action={action} /> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const KeyboardItem = ({ item, action }) => { |
||||||
|
return ( |
||||||
|
<div className="chat-suggest__row--item d-flex" onclick={() => action(item)}> |
||||||
|
{item.text} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,74 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-suggest { |
||||||
|
& .rec-slider-container { |
||||||
|
margin: 0 !important; |
||||||
|
} |
||||||
|
// border-bottom-right-radius: 40px; |
||||||
|
// border-bottom-left-radius: 40px; |
||||||
|
width: 100%; |
||||||
|
// height : 40px; |
||||||
|
padding: 2px 0px 0px; |
||||||
|
align-items: flex-start; |
||||||
|
margin-top: 5px; |
||||||
|
&__row { |
||||||
|
width: 100%; |
||||||
|
&--item { |
||||||
|
padding: 8px 6px; |
||||||
|
background-color: white; |
||||||
|
border-radius: 5px; |
||||||
|
margin: 0 2px; |
||||||
|
width: 100% !important; |
||||||
|
justify-content: right; |
||||||
|
color: black; |
||||||
|
height: 90px; |
||||||
|
text-align: right; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.portrait-slider { |
||||||
|
width: 100% !important; |
||||||
|
height: 100% !important; |
||||||
|
position: relative; |
||||||
|
padding: 0px 6px 0px; |
||||||
|
margin-bottom: 2px; |
||||||
|
justify-content: center !important; |
||||||
|
} |
||||||
|
|
||||||
|
.rec-dot_active { |
||||||
|
background-color: white !important; |
||||||
|
color: white !important; |
||||||
|
// box-shadow: 0 0 1px rgba(255, 255, 255, 1) !important; |
||||||
|
} |
||||||
|
|
||||||
|
.Carousel-button-10 { |
||||||
|
background-color: white !important; |
||||||
|
} |
||||||
|
.rec-pagination { |
||||||
|
z-index: 600; |
||||||
|
margin-top: 2px !important; |
||||||
|
// position: absolute; |
||||||
|
// top: -12px; |
||||||
|
// left: calc(50% - 20px) !important; |
||||||
|
& button { |
||||||
|
background-color: grey; |
||||||
|
margin: 2px !important; |
||||||
|
box-shadow: 0px 0px 0px rgba(255, 255, 255, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// .guuruq{ |
||||||
|
// box-shadow: 0 1px 2px rgba(0, 0, 0, 0%); |
||||||
|
// } |
||||||
|
|
||||||
|
// .cJeRRR{ |
||||||
|
// background-color: white !important; |
||||||
|
|
||||||
|
// } |
||||||
|
|
||||||
|
// .cJeRRR:hover, .cJeRRR:focus{ |
||||||
|
// cursor: pointer; |
||||||
|
// box-shadow: 0px 0px 0px rgba(255,255,255,1) !important; |
||||||
|
// background-color: white !important; |
||||||
|
// } |
@ -0,0 +1,83 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import DoneIcon from '@material-ui/icons/Done'; |
||||||
|
import DoneAllIcon from '@material-ui/icons/DoneAll'; |
||||||
|
import EditIcon from '@material-ui/icons/Edit'; |
||||||
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; |
||||||
|
import './index.scss'; |
||||||
|
import Menu from '@material-ui/core/Menu'; |
||||||
|
import MenuItem from '@material-ui/core/MenuItem'; |
||||||
|
import ReplyIcon from '@material-ui/icons/Reply'; |
||||||
|
import ForwardIcon from '@material-ui/icons/Forward'; |
||||||
|
import DeleteIcon from '@material-ui/icons/Delete'; |
||||||
|
import ScheduleIcon from '@material-ui/icons/Schedule'; |
||||||
|
const menu = [ |
||||||
|
{ text: 'پسند', icon: FavoriteIcon, onClick: () => {} }, |
||||||
|
{ text: 'تبادل نظر', icon: TextsmsIcon, onClick: () => {} }, |
||||||
|
{ text: 'پاسخ', icon: ReplyIcon, onClick: () => {} }, |
||||||
|
{ text: 'باز ارسال', icon: ForwardIcon, onClick: () => {} }, |
||||||
|
]; |
||||||
|
const selfMenu = [ |
||||||
|
{ text: 'باز ارسال', icon: ForwardIcon, onClick: () => {} }, |
||||||
|
{ text: 'ویرایش', icon: EditIcon, onClick: () => {} }, |
||||||
|
{ text: 'حذف', icon: DeleteIcon, onClick: () => {} }, |
||||||
|
]; |
||||||
|
export default class Comment extends Component { |
||||||
|
state = { messageMenu: null }; |
||||||
|
handleClose = () => { |
||||||
|
this.setState({ |
||||||
|
messageMenu: null, |
||||||
|
}); |
||||||
|
}; |
||||||
|
handleClick = (event) => { |
||||||
|
this.setState({ |
||||||
|
messageMenu: event.currentTarget, |
||||||
|
}); |
||||||
|
}; |
||||||
|
render() { |
||||||
|
const { message, user, document, children, addcounter } = this.props; |
||||||
|
const { messageMenu } = this.state; |
||||||
|
const hasavatar = prevUserId != message.userId; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="comment-message d-flex flex-column d-flex" |
||||||
|
style={{ |
||||||
|
filter: document !== null ? 'blur(16px)' : 'blur(0px)', |
||||||
|
}} |
||||||
|
> |
||||||
|
<div className={`comment-message__box`}> |
||||||
|
<div |
||||||
|
className="comment-message__box--detail d-flex" |
||||||
|
> |
||||||
|
<div onClick={() => addcounter('nothing')}> |
||||||
|
<ExpandMoreIcon fontSize="small" onClick={this.handleClick} /> |
||||||
|
</div> |
||||||
|
<Menu |
||||||
|
anchorEl={messageMenu} |
||||||
|
keepMounted |
||||||
|
open={Boolean(messageMenu)} |
||||||
|
onClose={() => this.handleClose()} |
||||||
|
className="rtl fontLight" |
||||||
|
> |
||||||
|
{(isSelf ? selfMenu : menu).map((e) => ( |
||||||
|
<MenuItem |
||||||
|
className="fontLight" |
||||||
|
onClick={() => { |
||||||
|
this.handleClose(); |
||||||
|
e.onClick(); |
||||||
|
addcounter('nothing'); |
||||||
|
}} |
||||||
|
> |
||||||
|
<e.icon fontSize="small" /> |
||||||
|
{e.text} |
||||||
|
</MenuItem> |
||||||
|
))} |
||||||
|
</Menu> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p>{message.text}</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
import { toast } from 'react-toastify'; |
||||||
|
|
||||||
|
export default class Message2D extends Component { |
||||||
|
state = { value: this.props.message.value }; |
||||||
|
click(id) { |
||||||
|
if (this.props.isActive) { |
||||||
|
this.setState({ value: id }); |
||||||
|
toast.success('ثبت شد'); |
||||||
|
this.props.action(); |
||||||
|
} |
||||||
|
} |
||||||
|
render() { |
||||||
|
const { message, user, isSelf, isActive, action } = this.props; |
||||||
|
return ( |
||||||
|
<div className="message-2d d-flex flex-column d-flex"> |
||||||
|
<div className="message-2d__options d-flex flex-column"> |
||||||
|
{message.options.map((option, i) => ( |
||||||
|
<div |
||||||
|
key={message.id + '_' + option.id + '_' + i} |
||||||
|
className="message-2d__options--row d-flex" |
||||||
|
> |
||||||
|
{option.map((item, i) => ( |
||||||
|
<div |
||||||
|
key={message.id + '_' + item.id + '_' + i} |
||||||
|
className="d-flex" |
||||||
|
style={{ |
||||||
|
width: `calc(100% / ${option.length} )`, |
||||||
|
|
||||||
|
backgroundColor: item.id == this.state.value ? '#64cd82' : '', |
||||||
|
}} |
||||||
|
onClick={() => this.click(item.id)} |
||||||
|
> |
||||||
|
<span>{item.name}</span> |
||||||
|
</div> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,101 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.message-2d { |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
// width: 100%; |
||||||
|
position: relative; |
||||||
|
img { |
||||||
|
width: 65px; |
||||||
|
height: 65px; |
||||||
|
object-fit: cover; |
||||||
|
border-radius: 30px; |
||||||
|
border: 3px solid rgba(201, 201, 201, 0.857); |
||||||
|
position: relative; |
||||||
|
top: 20px; |
||||||
|
z-index: 50; |
||||||
|
} |
||||||
|
&__text { |
||||||
|
justify-content: flex-end; |
||||||
|
width: 100%; |
||||||
|
padding: 15px 15px 5px; |
||||||
|
background-color: white; |
||||||
|
border-radius: 5px; |
||||||
|
position: relative; |
||||||
|
margin-bottom: 5px; |
||||||
|
text-align: right; |
||||||
|
direction: rtl; |
||||||
|
p { |
||||||
|
width: 100%; |
||||||
|
text-align: right; |
||||||
|
font-size: 16px; |
||||||
|
// font-family: IRANSansNumeralBold; |
||||||
|
} |
||||||
|
} |
||||||
|
&__options { |
||||||
|
width: 100%; |
||||||
|
z-index: 200; |
||||||
|
&--row { |
||||||
|
width: 100%; |
||||||
|
justify-content: space-around; |
||||||
|
div { |
||||||
|
background-color: rgb(255 255 255 / 40%); |
||||||
|
border-radius: 10px; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
margin: 2px 3px; |
||||||
|
padding: 6px; |
||||||
|
flex: 1; |
||||||
|
text-align: center; |
||||||
|
span { |
||||||
|
font-size: 16px; |
||||||
|
color: black; |
||||||
|
font-weight: 400; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&--radio { |
||||||
|
width: calc(50% - 6px); |
||||||
|
margin: 3px; |
||||||
|
padding: 10px; |
||||||
|
text-align: center; |
||||||
|
font-size: 16px; |
||||||
|
color: black; |
||||||
|
font-weight: 600; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
|
&--draggable { |
||||||
|
background-color: rgb(255 255 255 / 40%); |
||||||
|
border-radius: 10px; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
margin: 2px 3px; |
||||||
|
padding: 6px; |
||||||
|
font-size: 16px; |
||||||
|
color: black; |
||||||
|
font-weight: 600; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
} |
||||||
|
& button { |
||||||
|
background: #64cd82; |
||||||
|
// background: linear-gradient(180deg, rgb(163, 73, 186) 0%, rgb(108, 72, 191) 52%); |
||||||
|
width: 100%; |
||||||
|
margin: 3px auto 0px; |
||||||
|
border: none; |
||||||
|
padding: 5px 0px; |
||||||
|
font-size: 18px; |
||||||
|
border-radius: 10px; |
||||||
|
color: white; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.MuiGrid-container { |
||||||
|
display: flex !important; |
||||||
|
width: 100% !important; |
||||||
|
margin: 0px !important; |
||||||
|
background-color: rgb(255 255 255 / 40%); |
||||||
|
justify-content: center !important; |
||||||
|
align-items: center !important; |
||||||
|
border-radius: 10px; |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import ArrowRightAltIcon from '@material-ui/icons/ArrowRightAlt'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
import { toast } from 'react-toastify'; |
||||||
|
|
||||||
|
export default class RadioMessage extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
value: this.props.message.value, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
handleRadioChange = (newValue) => { |
||||||
|
if (this.props.isActive) |
||||||
|
this.setState({ |
||||||
|
value: newValue, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { message, user, isSelf, isActive } = this.props; |
||||||
|
return ( |
||||||
|
<div className="message-2d d-flex flex-column d-flex"> |
||||||
|
<div className="message-2d__options d-flex flex-wrap justify-content-center"> |
||||||
|
{message.options.map((row) => ( |
||||||
|
<Row list={row} handleRadioChange={this.handleRadioChange} value={this.state.value} /> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
{isActive && ( |
||||||
|
<button className="message-2d__submit" onClick={() => toast.success('ثبت شد')}> |
||||||
|
ثبت |
||||||
|
<ArrowRightAltIcon style={{ color: 'white', width: 32, height: 32, marginLeft: 10 }} /> |
||||||
|
</button> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const Row = (props) => { |
||||||
|
return ( |
||||||
|
<div className="message-2d__options--row d-flex"> |
||||||
|
{props.list.map((item) => ( |
||||||
|
<Item item={item} {...props} /> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const Item = (props) => { |
||||||
|
return ( |
||||||
|
<div |
||||||
|
onClick={() => props.handleRadioChange(props.item.name)} |
||||||
|
style={{ |
||||||
|
backgroundColor: props.item.name === props.value ? '#6f42c1' : 'rgb(181 224 252 / 47%)', |
||||||
|
color: props.item.name === props.value ? 'white' : 'black', |
||||||
|
}} |
||||||
|
> |
||||||
|
{props.item.name} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,245 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import ReactAudioPlayer from 'react-audio-player'; |
||||||
|
import ReactPlayer from 'react-player'; |
||||||
|
import CloudDownloadIcon from '@material-ui/icons/CloudDownload'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
import moment from 'jalali-moment'; |
||||||
|
import DoneIcon from '@material-ui/icons/Done'; |
||||||
|
import DoneAllIcon from '@material-ui/icons/DoneAll'; |
||||||
|
import EditIcon from '@material-ui/icons/Edit'; |
||||||
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; |
||||||
|
import './index.scss'; |
||||||
|
import Menu from '@material-ui/core/Menu'; |
||||||
|
import MenuItem from '@material-ui/core/MenuItem'; |
||||||
|
import ReplyIcon from '@material-ui/icons/Reply'; |
||||||
|
import ForwardIcon from '@material-ui/icons/Forward'; |
||||||
|
import DeleteIcon from '@material-ui/icons/Delete'; |
||||||
|
import FavoriteIcon from '@material-ui/icons/Favorite'; |
||||||
|
import TextsmsIcon from '@material-ui/icons/Textsms'; |
||||||
|
import ScheduleIcon from '@material-ui/icons/Schedule'; |
||||||
|
const file = (fileId) => `${window.baseURL}/file/download/${fileId}`; |
||||||
|
const menu = [ |
||||||
|
{ text: 'پسند', icon: FavoriteIcon, onClick: () => {} }, |
||||||
|
{ text: 'تبادل نظر', icon: TextsmsIcon, onClick: () => {} }, |
||||||
|
{ text: 'پاسخ', icon: ReplyIcon, onClick: () => {} }, |
||||||
|
{ text: 'باز ارسال', icon: ForwardIcon, onClick: () => {} }, |
||||||
|
]; |
||||||
|
const selfMenu = [ |
||||||
|
{ text: 'باز ارسال', icon: ForwardIcon, onClick: () => {} }, |
||||||
|
{ text: 'ویرایش', icon: EditIcon, onClick: () => {} }, |
||||||
|
{ text: 'حذف', icon: DeleteIcon, onClick: () => {} }, |
||||||
|
]; |
||||||
|
export default class NormalMessage extends Component { |
||||||
|
state = { messageMenu: null }; |
||||||
|
handleClose = () => { |
||||||
|
this.setState({ |
||||||
|
messageMenu: null, |
||||||
|
}); |
||||||
|
}; |
||||||
|
handleClick = (event) => { |
||||||
|
this.setState({ |
||||||
|
messageMenu: event.currentTarget, |
||||||
|
}); |
||||||
|
}; |
||||||
|
render() { |
||||||
|
const { message, user, document, isSelf, prevUserId, children,addcounter } = this.props; |
||||||
|
const { messageMenu } = this.state; |
||||||
|
const hasavatar = prevUserId != message.userId; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="normal-message d-flex flex-column d-flex" |
||||||
|
style={{ |
||||||
|
filter: document !== null ? 'blur(16px)' : 'blur(0px)', |
||||||
|
}} |
||||||
|
> |
||||||
|
{hasavatar && false && ( |
||||||
|
<Avatar |
||||||
|
alt={user.name} |
||||||
|
src={window.baseURL + '/file/download/' + user.fileId} |
||||||
|
className="" |
||||||
|
style={{ |
||||||
|
marginTop: -5, |
||||||
|
backgroundColor: user.color, |
||||||
|
alignSelf: isSelf ? 'flex-end' : 'flex-start', |
||||||
|
}} |
||||||
|
> |
||||||
|
{user.name |
||||||
|
.split(' ') |
||||||
|
.map((e) => e.slice(0, 1)) |
||||||
|
.join(' ')} |
||||||
|
</Avatar> |
||||||
|
)} |
||||||
|
|
||||||
|
<div |
||||||
|
className="d-flex" |
||||||
|
style={{ direction: isSelf ? 'rtl' : 'ltr', marginTop: hasavatar ? 0 : 0 }} |
||||||
|
> |
||||||
|
<div |
||||||
|
className={ |
||||||
|
message.type == 'text' |
||||||
|
? `normal-message__box ` |
||||||
|
: `normal-message__box normal-message__box--file` |
||||||
|
} |
||||||
|
style={{ |
||||||
|
paddingTop: hasavatar ? 25 : 15, |
||||||
|
backgroundColor: isSelf ? 'white' : 'rgb(220, 248, 198)', |
||||||
|
width: 'calc(100%-70px)', |
||||||
|
}} |
||||||
|
> |
||||||
|
<div |
||||||
|
className="normal-message__box--detail d-flex" |
||||||
|
style={{ |
||||||
|
top: 0, |
||||||
|
|
||||||
|
direction: isSelf ? 'ltr' : 'rtl', |
||||||
|
paddingRight: isSelf ? 20 : 20, |
||||||
|
paddingLeft: isSelf ? 0 : 0, |
||||||
|
}} |
||||||
|
> |
||||||
|
<div style={{ color: isSelf ? '#aaa' : 'gray' }} onClick={() => addcounter('nothing')}> |
||||||
|
<ExpandMoreIcon fontSize="small" onClick={this.handleClick} /> |
||||||
|
</div> |
||||||
|
<Menu |
||||||
|
anchorEl={messageMenu} |
||||||
|
keepMounted |
||||||
|
open={Boolean(messageMenu)} |
||||||
|
onClose={() => this.handleClose()} |
||||||
|
className="rtl fontLight" |
||||||
|
> |
||||||
|
{(isSelf ? selfMenu : menu).map((e) => ( |
||||||
|
<MenuItem |
||||||
|
className="fontLight" |
||||||
|
onClick={() => { |
||||||
|
this.handleClose(); |
||||||
|
e.onClick(); |
||||||
|
addcounter('nothing'); |
||||||
|
}} |
||||||
|
> |
||||||
|
{e.text} |
||||||
|
<e.icon fontSize="samall" /> |
||||||
|
</MenuItem> |
||||||
|
))} |
||||||
|
</Menu> |
||||||
|
{hasavatar && <div style={{ color: isSelf ? '#aaa' : 'gray' }}>{user.name}</div>} |
||||||
|
</div> |
||||||
|
|
||||||
|
{message.type == 'text' ? ( |
||||||
|
<p style={{ color: isSelf ? 'black' : 'black' }}>{message.text}</p> |
||||||
|
) : null} |
||||||
|
{message.type == 'voice' ? ( |
||||||
|
<ReactAudioPlayer src={file(message.fileId)} controls /> |
||||||
|
) : null} |
||||||
|
{message.type == 'image' ? ( |
||||||
|
<div className="normal-message__box--caption"> |
||||||
|
<a href={file(message.fileId)} download> |
||||||
|
<img src={file(message.fileId)} download alt="" /> |
||||||
|
</a> |
||||||
|
<p style={{ color: isSelf ? 'black' : 'black' }}>{message.text}</p> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{message.type == 'video' ? ( |
||||||
|
<div className="normal-message__box--caption"> |
||||||
|
<a href={file(message.fileId)} download> |
||||||
|
<ReactPlayer url={file(message.fileId)} controls width={'100%'} height={250} /> |
||||||
|
</a> |
||||||
|
<p style={{ color: isSelf ? 'black' : 'black' }}>{message.text}</p> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{message.type == 'audio' ? ( |
||||||
|
<div className="normal-message__box--caption"> |
||||||
|
<ReactAudioPlayer src={file(message.fileId)} controls /> |
||||||
|
<p style={{ color: isSelf ? 'black' : 'black' }}>{message.text}</p> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{message.type == 'document' ? ( |
||||||
|
<a |
||||||
|
href={file(message.fileId)} |
||||||
|
download |
||||||
|
className="normal-message__box--document d-flex" |
||||||
|
style={{ |
||||||
|
backgroundColor: isSelf ? 'rgb(15, 93, 190)' : 'white', |
||||||
|
color: isSelf ? 'black' : 'black', |
||||||
|
}} |
||||||
|
> |
||||||
|
<CloudDownloadIcon |
||||||
|
style={{ |
||||||
|
color: isSelf ? 'black' : 'black', |
||||||
|
width: 32, |
||||||
|
height: 32, |
||||||
|
marginRight: 10, |
||||||
|
}} |
||||||
|
/> |
||||||
|
<div>{message.text}</div> |
||||||
|
</a> |
||||||
|
) : null} |
||||||
|
|
||||||
|
<div className={'normal-message__box--date d-flex ' + (isSelf ? 'self' : '')}> |
||||||
|
<span style={{ color: isSelf ? '#aaa' : 'gray' }}> |
||||||
|
{message.updatedAt != message.createdAt ? ( |
||||||
|
<> |
||||||
|
<span> ویرایش در</span> |
||||||
|
|
||||||
|
{moment(message.updatedAt).format(' hh:mm jMM/jDD')} |
||||||
|
</> |
||||||
|
) : ( |
||||||
|
moment(message.createdAt).format('hh:mm') |
||||||
|
)} |
||||||
|
</span> |
||||||
|
<span |
||||||
|
style={{ |
||||||
|
color: isSelf ? '#aaa' : 'gray', |
||||||
|
padding: '0 2px', |
||||||
|
}} |
||||||
|
> |
||||||
|
{isSelf && message.status == 0 && <ScheduleIcon fontSize="small" />} |
||||||
|
{isSelf && message.status == 2 && <DoneIcon fontSize="small" />} |
||||||
|
{isSelf && message.status == 1 && ( |
||||||
|
<DoneAllIcon fontSize="small" style={{ color: '#00afea', fontSize: '17px' }} /> |
||||||
|
)} |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div className={isSelf ? 'icons self' : 'icons'} onClick={() => addcounter('nothing')}> |
||||||
|
{!isSelf ? ( |
||||||
|
<> |
||||||
|
{' '} |
||||||
|
<div> |
||||||
|
<span> {10}</span> |
||||||
|
<FavoriteIcon fontSize="samall" color="primary" /> |
||||||
|
|
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<span> {10}</span> |
||||||
|
<TextsmsIcon fontSize="samall" color="secondary" /> |
||||||
|
</div> |
||||||
|
</> |
||||||
|
) : ( |
||||||
|
<> |
||||||
|
<div> |
||||||
|
<span> |
||||||
|
+5 |
||||||
|
<br /> |
||||||
|
خلاقیت |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
</> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div |
||||||
|
className="f-flex keys" |
||||||
|
style={{ |
||||||
|
width: 'calc(100% - 70px)', |
||||||
|
marginRight: isSelf ? 0 : 70, |
||||||
|
marginLeft: isSelf ? 70 : 0, |
||||||
|
alignSelf: isSelf ? 'flex-end' : 'flex-start', |
||||||
|
}} |
||||||
|
> |
||||||
|
{children} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,155 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.normal-message__box--date.self { |
||||||
|
padding-right: 20px 0 0 !important ; |
||||||
|
} |
||||||
|
.keys { |
||||||
|
max-width: 465px; |
||||||
|
min-width: 250px; |
||||||
|
padding: 2px 0; |
||||||
|
} |
||||||
|
.icons { |
||||||
|
//position: absolute; |
||||||
|
width: 90px; |
||||||
|
padding: 0 5px; |
||||||
|
display: inline-block !important; |
||||||
|
// top: 55px; |
||||||
|
// right: -35px; |
||||||
|
direction:rtl; |
||||||
|
text-align: left; |
||||||
|
& .MuiSvgIcon-root { |
||||||
|
font-size: 18px !important; |
||||||
|
opacity: 0.8; |
||||||
|
} |
||||||
|
& span { |
||||||
|
font-size: 11px !important; |
||||||
|
opacity: 0.8; |
||||||
|
} |
||||||
|
} |
||||||
|
.icons.self { |
||||||
|
direction: ltr; |
||||||
|
text-align: right; |
||||||
|
font-size: small; |
||||||
|
// left: -35px; |
||||||
|
// right: none; |
||||||
|
} |
||||||
|
.MuiMenuItem-root { |
||||||
|
min-height: 10px !important; |
||||||
|
font-size: 12px !important; |
||||||
|
color: grey; |
||||||
|
padding: 5px 10px !important; |
||||||
|
& .MuiSvgIcon-root { |
||||||
|
font-size: 16px !important; |
||||||
|
padding: 2px; |
||||||
|
color: grey; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.normal-message { |
||||||
|
// width: 100%; |
||||||
|
position: relative; |
||||||
|
margin-bottom: 2px; |
||||||
|
img { |
||||||
|
width: 65px; |
||||||
|
height: 65px; |
||||||
|
object-fit: cover; |
||||||
|
border-radius: 15px; |
||||||
|
border: 3px solid rgba(201, 201, 201, 0.857); |
||||||
|
position: relative; |
||||||
|
top: 20px; |
||||||
|
z-index: 50; |
||||||
|
} |
||||||
|
&__box { |
||||||
|
line-height: 1.3em; |
||||||
|
max-width: 500px; |
||||||
|
min-width: 250px; |
||||||
|
display: flex; |
||||||
|
justify-content: flex-end; |
||||||
|
// width: 100%; |
||||||
|
padding: 20px 10px 15px; |
||||||
|
background-color: white; |
||||||
|
border-radius: 5px; |
||||||
|
position: relative; |
||||||
|
p { |
||||||
|
width: 100%; |
||||||
|
text-align: right; |
||||||
|
direction: rtl; |
||||||
|
font-size: 15px; |
||||||
|
margin: 0 0 5px !important; |
||||||
|
// font-family: IRANSansNumeral; |
||||||
|
font-weight: 200; |
||||||
|
color: #afafaf; |
||||||
|
} |
||||||
|
&--detail { |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
top: 10px; |
||||||
|
justify-content: space-between; |
||||||
|
font-size: 12px; |
||||||
|
span { |
||||||
|
font-family: IRANSansNumeralLight; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&--date { |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
padding: 0px 0px 0; |
||||||
|
bottom: 0px; |
||||||
|
justify-content: flex-end; |
||||||
|
font-size: 11px; |
||||||
|
span { |
||||||
|
font-family: IRANSansNumeralLight; |
||||||
|
} |
||||||
|
} |
||||||
|
&--date.self { |
||||||
|
justify-content: flex-end; |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
&--caption { |
||||||
|
width: 100%; |
||||||
|
margin-bottom: 20px; |
||||||
|
text-align: right; |
||||||
|
& img { |
||||||
|
height: 100%; |
||||||
|
max-height: 250px; |
||||||
|
width: 100%; |
||||||
|
max-width: 250px; |
||||||
|
border-radius: 0px; |
||||||
|
border: 0px; |
||||||
|
position: static; |
||||||
|
} |
||||||
|
& video { |
||||||
|
height: 180px !important; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
& p { |
||||||
|
margin-top: 20px; |
||||||
|
} |
||||||
|
// & audio{ |
||||||
|
// min-width: 100% !important; |
||||||
|
// } |
||||||
|
} |
||||||
|
&--file { |
||||||
|
background-color: rgb(143, 228, 143) !important; |
||||||
|
} |
||||||
|
&--document { |
||||||
|
width: 100%; |
||||||
|
max-width: 300px; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
height: 50px; |
||||||
|
padding: 10px; |
||||||
|
border-radius: 10px; |
||||||
|
div { |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.react-audio-player { |
||||||
|
width: 100% !important; |
||||||
|
color: red; |
||||||
|
fill: red; |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import ArrowRightAltIcon from '@material-ui/icons/ArrowRightAlt'; |
||||||
|
|
||||||
|
export default class RadioMessage extends Component { |
||||||
|
state = { |
||||||
|
value: this.props.message.value, |
||||||
|
}; |
||||||
|
handleRadioChange = (value) => { |
||||||
|
if (this.props.isActive) this.setState({ value }); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { message, user, isSelf, isActive, action } = this.props; |
||||||
|
const { value } = this.state; |
||||||
|
return ( |
||||||
|
<div className="message-2d d-flex flex-column d-flex"> |
||||||
|
<div className="message-2d__options d-flex flex-wrap justify-content-center"> |
||||||
|
{message.options.map((row) => ( |
||||||
|
<Row list={row} handleRadioChange={this.handleRadioChange} value={value} /> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
{isActive && ( |
||||||
|
<button className="message-2d__submit" onClick={() => action({ value })}> |
||||||
|
ثبت |
||||||
|
<ArrowRightAltIcon /> |
||||||
|
</button> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const Row = (props) => { |
||||||
|
return ( |
||||||
|
<div className="message-2d__options--row d-flex"> |
||||||
|
{props.list.map((item) => ( |
||||||
|
<Item item={item} {...props} /> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const Item = (props) => { |
||||||
|
return ( |
||||||
|
<div |
||||||
|
onClick={() => props.handleRadioChange(props.item.name)} |
||||||
|
style={{ |
||||||
|
backgroundColor: |
||||||
|
props.item.name === props.value ? 'rgb(100, 205, 130)' : 'rgba(255, 255, 255, 0.4)', |
||||||
|
color: props.item.name === props.value ? 'white' : 'black', |
||||||
|
}} |
||||||
|
> |
||||||
|
{props.item.name} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,62 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import Grid from '@material-ui/core/Grid'; |
||||||
|
import Slider from '@material-ui/core/Slider'; |
||||||
|
import Input from '@material-ui/core/Input'; |
||||||
|
import ArrowRightAltIcon from '@material-ui/icons/ArrowRightAlt'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
import { toast } from 'react-toastify'; |
||||||
|
export default class SliderMessage extends Component { |
||||||
|
state = { |
||||||
|
value: this.props.message.value || 0, |
||||||
|
}; |
||||||
|
onChange = (value) => { |
||||||
|
if (!this.props.isActive || !value) return; |
||||||
|
const [min, max, step] = this.props.message.options[0] || [0, 100, 1]; |
||||||
|
this.setState({ value: Math.min(max, Math.max(min, parseFloat(value))) }); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { message, isActive, action } = this.props; |
||||||
|
const [min, max, step] = message.options[0] || [0, 100, 1]; |
||||||
|
const { value } = this.state; |
||||||
|
return ( |
||||||
|
<div className="message-2d d-flex flex-column d-flex sliderBox"> |
||||||
|
<Grid container spacing={2} alignItems="center"> |
||||||
|
<Grid item xs> |
||||||
|
<Slider |
||||||
|
className="slider" |
||||||
|
value={value} |
||||||
|
onChange={(e, value) => this.onChange(value)} |
||||||
|
aria-labelledby="input-slider" |
||||||
|
min={min} |
||||||
|
max={max} |
||||||
|
step={step} |
||||||
|
/> |
||||||
|
</Grid> |
||||||
|
<Grid item> |
||||||
|
<Input |
||||||
|
className="input" |
||||||
|
disabled={!isActive} |
||||||
|
value={this.state.value} |
||||||
|
onChange={(e) => this.onChange(e.target.value)} |
||||||
|
onBlur={() => this.onChange(value)} |
||||||
|
inputProps={{ |
||||||
|
step: step, |
||||||
|
min: min, |
||||||
|
max: max, |
||||||
|
type: 'number', |
||||||
|
'aria-labelledby': 'input-slider', |
||||||
|
}} |
||||||
|
/> |
||||||
|
</Grid> |
||||||
|
</Grid> |
||||||
|
{isActive && ( |
||||||
|
<button className="message-2d__submit" onClick={() => action()}> |
||||||
|
ثبت |
||||||
|
<ArrowRightAltIcon /> |
||||||
|
</button> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
.sliderBox { |
||||||
|
margin-top: 2px; |
||||||
|
.slider { |
||||||
|
margin-top: 10px; |
||||||
|
} |
||||||
|
input { |
||||||
|
width: 42px; |
||||||
|
border-bottom: 2px solid #000099; |
||||||
|
padding-left: 10px; |
||||||
|
margin-bottom: 18px; |
||||||
|
color: #000099; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
import React, { Component, useEffect } from 'react'; |
||||||
|
import { SortableContainer, SortableElement } from 'react-sortable-hoc'; |
||||||
|
import arrayMove from 'array-move'; |
||||||
|
import ArrowRightAltIcon from '@material-ui/icons/ArrowRightAlt'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
import { toast } from 'react-toastify'; |
||||||
|
|
||||||
|
export default class DraggableMessage extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = this.props.message; |
||||||
|
} |
||||||
|
onSortEnd = ({ oldIndex, newIndex }) => { |
||||||
|
if (this.props.isActive) |
||||||
|
this.setState(({ options }) => ({ |
||||||
|
options: arrayMove(options, oldIndex, newIndex), |
||||||
|
})); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { message, user, isSelf, isActive, action } = this.props; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="message-2d d-flex flex-column d-flex"> |
||||||
|
<SortableList items={this.state.options} onSortEnd={this.onSortEnd} disabled={!isActive} /> |
||||||
|
{isActive && ( |
||||||
|
<button className="message-2d__submit" onClick={() => action()}> |
||||||
|
ثبت |
||||||
|
<ArrowRightAltIcon /> |
||||||
|
</button> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const SortableList = SortableContainer(({ items, disabled }) => { |
||||||
|
return ( |
||||||
|
<div className="message-2d__options d-flex flex-column"> |
||||||
|
{items.map((row, index) => ( |
||||||
|
<SortableItem key={`item-${index}`} index={index} value={row} disabled={disabled} /> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
const SortableItem = SortableElement(({ value }) => ( |
||||||
|
<div className="message-2d__options--row d-flex"> |
||||||
|
{value.map((item) => ( |
||||||
|
<div>{item.name}</div> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
)); |
@ -0,0 +1,27 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import arrayMove from 'array-move'; |
||||||
|
import './index.scss'; |
||||||
|
|
||||||
|
export default class DraggableMessage extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = this.props.message; |
||||||
|
} |
||||||
|
onSortEnd = ({ oldIndex, newIndex }) => { |
||||||
|
if (this.props.isActive) |
||||||
|
this.setState(({ options }) => ({ |
||||||
|
options: arrayMove(options, oldIndex, newIndex), |
||||||
|
})); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { message, user, isSelf, isActive } = this.props; |
||||||
|
if (!isActive) return null; |
||||||
|
return <div className="ptapbox"></div>; |
||||||
|
} |
||||||
|
a = ( |
||||||
|
<button className="message-2d__submit" onClick={(e) => this.props.action({ value : e.target.value })}> |
||||||
|
ثبت |
||||||
|
</button> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
.tapbox { |
||||||
|
z-index: 500; |
||||||
|
position: absolute; |
||||||
|
left: -10px; |
||||||
|
background-color: #fff; |
||||||
|
width: 100vw; |
||||||
|
height: calc(100% - 90px); |
||||||
|
opacity: 0.1; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
.ptapbox { |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
position: absolute; |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import Normal from './Normal'; |
||||||
|
import Inline from './Inline'; |
||||||
|
import Sort from './Sort'; |
||||||
|
import Slider from './Slider'; |
||||||
|
import Select from './Select'; |
||||||
|
import MultiSelect from './MultiSelect'; |
||||||
|
import Tap from './Tap'; |
||||||
|
import ArrowRightAltIcon from '@material-ui/icons/ArrowRightAlt'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
const types = { |
||||||
|
sort: Sort, |
||||||
|
inline: Inline, |
||||||
|
slider: Slider, |
||||||
|
select: Select, |
||||||
|
multiselect: MultiSelect, |
||||||
|
tap: Tap, |
||||||
|
}; |
||||||
|
export default class Message extends Component { |
||||||
|
render() { |
||||||
|
const { message, user, isSelf, file, document, prevUserId, isActive, addcounter } = this.props; |
||||||
|
const Action = types[message.action]; |
||||||
|
return ( |
||||||
|
<div className="Message"> |
||||||
|
<Normal |
||||||
|
addcounter={addcounter} |
||||||
|
message={message} |
||||||
|
prevUserId={prevUserId} |
||||||
|
user={user} |
||||||
|
isSelf={isSelf} |
||||||
|
file={file} |
||||||
|
document={document} |
||||||
|
> |
||||||
|
{Action ? ( |
||||||
|
<Action message={message} isSelf={isSelf} isActive={isActive} action={addcounter} /> |
||||||
|
) : null} |
||||||
|
{/* {isActive && ( |
||||||
|
<button className="message-2d__submit" onClick={() => action({ value })}> |
||||||
|
ثبت |
||||||
|
<ArrowRightAltIcon /> |
||||||
|
</button> |
||||||
|
)} */} |
||||||
|
</Normal> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.Message { |
||||||
|
margin-top: 2px; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,493 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import Message from './Message'; |
||||||
|
import ChatInputs from './Input'; |
||||||
|
import Keyboard from './Keyboard'; |
||||||
|
import { RecordState } from 'audio-react-recorder'; |
||||||
|
import ReactPlayer from 'react-player'; |
||||||
|
import ReactAudioPlayer from 'react-audio-player'; |
||||||
|
import { ToastContainer } from 'react-toastify'; |
||||||
|
import { list, send, sendKeys } from '../../../Redux/actions/message'; |
||||||
|
import { info, bio } from '../../../Redux/actions/chat'; |
||||||
|
import { connect } from 'react-redux'; |
||||||
|
import Emoji from './Emoji/index'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
class List extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
emoji: false, |
||||||
|
counter: 1, |
||||||
|
id: window.location.href.split('/').pop() * 1, |
||||||
|
data: {}, |
||||||
|
message: '', |
||||||
|
voice: null, |
||||||
|
file: null, |
||||||
|
image: null, |
||||||
|
video: null, |
||||||
|
music: null, |
||||||
|
document: null, |
||||||
|
}; |
||||||
|
} |
||||||
|
addcounter(type) { |
||||||
|
if (type === 'parent') { |
||||||
|
if (localStorage.getItem('tapType') === 'nothing') { |
||||||
|
localStorage.removeItem('tapType'); |
||||||
|
return; |
||||||
|
} else { |
||||||
|
this.setState({ counter: this.state.counter + 1 }); |
||||||
|
} |
||||||
|
} else { |
||||||
|
localStorage.setItem('tapType', 'nothing'); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
start = () => { |
||||||
|
this.setState({ |
||||||
|
voice: RecordState.START, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
stop = () => { |
||||||
|
this.setState({ |
||||||
|
voice: RecordState.STOP, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
//audioData contains blob and blobUrl
|
||||||
|
onStop = (audioData) => { |
||||||
|
this.setState({ |
||||||
|
voice: audioData, |
||||||
|
}); |
||||||
|
this.sendVoice(audioData); |
||||||
|
}; |
||||||
|
|
||||||
|
cancel = () => { |
||||||
|
this.setState({ |
||||||
|
voice: null, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
typeText = (type,val) => { |
||||||
|
if(type === 'text'){ |
||||||
|
this.setState({ |
||||||
|
message: val, |
||||||
|
}); |
||||||
|
} |
||||||
|
else{ |
||||||
|
this.setState(prevState => ({ |
||||||
|
message: prevState.message + val , |
||||||
|
})); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
addFile = async (e) => { |
||||||
|
if ( |
||||||
|
e.target.files[0].type === 'image/apng' || |
||||||
|
e.target.files[0].type === 'image/avif' || |
||||||
|
e.target.files[0].type === 'image/gif' || |
||||||
|
e.target.files[0].type === 'image/jpeg' || |
||||||
|
e.target.files[0].type === 'image/png' || |
||||||
|
e.target.files[0].type === 'image/svg+xml' || |
||||||
|
e.target.files[0].type === 'image/webp' |
||||||
|
) { |
||||||
|
this.setState({ |
||||||
|
image: URL.createObjectURL(e.target.files[0]), |
||||||
|
file: 'fill', |
||||||
|
video: null, |
||||||
|
document: null, |
||||||
|
music: null, |
||||||
|
}); |
||||||
|
} else if ( |
||||||
|
e.target.files[0].type === 'video/3gpp' || |
||||||
|
e.target.files[0].type === 'video/mpeg' || |
||||||
|
e.target.files[0].type === 'video/mp4' || |
||||||
|
e.target.files[0].type === 'video/ogg' || |
||||||
|
e.target.files[0].type === 'video/quicktime' || |
||||||
|
e.target.files[0].type === 'video/webm' |
||||||
|
) { |
||||||
|
this.setState({ |
||||||
|
image: null, |
||||||
|
file: 'fill', |
||||||
|
video: URL.createObjectURL(e.target.files[0]), |
||||||
|
document: null, |
||||||
|
music: null, |
||||||
|
}); |
||||||
|
} else if ( |
||||||
|
e.target.files[0].type === 'audio/3gpp' || |
||||||
|
e.target.files[0].type === 'audio/aac' || |
||||||
|
e.target.files[0].type === 'audio/flac' || |
||||||
|
e.target.files[0].type === 'audio/mpeg' || |
||||||
|
e.target.files[0].type === 'audio/mp3' || |
||||||
|
e.target.files[0].type === 'audio/mp4' || |
||||||
|
e.target.files[0].type === 'audio/ogg' || |
||||||
|
e.target.files[0].type === 'audio/wav' || |
||||||
|
e.target.files[0].type === 'audio/webm' |
||||||
|
) { |
||||||
|
this.setState({ |
||||||
|
image: null, |
||||||
|
file: 'fill', |
||||||
|
video: null, |
||||||
|
document: null, |
||||||
|
music: URL.createObjectURL(e.target.files[0]), |
||||||
|
}); |
||||||
|
} else { |
||||||
|
this.setState({ |
||||||
|
image: null, |
||||||
|
file: 'fill', |
||||||
|
video: null, |
||||||
|
music: null, |
||||||
|
document: { data: URL.createObjectURL(e.target.files[0]), name: e.target.files[0].name }, |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
sendMessage = () => { |
||||||
|
if (this.state.file !== null) { |
||||||
|
this.sendFile(); |
||||||
|
return; |
||||||
|
} else { |
||||||
|
let now = new Date(); |
||||||
|
this.setState((prevState) => ({ |
||||||
|
data: { |
||||||
|
...prevState.data, |
||||||
|
messages: [ |
||||||
|
...prevState.data.messages, |
||||||
|
{ |
||||||
|
id: 'm12', |
||||||
|
type: 'normal', |
||||||
|
text: prevState.message, |
||||||
|
voice: null, |
||||||
|
image: null, |
||||||
|
file: null, |
||||||
|
video: null, |
||||||
|
music: null, |
||||||
|
document: null, |
||||||
|
createdAt: now.toString(), |
||||||
|
user: { |
||||||
|
id: 'u1', |
||||||
|
name: 'علی', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
})); |
||||||
|
this.setState({ |
||||||
|
message: '', |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
sendVoice = (audioData) => { |
||||||
|
let now = new Date(); |
||||||
|
this.setState((prevState) => ({ |
||||||
|
data: { |
||||||
|
...prevState.data, |
||||||
|
messages: [ |
||||||
|
...prevState.data.messages, |
||||||
|
{ |
||||||
|
id: 'm9', |
||||||
|
text: null, |
||||||
|
type: 'normal', |
||||||
|
voice: audioData, |
||||||
|
createdAt: now.toString(), |
||||||
|
image: null, |
||||||
|
video: null, |
||||||
|
document: null, |
||||||
|
music: null, |
||||||
|
user: { |
||||||
|
id: 'u1', |
||||||
|
name: 'علی', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
})); |
||||||
|
this.setState({ |
||||||
|
voice: null, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
sendFile = () => { |
||||||
|
const { image, video, music, document } = this.state; |
||||||
|
let now = new Date(); |
||||||
|
if (image !== null) { |
||||||
|
this.setState((prevState) => ({ |
||||||
|
data: { |
||||||
|
...prevState.data, |
||||||
|
messages: [ |
||||||
|
...prevState.data.messages, |
||||||
|
{ |
||||||
|
id: 'm8', |
||||||
|
type: 'normal', |
||||||
|
text: prevState.message, |
||||||
|
voice: null, |
||||||
|
createdAt: now.toString(), |
||||||
|
image: image, |
||||||
|
video: null, |
||||||
|
document: null, |
||||||
|
music: null, |
||||||
|
user: { |
||||||
|
id: 'u1', |
||||||
|
name: 'علی', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
})); |
||||||
|
this.setState({ |
||||||
|
file: null, |
||||||
|
image: null, |
||||||
|
message: '', |
||||||
|
}); |
||||||
|
} else if (video !== null) { |
||||||
|
this.setState((prevState) => ({ |
||||||
|
data: { |
||||||
|
...prevState.data, |
||||||
|
messages: [ |
||||||
|
...prevState.data.messages, |
||||||
|
{ |
||||||
|
id: 'm8', |
||||||
|
type: 'normal', |
||||||
|
text: prevState.message, |
||||||
|
voice: null, |
||||||
|
createdAt: now.toString(), |
||||||
|
image: null, |
||||||
|
video: video, |
||||||
|
document: null, |
||||||
|
music: null, |
||||||
|
user: { |
||||||
|
id: 'u1', |
||||||
|
name: 'علی', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
})); |
||||||
|
this.setState({ |
||||||
|
file: null, |
||||||
|
video: null, |
||||||
|
message: '', |
||||||
|
}); |
||||||
|
} else if (music !== null) { |
||||||
|
this.setState((prevState) => ({ |
||||||
|
data: { |
||||||
|
...prevState.data, |
||||||
|
messages: [ |
||||||
|
...prevState.data.messages, |
||||||
|
{ |
||||||
|
id: 'm8', |
||||||
|
text: prevState.message, |
||||||
|
type: 'normal', |
||||||
|
voice: null, |
||||||
|
createdAt: now.toString(), |
||||||
|
image: null, |
||||||
|
video: null, |
||||||
|
document: null, |
||||||
|
music: music, |
||||||
|
user: { |
||||||
|
id: 'u1', |
||||||
|
name: 'علی', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
})); |
||||||
|
this.setState({ |
||||||
|
file: null, |
||||||
|
music: null, |
||||||
|
message: '', |
||||||
|
}); |
||||||
|
} else if (document !== null) { |
||||||
|
this.setState((prevState) => ({ |
||||||
|
data: { |
||||||
|
...prevState.data, |
||||||
|
messages: [ |
||||||
|
...prevState.data.messages, |
||||||
|
{ |
||||||
|
id: 'm8', |
||||||
|
text: prevState.message, |
||||||
|
type: 'normal', |
||||||
|
voice: null, |
||||||
|
|
||||||
|
createdAt: now.toString(), |
||||||
|
image: null, |
||||||
|
video: null, |
||||||
|
document: document, |
||||||
|
music: null, |
||||||
|
user: { |
||||||
|
id: 'u1', |
||||||
|
name: 'علی', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
})); |
||||||
|
this.setState({ |
||||||
|
file: null, |
||||||
|
document: null, |
||||||
|
message: '', |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
cancelSendFile = () => { |
||||||
|
this.setState({ |
||||||
|
file: null, |
||||||
|
document: null, |
||||||
|
message: '', |
||||||
|
image: null, |
||||||
|
video: null, |
||||||
|
voice: null, |
||||||
|
music: null, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
componentDidMount() { |
||||||
|
this.props.list({ chatId: this.state.id }); |
||||||
|
this.props.info({ id: this.state.id }); |
||||||
|
// this.componentDidUpdate();
|
||||||
|
} |
||||||
|
|
||||||
|
componentDidUpdate() { |
||||||
|
let chatroom = document.getElementById('chatroom'); |
||||||
|
chatroom.scrollTop = chatroom.scrollHeight + 40; |
||||||
|
} |
||||||
|
randomColor() { |
||||||
|
let hex = Math.floor(Math.random() * 0x999999); |
||||||
|
let color = '#' + hex.toString(16); |
||||||
|
|
||||||
|
return color; |
||||||
|
} |
||||||
|
render() { |
||||||
|
const { setPage, chatInfo, messageList: msaster, userId } = this.props; //last
|
||||||
|
const messageList = msaster.slice(0, this.state.counter); |
||||||
|
const last = messageList.slice(-1)[0] || {}; |
||||||
|
const userIdx = this.userIdx || {}; |
||||||
|
if (Object.keys(userIdx).length == 0) { |
||||||
|
chatInfo.users.map((e) => (userIdx[e.id] = { ...e, color: this.randomColor() })); |
||||||
|
this.userIdx = userIdx; |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="chat-body d-flex flex-column nobar " |
||||||
|
onClick={() => this.addcounter('parent')} |
||||||
|
> |
||||||
|
<div |
||||||
|
className="chat-body__content d-flex flex-column nobar" |
||||||
|
id="chatroom" |
||||||
|
style={{ |
||||||
|
paddingTop: 10, |
||||||
|
overflowX: 'hidden', |
||||||
|
overflowY: this.state.file !== null ? 'hidden' : 'scroll', |
||||||
|
paddingBottom: last.action === 'keyboard' ? 150 : 10, |
||||||
|
}} |
||||||
|
> |
||||||
|
{chatInfo.users && |
||||||
|
messageList.map((message, i) => |
||||||
|
this.state.image === null && |
||||||
|
this.state.music === null && |
||||||
|
this.state.video === null ? ( |
||||||
|
<Message |
||||||
|
addcounter={() => this.addcounter()} |
||||||
|
isActive={message.id == last.id} |
||||||
|
prevUserId={i > 0 ? messageList[i - 1].userId : 0} |
||||||
|
isSelf={new Set([101, 103, 106, 108, 110]).has(message.userId * 1)} |
||||||
|
key={message.id} |
||||||
|
file={this.state.image} |
||||||
|
document={this.state.document} |
||||||
|
message={message} |
||||||
|
user={userIdx[message.userId] || { id: 0, fileId: 0, name: 'null' }} |
||||||
|
/> |
||||||
|
) : null |
||||||
|
)} |
||||||
|
{this.state.image !== null ? ( |
||||||
|
<div className="chat-body__content--preview d-flex"> |
||||||
|
<img src={this.state.image} alt="" /> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{this.state.video !== null ? ( |
||||||
|
<div className="chat-body__content--preview d-flex"> |
||||||
|
<ReactPlayer url={this.state.video} controls /> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{this.state.music !== null ? ( |
||||||
|
<div className="chat-body__content--preview d-flex"> |
||||||
|
<ReactAudioPlayer src={this.state.music} controls /> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
{this.state.document !== null ? ( |
||||||
|
<div className="chat-body__content--confirm d-flex"> |
||||||
|
<div className="chat-body__content--confirm___box d-flex flex-column"> |
||||||
|
<p>{`ارسال (${this.state.document.name}) به ${this.props.info.title}؟`}</p> |
||||||
|
<div className="chat-body__content--confirm___box---options d-flex"> |
||||||
|
<button style={{ color: '#00ff00' }} onClick={() => this.sendFile()}> |
||||||
|
ارسال |
||||||
|
</button> |
||||||
|
<button style={{ color: '#ffffff' }} onClick={() => this.cancelSendFile()}> |
||||||
|
کنسل |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
|
<div |
||||||
|
className="chat-body__footer d-flex nobar d-flex flex-column" |
||||||
|
onClick={() => this.addcounter('nothing')} |
||||||
|
> |
||||||
|
{last.action == 'text' ? ( |
||||||
|
<ChatInputs |
||||||
|
addcounter={() => this.addcounter()} |
||||||
|
onStop={this.onStop} |
||||||
|
stop={this.stop} |
||||||
|
start={this.start} |
||||||
|
cancel={this.cancel} |
||||||
|
message={this.state.message} |
||||||
|
recordState={this.state.voice} |
||||||
|
typeText={this.typeText} |
||||||
|
sendMessage={this.sendMessage} |
||||||
|
addFile={this.addFile} |
||||||
|
file={this.state.file} |
||||||
|
parent={this} |
||||||
|
/> |
||||||
|
) : null} |
||||||
|
{last.action === 'keyboard' ? ( |
||||||
|
<Keyboard options={last.options} addcounter={() => this.addcounter()} /> |
||||||
|
) : null} |
||||||
|
{this.state.emoji ? ( |
||||||
|
<div className="chat-body__footer--emoji d-flex flex-column"> |
||||||
|
<Emoji typeText={this.typeText} /> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
|
<ToastContainer |
||||||
|
position="top-center" |
||||||
|
autoClose={1500} |
||||||
|
hideProgressBar={true} |
||||||
|
newestOnTop={true} |
||||||
|
closeOnClick |
||||||
|
rtl={true} |
||||||
|
pauseOnFocusLoss |
||||||
|
draggable |
||||||
|
pauseOnHover |
||||||
|
/> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
export default connect( |
||||||
|
(state) => { |
||||||
|
return { |
||||||
|
chatInfo: state.chat.info, |
||||||
|
userId: state.user.isLogin.id, |
||||||
|
messageList: state.message.list || [], |
||||||
|
last: state.message.list.slice(-1)[0] || {}, |
||||||
|
}; |
||||||
|
}, |
||||||
|
{ list, send, sendKeys, info, bio } |
||||||
|
)(List); |
@ -0,0 +1,139 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-body .MuiAvatar-circle { |
||||||
|
box-shadow: 0px 0px 0px 2px #fff; |
||||||
|
border: 3px solid #ffffff66; |
||||||
|
width: 60px; |
||||||
|
height: 60px; |
||||||
|
// top: 20px; |
||||||
|
z-index: 30; |
||||||
|
// font-family: 'IRANSansNumeralBold'; |
||||||
|
// & div { |
||||||
|
// font-family: 'IRANSansNumeralBold'; |
||||||
|
// } |
||||||
|
} |
||||||
|
|
||||||
|
.chat-body { |
||||||
|
background-color: rgb(210, 196, 214); |
||||||
|
// justify-content: flex-start; |
||||||
|
flex: 1; |
||||||
|
height: 100%; |
||||||
|
overflow-x: hidden; |
||||||
|
font-family: numeralLight; |
||||||
|
&__content { |
||||||
|
background: url(../../../assets/images/whatsapp.png); |
||||||
|
background-size: cover; |
||||||
|
padding: 0px 10px 0px; |
||||||
|
margin-bottom: 55px; |
||||||
|
height: 100%; |
||||||
|
min-height: 200px; |
||||||
|
position: relative; |
||||||
|
&--preview { |
||||||
|
position: absolute; |
||||||
|
bottom: 0px; |
||||||
|
left: 0px; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
background-color: rgb(210, 196, 214); |
||||||
|
z-index: 1000; |
||||||
|
& img { |
||||||
|
width: 100%; |
||||||
|
max-height: 400px; |
||||||
|
object-fit: scale-down; |
||||||
|
} |
||||||
|
} |
||||||
|
&--confirm { |
||||||
|
width: 100vw; |
||||||
|
height: 100vh; |
||||||
|
position: fixed; |
||||||
|
top: 0px; |
||||||
|
left: 0px; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
z-index: 300; |
||||||
|
&___box { |
||||||
|
position: relative; |
||||||
|
bottom: 50px; |
||||||
|
width: 100%; |
||||||
|
max-width: 250px; |
||||||
|
padding: 10px; |
||||||
|
// background: rgb(139, 73, 186); |
||||||
|
// background: linear-gradient(180deg, rgb(144, 73, 186) 0%, #64cd82 95%); |
||||||
|
text-align: right; |
||||||
|
direction: rtl; |
||||||
|
color: white; |
||||||
|
border-radius: 5px; |
||||||
|
box-shadow: 0px 0px 20px rgba(0, 0, 0, 1); |
||||||
|
font-size: 16px; |
||||||
|
&---options { |
||||||
|
justify-self: flex-end; |
||||||
|
align-self: flex-start; |
||||||
|
width: 110px; |
||||||
|
height: 40px; |
||||||
|
justify-content: space-between; |
||||||
|
& button { |
||||||
|
background-color: inherit; |
||||||
|
border: none; |
||||||
|
font-size: 14px; |
||||||
|
&:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&__footer { |
||||||
|
width: 100%; |
||||||
|
z-index: 1000; |
||||||
|
background-color: rgb(210, 196, 214); |
||||||
|
background: url(../../../assets/images/whatsapp.png); |
||||||
|
// box-shadow: 0px 0px 5px 2px #9d9595ad; |
||||||
|
background-size: cover; |
||||||
|
overflow-y: scroll; |
||||||
|
overflow-x: hidden; |
||||||
|
position: fixed; |
||||||
|
bottom: 0px; |
||||||
|
left: 0; |
||||||
|
padding-bottom: 5px; |
||||||
|
&--emoji{ |
||||||
|
margin-top: 5px; |
||||||
|
width: 100%; |
||||||
|
background-color: red; |
||||||
|
height: 250px; |
||||||
|
// justify-self: flex-end; |
||||||
|
// position: absolute; |
||||||
|
// bottom: 0px; |
||||||
|
// left: 0px; |
||||||
|
.MuiBox-root{ |
||||||
|
max-height : 202px; |
||||||
|
min-height: 160px; |
||||||
|
overflow-y: scroll; |
||||||
|
padding: 10px 10px 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiTab-root{ |
||||||
|
padding: 2px !important; |
||||||
|
min-height: 22px !important; |
||||||
|
min-width: 34px !important; |
||||||
|
font-size: 24px !important; |
||||||
|
margin-right: 10px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiTabs-root{ |
||||||
|
min-height: 28px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.PrivateTabIndicator-colorPrimary-7{ |
||||||
|
width : 34px !important; |
||||||
|
background-color: green !important; |
||||||
|
} |
||||||
|
|
||||||
|
.MuiPaper-elevation4{ |
||||||
|
box-shadow: none !important; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import Badge from '@material-ui/core/Badge'; |
||||||
|
import Avatar from '@material-ui/core/Avatar'; |
||||||
|
import { makeStyles, withStyles } from '@material-ui/core/styles'; |
||||||
|
|
||||||
|
const StyledBadge = withStyles((theme) => ({ |
||||||
|
badge: { |
||||||
|
backgroundColor: '#44b700', |
||||||
|
color: '#44b700', |
||||||
|
boxShadow: `0 0 0 2px ${theme.palette.background.paper}`, |
||||||
|
'&::after': { |
||||||
|
position: 'absolute', |
||||||
|
top: 0, |
||||||
|
left: 0, |
||||||
|
width: '100%', |
||||||
|
height: '100%', |
||||||
|
borderRadius: '50%', |
||||||
|
animation: '$ripple 1.2s infinite ease-in-out', |
||||||
|
border: '1px solid currentColor', |
||||||
|
content: '""', |
||||||
|
}, |
||||||
|
}, |
||||||
|
'@keyframes ripple': { |
||||||
|
'0%': { |
||||||
|
transform: 'scale(.8)', |
||||||
|
opacity: 1, |
||||||
|
}, |
||||||
|
'100%': { |
||||||
|
transform: 'scale(2.4)', |
||||||
|
opacity: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}))(Badge); |
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({ |
||||||
|
root: { |
||||||
|
display: 'flex', |
||||||
|
'& > *': { |
||||||
|
margin: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
})); |
||||||
|
|
||||||
|
export default function StatusAvatar(props) { |
||||||
|
const classes = useStyles(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={classes.root}> |
||||||
|
<StyledBadge> |
||||||
|
<Avatar style={{ width: 40, height: 40 }} alt="Remy Sharp" src={props.src} /> |
||||||
|
</StyledBadge> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
import React, { Component } from "react"; |
||||||
|
import MoreVertIcon from "@material-ui/icons/MoreVert"; |
||||||
|
import ArrowForwardIcon from "@material-ui/icons/ArrowForward"; |
||||||
|
import Menu from "@material-ui/core/Menu"; |
||||||
|
import MenuItem from "@material-ui/core/MenuItem"; |
||||||
|
import VideocamIcon from "@material-ui/icons/Videocam"; |
||||||
|
import StatusAvatar from "./Avatar/index.js"; |
||||||
|
import CallIcon from "@material-ui/icons/Call"; |
||||||
|
import { connect } from "react-redux"; |
||||||
|
|
||||||
|
import "./index.scss"; |
||||||
|
class Header extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
anchorEl: null, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
handleClick = (event) => { |
||||||
|
this.setState({ |
||||||
|
anchorEl: event.currentTarget, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
handleClose = () => { |
||||||
|
this.setState({ |
||||||
|
anchorEl: null, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
back = () => { |
||||||
|
window.history.back(); |
||||||
|
}; |
||||||
|
render() { |
||||||
|
const { page, setPage, chatInfo } = this.props; |
||||||
|
const { anchorEl } = this.state; |
||||||
|
return ( |
||||||
|
<div className="chat-header d-flex align-items-center"> |
||||||
|
<div className="d-flex align-items-center"> |
||||||
|
<ArrowForwardIcon |
||||||
|
onClick={() => |
||||||
|
page === "chatroom" ? this.back() : setPage("chatroom") |
||||||
|
} |
||||||
|
style={{ color: "white", width: 29, height: 29, marginTop: 4 }} |
||||||
|
/> |
||||||
|
<div |
||||||
|
onClick={() => setPage("info")} |
||||||
|
className="chat-header__info d-flex mr-1" |
||||||
|
> |
||||||
|
<StatusAvatar /> |
||||||
|
<div className="d-flex flex-column mr-1"> |
||||||
|
<h1>{chatInfo ? chatInfo.title : null}</h1> |
||||||
|
<span>{chatInfo ? chatInfo.subTitle : null}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<div className="d-flex align-items-center"> |
||||||
|
<MoreVertIcon |
||||||
|
aria-controls="simple-menu" |
||||||
|
aria-haspopup="true" |
||||||
|
onClick={this.handleClick} |
||||||
|
style={{ color: "white", width: 32, height: 32 }} |
||||||
|
/> |
||||||
|
{/* <VideocamIcon style={{ color: 'white', width: 30, height: 30, marginLeft: 8 }} /> |
||||||
|
<CallIcon style={{ color: 'white', width: 27, height: 27, marginLeft: 17 }} /> */} |
||||||
|
</div> |
||||||
|
<Menu |
||||||
|
id="simple-menu" |
||||||
|
anchorEl={anchorEl} |
||||||
|
keepMounted |
||||||
|
open={Boolean(anchorEl)} |
||||||
|
onClose={() => this.handleClose()} |
||||||
|
className="fontLight rtl" |
||||||
|
> |
||||||
|
<MenuItem |
||||||
|
className="fontLight menu" |
||||||
|
onClick={() => this.handleClose()} |
||||||
|
> |
||||||
|
پروفایل |
||||||
|
</MenuItem> |
||||||
|
<MenuItem |
||||||
|
className="fontLight menu" |
||||||
|
onClick={() => this.handleClose()} |
||||||
|
> |
||||||
|
حساب کاربری |
||||||
|
</MenuItem> |
||||||
|
<MenuItem |
||||||
|
className="fontLight menu" |
||||||
|
onClick={() => this.handleClose()} |
||||||
|
> |
||||||
|
خروج |
||||||
|
</MenuItem> |
||||||
|
</Menu> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default connect((state) => ({ chatInfo: state.chat.info }), {})(Header); |
@ -0,0 +1,31 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-header { |
||||||
|
height: 60px; |
||||||
|
width: 100%; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: flex-end; |
||||||
|
padding: 5px 5px 5px; |
||||||
|
position: relative; |
||||||
|
background-color: #128c7e; |
||||||
|
&__info { |
||||||
|
text-align: right; |
||||||
|
|
||||||
|
& h1 { |
||||||
|
font-size: 16px; |
||||||
|
color: white; |
||||||
|
margin: 0px; |
||||||
|
margin-bottom: 5px; |
||||||
|
font-weight: 600; |
||||||
|
} |
||||||
|
& span { |
||||||
|
color: white; |
||||||
|
font-size: 11px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.MuiMenu-paper { |
||||||
|
background: #00cba2; //rgb(63, 71, 67) !important; |
||||||
|
color: black !important; |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
export default class FileTabs extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
type: 'media', |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
setType = (val) => { |
||||||
|
this.setState({ |
||||||
|
type: val, |
||||||
|
}); |
||||||
|
}; |
||||||
|
render() { |
||||||
|
return ( |
||||||
|
<div className="file-tabs d-flex flex-column"> |
||||||
|
<div className="file-tabs__types d-flex"> |
||||||
|
<li |
||||||
|
style={{ |
||||||
|
borderBottom: this.state.type === 'media' ? '2px solid rgb(13, 84, 150)' : 'none', |
||||||
|
}} |
||||||
|
onClick={() => this.setType('media')} |
||||||
|
> |
||||||
|
Media |
||||||
|
</li> |
||||||
|
<li |
||||||
|
style={{ |
||||||
|
borderBottom: this.state.type === 'file' ? '2px solid rgb(13, 84, 150)' : 'none', |
||||||
|
}} |
||||||
|
onClick={() => this.setType('file')} |
||||||
|
> |
||||||
|
Files |
||||||
|
</li> |
||||||
|
<li |
||||||
|
style={{ |
||||||
|
borderBottom: this.state.type === 'link' ? '2px solid rgb(13, 84, 150)' : 'none', |
||||||
|
}} |
||||||
|
onClick={() => this.setType('link')} |
||||||
|
> |
||||||
|
Links |
||||||
|
</li> |
||||||
|
<li |
||||||
|
style={{ |
||||||
|
borderBottom: this.state.type === 'music' ? '2px solid rgb(13, 84, 150)' : 'none', |
||||||
|
}} |
||||||
|
onClick={() => this.setType('music')} |
||||||
|
> |
||||||
|
Music |
||||||
|
</li> |
||||||
|
<li |
||||||
|
style={{ |
||||||
|
borderBottom: this.state.type === 'voice' ? '2px solid rgb(13, 84, 150)' : 'none', |
||||||
|
}} |
||||||
|
onClick={() => this.setType('voice')} |
||||||
|
> |
||||||
|
Voice |
||||||
|
</li> |
||||||
|
</div> |
||||||
|
{this.state.type === 'media' ? ( |
||||||
|
<div className="file-tabs__media d-flex flex-wrap"> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
<div className="file-tabs__media--item"></div> |
||||||
|
</div> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.file-tabs { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
position: relative; |
||||||
|
direction: rtl; |
||||||
|
position: sticky; |
||||||
|
top: 0-5px; |
||||||
|
&__types { |
||||||
|
width: 100%; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
padding: 3px calc((100vw - 310px) / 2) 3px calc((100vw - 310px) / 2); |
||||||
|
direction: ltr; |
||||||
|
border-top: 8px solid rgb(13, 84, 150); |
||||||
|
margin-top: 20px; |
||||||
|
background-color: #128c7e; |
||||||
|
& li { |
||||||
|
font-size: 16px; |
||||||
|
list-style: none; |
||||||
|
font-weight: 600; |
||||||
|
} |
||||||
|
} |
||||||
|
&__media { |
||||||
|
width: 100%; |
||||||
|
overflow-y: scroll; |
||||||
|
padding-bottom: 52px; |
||||||
|
&--item { |
||||||
|
width: calc(100% / 3); |
||||||
|
height: calc(100vw / 3); |
||||||
|
border: 2px solid rgb(200, 183, 232); |
||||||
|
background-color: red; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import Carousel from 'react-elastic-carousel'; |
||||||
|
import CloseIcon from '@material-ui/icons/Close'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
|
||||||
|
export default function Gallery(props) { |
||||||
|
// const [state,setState] = useState({
|
||||||
|
|
||||||
|
// });
|
||||||
|
return ( |
||||||
|
<div className="gallery-modal d-flex justify-content align-items-center"> |
||||||
|
<div onClick={() => props.onClick(null)}> |
||||||
|
<CloseIcon |
||||||
|
style={{ color: 'red', width: 46, height: 46, position: 'absolute', right: 5, top: 20 }} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<Carousel itemsToShow={1} isRTL={true} enableTilt={false} showArrows={true}> |
||||||
|
{props.data.map((item, i) => ( |
||||||
|
<Image item={item} key={i} /> |
||||||
|
))} |
||||||
|
</Carousel> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const Image = (props) => { |
||||||
|
return <img style={{ maxHeight: '50%', maxWidth: '100vw' }} src={props.item.src} alt="" />; |
||||||
|
}; |
@ -0,0 +1,64 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.gallery-modal { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
background-color: #383737f1; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
top: 0; |
||||||
|
z-index: 700; |
||||||
|
.rec-carousel-wrapper { |
||||||
|
position: relative; |
||||||
|
bottom: 70px; |
||||||
|
} |
||||||
|
.rec-arrow { |
||||||
|
position: absolute; |
||||||
|
background: none; |
||||||
|
box-shadow: none; |
||||||
|
&:hover:enabled { |
||||||
|
background: none; |
||||||
|
box-shadow: none; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
} |
||||||
|
.rec-arrow-right { |
||||||
|
top: calc(50% - 20px); |
||||||
|
left: 0px; |
||||||
|
z-index: 800; |
||||||
|
} |
||||||
|
.rec-arrow-left { |
||||||
|
top: calc(50% - 20px); |
||||||
|
right: 0px; |
||||||
|
z-index: 800; |
||||||
|
} |
||||||
|
.rec-pagination { |
||||||
|
// display:none; |
||||||
|
z-index: 600; |
||||||
|
position: absolute; |
||||||
|
top: auto; |
||||||
|
bottom: -30px !important; |
||||||
|
// left: calc(50% - 20px) !important; |
||||||
|
& button { |
||||||
|
background-color: grey; |
||||||
|
margin: 2px !important; |
||||||
|
box-shadow: 0px 0px 0px rgba(255, 255, 255, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.rec-dot_active { |
||||||
|
background-color: white !important; |
||||||
|
color: white !important; |
||||||
|
// box-shadow: 0 0 1px rgba(255, 255, 255, 1) !important; |
||||||
|
} |
||||||
|
|
||||||
|
.Carousel-button-10 { |
||||||
|
background-color: white !important; |
||||||
|
} |
||||||
|
.rec-pagination { |
||||||
|
img { |
||||||
|
// width: 100vw; |
||||||
|
// max-height: 200px; |
||||||
|
// height: 100vh; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import ChatIcon from '@material-ui/icons/Chat'; |
||||||
|
import FileTabs from './FileTabs'; |
||||||
|
import Gallery from './Gallery'; |
||||||
|
import user2 from '../../../assets/images/user2.png'; |
||||||
|
|
||||||
|
import './index.scss'; |
||||||
|
export default class ChatInfo extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
gallery: null, |
||||||
|
user: { |
||||||
|
profileImages: [ |
||||||
|
{ id: 0, src: user2 }, |
||||||
|
{ id: 1, src: user2 }, |
||||||
|
{ id: 2, src: user2 }, |
||||||
|
{ id: 3, src: user2 }, |
||||||
|
], |
||||||
|
name: 'محسن محمدی', |
||||||
|
lastAct: '2 دقیقه پیش آنلاین بوده', |
||||||
|
bio: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد ', |
||||||
|
}, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
setGallery = (val) => { |
||||||
|
this.setState({ |
||||||
|
gallery: val, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { user, gallery } = this.state; |
||||||
|
return ( |
||||||
|
<div className="chat-info d-flex flex-column"> |
||||||
|
<div className="chat-info__image d-flex"> |
||||||
|
<img src={user.profileImages[0].src} onClick={() => this.setGallery('profile')} alt="" /> |
||||||
|
<div className="chat-info__image--float d-flex"> |
||||||
|
<ChatIcon style={{ color: 'white', width: 46, height: 46 }} /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className="chat-info__box d-flex flex-column"> |
||||||
|
<div className="chat-info__box--status d-flex flex-column"> |
||||||
|
<h1>{user.name}</h1> |
||||||
|
<p>{user.lastAct}</p> |
||||||
|
</div> |
||||||
|
<div className="chat-info__box--description d-flex"> |
||||||
|
<p>{user.bio}</p> |
||||||
|
</div> |
||||||
|
<FileTabs onClick={this.setGallery} /> |
||||||
|
</div> |
||||||
|
{gallery === 'profile' ? ( |
||||||
|
<Gallery data={user.profileImages} onClick={this.setGallery} /> |
||||||
|
) : null} |
||||||
|
{gallery === 'media' ? <Gallery data={null} /> : null} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-info { |
||||||
|
width: 100%; |
||||||
|
min-height: 100vh; |
||||||
|
position: relative; |
||||||
|
direction: rtl; |
||||||
|
&__image { |
||||||
|
width: 100%; |
||||||
|
background-color: rgb(82, 82, 82); |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
height: 290px; |
||||||
|
position: relative; |
||||||
|
& img { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
object-fit: cover; |
||||||
|
} |
||||||
|
&--float { |
||||||
|
position: absolute; |
||||||
|
width: 65px; |
||||||
|
height: 65px; |
||||||
|
bottom: -30px; |
||||||
|
right: 40px; |
||||||
|
background : #128c7e; |
||||||
|
padding: 5px; |
||||||
|
border-radius: 100px; |
||||||
|
z-index: 400; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
box-shadow: 0px 0px 50px rgba(36, 0, 72, 0.8); |
||||||
|
} |
||||||
|
} |
||||||
|
&__box { |
||||||
|
width: 100%; |
||||||
|
z-index: 100; |
||||||
|
height: calc(100% - 250px); |
||||||
|
background-color: #0ab8a3; |
||||||
|
direction: rtl; |
||||||
|
padding: 20px 0px 0px 0px; |
||||||
|
position: sticky; |
||||||
|
// transform: translateY(-40px); |
||||||
|
//top: -150px; |
||||||
|
overflow-y: scroll; |
||||||
|
overflow-x: hidden; |
||||||
|
z-index: 200; |
||||||
|
&::-webkit-scrollbar { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
&--status { |
||||||
|
width: 100%; |
||||||
|
align-items: flex-end; |
||||||
|
padding: 0px 30px; |
||||||
|
h1 { |
||||||
|
font-size: 19px; |
||||||
|
margin: 0; |
||||||
|
letter-spacing: -1px; |
||||||
|
font-family: IRANSansNumeralLight; |
||||||
|
color: black; |
||||||
|
font-weight: 100; |
||||||
|
} |
||||||
|
p { |
||||||
|
font-size: 14px; |
||||||
|
color: rgb(61, 61, 61); |
||||||
|
margin: 0px; |
||||||
|
} |
||||||
|
} |
||||||
|
&--description { |
||||||
|
width: 100%; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
margin-top: 20px; |
||||||
|
& p { |
||||||
|
width: 100%; |
||||||
|
max-width: 310px; |
||||||
|
text-align: justify; |
||||||
|
font-size: 12px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import Header from './Header'; |
||||||
|
import Body from './Body'; |
||||||
|
import Info from './Info'; |
||||||
|
import './index.scss'; |
||||||
|
export default class ChatRoom extends Component { |
||||||
|
constructor(props) { |
||||||
|
super(props); |
||||||
|
window.nav = this.nav.bind(this); |
||||||
|
this.state = { |
||||||
|
page: 'chatroom', |
||||||
|
}; |
||||||
|
} |
||||||
|
nav = (url) => { |
||||||
|
this.props.history.push(url); |
||||||
|
}; |
||||||
|
setPage = (val) => { |
||||||
|
this.setState({ |
||||||
|
page: val, |
||||||
|
}); |
||||||
|
}; |
||||||
|
render() { |
||||||
|
return ( |
||||||
|
<div className="chat-room d-flex flex-column"> |
||||||
|
<Header page={this.state.page} setPage={this.setPage} /> |
||||||
|
{this.state.page === 'chatroom' ? ( |
||||||
|
<> |
||||||
|
<Body setPage={this.setPage} /> |
||||||
|
</> |
||||||
|
) : ( |
||||||
|
<> |
||||||
|
<Info /> |
||||||
|
</> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
@media screen and (max-width: 4500px) { |
||||||
|
.chat-room { |
||||||
|
flex: 1; |
||||||
|
background: rgb(139, 73, 186); |
||||||
|
background: linear-gradient(180deg, rgb(144, 73, 186) 0%, #64cd82 22%); |
||||||
|
height: 100vh; |
||||||
|
overflow: hidden; |
||||||
|
width: 100vw; |
||||||
|
box-shadow: 0px 0px 40px rgba(145, 145, 145, 0.8); |
||||||
|
&__status { |
||||||
|
border-top-left-radius: 40px; |
||||||
|
border-top-right-radius: 40px; |
||||||
|
height: 150px; |
||||||
|
background: rgb(106, 103, 250); |
||||||
|
position: relative; |
||||||
|
align-items: center; |
||||||
|
justify-content: flex-start; |
||||||
|
h1 { |
||||||
|
font-size: 18px; |
||||||
|
margin: 0; |
||||||
|
letter-spacing: -1px; |
||||||
|
font-family: IRANSansNumeralLight; |
||||||
|
color: white; |
||||||
|
font-weight: 100; |
||||||
|
} |
||||||
|
p { |
||||||
|
font-size: 12px; |
||||||
|
color: white; |
||||||
|
margin: 0px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue