瀏覽代碼

Project CodePen Done

Vadym Hlushko 3 年之前
父節點
當前提交
97d0ee5710
共有 48 個文件被更改,包括 980 次插入624 次删除
  1. 16 17
      projectreact/src/App.css
  2. 14 18
      projectreact/src/App.js
  3. 1 0
      projectreact/src/actions/actionAuthLogin.js
  4. 1 0
      projectreact/src/actions/actionAuthLogout.js
  5. 8 0
      projectreact/src/actions/actionFindUser.js
  6. 10 0
      projectreact/src/actions/actionFullAvatar.js
  7. 17 0
      projectreact/src/actions/actionFullLogin.js
  8. 11 0
      projectreact/src/actions/actionFullRegister.js
  9. 3 0
      projectreact/src/actions/actionImgFind.js
  10. 5 0
      projectreact/src/actions/actionPending.js
  11. 14 0
      projectreact/src/actions/actionPromise.js
  12. 6 0
      projectreact/src/actions/actionRegister.js
  13. 6 0
      projectreact/src/actions/actionRejected.js
  14. 6 0
      projectreact/src/actions/actionResolved.js
  15. 7 0
      projectreact/src/actions/actionSearch.js
  16. 8 0
      projectreact/src/actions/actionSetAvatar.js
  17. 12 0
      projectreact/src/actions/actionSnippetAdd.js
  18. 10 0
      projectreact/src/actions/actionSnippetById.js
  19. 6 0
      projectreact/src/actions/actionSnippetFindByOwner.js
  20. 18 0
      projectreact/src/actions/actionUploadFile.js
  21. 16 0
      projectreact/src/actions/gql.js
  22. 0 249
      projectreact/src/actions/index.js
  23. 131 0
      projectreact/src/actions/requests.js
  24. 16 9
      projectreact/src/components/ava.js
  25. 9 12
      projectreact/src/components/editor.js
  26. 17 17
      projectreact/src/components/header.js
  27. 11 6
      projectreact/src/components/logo.js
  28. 13 12
      projectreact/src/components/nick.js
  29. 34 18
      projectreact/src/components/nickHeader.js
  30. 25 0
      projectreact/src/components/privateRoute.js
  31. 11 6
      projectreact/src/components/profile.js
  32. 38 40
      projectreact/src/components/routes.js
  33. 36 12
      projectreact/src/components/select.js
  34. 58 12
      projectreact/src/components/snippet.js
  35. 3 6
      projectreact/src/components/tester.js
  36. 41 22
      projectreact/src/pages/cabinet.js
  37. 9 10
      projectreact/src/pages/homePage.js
  38. 13 8
      projectreact/src/pages/login.js
  39. 59 16
      projectreact/src/pages/project.js
  40. 41 22
      projectreact/src/pages/projects.js
  41. 95 56
      projectreact/src/pages/reg.js
  42. 59 0
      projectreact/src/pages/search.js
  43. 1 1
      projectreact/src/pages/upload.js
  44. 26 0
      projectreact/src/reducers/authReducer.js
  45. 0 55
      projectreact/src/reducers/index.js
  46. 13 0
      projectreact/src/reducers/promiseReducer.js
  47. 7 0
      projectreact/src/reducers/reducers.js
  48. 19 0
      projectreact/src/reducers/store.js

+ 16 - 17
projectreact/src/App.css

@@ -1,23 +1,17 @@
-
-
 .App {
-  font: 400 14px 'Open Sans', 'Arial', 'Helvetica Neue', 'Helvetica', sans-serif;
-  /* overflow-x:hidden;  для горизонтального */
+  font: 400 14px "Open Sans", "Arial", "Helvetica Neue", "Helvetica", sans-serif;
+  overflow-x: hidden;
+  max-width: 100%;
 }
 
 .editor {
-display: inline-block;
-
+  display: inline-block;
 }
 
 .ava {
   cursor: pointer;
 }
 
-/* .ace_marker-layer .ace_selected-word {
-  border: 1px solid #494949
-} */
-
 .select {
   margin: auto;
 }
@@ -38,15 +32,20 @@ display: inline-block;
 }
 
 .form-elegant .font-small {
-  font-size: 0.8rem; }
+  font-size: 0.8rem;
+}
 
 .form-elegant .z-depth-1a {
-  -webkit-box-shadow: 0 2px 5px 0 rgba(55, 161, 255, 0.26), 0 4px 12px 0 rgba(121, 155, 254, 0.25);
-  box-shadow: 0 2px 5px 0 rgba(55, 161, 255, 0.26), 0 4px 12px 0 rgba(121, 155, 254, 0.25); }
+  -webkit-box-shadow: 0 2px 5px 0 rgba(55, 161, 255, 0.26),
+    0 4px 12px 0 rgba(121, 155, 254, 0.25);
+  box-shadow: 0 2px 5px 0 rgba(55, 161, 255, 0.26),
+    0 4px 12px 0 rgba(121, 155, 254, 0.25);
+}
 
 .form-elegant .z-depth-1-half,
 .form-elegant .btn:hover {
-  -webkit-box-shadow: 0 5px 11px 0 rgba(85, 182, 255, 0.28), 0 4px 15px 0 rgba(36, 133, 255, 0.15);
-  box-shadow: 0 5px 11px 0 rgba(85, 182, 255, 0.28), 0 4px 15px 0 rgba(36, 133, 255, 0.15); }
-
-
+  -webkit-box-shadow: 0 5px 11px 0 rgba(85, 182, 255, 0.28),
+    0 4px 15px 0 rgba(36, 133, 255, 0.15);
+  box-shadow: 0 5px 11px 0 rgba(85, 182, 255, 0.28),
+    0 4px 15px 0 rgba(36, 133, 255, 0.15);
+}

+ 14 - 18
projectreact/src/App.js

@@ -1,23 +1,19 @@
-import React from 'react';
-import './App.css';
-import {Provider, connect}   from 'react-redux';
-import ConnectedRoutes from './components/routes';
-import store from './reducers';
-import CTester from './components/tester';
-
-
+import React from "react";
+import "./App.css";
+import { Provider } from "react-redux";
+import Routes from "./components/routes";
+import { store } from "./reducers/store";
+import CTester from "./components/tester";
 
 function App() {
-return (
-  
-  <>
-  
-  <Provider store = {store}>
-  <CTester/>
- <ConnectedRoutes/>
- </Provider>
- </>
-)
+  return (
+    <>
+      <Provider store={store}>
+        {/* <CTester/> */}
+        <Routes />
+      </Provider>
+    </>
+  );
 }
 
 export default App;

+ 1 - 0
projectreact/src/actions/actionAuthLogin.js

@@ -0,0 +1 @@
+export const actionAuthLogin = (token) => ({ type: "LOGIN", token });

+ 1 - 0
projectreact/src/actions/actionAuthLogout.js

@@ -0,0 +1 @@
+export const actionAuthLogout = () => ({ type: "LOGOUT" });

+ 8 - 0
projectreact/src/actions/actionFindUser.js

@@ -0,0 +1,8 @@
+import { actionPromise } from "./actionPromise";
+import { userFind } from "./requests";
+
+export const actionFindUser = () => async (dispatch, getState) => {
+    return await dispatch(
+      actionPromise("findUser", userFind(getState()?.auth?.payload?.sub?.id))
+    );
+  };

+ 10 - 0
projectreact/src/actions/actionFullAvatar.js

@@ -0,0 +1,10 @@
+import { actionUploadFile } from "./actionUploadFile";
+import { actionSetAvatar } from "./actionSetAvatar";
+import { actionFindUser } from "./actionFindUser";
+
+export const actionFullAvatar = (file) => async (dispatch) => {
+    let result = await dispatch(actionUploadFile(file));
+    await dispatch(actionSetAvatar(result._id));
+    await dispatch(actionFindUser());
+  };
+  

+ 17 - 0
projectreact/src/actions/actionFullLogin.js

