2 Commits a6a2311e12 ... 69b409804c

Author SHA1 Message Date
  Ivar 69b409804c reducer fixed 2 years ago
  Ivar 3ddacceb28 reducer & markup & router fixed 2 years ago

+ 66 - 62
src/App.js

@@ -1,95 +1,86 @@
-import React, {useState, useEffect, useRef, Component} from 'react';
-import logo from './logo.svg'
+import React, {useState, useEffect, useRef, Component} from 'react'
 import './App.scss'
-import {Provider, connect}   from 'react-redux'
+import {Provider, connect} from 'react-redux'
 import {Router, Route, Link, Redirect, Switch} from 'react-router-dom'
 import createHistory from "history/createBrowserHistory"
+import {
+  store
+} from "./reducers"
+import {
+  actionFullChatList
+} from "./actions"
 
 import {
   Login, 
   Register, 
   Main,
+  ChatsPage,
+  CMsgPage
 } from "./pages"
 import {
-  actionAddChat, 
-  actionUpdateChat,
-  actionGetChatsByUser,
-  actionGetAllChats,
+  CChatList
+} from "./components"
 
-  actionFullChatList,
+import Grid from '@mui/material/Grid'
 
-  actionGetMsgsByChat,
-  actionMsgsCount,
 
-} from "./actions"
-import {store} from "./reducers"
 
