Skip to content
This repository was archived by the owner on Dec 22, 2022. It is now read-only.

Commit d290ddc

Browse files
committed
login and register
1 parent f3ae813 commit d290ddc

File tree

11 files changed

+365
-3
lines changed

11 files changed

+365
-3
lines changed

api/customer/fragments/address.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import gql from 'graphql-tag'
2+
3+
export const mailingAddress = gql`
4+
fragment mailingAddress on MailingAddress {
5+
address1
6+
address2
7+
city
8+
company
9+
country
10+
countryCodeV2
11+
firstName
12+
formattedArea
13+
id
14+
lastName
15+
latitude
16+
longitude
17+
name
18+
phone
19+
province
20+
provinceCode
21+
zip
22+
}
23+
`

api/customer/fragments/customer.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import gql from 'graphql-tag'
2+
import { mailingAddress } from './address'
3+
4+
export const customer = gql`
5+
${mailingAddress}
6+
fragment customer on Customer {
7+
acceptsMarketing
8+
createdAt
9+
defaultAddress {
10+
...mailingAddress
11+
}
12+
displayName
13+
email
14+
firstName
15+
id
16+
lastName
17+
phone
18+
tags
19+
updatedAt
20+
}
21+
`
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import gql from 'graphql-tag'
2+
3+
export const customerAccessTokenCreate = gql`
4+
mutation customerAccessTokenCreate(
5+
$input: CustomerAccessTokenCreateInput!
6+
) {
7+
customerAccessTokenCreate(
8+
input: $input
9+
) {
10+
customerAccessToken {
11+
accessToken
12+
expiresAt
13+
}
14+
customerUserErrors {
15+
code
16+
field
17+
message
18+
}
19+
}
20+
}
21+
`
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import gql from 'graphql-tag'
2+
3+
export const customerAccessTokenDelete = gql`
4+
mutation customerAccessTokenDelete(
5+
$customerAccessToken: String!
6+
) {
7+
customerAccessTokenDelete(
8+
customerAccessToken: $customerAccessToken
9+
) {
10+
deletedAccessToken
11+
deletedCustomerAccessTokenId
12+
userErrors {
13+
field
14+
message
15+
}
16+
}
17+
}
18+
`
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import gql from 'graphql-tag'
2+
import { customer } from '../fragments/customer'
3+
4+
export const customerCreate = gql`
5+
${customer}
6+
mutation customerCreate(
7+
$input: CustomerCreateInput!
8+
) {
9+
customerCreate(
10+
input: $input
11+
) {
12+
customer {
13+
...customer
14+
}
15+
customerUserErrors {
16+
code
17+
field
18+
message
19+
}
20+
}
21+
}
22+
`

api/customer/mutations/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { customerAccessTokenCreate } from './customerAccessTokenCreate'
2+
export { customerAccessTokenDelete } from './customerAccessTokenDelete'
3+
export { customerCreate } from './customerCreate'

api/customer/queries/customer.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import gql from 'graphql-tag'
2+
import { customer } from '../fragments/customer'
3+
4+
export const getCustomer = gql`
5+
${customer}
6+
query customer (
7+
$customerAccessToken: String!
8+
) {
9+
customer (
10+
customerAccessToken: $customerAccessToken
11+
) {
12+
...customer
13+
}
14+
}
15+
`