@@ -0,0 +1,17 @@
+import { actionPromise } from "./actionPromise";
+import { log } from "./requests";
+import { actionAuthLogin } from "./actionAuthLogin";
+import { actionFindUser } from "./actionFindUser";
+
+export const actionFullLogin = (login, password) => async (dispatch) => {
+  let result = await dispatch(actionPromise("login", log(login, password)));
+  if (result?.data?.login !== null) {
+    dispatch(actionAuthLogin(result.data.login));
+  } else {
+    alert("Такого пользователя не существует!");
+  }
+  await dispatch(actionFindUser());
+};
+
+
+

+ 11 - 0
projectreact/src/actions/actionFullRegister.js

@@ -0,0 +1,11 @@
+import { actionRegister } from "./actionRegister";
+import { actionFullLogin } from "./actionFullLogin";
+
+export const actionFullRegister = (login, password) => async (dispatch) => {
+    let result = await dispatch(actionRegister(login, password));
+    if (result?.data?.createUser !== null) {
+      await dispatch(actionFullLogin(login, password));
+    } else {
+      alert("Такой пользователь уже есть!");
+    }
+  };

+ 3 - 0
projectreact/src/actions/actionImgFind.js

@@ -0,0 +1,3 @@
+export const actionImgFind = () => async (dispatch) => {
+    return await dispatch(actionPromise("img", imgFind()));
+  };

+ 5 - 0
projectreact/src/actions/actionPending.js

@@ -0,0 +1,5 @@
+export const actionPending = (name) => ({
+    type: "PROMISE",
+    status: "PENDING",
+    name,
+  });

+ 14 - 0
projectreact/src/actions/actionPromise.js

@@ -0,0 +1,14 @@
+import { actionPending } from "./actionPending";
+import { actionResolved } from "./actionResolved";
+import { actionRejected } from "./actionRejected";
+
+export const actionPromise = (name, promise) => async (dispatch) => {
+  dispatch(actionPending(name));
+  try {
+    let payload = await promise;
+    dispatch(actionResolved(name, payload));
+    return payload;
+  } catch (error) {
+    dispatch(actionRejected(name, error));
+  }
+};

+ 6 - 0
projectreact/src/actions/actionRegister.js

@@ -0,0 +1,6 @@
+import { actionPromise } from "./actionPromise";
+import { reg } from "./requests";
+
+export const actionRegister = (login, password) => async (dispatch) => {
+    return await dispatch(actionPromise("register", reg(login, password)));
+  };

+ 6 - 0
projectreact/src/actions/actionRejected.js

@@ -0,0 +1,6 @@
+export const actionRejected = (name, error) => ({
+    type: "PROMISE",
+    status: "REJECTED",
+    name,
+    error,
+  });

+ 6 - 0
projectreact/src/actions/actionResolved.js

@@ -0,0 +1,6 @@
+export const actionResolved = (name, payload) => ({
+    type: "PROMISE",
+    status: "RESOLVED",
+    name,
+    payload,
+  });

+ 7 - 0
projectreact/src/actions/actionSearch.js

@@ -0,0 +1,7 @@
+import { search } from "./requests";
+import { actionPromise } from "./actionPromise";
+
+export const actionSearch = (string) => async (dispatch) => {
+    return await dispatch(actionPromise('searchSnippet', search(string)))
+}
+

+ 8 - 0
projectreact/src/actions/actionSetAvatar.js

@@ -0,0 +1,8 @@
+import { actionPromise } from "./actionPromise";
+import { ava } from "./requests";
+
+export const actionSetAvatar = (id) => async (dispatch, getState) => {
+    return await dispatch(
+      actionPromise("setAvatar", ava(getState()?.auth?.payload?.sub?.id, id))
+    );
+  };

+ 12 - 0
projectreact/src/actions/actionSnippetAdd.js

@@ -0,0 +1,12 @@
+import { actionPromise } from "./actionPromise";
+import { snippetAdd } from "./requests";
+
+export const actionSnippetAdd =
+(title, description, files, idSnippet) => async (dispatch) => {
+  return await dispatch(
+    actionPromise(
+      "addSnippet",
+      snippetAdd(title, description, files, idSnippet)
+    )
+  );
+};

+ 10 - 0
projectreact/src/actions/actionSnippetById.js

@@ -0,0 +1,10 @@
+import { actionPromise } from "./actionPromise";
+import { snippetById } from "./requests";
+
+export const actionSnippetById =
+(id) => async (dispatch) => {
+  return await dispatch(
+    actionPromise("findSnippetById",
+    snippetById(id))
+  );
+};

+ 6 - 0
projectreact/src/actions/actionSnippetFindByOwner.js

@@ -0,0 +1,6 @@
+import { actionPromise } from "./actionPromise";
+import { snippetByOwner } from "./requests";
+
+export const actionSnippetFindByOwner = (id) => async (dispatch) => {
+    return await dispatch(actionPromise("findSnippet", snippetByOwner(id)));
+  };

+ 18 - 0
projectreact/src/actions/actionUploadFile.js

@@ -0,0 +1,18 @@
+import { actionPromise } from "./actionPromise";
+
+export const actionUploadFile = (files) => async (dispatch) => {
+    let fd = new FormData();
+    fd.append("photo", files);
+    return await dispatch(
+      actionPromise(
+        "upload",
+        fetch("/upload", {
+          method: "POST",
+          headers: localStorage.authToken
+            ? { Authorization: "Bearer " + localStorage.authToken }
+            : {},
+          body: fd,
+        }).then((res) => res.json())
+      )
+    );
+};

+ 16 - 0
projectreact/src/actions/gql.js

@@ -0,0 +1,16 @@
+const getGQL =
+  (url) =>
+  (query, variables = {}) =>
+    fetch(url, {
+      method: "POST",
+      headers: {
+        //Accept: "application/json",
+        "Content-Type": "application/json",
+        ...(localStorage.authToken
+          ? { Authorization: "Bearer " + localStorage.authToken }
+          : {}),
+      },
+      body: JSON.stringify({ query, variables }),
+    }).then((res) => res.json());
+
+export const gql = getGQL("/graphql");

+ 0 - 249
projectreact/src/actions/index.js

