sheva77 3 rokov pred
rodič
commit
5024219205

+ 17 - 4
chat_final_bootstrap/src/Actions/ActionLogin.js

@@ -63,8 +63,7 @@ export const actionLogin = (login, password) => async (dispatch) => {
             )
         )
     );
-
-    // console.log("loginData", loginData);
+    console.log("loginData", loginData);
 
     if (loginData && loginData.data.login) {
         dispatch(actionAuthLogin(loginData.data.login));
@@ -72,7 +71,14 @@ export const actionLogin = (login, password) => async (dispatch) => {
 
         history.push(`/main`);
     } else {
-        alert("Авторизация не прошла. Проверьте логин и пароль.");
+        alert(
+            `Авторизация не прошла. ${
+                (store.getState().promise.login &&
+                    store.getState().promise.login.error &&
+                    store.getState().promise.login.error.message) ||
+                "Проблемы с сетью/сервером"
+            }`
+        );
     }
 };
 
@@ -100,6 +106,13 @@ export const actionRegistration = (login, password, nick) => async (dispatch) =>
     if (regData && regData.data && regData.data.UserUpsert && regData.data.UserUpsert.login) {
         await actionLogin(login, password)(dispatch);
     } else {
-        alert(`Ошибка регистрации: ${regData.errors && regData.errors[0].message}`);
+        alert(
+            `Ошибка регистрации: ${
+                (store.getState().promise.registration &&
+                    store.getState().promise.registration.error &&
+                    store.getState().promise.registration.error.message) ||
+                "Проблемы с сетью/сервером"
+            }`
+        );
     }
 };

+ 13 - 0
chat_final_bootstrap/src/Actions/ActionsChatUsers.js

@@ -0,0 +1,13 @@
+//
+
+export const actionNewChatList = (user) => {
+    return { type: "NEW_CHAT_LIST", user: { [user._id]: user } };
+};
+
+export const actionAddUserToChatList = (user) => {
+    return { type: "ADD_USER_TO_CHAT_LIST", user: { [user._id]: user } };
+};
+
+export const actionDelUserFromChatList = (_id) => {
+    return { type: "DELETE_USER_FROM_CHAT_LIST", _id };
+};

+ 12 - 8
chat_final_bootstrap/src/Actions/ActionsGql.js

@@ -135,7 +135,7 @@ export const actionSearchChat = (_userId = "", str = "") => async (dispatch) =>
     if (_userId) {
         searchStr = { $and: [{ ___owner: _userId }] };
         searchStr.$and.push(str);
-    } else searchStr = { str };
+    } else searchStr = { ...str };
     // console.log("actionSearchChat-searchStr: ", searchStr);
 
     let searchData = await dispatch(
@@ -158,7 +158,9 @@ export const actionSearchChat = (_userId = "", str = "") => async (dispatch) =>
     console.log("actionSearchChat - searchData:", searchData);
 };
 
