|
@@ -0,0 +1,126 @@
|
|
|
+import logo from './logo.svg';
|
|
|
+import './App.css';
|
|
|
+import React, {useCallback} from 'react'
|
|
|
+import thunk from 'redux-thunk';
|
|
|
+import {createStore, combineReducers, applyMiddleware} from 'redux';
|
|
|
+import {Provider, connect} from 'react-redux';
|
|
|
+import {useDropzone} from 'react-dropzone'
|
|
|
+
|
|
|
+const actionPending = name => ({type: 'PROMISE', status: 'PENDING', name})
|
|
|
+const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload})
|
|
|
+const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name, error})
|
|
|
+
|
|
|
+const actionPromise = (name, promise) =>
|
|
|
+ async dispatch => {
|
|
|
+ dispatch(actionPending(name)) // 1. {delay1000: {status: 'PENDING'}}
|
|
|
+ try{
|
|
|
+ let payload = await promise
|
|
|
+ dispatch(actionResolved(name, payload))
|
|
|
+ return payload
|
|
|
+ }
|
|
|
+ catch(error){
|
|
|
+ dispatch(actionRejected(name, error))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+const getGQL = url =>
|
|
|
+ (query, variables = {}) =>
|
|
|
+ fetch(url, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ ...(localStorage.authToken ? { "Authorization": "Bearer " + localStorage.authToken } :
|
|
|
+ {})
|
|
|
+ },
|
|
|
+ body: JSON.stringify({ query, variables })
|
|
|
+ })
|
|
|
+ .then(res => res.json())
|
|
|
+ .then(data => {
|
|
|
+ if (data.errors && !data.data)
|
|
|
+ throw new Error(JSON.stringify(data.errors))
|
|
|
+ return data.data[Object.keys(data.data)[0]]
|
|
|
+ })
|
|
|
+
|
|
|
+const backendURL = "http://player.asmer.fs.a-level.com.ua"
|
|
|
+const gql = getGQL(backendURL + '/graphql')
|
|
|
+
|
|
|
+function jwtDecode(token) {
|
|
|
+ try {
|
|
|
+ let decoded = token.split('.')
|
|
|
+ decoded = decoded[1]
|
|
|
+ decoded = atob(decoded)
|
|
|
+ decoded = JSON.parse(decoded)
|
|
|
+ return decoded
|
|
|
+
|
|
|
+ } catch (e) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const actionLoadFile = (file) => {
|
|
|
+ let fd = new FormData
|
|
|
+ fd.append('photo', file)
|
|
|
+
|
|
|
+ return (
|
|
|
+ actionPromise('loadFile', fetch(backendURL + '/upload',{
|
|
|
+ method: "POST",
|
|
|
+ headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
|
|
|
+ body: fd
|
|
|
+ })
|
|
|
+ .then(res => res.json())
|
|
|
+ )
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+function promiseReducer(state={}, {type, name, status, payload, error}){
|
|
|
+ if (type === 'PROMISE'){
|
|
|
+ return {
|
|
|
+ ...state,
|
|
|
+ [name]:{status, payload, error}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return state
|
|
|
+}
|
|
|
+
|
|
|
+const store = createStore(
|
|
|
+ combineReducers(
|
|
|
+ {
|
|
|
+ promise: promiseReducer,
|
|
|
+ }
|
|
|
+ ), applyMiddleware(thunk)
|
|
|
+)
|
|
|
+store.subscribe(() => console.log(store.getState()))
|
|
|
+
|
|
|
+function MyDropzone({onLoad}) {
|
|
|
+ const onDrop = useCallback(acceptedFiles => {
|
|
|
+ //console.log(acceptedFiles)
|
|
|
+ onLoad(acceptedFiles[0])
|
|
|
+ }, [])
|
|
|
+ const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div {...getRootProps()}>
|
|
|
+ <input {...getInputProps()} />
|
|
|
+ {
|
|
|
+ isDragActive ?
|
|
|
+ <p>Drop the files here ...</p> :
|
|
|
+ <p>Drag 'n' drop some files here, or click to select files</p>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const ConnectDropzone = connect(null, {onLoad: actionLoadFile})(MyDropzone)
|
|
|
+
|
|
|
+function App() {
|
|
|
+ return (
|
|
|
+ <Provider store={store}>
|
|
|
+ <div className="App">
|
|
|
+ <ConnectDropzone />
|
|
|
+ </div>
|
|
|
+ </Provider>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+export default App;
|