Illia Kozyr vor 1 Jahr
Ursprung
Commit
f16435c455

+ 46 - 0
Fakogram REACT project/fakogram/package-lock.json

@@ -17,6 +17,7 @@
         "react-dom": "^18.2.0",
         "react-dropzone": "^14.2.2",
         "react-password-checklist": "^1.4.1",
+        "react-preloaders": "^3.0.3",
         "react-redux": "^8.0.2",
         "react-router-dom": "^5.3.3",
         "react-scripts": "5.0.1",
@@ -14449,6 +14450,29 @@
         "react": ">16.0.0-alpha || >17.0.0-alpha || >18.0.0-alpha"
       }
     },
+    "node_modules/react-preloaders": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/react-preloaders/-/react-preloaders-3.0.3.tgz",
+      "integrity": "sha512-kDqXpJBK+HLRHpYvVHWLMdQo2Y7sqdNBS19YKzLZD6spkAJbEPd256GrZqwNn6b+/MX+1dLHPMBczbFEX7lWRA==",
+      "dependencies": {
+        "prop-types": "^15.7.2",
+        "react": "^16.8.6",
+        "styled-components": "^5.0.0-beta.0"
+      }
+    },
+    "node_modules/react-preloaders/node_modules/react": {
+      "version": "16.14.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
+      "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1",
+        "prop-types": "^15.6.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/react-redux": {
       "version": "8.0.2",
       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.2.tgz",
@@ -27690,6 +27714,28 @@
         "styled-components": "^5.3.5"
       }
     },
+    "react-preloaders": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/react-preloaders/-/react-preloaders-3.0.3.tgz",
+      "integrity": "sha512-kDqXpJBK+HLRHpYvVHWLMdQo2Y7sqdNBS19YKzLZD6spkAJbEPd256GrZqwNn6b+/MX+1dLHPMBczbFEX7lWRA==",
+      "requires": {
+        "prop-types": "^15.7.2",
+        "react": "^16.8.6",
+        "styled-components": "^5.0.0-beta.0"
+      },
+      "dependencies": {
+        "react": {
+          "version": "16.14.0",
+          "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
+          "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
+          "requires": {
+            "loose-envify": "^1.1.0",
+            "object-assign": "^4.1.1",
+            "prop-types": "^15.6.2"
+          }
+        }
+      }
+    },
     "react-redux": {
       "version": "8.0.2",
       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.2.tgz",

+ 1 - 0
Fakogram REACT project/fakogram/package.json

@@ -12,6 +12,7 @@
     "react-dom": "^18.2.0",
     "react-dropzone": "^14.2.2",
     "react-password-checklist": "^1.4.1",
+    "react-preloaders": "^3.0.3",
     "react-redux": "^8.0.2",
     "react-router-dom": "^5.3.3",
     "react-scripts": "5.0.1",

+ 4 - 2
Fakogram REACT project/fakogram/public/index.html

@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="utf-8" />
-    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <link rel="icon" href="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTmMbVgb2YhYvBBriDqAps1xohVIdxu4SZKLA&usqp=CAU" />
     <meta name="viewport" content="width=device-width, initial-scale=1" />
     <meta name="theme-color" content="#000000" />
     <meta
@@ -24,7 +24,8 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-    <title>React App</title>
+    <title>facogram</title>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>
@@ -39,5 +40,6 @@
       To begin the development, run `npm start` or `yarn start`.
       To create a production bundle, use `npm run build` or `yarn build`.
     -->
+    
   </body>
 </html>

+ 240 - 55
Fakogram REACT project/fakogram/src/App.css

@@ -3,7 +3,7 @@
 }
 
 .navbar.navbar-light.bg-primary {
-  width: 1340px;
+    width: 1340px;
 }
 
 .formContainerLogin,
@@ -74,7 +74,8 @@
 }
 
 .buttonSetting {
-    margin-top: 20px;
+    margin: 20px 0;
+    
 }
 
 .textProfile {
@@ -97,6 +98,14 @@
     border-radius: 50%;
 }
 
+.forChatHeader {
+    width: 50px;
+    height: 50px;
+    margin: 0 10px;
+    overflow: hidden;
+    border-radius: 50%;
+}
+
 .smallForChat {
     width: 60px;
     height: 60px;
@@ -105,13 +114,48 @@
     border-radius: 50%;
 }
 
+.smallForChat1{
+    width: 30px;
+    height: 30px;
+    margin-right: 10px;
+    overflow: hidden;
+    border-radius: 50%;
+}
+
 .avatarStub {
     width: 60px;
     height: 60px;
     margin: 0 10px;
     overflow: hidden;
     border-radius: 50%;
-    background-color: blue;
+    background-color: #0d6efd;
+}
+
+.avatarStubChat {
+    width: 120px;
+    height: 120px;
+    margin: 0 10px;
+    overflow: hidden;
+    border-radius: 50%;
+    background-color: #0d6efd;
+}
+
+.avatarStubChat1 {
+    width: 30px;
+    height: 30px;
+    margin-right: 10px;
+    overflow: hidden;
+    border-radius: 50%;
+    background-color: #0d6efd;
+}
+
+.avatarStubChat2 {
+    width: 60px;
+    height: 60px;
+    margin: 0 10px;
+    overflow: hidden;
+    border-radius: 50%;
+    background-color: #0d6efd;
 }
 
 .loginAvatar {
@@ -127,7 +171,7 @@
 }
 
 .mainContainer {
-  display: flex;
+    display: flex;
 }
 
 .chatsList {
@@ -142,6 +186,12 @@
     background-color: lightgray;
 }
 
+
+.search-item:hover {
+    width: 100%;
+    background-color: lightgray;
+}
+
 .chatsList h1 {
     font-size: 1.5rem;
 }
@@ -153,6 +203,15 @@
     text-align: center;
 }
 
+.chatAvatarTextHeader {
+    padding: 6px;
+    color: white;
+    font-size: 25px;
+    text-align: center;
+    order: 10;
+    
+}
+
 .chatTitle {
     color: black;
 }
@@ -165,6 +224,15 @@
     border-radius: 50%;
 }
 
+.stubAvatarHeader {
+    width: 50px;
+    height: 50px;
+    margin: 0 10px;
+    overflow: hidden;
+    border-radius: 50%;
+    
+}
+
 .burger.navbar-toggler.collapsed {
     margin-left: 10px;
     background-color: blueviolet;
@@ -206,6 +274,10 @@
     margin-bottom: 40px;
 }
 
+.msgMedia {
+    max-width: 480px;
+}
+
 .dropZoneStyle {
     padding-left: 10px;
     max-width: 500px;
@@ -213,6 +285,10 @@
     margin: 0 auto;
 }
 
+/* .dropZoneStyle2{
+
+} */
+
 .dropZoneStyle:hover {
     cursor: pointer;
 }
@@ -258,94 +334,203 @@
 }
 
 .newChatContainer {
-    padding-top: 150px;
+    padding-top: 50px;
 }
 
 .chatAside {
-  list-style: none;
-  padding: 0;
+    list-style: none;
+    padding: 0;
 }
 
-.chatMain{
-  min-width: 100vh;
-  height: 75vh;
-  display: flex;
-  flex-direction: column;
-  /* flex-wrap: nowrap; */
-  overflow: auto;
-  padding: 20px;
-  
+.chatMain {
+    min-width: 100vh;
+    height: 75vh;
+    display: flex;
+    flex-direction: column;
+    /* flex-wrap: nowrap; */
+    overflow: auto;
+    padding: 20px;
 }
 
-
 .msgLi {
-  max-width: 500px;
-  border: 1px solid gray;
-  margin: 10px;
-  background-color: rgb(76, 145, 199);
-  border-radius: 15px;
-  padding: 8px;
-  /* margin-left: 30vh; */
- 
+    max-width: 500px;
+    border: 1px solid gray;
+    margin: 10px;
+    background-color: rgb(76, 145, 199);
+    border-radius: 15px;
+    padding: 8px;
+    list-style-type: none;
+    margin-left: 40vh;
+}
 
+.msgOther {
+    max-width: 500px;
+    border: 1px solid gray;
+    margin: 10px;
+    background-color: rgb(244, 244, 244);
+    border-radius: 15px;
+    list-style-type: none;
+    padding: 8px;
 }
 
-.msgsContainer{
-  display: flex;
-  justify-content: flex-end;
+.noMsg {
+    padding: 0vh 0 0 35vh;
 }
 
+.chatLi ul {
+    margin-left: 10px;
+}
 
+.chatLi h5 {
+    color: black;
+}
 
-.msgOther {
-  max-width: 500px;
-  border: 1px solid gray;
-  margin: 10px;
-  background-color:rgb(244, 244, 244);
-  border-radius: 15px;
-  padding: 8px;
+.chatContainer {
+    margin: 20px 0px;
+    max-height: 75vh;
+    width: 240vh;
+    overflow: auto;
+}
 
+.btn.btn-primary {
+    max-width: 90vh;
 }
 
-.chatLi ul{
-  margin-left: 10px;
+.chatBlock {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
 }
 
-.sendMsgBlock{
-  display: flex;
-  flex-direction: column;
-  padding-right: 30px;
+.msgBlock {
+    /* max-width: 500px; */
+    display: flex;
 }
 
-.sendMsgBlock textarea {
-  /* margin: 20px 0px 0px 0px; */
-  padding: 10px;
-  width: 90vh;
+.sendMsgBlock {
+    display: flex;
+    flex-direction: column;
+    padding-right: 30px;
+}
 
+.sendMsgBlock textarea {
+    /* margin: 20px 0px 0px 0px; */
+    padding: 10px;
+    width: 90vh;
 }
 
 .sendMsgBlock button {
-  margin: 20px 30px 20px 50px;
-
-  
+    margin: 20px 30px 20px 50px;
 }
 
 .sendBlock {
-  display: flex;
-  
+    display: flex;
 }
 
 .sendBlock img {
-  margin: 20px;
+    margin: 20px;
 }
 
-.flexContainer{
-  margin: 0 auto;
+.flexContainer {
+    margin: 0 auto;
 }
 
 .sandFile {
-  width: 30px;
- 
+    width: 30px;
+}
+
+.chatsList {
+    display: flex;
+}
 
+.chatsCard {
+    display: flex;
 }
 
+.displayFixed {
+    display: flex;
+    align-items: center;
+    position: absolute;
+    top: 2px;
+}
+.displayFixed h5 {
+    padding-top: 3px;
+    color: white;
+}
+
+.displayFixed h6 {
+    padding: 10px 0 0 50vh;
+    color: white;
+}
+
+#spinner {
+    display: block;
+}
+
+
+/* ---------------------------------- */ 
+@keyframes ldio-95gtuxj5ve {
+  0% { transform: translate(-50%,-50%) rotate(0deg); }
+  100% { transform: translate(-50%,-50%) rotate(360deg); }
+}
+.ldio-95gtuxj5ve div {
+  position: absolute;
+  width: 120px;
+  height: 120px;
+  border: 20px solid #0d6efd;
+  border-top-color: transparent;
+  border-radius: 50%;
+}
+.ldio-95gtuxj5ve div {
+  animation: ldio-95gtuxj5ve 1s linear infinite;
+  top: 100px;
+  left: 100px
+}
+.loadingio-spinner-rolling-e3qh2r8uzre {
+  width: 200px;
+  height: 200px;
+  display: inline-block;
+  overflow: hidden;
+  background: #f1f2f3;
+}
+.ldio-95gtuxj5ve {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  transform: translateZ(0) scale(1);
+  backface-visibility: hidden;
+  transform-origin: 0 0; /* see note above */
+}
+.ldio-95gtuxj5ve div { box-sizing: content-box; }
+/* generated by https://loading.io/ */
+/* ------------------------------------------------------------ */
+
+.preloader {
+    color: #0d6efd;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding-top: 30vh;
+}
+
+.searchBlock:hover{
+    width: 100%;
+    background-color: lightgray;
+}
+
+.search-item {
+    display: flex;
+    align-items: center;
+    width: 53vh;
+}
+
+.search-item div{
+    font-size: 20px;
+    color: black;
+    
+}
+
+.search-item {
+    margin: 5px 0;
+    text-decoration: none;
+}

+ 51 - 31
Fakogram REACT project/fakogram/src/App.js

@@ -1,3 +1,4 @@
+import React, { useState } from "react";
 import "./App.css";
 import "bootstrap/dist/css/bootstrap.min.css";
 import { store, socket } from "./reducers";
@@ -12,50 +13,69 @@ import { ChatPage, CChatsPage } from "./pages/ChatsPage";
 import { CNewChatPage } from "./pages/NewChatPage";
 import { CChangePass } from "./pages/ChangePassPage";
 import { ChangesDone } from "./pages/ChangesDonePage";
-import { ChangesDoneForChats } from './pages/ChangeDoneForChat'
+import { ChangesDoneForChats } from "./pages/ChangeDoneForChat";
 import { AboutUs } from "./pages/AboutUs";
 import { Redirect } from "react-router-dom";
-import { OneChat } from './pages/MsgPage'
+import { CChatMsgs } from "./pages/ChatMsgsPage";
+import { CChatsAside } from "./pages/ChatsAside";
+import { Preloader } from "./helpers/preloaders";
+import { CChatEditing } from "./pages/ChatEditing";
 
 export const history = createHistory();
 
+const AuthSwitch = ({ token }) => {
+    if (token) {
+        console.log("подключение сокета");
+        socket.emit("jwt", token);
+    }
+    return (
+        <>
+            <Switch>
+                <Route path="/login" component={() => <></>} />
+                <Route path="/registration" component={() => <></>} />
+                <Header />
+            </Switch>
+            <Route path="/login" component={CLogin} />
+            <Route path="/registration" component={CRegistration} />
+            <Route path="/profile" component={CProfilePage} />
+            <Route path="/newchat" component={CNewChatPage} />
+            <Route path="/changepas" component={CChangePass} />
+            <Route path="/changesdone" component={ChangesDone} />
+            <Route path="/changesdonechats" component={ChangesDoneForChats} />
+            <Route path="/chatediting/:_id" component={CChatEditing} />
+            <Route path="/aboutus" component={AboutUs} />
+            <div className="mainContainer">
+                <Route path="/main/" component={CChatsAside} />
+
+                <Route path="/main/:_id" component={CChatMsgs} />
+            </div>
+            <Redirect
+                to={
+                    store.getState().auth.token === undefined
+                        ? "/login"
+                        : "/main"
+                }
+            />
+        </>
+    );
+};
+
+const CAuthSwitch = connect((state) => ({ token: state.auth.token || null }))(
+    AuthSwitch
+);
+
 function App() {
     return (
-        <div className="container">
+        <>
             <Router history={history}>
                 <Provider store={store}>
-                    <Switch>
-                        <Route path="/login" component={() => <></>} />
-                        <Route path="/registration" component={() => <></>} />
-                        <Header />
-                    </Switch>
-                    <Route path="/login" component={CLogin} />
-                    <Route path="/registration" component={CRegistration} />
-                    <Route path="/profile" component={CProfilePage} />
-                    
-                    <Route path="/newchat" component={CNewChatPage} />
-                    <Route path="/changepas" component={CChangePass} />
-                    <Route path="/changesdone" component={ChangesDone} />
-                    <Route path="/changesdonechats" component={ChangesDoneForChats} />
-                    <Route path="/aboutus" component={AboutUs} />
-                    <div className="chatPageContainer">
-                    <Route path="/main/" component={CChatsPage} />
-                    {/* <Route path="/main/:_id" component={OneChat} /> */}
+                    <div className="container">
+                        <CAuthSwitch />
                     </div>
-                    
-                    <Redirect
-                        to={
-                            store.getState().auth.token === undefined
-                                ? "/login"
-                                : "/main"
-                        }
-                    />
                 </Provider>
             </Router>
-        </div>
+        </>
     );
 }
 
-
-
 export default App;

+ 63 - 57
Fakogram REACT project/fakogram/src/actions/chatsActions.js

@@ -1,5 +1,5 @@
-import { history } from '../App'
-import { gql } from '../helpers'
+import { history } from "../App";
+import { gql } from "../helpers";
 import {
     actionPromise,
     actionChatList,
@@ -7,14 +7,14 @@ import {
     actionChatLeft,
     actionAboutMe,
     store,
-} from '../reducers'
-import { actionGetAllLastMsg } from './msgActions'
-import { actionUploadFile } from './mediaActions'
+} from "../reducers";
+import { actionGetAllLastMsg } from "./msgActions";
+import { actionUploadFile } from "./mediaActions";
 
 // в массив newMemders передавать объекты только с полем _id
 const actionUpdateChat = (title, members, chatId) =>
     actionPromise(
-        'updateChat',
+        "updateChat",
         gql(
             `mutation updateChat($chat:ChatInput) {
       ChatUpsert(chat:$chat) {
@@ -46,13 +46,13 @@ const actionUpdateChat = (title, members, chatId) =>
    }`,
             { chat: { _id: chatId, title, members } }
         )
-    )
+    );
 
 // MediaUpsert нужен только для добавления данных для загруженного файла
 // и дальнейшего отображения его через эти данные (через аватары, сообщения)
 const actionUpdateChatAvatar = (mediaId, chatId) =>
     actionPromise(
-        'uploadFile',
+        "uploadFile",
         gql(
             `mutation uploadFile($media: MediaInput) {  
         MediaUpsert(media: $media) {
@@ -62,25 +62,27 @@ const actionUpdateChatAvatar = (mediaId, chatId) =>
     }`,
             { media: { _id: mediaId, chatAvatars: { _id: chatId } } }
         )
-    )
+    );
 
 export const actionSetChatInfo =
     (name, file, title, members, chatId) => async (dispatch) => {
-        const chat = await dispatch(actionUpdateChat(title, members, chatId))
+        const chat = await dispatch(actionUpdateChat(title, members, chatId));
 
         if (file && chat._id) {
-            const fileObj = await dispatch(actionUploadFile(name, file))
+            const fileObj = await dispatch(actionUploadFile(name, file));
             const chatAvatar = await dispatch(
                 actionUpdateChatAvatar(fileObj?._id, chat._id)
-            )
-            await dispatch(actionChatOne({ _id: chat._id, avatar: chatAvatar }))
+            );
+            await dispatch(
+                actionChatOne({ _id: chat._id, avatar: chatAvatar })
+            );
         }
-    }
+    };
 
 // поиск по значению в массиве объектов - { 'members._id': userId }
 export const actionGetChatsByUser = (userId, skipCount = 0, limitCount = 50) =>
     actionPromise(
-        'userChats',
+        "userChats",
         gql(
             `query userChats($q: String) {
       ChatFind (query: $q){
@@ -89,7 +91,7 @@ export const actionGetChatsByUser = (userId, skipCount = 0, limitCount = 50) =>
          avatar {
             _id
             url
-         }
+         } 
          owner {
             _id
             login
@@ -97,7 +99,7 @@ export const actionGetChatsByUser = (userId, skipCount = 0, limitCount = 50) =>
                _id
                url
             }
-         }
+        }
          members {
             _id
             login
@@ -108,12 +110,15 @@ export const actionGetChatsByUser = (userId, skipCount = 0, limitCount = 50) =>
             }
          }
          lastModified
+         lastMessage {
+            _id text
+          }
       }     
    }`,
             {
                 q: JSON.stringify([
                     {
-                        $or: [{ ___owner: userId }, { 'members._id': userId }],
+                        $or: [{ ___owner: userId }, { "members._id": userId }],
                     },
                     {
                         sort: [{ lastModified: -1 }],
@@ -123,24 +128,24 @@ export const actionGetChatsByUser = (userId, skipCount = 0, limitCount = 50) =>
                 ]),
             }
         )
-    )
+    );
 
 export const actionFullChatList =
     (userId, currentCount, limitCount = 50) =>
     async (dispatch) => {
         const payload = await dispatch(
             actionGetChatsByUser(userId, currentCount, limitCount)
-        )
+        );
         if (payload) {
-            await dispatch(actionChatList(payload))
+            await dispatch(actionChatList(payload));
 
-            await dispatch(actionGetAllLastMsg(payload))
+            await dispatch(actionGetAllLastMsg(payload));
         }
-    }
+    };
 
 export const actionGetChatById = (chatId) =>
     actionPromise(
-        'chatById',
+        "chatById",
         gql(
             `query chatById($q: String) {
       ChatFindOne (query: $q){
@@ -158,6 +163,7 @@ export const actionGetChatById = (chatId) =>
                url
             }
          }
+
          members {
             _id
             login
@@ -168,19 +174,20 @@ export const actionGetChatById = (chatId) =>
             }
          }
          lastModified
-         
-         
+         messages {
+          _id text
+        }
       }     
    }`,
             {
                 q: JSON.stringify([{ _id: chatId }]),
             }
         )
-    )
+    );
 
 export const actionChatsCount = (userId) =>
     actionPromise(
-        'chatsCount',
+        "chatsCount",
         gql(
             `query chatsCount($q: String) {
       ChatCount (query: $q)  
@@ -189,12 +196,12 @@ export const actionChatsCount = (userId) =>
                 q: JSON.stringify([{ ___owner: userId }]),
             }
         )
-    )
+    );
 
 // происходит когда юзер уходит сам, иначе в чат добавляются юзер, а не наоборот
 const actionUpdateUserChats = (userId, newChats) =>
     actionPromise(
-        'updateUserChats',
+        "updateUserChats",
         gql(
             `mutation updateUserChats($user:UserInput) {
       UserUpsert(user:$user) {
@@ -209,31 +216,30 @@ const actionUpdateUserChats = (userId, newChats) =>
    }`,
             { user: { _id: userId, chats: newChats } }
         )
-    )
-
-export const removeUserChat = (chatId) => async (dispatch, getState) => {
-    const state = getState()
-    const myId = state.promise.myProfile.payload._id
-    const oldChats = state.promise.myProfile.payload.chats
-
-    const newChats = oldChats.filter((chat) => chat._id !== chatId)
-    await dispatch(actionUpdateUserChats(myId, newChats))
-
-    const ownerId = state.chats[chatId]?.owner?._id
-    // тут событие ухода из чата не приходит по сокету,
-    // поэтому нужно делать все то, что и в сокете
-
-    if (myId !== ownerId) {
-        dispatch(actionChatLeft({ _id: chatId }))
-        const [, , histId] = history.location.pathname.split('/')
-        if (histId === chatId) {
-            history.push('/')
+    );
+
+    export const removeUserChat = (chatId) => async (dispatch, getState) => {
+        const state = getState()
+        const myId = state.promise.myProfile.payload._id
+        const oldChats = state.promise.myProfile.payload.chats
+    
+        const newChats = oldChats.filter((chat) => chat._id !== chatId)
+        await dispatch(actionUpdateUserChats(myId, newChats))
+    
+        const ownerId = state.chats[chatId]?.owner?._id
+        // тут событие ухода из чата не приходит по сокету,
+        // поэтому нужно делать все то, что и в сокете
+    
+        if (myId !== ownerId) {
+            dispatch(actionChatLeft({ _id: chatId }))
+            const [, , histId] = history.location.pathname.split('/')
+            if (histId === chatId) {
+                history.push('/')
+            }
+        } else {
+            const chat = await dispatch(actionGetChatById(chatId))
+            await dispatch(actionChatOne(chat))
         }
-    } else {
-        const chat = await dispatch(actionGetChatById(chatId))
-        await dispatch(actionChatOne(chat))
-    }
-
-    await dispatch(actionAboutMe())
-}
-
+    
+        await dispatch(actionAboutMe())
+    }

+ 2 - 0
Fakogram REACT project/fakogram/src/actions/index.js

@@ -23,6 +23,7 @@ import {
     actionMsgsCount,
     actionGetMsgById,
     actionSendMsg,
+    actionUpdateMsg
 } from "./msgActions";
 
 export {
@@ -49,4 +50,5 @@ export {
     actionMsgsCount,
     actionGetMsgById,
     actionSendMsg,
+    actionUpdateMsg
 };

+ 4 - 15
Fakogram REACT project/fakogram/src/actions/msgActions.js

@@ -48,6 +48,7 @@ export const actionGetMsgsByChat = (chatId, skipCount = 0, limitCount = 50) =>
          forwarded {
             _id
          }
+         
       }     
    }`,
             {
@@ -190,7 +191,7 @@ export const actionGetMsgById = (msgId) =>
         )
     )
 
-const actionUpdateMsg = (chatId, text, media, msgId) =>
+export const actionUpdateMsg = (chatId, text, media, msgId) =>
     actionPromise(
         'updateMsg',
         gql(
@@ -270,20 +271,8 @@ export const actionSendMsg =
 
         const payload = await dispatch(
             actionUpdateMsg(chatId, text, media, msgId)
-        ) // eslint-disable-line
-        // if (payload) {
-        //    await dispatch(actionMsgOne(payload))
-        //    let chatUpdated = await dispatch(actionGetChatById(chatId))
-        //    await dispatch(actionChatOne(chatUpdated))
-        // }
+        ) 
     }
 
-// const actionRemoveMsg = (msgId) => (
-//    actionPromise('removeMsg', gql(`mutation removeMsg($msg: MessageInput) {
-//       MessageDelete(message: $msg) {
-//          _id
-//       }
-//    }`, { msg: { _id: msgId } }
-//    ))
-// )
+
 

+ 23 - 4
Fakogram REACT project/fakogram/src/components/Avatar.js

@@ -26,15 +26,34 @@ export const CMyAvatar = connect((state) => ({
     profile: state.promise.myProfile?.payload || {},
 }))(UserAvatar);
 
-export const ChatAvatar = ({ chat, className = "small" }) => {
+export const ChatAvatar = ({ userChat, text = "", className = "small", _id }) => {
     return (
         <>
-            <div className={className} style={{backgroundColor: "gray"}}></div>
+            <div style={{display: "flex", alignItems: 'center'}}>
+                {userChat[_id]?.avatar?.url ? <img className={className} src={backURL + userChat[_id]?.avatar?.url} /> : <div className="avatarStubChat"></div>}
+                
+                <p>{text}</p>
+            </div>
+            
         </>
     )
 }
 
+
+
 export const CChatAvatar = connect((state) => ({
-    profile: state.promise.userChats?.payload || {},
-}))(UserAvatar);
+    userChat: state.chats || {},
+}))(ChatAvatar);
+ 
+const SearchAvatar = ({findUser, avatarUrl}) => {
+    return(
+        <div className="searchBlock">
+            <img src={backURL + avatarUrl.avatar.url} className="smallForChat"/>
+            
+        </div>
+    )
+}
 
+export const CSearchAvatar = connect((state) => ({findUser: state?.promise?.findUser?.payload}))(
+SearchAvatar
+)

+ 28 - 3
Fakogram REACT project/fakogram/src/components/AvatarStub.js

@@ -9,8 +9,33 @@ export const color = () => {
 
 export const AvatarStub = (props) => {
     return (
-        <div className="stubAvatar" style={{backgroundColor: props.color}}>
-            <p className="chatAvatarText">{((props.login).split(' ').map(function(item){return item[0]}).join(''))}</p>
+        <div className="stubAvatar" style={{ backgroundColor: props.color }}>
+            <p className="chatAvatarText">
+                {props.login
+                    .split(" ")
+                    .map(function (item) {
+                        return item[0];
+                    })
+                    .join("")}
+            </p>
         </div>
     );
-};
+};
+
+export const AvatarStubHeader = (props) => {
+    return (
+        <div
+            className="stubAvatarHeader"
+            style={{ backgroundColor: props.color }}
+        >
+            {/* <p className="chatAvatarTextHeader">
+                {props?.login
+                    .split(" ")
+                    .map(function (item) {
+                        return item[0];
+                    })
+                    .join("")}
+            </p> */}
+        </div>
+    );
+};

+ 21 - 0
Fakogram REACT project/fakogram/src/components/OneUserCard.js

@@ -0,0 +1,21 @@
+import React from "react";
+import { Link } from "react-router-dom";
+import { CSearchAvatar } from "../components/Avatar";
+
+export const OneUserCard = ({ user }) => {
+    return (
+        <>
+            <div className="searchBlock">
+                <Link className="search-item">
+                    {user?.avatar !== null ? (
+                        <CSearchAvatar avatarUrl={user} />
+                    ) : (
+                        <div className="avatarStubChat2"></div>
+                    )}
+
+                    <div>{user?.login ? user.login : "anon"}</div>
+                </Link>
+            </div>
+        </>
+    );
+};

+ 45 - 103
Fakogram REACT project/fakogram/src/helpers/UserSearch.js

@@ -1,112 +1,54 @@
-import React, { useState, useEffect, useRef } from "react";
-import { actionFindUsers } from '../actions'
-import {store} from '../reducers'
-import { connect } from "react-redux";
+import React, {useEffect, useRef, useState} from 'react';
+import {connect, useDispatch} from 'react-redux';
+import {actionFindUsers} from "../actions";
+import {OneUserCard} from "../components/OneUserCard";
 
+import Button from 'react-bootstrap/esm/Button';
+import {Link} from "react-router-dom";
 
-const UserSearch = ({
-    findedUsers,
-    onSearch,
-    alreadySearched = [],
-    onAdd,
-    open,
-}) => {
-    const [finded, setFinded] = useState([])
-    const [input, setInput] = useState(null)
-
-    useEffect(() => {
-        let timeout
-        if (input !== null) {
-            timeout = setTimeout(() => {
-                onSearch(input)
-            }, 500)
-        }
-        return () => {
-            clearTimeout(timeout)
-        }
-    }, [input])
-
+const useDebounce = (cb, depArray, delay) => {
+    let timeoutRef = useRef()
+    // timeoutRef.current = setTimeout
     useEffect(() => {
-        setFinded(findedUsers)
-    }, [findedUsers])
-
-    useEffect(() => {
-        setInput(null)
-        setFinded([])
-    }, [open])
+        clearInterval(timeoutRef.current)
+        timeoutRef.current === undefined ? timeoutRef.current = -1 : timeoutRef.current = setTimeout(cb, delay)
+    }, depArray)
+};
 