-export const actionAllUsersFind = (skip = 0) => async (dispatch) => {
+export const actionAllUsersFind = (skip = 0, str = "") => async (dispatch) => {
+    str = toQuery(str);
+
     let users = await dispatch(
         actionPromise(
             "UserFind",
@@ -171,23 +173,25 @@ export const actionAllUsersFind = (skip = 0) => async (dispatch) => {
                         avatar{url}
                     }
                 }`,
-                { query: JSON.stringify([{}, { sort: [{ _id: -1 }], skip: [skip], limit: [100] }]) }
+                { query: JSON.stringify([str, { sort: [{ _id: -1 }], skip: [skip], limit: [100] }]) }
             )
         )
     );
+
     if (!users.errors) {
         users = users.data;
         // console.log("actionUserFind - UserFind:", users);
     }
 };
 
-export const actionUsersConcat = (userArr) => {
-    // console.log("actionUsersConcat - ", JSON.stringify(userArr, null, 4));
-    // console.log("actionUsersConcat - ", userArr);
-    return { type: "NEW_USER_PART", userArr };
-};
+// export const actionUsersConcat = (userArr) => {
+//     // console.log("actionUsersConcat - ", JSON.stringify(userArr, null, 4));
+//     // console.log("actionUsersConcat - ", userArr);
+//     return { type: "NEW_USER_PART", userArr };
+// };
 
 // это НИЗЗЯ!! это - затянуть всех пользователей сети к себе на Front!!
+
 // export const actionGetAllUsers = () => async (dispatch) => {
 //     let userCount = await dispatch(
 //         actionPromise(

+ 12 - 1
chat_final_bootstrap/src/Actions/index.js

@@ -1,6 +1,13 @@
 import { actionAuthLogin, actionAuthLogout, actionLogin, actionRegistration, actionUserInfo } from "./ActionLogin";
-import { gql, actionSearchMessagesByChatId, actionGetMessagesByChatId, actionSearchChat } from "./ActionsGql";
+import {
+    gql,
+    actionSearchMessagesByChatId,
+    actionGetMessagesByChatId,
+    actionSearchChat,
+    actionAllUsersFind,
+} from "./ActionsGql";
 import { actionMsgNewChat, actionCurChatId, actionMsgInsertInHead } from "./ActionsMsg";
+import { actionAddUserToChatList, actionDelUserFromChatList, actionNewChatList } from "./ActionsChatUsers";
 
 export {
     actionUserInfo,
@@ -15,4 +22,8 @@ export {
     actionMsgNewChat,
     actionCurChatId,
     actionMsgInsertInHead,
+    actionDelUserFromChatList,
+    actionAddUserToChatList,
+    actionNewChatList,
+    actionAllUsersFind,
 };

+ 2 - 2
chat_final_bootstrap/src/App.js

@@ -14,7 +14,7 @@ import {
 import history from "./history";
 import { Provider, connect } from "react-redux";
 import { Header, Footer } from "./Layout";
-import { CPageMain, PageLogin, PageNewChat, PageUpload, PageAbout, CPageSearch } from "./Pages";
+import { CPageMain, PageLogin, CPageNewChat, PageUpload, PageAbout, CPageSearch } from "./Pages";
 import { actionFindChatsByUserId } from "./Actions";
 
 import { store } from "./Reducers";
@@ -38,7 +38,7 @@ const App = () => (
 
                 <Switch>
                     <Route path="/about" component={PageAbout} exact />
-                    <Route path="/newchat" component={PageNewChat} exact />
+                    <Route path="/newchat" component={CPageNewChat} exact />
                     <Route path="/upload" component={PageUpload} exact />
                     <Route path="/" component={PageLogin} exact />
                     <Route path="/main/:_chatId" component={CPageMain} exact />

+ 25 - 11
chat_final_bootstrap/src/App.scss

@@ -23,6 +23,10 @@ div {
     background-color: #d1e7dd;
 }
 
+// ul :nth-child(odd) {
+//     color: red;
+// }
+
 ::-webkit-scrollbar-track {
     box-shadow: 5px 5px 5px -5px rgba(11, 61, 6, 0.2) inset;
     -webkit-box-shadow: 5px 5px 5px -5px rgba(11, 61, 6, 0.2) inset;
@@ -48,18 +52,8 @@ body {
     min-width: 250px;
 }
 
-.ChatsList {
-    max-height: calc(100vh - 220px);
-    overflow: auto;
-
-    img {
-        width: 48px;
-        height: 48px;
-    }
-}
-
 .allUsersList {
-    max-height: calc(100vh - 220px);
+    max-height: calc(100vh - 300px);
     overflow: auto;
 }
 
@@ -109,5 +103,25 @@ body {
     text-decoration: none;
 }
 
+.ChatsList {
+    max-height: calc(100vh - 220px);
+    overflow: auto;
+
+    img {
+        width: 48px;
+        height: 48px;
+    }
+}
+
+.ChatDashBoard {
+    min-height: calc(100vh - 110px);
+    padding: 20px;
+    table td:first-child {
+        white-space: nowrap;
+        text-align: end;
+        padding-right: 10px;
+    }
+}
+
 @import "/node_modules/bootstrap/scss/bootstrap";
 @import "./login.scss";

+ 5 - 5
chat_final_bootstrap/src/Components/AdditionalTools.js

@@ -16,7 +16,7 @@ export const AdditionalTools = ({ _userId, onSearch = null }) => {
     // }, [searchStr]);
 
     return (
-        <div className="bg-light mb-2 text-nowrap">
+        <div className="bg-light  text-nowrap ">
             {/* <input
                 className="form-control mb-2 p-2 border border-success border-2"
                 placeholder="Search by title in my chats"
@@ -26,17 +26,17 @@ export const AdditionalTools = ({ _userId, onSearch = null }) => {
             ></input> */}
             {/* <span>🔍</span> */}
             <Button
-                className="gradient"
-                variant="secondary btn-sm"
+                className="gradient ms-2 mb-2"
+                variant="success btn-sm"
                 onClick={() => {
                     history.push("/newchat");
                 }}
             >
                 New Chat
             </Button>
-            <Button className="gradient" variant="secondary btn-sm  ms-2">
+            {/* <Button className="gradient" variant="secondary btn-sm  m-2">
                 Join to another chat
-            </Button>
+            </Button> */}
         </div>
     );
 };

+ 3 - 2
chat_final_bootstrap/src/Components/ButtonToMain.js

@@ -1,10 +1,11 @@
 import { Button } from "react-bootstrap";
 import history from "../history";
+import houseSvg from "../icons/house.svg";
 
 export const ButtonToMain = () => (
     <>
-        <Button className="gradient mx-2" variant="success btn-sm" onClick={() => history.push("/main")}>
-            Вернуться на главную
+        <Button className="gradient mb-2 ms-2" variant="success btn-sm" onClick={() => history.push("/main")}>
+            <i className="bi bi-house-door"></i> Main page
         </Button>
     </>
 );

+ 3 - 0
chat_final_bootstrap/src/Components/ChatsList.js

@@ -61,6 +61,7 @@ const List = ({ arrayOfChats, userId, currentChatId }) => {
     // console.log(arrayOfChats);
     // arrayOfChats - массив всех чатов пользователя
     if (!arrayOfChats) return <></>;
+    // console.log("+++++++++++ ", arrayOfChats);
 
     // сортируем чаты так, чтобы сверху показывались чаты, в которых последнее сообщение "свежее" всех остальных
     // чаты без сообщений отправляются в конец списка
@@ -78,6 +79,8 @@ const List = ({ arrayOfChats, userId, currentChatId }) => {
     // сортировка вариант2:
     // за последнюю дату чата принимается дата последнего сообщения либо если нет сообщений,
     // то дата создания чата
+
+    //FIXME:
     arrayOfChats.sort((a, b) => {
         a = a.messages && a.messages.length ? a.messages[a.messages.length - 1].createdAt : a.createdAt;
         b = b.messages && b.messages.length ? b.messages[b.messages.length - 1].createdAt : b.createdAt;

+ 196 - 0
chat_final_bootstrap/src/Layout/AllUsersList.js

@@ -0,0 +1,196 @@
+//
+
+import { ButtonToMain } from "../Components";
+import { urlUploadConst } from "../const";
+import { actionDelUserFromChatList, actionAddUserToChatList, actionNewChatList } from "../Actions";
+import { connect } from "react-redux";
+import { useEffect } from "react";
+import { useState } from "react";
+import { store } from "../Reducers";
+import { useRef } from "react";
+import history from "../history";
+import { CUserInfo } from "../Layout";
+
+// заглушка для отладки на случай "сервер лег / вырубили свет"
+const AllUsersConst = [
+    {
+        _id: "5e25e0a41719bf13be585729",
+        login: "test3",
+        nick: "",
+        avatar: null,
+    },
+    {
+        _id: "5e25bf671719bf13be5856c4",
+        login: "t",
+        nick: "t",
+        avatar: null,
+    },
+    {
+        _id: "5f3e4cd7c3de58221910d207",
+        login: "Kiliar",
+        nick: "Kiliar",
+        avatar: null,
+    },
+    {
+        _id: "5f528e96c3de58221910d20c",
+        login: "mdm1",
+        nick: "jj",
+        avatar: null,
+    },
+    {
+        _id: "5f568538c3de58221910d20e",
+        login: "11",
+        nick: "11",
+        avatar: null,
+    },
+];
+
+const UserItem = ({ _id, login, nick, avatar, myId, addUserToList = null, delUserFromList = null }) => {
+    const [isSelected, setIsSelected] = useState(false);
+    const avatarUrl = avatar && avatar.url;
+    nick = !!nick ? nick : login;
+
+    const doSelectUser = () => {
+        if (_id !== myId) {
+            if (isSelected) {
+                if (typeof addUserToList === "function") {
+                    delUserFromList(_id);
+                }
+            } else {
+                if (typeof delUserFromList === "function") {
+                    addUserToList({ _id, login, nick, avatar });
+                }
+            }
+            setIsSelected((prev) => !prev);
+        }
+    };
+
+    return (
+        <>
+            <li
+                className={`list-group-item list-group-item-${
+                    isSelected || _id === myId ? "success" : "light"
+                } m-1 gradient shadow-sm border-2 `}
+                onClick={doSelectUser}
+            >
+                <div className="d-flex justify-content-start align-items-center">
+                    <div className="avatarka ">
+                        {avatarUrl ? (
+                            <img
+                                src={`${urlUploadConst}/${avatarUrl}`}
+                                className="border border-2 border-success"
+                            ></img>
+                        ) : (
+                            <div className="d-flex justify-content-center align-items-center bg-success border border-2 border-success gradient">
+                                <div className="fs-5 text-light fw-bolder">
+                                    {!!nick &&
+                                        `${
+                                            nick.split(" ")[0] &&
+                                            nick.split(" ")[0][0] &&
+                                            nick.split(" ")[0][0].toUpperCase()
+                                        }` +
+                                            `${
+                                                (nick.split(" ").slice(1).pop() &&
+                                                    nick.split(" ").slice(1).pop()[0] &&
+                                                    nick.split(" ").slice(1).pop()[0].toUpperCase()) ||
+                                                ""
+                                            }`}
+                                </div>
+                            </div>
+                        )}
+                    </div>
+                    <div className="text-dark fs-5  ms-2">{`${nick}`}</div>
+                </div>
+                <span className="position-absolute bottom-0 end-0  badge rounded-pill bg-secondary">
+                    {_id}
+                    <span className="visually-hidden">всего сообщений</span>
+                </span>
+            </li>
+        </>
+    );
+};
+
+const CUserItem = connect(null, { delUserFromList: actionDelUserFromChatList, addUserToList: actionAddUserToChatList })(
+    UserItem
+);
+
+const AllUsersList = ({
+    searchUserResultArr = [],
+    myId,
+    myLogin,
+    myNick,
+    myAvatarUrl,
+    myChats = [],
+    createNewChatList = null,
+    searchUserStr,
+}) => {
+    //  FIXME: следующая строка - для отладки без инета
+    // searchUserResultArr = AllUsersConst;
+
+    useEffect(() => {
+        if (typeof createNewChatList === "function")
+            createNewChatList({ _id: myId, login: myLogin, nick: myNick, avatar: { url: myAvatarUrl } });
+    }, []);
+
+    let tempResult;
+
+    // если из базы ничего еще не пришло по поиску пользователей,
+    // то посмотрим на всех, с кeм мы вообще уже общались в чатах
+
+    if (!searchUserStr || !searchUserResultArr || !searchUserResultArr.length) {
+        let tempObj = {};
+        for (let chat of myChats) {
+            for (let member of chat.members) {
+                let { _id, ...restData } = member;
+                tempObj = { ...tempObj, [_id]: member };
+            }
+        }
+        tempResult = Object.values(tempObj);
+    } else {
+        tempResult = searchUserResultArr;
+    }
+
+    // выкидываем пользователей, у которых (ник из одних пробелов) или (нет ника но логин из одних пробелов)
+
+    searchUserResultArr = tempResult
+        .filter((el) => {
+            if (!el.login) return false;
+            if (el.nick && !el.nick.replace(/ +/g, " ").trim()) {
+                return false;
+            } else {
+                return !!el.login.replace(/ +/g, " ").trim();
+            }
+        })
+        .sort((a, b) => ((a.nick || a.login) > (b.nick || b.login) ? 1 : -1));
+
+    return (
+        <div className="bg-light">
+            <h6>Choose members:</h6>
+            <ul className="list-group allUsersList" role="tablist">
+                {!!searchUserResultArr &&
+                    searchUserResultArr.map((user) => <CUserItem key={user._id} {...user} myId={myId} />)}
+            </ul>
+        </div>
+    );
+};
+
+export const CAllUsersList = connect(
+    (s, { searchUserStr }) => ({
+        searchUserStr,
+        searchUserResultArr:
+            s.promise &&
+            s.promise.UserFind &&
+            s.promise.UserFind.payload &&
+            s.promise.UserFind.payload.data &&
+            s.promise.UserFind.payload.data.UserFind,
+        myId: s.auth.payloadId,
+        myLogin: s.auth.payload,
+        myNick: s.auth.nick,
+        myAvatarUrl: s.auth.avatarUrl,
+
+        myChats: s.auth.chats,
+    }),
+    {
+        createNewChatList: actionNewChatList,
+    }
+)(AllUsersList);

+ 0 - 1
chat_final_bootstrap/src/Layout/Header.js

@@ -3,7 +3,6 @@ import { CButtonLogout, CButtonUpload } from "../Components";
 import { CLoginInfo } from "../Components";
 import { connect } from "react-redux";
 import { Nav, Navbar } from "react-bootstrap";
-import { PersonFillIcon } from "../images/icons";
 import logo from "../images/logo23.png";
 
 const Logo = ({ link = "" }) => <img src={logo} width="50px" />;

+ 1 - 1
chat_final_bootstrap/src/Layout/UserInfo.js

@@ -6,7 +6,7 @@ import { urlUploadConst } from "../const";
 import { connect } from "react-redux";
 
 const UserInfo = ({ avatarUrl }) => (
-    <div className="userInfo bg-gradient bg-success text-white p-1 py-2 mb-2 text-white">
+    <div className="bg-gradient bg-success text-white p-1 py-2 mb-2 text-white">
         <Link to="/dashboard" className="noUnderLine">
             <span className="m-2  text-nowrap avatarka">
                 <img

+ 2 - 1
chat_final_bootstrap/src/Layout/index.js

@@ -2,5 +2,6 @@ import { Header } from "./Header";
 import { Footer } from "./Footer";
 import { CUserInfo } from "./UserInfo";
 import { Sidebar } from "./Sidebar";
+import { CAllUsersList } from "./AllUsersList";
 
-export { Header, Footer, CUserInfo, Sidebar };
+export { Header, Footer, CUserInfo, Sidebar, CAllUsersList };

+ 20 - 2
chat_final_bootstrap/src/Pages/PageLogin.js

@@ -53,6 +53,10 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                             placeholder="Login"
                             className="input"
                             ref={login_ref}
+                            onKeyUp={(e) => {
+                                if (e.key === "Enter" && typeof onRegistration === "function")
+                                    onRegistration(login, pass, nick);
+                            }}
                             onChange={(e) => {
                                 setLogin(e.target.value);
                             }}
@@ -63,6 +67,10 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                             placeholder="Nick"
                             className="input"
                             ref={nick_ref}
+                            onKeyUp={(e) => {
+                                if (e.key === "Enter" && typeof onRegistration === "function")
+                                    onRegistration(login, pass, nick);
+                            }}
                             onChange={(e) => {
                                 setNick(e.target.value);
                             }}
@@ -73,6 +81,10 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                             placeholder="Password"
                             className="input"
                             ref={pass_ref}
+                            onKeyUp={(e) => {
+                                if (e.key === "Enter" && typeof onRegistration === "function")
+                                    onRegistration(login, pass, nick);
+                            }}
                             onChange={(e) => {
                                 setPass(e.target.value);
                             }}
@@ -80,7 +92,7 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                         <button
                             className="btn_view"
                             onClick={() => {
-                                onRegistration(login, pass, nick);
+                                if (typeof onRegistration === "function") onRegistration(login, pass, nick);
                                 // console.log("кнопка регистрации нажата");
                             }}
                             disabled={isLoggedIn || !login || !pass || !nick}
@@ -100,6 +112,9 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                             placeholder="Login"
                             className="input"
                             ref={login2_ref}
+                            onKeyUp={(e) => {
+                                if (e.key === "Enter" && typeof onLogin === "function") onLogin(login, pass, nick);
+                            }}
                             onChange={(e) => {
                                 setLogin(e.target.value);
                             }}
@@ -110,6 +125,9 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                             placeholder="Password"
                             className="input"
                             ref={pass2_ref}
+                            onKeyUp={(e) => {
+                                if (e.key === "Enter" && typeof onLogin === "function") onLogin(login, pass, nick);
+                            }}
                             onChange={(e) => {
                                 setPass(e.target.value);
                             }}
@@ -119,7 +137,7 @@ const LoginForm = ({ onLogin = null, onRegistration = null, isLoggedIn, mode = "
                         <button
                             className="btn_view"
                             onClick={() => {
-                                onLogin(login, pass, nick);
+                                if (typeof onLogin === "function") onLogin(login, pass, nick);
                                 // console.log("кнопка логин нажата");
                             }}
                             disabled={isLoggedIn || !login || !pass}

+ 8 - 8
chat_final_bootstrap/src/Pages/PageMain.js

@@ -19,14 +19,14 @@ const PageMain = ({
     // console.log(_chatId);
     // console.log(messages);
 
-if (
-    !_userId ||
-    !store.getState().auth ||
-    !store.getState().auth.login ||
-    _userId !== store.getState().auth.payloadId
-) {
-    history.push("/");
-}
+    if (
+        !_userId ||
+        !store.getState().auth ||
+        !store.getState().auth.login ||
+        _userId !== store.getState().auth.payloadId
+    ) {
+        history.push("/");
+    }
     //
     //
     //

+ 74 - 145
chat_final_bootstrap/src/Pages/PageNewChat.js

@@ -1,182 +1,111 @@
 import { ButtonToMain } from "../Components";
 import { urlUploadConst } from "../const";
-import { actionGetAllUsers } from "../Actions";
+import { actionGetAllUsers, actionAllUsersFind } from "../Actions";
 import { connect } from "react-redux";
 import { useEffect } from "react";
 import { useState } from "react";
 import { store } from "../Reducers";
 import { useRef } from "react";
+import history from "../history";
+import { CUserInfo } from "../Layout";
+import { CAllUsersList } from "../Layout";
+import logo from "../images/logo23.png";
+import chat_square_text from "../icons/chat-square-text.svg";
 
-const ChatDashBoard = () => {
-    return (
-        <>
-            <h4>ChatDashBoard</h4>
-        </>
-    );
-};
-
-const AllUsersConst = [
-    {
-        _id: "5e25e0a41719bf13be585729",
-        login: "test3",
-        nick: "",
-        avatar: null,
-    },
-    {
-        _id: "5e25bf671719bf13be5856c4",
-        login: "t",
-        nick: "t",
-        avatar: null,
-    },
-    {
-        _id: "5f3e4cd7c3de58221910d207",
-        login: "Kiliar",
-        nick: "Kiliar",
-        avatar: null,
-    },
-    {
-        _id: "5f528e96c3de58221910d20c",
-        login: "mdm1",
-        nick: "jj",
-        avatar: null,
-    },
-    {
-        _id: "5f568538c3de58221910d20e",
-        login: "11",
-        nick: "11",
-        avatar: null,
-    },
-];
+const MemberItem = ({ member }) => <pre>{member.login}</pre>;
 
-const UserItem = ({ _id, login, nick, avatar, myId }) => {
-    const [isSelected, setIsSelected] = useState(false);
-    const avatarUrl = avatar && avatar.url;
-    nick = !!nick ? nick : login;
-
-    const doSelectUser = () => {
-        setIsSelected((prev) => !prev);
-    };
+const ChatDashBoard = ({ members = {} }) => {
+    const [chatMembers, setChatMembers] = useState(Object.values(members));
+    useEffect(() => setChatMembers(Object.values(members)), [members]);
 
     return (
         <>
-            <li
-                className={`list-group-item list-group-item-${
-                    isSelected || _id === myId ? "success" : "light"
-                } m-1 gradient shadow-sm border-2 `}
-                onClick={doSelectUser}
-            >
-                <div className="d-flex justify-content-start align-items-center">
-                    <div className="avatarka ">
-                        {avatarUrl ? (
-                            <img
-                                src={`${urlUploadConst}/${avatarUrl}`}
-                                className="border border-2 border-success"
-                            ></img>
-                        ) : (
-                            <div className="d-flex justify-content-center align-items-center bg-success border border-2 border-success gradient">
-                                <div className="fs-5 text-light fw-bolder">
-                                    {!!nick &&
-                                        `${
-                                            nick.split(" ")[0] &&
-                                            nick.split(" ")[0][0] &&
-                                            nick.split(" ")[0][0].toUpperCase()
-                                        }` +
-                                            `${
-                                                (nick.split(" ").slice(1).pop() &&
-                                                    nick.split(" ").slice(1).pop()[0] &&
-                                                    nick.split(" ").slice(1).pop()[0].toUpperCase()) ||
-                                                ""
-                                            }`}
-                                </div>
-                            </div>
-                        )}
-                    </div>
-                    <div className="text-dark fs-5  ms-2">{`${nick}`}</div>
-                </div>
-                <span className="position-absolute bottom-0 end-0  badge rounded-pill bg-secondary">
-                    {_id}
-                    <span className="visually-hidden">всего сообщений</span>
-                </span>
-            </li>
+            <div className="ChatDashBoard bg-light">
+                <h4>ChatDashBoard</h4>
+                <table className="table table-bordered">
+                    <tbody>
+                        <tr>
+                            <td>Chat title:</td>
+                            <td>
+                                <input
+                                    className="form-control mb-2 p-2 border border-success border-2"
+                                    placeholder="Input title for new chat"
+                                ></input>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>Chat avatar:</td>
+                            <td>
+                                <span className="avatarka">
+                                    <img
+                                        src={chat_square_text}
+                                        className="border border-2 border-success bg-light "
+                                        alt="Avatar"
+                                    />
+                                </span>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>Chat members:</td>
+                            <td>
+                                {chatMembers.map((member) => (
+                                    <MemberItem key={member._id} member={member} />
+                                ))}
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
         </>
     );
 };
 
-const AllUsers = ({ searchUserResultArr = [], findUsers = null, myId, myChats = [] }) => {
-    const [users, setUsers] = useState([]);
-    // console.log(myChats);
+const CChatDashBoard = connect((s) => ({ members: s.newChatUsers }))(ChatDashBoard);
 
-    useEffect(() => {
-        if (typeof getAllUsers === "function") findUsers();
-    }, []);
+const PageNewChat = ({ doSearchUsers = null }) => {
+    const [searchUserStr, setSearchUserStr] = useState("");
+
+    // если не залогинены - вперед к регистрации/логину
+    if (!store.getState().auth || !store.getState().auth.login) {
+        history.push("/");
+    }
 
     useEffect(() => {
-        if (!searchUserResultArr.length) {
-            let tempObj = {};
-            for (let chat of myChats) {
-                for (let member of chat.members) {
-                    // console.log(members);
-                    let { _id, ...restData } = member;
-                    tempObj = { ...tempObj, [_id]: member };
-                }
-            }
-            // console.log("+++++++++++++++++++", tempObj);
-            searchUserResultArr = Object.values(tempObj);
+        if (searchUserStr && typeof doSearchUsers === "function") {
+            doSearchUsers(0, searchUserStr);
         }
-        setUsers(
-            searchUserResultArr
-                .filter((el) => {
-                    if (!el.login) return false;
-                    if (el.nick && !el.nick.replace(/ +/g, " ").trim()) {
-                        return false;
-                    } else {
-                        return !!el.login.replace(/ +/g, " ").trim();
-                    }
-                })
-                .sort((a, b) => ((a.nick || a.login) > (b.nick || b.login) ? 1 : -1))
-        );
-        // выкидываем пользователей, у которых (ник из одних пробелов) или (нет ника но логин из одних пробелов)
-        // console.log("+++++++++++++++++", users, searchUserResultArr);
-    }, [searchUserResultArr]);
-
-    return (
-        <div className="bg-light">
-            <h4>AllUsers</h4>
-            <ul className="list-group allUsersList" role="tablist">
-                {!!users && users.map((user) => <UserItem key={user._id} {...user} myId={myId} />)}
-            </ul>
-        </div>
-    );
-};
+    }, [searchUserStr]);
 
-const CAllUsers = connect((s) => ({ searchUserResultArr: [], myId: s.auth.payloadId, myChats: s.auth.chats }), {
-    findUsers: null,
-})(AllUsers);
-
-export const PageNewChat = () => {
-    useEffect(() => {
-        store.dispatch({ type: "CLEAR_USERS" });
-    }, []);
+    //FIXME: это для чего???? уже не помню и похоже не надо ))))
+    // useEffect(() => {
+    //     store.dispatch({ type: "CLEAR_USERS" });
+    // }, []);
 
     return (
         <>
-            PageNewChat
-            <ButtonToMain />
             <div className="PageMain container-fluid">
                 <div className="row g-3">
-                    <div className="col-md-4">
+                    <div className="col-md-4  bg-light">
+                        <CUserInfo />
+                        <ButtonToMain />
+
                         <input
                             className="form-control mb-2 p-2 border border-success border-2"
-                            placeholder="Search user by nick/login/_id"
-                            onInput={(e) => {}}
+                            placeholder="Search users by nick/login/_id"
+                            onInput={(e) => {
+                                setSearchUserStr(e.target.value);
+                            }}
                         ></input>
-                        <CAllUsers />
+
+                        <CAllUsersList searchUserStr={searchUserStr} />
                     </div>
                     <div className="col-md-8">
-                        <ChatDashBoard />
+                        <CChatDashBoard />
                     </div>
                 </div>
             </div>
         </>
     );
 };
+
+export const CPageNewChat = connect(null, { doSearchUsers: actionAllUsersFind })(PageNewChat);

+ 2 - 2
chat_final_bootstrap/src/Pages/index.js

@@ -1,8 +1,8 @@
 import { CPageMain } from "./PageMain";
 import { PageLogin } from "./PageLogin";
-import { PageNewChat } from "./PageNewChat";
+import { CPageNewChat } from "./PageNewChat";
 import { PageUpload } from "./PageUpload";
 import { PageAbout } from "./PageAbout";
 import { CPageSearch } from "./PageSearch";
 
-export { CPageMain, PageLogin, PageNewChat, PageUpload, PageAbout, CPageSearch };
+export { CPageMain, PageLogin, CPageNewChat, PageUpload, PageAbout, CPageSearch };

+ 20 - 0
chat_final_bootstrap/src/Reducers/index.js

@@ -69,6 +69,25 @@ function msgReduser(state = {}, action) {
 
     return state;
 }
+function newChatUsersReduser(state = {}, action) {
+    // console.log(action);
+    if (["LOGOUT", "LOGIN"].includes(action.type)) return {};
+
+    if (action.type === "ADD_USER_TO_CHAT_LIST") {
+        return { ...state, ...action.user };
+    }
+
+    if (action.type === "DELETE_USER_FROM_CHAT_LIST") {
+        delete state[action._id];
+        return state;
+    }
+
+    if (action.type === "NEW_CHAT_LIST") {
+        return { ...state, ...action.user };
+    }
+
+    return state;
+}
 
 function currentChatIdReduser(state = {}, action) {
     if (["LOGOUT", "LOGIN"].includes(action.type)) return {};
@@ -122,6 +141,7 @@ export const store = createStore(
         promise: promiseReducer,
         msg: msgReduser,
         curChatId: currentChatIdReduser,
+        newChatUsers: newChatUsersReduser,
     }),
     applyMiddleware(thunk)
 );

+ 7 - 0
chat_final_bootstrap/src/icons/chat-square-text.svg

@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg"  
+fill="currentColor" 
+class="bi bi-chat-square-text" 
+viewBox="-5 -5 26 26">
+  <path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-2.5a2 2 0 0 0-1.6.8L8 14.333 6.1 11.8a2 2 0 0 0-1.6-.8H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2.5a1 1 0 0 1 .8.4l1.9 2.533a1 1 0 0 0 1.6 0l1.9-2.533a1 1 0 0 1 .8-.4H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
+  <path d="M3 3.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zM3 6a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 6zm0 2.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5z"/>
+</svg>

+ 4 - 0
chat_final_bootstrap/src/icons/house.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-house" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M2 13.5V7h1v6.5a.5.5 0 0 0 .5.5h9a.5.5 0 0 0 .5-.5V7h1v6.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5zm11-11V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/>
+  <path fill-rule="evenodd" d="M7.293 1.5a1 1 0 0 1 1.414 0l6.647 6.646a.5.5 0 0 1-.708.708L8 2.207 1.354 8.854a.5.5 0 1 1-.708-.708L7.293 1.5z"/>
+</svg>

+ 6 - 1
chat_final_bootstrap/src/icons/person-fill.svg

@@ -1,3 +1,8 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-person-fill" viewBox="0 0 16 16">
+<svg xmlns="http://www.w3.org/2000/svg"  
+width="16" 
+height="16" 
+fill="currentColor" 
+className="bi bi-person-fill" 
+viewBox="-5 -5 26 26">
   <path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
 </svg>

+ 27 - 0
temp2.js

@@ -0,0 +1,27 @@
+let testArr = [
+    ["USA", "Mexico"],
+    ["Green", "Red", "Blue"],
+    ["Metall", "Glass", "Plastic"],
+];
+
+function arrayOfTree(arr = []) {
+    let iter = arr.reduce((a, b) => a * b.length, 1); // 18
+    let res = Array.from(Array(iter), () => Array(arr.length)); // 18*3
+
+    let step = iter;
+    let i = 0;
+
+    for (let k = 0; k < arr.length; k++) {
+        step = step / arr[k].length; // 9, 3, 1
+        // console.log("step - ", step);
+        i = 0;
+        for (let j = 0; j < iter; j++) {
+            res[j][k] = arr[k][Math.floor(i++ / step) % arr[k].length];
+        }
+    }
+    return res;
+}
+
+console.log(arrayOfTree(testArr));
+
+// не боится пустого массива на входе