@@ -1,249 +0,0 @@
-const getGQL =
-  (url) =>
-  (query, variables = {}) =>
-    fetch(url, {
-      method: "POST",
-      headers: {
-        //Accept: "application/json",
-        "Content-Type": "application/json",
-        ...(localStorage.authToken
-          ? { Authorization: "Bearer " + localStorage.authToken }
-          : {}),
-      },
-      body: JSON.stringify({ query, variables }),
-    }).then((res) => res.json());
-
-let gql = getGQL("/graphql");
-
-export const actionPending = (name) => ({
-  type: "PROMISE",
-  status: "PENDING",
-  name,
-});
-export const actionResolved = (name, payload) => ({
-  type: "PROMISE",
-  status: "RESOLVED",
-  name,
-  payload,
-});
-export const actionRejected = (name, error) => ({
-  type: "PROMISE",
-  status: "REJECTED",
-  name,
-  error,
-});
-
-export const actionPromise = (name, promise) => async (dispatch) => {
-  dispatch(actionPending(name));
-  try {
-    let payload = await promise;
-    dispatch(actionResolved(name, payload));
-    return payload;
-  } catch (error) {
-    dispatch(actionRejected(name, error));
-  }
-};
-
-let log = async (login, password) => {
-  let query = ` query log($l:String!,$p:String!) {
-      login(login:$l,password:$p)
-    }`;
-  let qVariables = {
-    l: login,
-    p: password,
-  };
-  let result = await gql(query, qVariables);
-  return result;
-};
-
-let reg = async (login, password) => {
-  let query = `mutation reg($l:String! , $p:String!) {
-      createUser(login:$l,password:$p){
-  _id login
-}
-}`;
-  let qVariables = {
-    l: login,
-    p: password,
-  };
-  let result = await gql(query, qVariables);
-  return result;
-};
-
-export const actionAuthLogin = (token) => ({ type: "LOGIN", token });
-export const actionAuthLogout = () => ({ type: "LOGOUT" });
-export const actionFullLogin = (login, password) => async (dispatch) => {
-  let result = await dispatch(actionPromise("login", log(login, password)));
-  if (result?.data?.login !== null) {
-    dispatch(actionAuthLogin(result.data.login));
-  } else {
-    alert("такого пользователя не существует");
-  }
-  await dispatch(actionFindUser());
-};
-
-export const actionRegister = (login, password) => async (dispatch) => {
-  return await dispatch(actionPromise("register", reg(login, password)));
-};
-
-export const actionFullRegister = (login, password) => async (dispatch) => {
-  let result = await dispatch(actionRegister(login, password));
-
-  if (result?.data?.createUser !== null) {
-    await dispatch(actionFullLogin(login, password));
-  } else {
-    alert("Такой пользователь уже есть");
-  }
-};
-
-export const imgFind = async () => {
-  return await gql(`query fhbg{
-    ImageFind(query:"[{}]"){
-      url owner{
-        nick
-      }
-    }
-  }`);
-};
-
-const userFind = (_id) => {
-  return gql(
-    `query userOne($query:String) {
-                                     UserFindOne(query:$query){
-                                       _id avatar{
-                                         url
-                                       }
-                                     }
-}`,
-    { query: JSON.stringify([{ _id }]) }
-  );
-};
-
-const snippetByOwner = async (id) => {
-  let query = `query snippetFind($query:String){
-      SnippetFind(query:$query){
-                        owner{
-                          _id 
-                        }
-            title description _id files {
-             type text name
-           }
-        }
-}`;
-  let variables = {
-    query: JSON.stringify([{___owner: id } , {sort:[{_id: -1}]}])
-  };
-
-  let res = gql(query, variables);
-  return res;
-}
-
-const snippetById = async(id) => {
-  let query = `query snippetFind($query:String){
-    SnippetFind(query:$query){
-                      owner{
-                        _id 
-                      }
-          title description _id files {
-           type text name
-         }
-      }
-}`;
-let variables = {
-  query: JSON.stringify([{_id: id }])
-};
-
-let res = gql(query, variables);
-return res;
-}
-
-
-
-let ava = async (idUser, id) => {
-  let query = `mutation setAvatar($idUser:String , $idAvatar:ID){ 
-    UserUpsert(user:{_id: $idUser, avatar: {_id: $idAvatar}}){
-        _id, avatar{
-            url
-        }
-    }
-}`;
-  let qVariables = { idUser: idUser, idAvatar: id };
-
-  let res = await gql(query, qVariables);
-  return res;
-};
-
-let snippetAdd = async (title, description, files , idSnippet) => {
-  let query = `mutation newSnippet($snippet:SnippetInput) {
-    SnippetUpsert(snippet:$snippet){
-      _id
-    }
-  }`;
-
-  let qVariables = { snippet: { title, description, files } ,_id: idSnippet  };
-
-  let res = await gql(query, qVariables);
-  return res;
-};
-
-export const actionImgFind = () => async (dispatch) => {
-  return await dispatch(actionPromise("img", imgFind()));
-};
-
-export const actionFindUser = () => async (dispatch, getState) => {
-  return await dispatch(
-    actionPromise("findUser", userFind(getState().auth.payload.sub.id))
-  );
-};
-
-export const actionSetAvatar = (id) => async (dispatch, getState) => {
-  return await dispatch(
-    actionPromise("setAvatar", ava(getState().auth.payload.sub.id, id))
-  );
-};
-
-export const actionUploadFile = (files) => async (dispatch) => {
-  let fd = new FormData();
-  fd.append("photo", files);
-  return await dispatch(
-    actionPromise(
-      "upload",
-      fetch("/upload", {
-        method: "POST",
-        headers: localStorage.authToken
-          ? { Authorization: "Bearer " + localStorage.authToken }
-          : {},
-        body: fd,
-      }).then((res) => res.json())
-    )
-  );
-};
-
-export const actionFullAvatar = (file) => async (dispatch) => {
-  let result = await dispatch(actionUploadFile(file));
-  await dispatch(actionSetAvatar(result._id));
-  await dispatch(actionFindUser());
-};
-
-export const actionSnippetAdd =
-  (title, description, files , idSnippet) => async (dispatch) => {
-    return await dispatch(
-      actionPromise("addSnippet",
-      snippetAdd(title, description, files , idSnippet))
-    );
-  };
-
-  export const actionSnippetFindByOwner =
-  (id) => async (dispatch) => {
-    return await dispatch(
-      actionPromise("findSnippet",
-      snippetByOwner(id))
-    );
-  };
-  export const actionSnippetById =
-  (id) => async (dispatch) => {
-    return await dispatch(
-      actionPromise("findSnippetById",
-      snippetById(id))
-    );
-  };

+ 131 - 0
projectreact/src/actions/requests.js

@@ -0,0 +1,131 @@
+import { gql } from "./gql";
+
+export const snippetById = async(id) => {
+    let query = `query snippetFind($query:String){
+      SnippetFind(query:$query){
+                        owner{
+                          _id 
+                        }
+            title description _id files {
+             type text name
+           }
+        }
+  }`;
+  let variables = {
+    query: JSON.stringify([{_id: id }])
+  };
+  
+  let res = gql(query, variables);
+  return res;
+  }
+  export const snippetByOwner = async (id) => {
+    let query = `query snippetFind($query:String){
+        SnippetFind(query:$query){
+                          owner{
+                            _id 
+                          }
+              title description _id files {
+               type text name
+             }
+          }
+  }`;
+    let variables = {
+      query: JSON.stringify([{___owner: id } , {sort:[{_id: -1}]}])
+    };
+  
+    let res = gql(query, variables);
+    return res;
+  }
+  export const userFind = (_id) => {
+    return gql(
+      `query userOne($query:String) {
+                                       UserFindOne(query:$query){
+                                         _id avatar{
+                                           url
+                                         }
+                                       }
+  }`,
+      { query: JSON.stringify([{ _id }]) }
+    );
+  };
+  export const reg = async (login, password) => {
+    let query = `mutation reg($l:String! , $p:String!) {
+        createUser(login:$l,password:$p){
+    _id login
+  }
+  }`;
+    let qVariables = {
+      l: login,
+      p: password,
+    };
+    let result = await gql(query, qVariables);
+    return result;
+  };
+  export const log = async (login, password) => {
+    let query = ` query log($l:String!,$p:String!) {
+        login(login:$l,password:$p)
+      }`;
+    let qVariables = {
+      l: login,
+      p: password,
+    };
+    let result = await gql(query, qVariables);
+    return result;
+  };
+  export const imgFind = async () => {
+    return await gql(`query fhbg{
+      ImageFind(query:"[{}]"){
+        url owner{
+          nick
+        }
+      }
+    }`);
+  };
+  export const ava = async (idUser, id) => {
+    let query = `mutation setAvatar($idUser:String , $idAvatar:ID){ 
+      UserUpsert(user:{_id: $idUser, avatar: {_id: $idAvatar}}){
+          _id, avatar{
+              url
+          }
+      }
+  }`;
+    let qVariables = { idUser: idUser, idAvatar: id };
+  
+    let res = await gql(query, qVariables);
+    return res;
+  };
+  export const snippetAdd = async (title, description, files , idSnippet) => {
+    let query = `mutation newSnippet($snippet:SnippetInput) {
+      SnippetUpsert(snippet:$snippet){
+        _id
+      }
+    }`;
+  
+    let qVariables = { snippet: { title, description, files, _id: idSnippet }  };
+  
+    let res = await gql(query, qVariables);
+    return res;
+  };
+
+  export const search = async (string) => {
+    return gql(
+      `query snippetFind($query:String){
+        SnippetFind(query:$query){
+          owner {
+            _id login
+          }
+              title description _id files {
+               type text name
+             }
+          }
+    }`,
+      { query: JSON.stringify([
+        {
+            $or: [{title: `/${string.trim().split(" ").join('|')}/`},{description: `/${string.trim().split(" ").join('|')}/`}] 
+        },
+        {
+          sort: [{title: 1}]}]) }
+    );
+  };
+
+  