+const SearchByLogin = ({ user, onGetUser, foundUsers, state }) => {
+    const [login, setLogin] = useState()
+    useDebounce( () => onGetUser(login), [login], 2000);
     return (
-        <div className="userSearchBox">
-            <div className="searchField">
-                <input setInput={setInput} text={'Найти пользователя'} />
+        <form>
+            <label for="loginInput">
+            Add users to a group:{" "}
+                        </label>
+            <div className='search-box'>
+                <input
+                    className="form-control-editing form-control"
+                    placeholder=""
+                    value={login}
+                    onChange={(e) => setLogin(e.target.value)}
+                />
             </div>
 
-            <div className="usersBox">
-                <div className="usersList">
-                    {finded.map((user) => (
-                        <input
-                            key={user._id}
-                            user={user}
-                            
-                            onAction={() => onAdd(user)}
-                            disabled={
-                                !!alreadySearched.find(
-                                    (searchedUser) =>
-                                        searchedUser._id === user._id
-                                )
-                            }
-                        />
-                    ))}
-                </div>
-            </div>
-        </div>
-    )
-}
-
-const useLocalStoredState = (defaultState, localStorageKey) => {
-    const json = localStorage[localStorageKey];
-
-    try {
-        defaultState = JSON.parse(json);
-    } catch (e) {}
-
-    const [state, setState] = useState(defaultState);
-
-    localStorage.setItem(localStorageKey, JSON.stringify(state));
-
-    return [state, setState];
-};
-
-export const Input = () => {
-    const [text, setText] = useLocalStoredState(" ", "inputText");
-
-    return <input value={text} onChange={(e) => setText(e.target.value)} />;
+            {foundUsers  ?
+                    foundUsers.map((user) => {
+                        return (<OneUserCard key={user._id} user={user}/>)
+                        
+                    })
+                : null
+            }
+        </form>
+    );
 };
 
-const ThemeContext = React.createContext();
-
-export const InputDebounce = ({}) => {
-    const [text, setText] = useState("");
-
-    const timeoutRef = useRef();
-
-    useEffect(() => {
-        clearInterval(timeoutRef.current);
-
-        if (text)
-            timeoutRef.current = setTimeout(
-                () => console.log(store.dispatch(actionFindUsers())),
-                2000
-            );
-    }, [text]);
-
-    return <input value={text} onChange={(e) => setText(e.target.value)} />;
-};
-
-
-export const CUserSearch = connect(
-    (state) => ({ findedUsers: state.promise.findUsers?.payload || [] }),
-    { onSearch: actionFindUsers }
-)(InputDebounce)
-
-
+export const CSearchByLogin = connect(
+    (state) => ({
+        foundUsers: state?.promise?.findUsers?.payload
+        // state: state
+    }),
+    {
+        onGetUser: actionFindUsers,
+    }
+)(SearchByLogin);

+ 14 - 0
Fakogram REACT project/fakogram/src/helpers/preloaders.js

@@ -0,0 +1,14 @@
+import React from "react";
+
+export const Preloader = () => {
+    return (<div className="preloader">
+        <h1>FACOGRAM</h1>
+    <div className="loadingio-spinner-rolling-e3qh2r8uzre">
+            <div className="ldio-95gtuxj5ve">
+                <div></div>
+            </div>
+        </div>
+    </div>
+        
+    );
+};

+ 14 - 9
Fakogram REACT project/fakogram/src/index.js

@@ -1,14 +1,19 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from "react";
+import ReactDOM from "react-dom/client";
+import "./index.css";
+import App from "./App";
+import reportWebVitals from "./reportWebVitals";
+import { Preloader } from "./helpers/preloaders";
 
-const root = ReactDOM.createRoot(document.getElementById('root'));
+const root = ReactDOM.createRoot(document.getElementById("root"));
 root.render(
-  
-    <App />
-  
+    <>
+        {/* <div id="spinner"><Preloader/></div> */}
+        <App />
+    </>
+    
+        
+    
 );
 
 // If you want to start measuring performance in your app, pass a function

+ 133 - 0
Fakogram REACT project/fakogram/src/pages/ChatEditing.js

