App.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import logo from './logo.svg';
  2. import './App.css';
  3. import React, { useState, Component, useEffect, useRef } from "react";
  4. import {Provider, connect} from 'react-redux';
  5. import thunk from 'redux-thunk';
  6. import {createStore, combineReducers,applyMiddleware } from 'redux';
  7. import Form from './components/Form';
  8. const getGQL = url =>
  9. (query, variables) =>
  10. fetch(url, {
  11. method: 'POST',
  12. headers: {
  13. "content-type": "application/json",
  14. ...(localStorage.authToken ? {Authorization: "Bearer " + localStorage.authToken} : {})
  15. },
  16. body: JSON.stringify({query, variables})
  17. }).then(res => res.json())
  18. let gql = getGQL("http://snippet.asmer.fs.a-level.com.ua/graphql")
  19. function promiseReducer(state , {type, name ,status , payload, error}) {
  20. if (!state){
  21. return {} //{status , payload , error}
  22. }
  23. if (type === 'PROMISE') {
  24. return {
  25. ...state,
  26. [name]: [status,payload , error]
  27. }
  28. }
  29. return state
  30. }
  31. let reg = async(login,password) => {
  32. let query = `mutation reg($l:String! , $p:String!) {
  33. createUser(login:$l,password:$p){
  34. _id
  35. }
  36. }`
  37. let qVariables = {
  38. "l": login,
  39. "p": password
  40. }
  41. let result = await gql(query,qVariables)
  42. return result
  43. }
  44. let log = async(login , password) => {
  45. let query = ` query log($l:String!,$p:String!) {
  46. login(login:$l,password:$p)
  47. }`
  48. let qVariables = {
  49. "l": login,
  50. "p": password
  51. }
  52. let result = await gql(query,qVariables)
  53. console.log(result)
  54. localStorage.authToken = result.data.login
  55. }
  56. const actionPending = name => ({type: "PROMISE" ,status:"PENDING", name})
  57. const actionResolved = (name,payload) => ({type: "PROMISE" ,status:"RESOLVED", name,payload})
  58. const actionRejected = (name,error) => ({type: "PROMISE" ,status:"REJECTED", name,error})
  59. const actionPromise = (name, promise) =>
  60. async dispatch => {
  61. dispatch(actionPending(name))
  62. try {
  63. let payload = await promise
  64. dispatch(actionResolved(name , payload))
  65. return payload
  66. }
  67. catch(error){
  68. dispatch(actionRejected(name , error))
  69. }
  70. }
  71. function authReducer(state, action){ //....
  72. if (state === undefined){
  73. if (!localStorage.authToken){
  74. return {}
  75. }
  76. action.token = localStorage.authToken
  77. action.type = 'LOGIN'
  78. // добавить в action token из localStorage, и проимитировать LOGIN
  79. }
  80. if (action.type === 'LOGIN'){
  81. console.log('ЛОГИН')
  82. localStorage.authToken = action.token
  83. console.log(action.token)
  84. function jwt_decode (token) {
  85. var start64Url = token.split('.')[1]
  86. return JSON.parse(atob(start64Url))
  87. }
  88. return {token: action.token, payload: jwt_decode(action.token)}
  89. }
  90. if (action.type === 'LOGOUT'){
  91. console.log('ЛОГАУТ')
  92. localStorage.removeItem("authToken")
  93. //вернуть пустой объект
  94. return {}
  95. }
  96. return state
  97. }
  98. const actionAuthLogin = token => ({type:'LOGIN', token})
  99. const actionAuthLogout = () => ({type:'LOGOUT'})
  100. const actionFullLogin = (login , password) => async dispatch => {
  101. let result = await dispatch(actionPromise("login",log(login,password)))
  102. if (result.data.login !== null){
  103. dispatch(actionAuthLogin(result.data.login))
  104. }
  105. else {
  106. alert ('такого пользователя не существует')
  107. }
  108. }
  109. const actionRegister = (login,password) => async dispatch => {
  110. return await dispatch (actionPromise('register' , reg(login,password)))
  111. }
  112. const actionFullRegister = (login,password) => async dispatch => {
  113. let result = await dispatch (actionRegister(login,password))
  114. if (result.errors === undefined) {
  115. await dispatch (actionFullLogin(login,password))
  116. }
  117. else {
  118. alert("Такой пользователь уже есть")
  119. }
  120. }
  121. let reducers = {
  122. promise:promiseReducer,
  123. auth:authReducer
  124. }
  125. const store = createStore(combineReducers(reducers), applyMiddleware(thunk))
  126. const LoginForm = ({ onLogin }) => {
  127. const [login, setLogin] = useState("");
  128. const [password, setPassword] = useState("");
  129. //надо тип инпуту
  130. //надо проверку на пустоту инпутов и запрет кнопки (disabled)
  131. //надо при кнопке отправить в onLogin login и пароль. onLogin - это функция-колбэк
  132. return (
  133. <>
  134. <input value={login} onChange={(e) => setLogin(e.target.value)} />
  135. <input
  136. type="password"
  137. value={password}
  138. onChange={(e) => setPassword(e.target.value)}
  139. />
  140. <button
  141. onClick={() => onLogin(login, password)}
  142. disabled={!login || !password}
  143. >
  144. Sign in
  145. </button>
  146. </>
  147. );
  148. };
  149. const ConnectedLoginForm = connect(null, {onLogin: actionAuthLogin})(LoginForm)
  150. const unsubscribe = store.subscribe(() => console.log('result here',store.getState()))
  151. const NickName = ({nick}) => {
  152. return (
  153. <p></p>,
  154. <a href = '#'>{nick || 'anon'}</a>
  155. )
  156. }
  157. const ConnectedNick = connect(state => ({nick:state?.auth?.payload?.sub?.login }))(NickName)
  158. const LogOut = connect ((state) => ({children:'Logout' , disabled:!state.auth.token }) , ({onClick:actionAuthLogout}))('button')
  159. function App() {
  160. return (
  161. <div className="App">
  162. <Provider store = {store}>
  163. <ConnectedNick/> <br/>
  164. <ConnectedLoginForm/>
  165. <LogOut/>
  166. {/* <Form/> */}
  167. </Provider>
  168. </div>
  169. );
  170. }
  171. export default App;