Ordercloud signup hook/endpoint and stubbing out other ordercloud auth endpoints

This commit is contained in:
Adam Clason 2023-01-21 17:59:53 -06:00
parent e66cd12f4c
commit 233070869d
10 changed files with 204 additions and 44 deletions

View File

@ -48,8 +48,9 @@
},
"dependencies": {
"@vercel/commerce": "workspace:*",
"lodash.debounce": "^4.0.8",
"cookie": "^0.4.1"
"cookie": "^0.4.1",
"jsonwebtoken": "8.5.1",
"lodash.debounce": "^4.0.8"
},
"peerDependencies": {
"next": "^13",
@ -60,11 +61,12 @@
"@taskr/clear": "^1.1.0",
"@taskr/esnext": "^1.1.0",
"@taskr/watch": "^1.1.0",
"@types/cookie": "^0.4.1",
"@types/jsonwebtoken": "8.5.7",
"@types/lodash.debounce": "^4.0.6",
"@types/node": "^17.0.8",
"@types/react": "^18.0.14",
"@types/cookie": "^0.4.1",
"@types/node-fetch": "^2.6.2",
"@types/react": "^18.0.14",
"lint-staged": "^12.1.7",
"next": "^13.0.6",
"prettier": "^2.5.1",

View File

@ -7,6 +7,7 @@ import checkout from './checkout'
import products from './catalog/products'
import customerCard from './customer/card'
import customerAddress from './customer/address'
import signup from './signup';
const endpoints = {
cart,
@ -14,6 +15,7 @@ const endpoints = {
'customer/card': customerCard,
'customer/address': customerAddress,
'catalog/products': products,
'signup': signup
}
export default function ordercloudAPI(commerce: OrdercloudAPI) {

View File

@ -0,0 +1,18 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import signupEndpoint from '@vercel/commerce/api/endpoints/signup'
import type { SignupSchema } from '@vercel/commerce/types/signup'
import type { OrdercloudAPI } from '../..'
import signup from './signup'
export type SignupAPI = GetAPISchema<OrdercloudAPI, SignupSchema>
export type SignupEndpoint = SignupAPI['endpoint']
export const handlers: SignupEndpoint['handlers'] = { signup }
const singupApi = createEndpoint<SignupAPI>({
handler: signupEndpoint,
handlers,
})
export default singupApi

View File

@ -0,0 +1,58 @@
import type { SignupEndpoint } from '.'
import { decode, type JwtPayload } from 'jsonwebtoken'
import { serialize } from 'cookie'
import { access } from 'fs'
const signup: SignupEndpoint['handlers']['signup'] = async ({
req,
body: { firstName, lastName, password, email },
config: { restBuyerFetch, tokenCookie },
}) => {
// Get token
const token = req.cookies.get(tokenCookie)?.value
let headers: any = {}
const accessToken = await restBuyerFetch(
'PUT',
`/me/register`,
{
Username: email,
Password: password,
FirstName: firstName,
LastName: lastName,
Email: email,
Active: true,
},
{
token,
anonToken: true,
}
).then((response: any) => {
return response.access_token
})
console.log('got access token: ', accessToken)
if (accessToken) {
const decodedToken = decode(accessToken) as JwtPayload
console.log('decoded: ', decodedToken)
return {
headers: {
'Set-Cookie': serialize(tokenCookie, accessToken, {
maxAge: decodedToken.exp,
expires: new Date(Date.now() + decodedToken.exp! * 1000),
secure: process.env.NODE_ENV === 'production',
path: '/',
sameSite: 'lax',
}),
},
}
}
return { data: undefined, headers }
}
export default signup

View File

@ -57,10 +57,13 @@ export async function fetchData<T>(opts: {
// Destructure opts
const { path, body, fetchOptions, config, token, method = 'GET' } = opts
let url = `${config.commerceUrl}/${config.apiVersion}${path}`
if (fetchOptions?.anonToken) {
url += `?anonUserToken=${encodeURIComponent(token)}`
}
// Do the request with the correct headers
const dataResponse = await fetch(
`${config.commerceUrl}/${config.apiVersion}${path}`,
{
const dataResponse = await fetch(url, {
...fetchOptions,
method,
headers: {
@ -70,8 +73,7 @@ export async function fetchData<T>(opts: {
authorization: `Bearer ${token}`,
},
body: body ? JSON.stringify(body) : undefined,
}
)
})
// If something failed getting the data response
if (!dataResponse.ok) {

View File

@ -1,16 +1,43 @@
import { MutationHook } from '@vercel/commerce/utils/types'
import useLogin, { UseLogin } from '@vercel/commerce/auth/use-login'
import type { MutationHook } from '@vercel/commerce/utils/types'
import useLogin, { type UseLogin } from '@vercel/commerce/auth/use-login'
import { useCallback } from 'react'
import { CommerceError } from '@vercel/commerce/utils/errors'
import type { LoginHook } from '@vercel/commerce/types/login'
import useCustomer from '../customer/use-customer'
import useCart from '../cart/use-cart'
export default useLogin as UseLogin<typeof handler>
export const handler: MutationHook<any> = {
export const handler: MutationHook<LoginHook> = {
fetchOptions: {
query: '',
url: '/api/commerce/login',
method: 'POST',
},
async fetcher() {
return null
async fetcher({ input: { email, password }, options, fetch }) {
if (!(email && password)) {
throw new CommerceError({
message: 'An email and password are required to login',
})
}
return fetch({
...options,
body: { email, password },
})
},
useHook: () => () => {
return async function () {}
useHook:
({ fetch }) =>
() => {
const { mutate } = useCustomer()
const { mutate: mutateCart } = useCart()
return useCallback(
async function login(input) {
const data = await fetch({ input })
await mutate()
await mutateCart()
return data
},
[fetch, mutate, mutateCart]
)
},
}

View File

@ -1,17 +1,31 @@
import { MutationHook } from '@vercel/commerce/utils/types'
import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types'
import useLogout, { UseLogout } from '@vercel/commerce/auth/use-logout'
import type { LogoutHook } from '@vercel/commerce/types/logout'
import useCustomer from '../customer/use-customer'
import useCart from '../cart/use-cart'
export default useLogout as UseLogout<typeof handler>
export const handler: MutationHook<any> = {
export const handler: MutationHook<LogoutHook> = {
fetchOptions: {
query: '',
},
async fetcher() {
return null
url: '/api/commerce/logout',
method: 'GET',
},
useHook:
({ fetch }) =>
() =>
async () => {},
() => {
const { mutate } = useCustomer()
const { mutate: mutateCart } = useCart()
return useCallback(
async function logout() {
const data = await fetch()
await mutate(null, false)
await mutateCart(null, false)
return data
},
[fetch, mutate, mutateCart]
)
},
}

View File

@ -1,19 +1,46 @@
import { useCallback } from 'react'
import type { MutationHook } from '@vercel/commerce/utils/types'
import { CommerceError } from '@vercel/commerce/utils/errors'
import useSignup, { type UseSignup } from '@vercel/commerce/auth/use-signup'
import type { SignupHook } from '@vercel/commerce/types/signup'
import useCustomer from '../customer/use-customer'
import { MutationHook } from '@vercel/commerce/utils/types'
import useSignup, { UseSignup } from '@vercel/commerce/auth/use-signup'
export default useSignup as UseSignup<typeof handler>
export const handler: MutationHook<any> = {
export const handler: MutationHook<SignupHook> = {
fetchOptions: {
query: '',
url: '/api/commerce/signup',
method: 'POST',
},
async fetcher() {
return null
async fetcher({
input: { firstName, lastName, email, password },
options,
fetch,
}) {
if (!(firstName && lastName && email && password)) {
throw new CommerceError({
message:
'A first name, last name, email and password are required to signup',
})
}
return fetch({
...options,
body: { firstName, lastName, email, password },
})
},
useHook:
({ fetch }) =>
() =>
() => {},
() => {
//const { mutate } = useCustomer() TODO add mutate back in once useCustomer is implemented
return useCallback(
async function signup(input) {
const data = await fetch({ input })
// await mutate()
return data
},
[fetch] //mutate]
)
},
}

View File

@ -4,7 +4,7 @@
"wishlist": false,
"cart": true,
"search": true,
"customerAuth": false,
"customerAuth": true,
"customCheckout": true
}
}

10
pnpm-lock.yaml generated
View File

@ -263,12 +263,14 @@ importers:
'@taskr/esnext': ^1.1.0
'@taskr/watch': ^1.1.0
'@types/cookie': ^0.4.1
'@types/jsonwebtoken': 8.5.7
'@types/lodash.debounce': ^4.0.6
'@types/node': ^17.0.8
'@types/node-fetch': ^2.6.2
'@types/react': ^18.0.14
'@vercel/commerce': workspace:*
cookie: ^0.4.1
jsonwebtoken: 8.5.1
lint-staged: ^12.1.7
lodash.debounce: ^4.0.8
next: ^13.0.6
@ -281,12 +283,14 @@ importers:
dependencies:
'@vercel/commerce': link:../commerce
cookie: 0.4.2
jsonwebtoken: 8.5.1
lodash.debounce: 4.0.8
devDependencies:
'@taskr/clear': 1.1.0
'@taskr/esnext': 1.1.0
'@taskr/watch': 1.1.0
'@types/cookie': 0.4.1
'@types/jsonwebtoken': 8.5.7
'@types/lodash.debounce': 4.0.7
'@types/node': 17.0.45
'@types/node-fetch': 2.6.2
@ -3398,6 +3402,12 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
/@types/jsonwebtoken/8.5.7:
resolution: {integrity: sha512-CBHN+1unePowgS94ayLE7aVp7AfyhgG/3l2O+AjkhOMY4kAAfVI1OnbbLnOeDMAdTNLP5ZjJ3kdZanRtRQaK3Q==}
dependencies:
'@types/node': 18.7.18
dev: true
/@types/jsonwebtoken/8.5.9:
resolution: {integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==}
dependencies: