123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- import React, {useEffect} from 'react'
- import { gql } from '../helpers'
- import { actionChatsCount } from '../actions'
- import { createStore, combineReducers, applyMiddleware } from 'redux'
- import thunk from 'redux-thunk'
- import {
- actionOnMsg,
- actionOnChat,
- actionOnChatLeft,
- actionFullLogout,
- } from '../actions'
- import io from 'socket.io-client'
- import { actionFullChatList, actionFullMsgsByChat, actionGetChatById } from "../actions";
- export function promiseReducer(state, { type, status, payload, error, name }) {
- if (!state) {
- return {}
- }
- if (type === 'PROMISE') {
- return {
- ...state,
- [name]: {
- status: status,
- payload:
- (status === 'PENDING' &&
- state[name] &&
- state[name].payload) ||
- payload,
- error: error,
- },
- }
- //для пользы при работе с промисами надо бы пока PENDING не делать payload undefined
- //при наличии старого payload
- }
- return state
- }
- const actionPending = (name) => ({ type: 'PROMISE', status: 'PENDING', name })
- const actionResolved = (name, payload) => ({
- type: 'PROMISE',
- status: 'RESOLVED',
- name,
- payload,
- })
- const actionRejected = (name, error) => ({
- type: 'PROMISE',
- status: 'REJECTED',
- name,
- error,
- })
- export const actionPromise = (name, promise) => async (dispatch) => {
- dispatch(actionPending(name))
- try {
- let data = await promise
- dispatch(actionResolved(name, data))
- return data
- } catch (error) {
- dispatch(actionRejected(name, error))
- }
- }
- // ------------------
- function jwtDecode(token) {
- try {
- const decoded = JSON.parse(atob(token.split('.')[1]))
- return decoded
- } catch (err) {
- console.log(err)
- }
- }
- export function authReducer(state, { type, token }) {
- if (!state) {
- if (localStorage.authToken) {
- token = localStorage.authToken
- type = 'AUTH_LOGIN'
- } else {
- return {}
- }
- }
- if (type === 'AUTH_LOGIN') {
- const payload = jwtDecode(token)
- if (typeof payload === 'object') {
- localStorage.authToken = token
- return {
- ...state,
- token,
- payload,
- }
- } else {
- console.error(
- 'Токен ' + localStorage.authToken + ' неверный и был удален'
- )
- delete localStorage.authToken
- return state || {}
- }
- }
- if (type === 'AUTH_LOGOUT') {
- delete localStorage.authToken
- return {}
- }
- return state
- }
- export const actionAuthLogin = (token) => ({ type: 'AUTH_LOGIN', token })
- export const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })
- // -----------------------------------
- // const chats = {
- // chats: [
- // {_id: '333', title: 'moiChat2', avatar: null, lastModified: 'segodnya', owner: {login: 'ya'}, members:[]},
- // {_id: '222', title: 'moiChat', avatar: null, lastModified: 'vchera', owner: {login: 'ya'}, members:[]}
- // ],
- // messages: {
- // '222': [
- // {text: 'uuu'}, {text: 'uuuuuu'}
- // ],
- // '333': [
- // {text: 'UUU'}, {text: 'U'}
- // ]
- // }
- // }
- // payload - или массив чатов или массив сообщений или 1 чат
- export function chatsReducer(state, { type, payload }) {
- if (!state) {
- return {
- }
- }
- function refreshMsgs(newMsgs, oldMsgs) {
- const msgState = [...oldMsgs]
- for (const newMsg of newMsgs || []) {
- const currIndex = msgState.findIndex(
- (oldMsg) => oldMsg._id === newMsg._id
- )
- if (currIndex === -1) {
- msgState.push(newMsg)
- } else {
- msgState[currIndex] = newMsg
- }
- }
- const newMsgState = msgState.sort((a, b) => {
- if (a._id > b._id) {
- return 1
- }
- if (a._id < b._id) {
- return -1
- }
- return 0
- })
- return newMsgState
- }
- function getInfoAboutNext(msgState) {
- const informedState = []
- for (let i = 0; i < msgState.length; i++) {
- const msg = msgState[i]
- msg.nextMsg = msgState[i + 1] || null
- informedState.push(msg)
- }
- return informedState
- }
- function sortChats(unsortedChats) {
- return Object.fromEntries(
- Object.entries(unsortedChats).sort((a, b) => {
- if (a[1].lastModified > b[1].lastModified) {
- return -1
- }
- if (a[1].lastModified < b[1].lastModified) {
- return 1
- }
- return 0
- })
- )
- }
- const types = {
- CHATS() {
- if (payload) {
- const oldChats = { ...state }
- // перебираем новые чаты
- for (const chat of payload) {
- // находим старый чат с ид нового
- const oldChat = oldChats[chat._id]
- // если его еще нет, то просто записываем
- if (!oldChat) {
- oldChats[chat._id] = { ...chat }
- // если есть, то идем по свойствам нового чата
- } else
- for (const key in chat) {
- // записываем значение свойства нового и старого чата
- const oldValue = oldChat[key]
- const newValue = chat[key]
- // проверяем наличие значений
- // если оба значения или только новое, переходим к проверке на массив сообщений
- if (newValue) {
- // если массив сообщений, то вызываем соответствующие функции слияния
- if (key === 'messages') {
- oldChats[chat._id][key] = getInfoAboutNext(
- refreshMsgs(newValue, oldValue)
- )
- } else {
- oldChats[chat._id][key] = newValue //-----------------------------------
- }
- // если есть только старое, записать старое (можно ничего не делать)
- } else {
- oldChats[chat._id][key] = oldValue //-------------------------------------
- }
- }
- }
- const newState = sortChats(oldChats)
- return newState
- }
- return state
- },
- CHAT_LEFT() {
- const { [payload._id]: removed, ...newState } = state // eslint-disable-line
- return newState
- },
- CHATS_CLEAR() {
- return {}
- },
- MSGS() {
- if (payload && payload.length > 0) {
- const chatId = payload[0]?.chat?._id
- const msgState = state[chatId]?.messages || []
- const newMsgState = getInfoAboutNext(
- refreshMsgs(payload, msgState)
- )
- const newState = {
- ...state,
- [chatId]: {
- ...state[chatId],
- messages: newMsgState,
- },
- }
- return newState
- }
- return state
- },
- }
- if (type in types) {
- return types[type]()
- }
- return state
- }
- export const actionChatList = (chats) => ({ type: 'CHATS', payload: chats })
- export const actionChatOne = (chat) => ({ type: 'CHATS', payload: [chat] })
- export const actionChatLeft = (chat) => ({ type: 'CHAT_LEFT', payload: chat })
- export const actionChatsClear = () => ({ type: 'CHATS_CLEAR' })
- export const actionMsgList = (msgs) => ({ type: 'MSGS', payload: msgs })
- export const actionMsgOne = (msg) => ({ type: 'MSGS', payload: [msg] })
- // -------------------------------
- export const actionUserFindOne = (userId, name = 'findUserOne') =>
- actionPromise(
- name,
- gql(
- `query findUserOne($q: String) {
- UserFindOne (query: $q){
- _id
- createdAt
- login
- nick
- avatar {
- _id
- url
- }
- chats{
- avatar {
- _id
- url
- }
- messages {
- _id
- createdAt
- text
- owner {
- _id
- createdAt
- login
- nick
- }
- media {
- _id
- createdAt
- text
- url
- originalFileName
- type
- }
- }
- _id
- createdAt
- title
- lastMessage {
- _id
- createdAt
- text
- }
- }
- }
- }
- `,
- {
- q: JSON.stringify([{ _id: userId }]),
- }
- )
- )
- export const actionAboutMe = () => async (dispatch, getState) => {
- let { auth } = getState()
- let id = auth?.payload?.sub?.id
- if (id) {
- await dispatch(actionUserFindOne(id, 'myProfile'))
- await dispatch(actionChatsCount(id))
- }
- }
- // -----------------------
- // let initialState = localStorage.getItem('state')
- export const store = createStore(
- combineReducers({
- auth: authReducer,
- chats: chatsReducer,
- promise: promiseReducer,
- }),
- // initialState ? {chats: JSON.parse(initialState)} : {},
- applyMiddleware(thunk)
- )
- store.dispatch(actionAboutMe())
- // store.subscribe(() => console.log(store.getState()))
- // window.onbeforeunload = () => window.localStorage.setItem('state', JSON.stringify(store.getState().chats) )
- ///////////////////////////////////////////////////////////////////
- export const socket = io('ws://chat.ed.asmer.org.ua')
- socket.on('jwt_ok', (data) => console.log(data))
- socket.on('jwt_fail', (error) => {
- console.log(error)
- store.dispatch(actionFullLogout())
- })
- socket.on('msg', (msg) => {
- console.log('пришло смс')
- store.dispatch(actionOnMsg(msg))
- })
- socket.on('chat', (chat) => {
- console.log('нас добавили в чат')
- store.dispatch(actionOnChat(chat))
- const state = store.getState()
- socket.disconnect(true)
- socket.connect()
- socket.emit('jwt', state.auth.token)
- })
- socket.on('chat_left', (chat) => {
- console.log('нас выкинули из чата')
- store.dispatch(actionOnChatLeft(chat))
- })
- store.subscribe(() => console.log(store.getState()));
- console.log(store.getState())
- if(store.getState().auth.token){
- store.dispatch(actionFullChatList(store.getState().auth.payload?.sub.id))
- }
- const bodyColor = () => {return document.body.style.background = '#eee'}
- bodyColor()
- // store.dispatch(actionGetChatById("633b2f0c55e76f7ddb1eae97"))
-
|