Proyectos de Subversion LeadersLinked - SPA

Rev

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

Rev 5 Rev 197
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";
Línea 19... Línea 19...
19
 
19
 
20
const StyledChatContainer = styled.div`
20
const StyledChatContainer = styled.div`
21
  background-color: var(--bg-color);
21
  background-color: var(--bg-color);
22
  border-radius: var(--border-radius);
22
  border-radius: var(--border-radius);
23
  border: 1px solid var(--border-primary);
23
  border: 1px solid var(--border-primary);
24
  height: 80vh;
24
  height: 80vh;
25
  display: flex;
25
  display: flex;
26
  flex-direction: column;
26
  flex-direction: column;
27
  flex-grow: 1;
27
  flex-grow: 1;
Línea 28... Línea 28...
28
`
28
`;
29
 
29
 
30
const StyledChatHeader = styled.div`
30
const StyledChatHeader = styled.div`
31
  align-items: center;
31
  align-items: center;
Línea 44... Línea 44...
44
 
44
 
45
    @media (min-width: 768px) {
45
    @media (min-width: 768px) {
46
      display: none;
46
      display: none;
47
    }
47
    }
48
  }
48
  }
Línea 49... Línea 49...
49
`
49
`;
50
 
50
 
51
const StyledTitle = styled.h2`
51
const StyledTitle = styled.h2`
52
  font-size: 1.5rem;
52
  font-size: 1.5rem;
Línea 56... Línea 56...
56
  text-align: center;
56
  text-align: center;
Línea 57... Línea 57...
57
 
57
 
58
  @media (min-width: 768px) {
58
  @media (min-width: 768px) {
59
    max-width: 30ch;
59
    max-width: 30ch;
60
  }
60
  }
Línea 61... Línea 61...
61
`
61
`;
62
 
62
 
63
const StyledMessageList = styled.div`
63
const StyledMessageList = styled.div`
64
  gap: 0.5rem;
64
  gap: 0.5rem;
65
  display: flex;
65
  display: flex;
66
  flex-direction: column-reverse;
66
  flex-direction: column-reverse;
67
  height: -webkit-fill-available;
67
  height: -webkit-fill-available;
68
  padding: 0.5rem 0;
68
  padding: 0.5rem 0;
Línea 69... Línea 69...
69
  overflow: auto;
69
  overflow: auto;
70
`
70
`;
71
 
71
 
72
const StyledMessage = styled.div`
72
const StyledMessage = styled.div`
Línea 98... Línea 98...
98
  &:first-child {
98
  &:first-child {
99
    margin-top: 0.5rem;
99
    margin-top: 0.5rem;
100
  }
100
  }
Línea 101... Línea 101...
101
 
101
 
102
  .time {
102
  .time {
103
    color: $subtitle-color;
103
    color: var(--subtitle-color);
104
    font-size: 0.8rem;
104
    font-size: 0.8rem;
Línea 105... Línea 105...
105
  }
105
  }
106
 
106
 
Línea 114... Línea 114...
114
      return css`
114
      return css`
115
        align-self: flex-end;
115
        align-self: flex-end;
116
        background-color: var(--chat-send);
116
        background-color: var(--chat-send);
117
        border-radius: 10px 0 10px 10px;
117
        border-radius: 10px 0 10px 10px;
118
        margin-right: 0.5rem;
118
        margin-right: 0.5rem;
119
      `
119
      `;
120
    }
120
    }
121
    return css`
121
    return css`
122
      align-self: flex-start;
122
      align-self: flex-start;
123
      background-color: var(--chat-received);
123
      background-color: var(--chat-received);
124
      border-radius: 0 10px 10px 10px;
124
      border-radius: 0 10px 10px 10px;
125
      margin-left: 0.5rem;
125
      margin-left: 0.5rem;
126
    `
126
    `;
127
  }}
127
  }}
128
`
128
`;
Línea 129... Línea 129...
129
 
129
 
130
const StyledForm = styled.form`
130
const StyledForm = styled.form`
131
  border-top: 1px solid var(--border-primary);
131
  border-top: 1px solid var(--border-primary);
