reza added mobile chat

master
Reza_ashrafi 3 years ago
parent 607d02f340
commit 5915c72411
  1. 7
      package.json
  2. 11
      src/AppRouter.js
  3. 26
      src/Redux/actions/message.js
  4. 6
      src/Redux/proxy.js
  5. 32
      src/Redux/reducers/message.js
  6. BIN
      src/assets/images/whatsapp.png
  7. 22
      src/views/ChatList/Chat/index.js
  8. 72
      src/views/ChatList/Chat/index.scss
  9. 37
      src/views/ChatList/index.js
  10. 26
      src/views/ChatList/index.scss
  11. 224
      src/views/ChatRoom/Body/Emoji/index.js
  12. 0
      src/views/ChatRoom/Body/Emoji/index.scss
  13. 171
      src/views/ChatRoom/Body/Input/index.js
  14. 97
      src/views/ChatRoom/Body/Input/index.scss
  15. 32
      src/views/ChatRoom/Body/Keyboard/index.js
  16. 74
      src/views/ChatRoom/Body/Keyboard/index.scss
  17. 83
      src/views/ChatRoom/Body/Message/Comment/index.js
  18. 0
      src/views/ChatRoom/Body/Message/Comment/index.scss
  19. 46
      src/views/ChatRoom/Body/Message/Inline/index.js
  20. 101
      src/views/ChatRoom/Body/Message/Inline/index.scss
  21. 63
      src/views/ChatRoom/Body/Message/MultiSelect/index.js
  22. 245
      src/views/ChatRoom/Body/Message/Normal/index.js
  23. 155
      src/views/ChatRoom/Body/Message/Normal/index.scss
  24. 56
      src/views/ChatRoom/Body/Message/Select/index.js
  25. 0
      src/views/ChatRoom/Body/Message/Select/index.scss
  26. 62
      src/views/ChatRoom/Body/Message/Slider/index.js
  27. 13
      src/views/ChatRoom/Body/Message/Slider/index.scss
  28. 53
      src/views/ChatRoom/Body/Message/Sort/index.js
  29. 0
      src/views/ChatRoom/Body/Message/Sort/index.scss
  30. 27
      src/views/ChatRoom/Body/Message/Tap/index.js
  31. 15
      src/views/ChatRoom/Body/Message/Tap/index.scss
  32. 48
      src/views/ChatRoom/Body/Message/index.js
  33. 5
      src/views/ChatRoom/Body/Message/index.scss
  34. 493
      src/views/ChatRoom/Body/index.js
  35. 139
      src/views/ChatRoom/Body/index.scss
  36. 54
      src/views/ChatRoom/Header/Avatar/index.js
  37. 102
      src/views/ChatRoom/Header/index.js
  38. 31
      src/views/ChatRoom/Header/index.scss
  39. 90
      src/views/ChatRoom/Info/FileTabs/index.js
  40. 36
      src/views/ChatRoom/Info/FileTabs/index.scss
  41. 29
      src/views/ChatRoom/Info/Gallery/index.js
  42. 64
      src/views/ChatRoom/Info/Gallery/index.scss
  43. 60
      src/views/ChatRoom/Info/index.js
  44. 82
      src/views/ChatRoom/Info/index.scss
  45. 38
      src/views/ChatRoom/index.js
  46. 33
      src/views/ChatRoom/index.scss
  47. 155
      yarn.lock

@ -8,18 +8,25 @@
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"array-move": "^3.0.1",
"audio-react-recorder": "^1.0.4",
"axios": "^0.21.1", "axios": "^0.21.1",
"bootstrap": "^5.0.1", "bootstrap": "^5.0.1",
"jalali-moment": "^3.3.10", "jalali-moment": "^3.3.10",
"prettier": "^2.3.1", "prettier": "^2.3.1",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react": "^17.0.2", "react": "^17.0.2",
"react-audio-player": "^0.17.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-elastic-carousel": "^0.11.5", "react-elastic-carousel": "^0.11.5",
"react-leaflet": "^3.2.0",
"react-player": "^2.9.0",
"react-qr-scanner": "^1.0.0-alpha.7", "react-qr-scanner": "^1.0.0-alpha.7",
"react-redux": "^7.2.4", "react-redux": "^7.2.4",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-sortable-hoc": "^2.0.0",
"react-swipeable-views": "^0.14.0",
"react-toastify": "^7.0.4", "react-toastify": "^7.0.4",
"redux": "^4.1.0", "redux": "^4.1.0",
"redux-devtools-extension": "^2.13.9", "redux-devtools-extension": "^2.13.9",

