Mutations

We need to create the mutations that will allow our users to signup and sign into the app. The API has already created the mutations with the args needed for this functionality.

// gql/signinMutation
import { gql } from '@urql/next'

export const SigninMutation = gql`
  mutation Mutation($input: AuthInput!) {
    signin(input: $input) {
      token
    }
  }
`

// gql/signupMutation
import { gql } from '@urql/next'

export const SignupMutation = gql`
  mutation Mutation($input: AuthInput!) {
    createUser(input: $input) {
      token
    }
  }
`

Then we need to use these mutations in the matching pages.

// app/signup.ts
'use client'

import { SignupMutation } from '@/gql/signupMutation'
import { setToken } from '@/utils/token'
import { Button, Input } from '@nextui-org/react'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
import { useMutation } from 'urql'

const SignupPage = () => {
  const [signupResult, signup] = useMutation(SignupMutation)
  const [state, setState] = useState({ password: '', email: '' })
  const router = useRouter()

  const handleSignup = async (e) => {
    e.preventDefault()
    const result = await signup({ input: state })

    if (result.data.createUser) {
      setToken(result.data.createUser.token)
      router.push('/')
    }
  }

  return (
    <div className="bg-white rounded-md border p-4 w-full shadow-sm">
      <div className="text-2xl text-black/70">Sign up</div>
      <form onSubmit={handleSignup} className="flex flex-col gap-4 mt-4">
        <div>
          <Input
            value={state.email}
            onValueChange={(v) => setState((s) => ({ ...s, email: v }))}
            variant="faded"
            label="Email"
            classNames={{
              inputWrapper: 'bg-slate-50 border-slate-100',
            }}
          />
        </div>
        <div>
          <Input
            variant="faded"
            value={state.password}
            onValueChange={(v) => setState((s) => ({ ...s, password: v }))}
            label="Password"
            type="password"
            classNames={{ inputWrapper: 'bg-slate-50 border-slate-100' }}
          />
        </div>
        <div className="text-end">
          <Button type="submit" variant="solid" color="primary">
            Signup
          </Button>
        </div>
      </form>
    </div>
  )
}

export default SignupPage

You can see hose we use the useMutation hook.

Now, same thing for sign in.

// app/signin
'use client'

import { SigninMutation } from '@/gql/signinMutation'
import { setToken } from '@/utils/token'
import { Button, Input } from '@nextui-org/react'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
import { useMutation } from 'urql'

const SigninPage = () => {
  const [signinResult, signin] = useMutation(SigninMutation)
  const [state, setState] = useState({ password: '', email: '' })
  const router = useRouter()

  const handleSignin = async (e) => {
    e.preventDefault()
    const result = await signin({ input: state })

    if (result.data.signin) {
      setToken(result.data.signin.token)
      router.push('/')
    }
  }

  return (
    <div className="bg-white rounded-md border p-4 w-full shadow-sm">
      <div className="text-2xl text-black/70">Sign in</div>
      <form onSubmit={handleSignin} className="flex flex-col gap-4 mt-4">
        <div>
          <Input
            value={state.email}
            onValueChange={(v) => setState((s) => ({ ...s, email: v }))}
            variant="faded"
            label="Email"
            classNames={{
              inputWrapper: 'bg-slate-50 border-slate-100',
            }}
          />
        </div>
        <div>
          <Input
            variant="faded"
            value={state.password}
            onValueChange={(v) => setState((s) => ({ ...s, password: v }))}
            label="Password"
            type="password"
            classNames={{ inputWrapper: 'bg-slate-50 border-slate-100' }}
          />
        </div>
        <div className="text-end">
          <Button type="submit" variant="solid" color="primary">
            Signin
          </Button>
        </div>
      </form>
    </div>
  )
}

export default SigninPage