Proyectos de Subversion LeadersLinked - SPA

Rev

Rev 448 | Rev 679 | Ir a la última revisión | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 448 Rev 517
Línea 1... Línea 1...
1
import React, { memo, useEffect, useRef, useState } from "react";
1
import React, { memo, useEffect, useRef, useState } from 'react'
2
import { axios } from "../../utils";
2
import { axios } from '../../utils'
3
import { useForm } from "react-hook-form";
3
import { useForm } from 'react-hook-form'
4
import { useDispatch } from "react-redux";
4
import { useDispatch } from 'react-redux'
5
import { addNotification } from "../../redux/notification/notification.actions";
5
import { addNotification } from '../../redux/notification/notification.actions'
6
import parse from "html-react-parser";
6
import parse from 'html-react-parser'
7
import styled, { css } from "styled-components";
7
import styled, { css } from 'styled-components'
8
import SendIcon from "@mui/icons-material/Send";
8
import SendIcon from '@mui/icons-material/Send'
9
import IconButton from "@mui/material/IconButton";
9
import IconButton from '@mui/material/IconButton'
10
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
10
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
11
import AttachFileIcon from "@mui/icons-material/AttachFile";
11
import AttachFileIcon from '@mui/icons-material/AttachFile'
12
import InsertEmoticonIcon from "@mui/icons-material/InsertEmoticon";
12
import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon'
13
 
13
 
14
import Options from "../UI/Option";
14
import Options from '../UI/Option'
15
import Emojione from "./emojione/Emojione";
15
import Emojione from './emojione/Emojione'
16
import FileModal from "../modals/FileModal";
16
import FileModal from '../modals/FileModal'
17
import LoaderContainer from "../UI/LoaderContainer";
17
import LoaderContainer from '../UI/LoaderContainer'
18
import Spinner from "../UI/Spinner";
18
import Spinner from '../UI/Spinner'
-
 
19
import { Link } from 'react-router-dom'
Línea 19... Línea 20...
19
 
20
 
20
const StyledChatContainer = styled.div`
21
const StyledChatContainer = styled.div`
21
  background-color: var(--bg-color);
22
  background-color: var(--bg-color);
22
  border-radius: var(--border-radius);
23
  border-radius: var(--border-radius);
23
  border: 1px solid var(--border-primary);
24
  border: 1px solid var(--border-primary);
24
  height: 80vh;
25
  height: 80vh;
25
  display: flex;
26
  display: flex;
26
  flex-direction: column;
27
  flex-direction: column;
27
  flex-grow: 1;
28
  flex-grow: 1;
28
  padding: 0px 0px !important;
29
  padding: 0px 0px !important;
Línea 29... Línea 30...
29
`;
30
`
30
 
31
 
31
const StyledChatHeader = styled.div`
32
const StyledChatHeader = styled.div`
32
  align-items: center;
33
  align-items: center;
Línea 44... Línea 45...
44
    display: inline-flex;
45
    display: inline-flex;
Línea 45... Línea 46...
45
 
46
 
46
    @media (min-width: 768px) {
47
    @media (min-width: 768px) {
47
      display: none;
48
      display: none;
48
    }
-
 
49
   
49
    }
50
  }
50
  }
Línea 51... Línea 51...
51
`;
51
`
52
 
52
 
53
const StyledTitle = styled.h2`
53
const StyledTitle = styled.h2`
54
font-size: 16px;
54
  font-size: 16px;
55
font-weight: 600;
55
  font-weight: 600;
56
width: fit-content;
56
  width: fit-content;
57
max-width: 20ch;
57
  max-width: 20ch;
58
text-align: center;
-
 
Línea 59... Línea 58...
59
color: #1d315c;
58
  text-align: center;
60
 
59
  color: #1d315c;
61
 
60
 
62
  @media (min-width: 768px) {
61
  @media (min-width: 768px) {
Línea 63... Línea 62...
63
    max-width: 30ch;
62
    max-width: 30ch;
64
  }
63
  }
65
`;
64
`
66
 
65
 
67
const StyledMessageList = styled.div`
66
const StyledMessageList = styled.div`
68
  gap: 0.5rem;
67
  gap: 0.5rem;
69
  display: flex;
68
  display: flex;
70
  flex-direction: column-reverse;
69
  flex-direction: column-reverse;
Línea 71... Línea 70...
71
  height: -webkit-fill-available;
70
  height: -webkit-fill-available;
72
  padding: 0.5rem 0;