@ -12,6 +12,8 @@ import QR from './views/QR/index';
import Auth from './views/Auth/index'; import Auth from './views/Auth/index';
import QRScan from './views/QRScan/index'; import QRScan from './views/QRScan/index';
import Activation from './views/Activation/index'; import Activation from './views/Activation/index';
import ChatList from './views/ChatList/index';
import Chatroom from './views/ChatRoom/index';
class AppRouter extends Component { class AppRouter extends Component {
constructor(props) { constructor(props) {
@ -64,6 +66,15 @@ class AppRouter extends Component {
<Route exact path={'/activation'}> <Route exact path={'/activation'}>
<Activation /> <Activation />
</Route> </Route>
<Route exact path={'/chatroom'}>
<ChatList />
</Route>
{
window.innerWidth < 1000 ?
<Route exact path={'/chatroom/:id'}>
<Chatroom />
</Route> : null
}
</Switch> </Switch>
</Router> </Router>
); );

@ -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,6 +1,6 @@
import axios from 'axios'; import axios from 'axios';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
const baseURL = 'https://chatstory.ir/api/v1'; //"https://chatstory.ir/api/v1"; const baseURL = 'https://chatstory.ir/api/v1'; //'https://chatstory.ir/api/v1';
const token = ''; const token = '';
const loginURL = 'user/otp/login'; const loginURL = 'user/otp/login';
const logoutURL = 'user/logout'; const logoutURL = 'user/logout';
@ -48,7 +48,7 @@ class Proxy {
localStorage.setItem('refresh', login.refreshToken); localStorage.setItem('refresh', login.refreshToken);
delete login.refreshToken; delete login.refreshToken;
localStorage.setItem('userData', JSON.stringify(login)); localStorage.setItem('userData', JSON.stringify(login));
if (data !== {}) window.router.setState({ islogin: true }); if (data != {}) window.router.setState({ islogin: true });
return this.result('login', login); return this.result('login', login);
}; };
logout = async () => { logout = async () => {
@ -62,7 +62,7 @@ class Proxy {
let refresh = localStorage.getItem('refresh'); let refresh = localStorage.getItem('refresh');
let userData = localStorage.getItem('userData'); let userData = localStorage.getItem('userData');
if (!refresh) return false; if (!refresh) return false;
if (refresh === 'undefined') { if (refresh == 'undefined') {
localStorage.removeItem('refresh'); localStorage.removeItem('refresh');
localStorage.removeItem('userData'); localStorage.removeItem('userData');
return false; return false;

@ -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;
// } }
// } }

Binary file not shown.

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,224 @@
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
import './index.scss';
const Smileys = [
'😃',
'😃',
'😄',
'😁',
'😆',
'😅',
'😂',
'🤣',
'🥲',
'☺',
'😊',
'😇',
'🙂',
'🙃',
'😉',
'😌',
'😍',
'🥰',
'😘',
'😗',
'😙',
'😚',
'😋',
'😛',
'😝',
'😜',
'🤪',
'🤨',
'🧐',
'🤓',
'😎',
'🥸',
'🤩',
'🥳',
'😏',
'😒',
'😞',
'😔',
'😟',
'😕',
'🙁',
'☹',
'😣',
'😖',
'😫',
'😩',
'🥺',
'😢',
'😭',
'😤',
'😠',
'😡',
'🤬',
'🤯',
'😳',
'🥵',
'🥶',
'😱',
'😨',
'😰',
'😥',
'😓',
'🤗',
'🤔',
'🤭',
'🤫',
'🤥',
'😶',
'😐',
'😑',
'😬',
'🙄',
'😯',
'😦',
'😧',
'😮',
'😲',
'🥱',
'😴',
'🤤',
'😪',
'😵',
'🤐',
'🥴',
'🤢',
'🤮',
'🤧',
'😷',
'🤒',
'🤕',
'🤑',
'🤠',
'😈',
'👿',
'👹',
'👺',
'🤡',
'💩',
'👻',
'💀',
'☠',
'👽',
'👾',
'🤖',
'🎃',
'😺',
'😸',
'😹',
'😻',
'😼',
'😽',
'🙀',
'😿',
'😾',
];
const animals = [
'🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐻', '🐨', '🐯', '🦁', '🐮', '🐷', '🐽', '🐸', '🐵', '🙈', '🙉', '🙊', '🐒', '🐔', '🐧', '🐦', '🐤', '🐣', '🐥', '🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🪱', '🐛', '🦋', '🐌', '🐞', '🐜', '🪰', '🪲', '🪳', '🦟', '🦗', '🕷', '🕸', '🦂', '🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦞', '🦀', '🐡', '🐠', '🐟', '🐬', '🐳', '🐋', '🦈', '🐊', '🐅', '🐆', '🦓', '🦍', '🦧', '🦣', '🐘', '🦛', '🦏', '🐪', '🐫', '🦒', '🦘', '🦬', '🐃', '🐂', '🐄', '🐎', '🐖', '🐏', '🐑', '🦙', '🐐', '🦌', '🐕', '🐩', '🦮', '🐕🦺', '🐈', '🐈⬛', '🪶', '🐓', '🦃', '🦤', '🦚', '🦜', '🦢', '🦩', '🕊', '🐇', '🦝', '🦨', '🦡', '🦫', '🦦', '🦥', '🐁', '🐀', '🐿', '🦔', '🐾', '🐉', '🐲', '🌵', '🎄', '🌲', '🌳', '🌴', '🪵', '🌱', '🌿', '☘', '🍀', '🎍', '🪴', '🎋', '🍃', '🍂', '🍁', '🍄', '🐚', '🪨', '🌾', '💐', '🌷', '🌹', '🥀', '🌺', '🌸', '🌼', '🌻', '🌞', '🌝', '🌛', '🌜', '🌚', '🌕', '🌖', '🌗', '🌘', '🌑', '🌒', '🌓', '🌔', '🌙', '🌎', '🌍', '🌏', '🪐 ', '💫', '⭐', '🌟', '✨', '⚡', '☄', '💥', '🔥', '🌪', '🌈', '☀', '🌤', '⛅', '🌥', '☁', '🌦', '🌧', '⛈', '🌩', '🌨', '❄', '☃', '⛄', '🌬', '💨', '💧', '💦', '☔', '☂', '🌊', '🌫'
];
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`scrollable-force-tabpanel-${index}`}
aria-labelledby={`scrollable-force-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `scrollable-force-tab-${index}`,
'aria-controls': `scrollable-force-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
flexDirection: 'row-reverse'
},
list: {
flex: 1,
width: '100%',
flexDirection: 'row-reverse'
},
}));
export default function ScrollableTabsButtonForce(props) {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
console.log(props.emojies[0]);
return (
<div className={classes.root}>
<AppBar position="static" color="default">
<Tabs
value={value}
onChange={handleChange}
variant="scrollable"
scrollButtons="on"
indicatorColor="primary"
textColor="primary"
aria-label="scrollable force tabs example"
>
{props.emojies.map((item) => (
<Tab label="" icon={item.list[0]} {...a11yProps(item.id)} />
))}
</Tabs>
</AppBar>
{props.emojies.map((item) => (
<TabPanel value={value} index={item.id}>
<div className="d-flex flex-wrap">
{item.list.map((jojo,i) => (
<span value={jojo} onClick={() => props.typeText('emoji',jojo)} style={{fontSize: 24, width: 30, height:30 }} className="m-1">{jojo}</span>
))}
</div>
</TabPanel>
))}
</div>
);
}
ScrollableTabsButtonForce.defaultProps = {
emojies: [
{ type: 'Smileys', list: Smileys, id: 0 },
{ type: 'Animals', list: animals, id: 1 },
],
};

@ -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;
}
}
}
}

