Merge branch 'kibocommerce_LogIn' into ICKY-169-LogIn

This commit is contained in:
SushantJadhav 2021-08-26 07:43:37 +05:30
commit a122d68a2c
13 changed files with 175 additions and 19 deletions

View File

@ -40,7 +40,7 @@ const UserNav: FC<Props> = ({ className }) => {
</Link>
</li>
)}
{process.env.COMMERCE_CUSTOMERAUTH_ENABLED && (
<li className={s.item}>
{customer ? (
<DropdownMenu />
@ -54,7 +54,7 @@ const UserNav: FC<Props> = ({ className }) => {
</button>
)}
</li>
)}
</ul>
</nav>
)

View File

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

View File

@ -0,0 +1,62 @@
import Cookies from 'js-cookie'
import { FetcherError } from '@commerce/utils/errors'
import type { LoginEndpoint } from '.'
import { loginMutation } from '../../mutations/login-mutation'
import {prepareSetCookie} from '../../../lib/prepareSetCookie';
import {setCookies} from '../../../lib/setCookie'
const invalidCredentials = /invalid credentials/i
let response;
const login: LoginEndpoint['handlers']['login'] = async ({
req,
res,
body: { email, password },
config,
commerce,
}) => {
if (!(email && password)) {
return res.status(400).json({
data: null,
errors: [{ message: 'Invalid request' }],
})
}
try {
response = await config.fetch(loginMutation, { variables: { loginInput : { username: email, password }}})
const { account: token } = response.data;
const authCookie = prepareSetCookie(
config.customerCookie,
JSON.stringify(token),
token.accessTokenExpiration ? { expires: new Date(token.accessTokenExpiration) }: {},
)
setCookies(res, [authCookie])
} 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
}
res.status(200).json({ data: response })
}
export default login

View File