@@ -0,0 +1,133 @@
+import React, { useState } from "react";
+import { connect } from "react-redux";
+import { useDropzone } from "react-dropzone";
+import { Link, useParams } from "react-router-dom";
+import Button from "react-bootstrap/esm/Button";
+import { Input, InputDebounce } from "../helpers/UserSearch";
+import { CUserSearch } from "../helpers/UserSearch";
+import { removeUserChat } from "../actions";
+import { CSearchByLogin } from '../helpers/UserSearch'
+
+import { actionSetChatInfo } from "../actions";
+
+import { CChatAvatar } from "../components/Avatar";
+
+const ChatEditing = ({ chatId, onChat, myProfile, create, onLeave }) => {
+    let { _id } = useParams();
+
+    const [chat] = useState();
+    const [img, setImg] = useState(null);
+    const [newTitle, setNewTitle] = useState(chatId[_id]?.title || "");
+    const [members, setMembers] = useState(chat?.members || [myProfile]);
+
+    const { getRootProps, getInputProps, isDragActive } = useDropzone({
+        accept: "image/*",
+        maxFiles: 1,
+        onDrop: (acceptedFiles) => {
+            setImg(acceptedFiles[0]);
+        },
+    });
+
+    function prepareMembers(members) {
+        const newMembers = [];
+
+        for (const member of members) {
+            if (create) {
+                if (member._id !== myProfile?._id) {
+                    newMembers.push({ _id: member._id });
+                }
+            } else {
+                newMembers.push({ _id: member._id });
+            }
+        }
+        return newMembers;
+    }
+
+    return (
+        <div className="newChatContainer">
+            <div {...getRootProps({ className: "dropZoneStyle" })}>
+                <input {...getInputProps()} />
+                {isDragActive ? (
+                    <p className="dropZoneStyleBr">Drop the files here ...</p>
+                ) : (
+                    <CChatAvatar
+                        _id={_id}
+                        text="upload chat avatar"
+                        className="profileStyle"
+                    />
+                )}
+            </div>
+            <div className="profileContainer">
+                <div className="loginNickSetting">
+                    <div className="inputContainer">
+                        <label for="loginInput">
+                            Enter the new name of the chat:{" "}
+                        </label>
+                        <input
+                            className="form-control-editing form-control"
+                            id="loginInput"
+                            type="text"
+                            value={newTitle}
+                            onChange={(e) => {
+                                setNewTitle(e.target.value);
+                            }}
+                        />
+                    </div>
+
+                    <div className="inputContainer">
+                        <CSearchByLogin/>
+                    </div>
+                    <div className="df">
+                        <div className="df"></div>
+                        <Button
+                            variant="primary"
+                            className="buttonSetting"
+                            onClick={() => {
+                                onChat(
+                                    "media",
+                                    img,
+                                    newTitle,
+                                    prepareMembers(members),
+                                    _id
+                                );
+                            }}
+                        >
+                            <Link
+                                to="/changesdonechats"
+                                style={{
+                                    color: "white",
+                                    textDecoration: "none",
+                                }}
+                            >
+                                Apply Changes
+                            </Link>
+                        </Button>
+                        <Button variant="danger" onClick={() => onLeave(_id)}>
+                            <Link
+                                to="/changesdonechats"
+                                style={{
+                                    color: "white",
+                                    textDecoration: "none",
+                                }}
+                            >
+                                Remove chat
+                            </Link>
+                        </Button>
+
+                        <Link to={"/main/" + _id} className="changepasLink">
+                            Back to chat
+                        </Link>
+                    </div>
+                </div>
+            </div>
+        </div>
+    );
+};
+
+export const CChatEditing = connect(
+    (state) => ({
+        myProfile: state.promise.myProfile?.payload || {},
+        chatId: state.chats,
+    }),
+    { onChat: actionSetChatInfo, onLeave: removeUserChat }
+)(ChatEditing);

+ 188 - 0
Fakogram REACT project/fakogram/src/pages/ChatMsgsPage.js

@@ -0,0 +1,188 @@
+import React, { useState, useEffect } from "react";
+import { connect } from "react-redux";
+import { Link, useParams } from "react-router-dom";
+import { actionFullMsgsByChat } from "../actions";
+import { store } from "../reducers";
+import Button from "react-bootstrap/esm/Button";
+import { backURL } from "../constants";
+import { AvatarStubHeader, color } from "../components/AvatarStub";
+import { actionSendMsg } from "../actions";
+import { useDropzone } from "react-dropzone";
+
+const ChatMsgs = ({
+    chatMsgs = [],
+    getChat,
+    msgsCount = 20,
+    sendMsg,
+    msg,
+    nickOwner,
+}) => {
+   
+    const [files, setFiles] = useState(
+        msg?.media.map((mediaFile) => ({
+            ...mediaFile,
+            url: backURL + mediaFile.url,
+        })) || []
+    );
+
+    const { getRootProps, getInputProps, isDragActive } = useDropzone({
+        accept: "image/*",
+        maxFiles: 2,
+        onDrop: (acceptedFiles) => {
+            setFiles(acceptedFiles[0]);
+        },
+    });
+
+    const [msgsBlock, setMsgsBlock] = useState(0);
+
+    let { _id } = useParams();
+
+    useEffect(() => {
+        chatMsgs(_id, msgsBlock, msgsCount);
+    }, [_id]);
+
+    const [text, setText] = useState("");
+    const [msgs] = useState(getChat);
+
+    const oneChatMsgs = getChat[_id]?.messages;
+    return (
+        <>
+            <div className="chatBlock">
+                <Link to={"/chatediting/" + getChat[_id]?._id}>
+                    <div className="displayFixed">
+                        {getChat[_id]?.avatar?.url ? (
+                            <img
+                                className="forChatHeader"
+                                src={backURL + getChat[_id]?.avatar?.url}
+                            />
+                        ) : (
+                            <AvatarStubHeader
+                                login={
+                                    getChat[_id]?.title !== null
+                                        ? getChat[_id]?.title
+                                        : "chat without title"
+                                }
+                                color={color()}
+                            />
+                        )}
+                        <h5>{getChat[_id]?.title}</h5>
+                        <h6>Members: {getChat[_id]?.members.length}</h6>
+                    </div>
+                </Link>
+
+                <div className="chatContainer">
+                    <ul className="msgsContainer">
+                        {oneChatMsgs === undefined ? (
+                            <h2 className="noMsg">No messages</h2>
+                        ) : (
+                            oneChatMsgs.map((msg) => (
+                                <div
+                                    className={
+                                        msg.owner.nick === nickOwner
+                                            ? "msgLi"
+                                            : "msgOther"
+                                    }
+                                >
+                                    {/* {msg?.media[0]?.url !== undefined ? (
+                                            <img
+                                                className="msgMedia"
+                                                src={
+                                                    backURL + msg?.media[0]?.url
+                                                }
+                                            />
+                                        ) : (
+                                            ""
+                                        )} */}
+
+                                        {console.log(msg?.owner.avatar?.url)}
+                                    <div className="msgBlock">
+                                        {msg?.owner.avatar?.url === undefined ? 
+                                        <div className="avatarStubChat1"></div> :
+                                        <img
+                                            src={
+                                                backURL + msg?.owner.avatar?.url
+                                            }
+                                            className="smallForChat1"
+                                        /> }
+                                        <h5 style={{ paddingTop: "5px" }}>
+                                            {msg?.owner.nick}
+                                        </h5>
+                                    </div>
+                                    <li key={Math.random}>{msg?.text}</li>
+                                </div>
+                            ))
+                        )}
+                    </ul>
+                </div>
+
+                <div>
+                    {oneChatMsgs === getChat[_id] ? (
+                        <></>
+                    ) : (
+                        <div className="sendMsgBlock">
+                            <div className="sendBlock">
+                                <div
+                                    {...getRootProps({
+                                        className: "dropZoneStyle2",
+                                    })}
+                                >
+                                    <input {...getInputProps()} />
+                                    {isDragActive ? (
+                                        <p className="dropZoneStyleBr">
+                                            Drop the files here ...
+                                        </p>
+                                    ) : (
+                                        <img
+                                            src="https://img.icons8.com/ios-filled/344/folder-invoices--v2.png"
+                                            className="sandFile"
+                                        />
+                                    )}
+                                </div>
+                                {/* <img
+                                    src="https://img.icons8.com/ios-filled/344/folder-invoices--v2.png"
+                                    className="sandFile"
+                                    value={text}
+                            onChange={(e) => {
+                                setText(e.target.value);
+                            }}
+                                /> */}
+                                <textarea
+                                    placeholder="Write a message..."
+                                    rows="2"
+                                    value={text}
+                                    onChange={(e) => {
+                                        setText(e.target.value);
+                                    }}
+                                />
+                            </div>
+
+                            <Button
+                                onClick={() =>
+                                    sendMsg(
+                                        getChat[_id]?._id,
+                                        text,
+                                        "media",
+                                        files
+                                    )
+                                }
+                            >
+                                Send a message
+                            </Button>
+                        </div>
+                    )}
+                </div>
+            </div>
+        </>
+    );
+};
+
+export const CChatMsgs = connect(
+    (state) => ({
+        getChat: state.chats,
+        nickOwner: store.getState().promise.myProfile.payload.nick,
+    }),
+    {
+        chatMsgs: actionFullMsgsByChat,
+        sendMsg: actionSendMsg,
+    }
+)(ChatMsgs);