132
  padding: 0.5rem;
132
  padding: 0.5rem;
133
  position: relative;
133
  position: relative;
134
  display: flex;
134
  display: flex;
135
  justify-content: center;
135
  justify-content: center;
136
  align-items: center;
136
  align-items: center;
137
  gap: 0.5rem;
137
  gap: 0.5rem;
Línea 138... Línea 138...
138
`
138
`;
139
 
139
 
140
const StyledInput = styled.input`
140
const StyledInput = styled.input`
141
  border: none;
141
  border: none;
142
  outline: none;
142
  outline: none;
143
  flex: 1;
143
  width: 100%;
144
  padding: 0.5rem 1rem;
144
  padding: 0.5rem 1rem;
Línea 145... Línea 145...
145
  border-radius: 30px;
145
  border-radius: 30px;
146
  background: $bg-color-secondary;
146
  background: var(--bg-color-secondary);
147
 
147
 
148
  &:focus {
148
  &:focus {
Línea 149... Línea 149...
149
    background: $bg-color-secondary;
149
    background: var(--bg-color-secondary);
150
  }
150
  }
151
`
151
`;
152
 
152
 
Línea 153... Línea 153...
153
const StyledLoader = styled(LoaderContainer)`
153
const StyledLoader = styled(LoaderContainer)`
154
  max-height: 50px;
154
  max-height: 50px;
155
  max-width: 50px;
155
  max-width: 50px;
156
`
156
`;
157
 
157
 
Línea 158... Línea 158...
158
function messageAreEqual(oldProps, newProps) {
158
function messageAreEqual(oldProps, newProps) {
159
  return oldProps.message.id
159
  return oldProps.message.id
160
    ? oldProps.message.id === newProps.message.id
160
    ? oldProps.message.id === newProps.message.id
Línea 161... Línea 161...
161
    : oldProps.message.uuid === newProps.message.uuid
161
    : oldProps.message.uuid === newProps.message.uuid;
162
}
162
}
163
 
163
 
164
const Chat = ({ children }) => {
164
const Chat = ({ children }) => {
165
  return <StyledChatContainer>{children}</StyledChatContainer>
165
  return <StyledChatContainer>{children}</StyledChatContainer>;
166
}
166
};
167
 
167
 
168
const Header = ({ children, options = [], onClose }) => {
168
const Header = ({ children, options = [], onClose }) => {
169
  return (
169
  return (
170
    <StyledChatHeader>
170
    <StyledChatHeader>
171
      <IconButton onClick={onClose}>
171
      <IconButton onClick={onClose}>
Línea 172... Línea 172...
172
        <ArrowBackIcon />
172
        <ArrowBackIcon />
173
      </IconButton>
173
      </IconButton>
174
      {children}
174
      {children}
175
      {!!options.length && <Options options={options} right="1rem" />}
175
      {!!options.length && <Options options={options} right="1rem" />}
Línea 176... Línea 176...
176
    </StyledChatHeader>
176
    </StyledChatHeader>
177
  )
177
  );
178
}
178
};
179
 
179
 
180
const Title = ({ children, url }) => {
180
const Title = ({ children, url }) => {
181
  if (!url) {
181
  if (!url) {
Línea 182... Línea 182...
182
    return <StyledTitle>{children}</StyledTitle>
182
    return <StyledTitle>{children}</StyledTitle>;
183
  }
183
  }
Línea 184... Línea 184...
184
 
184
 
185
  return (
185
  return (
Línea 186... Línea 186...
186
    <a href={url} style={{ width: 'fit-content' }}>
186
    <a href={url} style={{ width: "fit-content" }}>
187
      <StyledTitle>{children}</StyledTitle>
187
      <StyledTitle>{children}</StyledTitle>
188
    </a>
188
    </a>
Línea 189... Línea 189...
189
  )
189
  );
190
}
190
};
191
 
191
 