71
  padding: 0.5rem 0;
73
  overflow: auto;
72
  overflow: auto;
74
`;
73
`
Línea 119... Línea 118...
119
        align-self: flex-end;
118
        align-self: flex-end;
120
        background-color: #eee;
119
        background-color: #eee;
121
        border-radius: 10px 0px 10px 10px;
120
        border-radius: 10px 0px 10px 10px;
122
        margin-right: 0.5rem;
121
        margin-right: 0.5rem;
123
        color: #393939;
122
        color: #393939;
124
      `;
123
      `
125
    }
124
    }
126
    return css`
125
    return css`
127
      align-self: flex-start;
126
      align-self: flex-start;
128
      background-color: var(--chat-received);
127
      background-color: var(--chat-received);
129
      border-radius: 0 10px 10px 10px;
128
      border-radius: 0 10px 10px 10px;
130
      margin-left: 0.5rem;
129
      margin-left: 0.5rem;
131
    `;
130
    `
132
  }}
131
  }}
133
`;
132
`
Línea 134... Línea 133...
134
 
133
 
135
const StyledForm = styled.form`
134
const StyledForm = styled.form`
136
  border-top: 1px solid var(--border-primary);
135
  border-top: 1px solid var(--border-primary);
137
  padding: 0.5rem;
136
  padding: 0.5rem;
138
  position: relative;
137
  position: relative;
139
  display: flex;
138
  display: flex;
140
  justify-content: center;
139
  justify-content: center;
141
  align-items: center;
140
  align-items: center;
142
  gap: 0.5rem;
141
  gap: 0.5rem;
Línea 143... Línea 142...
143
`;
142
`
144
 
143
 
145
const StyledInput = styled.input`
144
const StyledInput = styled.input`
146
  border: none;
145
  border: none;
Línea 151... Línea 150...
151
  background: var(--bg-color-secondary);
150
  background: var(--bg-color-secondary);
Línea 152... Línea 151...
152
 
151
 
153
  &:focus {
152
  &:focus {
154
    background: var(--bg-color-secondary);
153
    background: var(--bg-color-secondary);
155
  }
154
  }
Línea 156... Línea 155...
156
`;
155
`
157
 
156
 
158
const StyledLoader = styled(LoaderContainer)`
157
const StyledLoader = styled(LoaderContainer)`
159
  max-height: 50px;
158
  max-height: 50px;
Línea 160... Línea 159...
160
  max-width: 50px;
159
  max-width: 50px;
161
`;
160
`
162
 
161
 
163
function messageAreEqual(oldProps, newProps) {
162
function messageAreEqual(oldProps, newProps) {
164
  return oldProps.message.id
163
  return oldProps.message.id
Línea 165... Línea 164...
165
    ? oldProps.message.id === newProps.message.id
164
    ? oldProps.message.id === newProps.message.id
166
    : oldProps.message.uuid === newProps.message.uuid;
165
    : oldProps.message.uuid === newProps.message.uuid
167
}
166
}
Línea 168... Línea 167...
168
 
167
 
169
const Chat = ({ children }) => {
168
const Chat = ({ children }) => {
170
  return <StyledChatContainer>{children}</StyledChatContainer>;
169
  return <StyledChatContainer>{children}</StyledChatContainer>
171
};
170
}
172
 
171
 
173
const Header = ({ children, options = [], onClose }) => {
172
const Header = ({ children, options = [], onClose }) => {
174
  return (
173
  return (
175
    <StyledChatHeader>
174
    <StyledChatHeader>
176
      <IconButton onClick={onClose}>
175
      <IconButton onClick={onClose}>
177
        <ArrowBackIcon />
176
        <ArrowBackIcon />
178
      </IconButton>
177
      </IconButton>
Línea 179... Línea 178...
179
      {children}
178
      {children}
180
      {!!options.length && <Options options={options} right="1rem" />}
179
      {!!options.length && <Options options={options} right="1rem" />}
181
    </StyledChatHeader>
180
    </StyledChatHeader>
182
  );
181
  )
Línea 183... Línea 182...
183
};
182
}
184
 
183
 