+ 16 - 9
projectreact/src/components/ava.js

@@ -1,14 +1,21 @@
 import React from "react";
 import { connect } from "react-redux";
-import icon from '../icon.png'
+import icon from "../icon.png";
 
+function AvaLogo({ px, mrgn, link }) {
+  // Import result is the URL of your image
+  return (
+    <img
+      src={link ? "http://localhost:3000/" + link : icon}
+      className="ava"
+      style={{ width: px, marginRight: mrgn, borderRadius: "50%" }}
+    />
+  );
+}
 
-function AvaLogo({px , mrgn , link }) {
-    // Import result is the URL of your image
-    return <img src= {link ? ('http://localhost:3000/' + link) : icon} className = 'ava'  style = {{width: px , marginRight:mrgn , borderRadius:"50%"}} />;
-  }
+const ConnectedAvaLogo = connect((state) => ({
+  link: state?.promise?.findUser?.payload?.data?.UserFindOne?.avatar?.url,
+}))(AvaLogo);
+//'http://localhost:3000/images/5d6600e2254cff050d32c6967bcf3104'
 
-  const ConnectedAvaLogo = connect(state => ({link:state?.promise?.findUser?.payload?.data?.UserFindOne?.avatar?.url}))(AvaLogo)
-  //'http://localhost:3000/images/5d6600e2254cff050d32c6967bcf3104'
-
-  export default ConnectedAvaLogo
+export default ConnectedAvaLogo;

+ 9 - 12
projectreact/src/components/editor.js

@@ -1,4 +1,3 @@
-import { useState } from "react";
 import SelectLang from "./select";
 import AceEditor from "react-ace";
 import "ace-builds/src-noconflict/mode-html";
@@ -19,7 +18,6 @@ import "ace-builds/src-noconflict/mode-elixir";
 import "ace-builds/src-noconflict/mode-typescript";
 import "ace-builds/src-noconflict/theme-monokai";
 import "ace-builds/src-noconflict/ext-language_tools";