pages/account.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ useHead({
88

99
<template>
1010
<div>
11-
Account Page
11+
<NuxtPage></NuxtPage>
1212
</div>
1313
</template>

pages/account/login.vue

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<script setup lang="ts">
2+
import {} from '@/types'
3+
import { useCustomer } from '@/stores'
4+
5+
// TODO: handle if customer has no password?
6+
7+
const email = ref('')
8+
const password = ref('')
9+
const canLogin = computed(() => email.value && password.value)
10+
const loginErrors = computed(() => useCustomer().customerUserErrors)
11+
12+
const submitLogin = () => {
13+
if (canLogin.value) {
14+
useCustomer().login(email.value, password.value)
15+
}
16+
}
17+
onMounted(() => {
18+
const createdEmailParam = useRoute().params.email
19+
createdEmailParam ? typeof createdEmailParam === 'string' ? email.value = createdEmailParam : email.value = createdEmailParam[0] : false
20+
})
21+
</script>
22+
23+
<template>
24+
<div>
25+
<h1 class="pb-6 text-lg font-extrabold border-b border-gray-200 md:text-3xl xl:text-4xl pt-14">Login</h1>
26+
<form
27+
class="grid max-w-xs gap-4 my-6"
28+
@submit.prevent="submitLogin"
29+
>
30+
<UIInput
31+
stretch
32+
type="email"
33+
label="Email"
34+
v-model="email"
35+
required
36+
/>
37+
<UIInput
38+
stretch
39+
type="password"
40+
label="Password"
41+
v-model="password"
42+
required
43+
/>
44+
<div class="text-red-600" v-if="loginErrors?.length">
45+
<span v-for="error in loginErrors">{{ error.message }}</span>
46+
</div>
47+
<div class="flex items-center space-x-3">
48+
<UIButton
49+
type="submit"
50+
:disabled="!canLogin"
51+
>
52+
Sign In
53+
</UIButton>
54+
<span>or</span>
55+
<NuxtLink
56+
:to="{ name: 'account-register' }"
57+
class="prose"
58+
>
59+
Create an Account
60+
</NuxtLink>
61+
</div>
62+
</form>
63+
</div>
64+
</template>

pages/account/register.vue

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<script setup lang="ts">
2+
import {} from '@/types'
3+
import { useCustomer } from '@/stores'
4+
import {} from '@/api/customer/mutations'
5+
6+
const customer = reactive({
7+
firstName: '',
8+
lastName: '',
9+
email: '',
10+
password: ''
11+
})
12+
const confirmPassword = ref('')
13+
const canRegister = computed(() =>
14+
customer.firstName &&
15+
customer.lastName &&
16+
customer.email &&
17+
customer.password &&
18+
customer.password === confirmPassword.value
19+
)
20+
const loginErrors = computed(() => useCustomer().customerUserErrors)
21+
22+
const submitRegister = () => {
23+
if (canRegister.value) {
24+
useCustomer().customerCreate(customer)
25+
}
26+
}
27+
28+
</script>
29+
30+
<template>
31+
<div>
32+
<h1 class="pb-6 text-lg font-extrabold border-b border-gray-200 md:text-3xl xl:text-4xl pt-14">Register</h1>
33+
<form
34+
class="grid max-w-xs gap-4 my-6"
35+
@submit.prevent="submitRegister"
36+
>
37+
<UIInput
38+
stretch
39+
type="text"
40+
label="First Name"
41+
v-model="customer.firstName"
42+
required
43+
/>
44+
<UIInput
45+
stretch
46+
type="text"
47+
label="Last Name"
48+
v-model="customer.lastName"
49+
required
50+
/>
51+
<UIInput
52+
stretch
53+
type="email"
54+
label="Email"
55+
v-model="customer.email"
56+
required
57+
/>
58+
<UIInput
59+
stretch
60+
type="password"
61+
label="Password"
62+
v-model="customer.password"
63+
required
64+
/>
65+
<UIInput
66+
stretch
67+
type="password"
68+
label="Password"
69+
v-model="confirmPassword"
70+
required
71+
/>
72+
<div class="text-red-600">
73+
<span v-for="error in loginErrors">{{ error.message }}</span>
74+
<span v-if="confirmPassword !== customer.password">Passwords do not match</span>
75+
</div>
76+
<div class="flex items-center space-x-3">
77+
<UIButton
78+
type="submit"
79+
:disabled="!canRegister"
80+
>
81+
Register
82+
</UIButton>
83+
<span>or</span>
84+
<NuxtLink
85+
:to="{ name: 'account-login' }"
86+
class="prose"
87+
>
88+
Login
89+
</NuxtLink>
90+
</div>
91+
</form>
92+
</div>
93+
</template>

stores/customer.ts

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,89 @@
11
import { defineStore } from 'pinia'
2+
import { useClient } from '@/utilities/apollo-client'
3+
import {
4+
Customer,
5+
CustomerAccessTokenCreateInput,
6+
CustomerAccessTokenDeleteInput,
7+
CustomerAccessToken,
8+
CustomerUserError,
9+
CustomerAccessTokenCreatePayload,
10+
CustomerCreateInput,
11+
CustomerCreatePayload,
12+
} from '@/types'
13+
import {
14+
customerAccessTokenCreate,
15+
customerAccessTokenDelete,
16+
customerCreate
17+
} from '@/api/customer/mutations'
18+
19+
type CustomerMutTokenCreate = {
20+
customerAccessTokenCreate: CustomerAccessTokenCreatePayload
21+
}
222

323
export const useCustomer = defineStore('customer', {
4-
state: () => ({}),
24+
state: () => ({
25+
customer: null as Customer | null,
26+
customerAccessToken: null as CustomerAccessToken | null,
27+
loading: false as boolean,
28+
customerUserErrors: null as CustomerUserError[],
29+
}),
30+
actions: {
31+
async customerCreate (input: CustomerCreateInput) {
32+
if (input) {
33+
const { data } = await useClient().mutate({
34+
mutation: customerCreate,
35+
variables: { input }
36+
})
37+
if (data.customerCreate.customer) {
38+
useRouter().push({ name: 'account-login', params: { email: input.email } })
39+
}
40+
if (data.customerCreate.customerUserErrors) {
41+
this.customerUserErrors = data.customerCreate.customerUserErrors
42+
}
43+
}
44+
},
45+
async getCustomer (accessToken: string) {
46+
console.log('getCustomer', accessToken)
47+
},
48+
async login (email: string, password: string) {
49+
try {
50+
this.loading = true
51+
if (!this.customerAccessToken) {
52+
const tokenCreateInput = { email, password }
53+
this.customerAccessTokenCreate(tokenCreateInput)
54+
}
55+
if (this.customerAccessToken.accessToken) {
56+
this.getCustomer(this.customerAccessToken.accessToken)
57+
}
58+
} catch (e) {
59+
return e
60+
} finally {
61+
this.loading = false
62+
}
63+
},
64+
async logout () {},
65+
async customerAccessTokenCreate (input: CustomerAccessTokenCreateInput) {
66+
try {
67+
const { data } = await useClient().mutate<CustomerMutTokenCreate>({
68+
mutation: customerAccessTokenCreate,
69+
variables: {
70+
input,
71+
}
72+
})
73+
if (data.customerAccessTokenCreate.customerAccessToken) {
74+
this.customerAccessToken = data.customerAccessTokenCreate.customerAccessToken
75+
}
76+
if (data.customerAccessTokenCreate.customerUserErrors) {
77+
this.customerUserErrors = data.customerAccessTokenCreate.customerUserErrors
78+
}
79+
} catch (e) {
80+
return e
81+
}
82+
},
83+
async customerAccessTokenDelete () {},
84+
},
85+
persist: {
86+
paths: ['customer', 'customerAccessToken'],
87+
},
588
getters: {},
6-
actions: {}
789
})

0 commit comments

Comments
 (0)