185
const Title = ({ children, url }) => {
184
const Title = ({ children, url }) => {
186
  if (!url) {
185
  if (!url) {
187
    return <StyledTitle>{children}</StyledTitle>;
186
    return <StyledTitle>{children}</StyledTitle>
188
  }
187
  }
Línea 189... Línea 188...
189
 
188
 
190
  return (
189
  return (
Línea 191... Línea 190...
191
    <a href={url} style={{ width: "fit-content" }}>
190
    <Link to={url} style={{ width: 'fit-content' }}>
192
      <StyledTitle>{children}</StyledTitle>
191
      <StyledTitle>{children}</StyledTitle>
Línea 193... Línea 192...
193
    </a>
192
    </Link>
194
  );
193
  )
195
};
194
}
Línea 196... Línea 195...
196
 
195
 
197
const List = ({ messages = [], onPagination, scrollRef, loading }) => {
196
const List = ({ messages = [], onPagination, scrollRef, loading }) => {
198
  const loadMoreEl = useRef(null);
197
  const loadMoreEl = useRef(null)
199
 
198
 
Línea 200... Línea 199...
200
  useEffect(() => {
199
  useEffect(() => {
201
    const observer = new IntersectionObserver(onPagination);
200
    const observer = new IntersectionObserver(onPagination)
202
 
201
 
203
    if (loadMoreEl.current) {
202
    if (loadMoreEl.current) {
Línea 219... Línea 218...
219
        <StyledLoader>
218
        <StyledLoader>
220
          <Spinner />
219
          <Spinner />
221
        </StyledLoader>
220
        </StyledLoader>
222
      )}
221
      )}
223
    </StyledMessageList>
222
    </StyledMessageList>
224
  );
223
  )
225
};
224
}
Línea 226... Línea 225...
226
 
225
 
