Skip to content

feat: my account release 2 #2786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2cc5f7c
feat: page structure (#2758)
artursantiago Apr 14, 2025
8aed92a
feat: my orders summary card (#2766)
artursantiago Apr 16, 2025
9f6279f
Feat/my orders ordered by card (#2783)
artursantiago Apr 16, 2025
4714508
feat: use ssr in my account routes (#2787)
eduardoformiga Apr 16, 2025
4df5379
feat: my account extension points sections (#2788)
eduardoformiga Apr 17, 2025
abc26e3
feat: order details query (#2800)
eduardoformiga Apr 22, 2025
a88ede7
feat: feature flag all my account pages (#2801)
eduardoformiga Apr 23, 2025
577de01
chore: updates schema (#2806)
eduardoformiga Apr 24, 2025
1079454
feat: order details delivery card and delivery options graphql (#2808)
eduardoformiga Apr 29, 2025
8fc346f
chore: temp enable my account fs flag (#2814)
eduardoformiga Apr 29, 2025
7995e8d
feat: my orders payment card (#2769)
artursantiago Apr 29, 2025
5707d31
feat: cancel order graphql (#2812)
eduardoformiga Apr 30, 2025
0db3140
chore: removes weird label from friendly name (#2818)
eduardoformiga Apr 30, 2025
2770221
fix: user order type for cancellation order (#2820)
eduardoformiga Apr 30, 2025
1788f05
feat: my account 404 error with page structure (#2822)
eduardoformiga May 5, 2025
a0d0e2f
feat: my account list orders graphql API (#2816)
eduardoformiga May 5, 2025
cfdb21a
feat: sfs 2424 delivery card accordion (#2821)
artursantiago May 7, 2025
b55994c
feat: list orders search/filters integration + temp front style (#2825)
eduardoformiga May 9, 2025
fc65ea5
feat: list orders + filters (front) (#2829)
eduardoformiga May 12, 2025
c490d5d
feat: selected tags and clear all (#2837)
eduardoformiga May 12, 2025
03b80ef
feat: list orders pagination (#2838)
eduardoformiga May 12, 2025
4d9cc2b
feat: sfs 2469 order actions component (#2833)
artursantiago May 13, 2025
bbcfa5d
feat: my account status mapping (#2841)
eduardoformiga May 13, 2025
e990383
feat: empty state to orders list on My Account (#2839)
icaroov May 15, 2025
28e8ea3
feat: order details status card (#2765)
artursantiago May 15, 2025
021de90
feat: canceled statuses order status (#2846)
artursantiago May 15, 2025
7b14aeb
feat: implement order status handling and utility functions (#2828)
icaroov May 16, 2025
ff401ee
feat: order not found (#2843)
Guilera May 19, 2025
16b04f2
feat: order details custom fields (#2850)
eduardoformiga May 19, 2025
c10339f
feat: my account org drawer API (#2848)
eduardoformiga May 19, 2025
b4ca713
feat: my account org drawer frontend (#2849)
eduardoformiga May 19, 2025
ac39b8f
Merge branch 'main' into feat/my-account-release-2
eduardoformiga May 19, 2025
f1a5f0a
feat: add 'productCount' query to the GraphQL schema
eduardoformiga May 19, 2025
d0a042b
test: add validation for GraphQL schema integrity
eduardoformiga May 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
816 changes: 816 additions & 0 deletions packages/api/src/__generated__/schema.ts

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion packages/api/src/platforms/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
type ErrorType = 'BadRequestError' | 'NotFoundError' | 'RedirectError'
type ErrorType =
| 'BadRequestError'
| 'NotFoundError'
| 'RedirectError'
| 'ForbiddenError'

interface Extension {
type: ErrorType
Expand Down Expand Up @@ -27,6 +31,12 @@ export class NotFoundError extends FastStoreError {
}
}

export class ForbiddenError extends FastStoreError {
constructor(message?: string) {
super({ status: 403, type: 'ForbiddenError' }, message)
}
}

export const isFastStoreError = (error: any): error is FastStoreError =>
error?.name === 'FastStoreError'

Expand All @@ -35,3 +45,6 @@ export const isNotFoundError = (error: any): error is NotFoundError =>

export const isBadRequestError = (error: any): error is BadRequestError =>
error?.extensions?.type === 'BadRequestError'

export const isForbiddenError = (error: any): error is ForbiddenError =>
error?.extensions?.type === 'ForbiddenError'
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface ContractResponse {
isCorporate: boolean
corporateName: string
firstName: string
lastName: string
userName: string
}
226 changes: 218 additions & 8 deletions packages/api/src/platforms/vtex/clients/commerce/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@ import { parse } from 'cookie'
import type { FACET_CROSS_SELLING_MAP } from '../../utils/facets'
import { fetchAPI } from '../fetch'

import type { StoreMarketingData } from '../../../..'
import type {
IUserOrderCancel,
QueryListUserOrdersArgs,
StoreMarketingData,
UserOrder,
UserOrderCancel,
UserOrderListResult,
} from '../../../..'
import type { Context, Options } from '../../index'
import type { Channel } from '../../utils/channel'
import { getStoreCookie, getWithCookie } from '../../utils/cookies'
import {
getStoreCookie,
getWithAutCookie,
getWithCookie,
} from '../../utils/cookies'
import type { ContractResponse } from './Contract'
import type { Address, AddressInput } from './types/Address'
import type { Brand } from './types/Brand'
import type { CategoryTree } from './types/CategoryTree'
Expand All @@ -22,6 +34,8 @@ import type {
SimulationArgs,
SimulationOptions,
} from './types/Simulation'
import type { ScopesByUnit, UnitResponse } from './types/Unit'
import type { VtexIdResponse } from './types/VtexId'

type ValueOf<T> = T extends Record<string, infer K> ? K : never

Expand All @@ -39,6 +53,7 @@ export const VtexCommerce = (
const base = `https://${account}.${environment}.com.br`
const storeCookies = getStoreCookie(ctx)
const withCookie = getWithCookie(ctx)
const withAutCookie = getWithAutCookie(ctx)

const host =
new Headers(ctx.headers).get('x-forwarded-host') ?? ctx.headers?.host ?? ''
Expand Down Expand Up @@ -351,6 +366,29 @@ export const VtexCommerce = (
{ storeCookies }
)
},
cancelOrder: ({
orderId,
customerEmail,
reason,
}: IUserOrderCancel): Promise<UserOrderCancel> | undefined => {
const headers: HeadersInit = withCookie({
'content-type': 'application/json',
'X-FORWARDED-HOST': forwardedHost,
})

return fetchAPI(
`${base}/api/checkout/pub/orders/${orderId}/user-cancel-request`,
{
method: 'POST',
headers,
body: JSON.stringify({
customerEmail,
reason,
}),
},
{}
)
},
},
session: (search: string): Promise<Session> => {
const params = new URLSearchParams(search)
Expand Down Expand Up @@ -392,19 +430,191 @@ export const VtexCommerce = (
},
profile: {
addresses: async (userId: string): Promise<Record<string, string>> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/profile-system/pvt/profiles/${userId}/addresses`,
{ headers },
{ storeCookies }
)
},
},
oms: {
userOrder: ({ orderId }: { orderId: string }): Promise<UserOrder> => {
const headers: HeadersInit = withCookie({
'content-type': 'application/json',
'X-FORWARDED-HOST': forwardedHost,
})

const cookies = parse(ctx?.headers?.cookie ?? '')
const VtexIdclientAutCookie =
cookies['VtexIdclientAutCookie_' + account]
headers['VtexIdclientAutCookie'] = VtexIdclientAutCookie
return fetchAPI(
`${base}/api/oms/user/orders/${orderId}`,
{
method: 'GET',
headers,
},
{ storeCookies }
)
},
listUserOrders: ({
page,
status,
dateInitial,
dateFinal,
text,
clientEmail,
perPage,
}: QueryListUserOrdersArgs): Promise<UserOrderListResult> => {
const params = new URLSearchParams()

if (dateInitial) {
const dateInitialTimestamp = new Date(dateInitial).setHours(
0,
0,
0,
0
)
dateInitial = new Date(dateInitialTimestamp).toISOString()
}
if (dateFinal) {
const dateFinalTimestamp = new Date(dateFinal).setHours(
23,
59,
59,
999
)
dateFinal = new Date(dateFinalTimestamp).toISOString()
}

if (text) params.append('text', text)
if (status && status.length > 0) {
status.forEach((s) =>
s && s.length > 0 ? params.append('status', s) : null
)
}

if (dateInitial && dateFinal) {
params.append(
'creation_date',
`creationDate:[${dateInitial} TO ${dateFinal}]`
)
} else if (dateInitial) {
params.append('creation_date', `creationDate:[${dateInitial} TO *]`)
} else if (dateFinal) {
params.append('creation_date', `creationDate:[* TO ${dateFinal}]`)
}

if (clientEmail) params.append('clientEmail', clientEmail)
if (page) params.append('page', page.toString())
if (perPage) params.append('per_page', perPage.toString())

const headers: HeadersInit = withCookie({
'content-type': 'application/json',
'X-FORWARDED-HOST': forwardedHost,
})

return fetchAPI(
`${base}/api/profile-system/pvt/profiles/${userId}/addresses`,
{ headers },
`${base}/api/oms/user/orders?${params.toString()}`,
{
method: 'GET',
headers,
},
{ storeCookies }
)
},
},
units: {
getUnitByUserId: ({
userId,
}: { userId: string }): Promise<UnitResponse> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/units/v1/${userId}/unit`,
{
method: 'GET',
headers,
},
{}
)
},
getOrgUnitById: ({
orgUnitId,
}: { orgUnitId: string }): Promise<UnitResponse> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/units/v1/${orgUnitId}`,
{
method: 'GET',
headers,
},
{}
)
},
getScopesByOrgUnit: ({
orgUnitId,
}: { orgUnitId: string }): Promise<ScopesByUnit> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/units/v1/${orgUnitId}/scopes`,
{
method: 'GET',
headers,
},
{}
)
},
},
licenseManager: {
getUserById: ({
userId,
}: { userId: string }): Promise<{
id: string
name: string
email: string
}> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/license-manager/users/${userId}`,
{
method: 'GET',
headers,
},
{}
)
},
},
masterData: {
getContractById: ({
contractId,
}: { contractId: string }): Promise<ContractResponse> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/dataentities/CL/documents/${contractId}?_fields=_all`,
{
method: 'GET',
headers,
},
{}
)
},
},
vtexid: {
validate: (): Promise<VtexIdResponse> => {
const headers: HeadersInit = withAutCookie(forwardedHost, account)

return fetchAPI(
`${base}/api/vtexid/credential/validate`,
{
headers,
body: JSON.stringify({
token: headers['VtexIdclientAutCookie'],
}),
method: 'POST',
},
{ storeCookies }
)
},
Expand Down
19 changes: 19 additions & 0 deletions packages/api/src/platforms/vtex/clients/commerce/types/Unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface UnitResponse {
createdAt: string
updatedAt: string
name: string
path: {
ids: string
names: string
}
id: string
customerGroup: string[]
}

export interface ScopesByUnit {
organizationUnitId: string
scopes: Array<{
scope: string
ids: string[]
}>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface VtexIdResponse {
authStatus: string
id: string
user: string
account: string
audience: string
tokenType: string
customerId: string
unitName: string
isRepresentative: boolean
}
4 changes: 4 additions & 0 deletions packages/api/src/platforms/vtex/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { StoreSearchResult } from './resolvers/searchResult'
import { StoreSeo } from './resolvers/seo'
import { ShippingSLA } from './resolvers/shippingSLA'
import { SkuVariants } from './resolvers/skuVariations'
import { UserOrder } from './resolvers/userOrder'
import type { Channel } from './utils/channel'
import ChannelMarshal from './utils/channel'

Expand Down Expand Up @@ -63,6 +64,7 @@ export interface Context {
cookies: Map<string, Record<string, string>>
}
headers: Record<string, string>
account: string
}

export type Resolver<R = unknown, A = unknown, Return = any> = (
Expand All @@ -89,6 +91,7 @@ const Resolvers = {
StorePropertyValue,
SkuVariants,
ShippingSLA,
UserOrder,
ObjectOrString,
Query,
Mutation,
Expand All @@ -105,6 +108,7 @@ export const getContextFactory =
}
ctx.clients = getClients(options, ctx)
ctx.loaders = getLoaders(options, ctx)
ctx.account = options.account

return ctx
}
Expand Down
20 changes: 20 additions & 0 deletions packages/api/src/platforms/vtex/resolvers/cancelOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Context } from '..'
import type {
MutationCancelOrderArgs,
UserOrderCancel,
} from '../../../__generated__/schema'
import { BadRequestError } from '../../errors'

export const cancelOrder = async (
_: any,
{ data }: MutationCancelOrderArgs,
{ clients: { commerce } }: Context
): Promise<UserOrderCancel | null> => {
if (!data?.orderId) {
throw new BadRequestError('Missing orderId')
}

const response = await commerce.checkout.cancelOrder(data)

return { data: response?.data }
}
Loading
Loading