+ 88 - 0
Fakogram REACT project/fakogram/src/pages/ChatsAside.js

@@ -0,0 +1,88 @@
+import React, { useEffect, useState } from "react";
+import { connect } from "react-redux";
+import { actionFullChatList, actionChatsCount } from "../actions";
+import { backURL } from "../constants";
+import { Link } from "react-router-dom";
+import { AvatarStub, color } from "../components/AvatarStub";
+
+const ChatsAside = ({ chats = [], auth, ownerChats }) => {
+    const [chatBlock, setChatBlock] = useState(0);
+
+    useEffect(() => {
+        const userId = auth.payload?.sub?.id;
+        if (userId) {
+            ownerChats(userId);
+        }
+
+        return function cleanUp() {};
+    }, [chatBlock]);
+
+    return (
+        <>
+            <div className="chatsContainer" key={Math.random}>
+                {chats.map((chat, _id) => (
+                    <>
+                        <Link
+                            className="chatsList"
+                            to={`/main/${chat._id}`}
+                            key={Math.random}
+                        >
+                            <div className="chatsCard" key={Math.random()}>
+                                {chat.avatar?.url ? (
+                                    <img
+                                        key={Math.random()}
+                                        className="smallForChat"
+                                        src={backURL + chat.avatar?.url}
+                                    />
+                                ) : (
+                                    <AvatarStub
+                                        login={
+                                            chat.title !== null
+                                                ? chat.title
+                                                : "chat without title"
+                                        }
+                                        color={color()}
+                                        key={Math.random()}
+                                    />
+                                )}
+                                <div className="chatLi" key={Math.random()}>
+                                    <h5
+                                        className="chatTitle"
+                                        key={Math.random()}
+                                    >
+                                        {chat.title !== null
+                                            ? chat.title
+                                            : "chat without title"}
+                                    </h5>
+                                    <p key={Math.random()}>
+                                        {chat.lastMessage?.text.length >
+                                        parseInt("30")
+                                            ? chat.lastMessage?.text.substr(
+                                                  0,
+                                                  30
+                                              ) + "..."
+                                            : chat.lastMessage?.text.substr(
+                                                  0,
+                                                  30
+                                              )}
+                                    </p>
+                                </div>
+                            </div>
+                        </Link>
+                    </>
+                ))}
+                <Link className="newChatButton" to="/newchat" key={Math.random}>
+                    +
+                </Link>
+            </div>
+        </>
+    );
+};
+
+export const CChatsAside = connect(
+    (state) => ({
+        auth: state.auth,
+        chats: Object.values(state.chats).filter((el) => el._id),
+    }),
+    { ownerChats: actionFullChatList }
+)(ChatsAside);

+ 37 - 186
Fakogram REACT project/fakogram/src/pages/ChatsPage.js

@@ -5,206 +5,57 @@ import { Link } from "react-router-dom";
 import { AvatarStub, color } from "../components/AvatarStub";
 import { actionFullMsgsByChat } from "../actions";
 import { actionUserFindOne, store } from "../reducers";
-import { OneChat } from "./MsgPage";
 import Button from "react-bootstrap/esm/Button";
-import { CSendingField } from "../components/SendMsg";
 
-// const ChatsPage = ({ chats = [], }) => {
-//     return (
-//         <>
-//             <div className="chatsContainer">
-//                 {chats.map((chat, _id) => (
-//                     <>
 
-//                         <Link className="chatsList"  to={`/main/${chat._id}`}>
-//                             {chat.avatar?.url ? (
-//                                 <img
-//                                     className="smallForChat"
-//                                     src={backURL + chat.avatar?.url}
-//                                 />
-//                             ) : (
-//                                 <AvatarStub
-//                                     login={
-//                                         chat.title !== null
-//                                             ? chat.title
-//                                             : "chat without title"
-//                                     }
-//                                     color={color()}
-//                                 />
-//                             )}
-//                             <h5 className="chatTitle">
-//                                 {chat.title !== null
-//                                     ? chat.title
-//                                     : "chat without title"}
-//                             </h5>
 
-//                         </Link>
-//                     </>
-//                 ))}
-//                 <Link className="newChatButton" to="/newchat">
-//                     +
-//                 </Link>
-//             </div>
-//             <div>
-//                 {chats.map((chat) =>  <CChatList chatId={chat._id} chat={chat.messages} key={chat._id}/>)}
-
-//             </div>
-//         </>
-//     );
-// };
-
-// export const CChatsPage = connect(
-//     (state) => ({
-//         chats: Object.values(state.chats).filter((el) => el._id),
-//         // chat_Id: state.promise
-//     }),
-// )(ChatsPage);
-
-export const ChatPage = ({
-    match: {
-        params: { _id = store.getState().auth?.payload?.sub.id },
-    },
-    chats,
-    getData,
-    userName,
-}) => {
-    const [chatList, setChatList] = useState(chats || []);
-    const [messageList, setMessageList] = useState([]);
-
-    useEffect(() => {
-        async function getDataFunc() {
-            const res = await getData(_id);
-
-            setChatList(res.chats);
-            setMessageList(res.chats?.message);
-        }
-
-        getDataFunc();
-    }, [_id]);
-
-    const StrValid = "30";
-
-    function handleClick(_id) {
-        const filteredChatList = chatList.filter((item) => item._id === _id);
-        setMessageList(filteredChatList[0].messages);
-    }
+const ChatsPage = ({ chats = [], _id, msgOneChat, msgCount = 20,}) => {
 
+    
+    
     return (
         <>
-            <div className="mainContainer">
-                <aside className="chatsContainer">
-                    <ul className="chatAside">
-                        {chatList.map((item, index) => (
-                            <Link
-                                className="chatsList"
-                                to={`/main/${item._id}`}
-                                key={item._id}
-                            >
-                                {item.avatar?.url ? (
-                                    <img
-                                        className="smallForChat"
-                                        src={backURL + item.avatar?.url}
-                                    />
-                                ) : (
-                                    <AvatarStub
-                                        login={
-                                            item.title !== null
-                                                ? item.title
-                                                : "chat without title"
-                                        }
-                                        color={color()}
-                                    />
-                                )}
-                                <li
-                                    onClick={() => handleClick(item._id)}
-                                    className="chatLi"
-                                    key={item._id}
-                                >
-                                    <h4>{item.title}</h4>
-                                    <h6>
-                                        {item.lastMessage?.text.length >
-                                        parseInt(StrValid)
-                                            ? item.lastMessage?.text.substr(
-                                                  0,
-                                                  30
-                                              ) + "..."
-                                            : item.lastMessage?.text.substr(
-                                                  0,
-                                                  30
-                                              )}
-                                    </h6>
-                                </li>
-                            </Link>
-                        ))}
-                    </ul>
-                    <Link className="newChatButton" to="/newchat">
-                        +
-                    </Link>
-                </aside>
-                <div className="flexContainer">
-                    <main className="chatMain" id="chatMain">
-                        {messageList && messageList.length > 0 && (
-                            <div className="chatMain">
-                                {messageList.map((item1, index) => (
-                                    <div
-                                        className={
-                                            item1.owner.nick ===
-                                            store.getState().promise.myProfile
-                                                .payload.nick
-                                                ? "msgsContainer"
-                                                : "msgOtherContainer"
-                                        }
-                                    >
-                                        <div
-                                            className={
-                                                item1.owner.nick ===
-                                                store.getState().promise
-                                                    .myProfile.payload.nick
-                                                    ? "msgLi"
-                                                    : "msgOther"
-                                            }
-                                            key={index}
-                                        >
-                                            <h6>{item1.owner.nick}</h6>
-                                            <p>
-                                                {item1.text
-                                                    ? item1.text
-                                                    : "No messages"}
-                                            </p>
-                                        </div>
-                                    </div>
-                                ))}
-                            </div>
-                        )}
-                    </main>
-                    {messageList === undefined ? (
-                        <></>
-                    ) : (
-                        <div className="sendMsgBlock">
-                            <div className="sendBlock">
+            <div className="chatsContainer">
+                {chats.map((chat, _id) => (
+                    <>
+                        
+                        <Link className="chatsList"  to={`/main/${chat._id}`}>
+                            {chat.avatar?.url ? (
                                 <img
-                                    src="https://img.icons8.com/ios-filled/344/folder-invoices--v2.png"
-                                    className="sandFile"
+                                    className="smallForChat"
+                                    src={backURL + chat.avatar?.url}
                                 />
-                                <textarea
-                                    placeholder="Write a message..."
-                                    rows="2"
+                            ) : (
+                                <AvatarStub
+                                    login={
+                                        chat.title !== null
+                                            ? chat.title
+                                            : "chat without title"
+                                    }
+                                    color={color()}
                                 />
-                            </div>
-
-                            <Button>Send a message</Button>
-                        </div>
-                    )}
-                </div>
+                            )}
+                            <h5 className="chatTitle">
+                                {chat.title !== null
+                                    ? chat.title
+                                    : "chat without title"}
+                            </h5>
+
+                        </Link>
+                    </>
+                ))}
+                <Link className="newChatButton" to="/newchat">
+                    +
+                </Link>
+                
             </div>
+            
         </>
     );
 };
 
 export const CChatsPage = connect(
     (state) => ({
-        chats: state.promise.myProfile?.chats,
-        // _id: state.auth?.payload?.sub.id,
-    }),
-    { getData: actionUserFindOne }
-)(ChatPage);
+        chats: Object.values(state.chats).filter((el) => el._id),
+    }), {msgOneChat : actionFullMsgsByChat}
+)(ChatsPage);

