Add customer updated types & fixes

This commit is contained in:
Catalin Pinte 2022-09-14 09:28:12 +03:00
parent 6d289d1b5e
commit 5b6e50e7d0
14 changed files with 122 additions and 33 deletions

View File

@ -47,7 +47,19 @@ const getLoggedInCustomer: CustomerEndpoint['handlers']['getLoggedInCustomer'] =
}) })
} }
return res.status(200).json({ data: { customer } }) return res.status(200).json({
data: {
customer: {
id: String(customer.entityId),
firstName: customer.firstName,
lastName: customer.lastName,
email: customer.email,
company: customer.company,
phone: customer.phone,
notes: customer.notes,
},
},
})
} }
res.status(200).json({ data: null }) res.status(200).json({ data: null })

View File

@ -1,5 +1,7 @@
import { SWRHook } from '@vercel/commerce/utils/types' import { SWRHook } from '@vercel/commerce/utils/types'
import useCustomer, { UseCustomer } from '@vercel/commerce/customer/use-customer' import useCustomer, {
UseCustomer,
} from '@vercel/commerce/customer/use-customer'
import type { CustomerHook } from '../types/customer' import type { CustomerHook } from '../types/customer'
export default useCustomer as UseCustomer<typeof handler> export default useCustomer as UseCustomer<typeof handler>

View File

@ -2,6 +2,7 @@ import type { Product } from '../types/product'
import type { Cart, BigcommerceCart, LineItem } from '../types/cart' import type { Cart, BigcommerceCart, LineItem } from '../types/cart'
import type { Page } from '../types/page' import type { Page } from '../types/page'
import type { BCCategory, BCBrand, Category, Brand } from '../types/site' import type { BCCategory, BCBrand, Category, Brand } from '../types/site'
import { definitions } from '../api/definitions/store-content' import { definitions } from '../api/definitions/store-content'
import update from './immutability' import update from './immutability'
import getSlug from './get-slug' import getSlug from './get-slug'

View File