@ -1150,6 +1150,13 @@
core-js-pure "^3.14.0" core-js-pure "^3.14.0"
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==
dependencies:
regenerator-runtime "^0.12.0"
"@babel/runtime@7.12.1": "@babel/runtime@7.12.1":
version "7.12.1" version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
@ -1164,6 +1171,13 @@
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.2.0":
version "7.14.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.10.4", "@babel/template@^7.14.5", "@babel/template@^7.3.3": "@babel/template@^7.10.4", "@babel/template@^7.14.5", "@babel/template@^7.3.3":
version "7.14.5" version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
@ -1592,6 +1606,11 @@
schema-utils "^2.6.5" schema-utils "^2.6.5"
source-map "^0.7.3" source-map "^0.7.3"
"@react-leaflet/core@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@react-leaflet/core/-/core-1.1.0.tgz#389b2b373f1da4caeb3c4cf6f33d84561c58d504"
integrity sha512-zFxMHgfjCi7khRVB7o7H8NoJl36NaezvfcaeEurVXx22lAGHFlTHiSuLOGA4tOiHj+Ep+Lo3uwUGJ3YM9BGkHg==
"@rollup/plugin-node-resolve@^7.1.1": "@rollup/plugin-node-resolve@^7.1.1":
version "7.1.3" version "7.1.3"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca" resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca"
@ -2563,6 +2582,11 @@ array-includes@^3.1.1, array-includes@^3.1.2, array-includes@^3.1.3:
get-intrinsic "^1.1.1" get-intrinsic "^1.1.1"
is-string "^1.0.5" is-string "^1.0.5"
array-move@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/array-move/-/array-move-3.0.1.tgz#179645cc0987b65953a4fc06b6df9045e4ba9618"
integrity sha512-H3Of6NIn2nNU1gsVDqDnYKY/LCdWvCMMOWifNGhKcVQgiZ6nOek39aESOvro6zmueP07exSl93YLvkN4fZOkSg==
array-union@^1.0.1: array-union@^1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@ -2679,6 +2703,13 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
audio-react-recorder@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/audio-react-recorder/-/audio-react-recorder-1.0.4.tgz#db81f10286c2252af8d42162e1f49dbd1de0dffd"
integrity sha512-an7eX0yOGDbZOSu2LvnfWIsI41pkx9nXgtBVbI+9ByS91WKqoVGVb5pbmqHax5sZty2DjOIG/neuxcghIU/ucg==
dependencies:
prop-types "^15.7.2"
autoprefixer@^9.6.1: autoprefixer@^9.6.1:
version "9.8.6" version "9.8.6"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
@ -4217,7 +4248,7 @@ deep-is@^0.1.3, deep-is@~0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
deepmerge@^4.2.2: deepmerge@^4.0.0, deepmerge@^4.2.2:
version "4.2.2" version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
@ -6078,6 +6109,13 @@ internal-slot@^1.0.3:
has "^1.0.3" has "^1.0.3"
side-channel "^1.0.4" side-channel "^1.0.4"
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
ip-regex@^2.1.0: ip-regex@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@ -7141,6 +7179,11 @@ jss@10.6.0, jss@^10.5.1:
array-includes "^3.1.2" array-includes "^3.1.2"
object.assign "^4.1.2" object.assign "^4.1.2"
keycode@^2.1.7:
version "2.2.0"
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=
killable@^1.0.1: killable@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@ -7236,6 +7279,11 @@ load-json-file@^4.0.0:
pify "^3.0.0" pify "^3.0.0"
strip-bom "^3.0.0" strip-bom "^3.0.0"
load-script@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4"
integrity sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=
loader-runner@^2.4.0: loader-runner@^2.4.0:
version "2.4.0" version "2.4.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
@ -7351,7 +7399,7 @@ loglevel@^1.6.8:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -7449,6 +7497,11 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
memoize-one@^5.1.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
memory-fs@^0.4.1: memory-fs@^0.4.1:
version "0.4.1" version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@ -9220,7 +9273,7 @@ prompts@^2.0.1:
kleur "^3.0.3" kleur "^3.0.3"
sisteransi "^1.0.5" sisteransi "^1.0.5"
prop-types@^15.6.2, prop-types@^15.7.2: prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -9391,6 +9444,13 @@ react-app-polyfill@^2.0.0:
regenerator-runtime "^0.13.7" regenerator-runtime "^0.13.7"
whatwg-fetch "^3.4.1" whatwg-fetch "^3.4.1"
react-audio-player@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/react-audio-player/-/react-audio-player-0.17.0.tgz#4be7b1952512801f36ba0865a9c98f7b108f991e"
integrity sha512-aCZgusPxA9HK7rLZcTdhTbBH9l6do9vn3NorgoDZRxRxJlOy9uZWzPaKjd7QdcuP2vXpxGA/61JMnnOEY7NXeA==
dependencies:
prop-types "^15.7.2"
react-dev-utils@^11.0.3: react-dev-utils@^11.0.3:
version "11.0.4" version "11.0.4"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a"
@ -9445,6 +9505,20 @@ react-error-overlay@^6.0.9:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
react-event-listener@^0.6.0:
version "0.6.6"
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.6.tgz#758f7b991cad9086dd39fd29fad72127e1d8962a"
integrity sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==
dependencies:
"@babel/runtime" "^7.2.0"
prop-types "^15.6.0"
warning "^4.0.1"
react-fast-compare@^3.0.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@ -9455,11 +9529,29 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-leaflet@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-3.2.0.tgz#8d5d05beab3f9e52665738ad737bb7b1da99f30b"
integrity sha512-eHVqoRGjW8T9GxLt7jyTKP3BDQ7XQ5AD+tc/zkbaABn1dbmREDy8GojNcYjZQa3QFLQoOLQMcUC1PTtzytZpUA==
dependencies:
"@react-leaflet/core" "^1.1.0"
react-only-when@^1.0.2: react-only-when@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/react-only-when/-/react-only-when-1.0.2.tgz#a8a79b48dd6cfbd91ddc710674a94153e88039d3" resolved "https://registry.yarnpkg.com/react-only-when/-/react-only-when-1.0.2.tgz#a8a79b48dd6cfbd91ddc710674a94153e88039d3"
integrity sha512-agE6l3L6bqaVuwNtjihTQ36M+VBfPS63KOzcNL4ZTmlwSxQPvhzIqmBWfiol0/wLYmKxCcBqgXkEJpvj5Kob8Q== integrity sha512-agE6l3L6bqaVuwNtjihTQ36M+VBfPS63KOzcNL4ZTmlwSxQPvhzIqmBWfiol0/wLYmKxCcBqgXkEJpvj5Kob8Q==
react-player@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-player/-/react-player-2.9.0.tgz#ef7fe7073434087565f00ff219824e1e02c4b046"
integrity sha512-jNUkTfMmUhwPPAktAdIqiBcVUKsFKrVGH6Ocutj6535CNfM91yrvWxHg6fvIX8Y/fjYUPoejddwh7qboNV9vGA==
dependencies:
deepmerge "^4.0.0"
load-script "^1.0.0"
memoize-one "^5.1.1"
prop-types "^15.7.2"
react-fast-compare "^3.0.1"
react-qr-scanner@^1.0.0-alpha.7: react-qr-scanner@^1.0.0-alpha.7:
version "1.0.0-alpha.7" version "1.0.0-alpha.7"
resolved "https://registry.yarnpkg.com/react-qr-scanner/-/react-qr-scanner-1.0.0-alpha.7.tgz#f63993cffe238f8cbca4984d03973accc842500b" resolved "https://registry.yarnpkg.com/react-qr-scanner/-/react-qr-scanner-1.0.0-alpha.7.tgz#f63993cffe238f8cbca4984d03973accc842500b"
@ -9580,6 +9672,46 @@ react-scripts@4.0.3:
optionalDependencies: optionalDependencies:
fsevents "^2.1.3" fsevents "^2.1.3"
react-sortable-hoc@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-2.0.0.tgz#f6780d8aa4b922a21f3e754af542f032677078b7"
integrity sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==
dependencies:
"@babel/runtime" "^7.2.0"
invariant "^2.2.4"
prop-types "^15.5.7"
react-swipeable-views-core@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.14.0.tgz#6ac443a7cc7bc5ea022fbd549292bb5fff361cce"
integrity sha512-0W/e9uPweNEOSPjmYtuKSC/SvKKg1sfo+WtPdnxeLF3t2L82h7jjszuOHz9C23fzkvLfdgkaOmcbAxE9w2GEjA==
dependencies:
"@babel/runtime" "7.0.0"
warning "^4.0.1"
react-swipeable-views-utils@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.14.0.tgz#6b76e251906747482730c22002fe47ab1014ba32"
integrity sha512-W+fXBOsDqgFK1/g7MzRMVcDurp3LqO3ksC8UgInh2P/tKgb5DusuuB1geKHFc6o1wKl+4oyER4Zh3Lxmr8xbXA==
dependencies:
"@babel/runtime" "7.0.0"
keycode "^2.1.7"
prop-types "^15.6.0"
react-event-listener "^0.6.0"
react-swipeable-views-core "^0.14.0"
shallow-equal "^1.2.1"
react-swipeable-views@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.14.0.tgz#149c0df3d92220cc89e3f6d5c04a78dfe46f9b54"
integrity sha512-wrTT6bi2nC3JbmyNAsPXffUXLn0DVT9SbbcFr36gKpbaCgEp7rX/OFxsu5hPc/NBsUhHyoSRGvwqJNNrWTwCww==
dependencies:
"@babel/runtime" "7.0.0"
prop-types "^15.5.4"
react-swipeable-views-core "^0.14.0"
react-swipeable-views-utils "^0.14.0"
warning "^4.0.1"
react-swipeable@^5.5.1: react-swipeable@^5.5.1:
version "5.5.1" version "5.5.1"
resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-5.5.1.tgz#48ae6182deaf62f21d4b87469b60281dbd7c4a76" resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-5.5.1.tgz#48ae6182deaf62f21d4b87469b60281dbd7c4a76"
@ -9735,6 +9867,11 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.12.0:
version "0.12.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
version "0.13.7" version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
@ -10306,6 +10443,11 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1" inherits "^2.0.1"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
shallow-equal@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
shallowequal@^1.1.0: shallowequal@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
@ -11511,6 +11653,13 @@ walker@^1.0.7, walker@~1.0.5:
dependencies: dependencies:
makeerror "1.0.x" makeerror "1.0.x"
warning@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
watchpack-chokidar2@^2.0.1: watchpack-chokidar2@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"

Loading…
Cancel
Save