192
const List = ({ messages = [], onPagination, scrollRef, loading }) => {
192
const List = ({ messages = [], onPagination, scrollRef, loading }) => {
Línea 193... Línea 193...
193
  const loadMoreEl = useRef(null)
193
  const loadMoreEl = useRef(null);
194
 
194
 
195
  useEffect(() => {
195
  useEffect(() => {
196
    const observer = new IntersectionObserver(onPagination)
196
    const observer = new IntersectionObserver(onPagination);
Línea 214... Línea 214...
214
        <StyledLoader>
214
        <StyledLoader>
215
          <Spinner />
215
          <Spinner />
216
        </StyledLoader>
216
        </StyledLoader>
217
      )}
217
      )}
218
    </StyledMessageList>
218
    </StyledMessageList>
219
  )
219
  );
220
}
220
};
Línea 221... Línea 221...
221
 
221
 
222
// eslint-disable-next-line react/display-name
222
// eslint-disable-next-line react/display-name
223
const Message = memo(({ message }) => {
223
const Message = memo(({ message }) => {
224
  const senderName = (message) => {
224
  const senderName = (message) => {
225
    if (message.type === 'group' && !message.u === 1) {
225
    if (message.type === "group" && !message.u === 1) {
226
      return <span className="user_name">{message.user_name}</span>
226
      return <span className="user_name">{message.user_name}</span>;
227
    }
227
    }
Línea 228... Línea 228...
228
  }
228
  };
229
 
229
 
230
  const messagesContent = {
230
  const messagesContent = {
231
    text: (
231
    text: (
Línea 239... Línea 239...
239
    document: (
239
    document: (
240
      <a href={message.m || message.filename} download>
240
      <a href={message.m || message.filename} download>
241
        <img className="pdf" src="/images/extension/pdf.png" alt="pdf" />
241
        <img className="pdf" src="/images/extension/pdf.png" alt="pdf" />
242
      </a>
242
      </a>
243
    ),
243
    ),
244
  }
244
  };
Línea 245... Línea 245...
245
 
245
 
246
  return (
246
  return (
247
    <>
247
    <>
248
      {senderName(message)}
248
      {senderName(message)}
249
      <StyledMessage
249
      <StyledMessage
250
        send={message.u ? message.u === 1 : message.side === 'left'}
250
        send={message.u ? message.u === 1 : message.side === "left"}
251
      >
251
      >
252
        {messagesContent[message.mtype || message.type]}
252
        {messagesContent[message.mtype || message.type]}
253
        <label className="time">
253
        <label className="time">
254
          {!message.not_received && (
254
          {!message.not_received && (
255
            <i
255
            <i
256
              className="fa fa-check"
256
              className="fa fa-check"
257
              style={message.seen ? { color: 'blue' } : { color: 'gray' }}
257
              style={message.seen ? { color: "blue" } : { color: "gray" }}
258
            />
258
            />
259
          )}
259
          )}
260
          {message.time || message.date}
260
          {message.time || message.date}
261
        </label>
261
        </label>
262
      </StyledMessage>
262
      </StyledMessage>
263
    </>
263
    </>
264
  )
264
  );
Línea 265... Línea 265...
265
}, messageAreEqual)
265
}, messageAreEqual);
266
 
266
 
267
const SubmitForm = ({ sendUrl, uploadUrl, onSubmit: onComplete }) => {
267
const SubmitForm = ({ sendUrl, uploadUrl, onSubmit: onComplete }) => {
268
  const [showEmojione, setShowEmojione] = useState(false)
268
  const [showEmojione, setShowEmojione] = useState(false);
269
  const [isShowFileModal, setIsShowFileModal] = useState(false)
269
  const [isShowFileModal, setIsShowFileModal] = useState(false);
Línea 270... Línea 270...
270
  const [isSending, setIsSending] = useState(false)
270
  const [isSending, setIsSending] = useState(false);
Línea 271... Línea 271...
271
  const dispatch = useDispatch()
271
  const dispatch = useDispatch();
272
 
272
 
273
  const { handleSubmit, setValue, register, reset, getValues } = useForm()
273
  const { handleSubmit, setValue, register, reset, getValues } = useForm();
274
 
274
 
Línea 275... Línea 275...
275
  const onSubmit = handleSubmit(({ message }) => {
275
  const onSubmit = handleSubmit(({ message }) => {
276
    const formData = new FormData()
276
    const formData = new FormData();
Línea 277... Línea 277...
277
    // eslint-disable-next-line no-undef
277
    // eslint-disable-next-line no-undef
278
    formData.append('message', emojione.toShort(message))
278
    formData.append("message", emojione.toShort(message));
279
 
279
 
Línea 280... Línea 280...
280
    axios.post(sendUrl, formData).then((response) => {
280
    axios.post(sendUrl, formData).then((response) => {
281
      const { success, data } = response.data
281
      const { success, data } = response.data;
282
 
282
 
283
      if (!success) {
283
      if (!success) {
Línea 284... Línea 284...
284
        const errorMessage =
284
        const errorMessage =
285
          typeof data === 'string' ? data : 'Ha ocurrido un error'
285
          typeof data === "string" ? data : "Ha ocurrido un error";
286
 
286
 
287
        setShowEmojione(false)
287
        setShowEmojione(false);
288
        dispatch(addNotification({ style: 'danger', msg: errorMessage }))
288
        dispatch(addNotification({ style: "danger", msg: errorMessage }));
Línea 289... Línea 289...
289
        return
289
        return;
290
      }
290
      }
291
 
291
 
292
      setShowEmojione(false)
292
      setShowEmojione(false);
Línea 293... Línea 293...
293
      onComplete()
293
      onComplete();
294
      reset()
294
      reset();
295
    })
295
    });
296
  })
296
  });
297
 
297
 
298
  const sendFile = (file) => {
298
  const sendFile = (file) => {
299
    setIsSending(true)
299
    setIsSending(true);
300
    const formData = new FormData()
300
    const formData = new FormData();
301
    formData.append('file', file)
301
    formData.append("file", file);
302
 
302
 
Línea 303... Línea 303...
303
    axios
303
    axios
304
      .post(uploadUrl, formData)
304
      .post(uploadUrl, formData)
305
      .then(({ data: response }) => {
305
      .then(({ data: response }) => {
306
        const { success, data } = response
306
        const { success, data } = response;
307
        if (!success) {
307
        if (!success) {
Línea 308... Línea 308...
308
          const errorMessage =
308
          const errorMessage =
309
            typeof data === 'string' ? data : 'Ha ocurrido un error'
309
            typeof data === "string" ? data : "Ha ocurrido un error";
310
          dispatch(addNotification({ style: 'success', msg: errorMessage }))
310
          dispatch(addNotification({ style: "success", msg: errorMessage }));
Línea 311... Línea 311...
311
          return
311
          return;
312
        }
312
        }
313
 
313
 
Línea 314... Línea 314...
314
        toggleFileModal()
314
        toggleFileModal();
315
        onComplete()
315
        onComplete();
316
      })
316
      })
317
      .finally(() => setIsSending(false))
317
      .finally(() => setIsSending(false));
318
  }
318
  };
319
 
319
 
320
  const toggleEmojione = () => {
320
  const toggleEmojione = () => {
Línea 321... Línea 321...
321
    setShowEmojione(!showEmojione)
321
    setShowEmojione(!showEmojione);
322
  }
322
  };
323
 
323
 
324
  const toggleFileModal = () => {
324
  const toggleFileModal = () => {
Línea 358... Línea 358...
358
        onHide={toggleFileModal}
358
        onHide={toggleFileModal}
359
        onComplete={sendFile}
359
        onComplete={sendFile}
360
        loading={isSending}
360
        loading={isSending}
361
      />
361
      />
362
    </>
362
    </>
363
  )
363
  );
364
}
364
};
Línea 365... Línea 365...
365
 
365
 
366
Chat.Header = Header
366
Chat.Header = Header;
367
Chat.Title = Title
367
Chat.Title = Title;
368
Chat.List = List
368
Chat.List = List;
369
List.Message = Message
369
List.Message = Message;
Línea 370... Línea 370...
370
Chat.SubmitForm = SubmitForm
370
Chat.SubmitForm = SubmitForm;