+ 0 - 51
Fakogram REACT project/fakogram/src/pages/MsgPage.js

@@ -1,51 +0,0 @@
-import React, {useState, useEffect} from "react";
-import { connect } from "react-redux";
-
-
-export const OneChat = ({chats, _id, getData}) => {
-
-    
-
-    const [chatList, setChatList] = useState(chats || []);
-    const [messageList, setMessageList] = useState([]);
-
-    useEffect(() => {
-        async function getDataFunc() {
-            const res = await getData(_id);
-
-            setChatList(res.chats);
-            setMessageList(res.chats?.message);
-        }
-
-        getDataFunc();
-    }, [_id]);
-
-    function handleClick(_id) {
-        const filteredChatList = chatList.filter((item) => item._id === _id);
-        setMessageList(filteredChatList[0].messages);
-    }
-
-    {console.log(messageList, "messageListmessageListmessageList")}
-    return (
-        <main className="chatMain">
-            {messageList && messageList.length > 0 && (
-                <ul className="chatMain">
-                    {console.log(messageList, "messageListmessageListmessageList")}
-                    {messageList.map((item1, index) => (
-                        <li className="msgLi" key={index}>
-                            <h3>{item1.text}</h3>
-                        </li>
-                    ))}
-                </ul>
-            )}
-        </main>
-    );
-};
-
-export const COneChat = connect(
-    (state) => ({
-        chats: state.promise.myProfile?.chats,
-        // _id: state.auth?.payload?.sub.id,
-    }),
-)(OneChat);
-

+ 26 - 14
Fakogram REACT project/fakogram/src/pages/NewChatPage.js

@@ -3,8 +3,8 @@ import { connect } from "react-redux";
 import { useDropzone } from "react-dropzone";
 import { Link } from "react-router-dom";
 import Button from "react-bootstrap/esm/Button";
-import {Input, InputDebounce} from '../helpers/UserSearch'
-
+import { Input, InputDebounce } from "../helpers/UserSearch";
+import { CSearchByLogin } from "../helpers/UserSearch";
 
 import { actionSetChatInfo } from "../actions";
 
@@ -13,8 +13,8 @@ import { CChatAvatar } from "../components/Avatar";
 const ChatPage = ({ onChat, chat, myProfile, create }) => {
     const [img, setImg] = useState(null);
     const [title, setTitle] = useState(chat?.title || "");
-    const [members, setMembers] = useState(chat?.members || [myProfile])
-    
+    const [members, setMembers] = useState(chat?.members || [myProfile]);
+
     const { getRootProps, getInputProps, isDragActive } = useDropzone({
         accept: "image/*",
         maxFiles: 1,
@@ -24,18 +24,19 @@ const ChatPage = ({ onChat, chat, myProfile, create }) => {
     });
 
     function prepareMembers(members) {
-        const newMembers = []
+        const newMembers = [];
 
         for (const member of members) {
             if (create) {
                 if (member._id !== myProfile?._id) {
-                    newMembers.push({ _id: member._id })
+                    newMembers.push({ _id: member._id });
                 }
             } else {
-                newMembers.push({ _id: member._id })
+                newMembers.push({ _id: member._id });
             }
         }
-        return newMembers
+
+        return newMembers;
     }
 
     return (
@@ -45,13 +46,18 @@ const ChatPage = ({ onChat, chat, myProfile, create }) => {
                 {isDragActive ? (
                     <p className="dropZoneStyleBr">Drop the files here ...</p>
                 ) : (
-                    <CChatAvatar text="upload chat avatar" className="profileStyle" />
+                    <CChatAvatar
+                        text="upload chat avatar"
+                        className="profileStyle"
+                    />
                 )}
             </div>
             <div className="profileContainer">
                 <div className="loginNickSetting">
                     <div className="inputContainer">
-                        <label for="loginInput">Enter the name of the chat:  </label>
+                        <label for="loginInput">
+                            Enter the name of the chat:{" "}
+                        </label>
                         <input
                             className="form-control-editing form-control"
                             id="loginInput"
@@ -64,16 +70,22 @@ const ChatPage = ({ onChat, chat, myProfile, create }) => {
                     </div>
 
                     <div className="inputContainer">
-                        
+                        <CSearchByLogin/>
                     </div>
-                       
+
                     <div className="df">
                         <Button
                             variant="primary"
                             className="buttonSetting"
                             onClick={() => {
-                                onChat("media", img, title, prepareMembers(members), chat?.id);
-                                console.log("media", title, members, img);
+                                onChat(
+                                    "media",
+                                    img,
+                                    title,
+                                    prepareMembers(members),
+                                    chat?.id
+                                );
+                                
                             }}
                         >
                             <Link

+ 140 - 191
Fakogram REACT project/fakogram/src/reducers/index.js

@@ -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();
 
-