@ -32,7 +32,7 @@ export const handler: SWRHook<GetWishlistHook> = {
const { data: customer } = useCustomer() const { data: customer } = useCustomer()
const response = useData({ const response = useData({
input: [ input: [
['customerId', customer?.entityId], ['customerId', customer?.id],
['includeProducts', input?.includeProducts], ['includeProducts', input?.includeProducts],
], ],
swrOptions: { swrOptions: {

View File

@ -6,7 +6,7 @@ import isAllowedOperation from '../../utils/is-allowed-operation'
const customerEndpoint: GetAPISchema< const customerEndpoint: GetAPISchema<
any, any,
CustomerSchema<any> CustomerSchema
>['endpoint']['handler'] = async (ctx) => { >['endpoint']['handler'] = async (ctx) => {
const { req, res, handlers } = ctx const { req, res, handlers } = ctx

View File

@ -5,7 +5,7 @@ import type { HookFetcherFn, SWRHook } from '../utils/types'
import type { Provider } from '..' import type { Provider } from '..'
export type UseCustomer< export type UseCustomer<
H extends SWRHook<CustomerHook<any>> = SWRHook<CustomerHook> H extends SWRHook<CustomerHook> = SWRHook<CustomerHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<CustomerHook> = SWRFetcher export const fetcher: HookFetcherFn<CustomerHook> = SWRFetcher

View File

@ -49,6 +49,9 @@ export interface AddressFields {
country: string country: string
} }
/**
* Hook for getting a customer's addresses.
*/
export interface GetAddressesHook { export interface GetAddressesHook {
data: Address[] | null data: Address[] | null
input: {} input: {}
@ -56,6 +59,9 @@ export interface GetAddressesHook {
swrState: { isEmpty: boolean } swrState: { isEmpty: boolean }
} }
/**
* Hook for adding an address to a customer's account.
*/
export interface AddItemHook { export interface AddItemHook {
data: Address data: Address
input?: AddressFields input?: AddressFields
@ -64,6 +70,9 @@ export interface AddItemHook {
actionInput: AddressFields actionInput: AddressFields
} }
/**
* Hook for updating an address to a customer's account.
*/
export interface UpdateItemHook { export interface UpdateItemHook {
data: Address | null data: Address | null
input: { item?: AddressFields; wait?: number } input: { item?: AddressFields; wait?: number }
@ -72,6 +81,9 @@ export interface UpdateItemHook {
actionInput: AddressFields & { id: string } actionInput: AddressFields & { id: string }
} }
/**
* Hook for deliting an address to a customer's account.
*/
export interface RemoveItemHook { export interface RemoveItemHook {
data: Address | null | undefined data: Address | null | undefined
input: { item?: Address } input: { item?: Address }
@ -80,6 +92,9 @@ export interface RemoveItemHook {
actionInput: { id: string } actionInput: { id: string }
} }
/**
* Hooks for managing a customer's addresses.
*/
export interface CustomerAddressHooks { export interface CustomerAddressHooks {
getAddresses: GetAddressesHook getAddresses: GetAddressesHook
addItem: AddItemHook addItem: AddItemHook
@ -87,6 +102,10 @@ export interface CustomerAddressHooks {
removeItem: RemoveItemHook removeItem: RemoveItemHook
} }
/**
* API endpoints for managing a customer's addresses.
*/
export type AddItemHandler = AddItemHook & { export type AddItemHandler = AddItemHook & {
body: { cartId: string } body: { cartId: string }
} }

View File

@ -4,8 +4,8 @@ export interface Card {
*/ */
id: string id: string
/** /**
* Masked card number. * Masked card number. Contains only the last 4 digits.
* @example "************4242" * @example "4242"
*/ */
mask: string mask: string
/** /**

View File

@ -1,24 +1,53 @@
export * as Card from './card' export * as Card from './card'
export * as Address from './address' export * as Address from './address'
// TODO: define this type export interface Customer {
export type Customer = any /**
* The unique identifier for the customer.
export type CustomerTypes = { */
customer: Customer id: string
/**
* The customer's first name.
*/
firstName: string
/**
* The customer's last name.
*/
lastName: string
/**
* The customer's email address.
*/
email?: string
/**
* The customer's phone number.
* @optional
*/
phone?: string
/**
* The customer's company name.
*/
company?: string
/**
* The customer's notes.
*/
notes?: string
/**
* Indicates wathever the customer accepts marketing, such as email newsletters.
*/
acceptsMarketing?: boolean
} }
export type CustomerHook<T extends CustomerTypes = CustomerTypes> = { export interface CustomerHook {
data: T['customer'] | null data: Customer | null | undefined
fetchData: { customer: T['customer'] } | null fetchData: { customer: Customer } | null
} }
export type CustomerSchema<T extends CustomerTypes = CustomerTypes> = { export type CustomerSchema = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
getLoggedInCustomer: { getLoggedInCustomer: {
data: { customer: T['customer'] } | null data: { customer: Customer } | null
} }
} }
} }

View File

@ -1,7 +1,9 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { decode } from 'jsonwebtoken' import { decode } from 'jsonwebtoken'
import { SWRHook } from '@vercel/commerce/utils/types' import { SWRHook } from '@vercel/commerce/utils/types'
import useCustomer, { UseCustomer } from '@vercel/commerce/customer/use-customer' import useCustomer, {
UseCustomer,
} from '@vercel/commerce/customer/use-customer'
import { CUSTOMER_COOKIE, API_URL } from '../constants' import { CUSTOMER_COOKIE, API_URL } from '../constants'
import type { CustomerHook } from '../types/customer' import type { CustomerHook } from '../types/customer'
@ -13,12 +15,13 @@ export const handler: SWRHook<CustomerHook> = {
}, },
async fetcher({ options, fetch }) { async fetcher({ options, fetch }) {
const token = Cookies.get(CUSTOMER_COOKIE) const token = Cookies.get(CUSTOMER_COOKIE)
if (!token) { if (!token) {
return null return null
} }
const decodedToken = decode(token) as { cid: string } const decodedToken = decode(token) as { cid: string }
const customer = await fetch({ const customer = await fetch<any>({
query: options.query, query: options.query,
method: options.method, method: options.method,
variables: [ variables: [
@ -29,7 +32,16 @@ export const handler: SWRHook<CustomerHook> = {
token, token,
], ],
}) })
return customer return customer
? {
id: customer.id,
firstName: customer.firstname,
lastName: customer.lastname,
email: customer.email,
phone: customer.phone,
}
: null
}, },
useHook: useHook:
({ useData }) => ({ useData }) =>

View File

@ -95,12 +95,11 @@ export function normalizeCart(data: any): Cart {
export function normalizeCustomer(customer: CustomerAccountInput): Customer { export function normalizeCustomer(customer: CustomerAccountInput): Customer {
return { return {
id: customer.id, id: String(customer.id),
firstName: customer.firstName, firstName: customer.firstName || '',
lastName: customer.lastName, lastName: customer.lastName || '',
email: customer.emailAddress, email: customer.emailAddress || '',
userName: customer.userName, acceptsMarketing: !!customer.acceptsMarketing,
isAnonymous: customer.isAnonymous,
} }
} }

View File

@ -14,14 +14,28 @@ export const handler: SWRHook<CustomerHook> = {
}, },
async fetcher({ options, fetch }) { async fetcher({ options, fetch }) {
const customerAccessToken = getCustomerToken() const customerAccessToken = getCustomerToken()
if (customerAccessToken) { if (customerAccessToken) {
const data = await fetch<GetCustomerQuery, GetCustomerQueryVariables>({ const { customer } = await fetch<
GetCustomerQuery,
GetCustomerQueryVariables
>({
...options, ...options,
variables: { customerAccessToken: getCustomerToken() }, variables: { customerAccessToken: getCustomerToken() },
}) })
return data.customer
if (!customer) {
return null
}
return {
id: customer.id,
firstName: customer.firstName ?? 'N/A',
lastName: customer.lastName ?? '',
...(customer.email && { email: customer.email }),
...(customer.phone && { phone: customer.phone }),
}
} }
return null
}, },
useHook: useHook:
({ useData }) => ({ useData }) =>

View File

@ -6,10 +6,11 @@ const normalizeUser = (
_spreeSuccessResponse: SpreeSdkResponse, _spreeSuccessResponse: SpreeSdkResponse,
spreeUser: AccountAttr spreeUser: AccountAttr
): Customer => { ): Customer => {
const email = spreeUser.attributes.email
return { return {
email, id: spreeUser.id,
email: spreeUser.attributes.email,
firstName: spreeUser.attributes.firstname,
lastName: spreeUser.attributes.lastname,
} }
} }

View File

@ -23,8 +23,8 @@
"@components/*": ["components/*"], "@components/*": ["components/*"],
"@commerce": ["../packages/commerce/src"], "@commerce": ["../packages/commerce/src"],
"@commerce/*": ["../packages/commerce/src/*"], "@commerce/*": ["../packages/commerce/src/*"],
"@framework": ["../packages/shopify/src"], "@framework": ["../packages/vendure/src"],
"@framework/*": ["../packages/shopify/src/*"] "@framework/*": ["../packages/vendure/src/*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],