Revert "very incomplete progress on sign-in"

This reverts commit a8dd2af268.
This commit is contained in:
Oliver Heywood
2021-10-13 09:05:21 -05:00
parent a8dd2af268
commit bcaa3844ba
19 changed files with 48 additions and 360 deletions

View File

@@ -1,3 +1,4 @@
import { FetcherError } from '@commerce/utils/errors'
import type { LoginEndpoint } from '.' import type { LoginEndpoint } from '.'
const invalidCredentials = /invalid credentials/i const invalidCredentials = /invalid credentials/i
@@ -22,6 +23,11 @@ const login: LoginEndpoint['handlers']['login'] = async ({
try { try {
await commerce.login({ variables: { email, password }, config, res }) await commerce.login({ variables: { email, password }, config, res })
} catch (error) { } catch (error) {
// Check if the email and password didn't match an existing account
if (
error instanceof FetcherError &&
invalidCredentials.test(error.message)
) {
return res.status(401).json({ return res.status(401).json({
data: null, data: null,
errors: [ errors: [
@@ -33,6 +39,8 @@ const login: LoginEndpoint['handlers']['login'] = async ({
], ],
}) })
} }
throw error
} }
res.status(200).json({ data: null }) res.status(200).json({ data: null })

View File

@@ -1,35 +0,0 @@
import { CustomerEndpoint } from "."
const getLoggedInCustomer: CustomerEndpoint['handlers']['getLoggedInCustomer'] = async ({
req,
res,
config,
}) => {
const token = req.cookies[config.customerCookie]
// if (token) {
// const { data } = await config.fetch<GetLoggedInCustomerQuery>(
// getLoggedInCustomerQuery,
// undefined,
// {
// headers: {
// cookie: `${config.customerCookie}=${token}`,
// },
// }
// )
// const { customer } = data
// if (!customer) {
// return res.status(400).json({
// data: null,
// errors: [{ message: 'Customer not found', code: 'not_found' }],
// })
// }
// return res.status(200).json({ data: { customer } })
// }
res.status(200).json({ data: null })
}
export default getLoggedInCustomer

View File

@@ -1,19 +1 @@
import { GetAPISchema, createEndpoint } from '@commerce/api' export default function noopApi(...args: any[]): void {}
import customerEndpoint from '@commerce/api/endpoints/customer'
import { CustomerSchema } from '@commerce/types/customer'
import { OrdercloudAPI } from '@framework/api'
import getLoggedInCustomer from './get-logged-in-customer';
export type CustomerAPI = GetAPISchema<OrdercloudAPI, CustomerSchema>
export type CustomerEndpoint = CustomerAPI['endpoint']
export const handlers: CustomerEndpoint['handlers'] = { getLoggedInCustomer }
const customerApi = createEndpoint<CustomerAPI>({
handler: customerEndpoint,
handlers,
})
export default customerApi

View File

@@ -1,18 +1 @@
import { createEndpoint, GetAPISchema } from "@commerce/api" export default function noopApi(...args: any[]): void {}
import loginEndpoint from "@commerce/api/endpoints/login"
import { LoginSchema } from "@commerce/types/login"
import { OrdercloudAPI } from "@framework/api"
import login from "./login"
export type LoginAPI = GetAPISchema<OrdercloudAPI, LoginSchema>
export type LoginEndpoint = LoginAPI['endpoint']
export const handlers: LoginEndpoint['handlers'] = { login }
const loginApi = createEndpoint<LoginAPI>({
handler: loginEndpoint,
handlers,
})
export default loginApi

View File

@@ -1,57 +0,0 @@
import { FetcherError } from '@commerce/utils/errors'
import { passwordLogin } from '@framework/api/utils/fetch-rest'
import { provider } from 'framework/local/api'
import type { LoginEndpoint } from '.'
const invalidCredentials = /invalid credentials/i
const login: LoginEndpoint['handlers']['login'] = async ({
req,
res,
body: { email, password },
config: { commerceUrl },
}) => {
console.log(email, password)
// TODO: Add proper validations with something like Ajv
if (!(email && password)) {
return res.status(400).json({
data: null,
errors: [{ message: 'Invalid request' }],
})
}
// Get token from cookies
let response: any;
try {
response = await passwordLogin(email, password, commerceUrl);
} catch (error) {
// Check if the email and password didn't match an existing account
if (
error instanceof FetcherError &&
invalidCredentials.test(error.message)
) {
return res.status(401).json({
data: null,
errors: [
{
message:
'Cannot find an account that matches the provided credentials',
code: 'invalid_credentials',
},
],
})
}
throw error
}
console.log(response)
// set buyer token
global.token = response.access_token;
res.status(200).json({ data: null })
}
export default login

View File

@@ -1,18 +1 @@
import { GetAPISchema, createEndpoint } from '@commerce/api' export default function noopApi(...args: any[]): void {}
import logoutEndpoint from '@commerce/api/endpoints/logout'
import { LogoutSchema } from '@commerce/types/logout'
import { OrdercloudAPI } from '@framework/api'
import logout from './logout'
export type LogoutAPI = GetAPISchema<OrdercloudAPI, LogoutSchema>
export type LogoutEndpoint = LogoutAPI['endpoint']
export const handlers: LogoutEndpoint['handlers'] = { logout }
const logoutApi = createEndpoint<LogoutAPI>({
handler: logoutEndpoint,
handlers,
})
export default logoutApi

View File

@@ -1,20 +0,0 @@
import { LogoutEndpoint } from "."
const logout: LogoutEndpoint['handlers']['logout'] = async ({
res,
body: { redirectTo },
config,
}) => {
// Remove the buyer token
global.token = null;
// Only allow redirects to a relative URL
if (redirectTo?.startsWith('/')) {
res.redirect(redirectTo)
} else {
res.status(200).json({ data: null })
}
}
export default logout

View File

@@ -0,0 +1 @@
export default function noopApi(...args: any[]): void {}

View File

@@ -1,79 +0,0 @@
import { createEndpoint, GetAPISchema } from '@commerce/api';
import signupEndpoint from '@commerce/api/endpoints/signup';
import { SignupSchema } from '@commerce/types/signup';
import { OrdercloudAPI } from '@framework/api';
import { passwordLogin } from '@framework/api/utils/fetch-rest';
const signup: SignupEndpoint['handlers']['signup'] = async ({
req,
res,
body: { firstName, lastName, email, password },
config: { restBuyerFetch, commerceUrl, tokenCookie },
}) => {
// TODO: Add proper validations with something like Ajv
if (!(firstName && lastName && email && password)) {
return res.status(400).json({
data: null,
errors: [{ message: 'Invalid request' }],
})
}
// TODO: validate the password and email
// Passwords must be at least 7 characters and contain both alphabetic
// and numeric characters.
// Get token from cookies
const token = req.cookies[tokenCookie];
const newUser = {
Active: true,
Username: email,
Password: password,
FirstName: firstName,
LastName: lastName,
Email: email
}
// create user record
try {
await restBuyerFetch(
'PUT',
`/me/register?anonUserToken=${token}`,
newUser,
{ token }
);
} catch (error) {
var message = (error as any).errors[0].message
//const ordercloud_error = JSON.parse();
console.log(message)
return res.status(400).json({
data: null,
errors: [
{
message: message,
code: message
},
],
})
}
// Login the customer right after creating it
await passwordLogin(email, password, commerceUrl);
res.status(200).json({ data: null })
}
export type SignupAPI = GetAPISchema<OrdercloudAPI, SignupSchema>
export type SignupEndpoint = SignupAPI['endpoint']
export const handlers: SignupEndpoint['handlers'] = { signup }
const signupApi = createEndpoint<SignupAPI>({
handler: signupEndpoint,
handlers,
})
export default signupApi

View File

@@ -6,7 +6,6 @@ import { OrdercloudConfig } from '../index'
// Get an instance to vercel fetch // Get an instance to vercel fetch
const fetch = vercelFetch() const fetch = vercelFetch()
// Get token util // Get token util
async function getToken({ async function getToken({
baseUrl, baseUrl,
@@ -93,17 +92,6 @@ export async function fetchData<T>(opts: {
} }
} }
export async function passwordLogin(email: string, password: string, commerceUrl: string) {
return await fetch(`${commerceUrl}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
},
body: `username=${email}&password=${password}&grant_type=password`,
})
}
export const createMiddlewareFetcher: ( export const createMiddlewareFetcher: (
getConfig: () => OrdercloudConfig getConfig: () => OrdercloudConfig
) => <T>( ) => <T>(
@@ -141,7 +129,7 @@ export const createMiddlewareFetcher: (
} }
export const createBuyerFetcher: ( export const createBuyerFetcher: (
getConfig: () => OrdercloudConfig, getConfig: () => OrdercloudConfig
) => <T>( ) => <T>(
method: string, method: string,
path: string, path: string,

View File

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

View File

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

View File

@@ -2,43 +2,18 @@ import { useCallback } from 'react'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
import { MutationHook } from '@commerce/utils/types' import { MutationHook } from '@commerce/utils/types'
import useSignup, { UseSignup } from '@commerce/auth/use-signup' import useSignup, { UseSignup } from '@commerce/auth/use-signup'
import { CommerceError } from '@commerce/utils/errors'
import { SignupHook } from '@commerce/types/signup'
export default useSignup as UseSignup<typeof handler> export default useSignup as UseSignup<typeof handler>
export const handler: MutationHook<SignupHook> = { export const handler: MutationHook<any> = {
fetchOptions: { fetchOptions: {
url: '/api/signup', query: '',
method: 'POST',
}, },
async fetcher({ async fetcher() {
input: { firstName, lastName, email, password }, return null
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 { revalidate } = useCustomer()
return useCallback(
async function signup(input) {
const data = await fetch({ input })
await revalidate()
return data
},
[fetch, revalidate]
)
}, },
useHook:
({ fetch }) =>
() =>
() => {},
} }

View File

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

View File

@@ -1,23 +1,15 @@
import { SWRHook } from '@commerce/utils/types' import { SWRHook } from '@commerce/utils/types'
import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' import useCustomer, { UseCustomer } from '@commerce/customer/use-customer'
import { CustomerHook } from '@commerce/types/customer'
export default useCustomer as UseCustomer<typeof handler> export default useCustomer as UseCustomer<typeof handler>
export const handler: SWRHook<CustomerHook> = { export const handler: SWRHook<any> = {
fetchOptions: { fetchOptions: {
url: '/api/customer', query: '',
method: 'GET',
}, },
async fetcher({ options, fetch }) { async fetcher({ input, options, fetch }) {},
const data = await fetch(options) useHook: () => () => {
return data?.customer ?? null return async function addItem() {
}, return {}
useHook: ({ useData }) => (input) => { }
return useData({
swrOptions: {
revalidateOnFocus: false,
...input?.swrOptions,
},
})
}, },
} }

View File

@@ -2,7 +2,7 @@
"name": "nextjs-commerce", "name": "nextjs-commerce",
"version": "1.0.0", "version": "1.0.0",
"scripts": { "scripts": {
"dev": "next dev", "dev": "NODE_OPTIONS='--inspect' next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"analyze": "BUNDLE_ANALYZE=both yarn build", "analyze": "BUNDLE_ANALYZE=both yarn build",

View File

@@ -1,4 +1,4 @@
import logoutApi from '@framework/api/endpoints/logout/logout' import logoutApi from '@framework/api/endpoints/logout'
import commerce from '@lib/api/commerce' import commerce from '@lib/api/commerce'
export default logoutApi(commerce) export default logoutApi(commerce)

View File

@@ -1,4 +1,4 @@
import singupApi from '@framework/api/endpoints/signup/signup' import singupApi from '@framework/api/endpoints/signup'
import commerce from '@lib/api/commerce' import commerce from '@lib/api/commerce'
export default singupApi(commerce) export default singupApi(commerce)

View File

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