Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 6922 | Rev 6927 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
6911 stevensc 1
import React, { useEffect, useRef, useState } from 'react'
2
import { axios } from '../../utils'
3
import { useForm } from 'react-hook-form'
4
import { useDispatch } from 'react-redux'
5
import { addNotification } from '../../redux/notification/notification.actions'
6
import parse from 'html-react-parser'
7
import styled from 'styled-components'
8
import SendIcon from '@mui/icons-material/Send'
9
import IconButton from '@mui/material/IconButton'
10
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
11
import AttachFileIcon from '@mui/icons-material/AttachFile'
12
import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon'
13
 
14
import Options from '../UI/Option'
15
import Emojione from './emojione/Emojione'
16
import FileModal from '../modals/FileModal'
17
 
18
const StyledChatContainer = styled.div`
6921 stevensc 19
  background-color: var(--bg-color);
20
  border-radius: var(--border-radius);
21
  border: 1px solid var(--border-primary);
6911 stevensc 22
  height: 80vh;
23
  display: flex;
24
  flex-direction: column;
6922 stevensc 25
  flex-grow: 1;
6911 stevensc 26
`
27
 
6921 stevensc 28
const StyledChatHeader = styled.div`
6926 stevensc 29
  align-items: center;
6921 stevensc 30
  border-bottom: 1px solid var(--border-primary);
6926 stevensc 31
  display: flex;
32
  justify-content: center;
6921 stevensc 33
  padding: 1rem 0.5rem;
34
  position: relative;
35
 
36
  & > button {
37
    position: absolute;
38
    left: 1rem;
39
    top: 50%;
40
    transform: translateY(-50%);
41
    display: none;
42
  }
43
`
44
 
45
const StyledTitle = styled.h2`
46
  font-size: 1.5rem;
47
  font-weight: 500;
48
  width: fit-content;
49
  max-width: 30ch;
50
  text-align: center;
51
`
52
 
6922 stevensc 53
const StyledMessageList = styled.div`
54
  gap: 0.5rem;
6921 stevensc 55
  display: flex;
6922 stevensc 56
  flex-direction: column-reverse;
6921 stevensc 57
  height: -webkit-fill-available;
58
  padding: 0.5rem 0;
59
  overflow: auto;
60
`
61
 
6911 stevensc 62
const Chat = ({ children }) => {
63
  return <StyledChatContainer>{children}</StyledChatContainer>
64
}
65
 
66
const Header = ({ children, options, onClose }) => {
67
  return (
6921 stevensc 68
    <StyledChatHeader>
6911 stevensc 69
      <IconButton onClick={onClose}>
70
        <ArrowBackIcon />
71
      </IconButton>
72
      {children}
73
      {options && <Options options={options} />}
6921 stevensc 74
    </StyledChatHeader>
6911 stevensc 75
  )
76
}
77
 
6921 stevensc 78
const Title = ({ children, url }) => {
6911 stevensc 79
  if (!url) {
6921 stevensc 80
    return <StyledTitle>{children}</StyledTitle>
6911 stevensc 81
  }
82
 
83
  return (
6921 stevensc 84
    <a href={url} style={{ width: 'fit-content' }}>
85
      <StyledTitle>{children}</StyledTitle>
6911 stevensc 86
    </a>
87
  )
88
}
89
 
90
const List = ({
91
  messages,
92
  pages,
93
  currentPage,
94
  onPagination,
95
  scrollRef,
96
  loading,
97
}) => {
6921 stevensc 98
  const loadMoreEl = useRef(null)
6911 stevensc 99
 
100
  useEffect(() => {
101
    const observer = new IntersectionObserver(onPagination)
102
 
103
    if (loadMoreEl.current) {
104
      observer.observe(loadMoreEl.current)
105
    }
106
 
107
    return () => {
108
      observer.disconnect()
109
    }
110
  }, [messages])
111
 
112
  return (
6922 stevensc 113
    <StyledMessageList ref={scrollRef}>
114
      {messages.map((message) => (
115
        <List.Message message={message} key={message.id} />
116
      ))}
117
      {pages > currentPage && !loading && <p ref={loadMoreEl}>Cargando...</p>}
118
    </StyledMessageList>
6911 stevensc 119
  )
120
}
121
 
122
const Message = ({ message }) => {
123
  const senderName = (message) => {
124
    if (message.type === 'group' && !message.u === 1) return message.user_name
125
  }
126
 
127
  const messagesContent = {
128
    // eslint-disable-next-line no-undef
129
    text: <p>{parse(emojione.shortnameToImage(message.m))}</p>,
130
    image: <img src={message.m} alt="chat_image" />,
131
    video: <video src={message.m} preload="none" controls />,
132
    document: (
133
      <img
134
        className="pdf"
135
        src="/storage/type/default/filename/pdf.png"
136
        alt="pdf"
137
      />
138
    ),
139
  }
140
 
141
  return (
142
    <div
143
      className={`message_container ${message.u === 1 ? 'sent' : 'received'}`}
144
    >
145
      <span className="user_name">{senderName(message)}</span>
146
      <div className={`message ${message.u === 1 ? 'sent' : 'received'}`}>
147
        {messagesContent[message.mtype]}
148
        <label className="message_time">
149
          {!message.not_received && (
150
            <i
151
              className="fa fa-check"
152
              style={message.seen ? { color: 'blue' } : { color: 'gray' }}
153
            />
154
          )}
155
          {message.time}
156
        </label>
157
      </div>
158
    </div>
159
  )
160
}
161
 
162
const SubmitForm = ({ sendUrl, uploadUrl, onSubmit: onComplete }) => {
163
  const [showEmojione, setShowEmojione] = useState(false)
164
  const [isShowFileModal, setIsShowFileModal] = useState(false)
165
  const [isSending, setIsSending] = useState(false)
166
  const dispatch = useDispatch()
167
 
168
  const { handleSubmit, setValue, register, reset, getValues } = useForm()
169
 
170
  const onSubmit = handleSubmit(({ message }) => {
171
    const formData = new FormData()
172
    // eslint-disable-next-line no-undef
173
    formData.append('message', emojione.toShort(message))
174
 
175
    axios.post(sendUrl, formData).then((response) => {
176
      const { success, data } = response.data
177
 
178
      if (!success) {
179
        const errorMessage =
180
          typeof data === 'string' ? data : 'Ha ocurrido un error'
181
 
182
        setShowEmojione(false)
183
        dispatch(addNotification({ style: 'danger', msg: errorMessage }))
184
        return
185
      }
186
 
187
      setShowEmojione(false)
188
      onComplete()
189
      reset()
190
    })
191
  })
192
 
193
  const sendFile = (file) => {
194
    setIsSending(true)
195
    const formData = new FormData()
196
    formData.append('file', file)
197
 
198
    axios
199
      .post(uploadUrl, formData)
200
      .then(({ data: response }) => {
201
        const { success, data } = response
202
        if (!success) {
203
          const errorMessage =
204
            typeof data === 'string' ? data : 'Ha ocurrido un error'
205
          dispatch(addNotification({ style: 'success', msg: errorMessage }))
206
          return
207
        }
208
 
209
        toggleFileModal()
210
        onComplete()
211
      })
212
      .finally(() => setIsSending(false))
213
  }
214
 
215
  const toggleEmojione = () => {
216
    setShowEmojione(!showEmojione)
217
  }
218
 
219
  const toggleFileModal = () => {
220
    setIsShowFileModal(!isShowFileModal)
221
  }
222
 
223
  const onClickEmoji = (event) => {
224
    const shortname = event.currentTarget.dataset.shortname
225
    const currentMessage = getValues('message')
226
    // eslint-disable-next-line no-undef
227
    const unicode = emojione.shortnameToUnicode(shortname)
228
    setValue('message', `${currentMessage}${unicode}`)
229
  }
230
 
231
  return (
232
    <>
233
      <form className="chat__input-container" onSubmit={onSubmit}>
234
        {showEmojione && <Emojione onClickEmoji={onClickEmoji} />}
235
        <IconButton onClick={toggleFileModal}>
236
          <AttachFileIcon />
237
        </IconButton>
238
        <IconButton onClick={toggleEmojione}>
239
          <InsertEmoticonIcon />
240
        </IconButton>
241
        <input
242
          type="text"
243
          name="message"
244
          placeholder="Escribe un mensaje"
245
          ref={register({ required: true })}
246
        />
247
        <IconButton type="submit">
248
          <SendIcon />
249
        </IconButton>
250
      </form>
251
      <FileModal
252
        isShow={isShowFileModal}
253
        onHide={toggleFileModal}
254
        onComplete={sendFile}
255
        loading={isSending}
256
      />
257
    </>
258
  )
259
}
260
 
261
Chat.Header = Header
262
Chat.Title = Title
263
Chat.List = List
264
List.Message = Message
265
Chat.SubmitForm = SubmitForm
266
 
267
export default Chat