diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b7384362d..aa1d2bb32 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -51,4 +51,4 @@ jobs: - name: Benchmark continue-on-error: true - run: deno bench --lock=deno.lock --lock-write -A . \ No newline at end of file + run: deno bench --lock=deno.lock --lock-write -A . diff --git a/.github/workflows/issues.yaml b/.github/workflows/issues.yaml index 9504b5705..d5f99f015 100644 --- a/.github/workflows/issues.yaml +++ b/.github/workflows/issues.yaml @@ -15,4 +15,4 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.issue.number }} - LABELS: triage \ No newline at end of file + LABELS: triage diff --git a/.github/workflows/releaser.yaml b/.github/workflows/releaser.yaml index 5584f177e..f4fb8d2a0 100644 --- a/.github/workflows/releaser.yaml +++ b/.github/workflows/releaser.yaml @@ -9,9 +9,9 @@ on: - main permissions: - contents: write # Necessary for accessing and modifying repository content - pull-requests: write # Necessary for interacting with pull requests - actions: write # Necessary for triggering other workflows + contents: write # Necessary for accessing and modifying repository content + pull-requests: write # Necessary for interacting with pull requests + actions: write # Necessary for triggering other workflows jobs: tag-discussion: @@ -21,9 +21,9 @@ jobs: - name: Checkout Code uses: actions/checkout@v3 with: - ref: ${{ github.event.pull_request.base.ref }} # Checkout the base branch (target repository) - repository: ${{ github.event.pull_request.base.repo.full_name }} # Checkout from the target repo - + ref: ${{ github.event.pull_request.base.ref }} # Checkout the base branch (target repository) + repository: ${{ github.event.pull_request.base.repo.full_name }} # Checkout from the target repo + - name: Calculate new versions id: calculate_versions run: | @@ -162,11 +162,11 @@ jobs: run: | git tag ${{ steps.determine_version.outputs.new_version }} git push origin ${{ steps.determine_version.outputs.new_version }} - + - name: Trigger Release Workflow run: | curl -X POST \ -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ -H "Accept: application/vnd.github.everest-preview+json" \ https://api.github.com/repos/${{ github.repository }}/actions/workflows/release.yaml/dispatches \ - -d '{"ref":"main", "inputs":{"tag_name":"${{ steps.determine_version.outputs.new_version }}"}}' \ No newline at end of file + -d '{"ref":"main", "inputs":{"tag_name":"${{ steps.determine_version.outputs.new_version }}"}}' diff --git a/a.ts b/a.ts new file mode 100644 index 000000000..3a92f9de4 --- /dev/null +++ b/a.ts @@ -0,0 +1,25 @@ +import "npm:@graphql-codegen/typescript"; +import "npm:@graphql-codegen/typescript-operations"; + +import { type CodegenConfig, generate } from "npm:@graphql-codegen/cli"; + +const config: CodegenConfig = { + schema: "https://storefront-api.fbits.net/graphql", + documents: "./wake/utils/graphql/queries.ts", + generates: { + "./wake/utils/graphql/storefront.graphql.gen.ts": { + // This order matters + plugins: [ + "typescript", + "typescript-operations", + ], + config: { + skipTypename: true, + enumsAsTypes: true, + }, + }, + }, +}; + +await import("deco/scripts/apps/bundle.ts"); +await generate({ ...config }, true); diff --git a/checkout/manifest.gen.ts b/checkout/manifest.gen.ts new file mode 100644 index 000000000..0315f088f --- /dev/null +++ b/checkout/manifest.gen.ts @@ -0,0 +1,12 @@ +// DO NOT EDIT. This file is generated by deco. +// This file SHOULD be checked into source version control. +// This file is automatically updated during development when running `dev.ts`. + +const manifest = { + "name": "checkout", + "baseUrl": import.meta.url, +}; + +export type Manifest = typeof manifest; + +export default manifest; diff --git a/deco.ts b/deco.ts index 48947b7b6..369574035 100644 --- a/deco.ts +++ b/deco.ts @@ -14,6 +14,7 @@ const config = { app("decopilot-app"), app("smarthint"), app("ra-trustvox"), + app("checkout"), app("anthropic"), app("resend"), app("emailjs"), diff --git a/shopify/utils/storefront/storefront.graphql.gen.ts b/shopify/utils/storefront/storefront.graphql.gen.ts index 286430b30..f4038d73e 100644 --- a/shopify/utils/storefront/storefront.graphql.gen.ts +++ b/shopify/utils/storefront/storefront.graphql.gen.ts @@ -7704,6 +7704,8 @@ export type FilterFragment = { id: string, label: string, type: FilterType, valu export type CartFragment = { id: string, checkoutUrl: any, totalQuantity: number, lines: { nodes: Array<{ id: string, quantity: number, merchandise: { id: string, title: string, image?: { url: any, altText?: string | null } | null, product: { title: string }, price: { amount: any, currencyCode: CurrencyCode } }, cost: { totalAmount: { amount: any, currencyCode: CurrencyCode }, subtotalAmount: { amount: any, currencyCode: CurrencyCode }, amountPerQuantity: { amount: any, currencyCode: CurrencyCode }, compareAtAmountPerQuantity?: { amount: any, currencyCode: CurrencyCode } | null } } | { id: string, quantity: number, merchandise: { id: string, title: string, image?: { url: any, altText?: string | null } | null, product: { title: string }, price: { amount: any, currencyCode: CurrencyCode } }, cost: { totalAmount: { amount: any, currencyCode: CurrencyCode }, subtotalAmount: { amount: any, currencyCode: CurrencyCode }, amountPerQuantity: { amount: any, currencyCode: CurrencyCode }, compareAtAmountPerQuantity?: { amount: any, currencyCode: CurrencyCode } | null } }> }, cost: { subtotalAmount: { amount: any, currencyCode: CurrencyCode }, totalAmount: { amount: any, currencyCode: CurrencyCode }, checkoutChargeAmount: { amount: any, currencyCode: CurrencyCode } }, discountCodes: Array<{ code: string, applicable: boolean }>, discountAllocations: Array<{ discountedAmount: { amount: any, currencyCode: CurrencyCode } } | { discountedAmount: { amount: any, currencyCode: CurrencyCode } } | { discountedAmount: { amount: any, currencyCode: CurrencyCode } }> }; +export type CustomerFragment = { id: string, email?: string | null, firstName?: string | null, lastName?: string | null }; + export type CreateCartMutationVariables = Exact<{ [key: string]: never; }>; @@ -7767,6 +7769,13 @@ export type ProductRecommendationsQueryVariables = Exact<{ export type ProductRecommendationsQuery = { productRecommendations?: Array<{ availableForSale: boolean, createdAt: any, description: string, descriptionHtml: any, handle: string, id: string, isGiftCard: boolean, onlineStoreUrl?: any | null, productType: string, publishedAt: any, requiresSellingPlan: boolean, tags: Array, title: string, totalInventory?: number | null, updatedAt: any, vendor: string, featuredImage?: { altText?: string | null, url: any } | null, images: { nodes: Array<{ altText?: string | null, url: any }> }, media: { nodes: Array<{ alt?: string | null, mediaContentType: MediaContentType, previewImage?: { altText?: string | null, url: any } | null } | { alt?: string | null, mediaContentType: MediaContentType, previewImage?: { altText?: string | null, url: any } | null } | { alt?: string | null, mediaContentType: MediaContentType, previewImage?: { altText?: string | null, url: any } | null } | { alt?: string | null, mediaContentType: MediaContentType, previewImage?: { altText?: string | null, url: any } | null }> }, options: Array<{ name: string, values: Array }>, priceRange: { minVariantPrice: { amount: any, currencyCode: CurrencyCode }, maxVariantPrice: { amount: any, currencyCode: CurrencyCode } }, seo: { title?: string | null, description?: string | null }, variants: { nodes: Array<{ availableForSale: boolean, barcode?: string | null, currentlyNotInStock: boolean, id: string, quantityAvailable?: number | null, requiresShipping: boolean, sku?: string | null, title: string, weight?: number | null, weightUnit: WeightUnit, compareAtPrice?: { amount: any, currencyCode: CurrencyCode } | null, image?: { altText?: string | null, url: any } | null, price: { amount: any, currencyCode: CurrencyCode }, selectedOptions: Array<{ name: string, value: string }>, unitPrice?: { amount: any, currencyCode: CurrencyCode } | null, unitPriceMeasurement?: { measuredType?: UnitPriceMeasurementMeasuredType | null, quantityValue: number, referenceUnit?: UnitPriceMeasurementMeasuredUnit | null, quantityUnit?: UnitPriceMeasurementMeasuredUnit | null } | null }> }, collections: { nodes: Array<{ description: string, descriptionHtml: any, handle: string, id: string, title: string, updatedAt: any, image?: { altText?: string | null, url: any } | null }> } }> | null }; +export type FetchCustomerInfoQueryVariables = Exact<{ + customerAccessToken: Scalars['String']['input']; +}>; + + +export type FetchCustomerInfoQuery = { customer?: { id: string, email?: string | null, firstName?: string | null, lastName?: string | null } | null }; + export type AddItemToCartMutationVariables = Exact<{ cartId: Scalars['ID']['input']; lines: Array | CartLineInput; @@ -7790,3 +7799,11 @@ export type UpdateItemsMutationVariables = Exact<{ export type UpdateItemsMutation = { payload?: { cart?: { id: string, checkoutUrl: any, totalQuantity: number, lines: { nodes: Array<{ id: string, quantity: number, merchandise: { id: string, title: string, image?: { url: any, altText?: string | null } | null, product: { title: string }, price: { amount: any, currencyCode: CurrencyCode } }, cost: { totalAmount: { amount: any, currencyCode: CurrencyCode }, subtotalAmount: { amount: any, currencyCode: CurrencyCode }, amountPerQuantity: { amount: any, currencyCode: CurrencyCode }, compareAtAmountPerQuantity?: { amount: any, currencyCode: CurrencyCode } | null } } | { id: string, quantity: number, merchandise: { id: string, title: string, image?: { url: any, altText?: string | null } | null, product: { title: string }, price: { amount: any, currencyCode: CurrencyCode } }, cost: { totalAmount: { amount: any, currencyCode: CurrencyCode }, subtotalAmount: { amount: any, currencyCode: CurrencyCode }, amountPerQuantity: { amount: any, currencyCode: CurrencyCode }, compareAtAmountPerQuantity?: { amount: any, currencyCode: CurrencyCode } | null } }> }, cost: { subtotalAmount: { amount: any, currencyCode: CurrencyCode }, totalAmount: { amount: any, currencyCode: CurrencyCode }, checkoutChargeAmount: { amount: any, currencyCode: CurrencyCode } }, discountCodes: Array<{ code: string, applicable: boolean }>, discountAllocations: Array<{ discountedAmount: { amount: any, currencyCode: CurrencyCode } } | { discountedAmount: { amount: any, currencyCode: CurrencyCode } } | { discountedAmount: { amount: any, currencyCode: CurrencyCode } }> } | null } | null }; + +export type SignInWithEmailAndPasswordMutationVariables = Exact<{ + email: Scalars['String']['input']; + password: Scalars['String']['input']; +}>; + + +export type SignInWithEmailAndPasswordMutation = { customerAccessTokenCreate?: { customerAccessToken?: { accessToken: string, expiresAt: any } | null, customerUserErrors: Array<{ code?: CustomerErrorCode | null, message: string }> } | null }; diff --git a/utils/graphql.ts b/utils/graphql.ts index b5f888042..81f09e06b 100644 --- a/utils/graphql.ts +++ b/utils/graphql.ts @@ -10,14 +10,17 @@ interface GraphQLResponse { errors: unknown[]; } -type GraphQLAPI = Record; - body: { - query: string; - variables?: Record; - operationName?: string; - }; -}>; +type GraphQLAPI = Record< + string, + { + response: GraphQLResponse; + body: { + query: string; + variables?: Record; + operationName?: string; + }; + } +>; export const gql = (query: TemplateStringsArray, ...fragments: string[]) => query.reduce((a, c, i) => `${a}${fragments[i - 1]}${c}`); @@ -40,7 +43,12 @@ export const createGraphqlClient = ( return { query: async ( - { query = "", fragments = [], variables, operationName }: { + { + query = "", + fragments = [], + variables, + operationName, + }: { query: string; fragments?: string[]; variables?: V; @@ -48,14 +56,17 @@ export const createGraphqlClient = ( }, init?: RequestInit, ): Promise => { - const { data, errors } = await http[key as any]({}, { - ...init, - body: { - query: [query, ...fragments].join("\n"), - variables: variables as any, - operationName, + const { data, errors } = await http[key as any]( + {}, + { + ...init, + body: { + query: [query, ...fragments].join("\n"), + variables: variables as any, + operationName, + }, }, - }).then((res) => res.json()); + ).then((res) => res.json()); if (Array.isArray(errors) && errors.length > 0) { throw errors; @@ -65,3 +76,109 @@ export const createGraphqlClient = ( }, }; }; + +/* + How update storefront.graphql.json data? + Search for this query on graphql playground + + +query IntrospectionQuery { + __schema { + queryType { + name + } + mutationType { + name + } + subscriptionType { + name + } + types { + ...FullType + } + directives { + name + description + locations + args { + ...InputValue + } + } + } +} + +fragment FullType on __Type { + kind + name + description + fields(includeDeprecated: true) { + name + description + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } +} + +fragment InputValue on __InputValue { + name + description + type { + ...TypeRef + } + defaultValue +} + +fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } +} +*/ diff --git a/wake/actions/associateCheckout.ts b/wake/actions/associateCheckout.ts new file mode 100644 index 000000000..cbce21d1f --- /dev/null +++ b/wake/actions/associateCheckout.ts @@ -0,0 +1,40 @@ +import { badRequest } from "@deco/deco"; +import type { AppContext } from "../mod.ts"; +import authenticate from "../utils/authenticate.ts"; +import { getCartCookie } from "../utils/cart.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; +import { CheckoutCustomerAssociate } from "../utils/graphql/queries.ts"; +import type { + CheckoutCustomerAssociateMutation, + CheckoutCustomerAssociateMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-checkoutcustomerassociate +export default async function (_props: object, req: Request, ctx: AppContext) { + try { + const headers = parseHeaders(req.headers); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + const customerAccessToken = ensureCustomerToken( + await authenticate(req, ctx), + ); + + // associate account to checkout + await ctx.storefront.query< + CheckoutCustomerAssociateMutation, + CheckoutCustomerAssociateMutationVariables + >( + { + variables: { + customerAccessToken, + checkoutId, + }, + ...CheckoutCustomerAssociate, + }, + { headers }, + ); + } catch (err) { + throw badRequest(err); + } +} diff --git a/wake/actions/cart/addCoupon.ts b/wake/actions/cart/addCoupon.ts index d4a72a879..d59c61015 100644 --- a/wake/actions/cart/addCoupon.ts +++ b/wake/actions/cart/addCoupon.ts @@ -1,8 +1,9 @@ +import { badRequest } from "@deco/deco"; import { HttpError } from "../../../utils/http.ts"; -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { getCartCookie, setCartCookie } from "../../utils/cart.ts"; import { AddCoupon } from "../../utils/graphql/queries.ts"; -import { +import type { AddCouponMutation, AddCouponMutationVariables, CheckoutFragment, @@ -26,21 +27,28 @@ const action = async ( throw new HttpError(400, "Missing cart cookie"); } - const data = await storefront.query< - AddCouponMutation, - AddCouponMutationVariables - >({ - variables: { checkoutId: cartId, ...props }, - ...AddCoupon, - }, { headers }); - - const checkoutId = data.checkout?.checkoutId; - - if (cartId !== checkoutId) { - setCartCookie(ctx.response.headers, checkoutId); + try { + const data = await storefront.query< + AddCouponMutation, + AddCouponMutationVariables + >( + { + variables: { checkoutId: cartId, ...props }, + ...AddCoupon, + }, + { headers }, + ); + + const checkoutId = data.checkout?.checkoutId; + + if (cartId !== checkoutId) { + setCartCookie(ctx.response.headers, checkoutId); + } + + return data.checkout ?? {}; + } catch (errors) { + throw badRequest(errors); } - - return data.checkout ?? {}; }; export default action; diff --git a/wake/actions/cart/addItem.ts b/wake/actions/cart/addItem.ts index 51939d286..a6ffb2e93 100644 --- a/wake/actions/cart/addItem.ts +++ b/wake/actions/cart/addItem.ts @@ -1,6 +1,6 @@ -import { AppContext } from "../../mod.ts"; -import { CheckoutFragment } from "../../utils/graphql/storefront.graphql.gen.ts"; -import { CartItem as Props } from "./addItems.ts"; +import type { AppContext } from "../../mod.ts"; +import type { CheckoutFragment } from "../../utils/graphql/storefront.graphql.gen.ts"; +import type { CartItem as Props } from "./addItems.ts"; export type { CartItem as Props } from "./addItems.ts"; diff --git a/wake/actions/cart/addItems.ts b/wake/actions/cart/addItems.ts index 30325ddf9..a3155ff61 100644 --- a/wake/actions/cart/addItems.ts +++ b/wake/actions/cart/addItems.ts @@ -1,8 +1,8 @@ import { HttpError } from "../../../utils/http.ts"; -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { getCartCookie, setCartCookie } from "../../utils/cart.ts"; import { AddItemToCart } from "../../utils/graphql/queries.ts"; -import { +import type { AddItemToCartMutation, AddItemToCartMutationVariables, CheckoutFragment, @@ -36,10 +36,13 @@ const action = async ( const data = await storefront.query< AddItemToCartMutation, AddItemToCartMutationVariables - >({ - variables: { input: { id: cartId, products: props.products } }, - ...AddItemToCart, - }, { headers }); + >( + { + variables: { input: { id: cartId, products: props.products } }, + ...AddItemToCart, + }, + { headers }, + ); const checkoutId = data.checkout?.checkoutId; diff --git a/wake/actions/cart/removeCoupon.ts b/wake/actions/cart/removeCoupon.ts index 94d70a8e7..1802aae4a 100644 --- a/wake/actions/cart/removeCoupon.ts +++ b/wake/actions/cart/removeCoupon.ts @@ -1,8 +1,8 @@ import { HttpError } from "../../../utils/http.ts"; -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { getCartCookie, setCartCookie } from "../../utils/cart.ts"; import { RemoveCoupon } from "../../utils/graphql/queries.ts"; -import { +import type { CheckoutFragment, RemoveCouponMutation, RemoveCouponMutationVariables, @@ -25,10 +25,13 @@ const action = async ( const data = await storefront.query< RemoveCouponMutation, RemoveCouponMutationVariables - >({ - variables: { checkoutId: cartId }, - ...RemoveCoupon, - }, { headers }); + >( + { + variables: { checkoutId: cartId }, + ...RemoveCoupon, + }, + { headers }, + ); const checkoutId = data.checkout?.checkoutId; diff --git a/wake/actions/cart/removeKit.ts b/wake/actions/cart/removeKit.ts index 928b943ee..0434e2c41 100644 --- a/wake/actions/cart/removeKit.ts +++ b/wake/actions/cart/removeKit.ts @@ -23,7 +23,9 @@ export interface Props { products: KitItem[]; quantity: number; kitId: number; + kitGroupId: string; } + const action = async ( props: Props, req: Request, @@ -32,7 +34,6 @@ const action = async ( const { storefront } = ctx; const cartId = getCartCookie(req.headers); const headers = parseHeaders(req.headers); - const { quantity, kitId, products } = props; if (!cartId) { throw new HttpError(400, "Missing cart cookie"); @@ -42,7 +43,7 @@ const action = async ( RemoveKitMutation, RemoveKitMutationVariables >({ - variables: { input: { id: cartId, quantity, kitId, products } }, + variables: { input: { id: cartId, ...props } }, ...RemoveKit, }, { headers }); diff --git a/wake/actions/cart/updateItemQuantity.ts b/wake/actions/cart/updateItemQuantity.ts index 49c81aed3..5bd3d4985 100644 --- a/wake/actions/cart/updateItemQuantity.ts +++ b/wake/actions/cart/updateItemQuantity.ts @@ -1,8 +1,8 @@ import { HttpError } from "../../../utils/http.ts"; -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { getCartCookie, setCartCookie } from "../../utils/cart.ts"; import { RemoveItemFromCart } from "../../utils/graphql/queries.ts"; -import { +import type { CheckoutFragment, RemoveItemFromCartMutation, RemoveItemFromCartMutationVariables, @@ -25,12 +25,15 @@ const removeFromCart = ( ctx.storefront.query< RemoveItemFromCartMutation, RemoveItemFromCartMutationVariables - >({ - variables: { - input: { id: cartId, products: [props] }, + >( + { + variables: { + input: { id: cartId, products: [props] }, + }, + ...RemoveItemFromCart, }, - ...RemoveItemFromCart, - }, { headers }); + { headers }, + ); const action = async ( props: Props, @@ -51,14 +54,14 @@ const action = async ( * calculate the difference between the current item amount and requested new amount */ - const cart = await ctx.invoke.wake.loaders.cart(props, req); + const cart = await ctx.invoke.wake.loaders.cart({}, req); const item = cart.products?.find((item) => item?.productVariantId === props.productVariantId ); const quantityItem = item?.quantity ?? 0; const quantity = props.quantity - quantityItem; - let checkout; + let checkout: Partial | null = null; if (props.quantity > 0 && quantity > 0) { checkout = await ctx.invoke.wake.actions.cart.addItem({ @@ -72,7 +75,7 @@ const action = async ( ctx, headers, ); - checkout = data.checkout; + checkout = data.checkout ?? null; } const checkoutId = checkout?.checkoutId; diff --git a/wake/actions/cloneCheckout.ts b/wake/actions/cloneCheckout.ts new file mode 100644 index 000000000..764442db1 --- /dev/null +++ b/wake/actions/cloneCheckout.ts @@ -0,0 +1,37 @@ +import type { AppContext } from "../mod.ts"; +import { getCartCookie, setCartCookie } from "../utils/cart.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; +import { CheckoutClone } from "../utils/graphql/queries.ts"; +import type { + CheckoutCloneMutation, + CheckoutCloneMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-checkoutclone +export default async function (props: object, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + const { checkoutClone } = await ctx.storefront.query< + CheckoutCloneMutation, + CheckoutCloneMutationVariables + >( + { + variables: { + checkoutId, + copyUser: true, + }, + ...CheckoutClone, + }, + { headers }, + ); + + const clonedCheckoutId = checkoutClone?.checkoutId; + + if (!clonedCheckoutId) { + throw new Error("Could not clone checkout"); + } + + setCartCookie(ctx.response.headers, clonedCheckoutId); +} diff --git a/wake/actions/completeCheckout.ts b/wake/actions/completeCheckout.ts new file mode 100644 index 000000000..762e1c9d4 --- /dev/null +++ b/wake/actions/completeCheckout.ts @@ -0,0 +1,49 @@ +import { deleteCookie, setCookie } from "std/http/cookie.ts"; +import type { AppContext } from "../mod.ts"; +import authenticate from "../utils/authenticate.ts"; +import { CART_COOKIE, getCartCookie } from "../utils/cart.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; +import { CheckoutComplete } from "../utils/graphql/queries.ts"; +import type { + CheckoutCompleteMutation, + CheckoutCompleteMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/checkoutcomplete +export default async function (props: Props, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + const customerAccessToken = ensureCustomerToken(await authenticate(req, ctx)); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + const { checkoutComplete } = await ctx.storefront.query< + CheckoutCompleteMutation, + CheckoutCompleteMutationVariables + >( + { + variables: { + paymentData: new URLSearchParams(props.paymentData).toString(), + comments: props.comments, + customerAccessToken, + checkoutId, + }, + ...CheckoutComplete, + }, + { headers }, + ); + + deleteCookie(ctx.response.headers, CART_COOKIE, { path: "/" }); + return checkoutComplete; +} + +interface Props { + /** + * Informações adicionais de pagamento + */ + paymentData?: Record; + /** + * Comentários + */ + comments?: string; +} diff --git a/wake/actions/createAddress.ts b/wake/actions/createAddress.ts new file mode 100644 index 000000000..4d8af4812 --- /dev/null +++ b/wake/actions/createAddress.ts @@ -0,0 +1,86 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + CustomerAddressCreateMutation, + CustomerAddressCreateMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CustomerAddressCreate } from "../utils/graphql/queries.ts"; +import authenticate from "../utils/authenticate.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; + +// https://wakecommerce.readme.io/docs/customeraddresscreate +export default async function ( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + const customerAccessToken = ensureCustomerToken(await authenticate(req, ctx)); + + const { customerAddressCreate } = await ctx.storefront.query< + CustomerAddressCreateMutation, + CustomerAddressCreateMutationVariables + >( + { + variables: { + address: props, + customerAccessToken, + }, + ...CustomerAddressCreate, + }, + { headers }, + ); + + return customerAddressCreate; +} + +interface Props { + /** + * Detalhes do endereço + */ + addressDetails: string; + /** + * Número do endereço + */ + addressNumber: string; + /** + * Cep do endereço + */ + cep: string; + /** + * Cidade do endereço + */ + city: string; + /** + * País do endereço, ex. BR + */ + country: string; + /** + * E-mail do usuário + */ + email: string; + /** + * Nome do usuário + */ + name: string; + /** + * Bairro do endereço + */ + neighborhood: string; + /** + * Telefone do usuário + */ + phone: string; + /** + * Ponto de referência do endereço + */ + referencePoint?: string; + /** + * Estado do endereço + */ + state: string; + /** + * Rua do endereço + */ + street: string; +} diff --git a/wake/actions/createCheckout.ts b/wake/actions/createCheckout.ts new file mode 100644 index 000000000..47abbc968 --- /dev/null +++ b/wake/actions/createCheckout.ts @@ -0,0 +1,56 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + CreateCheckoutMutation, + CreateCheckoutMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CreateCheckout } from "../utils/graphql/queries.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-createcheckout +export default async function ( + { products }: Props, + req: Request, + { storefront }: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + + const { createCheckout } = await storefront.query< + CreateCheckoutMutation, + CreateCheckoutMutationVariables + >( + { + variables: { products: products ?? [] }, + ...CreateCheckout, + }, + { headers }, + ); + + return createCheckout?.checkoutId ?? ""; +} + +interface Props { + products?: { + /** + * ID do variante do produto + */ + productVariantId: number; + /** + * Quantidade do produto a ser adicionado + */ + quantity: number; + /** + * Personalizações do produto + */ + customization?: { + customizationId: number; + value: string; + }[]; + /** + * Informações de assinatura + */ + subscription?: { + recurringTypeId: number; + subscriptionGroupId: number; + }; + }; +} diff --git a/wake/actions/deleteAddress.ts b/wake/actions/deleteAddress.ts new file mode 100644 index 000000000..1fabce08c --- /dev/null +++ b/wake/actions/deleteAddress.ts @@ -0,0 +1,42 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + CustomerAddressRemoveMutation, + CustomerAddressRemoveMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CustomerAddressRemove } from "../utils/graphql/queries.ts"; +import authenticate from "../utils/authenticate.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; + +// https://wakecommerce.readme.io/docs/customeraddressremove +export default async function ( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + const customerAccessToken = ensureCustomerToken(await authenticate(req, ctx)); + + const { customerAddressRemove } = await ctx.storefront.query< + CustomerAddressRemoveMutation, + CustomerAddressRemoveMutationVariables + >( + { + variables: { + id: props.addressId, + customerAccessToken, + }, + ...CustomerAddressRemove, + }, + { headers }, + ); + + return customerAddressRemove; +} + +interface Props { + /** + * ID do endereço + */ + addressId: string; +} diff --git a/wake/actions/deleteCartCookie.ts b/wake/actions/deleteCartCookie.ts new file mode 100644 index 000000000..687a6d108 --- /dev/null +++ b/wake/actions/deleteCartCookie.ts @@ -0,0 +1,11 @@ +import type { AppContext } from "../mod.ts"; +import { deleteCookie } from "std/http/cookie.ts"; +import { CART_COOKIE } from "../utils/cart.ts"; + +export default function ( + _props: object, + _req: Request, + { response }: AppContext, +) { + deleteCookie(response.headers, CART_COOKIE, { path: "/" }); +} diff --git a/wake/actions/login.ts b/wake/actions/login.ts new file mode 100644 index 000000000..1a6ecc472 --- /dev/null +++ b/wake/actions/login.ts @@ -0,0 +1,49 @@ +import type { AppContext } from "../mod.ts"; +import { getCartCookie } from "../utils/cart.ts"; +import { + CheckoutCustomerAssociate, + CustomerAuthenticatedLogin, +} from "../utils/graphql/queries.ts"; +import type { + CheckoutCustomerAssociateMutation, + CheckoutCustomerAssociateMutationVariables, + CustomerAuthenticatedLoginMutation, + CustomerAuthenticatedLoginMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import { setUserCookie } from "../utils/user.ts"; + +export default async function ( + props: Props, + req: Request, + { storefront, response, invoke }: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + + const { customerAuthenticatedLogin } = await storefront.query< + CustomerAuthenticatedLoginMutation, + CustomerAuthenticatedLoginMutationVariables + >({ variables: props, ...CustomerAuthenticatedLogin }, { headers }); + + if (customerAuthenticatedLogin) { + setUserCookie( + response.headers, + customerAuthenticatedLogin.token as string, + customerAuthenticatedLogin.legacyToken as string, + new Date(customerAuthenticatedLogin.validUntil), + ); + } + + return customerAuthenticatedLogin; +} + +export interface Props { + /** + * Email + */ + input: string; + /** + * Senha + */ + pass: string; +} diff --git a/wake/actions/loginGoogle.ts b/wake/actions/loginGoogle.ts new file mode 100644 index 000000000..1aed7283a --- /dev/null +++ b/wake/actions/loginGoogle.ts @@ -0,0 +1,70 @@ +import { setCookie } from "std/http/cookie.ts"; +import type { AppContext } from "../mod.ts"; +import { CustomerSocialLoginGoogle } from "../utils/graphql/queries.ts"; +import type { + CustomerSocialLoginGoogleMutation, + CustomerSocialLoginGoogleMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import { setUserCookie } from "../utils/user.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-customersociallogingoogle +export default async function ( + { userCredential }: Props, + req: Request, + { storefront, response }: AppContext, +): Promise< + { + customerSocialLoginGoogle: + CustomerSocialLoginGoogleMutation["customerSocialLoginGoogle"]; + hasAccount: boolean; + } | null +> { + const headers = parseHeaders(req.headers); + + const { customerSocialLoginGoogle } = await storefront.query< + CustomerSocialLoginGoogleMutation, + CustomerSocialLoginGoogleMutationVariables + >( + { + variables: { userCredential }, + ...CustomerSocialLoginGoogle, + }, + { headers }, + ); + + const token = customerSocialLoginGoogle?.token; + + if (!token) throw new Error("No google token found"); + + if (customerSocialLoginGoogle?.type === "NEW") { + setCookie(response.headers, { + name: "partialCustomerToken", + value: token, + // 1 hour + expires: new Date(Date.now() + 60 * 60 * 1000), + path: "/", + }); + } else if (customerSocialLoginGoogle?.type === "AUTHENTICATED") { + setUserCookie( + response.headers, + customerSocialLoginGoogle.token as string, + customerSocialLoginGoogle.legacyToken as string, + new Date(customerSocialLoginGoogle.validUntil), + ); + } else { + throw new Error(`Not implemented type: ${customerSocialLoginGoogle?.type}`); + } + + return { + customerSocialLoginGoogle, + hasAccount: customerSocialLoginGoogle?.type === "AUTHENTICATED", + }; +} + +interface Props { + /** + * Credencial retornada pelo processo de login da api do Google + */ + userCredential: string; +} diff --git a/wake/actions/logout.ts b/wake/actions/logout.ts new file mode 100644 index 000000000..58997742d --- /dev/null +++ b/wake/actions/logout.ts @@ -0,0 +1,13 @@ +import type { AppContext } from "../mod.ts"; +import { deleteCookie } from "std/http/cookie.ts"; +import { CART_COOKIE } from "../utils/cart.ts"; + +export default function ( + _props: object, + _req: Request, + { response }: AppContext, +) { + deleteCookie(response.headers, "customerToken", { path: "/" }); + deleteCookie(response.headers, "fbits-login", { path: "/" }); + deleteCookie(response.headers, CART_COOKIE, { path: "/" }); +} diff --git a/wake/actions/newsletter/register.ts b/wake/actions/newsletter/register.ts index 643012fe1..a01d60edc 100644 --- a/wake/actions/newsletter/register.ts +++ b/wake/actions/newsletter/register.ts @@ -1,7 +1,7 @@ import { HttpError } from "../../../utils/http.ts"; -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { CreateNewsletterRegister } from "../../utils/graphql/queries.ts"; -import { +import type { CreateNewsletterRegisterMutation, CreateNewsletterRegisterMutationVariables, NewsletterNode, @@ -24,12 +24,15 @@ const action = async ( const data = await storefront.query< CreateNewsletterRegisterMutation, CreateNewsletterRegisterMutationVariables - >({ - variables: { input: { ...props } }, - ...CreateNewsletterRegister, - }, { - headers, - }); + >( + { + variables: { input: { ...props } }, + ...CreateNewsletterRegister, + }, + { + headers, + }, + ); if (!data.createNewsletterRegister) { throw new HttpError(400, "Error on Register"); diff --git a/wake/actions/notifyme.ts b/wake/actions/notifyme.ts index 880191501..fd15e4586 100644 --- a/wake/actions/notifyme.ts +++ b/wake/actions/notifyme.ts @@ -1,6 +1,6 @@ -import { AppContext } from "../mod.ts"; +import type { AppContext } from "../mod.ts"; import { ProductRestockAlert } from "../utils/graphql/queries.ts"; -import { +import type { ProductRestockAlertMutation, ProductRestockAlertMutationVariables, RestockAlertNode, @@ -25,12 +25,15 @@ const action = async ( const data = await storefront.query< ProductRestockAlertMutation, ProductRestockAlertMutationVariables - >({ - variables: { input: props }, - ...ProductRestockAlert, - }, { - headers, - }); + >( + { + variables: { input: props }, + ...ProductRestockAlert, + }, + { + headers, + }, + ); return data.productRestockAlert ?? null; }; diff --git a/wake/actions/recoveryPassword.ts b/wake/actions/recoveryPassword.ts new file mode 100644 index 000000000..f573319fe --- /dev/null +++ b/wake/actions/recoveryPassword.ts @@ -0,0 +1,40 @@ +import type { AppContext } from "../mod.ts"; +import { CustomerPasswordRecovery } from "../utils/graphql/queries.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import { + CustomerPasswordRecoveryMutation, + CustomerPasswordRecoveryMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; + +export interface Props { + email: string; +} + +const action = async ( + props: Props, + req: Request, + ctx: AppContext, +): Promise => { + const { storefront } = ctx; + + const headers = parseHeaders(req.headers); + + const data = await storefront.query< + CustomerPasswordRecoveryMutation, + CustomerPasswordRecoveryMutationVariables + >( + { + variables: { + input: props.email, + }, + ...CustomerPasswordRecovery, + }, + { + headers, + }, + ); + + return data.customerPasswordRecovery; +}; + +export default action; diff --git a/wake/actions/review/create.ts b/wake/actions/review/create.ts index 10f441f2a..4e4d03ee4 100644 --- a/wake/actions/review/create.ts +++ b/wake/actions/review/create.ts @@ -1,6 +1,6 @@ -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { CreateProductReview } from "../../utils/graphql/queries.ts"; -import { +import type { CreateProductReviewMutation, CreateProductReviewMutationVariables, Review, @@ -27,12 +27,15 @@ const action = async ( const data = await storefront.query< CreateProductReviewMutation, CreateProductReviewMutationVariables - >({ - variables: props, - ...CreateProductReview, - }, { - headers, - }); + >( + { + variables: props, + ...CreateProductReview, + }, + { + headers, + }, + ); return data.createProductReview ?? null; }; diff --git a/wake/actions/selectAddress.ts b/wake/actions/selectAddress.ts new file mode 100644 index 000000000..71c59c3ae --- /dev/null +++ b/wake/actions/selectAddress.ts @@ -0,0 +1,40 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + CheckoutAddressAssociateMutation, + CheckoutAddressAssociateMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CheckoutAddressAssociate } from "../utils/graphql/queries.ts"; +import authenticate from "../utils/authenticate.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; +import { getCartCookie } from "../utils/cart.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-checkoutaddressassociate +export default async function (props: Props, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + const customerAccessToken = ensureCustomerToken(await authenticate(req, ctx)); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + await ctx.storefront.query< + CheckoutAddressAssociateMutation, + CheckoutAddressAssociateMutationVariables + >( + { + variables: { + addressId: props.addressId, + customerAccessToken, + checkoutId, + }, + ...CheckoutAddressAssociate, + }, + { headers }, + ); +} + +interface Props { + /** + * ID do endereço + */ + addressId: string; +} diff --git a/wake/actions/selectInstallment.ts b/wake/actions/selectInstallment.ts new file mode 100644 index 000000000..6a89a34a7 --- /dev/null +++ b/wake/actions/selectInstallment.ts @@ -0,0 +1,41 @@ +import type { AppContext } from "../mod.ts"; +import { getCartCookie } from "../utils/cart.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; +import { CheckoutSelectInstallment } from "../utils/graphql/queries.ts"; +import type { + CheckoutSelectInstallmentMutation, + CheckoutSelectInstallmentMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/checkoutselectinstallment +export default async function ( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + const { checkoutSelectInstallment } = await ctx.storefront.query< + CheckoutSelectInstallmentMutation, + CheckoutSelectInstallmentMutationVariables + >( + { + variables: { + installmentNumber: props.installmentNumber, + selectedPaymentMethodId: props.selectedPaymentMethodId, + checkoutId, + }, + ...CheckoutSelectInstallment, + }, + { headers }, + ); + + return checkoutSelectInstallment; +} + +interface Props { + installmentNumber: number; + selectedPaymentMethodId: string; +} diff --git a/wake/actions/selectPayment.ts b/wake/actions/selectPayment.ts new file mode 100644 index 000000000..bdc6e1b97 --- /dev/null +++ b/wake/actions/selectPayment.ts @@ -0,0 +1,39 @@ +import { getCartCookie } from "../utils/cart.ts"; +import type { AppContext } from "../mod.ts"; +import { CheckoutSelectPaymentMethod } from "../utils/graphql/queries.ts"; +import type { + CheckoutSelectPaymentMethodMutation, + CheckoutSelectPaymentMethodMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; + +// https://wakecommerce.readme.io/docs/checkoutselectpaymentmethod +export default async function ( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + const { checkoutSelectPaymentMethod } = await ctx.storefront.query< + CheckoutSelectPaymentMethodMutation, + CheckoutSelectPaymentMethodMutationVariables + >( + { + variables: { + paymentMethodId: props.paymentMethodId, + checkoutId, + }, + ...CheckoutSelectPaymentMethod, + }, + { headers }, + ); + + return checkoutSelectPaymentMethod; +} + +interface Props { + paymentMethodId: string; +} diff --git a/wake/actions/selectShipping.ts b/wake/actions/selectShipping.ts new file mode 100644 index 000000000..c1ca3db6d --- /dev/null +++ b/wake/actions/selectShipping.ts @@ -0,0 +1,33 @@ +import { getCartCookie } from "../utils/cart.ts"; +import type { AppContext } from "../mod.ts"; +import { CheckoutSelectShippingQuote } from "../utils/graphql/queries.ts"; +import type { + CheckoutSelectShippingQuoteMutation, + CheckoutSelectShippingQuoteMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-checkoutselectshippingquote +export default async function (props: Props, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + await ctx.storefront.query< + CheckoutSelectShippingQuoteMutation, + CheckoutSelectShippingQuoteMutationVariables + >( + { + variables: { + shippingQuoteId: props.shippingQuoteId, + checkoutId, + }, + ...CheckoutSelectShippingQuote, + }, + { headers }, + ); +} + +interface Props { + shippingQuoteId: string; +} diff --git a/wake/actions/shippingSimulation.ts b/wake/actions/shippingSimulation.ts index 538519511..a51dea57b 100644 --- a/wake/actions/shippingSimulation.ts +++ b/wake/actions/shippingSimulation.ts @@ -1,12 +1,13 @@ -import { AppContext } from "../mod.ts"; +import type { AppContext } from "../mod.ts"; import { ShippingQuotes } from "../utils/graphql/queries.ts"; -import { +import type { ShippingQuotesQuery, ShippingQuotesQueryVariables, } from "../utils/graphql/storefront.graphql.gen.ts"; import { getCartCookie } from "../utils/cart.ts"; import { HttpError } from "../../utils/http.ts"; import { parseHeaders } from "../utils/parseHeaders.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; export interface Props { cep?: string; @@ -16,7 +17,7 @@ export interface Props { useSelectedAddress?: boolean; } -const buildSimulationParams = ( +export const buildSimulationParams = ( props: Props, checkoutId?: string, ): ShippingQuotesQueryVariables => { @@ -57,22 +58,23 @@ const action = async ( const { storefront } = ctx; const headers = parseHeaders(req.headers); - - const cartId = getCartCookie(req.headers); - + const cartId = ensureCheckout(getCartCookie(req.headers)); const simulationParams = buildSimulationParams(props, cartId); const data = await storefront.query< ShippingQuotesQuery, ShippingQuotesQueryVariables - >({ - variables: { - ...simulationParams, + >( + { + variables: { + ...simulationParams, + }, + ...ShippingQuotes, + }, + { + headers, }, - ...ShippingQuotes, - }, { - headers, - }); + ); return data.shippingQuotes ?? []; }; diff --git a/wake/actions/signupCompany.ts b/wake/actions/signupCompany.ts new file mode 100644 index 000000000..9aaab7b1d --- /dev/null +++ b/wake/actions/signupCompany.ts @@ -0,0 +1,120 @@ +import { CustomerCreate } from "../utils/graphql/queries.ts"; +import type { + CustomerCreateMutation, + CustomerCreateMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-customercreate +export default async function ( + props: Props, + req: Request, + { storefront }: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + + const { customerCreate } = await storefront.query< + CustomerCreateMutation, + CustomerCreateMutationVariables + >( + { + variables: { input: { ...props, customerType: "COMPANY" } }, + ...CustomerCreate, + }, + { headers }, + ); + + return customerCreate ?? null; +} + +interface Props { + /** + * Endereço + */ + address: string; + /** + * Complemento + */ + addressComplement: string; + /** + * Número do endereço + */ + addressNumber: string; + /** + * CEP com pontuação 00000-000 + */ + cep: string; + /** + * Cidade + */ + city: string; + /** + * CNPJ com pontuação 00.000.000/0000-00 + */ + cnpj: string; + /** + * Nome da empresa + */ + corporateName: string; + /** + * Email + */ + email: string; + /** + * Isento de inscrição estadual + */ + isStateRegistrationExempt?: boolean; + /** + * Bairro + */ + neighborhood: string; + /** + * Aceitar assinar newsletter? + */ + newsletter?: boolean; + /** + * Senha de cadastro + */ + password: string; + /** + * Confirmação da senha de cadastro + */ + passwordConfirmation: string; + /** + * DDD do telefone principal do cliente + */ + primaryPhoneAreaCode: string; + /** + * Telefone principal do cliente com pontuação xxxxx-xxxx + */ + primaryPhoneNumber: string; + /** + * Nome do destinatário + */ + receiverName: string; + /** + * Referência de endereço + */ + reference?: string; + /** + * É revendedor? + */ + reseller?: boolean; + /** + * DDD do telefone secundário do cliente + */ + secondaryPhoneAreaCode?: string; + /** + * Telefone secundário do cliente com pontuação xxxxx-xxxx + */ + secondaryPhoneNumber?: string; + /** + * Estado do endereço + */ + state: string; + /** + * Inscrição estadual da empresa + */ + stateRegistration?: string; +} diff --git a/wake/actions/signupPartialCompany.ts b/wake/actions/signupPartialCompany.ts new file mode 100644 index 000000000..ebf201b2d --- /dev/null +++ b/wake/actions/signupPartialCompany.ts @@ -0,0 +1,97 @@ +import { deleteCookie, getCookies } from "std/http/cookie.ts"; +import type { AppContext } from "../mod.ts"; +import { CustomerCompletePartialRegistration } from "../utils/graphql/queries.ts"; +import type { + CompleteRegistrationMutation, + CompleteRegistrationMutationVariables, + CustomerSimpleCreateInputGraphInput, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import { setUserCookie } from "../utils/user.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-customercompletepartialregistration +export default async function ( + _props: Props, + req: Request, + { storefront, response }: AppContext, +): Promise< + CompleteRegistrationMutation["customerCompletePartialRegistration"] | null +> { + const headers = parseHeaders(req.headers); + const cookies = getCookies(req.headers); + + const keys = [ + "cnpj", + "corporateName", + "email", + "isStateRegistrationExempt", + "primaryPhoneAreaCode", + "primaryPhoneNumber", + "stateRegistration", + ]; + + const props = Object.fromEntries( + Object.entries(_props).filter(([key]) => keys.includes(key)), + ); + + const input = { + ...props, + customerType: "COMPANY", + } as CustomerSimpleCreateInputGraphInput; + const customerAccessToken = cookies.partialCustomerToken; + + const { customerCompletePartialRegistration } = await storefront.query< + CompleteRegistrationMutation, + CompleteRegistrationMutationVariables + >( + { + variables: { input, customerAccessToken }, + ...CustomerCompletePartialRegistration, + }, + { headers }, + ); + + if (customerCompletePartialRegistration) { + setUserCookie( + response.headers, + customerCompletePartialRegistration.token as string, + customerCompletePartialRegistration.legacyToken as string, + new Date(customerCompletePartialRegistration.validUntil), + ); + + deleteCookie(response.headers, "partialCustomerToken", { path: "/" }); + } + + return customerCompletePartialRegistration ?? null; +} + +interface Props { + /** + * CNPJ com pontuação 00.000.000/0000-00 + */ + cnpj: string; + /** + * Nome da empresa + */ + corporateName: string; + /** + * Email + */ + email: string; + /** + * Isento de inscrição estadual + */ + isStateRegistrationExempt?: boolean; + /** + * DDD do telefone principal do cliente + */ + primaryPhoneAreaCode: string; + /** + * Telefone principal do cliente com pontuação xxxxx-xxxx + */ + primaryPhoneNumber: string; + /** + * Inscrição estadual da empresa + */ + stateRegistration?: string; +} diff --git a/wake/actions/signupPartialPerson.ts b/wake/actions/signupPartialPerson.ts new file mode 100644 index 000000000..238dfdfbf --- /dev/null +++ b/wake/actions/signupPartialPerson.ts @@ -0,0 +1,93 @@ +import { deleteCookie, getCookies } from "std/http/cookie.ts"; +import type { AppContext } from "../mod.ts"; +import { CustomerCompletePartialRegistration } from "../utils/graphql/queries.ts"; +import type { + CompleteRegistrationMutation, + CompleteRegistrationMutationVariables, + CustomerSimpleCreateInputGraphInput, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import { setUserCookie } from "../utils/user.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-customercompletepartialregistration +export default async function ( + _props: Props, + req: Request, + { storefront, response }: AppContext, +): Promise< + CompleteRegistrationMutation["customerCompletePartialRegistration"] | null +> { + const headers = parseHeaders(req.headers); + const cookies = getCookies(req.headers); + + const keys = [ + "birthDate", + "cpf", + "email", + "fullName", + "primaryPhoneAreaCode", + "primaryPhoneNumber", + ]; + + const props = Object.fromEntries( + Object.entries(_props).filter(([key]) => keys.includes(key)), + ); + + const input = { + ...props, + customerType: "PERSON", + } as CustomerSimpleCreateInputGraphInput; + const customerAccessToken = cookies.partialCustomerToken ?? + cookies.customerToken; + + const { customerCompletePartialRegistration } = await storefront.query< + CompleteRegistrationMutation, + CompleteRegistrationMutationVariables + >( + { + variables: { input, customerAccessToken }, + ...CustomerCompletePartialRegistration, + }, + { headers }, + ); + + if (customerCompletePartialRegistration) { + setUserCookie( + response.headers, + customerCompletePartialRegistration.token as string, + customerCompletePartialRegistration.legacyToken as string, + new Date(customerCompletePartialRegistration.validUntil), + ); + + deleteCookie(response.headers, "partialCustomerToken", { path: "/" }); + } + + return customerCompletePartialRegistration ?? null; +} + +interface Props { + /** + * Data de nascimento DD/MM/AAAA + */ + birthDate: Date | string; + /** + * CPF com pontuação 000.000.000-00 + */ + cpf: string; + /** + * Email + */ + email: string; + /** + * Nome completo + */ + fullName: string; + /** + * DDD do telefone principal do cliente + */ + primaryPhoneAreaCode: string; + /** + * Telefone principal do cliente com pontuação xxxxx-xxxx + */ + primaryPhoneNumber: string; +} diff --git a/wake/actions/signupPerson.ts b/wake/actions/signupPerson.ts new file mode 100644 index 000000000..982ad5776 --- /dev/null +++ b/wake/actions/signupPerson.ts @@ -0,0 +1,120 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + CustomerCreateMutation, + CustomerCreateMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CustomerCreate } from "../utils/graphql/queries.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-customercreate +export default async function ( + props: Props, + req: Request, + { storefront }: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + + const { customerCreate } = await storefront.query< + CustomerCreateMutation, + CustomerCreateMutationVariables + >( + { + variables: { input: { ...props, customerType: "PERSON" } }, + ...CustomerCreate, + }, + { headers }, + ); + + return customerCreate ?? null; +} + +interface Props { + /** + * Endereço + */ + address: string; + /** + * Complemento + */ + addressComplement: string; + /** + * Número do endereço + */ + addressNumber: string; + /** + * Data de nascimento DD/MM/AAAA + */ + birthDate: Date | string; + /** + * CEP com pontuação 00000-000 + */ + cep: string; + /** + * Cidade + */ + city: string; + /** + * CPF com pontuação 000.000.000-00 + */ + cpf: string; + /** + * Email + */ + email: string; + /** + * Nome completo + */ + fullName: string; + /** + * Gênero + */ + gender: "MALE" | "FEMALE"; + /** + * Bairro + */ + neighborhood: string; + /** + * Aceitar assinar newsletter? + */ + newsletter?: boolean; + /** + * Senha de cadastro + */ + password: string; + /** + * Confirmação da senha de cadastro + */ + passwordConfirmation: string; + /** + * DDD do telefone principal do cliente + */ + primaryPhoneAreaCode: string; + /** + * Telefone principal do cliente com pontuação xxxxx-xxxx + */ + primaryPhoneNumber: string; + /** + * Nome do destinatário + */ + receiverName: string; + /** + * Referência de endereço + */ + reference?: string; + /** + * É revendedor? + */ + reseller?: boolean; + /** + * DDD do telefone secundário do cliente + */ + secondaryPhoneAreaCode?: string; + /** + * Telefone secundário do cliente com pontuação xxxxx-xxxx + */ + secondaryPhoneNumber?: string; + /** + * Estado do endereço + */ + state: string; +} diff --git a/wake/actions/submmitForm.ts b/wake/actions/submmitForm.ts index beac2c3bf..37d2e5e37 100644 --- a/wake/actions/submmitForm.ts +++ b/wake/actions/submmitForm.ts @@ -1,6 +1,6 @@ -import { AppContext } from "../mod.ts"; +import type { AppContext } from "../mod.ts"; import { SendGenericForm } from "../utils/graphql/queries.ts"; -import { +import type { SendGenericFormMutation, SendGenericFormMutationVariables, } from "../utils/graphql/storefront.graphql.gen.ts"; diff --git a/wake/actions/updateAddress.ts b/wake/actions/updateAddress.ts new file mode 100644 index 000000000..39747ce77 --- /dev/null +++ b/wake/actions/updateAddress.ts @@ -0,0 +1,95 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + CustomerAddressUpdateMutation, + CustomerAddressUpdateMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CustomerAddressUpdate } from "../utils/graphql/queries.ts"; +import authenticate from "../utils/authenticate.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; + +// https://wakecommerce.readme.io/docs/customeraddressupdate +export default async function ( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + const customerAccessToken = ensureCustomerToken(await authenticate(req, ctx)); + + if (!customerAccessToken) return null; + + const { customerAddressUpdate } = await ctx.storefront.query< + CustomerAddressUpdateMutation, + CustomerAddressUpdateMutationVariables + >( + { + variables: { + address: props.address, + id: props.addressId, + customerAccessToken, + }, + ...CustomerAddressUpdate, + }, + { headers }, + ); + + return customerAddressUpdate; +} + +interface Props { + /** + * ID do endereço + */ + addressId: string; + address: { + /** + * Detalhes do endereço + */ + addressDetails?: string; + /** + * Número do endereço + */ + addressNumber?: string; + /** + * Cep do endereço + */ + cep?: string; + /** + * Cidade do endereço + */ + city?: string; + /** + * País do endereço, ex. BR + */ + country?: string; + /** + * E-mail do usuário + */ + email?: string; + /** + * Nome do usuário + */ + name?: string; + /** + * Bairro do endereço + */ + neighborhood?: string; + /** + * Telefone do usuário + */ + phone?: string; + /** + * Ponto de referência do endereço + */ + referencePoint?: string; + /** + * Estado do endereço + */ + state?: string; + /** + * Rua do endereço + */ + street?: string; + }; +} diff --git a/wake/actions/wishlist/addProduct.ts b/wake/actions/wishlist/addProduct.ts index 93ebf7115..6d5811dda 100644 --- a/wake/actions/wishlist/addProduct.ts +++ b/wake/actions/wishlist/addProduct.ts @@ -1,8 +1,8 @@ -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import authenticate from "../../utils/authenticate.ts"; import { WishlistAddProduct } from "../../utils/graphql/queries.ts"; -import { ProductFragment } from "../../utils/graphql/storefront.graphql.gen.ts"; -import { +import type { ProductFragment } from "../../utils/graphql/storefront.graphql.gen.ts"; +import type { WishlistAddProductMutation, WishlistAddProductMutationVariables, WishlistReducedProductFragment, @@ -28,10 +28,13 @@ const action = async ( const data = await storefront.query< WishlistAddProductMutation, WishlistAddProductMutationVariables - >({ - variables: { customerAccessToken, productId }, - ...WishlistAddProduct, - }, { headers }); + >( + { + variables: { customerAccessToken, productId }, + ...WishlistAddProduct, + }, + { headers }, + ); const products = data.wishlistAddProduct; diff --git a/wake/actions/wishlist/removeProduct.ts b/wake/actions/wishlist/removeProduct.ts index 3102238e6..c1ab95c21 100644 --- a/wake/actions/wishlist/removeProduct.ts +++ b/wake/actions/wishlist/removeProduct.ts @@ -1,12 +1,12 @@ -import { AppContext } from "../../mod.ts"; +import type { AppContext } from "../../mod.ts"; import { WishlistRemoveProduct } from "../../utils/graphql/queries.ts"; -import { +import type { WishlistReducedProductFragment, WishlistRemoveProductMutation, WishlistRemoveProductMutationVariables, } from "../../utils/graphql/storefront.graphql.gen.ts"; -import { ProductFragment } from "../../utils/graphql/storefront.graphql.gen.ts"; +import type { ProductFragment } from "../../utils/graphql/storefront.graphql.gen.ts"; import authenticate from "../../utils/authenticate.ts"; import { parseHeaders } from "../../utils/parseHeaders.ts"; @@ -31,10 +31,13 @@ const action = async ( const data = await storefront.query< WishlistRemoveProductMutation, WishlistRemoveProductMutationVariables - >({ - variables: { customerAccessToken, productId }, - ...WishlistRemoveProduct, - }, { headers }); + >( + { + variables: { customerAccessToken, productId }, + ...WishlistRemoveProduct, + }, + { headers }, + ); const products = data.wishlistRemoveProduct; diff --git a/wake/hooks/context.ts b/wake/hooks/context.ts index 4d3f6b1c4..4cb7130a5 100644 --- a/wake/hooks/context.ts +++ b/wake/hooks/context.ts @@ -1,24 +1,26 @@ import { IS_BROWSER } from "$fresh/runtime.ts"; import { signal } from "@preact/signals"; +import type { Person } from "../../commerce/types.ts"; import { invoke } from "../runtime.ts"; +import { setClientCookie } from "../utils/cart.ts"; import type { CheckoutFragment, + ShopQuery, WishlistReducedProductFragment, } from "../utils/graphql/storefront.graphql.gen.ts"; -import { Person } from "../../commerce/types.ts"; -import { setClientCookie } from "../utils/cart.ts"; -import { ShopQuery } from "../utils/graphql/storefront.graphql.gen.ts"; export interface Context { cart: Partial; - user: Person | null; + user: (Person & { cpf: string | null }) | null; wishlist: WishlistReducedProductFragment[] | null; } const loading = signal(true); const context = { cart: signal>({}), - user: signal(null), + user: signal< + (Person & { cpf: string | null; phoneNumber: string | null }) | null + >(null), wishlist: signal(null), shop: signal(null), }; @@ -77,15 +79,15 @@ const enqueue2 = ( queue2 = queue2.then(async () => { try { const { shop } = await cb(controller.signal); + const headlessCheckout = await invoke.wake.loaders.headlessCheckout(); + const isLocalhost = window.location.hostname === "localhost"; if (!shop || !shop?.checkoutUrl) { console.error("Erro on get shop checkoutUrl"); return; } - const isLocalhost = window.location.hostname === "localhost"; - - if (!isLocalhost) { + if (!isLocalhost && !headlessCheckout) { const url = new URL("/api/carrinho", shop.checkoutUrl); const { Id } = await fetch(url, { credentials: "include" }).then((r) => @@ -116,16 +118,22 @@ const enqueue2 = ( }; const load2 = (signal: AbortSignal) => - invoke({ - shop: invoke.wake.loaders.shop(), - }, { signal }); + invoke( + { + shop: invoke.wake.loaders.shop(), + }, + { signal }, + ); const load = (signal: AbortSignal) => - invoke({ - cart: invoke.wake.loaders.cart(), - user: invoke.wake.loaders.user(), - wishlist: invoke.wake.loaders.wishlist(), - }, { signal }); + invoke( + { + cart: invoke.wake.loaders.cart(), + user: invoke.wake.loaders.user(), + wishlist: invoke.wake.loaders.wishlist(), + }, + { signal }, + ); if (IS_BROWSER) { enqueue2(load2); diff --git a/wake/hooks/useCart.ts b/wake/hooks/useCart.ts index d5f077a3f..2da8b2820 100644 --- a/wake/hooks/useCart.ts +++ b/wake/hooks/useCart.ts @@ -2,8 +2,8 @@ import type { AnalyticsItem } from "../../commerce/types.ts"; import type { Manifest } from "../manifest.gen.ts"; import { invoke } from "../runtime.ts"; -import { CheckoutFragment } from "../utils/graphql/storefront.graphql.gen.ts"; -import { Context, state as storeState } from "./context.ts"; +import type { CheckoutFragment } from "../utils/graphql/storefront.graphql.gen.ts"; +import { type Context, state as storeState } from "./context.ts"; const { cart, loading } = storeState; @@ -27,22 +27,27 @@ export const itemToAnalyticsItem = ( }; }; -type EnqueuableActions< - K extends keyof Manifest["actions"], -> = Manifest["actions"][K]["default"] extends - (...args: any[]) => Promise ? K : never; +type EnqueuableActions = + Manifest["actions"][K]["default"] extends ( + ...args: any[] + ) => Promise ? K + : never; -const enqueue = < - K extends keyof Manifest["actions"], ->(key: EnqueuableActions) => -(props: Parameters[0]) => - storeState.enqueue((signal) => - invoke({ cart: { key, props } } as any, { signal }) as any - ); +const enqueue = + (key: EnqueuableActions) => + (props: Parameters[0]) => + storeState.enqueue((signal) => + invoke({ cart: { key, props } } as any, { signal }) as any + ); const state = { cart, loading, + updateCart: async () => { + loading.value = true; + cart.value = await invoke.wake.loaders.cart(); + loading.value = false; + }, addItem: enqueue("wake/actions/cart/addItem.ts"), addKit: enqueue("wake/actions/cart/addKit.ts"), removeKit: enqueue("wake/actions/cart/removeKit.ts"), diff --git a/wake/hooks/useUser.ts b/wake/hooks/useUser.ts index ef405c564..7fd78ec70 100644 --- a/wake/hooks/useUser.ts +++ b/wake/hooks/useUser.ts @@ -1,7 +1,16 @@ +import { invoke } from "../runtime.ts"; import { state as storeState } from "./context.ts"; const { user, loading } = storeState; -const state = { user, loading }; +const state = { + user, + loading, + updateUser: async () => { + loading.value = true; + user.value = await invoke.wake.loaders.user(); + loading.value = false; + }, +}; export const useUser = () => state; diff --git a/wake/hooks/useWishlist.ts b/wake/hooks/useWishlist.ts index 460df6379..963ffe517 100644 --- a/wake/hooks/useWishlist.ts +++ b/wake/hooks/useWishlist.ts @@ -1,8 +1,8 @@ // deno-lint-ignore-file no-explicit-any -import { Product } from "../../commerce/types.ts"; -import { Manifest } from "../manifest.gen.ts"; +import type { Product } from "../../commerce/types.ts"; +import type { Manifest } from "../manifest.gen.ts"; import { invoke } from "../runtime.ts"; -import { WishlistReducedProductFragment } from "../utils/graphql/storefront.graphql.gen.ts"; +import type { WishlistReducedProductFragment } from "../utils/graphql/storefront.graphql.gen.ts"; import { state as storeState } from "./context.ts"; const { wishlist, loading } = storeState; @@ -21,7 +21,7 @@ const enqueue = < ); const getItem = (item: Omit) => - wishlist.value?.find((id) => id.productId == item.productId); + wishlist.value?.find((id) => id.productId === item.productId); const state = { wishlist, diff --git a/wake/loaders/calculatePrices.ts b/wake/loaders/calculatePrices.ts new file mode 100644 index 000000000..a39bda1ac --- /dev/null +++ b/wake/loaders/calculatePrices.ts @@ -0,0 +1,40 @@ +import type { AppContext } from "../mod.ts"; +import { CalculatePrices } from "../utils/graphql/queries.ts"; +import type { + CalculatePricesQuery, + CalculatePricesQueryVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-calculateprices +export default async function ( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + + const { calculatePrices } = await ctx.storefront.query< + CalculatePricesQuery, + CalculatePricesQueryVariables + >( + { + variables: { + partnerAccessToken: props.partnerAccessToken ?? "", + products: props.products, + }, + ...CalculatePrices, + }, + { headers }, + ); + + return calculatePrices || null; +} + +type Props = { + partnerAccessToken?: string; + products: { + productVariantId: number; + quantity: number; + }[]; +}; diff --git a/wake/loaders/cart.ts b/wake/loaders/cart.ts index 97350b25d..d52d65457 100644 --- a/wake/loaders/cart.ts +++ b/wake/loaders/cart.ts @@ -1,7 +1,8 @@ -import { AppContext } from "../mod.ts"; +import authenticate from "../utils/authenticate.ts"; +import type { AppContext } from "../mod.ts"; import { getCartCookie, setCartCookie } from "../utils/cart.ts"; import { CreateCart, GetCart } from "../utils/graphql/queries.ts"; -import { +import type { CheckoutFragment, CreateCartMutation, CreateCartMutationVariables, @@ -15,26 +16,33 @@ import { parseHeaders } from "../utils/parseHeaders.ts"; * @description Cart loader */ const loader = async ( - _props: unknown, + props: Props, req: Request, ctx: AppContext, ): Promise> => { const { storefront } = ctx; - const cartId = getCartCookie(req.headers); + const cartId = props?.cartId || getCartCookie(req.headers); const headers = parseHeaders(req.headers); + const customerAccessToken = await authenticate(req, ctx); const data = cartId - ? await storefront.query({ - variables: { checkoutId: cartId }, - ...GetCart, - }, { - headers, - }) - : await storefront.query({ - ...CreateCart, - }, { - headers, - }); + ? await storefront.query( + { + variables: { checkoutId: cartId, customerAccessToken }, + ...GetCart, + }, + { + headers, + }, + ) + : await storefront.query( + { + ...CreateCart, + }, + { + headers, + }, + ); const checkoutId = data.checkout?.checkoutId; @@ -46,3 +54,7 @@ const loader = async ( }; export default loader; + +interface Props { + cartId?: string; +} diff --git a/wake/loaders/checkoutCoupon.ts b/wake/loaders/checkoutCoupon.ts new file mode 100644 index 000000000..c7dc57f61 --- /dev/null +++ b/wake/loaders/checkoutCoupon.ts @@ -0,0 +1,34 @@ +import { getCartCookie } from "../utils/cart.ts"; +import ensureCheckout from "../utils/ensureCheckout.ts"; +import type { AppContext } from "../mod.ts"; +import { GetCheckoutCoupon } from "../utils/graphql/queries.ts"; +import type { + GetCheckoutCouponQuery, + GetCheckoutCouponQueryVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-checkout +export default async function ( + _props: object, + req: Request, + ctx: AppContext, +): Promise { + const headers = parseHeaders(req.headers); + const checkoutId = ensureCheckout(getCartCookie(req.headers)); + + if (!checkoutId) return null; + + const { checkout } = await ctx.storefront.query< + GetCheckoutCouponQuery, + GetCheckoutCouponQueryVariables + >( + { + variables: { checkoutId }, + ...GetCheckoutCoupon, + }, + { headers }, + ); + + return checkout?.coupon || null; +} diff --git a/wake/loaders/headlessCheckout.ts b/wake/loaders/headlessCheckout.ts new file mode 100644 index 000000000..7ed97c446 --- /dev/null +++ b/wake/loaders/headlessCheckout.ts @@ -0,0 +1,5 @@ +import type { AppContext } from "../mod.ts"; + +export default (_props: unknown, _req: Request, ctx: AppContext) => { + return ctx.headlessCheckout; +}; diff --git a/wake/loaders/paymentMethods.ts b/wake/loaders/paymentMethods.ts new file mode 100644 index 000000000..3e7d20e61 --- /dev/null +++ b/wake/loaders/paymentMethods.ts @@ -0,0 +1,27 @@ +import { getCartCookie } from "../utils/cart.ts"; +import type { AppContext } from "../mod.ts"; +import { PaymentMethods } from "../utils/graphql/queries.ts"; +import type { + PaymentMethodsQuery, + PaymentMethodsQueryVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/paymentmethods +export default async function (_props: object, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + const checkoutId = getCartCookie(req.headers); + + const { paymentMethods } = await ctx.storefront.query< + PaymentMethodsQuery, + PaymentMethodsQueryVariables + >( + { + variables: { checkoutId }, + ...PaymentMethods, + }, + { headers }, + ); + + return paymentMethods?.filter((i): i is NonNullable => !!i) || []; +} diff --git a/wake/loaders/productCustomizations.ts b/wake/loaders/productCustomizations.ts new file mode 100644 index 000000000..9cc0b74c7 --- /dev/null +++ b/wake/loaders/productCustomizations.ts @@ -0,0 +1,29 @@ +import type { AppContext } from "../mod.ts"; +import { GetProductCustomizations } from "../utils/graphql/queries.ts"; +import type { + GetProductCustomizationsQuery, + GetProductCustomizationsQueryVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-product +export default async function (props: Props, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + + const { product } = await ctx.storefront.query< + GetProductCustomizationsQuery, + GetProductCustomizationsQueryVariables + >( + { + variables: { productId: props.productId }, + ...GetProductCustomizations, + }, + { headers }, + ); + + return product; +} + +interface Props { + productId: number; +} diff --git a/wake/loaders/productDetailsPage.ts b/wake/loaders/productDetailsPage.ts index 560e93a15..1316a98a1 100644 --- a/wake/loaders/productDetailsPage.ts +++ b/wake/loaders/productDetailsPage.ts @@ -1,14 +1,14 @@ import type { Product, ProductDetailsPage } from "../../commerce/types.ts"; import type { RequestURLParam } from "../../website/functions/requestToParam.ts"; -import { AppContext } from "../mod.ts"; +import type { AppContext } from "../mod.ts"; import { MAXIMUM_REQUEST_QUANTITY } from "../utils/getVariations.ts"; -import { GetBuyList, GetProduct } from "../utils/graphql/queries.ts"; import { BuyListQuery, BuyListQueryVariables, GetProductQuery, GetProductQueryVariables, } from "../utils/graphql/storefront.graphql.gen.ts"; +import { GetBuyList, GetProduct } from "../utils/graphql/queries.ts"; import { parseHeaders } from "../utils/parseHeaders.ts"; import { parseSlug, toBreadcrumbList, toProduct } from "../utils/transform.ts"; diff --git a/wake/loaders/productList.ts b/wake/loaders/productList.ts index b529f10b6..a76ebc019 100644 --- a/wake/loaders/productList.ts +++ b/wake/loaders/productList.ts @@ -2,7 +2,7 @@ import type { Product } from "../../commerce/types.ts"; import type { AppContext } from "../mod.ts"; import { getVariations } from "../utils/getVariations.ts"; import { GetProducts } from "../utils/graphql/queries.ts"; -import { +import type { GetProductsQuery, GetProductsQueryVariables, ProductFragment, @@ -142,6 +142,13 @@ const productListLoader = async ( const url = new URL(req.url); const { storefront } = ctx; + console.log(props.filters); + console.log(props.filters); + console.log(props.filters); + console.log(props.filters); + console.log(props.filters); + console.log(props.filters); + const headers = parseHeaders(req.headers); const data = await storefront.query< diff --git a/wake/loaders/productListingPage.ts b/wake/loaders/productListingPage.ts index 35c990067..b174c41aa 100644 --- a/wake/loaders/productListingPage.ts +++ b/wake/loaders/productListingPage.ts @@ -1,5 +1,5 @@ import type { ProductListingPage } from "../../commerce/types.ts"; -import { SortOption } from "../../commerce/types.ts"; +import type { SortOption } from "../../commerce/types.ts"; import { capitalize } from "../../utils/capitalize.ts"; import { RequestURLParam } from "../../website/functions/requestToParam.ts"; import type { AppContext } from "../mod.ts"; @@ -167,10 +167,14 @@ const searchLoader = async ( ]; const onlyMainVariant = props.onlyMainVariant ?? true; - const [minimumPrice, maximumPrice] = - url.searchParams.getAll("filtro")?.find((i) => i.startsWith("precoPor")) - ?.split(":")[1]?.split(";").map(Number) ?? - url.searchParams.get("precoPor")?.split(";").map(Number) ?? []; + const [minimumPrice, maximumPrice] = url.searchParams + .getAll("filtro") + ?.find((i) => i.startsWith("precoPor")) + ?.split(":")[1] + ?.split(";") + .map(Number) ?? + url.searchParams.get("precoPor")?.split(";").map(Number) ?? + []; const offset = page <= 1 ? 0 : (page - 1) * limit; @@ -197,14 +201,17 @@ const searchLoader = async ( } } - const urlData = await storefront.query({ - variables: { - url: url.pathname, + const urlData = await storefront.query( + { + variables: { + url: url.pathname, + }, + ...GetURL, }, - ...GetURL, - }, { - headers, - }); + { + headers, + }, + ); const isHotsite = urlData.uri?.kind === "HOTSITE"; diff --git a/wake/loaders/proxy.ts b/wake/loaders/proxy.ts index 580124ada..464514538 100644 --- a/wake/loaders/proxy.ts +++ b/wake/loaders/proxy.ts @@ -1,5 +1,5 @@ -import { Route } from "../../website/flags/audience.ts"; -import { AppContext } from "../mod.ts"; +import type { Route } from "../../website/flags/audience.ts"; +import type { AppContext } from "../mod.ts"; const PATHS_TO_PROXY = [ ["/checkout", "/checkout"], diff --git a/wake/loaders/recommendations.ts b/wake/loaders/recommendations.ts index 2a7b37431..26ebcabb1 100644 --- a/wake/loaders/recommendations.ts +++ b/wake/loaders/recommendations.ts @@ -1,8 +1,8 @@ import type { Product } from "../../commerce/types.ts"; -import { RequestURLParam } from "../../website/functions/requestToParam.ts"; +import type { RequestURLParam } from "../../website/functions/requestToParam.ts"; import type { AppContext } from "../mod.ts"; import { ProductRecommendations } from "../utils/graphql/queries.ts"; -import { +import type { ProductFragment, ProductRecommendationsQuery, ProductRecommendationsQueryVariables, diff --git a/wake/loaders/shop.ts b/wake/loaders/shop.ts index 124d0ba5b..57cc61f13 100644 --- a/wake/loaders/shop.ts +++ b/wake/loaders/shop.ts @@ -1,6 +1,6 @@ import type { AppContext } from "../mod.ts"; import { Shop } from "../utils/graphql/queries.ts"; -import { +import type { ShopQuery, ShopQueryVariables, } from "../utils/graphql/storefront.graphql.gen.ts"; diff --git a/wake/loaders/suggestion.ts b/wake/loaders/suggestion.ts index c580511e1..1d86724cb 100644 --- a/wake/loaders/suggestion.ts +++ b/wake/loaders/suggestion.ts @@ -1,7 +1,7 @@ -import { Suggestion } from "../../commerce/types.ts"; -import { AppContext } from "../mod.ts"; +import type { Suggestion } from "../../commerce/types.ts"; +import type { AppContext } from "../mod.ts"; import { Autocomplete } from "../utils/graphql/queries.ts"; -import { +import type { AutocompleteQuery, AutocompleteQueryVariables, ProductFragment, diff --git a/wake/loaders/user.ts b/wake/loaders/user.ts index 3a0befaca..7cea226f3 100644 --- a/wake/loaders/user.ts +++ b/wake/loaders/user.ts @@ -1,8 +1,8 @@ -import { Person } from "../../commerce/types.ts"; +import type { Person } from "../../commerce/types.ts"; import type { AppContext } from "../mod.ts"; import authenticate from "../utils/authenticate.ts"; import { GetUser } from "../utils/graphql/queries.ts"; -import { +import type { GetUserQuery, GetUserQueryVariables, } from "../utils/graphql/storefront.graphql.gen.ts"; @@ -16,25 +16,26 @@ const userLoader = async ( _props: unknown, req: Request, ctx: AppContext, -): Promise => { +): Promise< + (Person & { cpf: string | null; phoneNumber: string | null }) | null +> => { const { storefront } = ctx; const headers = parseHeaders(req.headers); const customerAccessToken = await authenticate(req, ctx); - if (!customerAccessToken) return null; try { - const data = await storefront.query< - GetUserQuery, - GetUserQueryVariables - >({ - variables: { customerAccessToken }, - ...GetUser, - }, { - headers, - }); + const data = await storefront.query( + { + variables: { customerAccessToken }, + ...GetUser, + }, + { + headers, + }, + ); const customer = data.customer; @@ -47,8 +48,10 @@ const userLoader = async ( gender: customer?.gender === "Masculino" ? "https://schema.org/Male" : "https://schema.org/Female", + cpf: customer.cpf || null, + phoneNumber: customer.phoneNumber || null, }; - } catch { + } catch (e) { return null; } }; diff --git a/wake/loaders/userAddresses.ts b/wake/loaders/userAddresses.ts new file mode 100644 index 000000000..306dd6afd --- /dev/null +++ b/wake/loaders/userAddresses.ts @@ -0,0 +1,31 @@ +import type { AppContext } from "../mod.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; +import type { + GetUserAddressesQuery, + GetUserAddressesQueryVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { GetUserAddresses } from "../utils/graphql/queries.ts"; +import authenticate from "../utils/authenticate.ts"; +import ensureCustomerToken from "../utils/ensureCustomerToken.ts"; +import nonNullable from "../utils/nonNullable.ts"; + +// https://wakecommerce.readme.io/docs/storefront-api-customer +export default async function (_props: object, req: Request, ctx: AppContext) { + const headers = parseHeaders(req.headers); + const customerAccessToken = ensureCustomerToken(await authenticate(req, ctx)); + + if (!customerAccessToken) return []; + + const { customer } = await ctx.storefront.query< + GetUserAddressesQuery, + GetUserAddressesQueryVariables + >( + { + variables: { customerAccessToken }, + ...GetUserAddresses, + }, + { headers }, + ); + + return (customer?.addresses || []).filter(nonNullable); +} diff --git a/wake/loaders/wishlist.ts b/wake/loaders/wishlist.ts index a224f3023..297961ed1 100644 --- a/wake/loaders/wishlist.ts +++ b/wake/loaders/wishlist.ts @@ -1,9 +1,9 @@ -import { AppContext } from "../mod.ts"; +import type { AppContext } from "../mod.ts"; import authenticate from "../utils/authenticate.ts"; import { GetWishlist } from "../utils/graphql/queries.ts"; -import { - GetWishlistQuery, - GetWishlistQueryVariables, +import type { + GetWislistQuery, + GetWislistQueryVariables, WishlistReducedProductFragment, } from "../utils/graphql/storefront.graphql.gen.ts"; import { parseHeaders } from "../utils/parseHeaders.ts"; diff --git a/wake/manifest.gen.ts b/wake/manifest.gen.ts index 70b56ddad..3ce52fe45 100644 --- a/wake/manifest.gen.ts +++ b/wake/manifest.gen.ts @@ -2,69 +2,121 @@ // This file SHOULD be checked into source version control. // This file is automatically updated during development when running `dev.ts`. -import * as $$$$$$$$$0 from "./actions/cart/addCoupon.ts"; -import * as $$$$$$$$$1 from "./actions/cart/addItem.ts"; -import * as $$$$$$$$$2 from "./actions/cart/addItems.ts"; -import * as $$$$$$$$$3 from "./actions/cart/addKit.ts"; -import * as $$$$$$$$$4 from "./actions/cart/partnerAssociate.ts"; -import * as $$$$$$$$$5 from "./actions/cart/partnerDisassociate.ts"; -import * as $$$$$$$$$6 from "./actions/cart/removeCoupon.ts"; -import * as $$$$$$$$$7 from "./actions/cart/removeKit.ts"; -import * as $$$$$$$$$8 from "./actions/cart/updateItemQuantity.ts"; -import * as $$$$$$$$$9 from "./actions/newsletter/register.ts"; -import * as $$$$$$$$$10 from "./actions/notifyme.ts"; -import * as $$$$$$$$$11 from "./actions/review/create.ts"; -import * as $$$$$$$$$12 from "./actions/shippingSimulation.ts"; -import * as $$$$$$$$$13 from "./actions/submmitForm.ts"; -import * as $$$$$$$$$14 from "./actions/wishlist/addProduct.ts"; -import * as $$$$$$$$$15 from "./actions/wishlist/removeProduct.ts"; +import * as $$$$$$$$$0 from "./actions/associateCheckout.ts"; +import * as $$$$$$$$$1 from "./actions/cart/addCoupon.ts"; +import * as $$$$$$$$$2 from "./actions/cart/addItem.ts"; +import * as $$$$$$$$$3 from "./actions/cart/addItems.ts"; +import * as $$$$$$$$$4 from "./actions/cart/addKit.ts"; +import * as $$$$$$$$$5 from "./actions/cart/partnerAssociate.ts"; +import * as $$$$$$$$$6 from "./actions/cart/partnerDisassociate.ts"; +import * as $$$$$$$$$7 from "./actions/cart/removeCoupon.ts"; +import * as $$$$$$$$$8 from "./actions/cart/removeKit.ts"; +import * as $$$$$$$$$9 from "./actions/cart/updateItemQuantity.ts"; +import * as $$$$$$$$$10 from "./actions/cloneCheckout.ts"; +import * as $$$$$$$$$11 from "./actions/completeCheckout.ts"; +import * as $$$$$$$$$12 from "./actions/createAddress.ts"; +import * as $$$$$$$$$13 from "./actions/createCheckout.ts"; +import * as $$$$$$$$$14 from "./actions/deleteAddress.ts"; +import * as $$$$$$$$$15 from "./actions/deleteCartCookie.ts"; +import * as $$$$$$$$$16 from "./actions/login.ts"; +import * as $$$$$$$$$17 from "./actions/loginGoogle.ts"; +import * as $$$$$$$$$18 from "./actions/logout.ts"; +import * as $$$$$$$$$19 from "./actions/newsletter/register.ts"; +import * as $$$$$$$$$20 from "./actions/notifyme.ts"; +import * as $$$$$$$$$21 from "./actions/recoveryPassword.ts"; +import * as $$$$$$$$$22 from "./actions/review/create.ts"; +import * as $$$$$$$$$23 from "./actions/selectAddress.ts"; +import * as $$$$$$$$$24 from "./actions/selectInstallment.ts"; +import * as $$$$$$$$$25 from "./actions/selectPayment.ts"; +import * as $$$$$$$$$26 from "./actions/selectShipping.ts"; +import * as $$$$$$$$$27 from "./actions/shippingSimulation.ts"; +import * as $$$$$$$$$28 from "./actions/signupCompany.ts"; +import * as $$$$$$$$$29 from "./actions/signupPartialCompany.ts"; +import * as $$$$$$$$$30 from "./actions/signupPartialPerson.ts"; +import * as $$$$$$$$$31 from "./actions/signupPerson.ts"; +import * as $$$$$$$$$32 from "./actions/submmitForm.ts"; +import * as $$$$$$$$$33 from "./actions/updateAddress.ts"; +import * as $$$$$$$$$34 from "./actions/wishlist/addProduct.ts"; +import * as $$$$$$$$$35 from "./actions/wishlist/removeProduct.ts"; import * as $$$$0 from "./handlers/sitemap.ts"; -import * as $$$0 from "./loaders/cart.ts"; -import * as $$$1 from "./loaders/partners.ts"; -import * as $$$2 from "./loaders/productDetailsPage.ts"; -import * as $$$3 from "./loaders/productList.ts"; -import * as $$$4 from "./loaders/productListingPage.ts"; -import * as $$$5 from "./loaders/proxy.ts"; -import * as $$$6 from "./loaders/recommendations.ts"; -import * as $$$7 from "./loaders/shop.ts"; -import * as $$$8 from "./loaders/suggestion.ts"; -import * as $$$9 from "./loaders/user.ts"; -import * as $$$10 from "./loaders/wishlist.ts"; +import * as $$$0 from "./loaders/calculatePrices.ts"; +import * as $$$1 from "./loaders/cart.ts"; +import * as $$$2 from "./loaders/checkoutCoupon.ts"; +import * as $$$3 from "./loaders/headlessCheckout.ts"; +import * as $$$4 from "./loaders/partners.ts"; +import * as $$$5 from "./loaders/paymentMethods.ts"; +import * as $$$6 from "./loaders/productCustomizations.ts"; +import * as $$$7 from "./loaders/productDetailsPage.ts"; +import * as $$$8 from "./loaders/productList.ts"; +import * as $$$9 from "./loaders/productListingPage.ts"; +import * as $$$10 from "./loaders/proxy.ts"; +import * as $$$11 from "./loaders/recommendations.ts"; +import * as $$$12 from "./loaders/shop.ts"; +import * as $$$13 from "./loaders/suggestion.ts"; +import * as $$$14 from "./loaders/user.ts"; +import * as $$$15 from "./loaders/userAddresses.ts"; +import * as $$$16 from "./loaders/wishlist.ts"; const manifest = { "loaders": { - "wake/loaders/cart.ts": $$$0, - "wake/loaders/partners.ts": $$$1, - "wake/loaders/productDetailsPage.ts": $$$2, - "wake/loaders/productList.ts": $$$3, - "wake/loaders/productListingPage.ts": $$$4, - "wake/loaders/proxy.ts": $$$5, - "wake/loaders/recommendations.ts": $$$6, - "wake/loaders/shop.ts": $$$7, - "wake/loaders/suggestion.ts": $$$8, - "wake/loaders/user.ts": $$$9, - "wake/loaders/wishlist.ts": $$$10, + "wake/loaders/calculatePrices.ts": $$$0, + "wake/loaders/cart.ts": $$$1, + "wake/loaders/checkoutCoupon.ts": $$$2, + "wake/loaders/headlessCheckout.ts": $$$3, + "wake/loaders/partners.ts": $$$4, + "wake/loaders/paymentMethods.ts": $$$5, + "wake/loaders/productCustomizations.ts": $$$6, + "wake/loaders/productDetailsPage.ts": $$$7, + "wake/loaders/productList.ts": $$$8, + "wake/loaders/productListingPage.ts": $$$9, + "wake/loaders/proxy.ts": $$$10, + "wake/loaders/recommendations.ts": $$$11, + "wake/loaders/shop.ts": $$$12, + "wake/loaders/suggestion.ts": $$$13, + "wake/loaders/user.ts": $$$14, + "wake/loaders/userAddresses.ts": $$$15, + "wake/loaders/wishlist.ts": $$$16, }, "handlers": { "wake/handlers/sitemap.ts": $$$$0, }, "actions": { - "wake/actions/cart/addCoupon.ts": $$$$$$$$$0, - "wake/actions/cart/addItem.ts": $$$$$$$$$1, - "wake/actions/cart/addItems.ts": $$$$$$$$$2, - "wake/actions/cart/addKit.ts": $$$$$$$$$3, - "wake/actions/cart/partnerAssociate.ts": $$$$$$$$$4, - "wake/actions/cart/partnerDisassociate.ts": $$$$$$$$$5, - "wake/actions/cart/removeCoupon.ts": $$$$$$$$$6, - "wake/actions/cart/removeKit.ts": $$$$$$$$$7, - "wake/actions/cart/updateItemQuantity.ts": $$$$$$$$$8, - "wake/actions/newsletter/register.ts": $$$$$$$$$9, - "wake/actions/notifyme.ts": $$$$$$$$$10, - "wake/actions/review/create.ts": $$$$$$$$$11, - "wake/actions/shippingSimulation.ts": $$$$$$$$$12, - "wake/actions/submmitForm.ts": $$$$$$$$$13, - "wake/actions/wishlist/addProduct.ts": $$$$$$$$$14, - "wake/actions/wishlist/removeProduct.ts": $$$$$$$$$15, + "wake/actions/associateCheckout.ts": $$$$$$$$$0, + "wake/actions/cart/addCoupon.ts": $$$$$$$$$1, + "wake/actions/cart/addItem.ts": $$$$$$$$$2, + "wake/actions/cart/addItems.ts": $$$$$$$$$3, + "wake/actions/cart/addKit.ts": $$$$$$$$$4, + "wake/actions/cart/partnerAssociate.ts": $$$$$$$$$5, + "wake/actions/cart/partnerDisassociate.ts": $$$$$$$$$6, + "wake/actions/cart/removeCoupon.ts": $$$$$$$$$7, + "wake/actions/cart/removeKit.ts": $$$$$$$$$8, + "wake/actions/cart/updateItemQuantity.ts": $$$$$$$$$9, + "wake/actions/cloneCheckout.ts": $$$$$$$$$10, + "wake/actions/completeCheckout.ts": $$$$$$$$$11, + "wake/actions/createAddress.ts": $$$$$$$$$12, + "wake/actions/createCheckout.ts": $$$$$$$$$13, + "wake/actions/deleteAddress.ts": $$$$$$$$$14, + "wake/actions/deleteCartCookie.ts": $$$$$$$$$15, + "wake/actions/login.ts": $$$$$$$$$16, + "wake/actions/loginGoogle.ts": $$$$$$$$$17, + "wake/actions/logout.ts": $$$$$$$$$18, + "wake/actions/newsletter/register.ts": $$$$$$$$$19, + "wake/actions/notifyme.ts": $$$$$$$$$20, + "wake/actions/recoveryPassword.ts": $$$$$$$$$21, + "wake/actions/review/create.ts": $$$$$$$$$22, + "wake/actions/selectAddress.ts": $$$$$$$$$23, + "wake/actions/selectInstallment.ts": $$$$$$$$$24, + "wake/actions/selectPayment.ts": $$$$$$$$$25, + "wake/actions/selectShipping.ts": $$$$$$$$$26, + "wake/actions/shippingSimulation.ts": $$$$$$$$$27, + "wake/actions/signupCompany.ts": $$$$$$$$$28, + "wake/actions/signupPartialCompany.ts": $$$$$$$$$29, + "wake/actions/signupPartialPerson.ts": $$$$$$$$$30, + "wake/actions/signupPerson.ts": $$$$$$$$$31, + "wake/actions/submmitForm.ts": $$$$$$$$$32, + "wake/actions/updateAddress.ts": $$$$$$$$$33, + "wake/actions/wishlist/addProduct.ts": $$$$$$$$$34, + "wake/actions/wishlist/removeProduct.ts": $$$$$$$$$35, }, "name": "wake", "baseUrl": import.meta.url, diff --git a/wake/mod.ts b/wake/mod.ts index 487197940..709b98d9d 100644 --- a/wake/mod.ts +++ b/wake/mod.ts @@ -4,9 +4,9 @@ import { createGraphqlClient } from "../utils/graphql.ts"; import { createHttpClient } from "../utils/http.ts"; import { PreviewContainer } from "../utils/preview.tsx"; import type { Secret } from "../website/loaders/secret.ts"; -import manifest, { Manifest } from "./manifest.gen.ts"; -import { CheckoutApi } from "./utils/client.ts"; -import { OpenAPI } from "./utils/openapi/wake.openapi.gen.ts"; +import manifest, { type Manifest } from "./manifest.gen.ts"; +import type { OpenAPI } from "./utils/openapi/wake.openapi.gen.ts"; +import type { CheckoutApi } from "./utils/client.ts"; import { type App, type FnContext } from "@deco/deco"; export type AppContext = FnContext; export let state: null | State = null; @@ -37,13 +37,21 @@ export interface Props { * @hide true */ platform: "wake"; + + /** + * @description Use wake headless api for checkout + */ + headlessCheckout?: boolean; } export interface State extends Props { api: ReturnType>; checkoutApi: ReturnType>; storefront: ReturnType; + headlessCheckout: boolean; } -export const color = 0xB600EE; + +export const color = 0xb600ee; + /** * @title Wake * @description Loaders, actions and workflows for adding Wake Commerce Platform to your website. @@ -51,7 +59,14 @@ export const color = 0xB600EE; * @logo https://raw.githubusercontent.com/deco-cx/apps/main/wake/logo.png */ export default function App(props: Props): App { - const { token, storefrontToken, account, checkoutUrl } = props; + const { + token, + storefrontToken, + account, + checkoutUrl, + headlessCheckout = false, + } = props; + if (!token || !storefrontToken) { console.warn( "Missing tokens for wake app. Add it into the wake app config in deco.cx admin. Some functionalities may not work", @@ -65,7 +80,7 @@ export default function App(props: Props): App { : storefrontToken?.get?.() ?? ""; const api = createHttpClient({ base: "https://api.fbits.net", - headers: new Headers({ "Authorization": `Basic ${stringToken}` }), + headers: new Headers({ Authorization: `Basic ${stringToken}` }), fetcher: fetchSafe, }); //22e714b360b7ef187fe4bdb93385dd0a85686e2a @@ -78,7 +93,9 @@ export default function App(props: Props): App { base: checkoutUrl ?? `https://${account}.checkout.fbits.store`, fetcher: fetchSafe, }); - state = { ...props, api, storefront, checkoutApi }; + + state = { ...props, api, storefront, checkoutApi, headlessCheckout }; + return { state, manifest, diff --git a/wake/runtime.ts b/wake/runtime.ts index da42a2435..7ed2e05b7 100644 --- a/wake/runtime.ts +++ b/wake/runtime.ts @@ -1,3 +1,4 @@ import { Manifest } from "./manifest.gen.ts"; import { proxy } from "@deco/deco/web"; + export const invoke = proxy(); diff --git a/wake/utils/authenticate.ts b/wake/utils/authenticate.ts index f5d3a9d08..26849febb 100644 --- a/wake/utils/authenticate.ts +++ b/wake/utils/authenticate.ts @@ -1,22 +1,62 @@ +import { getCookies } from "std/http/cookie.ts"; import type { AppContext } from "../mod.ts"; -import { getUserCookie } from "../utils/user.ts"; +import { getUserCookie, setUserCookie } from "../utils/user.ts"; +import type { + CustomerAccessTokenRenewMutation, + CustomerAccessTokenRenewMutationVariables, +} from "../utils/graphql/storefront.graphql.gen.ts"; +import { CustomerAccessTokenRenew } from "../utils/graphql/queries.ts"; +import { parseHeaders } from "../utils/parseHeaders.ts"; const authenticate = async ( req: Request, ctx: AppContext, ): Promise => { - const { checkoutApi } = ctx; + const { checkoutApi, headlessCheckout } = ctx; - const loginCookie = getUserCookie(req.headers); + if (headlessCheckout) { + const headers = parseHeaders(req.headers); + const cookies = getCookies(req.headers); + const customerToken = cookies.customerToken; + + if (!customerToken) return null; + + const { customerAccessTokenRenew } = await ctx.storefront.query< + CustomerAccessTokenRenewMutation, + CustomerAccessTokenRenewMutationVariables + >( + { + variables: { customerAccessToken: customerToken }, + ...CustomerAccessTokenRenew, + }, + { headers }, + ); + + if (!customerAccessTokenRenew) return null; + const newCustomerToken = customerAccessTokenRenew.token; + if (!newCustomerToken) return null; + + setUserCookie( + ctx.response.headers, + newCustomerToken, + cookies["fbits-login"], + new Date(customerAccessTokenRenew.validUntil), + ); + return newCustomerToken; + } + + const loginCookie = getUserCookie(req.headers); if (!loginCookie) return null; - const data = await checkoutApi - ["GET /api/Login/Get"]( - {}, - { headers: req.headers }, - ).then((r) => r.json()); + if (headlessCheckout) return loginCookie; + const data = await checkoutApi["GET /api/Login/Get"]( + {}, + { + headers: req.headers, + }, + ).then((r) => r.json()); if (!data?.CustomerAccessToken) return null; return data?.CustomerAccessToken; diff --git a/wake/utils/cart.ts b/wake/utils/cart.ts index 812220e9b..3673ffa6c 100644 --- a/wake/utils/cart.ts +++ b/wake/utils/cart.ts @@ -1,6 +1,6 @@ import { getCookies, setCookie } from "std/http/cookie.ts"; -const CART_COOKIE = "carrinho-id"; +export const CART_COOKIE = "carrinho-id"; const TEN_DAYS_MS = 10 * 24 * 3600 * 1_000; @@ -22,7 +22,7 @@ export const setClientCookie = (value: string) => { let expires = ""; const date = new Date(Date.now() + TEN_DAYS_MS); - expires = "; expires=" + date.toUTCString(); + expires = `; expires=${date.toUTCString()}`; - document.cookie = CART_COOKIE + "=" + (value || "") + expires + "; path=/"; + document.cookie = `${CART_COOKIE}=${value || ""}${expires}; path=/`; }; diff --git a/wake/utils/ensureCheckout.ts b/wake/utils/ensureCheckout.ts new file mode 100644 index 000000000..51eb2f67c --- /dev/null +++ b/wake/utils/ensureCheckout.ts @@ -0,0 +1,5 @@ +export default function (token: string | undefined) { + if (!token) console.error("No checkout cookie"); + + return token; +} diff --git a/wake/utils/ensureCustomerToken.ts b/wake/utils/ensureCustomerToken.ts new file mode 100644 index 000000000..d9d7f0a2c --- /dev/null +++ b/wake/utils/ensureCustomerToken.ts @@ -0,0 +1,7 @@ +export default function (token: string | null) { + if (!token) { + throw new Error("No customer access token cookie, are you logged in?"); + } + + return token; +} diff --git a/wake/utils/getVariations.ts b/wake/utils/getVariations.ts index 7c228c9ba..4e5cab570 100644 --- a/wake/utils/getVariations.ts +++ b/wake/utils/getVariations.ts @@ -1,5 +1,5 @@ import { GetProducts } from "../utils/graphql/queries.ts"; -import { +import type { GetProductsQuery, GetProductsQueryVariables, ProductFragment, diff --git a/wake/utils/graphql/queries.ts b/wake/utils/graphql/queries.ts index 262a04bb3..acca1ad36 100644 --- a/wake/utils/graphql/queries.ts +++ b/wake/utils/graphql/queries.ts @@ -862,7 +862,95 @@ fragment SingleProductPart on SingleProduct { stamp title } - +} +`; + +const CheckoutCloseFields = gql` +fragment CheckoutCloseFields on Checkout { + checkoutId + completed + orders { + adjustments { + name + type + value + } + date + discountValue + interestValue + orderId + orderStatus + products { + adjustments { + name + additionalInformation + type + value + } + attributes { + name + value + } + imageUrl + name + productVariantId + quantity + value + } + shippingValue + totalValue + delivery { + address { + address + cep + city + complement + name + isPickupStore + neighborhood + pickupStoreText + } + cost + deliveryTime + name + } + dispatchTimeText + payment { + invoice { + digitableLine + paymentLink + } + name + pix { + qrCode + qrCodeExpirationDate + qrCodeUrl + } + } + } +} +`; + +const SelectPayment = gql` +fragment SelectPayment on Checkout { + checkoutId + total + subtotal + selectedPaymentMethod { + id + installments { + adjustment + number + total + value + } + selectedInstallment { + adjustment + number + total + value + } + } } `; @@ -873,7 +961,6 @@ fragment SingleProduct on SingleProduct { productId } } - `; const RestockAlertNode = gql` @@ -920,6 +1007,8 @@ const ShippingQuote = gql` export const Customer = gql` fragment Customer on Customer { id + cpf + phoneNumber email gender customerId @@ -953,8 +1042,9 @@ export const GetProduct = { export const GetCart = { fragments: [Checkout], - query: gql`query GetCart($checkoutId: String!) { - checkout(checkoutId: $checkoutId) { ...Checkout } + query: + gql`query GetCart($checkoutId: String!, $customerAccessToken: String) { + checkout(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) { ...Checkout } }`, }; @@ -1327,6 +1417,281 @@ export const RemoveKit = { }`, }; +export const CalculatePrices = { + query: + gql`query calculatePrices($partnerAccessToken: String!, $products: [CalculatePricesProductsInput]!) { + calculatePrices(partnerAccessToken: $partnerAccessToken, products: $products) { + bestInstallment { + displayName + name + } + discountPercentage + discounted + installmentPlans { + displayName + name + installments{ + discount + fees + number + value + } + } + listPrice + multiplicationFactor + price + } + }`, +}; + +export const CustomerCreate = { + query: gql`mutation CustomerCreate($input: CustomerCreateInput) { + customerCreate(input: $input) { + customerId + customerName + customerType + } + }`, +}; + +export const CustomerAuthenticatedLogin = { + query: + gql`mutation customerAuthenticatedLogin($input: String!, $pass: String!) { + customerAuthenticatedLogin(input:{input: $input, password: $pass}) { + isMaster + token + legacyToken + type + validUntil + } + }`, +}; + +export const CustomerAccessTokenRenew = { + query: gql`mutation customerAccessTokenRenew($customerAccessToken: String!) { + customerAccessTokenRenew(customerAccessToken: $customerAccessToken) { + token + validUntil + } + }`, +}; + +export const CustomerAddressCreate = { + query: gql`mutation customerAddressCreate( + $customerAccessToken: String!, + $address: CreateCustomerAddressInput!, + ) { + customerAddressCreate( + customerAccessToken: $customerAccessToken, + address: $address, + ) { + addressDetails + addressNumber + cep + city + country + email + id + name + neighborhood + phone + state + street + referencePoint + } + }`, +}; + +export const CustomerAddressRemove = { + query: + gql`mutation customerAddressRemove($customerAccessToken: String!, $id: ID!) { + customerAddressRemove(customerAccessToken: $customerAccessToken, id: $id) { + isSuccess + } + }`, +}; + +export const CustomerAddressUpdate = { + query: gql`mutation customerAddressUpdate( + $id: ID!, + $customerAccessToken: String!, + $address: UpdateCustomerAddressInput!, + ) { + customerAddressUpdate( + customerAccessToken: $customerAccessToken, + address: $address, + id: $id + ) { + addressDetails + addressNumber + cep + city + country + email + id + name + neighborhood + phone + state + street + referencePoint + } + }`, +}; + +export const GetUserAddresses = { + fragments: [Customer], + query: gql`query GetUserAddresses($customerAccessToken: String) { + customer(customerAccessToken: $customerAccessToken) { + ...Customer, + addresses { + address + address2 + addressDetails + addressNumber + cep + city + country + email + id + name + neighborhood + phone + referencePoint + state + street + } + } + }`, +}; + +export const CreateCheckout = { + query: gql`mutation createCheckout($products: [CheckoutProductItemInput]!) { + createCheckout(products: $products) { + checkoutId + } + }`, +}; + +export const CheckoutCustomerAssociate = { + query: + gql`mutation checkoutCustomerAssociate($checkoutId: Uuid!, $customerAccessToken: String!) { + checkoutCustomerAssociate(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) { + checkoutId + } + }`, +}; + +export const PaymentMethods = { + query: gql`query paymentMethods($checkoutId: Uuid!) { + paymentMethods(checkoutId: $checkoutId) { + id + name + imageUrl + } + }`, +}; + +export const GetCheckoutCoupon = { + query: gql`query GetCheckoutCoupon($checkoutId: String!) { + checkout(checkoutId: $checkoutId) { + coupon + } + }`, +}; + +export const CheckoutAddressAssociate = { + query: + gql`mutation checkoutAddressAssociate($customerAccessToken: String!, $addressId: ID!, $checkoutId: Uuid!) { + checkoutAddressAssociate( + customerAccessToken: $customerAccessToken + addressId: $addressId + checkoutId: $checkoutId + ) { + cep + checkoutId + url + updateDate + } + }`, +}; + +export const CheckoutSelectShippingQuote = { + query: + gql`mutation checkoutSelectShippingQuote($checkoutId: Uuid!, $shippingQuoteId: Uuid!) { + checkoutSelectShippingQuote( + checkoutId: $checkoutId + shippingQuoteId: $shippingQuoteId + ) { + cep + checkoutId + shippingFee + selectedShipping { + deadline + name + shippingQuoteId + type + value + } + } + }`, +}; + +export const GetSelectedShipping = { + query: + gql`query GetSelectedShipping($checkoutId: String!, $customerAccessToken: String!) { + checkout(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) { + selectedShipping { + deadline + deadlineInHours + deliverySchedule { + date + endDateTime + endTime + startDateTime + startTime + } + name + shippingQuoteId + type + value + } + } + }`, +}; + +export const CheckoutComplete = { + fragments: [CheckoutCloseFields], + query: gql`mutation checkoutComplete( + $checkoutId: Uuid! + $paymentData: String! + $comments: String + $customerAccessToken: String + ) { + checkoutComplete( + checkoutId: $checkoutId + paymentData: $paymentData + comments: $comments + customerAccessToken: $customerAccessToken + ) { + ...CheckoutCloseFields + } + }`, +}; + +export const CheckoutSelectPaymentMethod = { + fragments: [SelectPayment], + query: + gql`mutation checkoutSelectPaymentMethod($checkoutId: Uuid!, $paymentMethodId: ID!) { + checkoutSelectPaymentMethod( + checkoutId: $checkoutId + paymentMethodId: $paymentMethodId + ) { + ...SelectPayment + } + }`, +}; + export const GetPartners = { query: gql`query GetPartners($first: Int,$last: Int,$names: [String],$priceTableIds: [Int!],$sortDirection: SortDirection! = ASC,$sortKey: PartnerSortKeys! = ID,$before: String,$alias: [String],$after: String) { @@ -1350,6 +1715,23 @@ export const GetPartners = { }`, }; +export const CheckoutSelectInstallment = { + fragments: [Checkout], + query: gql`mutation checkoutSelectInstallment( + $checkoutId: Uuid! + $selectedPaymentMethodId: Uuid! + $installmentNumber: Int! + ) { + checkoutSelectInstallment( + checkoutId: $checkoutId + selectedPaymentMethodId: $selectedPaymentMethodId + installmentNumber: $installmentNumber + ) { + ...Checkout + } + }`, +}; + export const CheckoutPartnerAssociate = { fragments: [Checkout], query: @@ -1360,6 +1742,74 @@ export const CheckoutPartnerAssociate = { }`, }; +export const CheckoutClone = { + query: gql`mutation checkoutClone($checkoutId: Uuid!, $copyUser: Boolean) { + checkoutClone(checkoutId: $checkoutId, copyUser: $copyUser) { + checkoutId + } + }`, +}; + +export const GetProductCustomizations = { + query: gql`query GetProductCustomizations($productId: Long!) { + product(productId: $productId) { + productName + productId + productVariantId + customizations { + customizationId + cost + name + type + values + order + groupName + maxLength + id + } + } + } + `, +}; + +export const CustomerSocialLoginGoogle = { + query: gql`mutation customerSocialLoginGoogle($userCredential: String!) { + customerSocialLoginGoogle(userCredential: $userCredential) { + isMaster + token + legacyToken + type + validUntil + } + } + `, +}; + +export const CustomerCompletePartialRegistration = { + query: + gql`mutation CompleteRegistration($customerAccessToken: String!, $input: CustomerSimpleCreateInputGraphInput!) { + customerCompletePartialRegistration( + customerAccessToken: $customerAccessToken + input: $input) { + isMaster + token + legacyToken + type + validUntil + } + }`, +}; + +export const CustomerPasswordRecovery = { + query: gql` + mutation CustomerPasswordRecovery($input: String!) { + customerPasswordRecovery(input: $input) { + isSuccess + } + } + `, +}; + export const CheckoutPartnerDisassociate = { fragments: [Checkout], query: diff --git a/wake/utils/graphql/storefront.graphql.gen.ts b/wake/utils/graphql/storefront.graphql.gen.ts index aec4c3bb9..12c46b945 100644 --- a/wake/utils/graphql/storefront.graphql.gen.ts +++ b/wake/utils/graphql/storefront.graphql.gen.ts @@ -4997,6 +4997,10 @@ export type BuyListFragment = { mainVariant?: boolean | null, productName?: stri export type SingleProductPartFragment = { mainVariant?: boolean | null, productName?: string | null, productId?: any | null, alias?: string | null, collection?: string | null, numberOfVotes?: number | null, available?: boolean | null, averageRating?: number | null, condition?: string | null, createdAt?: any | null, ean?: string | null, id?: string | null, minimumOrderQuantity?: number | null, productVariantId?: any | null, sku?: string | null, stock?: any | null, variantName?: string | null, parallelOptions?: Array | null, urlVideo?: string | null, attributes?: Array<{ name?: string | null, type?: string | null, value?: string | null, attributeId: any, displayType?: string | null, id?: string | null } | null> | null, productCategories?: Array<{ id: number, name?: string | null, url?: string | null, hierarchy?: string | null, main: boolean, googleCategories?: string | null } | null> | null, informations?: Array<{ title?: string | null, value?: string | null, type?: string | null } | null> | null, breadcrumbs?: Array<{ text?: string | null, link?: string | null } | null> | null, images?: Array<{ url?: string | null, fileName?: string | null, print: boolean } | null> | null, prices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, bestInstallment?: { discount: boolean, displayName?: string | null, fees: boolean, name?: string | null, number: number, value: any } | null, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, priceTables?: Array<{ discountPercentage: any, id: any, listPrice?: any | null, price: any } | null> | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null } | null, productBrand?: { fullUrlLogo?: string | null, logoUrl?: string | null, name?: string | null, alias?: string | null } | null, seller?: { name?: string | null } | null, seo?: Array<{ name?: string | null, scheme?: string | null, type?: string | null, httpEquiv?: string | null, content?: string | null } | null> | null, reviews?: Array<{ rating: number, review?: string | null, reviewDate: any, email?: string | null, customer?: string | null } | null> | null, similarProducts?: Array<{ alias?: string | null, image?: string | null, imageUrl?: string | null, name?: string | null } | null> | null, attributeSelections?: { canBeMatrix: boolean, selections?: Array<{ attributeId: any, displayType?: string | null, name?: string | null, varyByParent: boolean, values?: Array<{ alias?: string | null, available: boolean, value?: string | null, selected: boolean, printUrl?: string | null } | null> | null } | null> | null, matrix?: { column?: { displayType?: string | null, name?: string | null, values?: Array<{ value?: string | null } | null> | null } | null, data?: Array | null> | null, row?: { displayType?: string | null, name?: string | null, values?: Array<{ value?: string | null, printUrl?: string | null } | null> | null } | null } | null, selectedVariant?: { aggregatedStock?: any | null, alias?: string | null, available?: boolean | null, ean?: string | null, id?: string | null, productId?: any | null, productVariantId?: any | null, productVariantName?: string | null, sku?: string | null, stock?: any | null, attributes?: Array<{ attributeId: any, displayType?: string | null, id?: string | null, name?: string | null, type?: string | null, value?: string | null } | null> | null, images?: Array<{ fileName?: string | null, mini: boolean, order: number, print: boolean, url?: string | null } | null> | null, prices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, priceTables?: Array<{ discountPercentage: any, id: any, listPrice?: any | null, price: any } | null> | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null, bestInstallment?: { discount: boolean, displayName?: string | null, fees: boolean, name?: string | null, number: number, value: any } | null } | null, offers?: Array<{ name?: string | null, productVariantId?: any | null, prices?: { listPrice?: any | null, price?: any | null, installmentPlans?: Array<{ displayName?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null } | null } | null> | null, promotions?: Array<{ content?: string | null, disclosureType?: string | null, id: any, fullStampUrl?: string | null, stamp?: string | null, title?: string | null } | null> | null } | null, candidateVariant?: { aggregatedStock?: any | null, alias?: string | null, available?: boolean | null, ean?: string | null, id?: string | null, productId?: any | null, productVariantId?: any | null, productVariantName?: string | null, sku?: string | null, stock?: any | null, attributes?: Array<{ attributeId: any, displayType?: string | null, id?: string | null, name?: string | null, type?: string | null, value?: string | null } | null> | null, images?: Array<{ fileName?: string | null, mini: boolean, order: number, print: boolean, url?: string | null } | null> | null, prices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, priceTables?: Array<{ discountPercentage: any, id: any, listPrice?: any | null, price: any } | null> | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null, bestInstallment?: { discount: boolean, displayName?: string | null, fees: boolean, name?: string | null, number: number, value: any } | null } | null, offers?: Array<{ name?: string | null, productVariantId?: any | null, prices?: { listPrice?: any | null, price?: any | null, installmentPlans?: Array<{ displayName?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null } | null } | null> | null, promotions?: Array<{ content?: string | null, disclosureType?: string | null, id: any, fullStampUrl?: string | null, stamp?: string | null, title?: string | null } | null> | null } | null } | null, promotions?: Array<{ content?: string | null, disclosureType?: string | null, id: any, fullStampUrl?: string | null, stamp?: string | null, title?: string | null } | null> | null }; +export type CheckoutCloseFieldsFragment = { checkoutId: any, completed: boolean, orders?: Array<{ date: any, discountValue: any, interestValue: any, orderId: any, orderStatus: OrderStatus, shippingValue: any, totalValue: any, dispatchTimeText?: string | null, adjustments?: Array<{ name?: string | null, type?: string | null, value: any } | null> | null, products?: Array<{ imageUrl?: string | null, name?: string | null, productVariantId: any, quantity: number, value: any, adjustments?: Array<{ name?: string | null, additionalInformation?: string | null, type?: string | null, value: any } | null> | null, attributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null, delivery?: { cost: any, deliveryTime: number, name?: string | null, address?: { address?: string | null, cep?: string | null, city?: string | null, complement?: string | null, name?: string | null, isPickupStore: boolean, neighborhood?: string | null, pickupStoreText?: string | null } | null } | null, payment?: { name?: string | null, invoice?: { digitableLine?: string | null, paymentLink?: string | null } | null, pix?: { qrCode?: string | null, qrCodeExpirationDate?: any | null, qrCodeUrl?: string | null } | null } | null } | null> | null }; + +export type SelectPaymentFragment = { checkoutId: any, total: any, subtotal: any, selectedPaymentMethod?: { id: any, installments?: Array<{ adjustment: number, number: number, total: number, value: number } | null> | null, selectedInstallment?: { adjustment: number, number: number, total: number, value: number } | null } | null }; + export type SingleProductFragment = { mainVariant?: boolean | null, productName?: string | null, productId?: any | null, alias?: string | null, collection?: string | null, numberOfVotes?: number | null, available?: boolean | null, averageRating?: number | null, condition?: string | null, createdAt?: any | null, ean?: string | null, id?: string | null, minimumOrderQuantity?: number | null, productVariantId?: any | null, sku?: string | null, stock?: any | null, variantName?: string | null, parallelOptions?: Array | null, urlVideo?: string | null, buyTogether?: Array<{ productId?: any | null } | null> | null, attributes?: Array<{ name?: string | null, type?: string | null, value?: string | null, attributeId: any, displayType?: string | null, id?: string | null } | null> | null, productCategories?: Array<{ id: number, name?: string | null, url?: string | null, hierarchy?: string | null, main: boolean, googleCategories?: string | null } | null> | null, informations?: Array<{ title?: string | null, value?: string | null, type?: string | null } | null> | null, breadcrumbs?: Array<{ text?: string | null, link?: string | null } | null> | null, images?: Array<{ url?: string | null, fileName?: string | null, print: boolean } | null> | null, prices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, bestInstallment?: { discount: boolean, displayName?: string | null, fees: boolean, name?: string | null, number: number, value: any } | null, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, priceTables?: Array<{ discountPercentage: any, id: any, listPrice?: any | null, price: any } | null> | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null } | null, productBrand?: { fullUrlLogo?: string | null, logoUrl?: string | null, name?: string | null, alias?: string | null } | null, seller?: { name?: string | null } | null, seo?: Array<{ name?: string | null, scheme?: string | null, type?: string | null, httpEquiv?: string | null, content?: string | null } | null> | null, reviews?: Array<{ rating: number, review?: string | null, reviewDate: any, email?: string | null, customer?: string | null } | null> | null, similarProducts?: Array<{ alias?: string | null, image?: string | null, imageUrl?: string | null, name?: string | null } | null> | null, attributeSelections?: { canBeMatrix: boolean, selections?: Array<{ attributeId: any, displayType?: string | null, name?: string | null, varyByParent: boolean, values?: Array<{ alias?: string | null, available: boolean, value?: string | null, selected: boolean, printUrl?: string | null } | null> | null } | null> | null, matrix?: { column?: { displayType?: string | null, name?: string | null, values?: Array<{ value?: string | null } | null> | null } | null, data?: Array | null> | null, row?: { displayType?: string | null, name?: string | null, values?: Array<{ value?: string | null, printUrl?: string | null } | null> | null } | null } | null, selectedVariant?: { aggregatedStock?: any | null, alias?: string | null, available?: boolean | null, ean?: string | null, id?: string | null, productId?: any | null, productVariantId?: any | null, productVariantName?: string | null, sku?: string | null, stock?: any | null, attributes?: Array<{ attributeId: any, displayType?: string | null, id?: string | null, name?: string | null, type?: string | null, value?: string | null } | null> | null, images?: Array<{ fileName?: string | null, mini: boolean, order: number, print: boolean, url?: string | null } | null> | null, prices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, priceTables?: Array<{ discountPercentage: any, id: any, listPrice?: any | null, price: any } | null> | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null, bestInstallment?: { discount: boolean, displayName?: string | null, fees: boolean, name?: string | null, number: number, value: any } | null } | null, offers?: Array<{ name?: string | null, productVariantId?: any | null, prices?: { listPrice?: any | null, price?: any | null, installmentPlans?: Array<{ displayName?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null } | null } | null> | null, promotions?: Array<{ content?: string | null, disclosureType?: string | null, id: any, fullStampUrl?: string | null, stamp?: string | null, title?: string | null } | null> | null } | null, candidateVariant?: { aggregatedStock?: any | null, alias?: string | null, available?: boolean | null, ean?: string | null, id?: string | null, productId?: any | null, productVariantId?: any | null, productVariantName?: string | null, sku?: string | null, stock?: any | null, attributes?: Array<{ attributeId: any, displayType?: string | null, id?: string | null, name?: string | null, type?: string | null, value?: string | null } | null> | null, images?: Array<{ fileName?: string | null, mini: boolean, order: number, print: boolean, url?: string | null } | null> | null, prices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, priceTables?: Array<{ discountPercentage: any, id: any, listPrice?: any | null, price: any } | null> | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null, bestInstallment?: { discount: boolean, displayName?: string | null, fees: boolean, name?: string | null, number: number, value: any } | null } | null, offers?: Array<{ name?: string | null, productVariantId?: any | null, prices?: { listPrice?: any | null, price?: any | null, installmentPlans?: Array<{ displayName?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null } | null } | null> | null, promotions?: Array<{ content?: string | null, disclosureType?: string | null, id: any, fullStampUrl?: string | null, stamp?: string | null, title?: string | null } | null> | null } | null } | null, promotions?: Array<{ content?: string | null, disclosureType?: string | null, id: any, fullStampUrl?: string | null, stamp?: string | null, title?: string | null } | null> | null }; export type RestockAlertNodeFragment = { email?: string | null, name?: string | null, productVariantId: any, requestDate: any }; @@ -5005,7 +5009,7 @@ export type NewsletterNodeFragment = { email?: string | null, name?: string | nu export type ShippingQuoteFragment = { id?: string | null, type?: string | null, name?: string | null, value: number, deadline: number, shippingQuoteId: any, deliverySchedules?: Array<{ date: any, periods?: Array<{ end?: string | null, id: any, start?: string | null } | null> | null } | null> | null, products?: Array<{ productVariantId: number, value: number } | null> | null }; -export type CustomerFragment = { id?: string | null, email?: string | null, gender?: string | null, customerId: any, companyName?: string | null, customerName?: string | null, customerType?: string | null, responsibleName?: string | null, informationGroups?: Array<{ exibitionName?: string | null, name?: string | null } | null> | null }; +export type CustomerFragment = { id?: string | null, cpf?: string | null, phoneNumber?: string | null, email?: string | null, gender?: string | null, customerId: any, companyName?: string | null, customerName?: string | null, customerType?: string | null, responsibleName?: string | null, informationGroups?: Array<{ exibitionName?: string | null, name?: string | null } | null> | null }; export type WishlistReducedProductFragment = { productId?: any | null, productName?: string | null }; @@ -5019,6 +5023,7 @@ export type GetProductQuery = { product?: { mainVariant?: boolean | null, produc export type GetCartQueryVariables = Exact<{ checkoutId: Scalars['String']['input']; + customerAccessToken?: InputMaybe; }>; @@ -5151,7 +5156,7 @@ export type GetUserQueryVariables = Exact<{ }>; -export type GetUserQuery = { customer?: { id?: string | null, email?: string | null, gender?: string | null, customerId: any, companyName?: string | null, customerName?: string | null, customerType?: string | null, responsibleName?: string | null, informationGroups?: Array<{ exibitionName?: string | null, name?: string | null } | null> | null } | null }; +export type GetUserQuery = { customer?: { id?: string | null, cpf?: string | null, phoneNumber?: string | null, email?: string | null, gender?: string | null, customerId: any, companyName?: string | null, customerName?: string | null, customerType?: string | null, responsibleName?: string | null, informationGroups?: Array<{ exibitionName?: string | null, name?: string | null } | null> | null } | null }; export type GetWishlistQueryVariables = Exact<{ customerAccessToken?: InputMaybe; @@ -5241,6 +5246,140 @@ export type RemoveKitMutationVariables = Exact<{ export type RemoveKitMutation = { checkout?: { checkoutId: any, shippingFee: any, subtotal: any, total: any, completed: boolean, coupon?: string | null, customer?: { customerId: any } | null, products?: Array<{ imageUrl?: string | null, brand?: string | null, ajustedPrice: any, listPrice: any, totalListPrice: any, totalAdjustedPrice: any, price: any, name?: string | null, productId: any, productVariantId: any, quantity: number, sku?: string | null, url?: string | null, category?: string | null, kit: boolean, gift: boolean, productAttributes?: Array<{ name?: string | null, type: number, value?: string | null } | null> | null, adjustments?: Array<{ observation?: string | null, type?: string | null, value: any } | null> | null, subscription?: { availableSubscriptions?: Array<{ name?: string | null, recurringDays: number, recurringTypeId: any, selected: boolean, subscriptionGroupDiscount: any, subscriptionGroupId: any } | null> | null, selected?: { selected: boolean, name?: string | null, recurringDays: number, recurringTypeId: any, subscriptionGroupDiscount: any, subscriptionGroupId: any } | null } | null, customization?: { id?: string | null, availableCustomizations?: Array<{ cost: any, customizationId: any, groupName?: string | null, id?: string | null, maxLength: number, name?: string | null, order: number, type?: string | null, values?: Array | null } | null> | null, values?: Array<{ cost: any, name?: string | null, value?: string | null } | null> | null } | null, attributeSelections?: { selectedVariant?: { id?: string | null, alias?: string | null, available?: boolean | null, productId?: any | null, productVariantId?: any | null, stock?: any | null, images?: Array<{ fileName?: string | null, url?: string | null } | null> | null, prices?: { listPrice?: any | null, price: any, discountPercentage: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, bestInstallment?: { name?: string | null, displayName?: string | null, discount: boolean, fees: boolean, number: number, value: any } | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null } | null } | null, selections?: Array<{ attributeId: any, displayType?: string | null, name?: string | null, varyByParent: boolean, values?: Array<{ alias?: string | null, available: boolean, printUrl?: string | null, selected: boolean, value?: string | null } | null> | null } | null> | null } | null } | null> | null, selectedAddress?: { addressNumber?: string | null, cep: number, city?: string | null, complement?: string | null, id?: string | null, neighborhood?: string | null, referencePoint?: string | null, state?: string | null, street?: string | null } | null, selectedShipping?: { deadline: number, deadlineInHours?: number | null, name?: string | null, shippingQuoteId: any, type?: string | null, value: number, deliverySchedule?: { date?: string | null, endDateTime: any, endTime?: string | null, startDateTime: any, startTime?: string | null } | null } | null, selectedPaymentMethod?: { html?: string | null, id: any, paymentMethodId?: string | null, scripts?: Array | null, installments?: Array<{ adjustment: number, number: number, total: number, value: number } | null> | null, selectedInstallment?: { adjustment: number, number: number, total: number, value: number } | null, suggestedCards?: Array<{ brand?: string | null, key?: string | null, name?: string | null, number?: string | null } | null> | null } | null, orders?: Array<{ date: any, discountValue: any, dispatchTimeText?: string | null, interestValue: any, orderId: any, orderStatus: OrderStatus, shippingValue: any, totalValue: any, adjustments?: Array<{ name?: string | null, type?: string | null, value: any } | null> | null, delivery?: { cost: any, deliveryTime: number, deliveryTimeInHours?: number | null, name?: string | null, address?: { address?: string | null, cep?: string | null, city?: string | null, complement?: string | null, isPickupStore: boolean, name?: string | null, neighborhood?: string | null, pickupStoreText?: string | null } | null } | null, payment?: { name?: string | null, card?: { brand?: string | null, cardInterest: any, installments: number, name?: string | null, number?: string | null } | null, invoice?: { digitableLine?: string | null, paymentLink?: string | null } | null, pix?: { qrCode?: string | null, qrCodeExpirationDate?: any | null, qrCodeUrl?: string | null } | null } | null, products?: Array<{ imageUrl?: string | null, name?: string | null, productVariantId: any, quantity: number, unitValue: any, value: any, adjustments?: Array<{ additionalInformation?: string | null, name?: string | null, type?: string | null, value: any } | null> | null, attributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null } | null> | null, kits?: Array<{ kitId: any, kitGroupId?: string | null, alias?: string | null, imageUrl?: string | null, listPrice: any, price: any, totalListPrice: any, totalAdjustedPrice: any, name?: string | null, quantity: number, products?: Array<{ productId: any, productVariantId: any, imageUrl?: string | null, name?: string | null, url?: string | null, quantity: number, productAttributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null } | null> | null } | null }; +export type CalculatePricesQueryVariables = Exact<{ + partnerAccessToken: Scalars['String']['input']; + products: Array> | InputMaybe; +}>; + + +export type CalculatePricesQuery = { calculatePrices?: { discountPercentage: any, discounted: boolean, listPrice?: any | null, multiplicationFactor: number, price: any, bestInstallment?: { displayName?: string | null, name?: string | null } | null, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null } | null }; + +export type CustomerCreateMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type CustomerCreateMutation = { customerCreate?: { customerId: any, customerName?: string | null, customerType?: string | null } | null }; + +export type CustomerAuthenticatedLoginMutationVariables = Exact<{ + input: Scalars['String']['input']; + pass: Scalars['String']['input']; +}>; + + +export type CustomerAuthenticatedLoginMutation = { customerAuthenticatedLogin?: { isMaster: boolean, token?: string | null, legacyToken?: string | null, type?: LoginType | null, validUntil: any } | null }; + +export type CustomerAccessTokenRenewMutationVariables = Exact<{ + customerAccessToken: Scalars['String']['input']; +}>; + + +export type CustomerAccessTokenRenewMutation = { customerAccessTokenRenew?: { token?: string | null, validUntil: any } | null }; + +export type CustomerAddressCreateMutationVariables = Exact<{ + customerAccessToken: Scalars['String']['input']; + address: CreateCustomerAddressInput; +}>; + + +export type CustomerAddressCreateMutation = { customerAddressCreate?: { addressDetails?: string | null, addressNumber?: string | null, cep?: string | null, city?: string | null, country?: string | null, email?: string | null, id?: string | null, name?: string | null, neighborhood?: string | null, phone?: string | null, state?: string | null, street?: string | null, referencePoint?: string | null } | null }; + +export type CustomerAddressRemoveMutationVariables = Exact<{ + customerAccessToken: Scalars['String']['input']; + id: Scalars['ID']['input']; +}>; + + +export type CustomerAddressRemoveMutation = { customerAddressRemove?: { isSuccess: boolean } | null }; + +export type CustomerAddressUpdateMutationVariables = Exact<{ + id: Scalars['ID']['input']; + customerAccessToken: Scalars['String']['input']; + address: UpdateCustomerAddressInput; +}>; + + +export type CustomerAddressUpdateMutation = { customerAddressUpdate?: { addressDetails?: string | null, addressNumber?: string | null, cep?: string | null, city?: string | null, country?: string | null, email?: string | null, id?: string | null, name?: string | null, neighborhood?: string | null, phone?: string | null, state?: string | null, street?: string | null, referencePoint?: string | null } | null }; + +export type GetUserAddressesQueryVariables = Exact<{ + customerAccessToken?: InputMaybe; +}>; + + +export type GetUserAddressesQuery = { customer?: { id?: string | null, cpf?: string | null, phoneNumber?: string | null, email?: string | null, gender?: string | null, customerId: any, companyName?: string | null, customerName?: string | null, customerType?: string | null, responsibleName?: string | null, addresses?: Array<{ address?: string | null, address2?: string | null, addressDetails?: string | null, addressNumber?: string | null, cep?: string | null, city?: string | null, country?: string | null, email?: string | null, id?: string | null, name?: string | null, neighborhood?: string | null, phone?: string | null, referencePoint?: string | null, state?: string | null, street?: string | null } | null> | null, informationGroups?: Array<{ exibitionName?: string | null, name?: string | null } | null> | null } | null }; + +export type CreateCheckoutMutationVariables = Exact<{ + products: Array> | InputMaybe; +}>; + + +export type CreateCheckoutMutation = { createCheckout?: { checkoutId: any } | null }; + +export type CheckoutCustomerAssociateMutationVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; + customerAccessToken: Scalars['String']['input']; +}>; + + +export type CheckoutCustomerAssociateMutation = { checkoutCustomerAssociate?: { checkoutId: any } | null }; + +export type PaymentMethodsQueryVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; +}>; + + +export type PaymentMethodsQuery = { paymentMethods?: Array<{ id?: string | null, name?: string | null, imageUrl?: string | null } | null> | null }; + +export type GetCheckoutCouponQueryVariables = Exact<{ + checkoutId: Scalars['String']['input']; +}>; + + +export type GetCheckoutCouponQuery = { checkout?: { coupon?: string | null } | null }; + +export type CheckoutAddressAssociateMutationVariables = Exact<{ + customerAccessToken: Scalars['String']['input']; + addressId: Scalars['ID']['input']; + checkoutId: Scalars['Uuid']['input']; +}>; + + +export type CheckoutAddressAssociateMutation = { checkoutAddressAssociate?: { cep?: number | null, checkoutId: any, url?: string | null, updateDate: any } | null }; + +export type CheckoutSelectShippingQuoteMutationVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; + shippingQuoteId: Scalars['Uuid']['input']; +}>; + + +export type CheckoutSelectShippingQuoteMutation = { checkoutSelectShippingQuote?: { cep?: number | null, checkoutId: any, shippingFee: any, selectedShipping?: { deadline: number, name?: string | null, shippingQuoteId: any, type?: string | null, value: number } | null } | null }; + +export type GetSelectedShippingQueryVariables = Exact<{ + checkoutId: Scalars['String']['input']; + customerAccessToken: Scalars['String']['input']; +}>; + + +export type GetSelectedShippingQuery = { checkout?: { selectedShipping?: { deadline: number, deadlineInHours?: number | null, name?: string | null, shippingQuoteId: any, type?: string | null, value: number, deliverySchedule?: { date?: string | null, endDateTime: any, endTime?: string | null, startDateTime: any, startTime?: string | null } | null } | null } | null }; + +export type CheckoutCompleteMutationVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; + paymentData: Scalars['String']['input']; + comments?: InputMaybe; + customerAccessToken?: InputMaybe; +}>; + + +export type CheckoutCompleteMutation = { checkoutComplete?: { checkoutId: any, completed: boolean, orders?: Array<{ date: any, discountValue: any, interestValue: any, orderId: any, orderStatus: OrderStatus, shippingValue: any, totalValue: any, dispatchTimeText?: string | null, adjustments?: Array<{ name?: string | null, type?: string | null, value: any } | null> | null, products?: Array<{ imageUrl?: string | null, name?: string | null, productVariantId: any, quantity: number, value: any, adjustments?: Array<{ name?: string | null, additionalInformation?: string | null, type?: string | null, value: any } | null> | null, attributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null, delivery?: { cost: any, deliveryTime: number, name?: string | null, address?: { address?: string | null, cep?: string | null, city?: string | null, complement?: string | null, name?: string | null, isPickupStore: boolean, neighborhood?: string | null, pickupStoreText?: string | null } | null } | null, payment?: { name?: string | null, invoice?: { digitableLine?: string | null, paymentLink?: string | null } | null, pix?: { qrCode?: string | null, qrCodeExpirationDate?: any | null, qrCodeUrl?: string | null } | null } | null } | null> | null } | null }; + +export type CheckoutSelectPaymentMethodMutationVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; + paymentMethodId: Scalars['ID']['input']; +}>; + + +export type CheckoutSelectPaymentMethodMutation = { checkoutSelectPaymentMethod?: { checkoutId: any, total: any, subtotal: any, selectedPaymentMethod?: { id: any, installments?: Array<{ adjustment: number, number: number, total: number, value: number } | null> | null, selectedInstallment?: { adjustment: number, number: number, total: number, value: number } | null } | null } | null }; + export type GetPartnersQueryVariables = Exact<{ first?: InputMaybe; last?: InputMaybe; @@ -5256,6 +5395,15 @@ export type GetPartnersQueryVariables = Exact<{ export type GetPartnersQuery = { partners?: { edges?: Array<{ node?: { partnerId: any, priceTableId: number, portfolioId: number, type?: string | null, startDate: any, endDate: any, name?: string | null, alias?: string | null, fullUrlLogo?: string | null, origin?: string | null, partnerAccessToken?: string | null } | null }> | null } | null }; +export type CheckoutSelectInstallmentMutationVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; + selectedPaymentMethodId: Scalars['Uuid']['input']; + installmentNumber: Scalars['Int']['input']; +}>; + + +export type CheckoutSelectInstallmentMutation = { checkoutSelectInstallment?: { checkoutId: any, shippingFee: any, subtotal: any, total: any, completed: boolean, coupon?: string | null, customer?: { customerId: any } | null, products?: Array<{ imageUrl?: string | null, brand?: string | null, ajustedPrice: any, listPrice: any, totalListPrice: any, totalAdjustedPrice: any, price: any, name?: string | null, productId: any, productVariantId: any, quantity: number, sku?: string | null, url?: string | null, category?: string | null, kit: boolean, gift: boolean, productAttributes?: Array<{ name?: string | null, type: number, value?: string | null } | null> | null, adjustments?: Array<{ observation?: string | null, type?: string | null, value: any } | null> | null, subscription?: { availableSubscriptions?: Array<{ name?: string | null, recurringDays: number, recurringTypeId: any, selected: boolean, subscriptionGroupDiscount: any, subscriptionGroupId: any } | null> | null, selected?: { selected: boolean, name?: string | null, recurringDays: number, recurringTypeId: any, subscriptionGroupDiscount: any, subscriptionGroupId: any } | null } | null, customization?: { id?: string | null, availableCustomizations?: Array<{ cost: any, customizationId: any, groupName?: string | null, id?: string | null, maxLength: number, name?: string | null, order: number, type?: string | null, values?: Array | null } | null> | null, values?: Array<{ cost: any, name?: string | null, value?: string | null } | null> | null } | null, attributeSelections?: { selectedVariant?: { id?: string | null, alias?: string | null, available?: boolean | null, productId?: any | null, productVariantId?: any | null, stock?: any | null, images?: Array<{ fileName?: string | null, url?: string | null } | null> | null, prices?: { listPrice?: any | null, price: any, discountPercentage: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, bestInstallment?: { name?: string | null, displayName?: string | null, discount: boolean, fees: boolean, number: number, value: any } | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null } | null } | null, selections?: Array<{ attributeId: any, displayType?: string | null, name?: string | null, varyByParent: boolean, values?: Array<{ alias?: string | null, available: boolean, printUrl?: string | null, selected: boolean, value?: string | null } | null> | null } | null> | null } | null } | null> | null, selectedAddress?: { addressNumber?: string | null, cep: number, city?: string | null, complement?: string | null, id?: string | null, neighborhood?: string | null, referencePoint?: string | null, state?: string | null, street?: string | null } | null, selectedShipping?: { deadline: number, deadlineInHours?: number | null, name?: string | null, shippingQuoteId: any, type?: string | null, value: number, deliverySchedule?: { date?: string | null, endDateTime: any, endTime?: string | null, startDateTime: any, startTime?: string | null } | null } | null, selectedPaymentMethod?: { html?: string | null, id: any, paymentMethodId?: string | null, scripts?: Array | null, installments?: Array<{ adjustment: number, number: number, total: number, value: number } | null> | null, selectedInstallment?: { adjustment: number, number: number, total: number, value: number } | null, suggestedCards?: Array<{ brand?: string | null, key?: string | null, name?: string | null, number?: string | null } | null> | null } | null, orders?: Array<{ date: any, discountValue: any, dispatchTimeText?: string | null, interestValue: any, orderId: any, orderStatus: OrderStatus, shippingValue: any, totalValue: any, adjustments?: Array<{ name?: string | null, type?: string | null, value: any } | null> | null, delivery?: { cost: any, deliveryTime: number, deliveryTimeInHours?: number | null, name?: string | null, address?: { address?: string | null, cep?: string | null, city?: string | null, complement?: string | null, isPickupStore: boolean, name?: string | null, neighborhood?: string | null, pickupStoreText?: string | null } | null } | null, payment?: { name?: string | null, card?: { brand?: string | null, cardInterest: any, installments: number, name?: string | null, number?: string | null } | null, invoice?: { digitableLine?: string | null, paymentLink?: string | null } | null, pix?: { qrCode?: string | null, qrCodeExpirationDate?: any | null, qrCodeUrl?: string | null } | null } | null, products?: Array<{ imageUrl?: string | null, name?: string | null, productVariantId: any, quantity: number, unitValue: any, value: any, adjustments?: Array<{ additionalInformation?: string | null, name?: string | null, type?: string | null, value: any } | null> | null, attributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null } | null> | null, kits?: Array<{ kitId: any, kitGroupId?: string | null, alias?: string | null, imageUrl?: string | null, listPrice: any, price: any, totalListPrice: any, totalAdjustedPrice: any, name?: string | null, quantity: number, products?: Array<{ productId: any, productVariantId: any, imageUrl?: string | null, name?: string | null, url?: string | null, quantity: number, productAttributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null } | null> | null } | null }; + export type CheckoutPartnerAssociateMutationVariables = Exact<{ checkoutId: Scalars['Uuid']['input']; customerAccessToken?: InputMaybe; @@ -5265,6 +5413,43 @@ export type CheckoutPartnerAssociateMutationVariables = Exact<{ export type CheckoutPartnerAssociateMutation = { checkout?: { checkoutId: any, shippingFee: any, subtotal: any, total: any, completed: boolean, coupon?: string | null, customer?: { customerId: any } | null, products?: Array<{ imageUrl?: string | null, brand?: string | null, ajustedPrice: any, listPrice: any, totalListPrice: any, totalAdjustedPrice: any, price: any, name?: string | null, productId: any, productVariantId: any, quantity: number, sku?: string | null, url?: string | null, category?: string | null, kit: boolean, gift: boolean, productAttributes?: Array<{ name?: string | null, type: number, value?: string | null } | null> | null, adjustments?: Array<{ observation?: string | null, type?: string | null, value: any } | null> | null, subscription?: { availableSubscriptions?: Array<{ name?: string | null, recurringDays: number, recurringTypeId: any, selected: boolean, subscriptionGroupDiscount: any, subscriptionGroupId: any } | null> | null, selected?: { selected: boolean, name?: string | null, recurringDays: number, recurringTypeId: any, subscriptionGroupDiscount: any, subscriptionGroupId: any } | null } | null, customization?: { id?: string | null, availableCustomizations?: Array<{ cost: any, customizationId: any, groupName?: string | null, id?: string | null, maxLength: number, name?: string | null, order: number, type?: string | null, values?: Array | null } | null> | null, values?: Array<{ cost: any, name?: string | null, value?: string | null } | null> | null } | null, attributeSelections?: { selectedVariant?: { id?: string | null, alias?: string | null, available?: boolean | null, productId?: any | null, productVariantId?: any | null, stock?: any | null, images?: Array<{ fileName?: string | null, url?: string | null } | null> | null, prices?: { listPrice?: any | null, price: any, discountPercentage: any, installmentPlans?: Array<{ displayName?: string | null, name?: string | null, installments?: Array<{ discount: boolean, fees: boolean, number: number, value: any } | null> | null } | null> | null, bestInstallment?: { name?: string | null, displayName?: string | null, discount: boolean, fees: boolean, number: number, value: any } | null, wholesalePrices?: Array<{ price: any, quantity: number } | null> | null } | null } | null, selections?: Array<{ attributeId: any, displayType?: string | null, name?: string | null, varyByParent: boolean, values?: Array<{ alias?: string | null, available: boolean, printUrl?: string | null, selected: boolean, value?: string | null } | null> | null } | null> | null } | null } | null> | null, selectedAddress?: { addressNumber?: string | null, cep: number, city?: string | null, complement?: string | null, id?: string | null, neighborhood?: string | null, referencePoint?: string | null, state?: string | null, street?: string | null } | null, selectedShipping?: { deadline: number, deadlineInHours?: number | null, name?: string | null, shippingQuoteId: any, type?: string | null, value: number, deliverySchedule?: { date?: string | null, endDateTime: any, endTime?: string | null, startDateTime: any, startTime?: string | null } | null } | null, selectedPaymentMethod?: { html?: string | null, id: any, paymentMethodId?: string | null, scripts?: Array | null, installments?: Array<{ adjustment: number, number: number, total: number, value: number } | null> | null, selectedInstallment?: { adjustment: number, number: number, total: number, value: number } | null, suggestedCards?: Array<{ brand?: string | null, key?: string | null, name?: string | null, number?: string | null } | null> | null } | null, orders?: Array<{ date: any, discountValue: any, dispatchTimeText?: string | null, interestValue: any, orderId: any, orderStatus: OrderStatus, shippingValue: any, totalValue: any, adjustments?: Array<{ name?: string | null, type?: string | null, value: any } | null> | null, delivery?: { cost: any, deliveryTime: number, deliveryTimeInHours?: number | null, name?: string | null, address?: { address?: string | null, cep?: string | null, city?: string | null, complement?: string | null, isPickupStore: boolean, name?: string | null, neighborhood?: string | null, pickupStoreText?: string | null } | null } | null, payment?: { name?: string | null, card?: { brand?: string | null, cardInterest: any, installments: number, name?: string | null, number?: string | null } | null, invoice?: { digitableLine?: string | null, paymentLink?: string | null } | null, pix?: { qrCode?: string | null, qrCodeExpirationDate?: any | null, qrCodeUrl?: string | null } | null } | null, products?: Array<{ imageUrl?: string | null, name?: string | null, productVariantId: any, quantity: number, unitValue: any, value: any, adjustments?: Array<{ additionalInformation?: string | null, name?: string | null, type?: string | null, value: any } | null> | null, attributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null } | null> | null, kits?: Array<{ kitId: any, kitGroupId?: string | null, alias?: string | null, imageUrl?: string | null, listPrice: any, price: any, totalListPrice: any, totalAdjustedPrice: any, name?: string | null, quantity: number, products?: Array<{ productId: any, productVariantId: any, imageUrl?: string | null, name?: string | null, url?: string | null, quantity: number, productAttributes?: Array<{ name?: string | null, value?: string | null } | null> | null } | null> | null } | null> | null } | null }; +export type CheckoutCloneMutationVariables = Exact<{ + checkoutId: Scalars['Uuid']['input']; + copyUser?: InputMaybe; +}>; + + +export type CheckoutCloneMutation = { checkoutClone?: { checkoutId: any } | null }; + +export type GetProductCustomizationsQueryVariables = Exact<{ + productId: Scalars['Long']['input']; +}>; + + +export type GetProductCustomizationsQuery = { product?: { productName?: string | null, productId?: any | null, productVariantId?: any | null, customizations?: Array<{ customizationId: any, cost: any, name?: string | null, type?: string | null, values?: Array | null, order: number, groupName?: string | null, maxLength: number, id?: string | null } | null> | null } | null }; + +export type CustomerSocialLoginGoogleMutationVariables = Exact<{ + userCredential: Scalars['String']['input']; +}>; + + +export type CustomerSocialLoginGoogleMutation = { customerSocialLoginGoogle?: { isMaster: boolean, token?: string | null, legacyToken?: string | null, type?: LoginType | null, validUntil: any } | null }; + +export type CompleteRegistrationMutationVariables = Exact<{ + customerAccessToken: Scalars['String']['input']; + input: CustomerSimpleCreateInputGraphInput; +}>; + + +export type CompleteRegistrationMutation = { customerCompletePartialRegistration?: { isMaster: boolean, token?: string | null, legacyToken?: string | null, type?: LoginType | null, validUntil: any } | null }; + +export type CustomerPasswordRecoveryMutationVariables = Exact<{ + input: Scalars['String']['input']; +}>; + + +export type CustomerPasswordRecoveryMutation = { customerPasswordRecovery?: { isSuccess: boolean } | null }; + export type CheckoutPartnerDisassociateMutationVariables = Exact<{ checkoutId: Scalars['Uuid']['input']; customerAccessToken?: InputMaybe; diff --git a/wake/utils/nonNullable.ts b/wake/utils/nonNullable.ts new file mode 100644 index 000000000..f308e0eb2 --- /dev/null +++ b/wake/utils/nonNullable.ts @@ -0,0 +1,3 @@ +export default function (val: T | null | undefined): val is T { + return val !== null && val !== undefined; +} diff --git a/wake/utils/transform.ts b/wake/utils/transform.ts index 2b06fe533..f48b9efbe 100644 --- a/wake/utils/transform.ts +++ b/wake/utils/transform.ts @@ -1,4 +1,4 @@ -import { +import type { BreadcrumbList, FilterRange, ListItem, diff --git a/wake/utils/user.ts b/wake/utils/user.ts index d42420974..77ea90e66 100644 --- a/wake/utils/user.ts +++ b/wake/utils/user.ts @@ -1,9 +1,30 @@ -import { getCookies } from "std/http/cookie.ts"; +import { getCookies, setCookie } from "std/http/cookie.ts"; -const LOGIN_COOKIE = "fbits-login"; +export const LOGIN_COOKIE = "fbits-login"; export const getUserCookie = (headers: Headers): string | undefined => { const cookies = getCookies(headers); return cookies[LOGIN_COOKIE]; }; + +export const setUserCookie = ( + headers: Headers, + token: string, + legacyToken: string, + expires: Date, +): void => { + setCookie(headers, { + name: "customerToken", + path: "/", + value: token, + expires, + }); + setCookie(headers, { + name: "fbits-login", + path: "/", + value: legacyToken, + // 1 year + expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), + }); +};