Tomi Cvetic před 5 roky
rodič
revize
bfd9678e8c

+ 2 - 2
backend/src/resolvers.js

@@ -2,13 +2,13 @@ const { forwardTo } = require('prisma-binding')
 const bcrypt = require('bcryptjs')
 const jwt = require('jsonwebtoken')
 
-const LoginError = new Error('You must be logged in.')
+const LoginError = new Error('ERR_LOGIN: You must be logged in.')
 
 const Query = {
   users: forwardTo('db'),
   trainings: forwardTo('db'),
   me: (parent, args, context, info) => {
-    if (!context.request.userId) throw new Error('Not logged in.')
+    if (!context.request.userId) throw LoginError
     return context.db.query.user({ where: { id: context.request.userId } }, info)
   }
 }

+ 78 - 5
frontend/components/user.js

@@ -1,14 +1,87 @@
-import { Mutation } from 'react-apollo'
+import { Query, Mutation } from 'react-apollo'
 import Link from 'next/link'
+import { Formik, Form, Field, ErrorMessage } from 'formik'
+import { email } from '../lib/regex'
+import { adopt } from 'react-adopt'
 
-import { USER_LOGIN } from '../lib/graphql'
+import { USER_LOGIN, CURRENT_USER } from '../lib/graphql'
 
 const UserLoginForm = props => <p>Login Form</p>
 
+const LoginAdoption = adopt({
+  mutation: ({ render, formik }) => (
+    <Mutation
+      mutation={USER_LOGIN}
+      refetchQueries={[{ query: CURRENT_USER }]}
+    >{render}
+    </Mutation>
+  ),
+  formik: ({ render, mutation }) => (
+    <Formik
+      initialValues={{ email: '', password: '' }}
+      validate={values => {
+        const errors = {}
+        if (!values.email) errors.email = 'Required'
+        else if (!email.test(values.email)) errors.email = 'Invalid email address'
+        return errors
+      }}
+      onSubmit={(values, { setSubmitting }) => {
+        mutation({ variables: values })
+      }}
+    >
+      {render}
+    </Formik>
+  )
+})
+
+const LoginForm = props => (
+  <LoginAdoption>
+    {({ formik, mutation }) => {
+      return (
+        <Form>
+          <Field type='email' name='email' />
+          <ErrorMessage name='email' component='span' />
+          <Field type='password' name='password' />
+          <ErrorMessage name='password' component='span' />
+          <button type='submit' disabled={formik.isSubmitting}>Login</button>
+        </Form>
+      )
+    }}
+  </LoginAdoption>
+)
+
 const UserNav = props => (
-  <Link href='user'>
-    <a>test</a>
-  </Link>
+  <Query query={CURRENT_USER}>
+    {
+      ({ data, error, loading }) => {
+        if (error) {
+          return <LoginForm />
+        }
+        if (loading) return (<p>Loading...</p>)
+        console.log(data)
+        return (
+          <Link href={{ pathname: 'user', query: { id: 12 } }}>
+            <a>test {props.query}</a>
+          </Link>
+        )
+      }
+    }
+  </Query>
+)
+
+const SignupForm = props => (
+  <Formik
+    initialValues={{ email: '', name: '', password: '', passwordAgain: '' }}
+    onSubmit={values => {
+      console.log('submitted', values)
+    }}
+  >
+    {
+      ({ isSubmitting }) => (
+        <Form />
+      )
+    }
+  </Formik>
 )
 
 const User = props => <a />

+ 11 - 2
frontend/lib/graphql.js

@@ -1,4 +1,3 @@
-import { mutation } from 'react-apollo'
 import gql from 'graphql-tag'
 
 const USER_LOGIN = gql`
@@ -27,4 +26,14 @@ const USER_SIGNUP = gql`
   }
 `
 
-export { USER_LOGIN, USER_LOGOUT, USER_SIGNUP }
+const CURRENT_USER = gql`
+  query {
+    me {
+      id
+      email
+      name
+    }
+  }
+`
+
+export { USER_LOGIN, USER_LOGOUT, USER_SIGNUP, CURRENT_USER }

+ 3 - 0
frontend/lib/regex.js

@@ -0,0 +1,3 @@
+const email = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i
+
+export { email }

+ 16 - 14
frontend/lib/withApollo.js

@@ -8,28 +8,30 @@
  */
 
 import withApollo from 'next-with-apollo'
-import ApolloClient from 'apollo-client'
+import { ApolloClient } from 'apollo-client'
 import { InMemoryCache } from 'apollo-cache-inmemory'
+import { HttpLink } from 'apollo-link-http'
 import { onError } from 'apollo-link-error'
 import { ApolloLink } from 'apollo-link'
 
 const cache = new InMemoryCache()
+const link = new HttpLink({ uri: 'http://localhost:8801/' })
+const oldLink = 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}`)
+  })
+])
 
 function createClient({ ctx, headers }) {
   return new ApolloClient({
-    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}`)
-      })
-    ]),
-    fetchOptions: { mode: 'no-cors' },
+    link,
     cache
   })
 }

+ 45 - 0
frontend/package-lock.json

@@ -2596,6 +2596,11 @@
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
       "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
     },
+    "deepmerge": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
+      "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA=="
+    },
     "defaults": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
@@ -3539,6 +3544,31 @@
         "worker-rpc": "^0.1.0"
       }
     },
+    "formik": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/formik/-/formik-2.0.6.tgz",
+      "integrity": "sha512-x2fC80v8AIrGgpxWrLqKaK9hdV8WX4OSLK+Fr5lclqExA59NCuxdB3WiuxJQc9/g043BmfTIuaILrV9Wq0MPVw==",
+      "requires": {
+        "deepmerge": "^2.1.1",
+        "hoist-non-react-statics": "^3.3.0",
+        "lodash": "^4.17.14",
+        "lodash-es": "^4.17.14",
+        "react-fast-compare": "^2.0.1",
+        "scheduler": "^0.17.0",
+        "tiny-warning": "^1.0.2",
+        "tslib": "^1.10.0"
+      },
+      "dependencies": {
+        "hoist-non-react-statics": {
+          "version": "3.3.1",
+          "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+          "integrity": "sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw==",
+          "requires": {
+            "react-is": "^16.7.0"
+          }
+        }
+      }
+    },
     "fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -4808,6 +4838,11 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
       "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
     },
+    "lodash-es": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
+      "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
+    },
     "lodash._reinterpolate": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -6567,6 +6602,11 @@
       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.6.tgz",
       "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q=="
     },
+    "react-fast-compare": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
+      "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
+    },
     "react-is": {
       "version": "16.8.6",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
@@ -7613,6 +7653,11 @@
         "setimmediate": "^1.0.4"
       }
     },
+    "tiny-warning": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+    },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",

+ 1 - 0
frontend/package.json

@@ -15,6 +15,7 @@
     "apollo-link-error": "^1.1.12",
     "apollo-link-http": "^1.5.16",
     "dotenv": "^8.2.0",
+    "formik": "^2.0.6",
     "fuse.js": "3.4.5",
     "graphql": "^14.5.8",
     "graphql-tag": "^2.10.1",