Purpose#
Services is the theme’s client-side service layer that centralizes API calls and shared storefront workflows.It exposes servicesreusabledefault as the common SDK used by components/reusables for cart, checkout, profile, offer, and payment operations.Where it's rendered#
No direct Liquid render call was found for Reusables/Services/Default in this workspace.This reusable is rendered without Liquid parameters.Template behavior (Liquid + Alpine)#
This reusable does not render UI.Its role is to register the global JavaScript object servicesreusabledefault, which is then consumed by other components and reusables.Data contract (JS runtime)#
Document runtime state shape, factories, and main state fields.JavaScript#
Standard function conventions#
1) Pattern: Axios + normalized return#
Most methods follow this structure:1.
Call an endpoint using axios.get/post/put/delete.
2.
Normalize the response via:getAxiosResponse(response, context)
3.
Return the normalized object:
Log with a method-specific console.error('<method> failed:', e)
Return e.response (raw Axios error response), or return the cancel error when using cancel tokens.
2) Context strings#
getAxiosResponse is always called with a stable context string (usually the method name), e.g.:this.getAxiosResponse(response, 'addToCart')
This makes error logs searchable and consistent.3) Cancellation#
Some methods cancel the previous request before starting a new one, using:axios.CancelToken.source()
The service caches Axios CancelToken sources on internal properties of the services object.4) Side effects#
Several methods intentionally do more than “just call an API”. Common side effects include:Updating localStorage (cartToken, checkoutToken, cartData)
Alpine.store('cart').update(...)
Alpine.store('checkout').set(...)
Alpine.store('checkout').validateStep(...)
Alpine.store('checkout').isUpdating = true/false
Alpine.store('modal').shouldReinitialize = true
5) fetch vs axios#
Some search endpoints use fetch(...) and return raw JSON (not the normalized wrapper). These are exceptions and are documented explicitly below.API reference (grouped by category)#
General#
getCartData#
clearCart#
teardownKlarnaPayments#
uuidv4#
completeCheckout#
fetchUsers#
deleteCompanyLogo#
getCartData()#
Fetches the current cart payload for the active session.Used by cart/checkout-related flows to refresh cartData after mutations.
Returns a normalized response (via getAxiosResponse).
teardownKlarnaPayments()#
Performs cleanup for Klarna Payments UI state.Intended to be called when leaving a Klarna step / when re-initializing checkout payment forms.
This method may interact with payment-specific globals/scripts loaded in the layout.
getAxiosResponse(response, context = "")#
Normalizes an Axios response into a stable shape.response: Axios response object (or falsy).
context: optional string used in logs.
If response.status is not 2xx, logs a structured error and returns:{ success: false, status, error: response }
{ success: true, status, data: response.data }
uuidv4()#
Generates a random GUID-like string using crypto.getRandomValues.setShopranosCookie(value, expiresAt)#
expiresAt: expiration date/time.
normalized response via getAxiosResponse.
internalUploadFile(file, url, endpoint = null)#
Uploads a file in chunks (200000 bytes per chunk) using fetch and FormData.endpoint: optional extra query param ?endpoint=....
guid (string) for the upload session, or null on failure.
Uses uuidv4() internally.
generateTextFromAI(data, cultureCode, currency)#
POSTs product-offer prompt payload to /api/ai/product/offer/notes and returns normalized response.fetchProductMixProducts(params)#
GET /api/product-mix/my-list?{params} and returns normalized response.Alpine.store('modal').shouldReinitialize = true.
Returns normalized response.data: request payload (shopping list creation model).
Returns normalized response.DELETE /api/ShoppingList/{alias}.alias: shopping list alias.
Returns normalized response.PUT /api/ShoppingList/{list.alias}.list: full list object; must include alias.
Returns normalized response.Imports items into an existing list.1.
Uploads the file via internalUploadFile(file, '/api/file') → returns guid
2.
POST /api/ShoppingList/import-items/{alias}/{guid}
Returns normalized response.POST /api/ShoppingList/export-items/{alias} with { responseType: 'blob' }.
Creates a browser download named ShoppingList-{alias}.xlsx.
Returns normalized response.Wishlist#
clearWishlist#
clearWishlist()#
DELETE /api/wishlist/items.Returns normalized response.addItemToWishlist(productId)#
POST /api/wishlist/items/products/{productId}.Returns normalized response.removeItemFromWishlist(productId)#
DELETE /api/wishlist/items/products/{productId}.Returns normalized response.Navbar (Search + announcements)#
findProductsByCriteria(searchCriteria)#
Performs a product search using fetch.Endpoint: GET /api/products/liquid with query string params.
searchCriteria: object of query params. Only non-null/undefined values are included.
Returns parsed JSON on success.
Returns null and logs on non-OK response.
findProductsByCriteriaExtended(searchCriteria)#
Like findProductsByCriteria but uses:GET /api/products/search-extended
searchCriteria: object of query params.
Throws an Error when the response is not OK.
setReadAnnouncementIds(ids)#
ids: array/payload containing announcement ids.
Returns normalized response.sendEmail(data)#
Sends the contact form to the backend.Uploads file fields first (where field.type == 4).
data: contact form payload; expected to include fields[].
Returns normalized response.internalUploadFiles(fields)#
Uploads contact form files for a set of form fields.fields: list of field definitions.
Reads files from DOM input document.getElementById(field.name).files.
Uploads each file via uploadContactFormFile(file).
Writes back field.value as a comma-joined list of returned GUIDs.
Uploads a single contact-form file.Calls internalUploadFile(file, '/api/file/contact').
Profile (Account, addresses, managed users)#
accountForgotPassword(data)#
POST /api/account/forgotpassword.data: forgot password payload.
Returns normalized response.changePassword(data)#
POST /api/account/changepassword.data: change password payload.
Returns normalized response.changePasswordProfile(data)#
POST /api/account/changeprofilepassword.data: profile password change payload.
Returns normalized response.updateUserProfile(data)#
PUT /api/account/updateuserinfo.data: user profile payload.
Returns normalized response.createUserAddress(data)#
POST /api/customer/addresses.Returns normalized response.updateUserAddress(data, addressId)#
PUT /api/customer/addresses/{addressId}.Returns normalized response.deleteUserAddress(addressId)#
DELETE /api/customer/addresses/{addressId}.Returns normalized response.setUserAddressAsPrimary(addressId)#
POST /api/customer/addresses/setdefault/{addressId}.Returns normalized response.accountLogin(data)#
Side effects on success (status == 200):GET /api/cart/user to retrieve a user cart.
Sets localStorage.cartToken, cookie cartToken, and localStorage.cartData.
Returns normalized response.accountRegister(data)#
POST /api/account/register.Returns normalized response.registerUser(data, token)#
POST /api/account/confirmInvitation/{token}.data: registration payload.
Returns normalized response.deleteUser(user)#
DELETE /api/managedusers/{user.id}.user: object with at least id.
Returns normalized response.updateUser(user)#
PUT /api/managedusers/{user.id}.user: user object (must include id).
Returns normalized response.inviteUser(data)#
POST /api/managedusers/invite.Returns normalized response.fetchUsers()#
GET /api/managedusers with params:Returns normalized response.uploadCompanyLogo(file, customerId)#
1.
Uploads the file via internalUploadFile(file, '/api/file', '/api/files/upload/logo/{customerId}')
Returns normalized response.deleteCompanyLogo()#
DELETE /api/customer/logo.Returns normalized response.Cart#
Adds a single item to the cart.POST /api/cart/{cartToken}/add
variantId: product variant id.
quantity: quantity to add.
finalPrice: used for GA payload (price).
originalPrice: used for GA payload (initialPrice).
showPopUp: passed to $store.cart.update(...) to control UI feedback.
Preconditions / side effects:Cancels previous cart update via cancelTokenSource.
Ensures localStorage.checkoutToken exists (creates one via uuidv4() and sets cookie checkoutToken).
Updates localStorage.cartToken + cookie cartToken.
If $store.cart exists, calls:Alpine.store('cart').update(cartData, [{ ...addedItem, addedQuantity: quantity }], showPopUp)
If cart has items, sends GA event addToCart.
Returns normalized response.Adds multiple items to cart in one request.POST /api/cart/{cartToken}/addmultiple
variations: array of objects with at least:showPopUp: passed to cart store update.
Updates $store.cart once with successfully added products.
Sends GA addToCart event.
Returns normalized response.updateProductCart(cartData, cancelToken)#
PUT /api/cart/{cartToken}
cartData: cart update payload.
cancelToken: Axios cancel token.
Calls Alpine.store('cart').update(cartData).
Returns normalized response (or cancel error).updateProductQuantity(data, cancelToken)#
Validates/resolves requested quantity.POST /api/cart/{cartToken}/resolveQuantity
cancelToken: Axios cancel token.
Returns normalized response (or cancel error).clearCart()#
DELETE /api/cart/{cartToken}/all
Sends GA removeFromCart based on stored localStorage.cartData.
Calls Alpine.store('cart').update(cartData).
Returns normalized response.removeFromCart(variantId)#
Removes an item by variant id.DELETE /api/cart/{cartToken}/{variantId}
variantId: product variant id.
Sends GA removeFromCart for the removed line.
Calls Alpine.store('cart').update(cartData).
Returns normalized response.getCartValidation()#
Fetches calculated cart validation and returns a simplified error summary.GET /api/cart/calculated/{cartToken}/
Cancels the previous calculation request using calculatecartCancelTokenSource.
On success: { isSuccess, lines: [{ type, count, lineIds[] }] }
On failure: returns e.response.
importCart(type, file)#
Imports cart lines from a CSV/Excel file using chunked upload.POST /api/cart/import?format={type}
type: import format (for example Csv or Excel).
file: File, FileList, or array-like file input; the first valid File is used.
Splits the file into 200000-byte chunks and posts each chunk with FormData.
Uses Axios option validateStatus: () => true so 202 chunk-accepted and final 200 responses are handled explicitly by the method.
Returns early for non-200/202 responses.
validateStatus#
importCart(...) sets Axios validateStatus: () => true so chunk responses are not rejected by Axios and can be handled explicitly in code (202 continue, 200 final payload, other statuses return early).When payload contains cart.token, updates localStorage.cartToken and cookie cartToken.
Final import payload on success, or e.response on failure.
exportCart(type)#
POST /api/cart/export with the selected format and triggers file download from the returned URL.Checkout#
updateCheckout(data, checkoutStep = null)#
POST /api/checkout/update/{checkoutToken}
data: checkout update payload.
checkoutStep: optional string; when present, triggers step validation.
Injects data.cartItems = Alpine.store('cart').items.
Toggles Alpine.store('checkout').isUpdating.
Alpine.store('checkout').set(returnResponse.data)
Alpine.store('checkout').validateStep(checkoutStep, true)
Alpine.store('checkout').globalError = true
validateStep(checkoutStep, false)
Returns normalized response.proceedToCheckout(data)#
High-level checkout continuation.Calls updateCheckout(data).
If there is a payment provider, calls initiatePayment(checkoutData).
Otherwise calls completeCheckout().
Returns normalized response.initiatePayment(data)#
Initiates payment and performs provider-specific redirects.POST /api/payment/initiate/{checkoutToken}
data: checkout data; must contain data.payment.provider.
Redirects the browser when redirectUrl is returned for providers like PayPal/JCC/Stripe/Nexi.
Builds and auto-submits provider forms for EDPS/Epay/CardLink.
Injects and executes HTML snippet for Klarna.
Otherwise falls back to completeCheckout().
Redirects to /checkout/error.
loadKlarnaPaymentsScript#
Loads or reuses the Klarna Payments script and resolves when the script is ready.buildKlarnaPaymentsContainer#
Builds/returns the DOM container used to host Klarna embedded payment content.showKlarnaPaymentsError#
Displays/logs a Klarna-specific error state for failed setup/authorization steps.cancelKlarnaPayments#
Cancels/tears down any in-flight Klarna UI/payment state.handleKlarnaPayments#
Coordinates Klarna payment flow selection and delegates to inline/HPP handlers.handleKlarnaPaymentsInLine#
Initializes and runs the embedded (inline) Klarna flow.handleKlarnaPaymentsHpp#
Initializes and runs the hosted payment page (HPP) Klarna flow.postKlarnaPaymentsAuthorize#
Submits Klarna authorization payload and returns the backend authorization result.completeCheckout()#
POST /api/checkout/complete/{checkoutToken}.
Returns normalized response.fetchPostalCodes(countryCode)#
GET /api/location/postalcodes/{countryCode}.
countryCode: country code.
Returns normalized response.Thank You#
triggerOrderViewedCleanup(orderId)#
Triggers analytics cleanup after the thank-you page is viewed.POST /api/order/{orderId}/analytics/thank-you-page-viewed
Returns normalized response.Offers / Quotes#
updateOfferPricing#
Updates offer pricing (line-level or aggregate) and returns normalized response.createOffer#
Creates a new offer and returns normalized response.updateOffer#
Updates an existing offer and returns normalized response.rejectOffer#
Rejects/cancels an existing offer and returns normalized response.createQuote#
Creates a quote payload/workflow entry and returns normalized response.Global Alpine stores#
This reusable may update these stores when they exist (depending on the called method):$store.toast (indirectly; most callers handle toasts themselves)
Services / API calls#
This reusable is the services layer itself.It calls backend endpoints under /api/... via axios (mostly) and fetch (in specific search endpoints).Dependencies#
JS: Reusables/Services/Default.js
Translations: Reusables/Services/Default.json
Notes#
servicesreusabledefault includes both:“thin” API wrappers (call endpoint + normalize)
“orchestrators” that update stores/local storage and trigger GA events.
Modified at 2026-06-15 06:42:42