|
@@ -1,261 +1,227 @@
|
|
|
-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 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";
|
|
|
-
|
|
|
+ actionFullMsgsByChat
|
|
|
+} from "../actions";
|
|
|
+import io from "socket.io-client";
|
|
|
+import { actionFindUsers } from "../actions";
|
|
|
|
|
|
export function promiseReducer(state, { type, status, payload, error, name }) {
|
|
|
if (!state) {
|
|
|
- return {}
|
|
|
+ return {};
|
|
|
}
|
|
|
- if (type === 'PROMISE') {
|
|
|
+ if (type === "PROMISE") {
|
|
|
return {
|
|
|
...state,
|
|
|
[name]: {
|
|
|
status: status,
|
|
|
payload:
|
|
|
- (status === 'PENDING' &&
|
|
|
+ (status === "PENDING" &&
|
|
|
state[name] &&
|
|
|
state[name].payload) ||
|
|
|
payload,
|
|
|
error: error,
|
|
|
},
|
|
|
- }
|
|
|
+ };
|
|
|
//для пользы при работе с промисами надо бы пока PENDING не делать payload undefined
|
|
|
//при наличии старого payload
|
|
|
}
|
|
|
- return state
|
|
|
+ return state;
|
|
|
}
|
|
|
|
|
|
-const actionPending = (name) => ({ type: 'PROMISE', status: 'PENDING', name })
|
|
|
+const actionPending = (name) => ({ type: "PROMISE", status: "PENDING", name });
|
|
|
const actionResolved = (name, payload) => ({
|
|
|
- type: 'PROMISE',
|
|
|
- status: 'RESOLVED',
|
|
|
+ type: "PROMISE",
|
|
|
+ status: "RESOLVED",
|
|
|
name,
|
|
|
payload,
|
|
|
-})
|
|
|
+});
|
|
|
const actionRejected = (name, error) => ({
|
|
|
- type: 'PROMISE',
|
|
|
- status: 'REJECTED',
|
|
|
+ type: "PROMISE",
|
|
|
+ status: "REJECTED",
|
|
|
name,
|
|
|
error,
|
|
|
-})
|
|
|
+});
|
|
|
|
|
|
export const actionPromise = (name, promise) => async (dispatch) => {
|
|
|
- dispatch(actionPending(name))
|
|
|
+ dispatch(actionPending(name));
|
|
|
try {
|
|
|
- let data = await promise
|
|
|
- dispatch(actionResolved(name, data))
|
|
|
- return data
|
|
|
+ let data = await promise;
|
|
|
+ dispatch(actionResolved(name, data));
|
|
|
+ return data;
|
|
|
} catch (error) {
|
|
|
- dispatch(actionRejected(name, error))
|
|
|
+ dispatch(actionRejected(name, error));
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
+};
|
|
|
|
|
|
// ------------------
|
|
|
|
|
|
-
|
|
|
-
|
|
|
function jwtDecode(token) {
|
|
|
try {
|
|
|
- const decoded = JSON.parse(atob(token.split('.')[1]))
|
|
|
- return decoded
|
|
|
+ const decoded = JSON.parse(atob(token.split(".")[1]));
|
|
|
+ return decoded;
|
|
|
} catch (err) {
|
|
|
- console.log(err)
|
|
|
+ console.log(err);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function authReducer(state, { type, token }) {
|
|
|
if (!state) {
|
|
|
if (localStorage.authToken) {
|
|
|
- token = localStorage.authToken
|
|
|
- type = 'AUTH_LOGIN'
|
|
|
+ token = localStorage.authToken;
|
|
|
+ type = "AUTH_LOGIN";
|
|
|
} else {
|
|
|
- return {}
|
|
|
+ return {};
|
|
|
}
|
|
|
}
|
|
|
- if (type === 'AUTH_LOGIN') {
|
|
|
- const payload = jwtDecode(token)
|
|
|
- if (typeof payload === 'object') {
|
|
|
- localStorage.authToken = token
|
|
|
+ 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 || {}
|
|
|
+ "Токен " + localStorage.authToken + " неверный и был удален"
|
|
|
+ );
|
|
|
+ delete localStorage.authToken;
|
|
|
+ return state || {};
|
|
|
}
|
|
|
}
|
|
|
- if (type === 'AUTH_LOGOUT') {
|
|
|
- delete localStorage.authToken
|
|
|
- return {}
|
|
|
+ if (type === "AUTH_LOGOUT") {
|
|
|
+ delete localStorage.authToken;
|
|
|
+ return {};
|
|
|
}
|
|
|
- return state
|
|
|
+ return state;
|
|
|
}
|
|
|
|
|
|
-export const actionAuthLogin = (token) => ({ type: 'AUTH_LOGIN', token })
|
|
|
-export const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })
|
|
|
-
|
|
|
-
|
|
|
+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 {
|
|
|
- }
|
|
|
+ return {};
|
|
|
}
|
|
|
function refreshMsgs(newMsgs, oldMsgs) {
|
|
|
- const msgState = [...oldMsgs]
|
|
|
+ const msgState = [...oldMsgs];
|
|
|
|
|
|
for (const newMsg of newMsgs || []) {
|
|
|
const currIndex = msgState.findIndex(
|
|
|
(oldMsg) => oldMsg._id === newMsg._id
|
|
|
- )
|
|
|
+ );
|
|
|
|
|
|
if (currIndex === -1) {
|
|
|
- msgState.push(newMsg)
|
|
|
+ msgState.push(newMsg);
|
|
|
} else {
|
|
|
- msgState[currIndex] = newMsg
|
|
|
+ msgState[currIndex] = newMsg;
|
|
|
}
|
|
|
}
|
|
|
const newMsgState = msgState.sort((a, b) => {
|
|
|
if (a._id > b._id) {
|
|
|
- return 1
|
|
|
+ return 1;
|
|
|
}
|
|
|
if (a._id < b._id) {
|
|
|
- return -1
|
|
|
+ return -1;
|
|
|
}
|
|
|
- return 0
|
|
|
- })
|
|
|
+ return 0;
|
|
|
+ });
|
|
|
|
|
|
- return newMsgState
|
|
|
+ return newMsgState;
|
|
|
}
|
|
|
|
|
|
function getInfoAboutNext(msgState) {
|
|
|
- const informedState = []
|
|
|
+ const informedState = [];
|
|
|
|
|
|
for (let i = 0; i < msgState.length; i++) {
|
|
|
- const msg = msgState[i]
|
|
|
+ const msg = msgState[i];
|
|
|
|
|
|
- msg.nextMsg = msgState[i + 1] || null
|
|
|
- informedState.push(msg)
|
|
|
+ msg.nextMsg = msgState[i + 1] || null;
|
|
|
+ informedState.push(msg);
|
|
|
}
|
|
|
|
|
|
- return informedState
|
|
|
+ return informedState;
|
|
|
}
|
|
|
|
|
|
function sortChats(unsortedChats) {
|
|
|
return Object.fromEntries(
|
|
|
Object.entries(unsortedChats).sort((a, b) => {
|
|
|
if (a[1].lastModified > b[1].lastModified) {
|
|
|
- return -1
|
|
|
+ return -1;
|
|
|
}
|
|
|
if (a[1].lastModified < b[1].lastModified) {
|
|
|
- return 1
|
|
|
+ return 1;
|
|
|
}
|
|
|
- return 0
|
|
|
+ return 0;
|
|
|
})
|
|
|
- )
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
const types = {
|
|
|
CHATS() {
|
|
|
if (payload) {
|
|
|
- const oldChats = { ...state }
|
|
|
+ const oldChats = { ...state };
|
|
|
|
|
|
- // перебираем новые чаты
|
|
|
for (const chat of payload) {
|
|
|
- // находим старый чат с ид нового
|
|
|
- const oldChat = oldChats[chat._id]
|
|
|
- // если его еще нет, то просто записываем
|
|
|
+ const oldChat = oldChats[chat._id];
|
|
|
+
|
|
|
if (!oldChat) {
|
|
|
- oldChats[chat._id] = { ...chat }
|
|
|
- // если есть, то идем по свойствам нового чата
|
|
|
+ oldChats[chat._id] = { ...chat };
|
|
|
} else
|
|
|
for (const key in chat) {
|
|
|
- // записываем значение свойства нового и старого чата
|
|
|
- const oldValue = oldChat[key]
|
|
|
- const newValue = chat[key]
|
|
|
+ const oldValue = oldChat[key];
|
|
|
+ const newValue = chat[key];
|
|
|
|
|
|
- // проверяем наличие значений
|
|
|
- // если оба значения или только новое, переходим к проверке на массив сообщений
|
|
|
if (newValue) {
|
|
|
- // если массив сообщений, то вызываем соответствующие функции слияния
|
|
|
- if (key === 'messages') {
|
|
|
+ if (key === "messages") {
|
|
|
oldChats[chat._id][key] = getInfoAboutNext(
|
|
|
refreshMsgs(newValue, oldValue)
|
|
|
- )
|
|
|
+ );
|
|
|
} else {
|
|
|
- oldChats[chat._id][key] = newValue //-----------------------------------
|
|
|
+ oldChats[chat._id][key] = newValue;
|
|
|
}
|
|
|
-
|
|
|
- // если есть только старое, записать старое (можно ничего не делать)
|
|
|
} else {
|
|
|
- oldChats[chat._id][key] = oldValue //-------------------------------------
|
|
|
+ oldChats[chat._id][key] = oldValue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const newState = sortChats(oldChats)
|
|
|
+ const newState = sortChats(oldChats);
|
|
|
|
|
|
- return newState
|
|
|
+ return newState;
|
|
|
}
|
|
|
- return state
|
|
|
+ return state;
|
|
|
},
|
|
|
|
|
|
CHAT_LEFT() {
|
|
|
- const { [payload._id]: removed, ...newState } = state // eslint-disable-line
|
|
|
- return newState
|
|
|
+ const { [payload._id]: removed, ...newState } = state;
|
|
|
+ return newState;
|
|
|
},
|
|
|
|
|
|
CHATS_CLEAR() {
|
|
|
- return {}
|
|
|
+ return {};
|
|
|
},
|
|
|
|
|
|
MSGS() {
|
|
|
if (payload && payload.length > 0) {
|
|
|
- const chatId = payload[0]?.chat?._id
|
|
|
+ const chatId = payload[0]?.chat?._id;
|
|
|
|
|
|
- const msgState = state[chatId]?.messages || []
|
|
|
+ const msgState = state[chatId]?.messages || [];
|
|
|
|
|
|
const newMsgState = getInfoAboutNext(
|
|
|
refreshMsgs(payload, msgState)
|
|
|
- )
|
|
|
+ );
|
|
|
|
|
|
const newState = {
|
|
|
...state,
|
|
@@ -263,36 +229,30 @@ export function chatsReducer(state, { type, payload }) {
|
|
|
...state[chatId],
|
|
|
messages: newMsgState,
|
|
|
},
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- return newState
|
|
|
+ return newState;
|
|
|
}
|
|
|
- return state
|
|
|
+ return state;
|
|
|
},
|
|
|
- }
|
|
|
+ };
|
|
|
if (type in types) {
|
|
|
- return types[type]()
|
|
|
+ return types[type]();
|
|
|
}
|
|
|
- return state
|
|
|
+ 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 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') =>
|
|
|
+export const actionUserFindOne = (userId, name = "findUserOne") =>
|
|
|
actionPromise(
|
|
|
name,
|
|
|
gql(
|
|
@@ -346,83 +306,72 @@ export const actionUserFindOne = (userId, name = 'findUserOne') =>
|
|
|
q: JSON.stringify([{ _id: userId }]),
|
|
|
}
|
|
|
)
|
|
|
- )
|
|
|
+ );
|
|
|
|
|
|
export const actionAboutMe = () => async (dispatch, getState) => {
|
|
|
- let { auth } = getState()
|
|
|
- let id = auth?.payload?.sub?.id
|
|
|
+ let { auth } = getState();
|
|
|
+ let id = auth?.payload?.sub?.id;
|
|
|
if (id) {
|
|
|
- await dispatch(actionUserFindOne(id, 'myProfile'))
|
|
|
- await dispatch(actionChatsCount(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())
|
|
|
+ applyMiddleware(thunk)
|
|
|
+);
|
|
|
|
|
|
-// store.subscribe(() => console.log(store.getState()))
|
|
|
-// window.onbeforeunload = () => window.localStorage.setItem('state', JSON.stringify(store.getState().chats) )
|
|
|
+store.dispatch(actionAboutMe());
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
-export const socket = io('ws://chat.ed.asmer.org.ua')
|
|
|
+// if (Object.keys(store.getState().auth).length > 0) {}
|
|
|
+
|
|
|
+ export const socket = window.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("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("msg", (msg) => {
|
|
|
+ console.log("пришло смс");
|
|
|
+ // store.dispatch(actionOnMsg(msg));
|
|
|
+ store.dispatch(actionMsgOne(msg));
|
|
|
+ });
|
|
|
|
|
|
-socket.on('chat', (chat) => {
|
|
|
- console.log('нас добавили в чат')
|
|
|
- store.dispatch(actionOnChat(chat))
|
|
|
+ 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)
|
|
|
-})
|
|
|
+ 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))
|
|
|
-})
|
|
|
+ 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))
|
|
|
-}
|
|
|
+
|
|
|
|
|
|
|
|
|
+store.subscribe(() => console.log(store.getState()));
|
|
|
+console.log(store.getState());
|
|
|
|
|
|
-const bodyColor = () => {return document.body.style.background = '#eee'}
|
|
|
-bodyColor()
|
|
|
-
|
|
|
-// store.dispatch(actionGetChatById("633b2f0c55e76f7ddb1eae97"))
|
|
|
+const bodyColor = () => {
|
|
|
+ return (document.body.style.background = "#eee");
|
|
|
+};
|
|
|
+bodyColor();
|
|
|
|
|
|
-
|