mirror of
https://github.com/vercel/commerce.git
synced 2025-05-17 15:06:59 +00:00
Ordercloud signup hook/endpoint and stubbing out other ordercloud auth endpoints
This commit is contained in:
parent
e66cd12f4c
commit
233070869d
@ -48,8 +48,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/commerce": "workspace:*",
|
"@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": {
|
"peerDependencies": {
|
||||||
"next": "^13",
|
"next": "^13",
|
||||||
@ -60,11 +61,12 @@
|
|||||||
"@taskr/clear": "^1.1.0",
|
"@taskr/clear": "^1.1.0",
|
||||||
"@taskr/esnext": "^1.1.0",
|
"@taskr/esnext": "^1.1.0",
|
||||||
"@taskr/watch": "^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/lodash.debounce": "^4.0.6",
|
||||||
"@types/node": "^17.0.8",
|
"@types/node": "^17.0.8",
|
||||||
"@types/react": "^18.0.14",
|
|
||||||
"@types/cookie": "^0.4.1",
|
|
||||||
"@types/node-fetch": "^2.6.2",
|
"@types/node-fetch": "^2.6.2",
|
||||||
|
"@types/react": "^18.0.14",
|
||||||
"lint-staged": "^12.1.7",
|
"lint-staged": "^12.1.7",
|
||||||
"next": "^13.0.6",
|
"next": "^13.0.6",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
|
@ -7,6 +7,7 @@ import checkout from './checkout'
|
|||||||
import products from './catalog/products'
|
import products from './catalog/products'
|
||||||
import customerCard from './customer/card'
|
import customerCard from './customer/card'
|
||||||
import customerAddress from './customer/address'
|
import customerAddress from './customer/address'
|
||||||
|
import signup from './signup';
|
||||||
|
|
||||||
const endpoints = {
|
const endpoints = {
|
||||||
cart,
|
cart,
|
||||||
@ -14,6 +15,7 @@ const endpoints = {
|
|||||||
'customer/card': customerCard,
|
'customer/card': customerCard,
|
||||||
'customer/address': customerAddress,
|
'customer/address': customerAddress,
|
||||||
'catalog/products': products,
|
'catalog/products': products,
|
||||||
|
'signup': signup
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ordercloudAPI(commerce: OrdercloudAPI) {
|
export default function ordercloudAPI(commerce: OrdercloudAPI) {
|
||||||
|
18
packages/ordercloud/src/api/endpoints/signup/index.ts
Normal file
18
packages/ordercloud/src/api/endpoints/signup/index.ts
Normal 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
|
58
packages/ordercloud/src/api/endpoints/signup/signup.ts
Normal file
58
packages/ordercloud/src/api/endpoints/signup/signup.ts
Normal 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
|
@ -57,21 +57,23 @@ export async function fetchData<T>(opts: {
|
|||||||
// Destructure opts
|
// Destructure opts
|
||||||
const { path, body, fetchOptions, config, token, method = 'GET' } = 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
|
// Do the request with the correct headers
|
||||||
const dataResponse = await fetch(
|
const dataResponse = await fetch(url, {
|
||||||
`${config.commerceUrl}/${config.apiVersion}${path}`,
|
...fetchOptions,
|
||||||
{
|
method,
|
||||||
...fetchOptions,
|
headers: {
|
||||||
method,
|
...fetchOptions?.headers,
|
||||||
headers: {
|
'Content-Type': 'application/json',
|
||||||
...fetchOptions?.headers,
|
accept: 'application/json, text/plain, */*',
|
||||||
'Content-Type': 'application/json',
|
authorization: `Bearer ${token}`,
|
||||||
accept: 'application/json, text/plain, */*',
|
},
|
||||||
authorization: `Bearer ${token}`,
|
body: body ? JSON.stringify(body) : undefined,
|
||||||
},
|
})
|
||||||
body: body ? JSON.stringify(body) : undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// If something failed getting the data response
|
// If something failed getting the data response
|
||||||
if (!dataResponse.ok) {
|
if (!dataResponse.ok) {
|
||||||
|
@ -1,16 +1,43 @@
|
|||||||
import { MutationHook } from '@vercel/commerce/utils/types'
|
import type { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
import useLogin, { UseLogin } from '@vercel/commerce/auth/use-login'
|
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 default useLogin as UseLogin<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler: MutationHook<LoginHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
url: '/api/commerce/login',
|
||||||
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher() {
|
async fetcher({ input: { email, password }, options, fetch }) {
|
||||||
return null
|
if (!(email && password)) {
|
||||||
},
|
throw new CommerceError({
|
||||||
useHook: () => () => {
|
message: 'An email and password are required to login',
|
||||||
return async function () {}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch({
|
||||||
|
...options,
|
||||||
|
body: { email, password },
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
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]
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -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 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 default useLogout as UseLogout<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler: MutationHook<LogoutHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
url: '/api/commerce/logout',
|
||||||
},
|
method: 'GET',
|
||||||
async fetcher() {
|
|
||||||
return null
|
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
({ fetch }) =>
|
({ 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]
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,46 @@
|
|||||||
import { useCallback } from 'react'
|
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 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 default useSignup as UseSignup<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler: MutationHook<SignupHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
url: '/api/commerce/signup',
|
||||||
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher() {
|
async fetcher({
|
||||||
return null
|
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:
|
useHook:
|
||||||
({ fetch }) =>
|
({ 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]
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"wishlist": false,
|
"wishlist": false,
|
||||||
"cart": true,
|
"cart": true,
|
||||||
"search": true,
|
"search": true,
|
||||||
"customerAuth": false,
|
"customerAuth": true,
|
||||||
"customCheckout": true
|
"customCheckout": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@ -263,12 +263,14 @@ importers:
|
|||||||
'@taskr/esnext': ^1.1.0
|
'@taskr/esnext': ^1.1.0
|
||||||
'@taskr/watch': ^1.1.0
|
'@taskr/watch': ^1.1.0
|
||||||
'@types/cookie': ^0.4.1
|
'@types/cookie': ^0.4.1
|
||||||
|
'@types/jsonwebtoken': 8.5.7
|
||||||
'@types/lodash.debounce': ^4.0.6
|
'@types/lodash.debounce': ^4.0.6
|
||||||
'@types/node': ^17.0.8
|
'@types/node': ^17.0.8
|
||||||
'@types/node-fetch': ^2.6.2
|
'@types/node-fetch': ^2.6.2
|
||||||
'@types/react': ^18.0.14
|
'@types/react': ^18.0.14
|
||||||
'@vercel/commerce': workspace:*
|
'@vercel/commerce': workspace:*
|
||||||
cookie: ^0.4.1
|
cookie: ^0.4.1
|
||||||
|
jsonwebtoken: 8.5.1
|
||||||
lint-staged: ^12.1.7
|
lint-staged: ^12.1.7
|
||||||
lodash.debounce: ^4.0.8
|
lodash.debounce: ^4.0.8
|
||||||
next: ^13.0.6
|
next: ^13.0.6
|
||||||
@ -281,12 +283,14 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@vercel/commerce': link:../commerce
|
'@vercel/commerce': link:../commerce
|
||||||
cookie: 0.4.2
|
cookie: 0.4.2
|
||||||
|
jsonwebtoken: 8.5.1
|
||||||
lodash.debounce: 4.0.8
|
lodash.debounce: 4.0.8
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@taskr/clear': 1.1.0
|
'@taskr/clear': 1.1.0
|
||||||
'@taskr/esnext': 1.1.0
|
'@taskr/esnext': 1.1.0
|
||||||
'@taskr/watch': 1.1.0
|
'@taskr/watch': 1.1.0
|
||||||
'@types/cookie': 0.4.1
|
'@types/cookie': 0.4.1
|
||||||
|
'@types/jsonwebtoken': 8.5.7
|
||||||
'@types/lodash.debounce': 4.0.7
|
'@types/lodash.debounce': 4.0.7
|
||||||
'@types/node': 17.0.45
|
'@types/node': 17.0.45
|
||||||
'@types/node-fetch': 2.6.2
|
'@types/node-fetch': 2.6.2
|
||||||
@ -3398,6 +3402,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
dev: true
|
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:
|
/@types/jsonwebtoken/8.5.9:
|
||||||
resolution: {integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==}
|
resolution: {integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user