Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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