@ -1,6 +1,6 @@
import type { CommerceAPI, CommerceAPIConfig } from '@commerce/api'
import { getCommerceApi as commerceApi } from '@commerce/api'
import createFetcher from './utils/fetch-local'
import fetchGraphqlApi from './utils/fetch-local'
import getAllPages from './operations/get-all-pages'
import getPage from './operations/get-page'
@ -12,12 +12,12 @@ import getProduct from './operations/get-product'
export interface KiboCommerceConfig extends CommerceAPIConfig {}
const config: KiboCommerceConfig = {
commerceUrl: process.env.KIBO_API_URL || '',
apiToken: process.env.KIBO_API_TOKEN || '',
cartCookie: process.env.KIBO_CART_COOKIE || '',
customerCookie: process.env.KIBO_CUSTOMER_COOKIE || '',
commerceUrl: process.env.KIBO_API_URL || 'https://t17194-s21127.dev10.kubedev.kibo-dev.com/graphql',
apiToken: process.env.KIBO_API_TOKEN || `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL3d3dy5raWJvY29tbWVyY2UuY29tL2FwcF9jbGFpbXMiOnsic3NsIjoiMCIsImVudCI6IjEiLCJtdHIiOiIxIiwidWMiOiIwIiwicm5kIjoxNDQ1NjE5MDQ0LCJhaWQiOiJraWJvLWRldmVsb3Blci1rZXkiLCJha2V5Ijoia2liby1kZXZlbG9wZXIta2V5IiwiYnYiOlswLC0xNTc3NzkyMiwxLDIwNzkwNjQwNjMsMiwyMTQ3NDgzNTgyLDMsLTk3LDQsODE5MSw1LC0xNzE1Myw2LC0xMzQyMTc3MjksNywtMSw4LDQxOTQzMDMsMzEsODM4ODM1Ml0sImV4cCI6IjIwMjYtMDQtMjlUMTg6NDA6MDQiLCJlbnYiOiJkZXYxMCJ9LCJuYmYiOjE2MTk3MjE2MDUsImV4cCI6MTc3NzQ4ODAwNCwiaWF0IjoxNjE5NzIxNjA1LCJpc3MiOiJodHRwczovL3d3dy5raWJvY29tbWVyY2UuY29tIiwiYXVkIjoiaHR0cHM6Ly93d3cua2lib2NvbW1lcmNlLmNvbSJ9.xn2i0-1bmH65x_z51UQVRDY8fwn4NXnnD5JtIhcrUkw`,
cartCookie: process.env.KIBO_CART_COOKIE || 'kibo_car',
customerCookie: process.env.KIBO_CUSTOMER_COOKIE || 'kibo_customer',
cartCookieMaxAge: 2592000,
fetch: createFetcher(() => getCommerceApi().getConfig()),
fetch: fetchGraphqlApi(() => getCommerceApi().getConfig()),
}
const operations = {

View File

@ -0,0 +1,20 @@
export const loginMutation = `
mutation login($loginInput:CustomerUserAuthInfoInput!) {
account:createCustomerAuthTicket(customerUserAuthInfoInput:$loginInput) {
accessToken
userId
refreshToken
refreshTokenExpiration
accessTokenExpiration
customerAccount {
id
firstName
lastName
emailAddress
userName
}
}
}
`

View File

@ -8,9 +8,11 @@ const fetchGraphqlApi: (getConfig: () => KiboCommerceConfig) => GraphQLFetcher =
async (query: string, { variables, preview } = {}, fetchOptions) => {
const config = getConfig()
const res = await fetch(config.commerceUrl, {
//const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), {
...fetchOptions,
method: 'POST',
headers: {
Authorization: `Bearer ${config.apiToken}`,
...fetchOptions?.headers,
'Content-Type': 'application/json',
},
@ -23,7 +25,7 @@ const fetchGraphqlApi: (getConfig: () => KiboCommerceConfig) => GraphQLFetcher =
const json = await res.json()
if (json.errors) {
throw new FetcherError({
errors: json.errors ?? [{ message: 'Failed to fetch for API' }],
errors: json.errors ?? [{ message: 'Failed to fetch KiboCommerce API' }],
status: res.status,
})
}

View File

@ -1,16 +1,40 @@
import { MutationHook } from '@commerce/utils/types'
import useLogin, { UseLogin } from '@commerce/auth/use-login'
import { useCallback } from 'react'
import { CommerceError } from '@commerce/utils/errors'
import type { LoginHook } from '../types/login'
import useCustomer from '../customer/use-customer'
export default useLogin as UseLogin<typeof handler>
export const handler: MutationHook<any> = {
export const handler: MutationHook<LoginHook> = {
fetchOptions: {
query: '',
url: '/api/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 { revalidate } = useCustomer()
return useCallback(
async function login(input) {
const data = await fetch({ input })
// await revalidate()
return data
},
[fetch, revalidate]
)
},
}

View File

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

View File

@ -0,0 +1,13 @@
export function prepareSetCookie(name: string, value: string, options: any = {}): string {
const cookieValue = [`${name}=${value}`];
if (options.maxAge) {
cookieValue.push(`Max-Age=${options.maxAge}`);
}
if (options.expires && !options.maxAge) {
cookieValue.push(`Expires=${options.expires.toUTCString()}`);
}
return cookieValue.join('; ');
}

View File

@ -0,0 +1,3 @@
export function setCookies(res: any, cookies: string[]): void {
res.setHeader('Set-Cookie', cookies);
}

View File

@ -11397,3 +11397,8 @@ export type WorkflowStateInput = {
shipmentState?: Maybe<Scalars['String']>
taskList?: Maybe<Array<Maybe<FulfillmentTaskInput>>>
}
export type LoginMutationVariables = Exact<{
email: Scalars['String']
password: Scalars['String']
}>

View File

@ -0,0 +1,8 @@
import * as Core from '@commerce/types/login'
import type { LoginMutationVariables } from '../schema'
export * from '@commerce/types/login'
export type LoginOperation = Core.LoginOperation & {
variables: LoginMutationVariables
}

View File

@ -1,4 +1,4 @@
import loginApi from '@framework/api/endpoints/login'
import { loginApi } from '@framework/api/endpoints/login'
import commerce from '@lib/api/commerce'
export default loginApi(commerce)