227
// eslint-disable-next-line react/display-name
226
// eslint-disable-next-line react/display-name
228
const Message = memo(({ message }) => {
227
const Message = memo(({ message }) => {
229
  const senderName = (message) => {
228
  const senderName = (message) => {
230
    if (message.type === "group" && !message.u === 1) {
229
    if (message.type === 'group' && !message.u === 1) {
231
      return <span className="user_name">{message.user_name}</span>;
230
      return <span className="user_name">{message.user_name}</span>
232
    }
231
    }
Línea 233... Línea 232...
233
  };
232
  }
234
 
233
 
235
  const messagesContent = {
234
  const messagesContent = {
236
    text: (
235
    text: (
Línea 244... Línea 243...
244
    document: (
243
    document: (
245
      <a href={message.m || message.filename} download>
244
      <a href={message.m || message.filename} download>
246
        <img className="pdf" src="/images/extension/pdf.png" alt="pdf" />
245
        <img className="pdf" src="/images/extension/pdf.png" alt="pdf" />
247
      </a>
246
      </a>
248
    ),
247
    ),
249
  };
248
  }
Línea 250... Línea 249...
250
 
249
 
251
  return (
250
  return (
252
    <>
251
    <>
253
      {senderName(message)}
252
      {senderName(message)}
254
      <StyledMessage
253
      <StyledMessage
255
        send={message.u ? message.u === 1 : message.side === "left"}
254
        send={message.u ? message.u === 1 : message.side === 'left'}
256
      >
255
      >
257
        {messagesContent[message.mtype || message.type]}
256
        {messagesContent[message.mtype || message.type]}
258
        <label className="time">
257
        <label className="time">
259
          {!message.not_received && (
258
          {!message.not_received && (
260
            <i
259
            <i
261
              className="fa fa-check"
260
              className="fa fa-check"
262
              style={message.seen ? { color: "blue" } : { color: "gray" }}
261
              style={message.seen ? { color: 'blue' } : { color: 'gray' }}
263
            />
262
            />
264
          )}
263
          )}
265
          {message.time || message.date}
264
          {message.time || message.date}
266
        </label>
265
        </label>
267
      </StyledMessage>
266
      </StyledMessage>
268
    </>
267
    </>
269
  );
268
  )
Línea 270... Línea 269...
270
}, messageAreEqual);
269
}, messageAreEqual)
271
 
270
 
272
const SubmitForm = ({ sendUrl, uploadUrl, onSubmit: onComplete }) => {
271
const SubmitForm = ({ sendUrl, uploadUrl, onSubmit: onComplete }) => {
273
  const [showEmojione, setShowEmojione] = useState(false);
272
  const [showEmojione, setShowEmojione] = useState(false)
274
  const [isShowFileModal, setIsShowFileModal] = useState(false);
273
  const [isShowFileModal, setIsShowFileModal] = useState(false)
Línea 275... Línea 274...
275
  const [isSending, setIsSending] = useState(false);
274
  const [isSending, setIsSending] = useState(false)
Línea 276... Línea 275...
276
  const dispatch = useDispatch();
275
  const dispatch = useDispatch()
277
 
276
 
278
  const { handleSubmit, setValue, register, reset, getValues } = useForm();
277
  const { handleSubmit, setValue, register, reset, getValues } = useForm()
279
 
278
 
Línea 280... Línea 279...
280
  const onSubmit = handleSubmit(({ message }) => {
279
  const onSubmit = handleSubmit(({ message }) => {
281
    const formData = new FormData();
280
    const formData = new FormData()
Línea 282... Línea 281...
282
    // eslint-disable-next-line no-undef
281
    // eslint-disable-next-line no-undef
283
    formData.append("message", emojione.toShort(message));
282
    formData.append('message', emojione.toShort(message))
284
 
283
 
Línea 285... Línea 284...
285
    axios.post(sendUrl, formData).then((response) => {
284
    axios.post(sendUrl, formData).then((response) => {
286
      const { success, data } = response.data;
285
      const { success, data } = response.data
287
 
286
 
288
      if (!success) {
287
      if (!success) {
Línea 289... Línea 288...
289
        const errorMessage =
288
        const errorMessage =
290
          typeof data === "string" ? data : "Ha ocurrido un error";
289
          typeof data === 'string' ? data : 'Ha ocurrido un error'
291
 
290
 
292
        setShowEmojione(false);
291
        setShowEmojione(false)
293
        dispatch(addNotification({ style: "danger", msg: errorMessage }));
292
        dispatch(addNotification({ style: 'danger', msg: errorMessage }))
Línea 294... Línea 293...
294
        return;
293
        return
295
      }
294
      }
296
 
295
 
297
      setShowEmojione(false);
296
      setShowEmojione(false)
Línea 298... Línea 297...
298
      onComplete();
297
      onComplete()
299
      reset();
298
      reset()
300
    });
299
    })
301
  });
300
  })
302
 
301
 
303
  const sendFile = (file) => {
302
  const sendFile = (file) => {
304
    setIsSending(true);
303
    setIsSending(true)
305
    const formData = new FormData();
304
    const formData = new FormData()
306
    formData.append("file", file);
305
    formData.append('file', file)
307
 
306
 
Línea 308... Línea 307...
308
    axios
307
    axios
309
      .post(uploadUrl, formData)
308
      .post(uploadUrl, formData)
310
      .then(({ data: response }) => {
309
      .then(({ data: response }) => {
311
        const { success, data } = response;
310
        const { success, data } = response
312
        if (!success) {
311
        if (!success) {
Línea 313... Línea 312...
313
          const errorMessage =
312
          const errorMessage =
314
            typeof data === "string" ? data : "Ha ocurrido un error";
313
            typeof data === 'string' ? data : 'Ha ocurrido un error'
315
          dispatch(addNotification({ style: "success", msg: errorMessage }));
314
          dispatch(addNotification({ style: 'success', msg: errorMessage }))
Línea 316... Línea 315...
316
          return;
315
          return
317
        }
316
        }
318
 
317
 
Línea 319... Línea 318...
319
        toggleFileModal();
318
        toggleFileModal()
320
        onComplete();
319
        onComplete()
321
      })
320
      })
322
      .finally(() => setIsSending(false));
321
      .finally(() => setIsSending(false))
323
  };
322
  }
324
 
323
 
325
  const toggleEmojione = () => {
324
  const toggleEmojione = () => {
Línea 326... Línea 325...
326
    setShowEmojione(!showEmojione);
325
    setShowEmojione(!showEmojione)
327
  };
326
  }
328
 
327
 
329
  const toggleFileModal = () => {
328
  const toggleFileModal = () => {
Línea 363... Línea 362...
363
        onHide={toggleFileModal}
362
        onHide={toggleFileModal}
364
        onComplete={sendFile}
363
        onComplete={sendFile}
365
        loading={isSending}
364
        loading={isSending}
366
      />
365
      />
367
    </>
366
    </>
368
  );
367
  )
369
};
368
}
Línea 370... Línea 369...
370
 
369
 
371
Chat.Header = Header;
370
Chat.Header = Header
372
Chat.Title = Title;
371
Chat.Title = Title
373
Chat.List = List;
372
Chat.List = List
374
List.Message = Message;
373
List.Message = Message
Línea 375... Línea 374...
375
Chat.SubmitForm = SubmitForm;
374
Chat.SubmitForm = SubmitForm