Эх сурвалжийг харах

experimenting with local state and using apollo client with file upload

Tomi Cvetic 5 жил өмнө
parent
commit
be2e08bfb4

+ 2 - 0
backend/schema.graphql

@@ -1,4 +1,5 @@
 # import * from './database/generated/prisma.graphql'
+scalar Upload
 
 type Query {
   projects(where: ProjectWhereInput, orderBy: ProjectOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Project]!
@@ -14,4 +15,5 @@ type Mutation {
   createProjectVersion(name: String!, date: String!, project: ID!, changes: [String]): ProjectVersion!
   userLogin(email: String!, password: String!): User!
   userLogout: String!
+  uploadFiles(files: [Upload!]!, name: String!, description: String!): String!
 }

+ 10 - 0
backend/src/resolvers.js

@@ -81,6 +81,16 @@ const Mutation = {
       }
     }, info)
     return projectVersion
+  },
+  uploadFiles: async (parent, args, context, info) => {
+    console.log(args)
+    const { name, description, files } = args
+    let res
+    for (const file of files) {
+      res = await file
+      console.log(res)
+    }
+    return res.filename
   }
 }
 

+ 1 - 1
frontend/components/Error.js

@@ -15,4 +15,4 @@ const ErrorList = props => {
 }
 
 export default ErrorList
-export { ErrorList }
+export { Errors }

+ 52 - 3
frontend/components/FileUpload.js

@@ -1,6 +1,55 @@
+import gql from 'graphql-tag'
+import { Mutation, Query } from 'react-apollo'
 import { useState } from 'react'
 import { endpoint } from '../config'
 
+const DO_LOCAL = gql`
+  {
+    doLocal @client
+  }
+`
+
+const UPLOAD_FILE = gql`
+  mutation UPLOAD_FILE($files: [Upload!]!, $name: String!, $description: String!) {
+    uploadFiles(files: $files, name: $name, description: $description)
+  }
+`
+
+const TestForm = props => {
+  const [state, setState] = useState({ files: null, name: '', description: '' })
+  function updateState(event) {
+    const { name, type, files, value } = event.target
+    setState({ ...state, [name]: type === 'file' ? files : value })
+  }
+  return (
+    <Mutation mutation={UPLOAD_FILE} variables={state}>
+      {(uploadFiles, { data, error, loading }) => (
+        <form onSubmit={async event => {
+          console.log(state)
+          event.preventDefault()
+          const res = await uploadFiles()
+          console.log(res)
+        }}>
+          <input type='file' multiple required name='files' onChange={updateState} />
+          <input type='text' name='name' value={state.name} onChange={updateState} />
+          <textarea name='description' value={state.description} onChange={updateState} />
+          <button>Send</button>
+          <Query query={DO_LOCAL}>
+            {({ data, client }) => (
+              <>
+                <button type='button' onClick={
+                  event => { client.writeData({ data: { doLocal: !data.doLocal } }) }
+                }>Do Local</button>
+                <button disabled={data.doLocal}>Uh-Oh!</button>
+              </>
+            )}
+          </Query>
+        </form>
+      )}
+    </Mutation>
+  )
+}
+
 const FileFields = props => {
   const [state, setState] = useState({ ...FileState })
 
@@ -17,8 +66,8 @@ const FileFields = props => {
   return (
     < fieldset >
       <label htmlFor='file'>File</label>
-      <input type='file' name='file' id='file' onChange={updateState} />
-      < label htmlFor='name'>File name</label>
+      <input type='file' multiple required name='file' id='file' onChange={updateState} />
+      <label htmlFor='name'>File name</label>
       <input type='text' name='name' id='name' placeholder='File name' value={state.name} onChange={updateState} />
       <label htmlFor='description'>File description</label>
       <textarea name='description' id='description' placeholder='File description' value={state.description} onChange={updateState} />
@@ -105,4 +154,4 @@ class FileUpload extends React.Component {
 }
 
 export default FileUpload
-export { FileFields, FileState, uploadFile }
+export { FileFields, FileState, uploadFile, TestForm }

+ 2 - 4
frontend/components/ProjectForm.js

@@ -1,5 +1,3 @@
-import { useState } from 'react'
-import styled from 'styled-components'
 import gql from 'graphql-tag'
 import { Mutation, Query } from 'react-apollo'
 import { FileFields, FileState, uploadFile } from './FileUpload'
@@ -68,7 +66,7 @@ const ProjectState = {
 }
 
 const ProjectFields = props => {
-  const [state, setState] = useState({ ...ProjectState })
+  const [state, setState] = React.useState({ ...ProjectState })
 
   const updateState = event => {
     setState({
@@ -92,7 +90,7 @@ const ProjectFields = props => {
 }
 
 const Project = props => {
-  const [state, setState] = useState({
+  const [state, setState] = React.useState({
     ...ProjectState,
     ...props.project
   })

+ 22 - 13
frontend/lib/withApollo.js

@@ -8,24 +8,33 @@
  */
 
 import withApollo from 'next-with-apollo'
-import ApolloClient from 'apollo-boost'
+import ApolloClient from 'apollo-client'
+import { InMemoryCache } from 'apollo-cache-inmemory'
+import { onError } from 'apollo-link-error'
+import { ApolloLink } from 'apollo-link'
+import { createUploadLink } from 'apollo-upload-client'
 import { endpoint, prodEndpoint } from '../config'
+import { resolvers, typeDefs } from './localState'
 
 function createClient ({ ctx, headers, initialState }) {
   return new ApolloClient({
-    uri: process.env.NODE_ENV === 'development' ? endpoint : prodEndpoint,
-    request: operation => {
-      operation.setContext({
-        fetchOptions: {
-          credentials: 'include'
-        },
-        headers
+    link: ApolloLink.from([
+      onError(({ graphQLErrors, networkError }) => {
+        if (graphQLErrors) {
+          graphQLErrors.map(({ message, locations, path }) =>
+            console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`))
+        }
+        if (networkError) console.log(`[Network error]: ${networkError}`)
+      }),
+      createUploadLink({
+        uri: process.env.NODE_ENV === 'development' ? endpoint : prodEndpoint,
+        headers,
+        credentials: 'include'
       })
-    },
-    clientState: {
-      resolvers: {},
-      defaults: {}
-    }
+    ]),
+    cache: new InMemoryCache(),
+    resolvers,
+    typeDefs
   })
 }
 

+ 2 - 0
frontend/pages/index.js

@@ -6,12 +6,14 @@
 import DemoForm from '../components/Form'
 import Project from '../components/ProjectForm'
 import ProjectVersionForm from '../components/ProjectVersionForm'
+import { TestForm } from '../components/FileUpload'
 
 const Index = props => (
   <div>
     <DemoForm />
     <Project />
     <ProjectVersionForm />
+    <TestForm />
   </div>
 )