-import { edit } from "ace-builds";
 
 const Editor = ({
   data = { type: "html", text: "", name: "" },
@@ -55,9 +53,8 @@ const Editor = ({
           aria-describedby="basic-addon1"
           value={data.name}
           onChange={(e) =>
-          onChange({ type: data.type, text: data.text, name: e.target.value })
-                    }
-            
+            onChange({ type: data.type, text: data.text, name: e.target.value })
+          }
         />
       </div>
       <button
@@ -72,6 +69,8 @@ const Editor = ({
       </button>
       <AceEditor
         className="editor"
+        width="480px"
+        height="300px"
         value={data.text}
         onChange={(text) =>
           onChange({ type: data.type, text, name: data.name })
@@ -84,13 +83,11 @@ const Editor = ({
         showPrintMargin={true}
         showGutter={true}
         highlightActiveLine={true}
-        setOptions={{
-          enableBasicAutocompletion: true,
-          enableLiveAutocompletion: true,
-          enableSnippets: false,
-          showLineNumbers: true,
-          tabSize: 2,
-        }}
+        wrapEnabled={true}
+        enableBasicAutocompletion={true}
+        enableLiveAutocompletion={true}
+        enableSnippets={true}
+        showLineNumbers={true}
       />
     </div>
   );

+ 17 - 17
projectreact/src/components/header.js

@@ -1,19 +1,19 @@
-import React from "react"
-import ConnectedNick from "./nickHeader"
-import { connect } from "react-redux"
-import Avatar from "react-avatar-edit"
-import ImgLogo from "./logo"
+import React from "react";
+import ConnectedNick from "./nickHeader";
+import ImgLogo from "./logo";
+import { connect } from "react-redux";
+import { useState } from "react";
+import { actionSearch } from "../actions/actionSearch";
 
+const Header = ({onSearch}) => {
+  const [request, setRequest] = useState('');
+  return (
+    <nav className="navbar navbar-expand-lg shadow-lg navbar-light bg-white mb-5">
+      <ImgLogo px={"70px"} />
+      <ConnectedNick />
+     
+    </nav>
+  );
+};
 
-const Header = () => {
-    return (
-<nav className="navbar navbar-expand-lg shadow-lg navbar-light bg-white mb-5">
-    
-    <ImgLogo px = {'70px'} />
-     <ConnectedNick/>
-     {/* <Avatar/> */}
-</nav>
-    )
-}
-
-export default Header
+export default Header;

+ 11 - 6
projectreact/src/components/logo.js

@@ -1,8 +1,13 @@
 import React from "react";
-import logo from '../logo.png'
+import logo from "../logo.png";
 
-function ImgLogo({px}) {
-    return <a href="/"> <img src={logo} alt="Logo" style = {{width: px}} /> </a>
-  }
-  
-  export default ImgLogo;
+function ImgLogo({ px }) {
+  return (
+    <a href="/">
+      {" "}
+      <img src={logo} alt="Logo" style={{ width: px }} />{" "}
+    </a>
+  );
+}
+
+export default ImgLogo;

+ 13 - 12
projectreact/src/components/nick.js

@@ -1,15 +1,16 @@
-import { connect } from "react-redux"
+import { connect } from "react-redux";
 
-const Nick =  ({nick}) => {
-    return (
-      <>
+const Nick = ({ nick }) => {
+  return (
+    <>
       <div>
-      <p>{nick}</p>
+        <p>{nick}</p>
       </div>
-      
-      </>
-      )
-    }
-    
-    const ConnectNickName = connect(state => ({nick:state?.auth?.payload?.sub?.login || 0 }))(Nick)
-    export default ConnectNickName
+    </>
+  );
+};
+
+const ConnectNickName = connect((state) => ({
+  nick: state?.auth?.payload?.sub?.login || 0,
+}))(Nick);
+export default ConnectNickName;

+ 34 - 18
projectreact/src/components/nickHeader.js

@@ -1,20 +1,36 @@
-import { connect } from "react-redux"
-import ConnectedAvaLogo from "./ava"
-import { actionAuthLogout } from "../actions"
+import { connect } from "react-redux";
+import ConnectedAvaLogo from "./ava";
+import { actionAuthLogout } from "../actions/actionAuthLogout";
+import { Redirect } from "react-router";
+import { Link } from "react-router-dom";
 
-const NickName =  ({nick , onLogOut}) => {
-    return (
-      <>
-      <div style ={{position:'relative', left:'75%'}}>
-      <span style ={{color:'black'}}>Your nickname </span>
-      <a href = '/cabinet' style = {{textDecoration:'none' , color:"#5F9EA0"}}>{nick} &nbsp;&nbsp;
-      <ConnectedAvaLogo px = {'50px'} mrgn = {'10px'} />
-      </a>
-      <button className = 'btn btn-secondary btn-sm' onClick = {() => (onLogOut())}>Log out</button>
+const NickName = ({ nick, onLogOut }) => {
+  return (
+    <>
+      <div style={{ position: "relative", left: "67%" }}>
+      <Link to = "/search"> <button
+          className="btn btn-outline-success  border-success mr-3"
+        >
+          Search
+        </button> </Link>
+        <span style={{ color: "black"}}>Your nickname </span>
+        <a href="/cabinet" style={{ textDecoration: "none", color: "#5F9EA0" }}>
+          {nick} &nbsp;&nbsp;
+          <ConnectedAvaLogo px={"50px"} mrgn={"10px"} />
+        </a>
+        <button
+          className="btn btn-secondary btn-sm"
+          onClick={() => onLogOut() }
+        >
+          Log out
+        </button>
       </div>
-      </>
-      )
-    }
-    
-    const ConnectedNick = connect(state => ({nick:state?.auth?.payload?.sub?.login}),{onLogOut:actionAuthLogout})(NickName)
-    export default ConnectedNick
+    </>
+  );
+};
+
+const ConnectedNick = connect(
+  (state) => ({ nick: state?.auth?.payload?.sub?.login , logedIn: state.auth.token}),
+  { onLogOut: actionAuthLogout }
+)(NickName);
+export default ConnectedNick;

+ 25 - 0
projectreact/src/components/privateRoute.js

@@ -0,0 +1,25 @@
+import React from "react"
+import { connect } from "react-redux"
+import { Redirect,Route } from "react-router"
+
+const PrivateRoute = ({component,roles,auth, ...originProps}) => {
+    const PageWrapper = (pageProps) => {
+      const OriginalPage = component
+      if(roles.includes('unknown')){
+        return <OriginalPage {...pageProps} />
+      }
+      if(auth === undefined) {
+        return <Redirect to='/login' />
+      }
+      let userL = roles.filter(item => auth.includes(item))
+      if(userL){
+        return <OriginalPage {...pageProps} />
+      }
+      return <Redirect to='/login' />
+    }
+    return (
+      <Route component={PageWrapper} {...originProps} />
+    )
+  }
+const ConnectedPrivateRoute = connect(state => ({auth: state?.auth?.token}))(PrivateRoute)
+export default ConnectedPrivateRoute

+ 11 - 6
projectreact/src/components/profile.js

@@ -1,8 +1,13 @@
 import React from "react";
-import wall from '../profileWall.jpeg'
+import wall from "../profileWall.jpeg";
 
-function ImgProfile({px }) {
-    return <a href="/"> <img src={wall} alt="wall" style = {{width: px}} /> </a>
-  }
-  
-  export default ImgProfile;
+function ImgProfile({ px }) {
+  return (
+    <a href="/">
+      {" "}
+      <img src={wall} alt="wall" style={{ width: px }} />{" "}
+    </a>
+  );
+}
+
+export default ImgProfile;

+ 38 - 40
projectreact/src/components/routes.js

@@ -1,44 +1,42 @@
-import React from 'react';
+import React from "react";
 import createHistory from "history/createBrowserHistory";
-import {Provider, connect}   from 'react-redux';
-import store from '../reducers';
-import RegForm from '../pages/reg';
-import { LogForm } from '../pages/login';
-import Home from '../pages/homePage';
-import ConnectCabinet from '../pages/cabinet';
-import CProjects from '../pages/projects';
-import ConUpload from '../pages/upload';
-import ConnectedProject from '../pages/project';
-import {
-  BrowserRouter as Router,
-  Switch,
-  Route, 
-  Link
-} from "react-router-dom";
+import { connect } from "react-redux";
+import RegForm from "../pages/reg";
+import { LogForm } from "../pages/login";
+import Home from "../pages/homePage";
+import ConnectCabinet from "../pages/cabinet";
+import CProjects from "../pages/projects";
+import ConUpload from "../pages/upload";
+import ConnectedProject from "../pages/project";
+import Search from "../pages/search";
+import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
+import { Redirect } from "react-router";
+import ConnectedPrivateRoute from "./privateRoute";
 
-const Routes = ({isAuth}) => {
-    return (
-        <div className="App">
-          <div className = 'contentDiv'>
+const Routes = ({ isAuth }) => {
+  return (
+    <div className="App">
+      <div className="contentDiv">
+        {/* <CTester/> */}
+        <Router history={createHistory()}>
+          
+            <Switch>
+              <ConnectedPrivateRoute exact path="/" roles = {['user']} component={Home} />
+              <ConnectedPrivateRoute path="/cabinet" roles = {['user']} component={ConnectCabinet} />
+              <ConnectedPrivateRoute path="/projects" roles = {['user']} component={CProjects} />
+              <ConnectedPrivateRoute path="/project/:id" roles = {['user']} component={ConnectedProject} />
+              <ConnectedPrivateRoute path="/upload" roles = {['user']} component={ConUpload} />
+              <ConnectedPrivateRoute path="/search" roles = {['user']} component={Search} />
+              <ConnectedPrivateRoute path="/login" roles = {['unknown']} component={LogForm} /> 
+              <ConnectedPrivateRoute path="/registration" roles = {['unknown']} component={RegForm} />
+              </Switch>
          
-            {/* <CTester/> */}
-          <Router history = {createHistory()}>
-              {isAuth && <Switch>
-            <Route exact path='/' component={Home} />
-          <Route path='/cabinet' component={ConnectCabinet}/>
-          <Route path='/projects' component={CProjects}/>
-          <Route path='/project/:id' component={ConnectedProject}/>
-          <Route path='/upload' component={ConUpload}/>
-          </Switch>}
-          {!isAuth && <Switch>
-          <Route path='/login' component={LogForm}/>
-          <Route path='/registration' component={RegForm}/>
-              </Switch>}
-          </Router>
-          </div>
-        </div>
-      );
-}
+        </Router>
+      </div>
+    </div>
+  );
+};
+
+export default Routes
+
 
-const ConnectedRoutes = connect(state => ({isAuth: state.auth.token}))(Routes)
-export default ConnectedRoutes

+ 36 - 12
projectreact/src/components/select.js

@@ -1,15 +1,39 @@
-import { useState } from "react";
-let languages = {html:'HTML' , css:'CSS' , javascript:'JavaScript' , java:'Java' , python:'Python' , xml:'XML' , ruby:'Ruby' , sass:'Sass' , markdown:'Markdown' , mysql:'MySql' , json:'JSON' , handlebars:'Handlebars' , golang:'Golang' , csharp:'C Sharp' ,elixir:'Elixir' , typescript:'TypeScript'}
+let languages = {
+  html: "HTML",
+  css: "CSS",
+  javascript: "JavaScript",
+  java: "Java",
+  python: "Python",
+  xml: "XML",
+  ruby: "Ruby",
+  sass: "Sass",
+  markdown: "Markdown",
+  mysql: "MySql",
+  json: "JSON",
+  handlebars: "Handlebars",
+  golang: "Golang",
+  csharp: "C Sharp",
+  elixir: "Elixir",
+  typescript: "TypeScript",
+};
 
-const SelectLang = ({list = languages , onChange , value}) => {
-   
-    return (
-     <>
-      <select style = {{marginBottom:'10px' , marginLeft:'15px'}} value = {value} onChange ={(e) => onChange(e.target.value)}  className = 'select'>
-      {Object.entries(list).map(([value , text]) => <option value={value} key={value}>{text}</option>)}
+const SelectLang = ({ list = languages, onChange, value }) => {
+  return (
+    <>
+      <select
+        style={{ marginBottom: "10px", marginLeft: "15px" }}
+        value={value}
+        onChange={(e) => onChange(e.target.value)}
+        className="select"
+      >
+        {Object.entries(list).map(([value, text]) => (
+          <option value={value} key={value}>
+            {text}
+          </option>
+        ))}
       </select>
-      </>
-    )
-  }
+    </>
+  );
+};
 
-  export default SelectLang
+export default SelectLang;

文件差異過大導致無法顯示
+ 58 - 12
projectreact/src/components/snippet.js


+ 3 - 6
projectreact/src/components/tester.js

@@ -1,11 +1,8 @@
 import React from "react";
 import { connect } from "react-redux";
 
-const Tester = (props) => 
-<pre>
-    {JSON.stringify(props , null , 4)}
-</pre>
+const Tester = (props) => <pre>{JSON.stringify(props, null, 4)}</pre>;
 
-const CTester = connect(state => (state))(Tester)
+const CTester = connect((state) => state?.promise?.searchSnippet?.payload?.data?.SnippetFind)(Tester);
 
-export default CTester
+export default CTester;

+ 41 - 22
projectreact/src/pages/cabinet.js

@@ -4,33 +4,52 @@ import ConnectNickName from "../components/nick";
 
 import ImgProfile from "../components/profile";
 import ConUpload from "./upload";
-import { actionAuthLogout } from "../actions";
+import { actionAuthLogout } from "../actions/actionAuthLogout";
 
-const Cabinet = ({onLogOut}) => {
-    return (
+const Cabinet = ({ onLogOut }) => {
+  return (
     <>
-    <div className="container d-flex justify-content-center align-items-center mt-5 mb-5">
-    <div className="card">
-        <div className="upper"> <ImgProfile px ={'300px'} /> </div>
-        <div className="user text-center">
-            <div className="profile mt-3" > <ConUpload width = {'100px'}/> </div>
-        </div>
-        <div className="mt-5 text-center">
-            <h4 className="mb-0"><ConnectNickName/></h4> 
-            <a href="/projects"><button type="button" className="btn btn-outline-success">My Projects</button></a>
+      <div className="container d-flex justify-content-center align-items-center mt-5 mb-5">
+        <div className="card">
+          <div className="upper">
+            {" "}
+            <ImgProfile px={"300px"} />{" "}
+          </div>
+          <div className="user text-center">
+            <div className="profile mt-3">
+              {" "}
+              <ConUpload width={"100px"} />{" "}
+            </div>
+          </div>
+          <div className="mt-5 text-center">
+            <h4 className="mb-0">
+              <ConnectNickName />
+            </h4>
+            <a href="/projects">
+              <button type="button" className="btn btn-outline-success">
+                My Projects
+              </button>
+            </a>
             <div className="d-flex justify-content-center align-items-center mt-4 px-4">
-            <a href="/">
-                <button className="btn btn-primary btn-sm mb-3 "  >Main Page</button>
-                </a> 
+              <a href="/">
+                <button className="btn btn-primary btn-sm mb-3 ">
+                  Main Page
+                </button>
+              </a>
             </div>
-                <button className = 'btn btn-secondary btn-sm mb-3' onClick = {() => (onLogOut())}>Log out</button>
+            <button
+              className="btn btn-secondary btn-sm mb-3"
+              onClick={() => onLogOut() }
+            >
+              Log out
+            </button>
+          </div>
         </div>
-    </div>
-</div>
+      </div>
     </>
-    )
-}
+  );
+};
 
-const ConnectCabinet = connect(null ,{onLogOut:actionAuthLogout})(Cabinet)
+const ConnectCabinet = connect(null, { onLogOut: actionAuthLogout })(Cabinet);
 
-export default ConnectCabinet
+export default ConnectCabinet;

+ 9 - 10
projectreact/src/pages/homePage.js

@@ -2,14 +2,13 @@ import React from "react";
 import Header from "../components/header";
 import ConnectedSnippetHome from "../components/snippet";
 
-const Home = () =>{
-return (
-  <>
-  <Header/>
-  <ConnectedSnippetHome/>
-  </>
-    )
-}
+const Home = () => {
+  return (
+    <>
+      <Header />
+      <ConnectedSnippetHome />
+    </>
+  );
+};
 
-
-export default Home
+export default Home;

+ 13 - 8
projectreact/src/pages/login.js

@@ -1,13 +1,14 @@
 import { connect } from "react-redux";
 import { useState } from "react";
-import { actionFullLogin } from "../actions";
-import { Redirect } from "react-router-dom";
+import { actionFullLogin } from "../actions/actionFullLogin";
+import { Redirect } from "react-router";
 
-const Log = ({ onLog , LogedIn}) => {
+const Log = ({ onLog, LogedIn }) => {
   const [login, setLogin] = useState("");
   const [password, setPassword] = useState("");
-  return LogedIn ? <Redirect to="/" />
-   : (
+  return LogedIn ? (
+    <Redirect to ="/"/>
+  ) : (
     <>
       <div className="container">
         <div
@@ -41,7 +42,7 @@ const Log = ({ onLog , LogedIn}) => {
                     className="form-control"
                     name="username"
                     value={login}
-                    onChange={(e) => setLogin(e.target.value)}
+                    onChange={(e) => setLogin(e.target.value) && <Redirect to ="/"/>}
                     placeholder="Login"
                   />
                 </div>
@@ -69,7 +70,9 @@ const Log = ({ onLog , LogedIn}) => {
                       id="btn-login"
                       href="#"
                       className="btn btn-success"
-                      onClick={() => (onLog(login, password))}
+                      onClick={() =>
+                        onLog(login, password)
+                      }
                     >
                       Login{" "}
                     </a>
@@ -97,4 +100,6 @@ const Log = ({ onLog , LogedIn}) => {
   );
 };
 
-export const LogForm = connect(state => ({LogedIn:state?.auth?.token}), { onLog: actionFullLogin })(Log);
+export const LogForm = connect((state) => ({ LogedIn: state?.auth?.token }), {
+  onLog: actionFullLogin,
+})(Log);

+ 59 - 16
projectreact/src/pages/project.js

@@ -1,10 +1,11 @@
 import { useEffect } from "react";
 import { connect } from "react-redux";
-import { actionSnippetById } from "../actions";
+import { actionSnippetById } from "../actions/actionSnippetById";
 import { useState } from "react";
 import Editor from "../components/editor";
-import { actionSnippetAdd } from "../actions";
+import { actionSnippetAdd } from "../actions/actionSnippetAdd";
 import { Link } from "react-router-dom";
+import { Redirect } from "react-router";
 
 const ProjectSnippet = ({
   onSave,
@@ -21,20 +22,45 @@ const ProjectSnippet = ({
     getSnippet(id);
   }, []);
   const [files, setFiles] = useState([]);
-  const [name, setName] = useState(nameText);
-  const [title, setTitle] = useState('');
-  const [description, setDescription] = useState('');
+  const [name, setName] = useState("");
+  const [title, setTitle] = useState("");
+  const [description, setDescription] = useState("");
   useEffect(() => {
-      setFiles(filesArr) 
-      setTitle(titleText)
-      setDescription(descriptionText)
-  },[filesArr , titleText , descriptionText])
+    setFiles(filesArr);
+    setTitle(titleText);
+    setDescription(descriptionText);
+  }, [filesArr, titleText, descriptionText]);
+  const [srcDoc, setSrcDoc] = useState("");
+  const html = files?.filter((el) => {
+    return el?.type === "html";
+  })[0]?.text;
+  const css = files?.filter((el) => {
+    return el?.type === "css";
+  })[0]?.text;
+  const js = files?.filter((el) => {
+    return el?.type === "javascript";
+  })[0]?.text;
+  console.log(js);
+  useEffect(() => {
+    const timeout = setTimeout(() => {
+      setSrcDoc(`
+        <html>
+          <body>${html || ""}</body>
+          <style>${css}</style>
+          <script>${js}</script>
+        </html>
+      `);
+    }, 250);
+
+    return () => clearTimeout(timeout);
+  }, [html, css, js]);
   return (
     <div>
+      <br />
       {files?.map((data, index) => (
         <>
           <Editor
-            onDelete={() => setFiles(files.filter((item) => item != data))}
+            onDelete={() => setFiles(files?.filter((item) => item !== data))}
             data={data}
             onChange={({ type, name, text }) =>
               setFiles([
@@ -62,10 +88,25 @@ const ProjectSnippet = ({
           >
             Add editor
           </button>
+          <iframe
+            srcDoc={srcDoc}
+            title="output"
+            sandbox="allow-scripts"
+            frameBorder="0"
+            width="95%"
+            height="95%"
+            style={{
+              marginTop: "10px",
+              border: "1px solid #F0FFFF",
+              boxShadow: "0px 5px 10px 2px rgba(34, 60, 80, 0.2)",
+            }}
+          />
           <div>
-          <Link to ="/projects">
-              <button className = 'btn btn-outline-info border-info'>All projects</button>
-          </Link>
+            <Link to="/projects">
+              <button className="btn btn-outline-info border-info mt-3">
+                All projects
+              </button>
+            </Link>
           </div>
         </div>
         <div className="input-group mb-3 mt-5 ml-auto mr-auto w-25">
@@ -98,7 +139,9 @@ const ProjectSnippet = ({
         </div>
         <button
           className="btn btn-success float-right mr-5 mb-5"
-          onClick={() => onSave(title, description, files)}
+          onClick={() =>
+            onSave(title, description, files, id) 
+          }
         >
           Save project
         </button>
@@ -109,7 +152,7 @@ const ProjectSnippet = ({
 
 const ConnectedProject = connect(
   (state) => ({
-    title:
+    titleText:
       state?.promise?.findSnippetById?.payload?.data?.SnippetFind?.[0]?.title,
     descriptionText:
       state?.promise?.findSnippetById?.payload?.data?.SnippetFind?.[0]
@@ -119,6 +162,6 @@ const ConnectedProject = connect(
     filesArr:
       state?.promise?.findSnippetById?.payload?.data?.SnippetFind?.[0]?.files,
   }),
-  { getSnippet: actionSnippetById ,onSave: actionSnippetAdd  }
+  { getSnippet: actionSnippetById, onSave: actionSnippetAdd }
 )(ProjectSnippet);
 export default ConnectedProject;

+ 41 - 22
projectreact/src/pages/projects.js

@@ -2,23 +2,33 @@ import { connect } from "react-redux";
 import { Link } from "react-router-dom";
 
 const Projects = ({ snippets }) => {
-  return  snippets  ? (
+  return snippets ? (
     <div>
-        <Link to ="/"><button className = 'float-left btn-secondary d-inline-block mt-2 ml-2'>Back to Main Page</button></Link> <br/> <br/>
+      <Link to="/">
+        <button className="float-left btn-secondary d-inline-block mt-2 ml-2">
+          Back to Main Page
+        </button>
+      </Link>
+      <br /> <br />
+      <div style={{ alignItems: "center", textAlign: "center" }}>
+        <Link to="/">
+          <button className="btn btn-success">New project</button>
+        </Link>
+      </div>
       {snippets?.map((key, index) => (
-        <div style ={{textAlign:'center' , alignItems:'center'}}>
-          <div className="card w-50 ml-auto mr-auto mt-3 mb-5"  >
-            <div className="card-body" style ={{textAlign:'center'}}>
-                <h3 className="card-title mb-4 text-info">{snippets?.[index]?.title || "Project without name"}</h3>   
+        <div style={{ textAlign: "center", alignItems: "center" }}>
+          <div className="card w-50 ml-auto mr-auto mt-3 mb-5">
+            <div className="card-body" style={{ textAlign: "center" }}>
+              <h3 className="card-title mb-4 text-info">
+                {snippets?.[index]?.title || "Project without name"}
+              </h3>
               <p className="card-text">
-                  <span className = 'text-muted'>Description</span>&nbsp; 
-              {snippets?.[index]?.description || ""} 
+                <span className="text-muted">Description</span>&nbsp;
+                {snippets?.[index]?.description || ""}
               </p>
-              <Link to = {'/project/' + snippets?.[index]?._id}>
-              <button className="btn btn-primary mt-3"  >
-                Open project
-                </button>  
-                </Link>
+              <Link to={"/project/" + snippets?.[index]?._id}>
+                <button className="btn btn-primary mt-3">Open project</button>
+              </Link>
             </div>
           </div>
         </div>
@@ -26,17 +36,26 @@ const Projects = ({ snippets }) => {
     </div>
   ) : (
     <div>
-    <Link to ="/"><button className = 'float-left btn-secondary d-inline-block mt-2 ml-2'>Back to Main Page</button></Link> <br/> <br/>
-    <div className="d-flex justify-content-center">
-    <div className="spinner-border mt-3" style={{width: "10rem" ,  height: "10rem"}} role="status">
-      <span className="sr-only">Loading...</span>
+      <Link to="/">
+        <button className="float-left btn-secondary d-inline-block mt-2 ml-2">
+          Back to Main Page
+        </button>
+      </Link>{" "}
+      <br /> <br />
+      <div className="d-flex justify-content-center">
+        <div
+          className="spinner-border mt-3"
+          style={{ width: "10rem", height: "10rem" }}
+          role="status"
+        >
+          <span className="sr-only">Loading...</span>
+        </div>
+      </div>
     </div>
-  </div>
-  </div>
   );
 };
 
-const CProjects = connect(state => ({
-  snippets: state?.promise?.findSnippet?.payload?.data?.SnippetFind
+const CProjects = connect((state) => ({
+  snippets: state?.promise?.findSnippet?.payload?.data?.SnippetFind,
 }))(Projects);
-export default CProjects;
+export default CProjects;

+ 95 - 56
projectreact/src/pages/reg.js

@@ -1,70 +1,109 @@
 import { connect } from "react-redux";
-import { useState} from "react";
-import { actionFullRegister } from "../actions";
-import { Redirect } from "react-router-dom";
+import { useState } from "react";
+import { actionFullRegister } from "../actions/actionFullRegister";
+import { Redirect } from "react-router";
 
-const Reg = ({ onReg,LogedIn }) => {
+const Reg = ({ onReg, LogedIn }) => {
   const [login, setLogin] = useState("");
   const [password, setPassword] = useState("");
-      //надо тип инпуту
+  //надо тип инпуту
   //надо проверку на пустоту инпутов и запрет кнопки (disabled)
   //надо при кнопке отправить в onLogin login и пароль. onLogin - это функция-колбэк
-  return LogedIn? <Redirect to = "/"/> :
-  (
+  return LogedIn ? (
+    <Redirect to = "/"/>
+  ) : (
     <>
-      <div className="container">    
-      <div id="loginbox" style={{"margin-top":"50px"}} className="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">                    
-          <div className="panel panel-info" >
-                  <div className="panel-heading">
-                      <div className="panel-title">Registration</div>
-                  </div>     
+      <div className="container">
+        <div
+          id="loginbox"
+          style={{ "margin-top": "50px" }}
+          className="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2"
+        >
+          <div className="panel panel-info">
+            <div className="panel-heading">
+              <div className="panel-title">Registration</div>
+            </div>
 
-                  <div style={{"padding-top":"30px"}} className="panel-body" >
+            <div style={{ "padding-top": "30px" }} className="panel-body">
+              <div
+                style={{ display: "none" }}
+                id="login-alert"
+                className="alert alert-danger col-sm-12"
+              ></div>
 
-                      <div style={{"display":"none"}} id="login-alert" className="alert alert-danger col-sm-12"></div>
-                          
-                      <form id="loginform" className="form-horizontal" role="form">
-                                  
-                          <div style={{"margin-bottom": "25px"}} className="input-group">
-                                      <span className="input-group-addon"><i className="glyphicon glyphicon-user"></i></span>
-                                      <input id="login-username" type="text" className="form-control" name="username" value={login} onChange={(e) => setLogin(e.target.value)} placeholder="Login"/>                                        
-                                  </div>
-                              
-                          <div style={{"margin-bottom": "25px"}} className="input-group">
-                                      <span className="input-group-addon"><i className="glyphicon glyphicon-lock"></i></span>
-                                      <input id="login-password" type="password" className="form-control" name="password" placeholder="Password" value = {password} onChange={(e) => setPassword(e.target.value)}/>
-                                  </div>
-                              <div style={{'margin-top':"10px"}} className="form-group">
-                                  <div className="col-sm-12 controls">
-                                    <a id="btn-login" href="#" className="btn btn-success" onClick={() => (onReg(login, password))}>Sign up  </a>
+              <form id="loginform" className="form-horizontal" role="form">
+                <div
+                  style={{ "margin-bottom": "25px" }}
+                  className="input-group"
+                >
+                  <span className="input-group-addon">
+                    <i className="glyphicon glyphicon-user"></i>
+                  </span>
+                  <input
+                    id="login-username"
+                    type="text"
+                    className="form-control"
+                    name="username"
+                    value={login}
+                    onChange={(e) => setLogin(e.target.value)}
+                    placeholder="Login"
+                  />
+                </div>
 
-                                  </div>
-                              </div>
+                <div
+                  style={{ "margin-bottom": "25px" }}
+                  className="input-group"
+                >
+                  <span className="input-group-addon">
+                    <i className="glyphicon glyphicon-lock"></i>
+                  </span>
+                  <input
+                    id="login-password"
+                    type="password"
+                    className="form-control"
+                    name="password"
+                    placeholder="Password"
+                    value={password}
+                    onChange={(e) => setPassword(e.target.value)}
+                  />
+                </div>
+                <div style={{ "margin-top": "10px" }} className="form-group">
+                  <div className="col-sm-12 controls">
+                    <a
+                      id="btn-login"
+                      href="#"
+                      className="btn btn-success"
+                      onClick={() => onReg(login, password)}
+                    >
+                      Sign up{" "}
+                    </a>
+                  </div>
+                </div>
 
-
-                              <div className="form-group">
-                                  <div className="col-md-12 control">
-                                      <div style={{"border-top": "1px solid#888", "padding-top":"15px", "font-size":"85%"}}>
-                                      <a href="/login">
-                                          Login Here
-                                      </a>
-                                      </div>
-                                  </div>
-                              </div>    
-                          </form>     
-
-
-
-                      </div>                     
-                  </div>  
+                <div className="form-group">
+                  <div className="col-md-12 control">
+                    <div
+                      style={{
+                        "border-top": "1px solid#888",
+                        "padding-top": "15px",
+                        "font-size": "85%",
+                      }}
+                    >
+                      <a href="/login">Login Here</a>
+                    </div>
+                  </div>
+                </div>
+              </form>
+            </div>
+          </div>
+        </div>
       </div>
-  </div>
-      
     </>
-    );
-  };
-  
-  const RegForm = connect(state => ({LogedIn:state?.auth?.token}), {onReg: actionFullRegister})(Reg)
+  );
+};
+
+const RegForm = connect((state) => ({ LogedIn: state?.auth?.token }), {
+  onReg: actionFullRegister,
+})(Reg);
 
-  
-export default RegForm
+export default RegForm;

+ 59 - 0
projectreact/src/pages/search.js

@@ -0,0 +1,59 @@
+import { Link } from "react-router-dom";
+import { actionSearch } from "../actions/actionSearch";
+import { connect } from "react-redux";
+import { useState } from "react";
+
+const Search = ({onSearch , snippets}) => {
+    const [request, setRequest] = useState('');
+  return (
+    <>
+    <Link to="/">
+        <button className="float-left btn-secondary d-inline-block mt-2 ml-2">
+          Back to Main Page
+        </button>
+      </Link>
+      <br/>
+      <br/>
+      <div style ={{textAlign: "center" , alignItems:"center", justifyContent:'center'}}>
+    <input
+    value={request}
+    onChange={(e) => setRequest(e.target.value)}
+      className="form-control d-inline-block w-50 mt-2"
+      type="search"
+      placeholder="Name of project"
+      aria-label="Search"
+    />
+    <br/>
+    <button
+      className="btn btn-outline-success border-success mt-4 mb-4" onClick = {() => onSearch(request)}
+    >
+      Search
+    </button>
+    </div>
+
+  {snippets?.map((key, index) => (
+    <div style={{ textAlign: "center", alignItems: "center" }}>
+      <div className="card w-50 ml-auto mr-auto mt-3 mb-5">
+        <div className="card-body" style={{ textAlign: "center" }}>
+          <h3 className="card-title mb-4 text-info">
+            {snippets?.[index]?.title || "Project without name"}
+          </h3>
+          <p className="card-text">
+            <span className="text-muted">Description</span>&nbsp;
+            {snippets?.[index]?.description || ""}
+          </p>
+          <p>{`Owner: ${snippets?.[index]?.owner?.login}`}</p>
+          <Link to={"/project/" + snippets?.[index]?._id}>
+            <button className="btn btn-primary mt-3">Open project</button>
+          </Link>
+        </div>
+      </div>
+    </div>
+  ))}
+</>
+  )
+};
+
+const CSearch = connect(state => ({snippets:state?.promise?.searchSnippet?.payload?.data?.SnippetFind}) , {onSearch:actionSearch})(Search)
+
+export default CSearch;

+ 1 - 1
projectreact/src/pages/upload.js

@@ -1,6 +1,6 @@
 import React from 'react';
 import {useDropzone} from 'react-dropzone';
-import { actionFullAvatar } from '../actions';
+import { actionFullAvatar } from '../actions/actionFullAvatar';
 import { connect } from 'react-redux';
 import ConnectedAvaLogo from '../components/ava';
 

+ 26 - 0
projectreact/src/reducers/authReducer.js

@@ -0,0 +1,26 @@
+function authReducer(state, action) {
+  //....
+  if (state === undefined) {
+    if (!localStorage.authToken) {
+      return {};
+    }
+    action.token = localStorage.authToken;
+    action.type = "LOGIN";
+    // добавить в action token из localStorage, и проимитировать LOGIN
+  }
+  if (action.type === "LOGIN") {
+    localStorage.authToken = action.token;
+    function jwt_decode(token) {
+      var start64Url = token.split(".")[1];
+      return JSON.parse(atob(start64Url));
+    }
+    return { token: action.token, payload: jwt_decode(action.token) };
+  }
+  if (action.type === "LOGOUT") {
+    localStorage.removeItem("authToken");
+    //вернуть пустой объект
+    return {};
+  }
+  return state;
+}
+export default authReducer;

+ 0 - 55
projectreact/src/reducers/index.js

@@ -1,55 +0,0 @@
-import thunk  from 'redux-thunk'
-import {createStore, combineReducers,applyMiddleware } from 'redux';
-import { actionFindUser , actionSnippetFindByOwner} from '../actions';
-
-
-function promiseReducer(state , {type, name ,status , payload, error}) {
-  if (!state){
-      return {} //{status , payload , error}
-  }
-  if (type === 'PROMISE') {
-      return {
-          ...state,
-          [name]: {status,payload , error}
-      }
-  }
-  return state
-}
-
-function authReducer(state, action){ //....
-    if (state === undefined){
-        if (!localStorage.authToken){
-            return {}
-        }
-        action.token = localStorage.authToken
-        action.type = 'LOGIN'
-        // добавить в action token из localStorage, и проимитировать LOGIN 
-    }
-    if (action.type === 'LOGIN'){
-        localStorage.authToken = action.token
-        function jwt_decode (token) {
-            var start64Url = token.split('.')[1]
-            return JSON.parse(atob(start64Url))
-        }
-        return {token: action.token, payload: jwt_decode(action.token)}
-    }
-    if (action.type === 'LOGOUT'){
-        localStorage.removeItem("authToken")
-        //вернуть пустой объект
-        return {}
-    }
-    return state
-}
-export const reducers = {
-    promise:promiseReducer,
-    auth:authReducer
-}
-
-export const store = createStore(combineReducers(reducers), applyMiddleware(thunk))
-const unsubscribe = store.subscribe(() => console.log('result here',store.getState()))
-if (localStorage.authToken) {
-    store.dispatch(actionFindUser())
-    store.dispatch(actionSnippetFindByOwner(store.getState().auth.payload.sub.id))
-}
-
-export default store

+ 13 - 0
projectreact/src/reducers/promiseReducer.js

@@ -0,0 +1,13 @@
+function promiseReducer(state, { type, name, status, payload, error }) {
+  if (!state) {
+    return {}; //{status , payload , error}
+  }
+  if (type === "PROMISE") {
+    return {
+      ...state,
+      [name]: { status, payload, error },
+    };
+  }
+  return state;
+}
+export default promiseReducer;

+ 7 - 0
projectreact/src/reducers/reducers.js

@@ -0,0 +1,7 @@
+import promiseReducer from "./promiseReducer";
+import authReducer from "./authReducer";
+
+export const reducers = {
+  promise: promiseReducer,
+  auth: authReducer,
+};

+ 19 - 0
projectreact/src/reducers/store.js

@@ -0,0 +1,19 @@
+import { createStore, combineReducers, applyMiddleware } from "redux";
+import thunk from "redux-thunk";
+import { reducers } from "./reducers";
+import { actionFindUser } from "../actions/actionFindUser";
+import { actionSnippetFindByOwner } from "../actions/actionSnippetFindByOwner";
+
+export const store = createStore(
+  combineReducers(reducers),
+  applyMiddleware(thunk)
+);
+const unsubscribe = store.subscribe(() =>
+  console.log("result here", store.getState())
+);
+if (localStorage.authToken) {
+  store.dispatch(actionFindUser());
+  store.dispatch(
+    actionSnippetFindByOwner(store.getState().auth.payload.sub.id)
+  );
+}