-const Page404 = () => (
-  <h1>Тут ведутся работы</h1>
+const PageNoChat = () => (
+  <h1>Выбирай чат</h1>
 )
 
+const AuthSwitch = ({auth={}, getFirstChats}) => {
 
+  useEffect(() => {
+    const userId = auth.payload?.sub?.id 
+    if (userId) {
+      getFirstChats(userId, 0, 20)
+    } 
+  })
 
-// const RRoute = ({ action, component:Component, ...routeProps}) => {
-//   const WrapperComponent = (componentProps) => {
-//     action(componentProps.match)
-//     return <Component {...componentProps} />
-//   }
-//   return <Route {...routeProps} component={WrapperComponent} />
-// }
-// const CRRoute = connect(null, {action: match => ({type: 'ROUTE', match})})(RRoute)
-
-
-
-
-
-
-
-const AuthSwitch = ({token}) => {
   return (
     <>      
-      {token ? 
-      <>      
-      <Switch> 
-        <Route path="/main" component={Main} exact/>
-        <Route path="*" component={Main} /> 
-      </Switch>
+      {auth.token ? 
+      <>
+        <Main>
+
+          <Grid item xs={12} sm={4}>
+              <ChatsPage>
+                <Switch> 
+                  <Route path="/find" component={PageNoChat} />
+                  <Route path="*" component={CChatList} /> 
+                </Switch>
+              </ChatsPage>
+          </Grid>
+
+          <Grid item xs={12} sm={8}>
+            <Switch> 
+              <Route path="/main" component={PageNoChat} exact/>
+              <Route path="/main/:_id" component={CMsgPage} />
+              <Route path="*" component={PageNoChat} /> 
+            </Switch>
+          </Grid>
+
+        </Main>
       </>
       : 
       <>      
-      <Switch>        
-        <Route path="/reg" component={Register} />
-        <Route path="/login" component={Login} />
-        <Redirect from="/main" to="/login" exact/>
-        <Route path="*" component={Login} />
-      </Switch>
+        <Switch>        
+          <Route path="/reg" component={Register} />
+          <Route path="/login" component={Login} />
+          <Route path="*" component={Login} />
+        </Switch>
       </>
       }
     </>
   )
 }
-const CAuthSwitch = connect(state => ({token: state.auth.token || null}))(AuthSwitch)
+const CAuthSwitch = connect(state => ({auth: state.auth }), 
+                                                  {getFirstChats: actionFullChatList} )(AuthSwitch)
 
 const history = createHistory()
 
 function App() {
-    // "61d76d947b27dd2bab607273"  bu
-    // "617ad9262b5f0a03e6fd4037"  tst
-  let memb =  [
-      {_id: "61d76d947b27dd2bab607273"},
-      {_id: "617ad9262b5f0a03e6fd4037"},
-    ]
-    // "61dae9437b27dd2bab6072b6" ЗАЛУПА228
-
-  // store.dispatch(actionAddChat('Титул'))
-  // store.dispatch(actionUpdateChat("61dae9437b27dd2bab6072b6", 'ЗАЛУПА228', memb))
-  // store.dispatch(actionGetChatsByUser("61d76d947b27dd2bab607273"))
-  // store.dispatch(actionFullChatList("61d76d947b27dd2bab607273", 0))
-
-  // store.dispatch(actionGetMsgsByChat("61dae9437b27dd2bab6072b6"))
-  // store.dispatch(actionMsgsCount("61dae9437b27dd2bab6072b6"))
-
-
 
   return (
     <Router history={history}>
@@ -101,7 +92,20 @@ function App() {
           </div>
         </Provider>
     </Router>  
-  );
+  )
 }
+export default App
+
+
+
+
+// const RRoute = ({ action, component:Component, ...routeProps}) => {
+//   const WrapperComponent = (componentProps) => {
+//     action(componentProps.match)
+//     return <Component {...componentProps} />
+//   }
+//   return <Route {...routeProps} component={WrapperComponent} />
+// }
+// const CRRoute = connect(null, {action: match => ({type: 'ROUTE', match})})(RRoute)
+
 
-export default App;

+ 4 - 4
src/actions/authActions.js

@@ -11,12 +11,12 @@ import {
 } from './mediaActions'
 
 
-   export const actionFullLogout = () => {
+   export const actionFullLogout = () => (
       async (dispatch) => {
          await dispatch(actionAuthLogout())
-         socket.disconnect()
+         // socket.disconnect()
       }
-   }
+   )   
  
    const actionLogin = (login, password) => (
       actionPromise('login', gql(`query log($login: String, $password: String) {
@@ -30,7 +30,7 @@ import {
          if (token) {
             await dispatch(actionAuthLogin(token))
             await dispatch(actionAboutMe())
-            socket.emit('jwt', token)
+            // socket.emit('jwt', token)
          }
       }
    )

+ 15 - 14
src/components/ChatList.jsx

@@ -1,13 +1,14 @@
 import React, {useState, useEffect, useRef} from 'react';
-import Link from '@mui/material/Link';
 import List from '@mui/material/List';
 import ListItem from '@mui/material/ListItem';
 import ListItemText from '@mui/material/ListItemText';
 import ListItemAvatar from '@mui/material/ListItemAvatar';
 import Box from '@mui/material/Box';
 
-import {FloatBtn, ChatAvatar} from "../components"
-import {connect}  from 'react-redux'
+import {Link} from 'react-router-dom'
+
+import { FloatBtn, ChatAvatar } from "../components"
+import { connect }  from 'react-redux'
 import {
   actionFullChatList
 } from "../actions"
@@ -17,7 +18,7 @@ const Chat = ({chat}) => {
   const {_id, title, owner, members} = chat
 
   return (
-    <Link href={`/main/${_id}`}>
+    <Link style={{textDecoration: 'none', color: "#1976d2"}} to={`/main/${_id}`}>
       <ListItem >
         <ListItemAvatar>
           <ChatAvatar chat={chat} />
@@ -28,13 +29,15 @@ const Chat = ({chat}) => {
   )
 }
 
+const ChatList = ({chats, getData}) => {
+  // const [chatBlock, setChatBlock] = useState(0)
 
-const ChatList = ({chats, userId, getData}) => {
-  const [chatBlock, setChatBlock] = useState(0)
-
-  useEffect(() => {
-    getData(userId, chatBlock, 20)
-  },[])
+  // useEffect(() => {
+  //   const userId = auth.payload?.sub?.id 
+  //   if (userId) {
+  //     getData(userId, chatBlock, 20)
+  //   } 
+  // },[])
 
   return (
     <List sx={{ width: '100%', bgcolor: 'background.paper', position: 'relative', zIndex: 2 }}>
@@ -46,9 +49,7 @@ const ChatList = ({chats, userId, getData}) => {
     </List>
   )
 }
-export const CChatList = connect( state => ({ chats: Object.values(state.chats) || [],
-                                              userId: state.auth.payload.sub.id || null}),
-                                  {getData: actionFullChatList}
-                                  )(ChatList)
+export const CChatList = connect( state => ({ chats: Object.values(state.chats) || []}),
+                                        {getData: actionFullChatList})(ChatList)
 
 

+ 15 - 34
src/components/MsgList.jsx

@@ -1,12 +1,16 @@
 import React, {useState, useEffect, useRef} from 'react'
-import Stack from '@mui/material/Stack'
-import Box from '@mui/material/Box'
 
-
-import {connect}  from 'react-redux'
+import { connect } from 'react-redux'
 
 import { actionFullMsgsByChat } from '../actions'
 
+const msgsWrapper = {
+   display: "flex",
+   flexDirection: "column-reverse",
+   justifyContent: "flex-start",
+   alignItems: "stretch",
+}
+
 
 const Msg = ({msg}) => {
 
@@ -27,36 +31,13 @@ const MsgList = ({chats, chatId}) => {
    const msgArr =  chats[chatId]?.messages
 
    return (
-      <Box>
-         <Stack
-            direction="column-reverse"
-            justifyContent="flex-start"
-            alignItems="stretch"
-            spacing={2}
-         >
-            { msgArr ?
-               msgArr.map(msg => <Msg key={msg._id} msg={msg}/>) :
-                  <div>сообщений нема</div>         
-            }  
-
-         </Stack>
-      </Box>
-   )
-}
-const CMsgList = connect(state => ({chats: state.chats}))(MsgList)
-
+      <div style={msgsWrapper}>
+         { msgArr ?
+            msgArr.map(msg => <Msg key={msg._id} msg={msg}/>) :
+               <div>сообщений нема</div>         
+         }  
 
-const MsgListWrapp = ({match:{params:{_id}}, getData}) => {
-   const [msgBlock, setMsgBlock] = useState(0)
-
-   useEffect(() => {
-      getData(_id, msgBlock, 50)
-  },[_id])
-
-   return (
-      <>
-         <CMsgList chatId={_id} />
-      </>
+      </div>
    )
 }
-export const CMsgListWrapp= connect(null, {getData: actionFullMsgsByChat})(MsgListWrapp)
+export const CMsgList = connect(state => ({chats: state.chats}))(MsgList)

+ 4 - 3
src/components/SendingField.jsx

@@ -192,16 +192,17 @@ const SendingField = ({onSend}) => {
    const [files, setFiles] = useState([])
 
    return (
-      <Box sx={{ display: 'flex', alignItems: 'center', /* flexDirection: 'column', */
+      <Box sx={{ display: 'flex', alignItems: 'stratch', flexDirection: 'column',
             height: '100%', width: '100%'}} >
       
-         <Box sx={{ flexGrow: 1, flexShrink: 1, flexBasis: '80%', overflow: 'auto', height: '100%', backgroundColor: '#fff' }}>
+         <Box sx={{ flexGrow: 1, flexShrink: 1, overflow: 'auto', backgroundColor: '#fff' }}>
             
             <MsgDropZone setText={setText} setFiles={setFiles} files={files} />
          
          </Box>         
-         <Box sx={{ flexGrow: 1, flexShrink: 0, flexBasis: '50px'}}>
+         <Box sx={{ flexGrow: 1, flexShrink: 1}}>
             <Button 
+               sx={{ width: "100%" }}
                variant="contained" 
                endIcon={<SendIcon />} 
                onClick={() => onSend(null, text, "media", files)}

+ 2 - 2
src/components/index.js

@@ -1,6 +1,6 @@
 // универсальные компоненты, повторяющиеся на многих страницах
 import {CChatList} from './ChatList'
-import {CMsgListWrapp} from './MsgList'
+import {CMsgList} from './MsgList'
 import {CPreloaded} from './Preload'
 import {MainMenu, MenuDrawer} from './MainMenu'
 import {Header} from './Header'
@@ -14,7 +14,7 @@ import {CSendingField} from './SendingField'
 
 
 export {CChatList}
-export {CMsgListWrapp} 
+export {CMsgList} 
 export {CPreloaded} 
 export {MainMenu, MenuDrawer} 
 export {Header}  

+ 5 - 2
src/index.js

@@ -12,12 +12,15 @@ import '@fontsource/roboto/700.css';
 // import { AccessAlarm, ThreeDRotation } from '@mui/icons-material';
 
 ReactDOM.render(
-  <React.StrictMode>
+ 
     <App />
-  </React.StrictMode>,
+  ,
   document.getElementById('root')
 );
 
+
+{/* <React.StrictMode>
+</React.StrictMode> */}
 // If you want to start measuring performance in your app, pass a function
 // to log results (for example: reportWebVitals(console.log))
 // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals

File diff suppressed because it is too large
+ 0 - 1
src/logo.svg


+ 40 - 20
src/pages/ChatsPage.jsx

@@ -1,20 +1,40 @@
-
-
-
-
-
-
-// const ChatsPage = ({}) => {
-
-//    useEffect(() => {
-//       getData(userId)
-//     },[])
-
-//    return (
-//       <>
-//       </>
-//    )
-// }
-// export const CChatList = connect( state => ({userId: state.auth.payload.sub.id || null}),
-//                                              {getData: actionFullChatList}
-//                                                    )(ChatsPage)
+import React from 'react'
+
+import {
+   MenuDrawer, 
+   SearchBlock, 
+   Header, 
+} from "../components"
+
+
+const chatsPageContainer = {
+   height: "100vh",
+   width: "100%"
+}
+const chatsPageHeader = {
+   height: "60px"
+}
+const chatsPageBody = {
+   height: "calc(100vh - 60px)",
+   overflowY: "auto"
+}
+
+export const ChatsPage = ({children}) => {
+
+   return (
+      <div style={chatsPageContainer}>
+
+         <div style={chatsPageHeader}>
+            <Header>
+               <MenuDrawer />
+               <SearchBlock />
+            </Header>  
+         </div>
+
+         <div style={chatsPageBody}>
+            {children}
+         </div>
+
+      </div>
+   )
+}

+ 3 - 93
src/pages/Main.jsx

@@ -1,109 +1,19 @@
-import React, {useState, useEffect, useRef} from 'react';
-import {Router, Route, Redirect, Switch} from 'react-router-dom'
-
-import Button from '@mui/material/Button';
-import Typography from '@mui/material/Typography';
-import Link from '@mui/material/Link';
+import React from 'react';
 import CssBaseline from '@mui/material/CssBaseline';
 import Grid from '@mui/material/Grid';
-import Box from '@mui/material/Box';
 import Container from '@mui/material/Container';
 import { createTheme, ThemeProvider } from '@mui/material/styles';
 
 
-
-import {
-   MenuDrawer, 
-   SearchBlock, 
-   CChatList, 
-   Header, 
-   CUserAvatar, 
-   CSendingField,
-   CMsgListWrapp
-} from "../components"
-import {
-   actionChangePass,
-   actionAddChat
- } from "../actions"
- import {store} from "../reducers"
-
-
- const PageNoChat = () => (
-   <h1>Выбирай чат</h1>
- )
-
 const theme = createTheme()
-export const Main = ({}) => {
-
+export const Main = ({children}) => {
    return (
       <ThemeProvider theme={theme}>
          <Container component="main" maxWidth="xxl">
             <CssBaseline />
-
             <Grid container direction="row" justifyContent="center" alignItems="start" >
-
-               <Grid item xs={12} sm={4}>
-                  <Grid container direction="column" justifyContent="space-between" alignItems="stretch" 
-                        height="100vh">
-
-                     <Grid item height="60px"> 
-                        <Header> 
-
-                           <MenuDrawer />
-                           <CUserAvatar />
-
-                           <SearchBlock />
-
-                        </Header>                        
-                     </Grid>
-
-                     <Grid container direction="column" justifyContent="start" alignItems="stretch" 
-                           height="calc(100vh - 60px)" sx={{overflowY:"scroll"}}>
-                        
-                        <CChatList />
-
-                     </Grid>
-
-                  </Grid>              
-               </Grid>
-
-               <Grid item xs={12} sm={8}>
-
-
-                  <Grid container direction="column" justifyContent="space-between" alignItems="stretch" 
-                        height="100vh" sx={{backgroundColor: '#eee'}} >
-                     
-                     
-                     <Grid item height="60px"> 
-                        <Header> 
-                           <Typography variant="body1" color="inherit" component="div">
-                              шапка2: инфо о чате и управление, управление сообщениями, ?поиск
-                           </Typography>
-                        </Header>                    
-                     </Grid>
-
-                     <Grid item sx={{ flexGrow: 0, flexShrink: 1, overflowY: "scroll" }} height="calc(100vh - 300px)" >
-
-
-                           
-                        <Switch> 
-                           <Route path="/main/:_id" component={CMsgListWrapp} />
-                           <Route path="*" component={PageNoChat} /> 
-                        </Switch>
-
-                     </Grid>
-
-                     <Grid item  sx={{ flexGrow: 0 }} height="max-content" > 
-                           <CSendingField />
-                     </Grid>
-
-                  </Grid>  
-                  
-                              
-               </Grid>
-
+               {children}
             </Grid>
-
          </Container>
       </ThemeProvider>
    )

+ 75 - 0
src/pages/MsgPage.jsx

@@ -0,0 +1,75 @@
+import React, {useState, useEffect} from 'react';
+
+import {
+   Header, 
+   CMsgList,
+   CSendingField,   
+} from "../components"
+
+import {
+   actionFullMsgsByChat
+ } from "../actions"
+ import { connect } from 'react-redux'
+
+
+
+const msgPageContainer = {
+   backgroundColor: '#eee',
+   height: "100vh",
+   width: "100%"
+}
+const msgPageHeader = {
+   height: "60px"
+}
+const msgPageBody = {
+   height: "calc(100vh - 60px)",
+   display: "flex",
+   flexDirection: "column",
+   justifyContent: "space-between"
+}
+
+const msgs = {
+   flexGrow: 1,
+   overflowY: "auto",
+}
+const msgSend = {
+   flexGrow: 0,
+   height: "max-content",
+   maxHeight: "60%",
+}
+
+const MsgPage = ({ match:{params:{_id}}, getData }) => {
+
+   useEffect(() => {
+      getData(_id, 0, 50)
+   },[_id])
+
+   return (
+      <>  
+         <div style={msgPageContainer}>
+
+            <div style={msgPageHeader}>
+               <Header> 
+                  <div>
+                     шапка2: инфо о чате и управление, управление сообщениями
+                  </div>
+               </Header>  
+            </div>
+
+            <div style={msgPageBody}>
+
+               <div style={msgs}>
+                  <CMsgList key={_id} chatId={_id} />
+               </div>
+
+               <div style={msgSend}>
+                  <CSendingField key={_id} chatId={_id} />
+               </div>       
+
+            </div>
+
+         </div>              
+      </>
+   )
+}
+export const CMsgPage = connect( null, {getData: actionFullMsgsByChat})(MsgPage)

+ 2 - 2
src/pages/index.js

@@ -2,13 +2,13 @@
 import {Login} from './Login'
 import {Register} from './Register'
 import {Main} from './Main'
-import {CChatsPage} from './ChatsPage'
+import {ChatsPage} from './ChatsPage'
 import {CMsgPage} from './MsgPage'
 
 
 export {Login} 
 export {Register} 
 export {Main} 
-export {CChatsPage} 
+export {ChatsPage} 
 export {CMsgPage} 
 

+ 15 - 11
src/reducers/chatsReducer.js

@@ -25,16 +25,13 @@
       CHATS() {
         if (payload && payload.length > 0) {
 
-          const newChats = {}        
+          const newChats = state      
           for (const chat of payload) {
             newChats[chat._id] = chat
           }
 
           const newState = Object.fromEntries(
-            Object.entries({
-              ...state,
-              ...newChats
-            }).sort((a, b) => {
+            Object.entries(newChats).sort((a, b) => {
               if (a[1].lastModified > b[1].lastModified) {
                 return -1
               }
@@ -60,12 +57,19 @@
         
           const chatId = payload[0]?.chat?._id
 
-          // console.log(chatId, state[chatId]?.messages, payload)
+          const msgState = state[chatId]?.messages || []
+          
+          for (const newMsg of payload || []) {   
+              const currIndex = msgState.findIndex(oldMsg => oldMsg._id === newMsg._id)
+              
+              if (currIndex === -1) {
+                msgState.push(newMsg)                
+              } else {
+                msgState[currIndex] = newMsg
+              }
+          }
 
-          const msgState = [
-            ...state[chatId]?.messages, 
-            ...payload
-          ].sort((a, b) => {
+          const newMsgState = msgState.sort((a, b) => {
             if (a._id > b._id) {
               return -1
             }
@@ -79,7 +83,7 @@
             ...state,
             [chatId]: {
               ...state[chatId],
-              messages: msgState
+              messages: newMsgState
             }
           }
           return newState

+ 2 - 2
src/reducers/index.js

@@ -18,7 +18,7 @@ import {
     actionUserFindOne,
     actionAboutMe
 } from './findUserActions'
-import {store, socket} from './store'
+import {store} from './store'
 
 
 export {
@@ -39,7 +39,7 @@ export {
     actionUserFindOne,
     actionAboutMe
 } 
-export {store, socket} 
+export {store} 
 
 
 

+ 17 - 16
src/reducers/store.js

@@ -31,28 +31,29 @@ store.subscribe(() => console.log(store.getState()))
 
 
 
-export const socket = window.io("ws://chat.fs.a-level.com.ua")
+// export const socket = window.io("ws://chat.fs.a-level.com.ua")
+
+// socket.on('jwt_ok',   (data) => console.log(data))
+// socket.on('jwt_fail', (error) => console.log(error))
+
+// socket.on('msg', (msg) => { 
+//    console.log('пришло смс')
+//     store.dispatch(actionMsgOne(msg)) 
+// })
+// socket.on('chat', (chat) => { 
+//     store.dispatch(actionChatOne(chat)) 
+// })
+// socket.on('chat_left', (chat) => { 
+//     store.dispatch(actionChatLeft(chat)) 
+// })
+
+
 
 // if (localStorage.authToken) {
 //    socket.emit('jwt', localStorage.authToken)
 // }
 // socket.disconnect()
 
-socket.on('jwt_ok',   (data) => console.log(data))
-socket.on('jwt_fail', (error) => console.log(error))
-
-socket.on('msg', (msg) => { 
-   console.log('пришло смс')
-    store.dispatch(actionMsgOne(msg)) 
-})
-socket.on('chat', (chat) => { 
-    store.dispatch(actionChatOne(chat)) 
-})
-socket.on('chat_left', (chat) => { 
-    store.dispatch(actionChatLeft(chat)) 
-})
-
-
 // combineReducers({cart: localStoredReducer(cartReducer, 'cart'),
 //                  promise: localStoredReducer(promiseReducer, 'promise') })
 //для пользы при работе с промисами надо бы пока PENDING не делать payload undefined