Purpose#
Offers is the Profile-tab reusable that lists customer offers with status/sort filtering and pagination.It renders responsive offer tables/cards and keeps filter/page state in URL query parameters.Where it's rendered#
In Components/Profile/Default.liquid:{% render 'Reusables\\Offers\\Default', offerData: offerData %}
Offers is rendered with a single parameter:Model shape (storefront example)#
Sanitized example of the payload used by this reusable:{
"offerData": {
"status": "Open",
"sort": "expiresAt_desc",
"pagination": {
"pageNumber": 1,
"numberOfPages": 3
},
"availableStatuses": [
"All",
"Draft",
"Open",
"Accepted",
"Expired",
"Rejected"
],
"availableSorts": [
"expiresAt_desc",
"expiresAt_asc",
"insertdate_desc",
"insertdate_asc"
],
"list": [
{
"id": "Offer Id",
"title": "Sample title",
"customerName": "Sample name",
"status": "Open",
"insertDate": "2026-05-10T09:15:00Z",
"expiresAt": "2026-06-10T09:15:00Z"
}
]
}
}
Required fields#
offerData.pagination.pageNumber
offerData.pagination.numberOfPages
Optional fields#
offerData.availableStatuses
Template behavior (Liquid + Alpine)#
Source: Reusables/Offers/Default.liquid.Computes a Liquid sliding-window pagination list.
x-data="offersreusabledefault.initComponent(currentPage, totalPages, offerData)"
Status and sort selectors call redirectToState(1) on change.
If offerData is empty/null, it renders a no-data/no-results message.
Offer rows link to /offer/{id} in a new tab.
Data contract (JS runtime)#
Alpine state returned by initComponent:currentPage / totalPages — pagination window, seeded from Liquid.
offerData — the payload rendered by the template.
status — selected status filter, defaults to offerData.status or All.
sort — selected sort, defaults to offerData.sort or -ExpiresAt.
exportingOfferIds — ids of the offers whose Excel export is currently in flight.
JavaScript#
Source: Reusables/Offers/Default.js.initComponent#
Factory that returns reusable state (currentPage, totalPages, offerData, status, sort,
exportingOfferIds) and handlers.isExportingOffer#
Returns whether an export is currently in flight for the given offer id, by checking
exportingOfferIds. Used to disable the export control and show a pending state per row.exportOffer#
Exports a single offer to Excel via servicesreusabledefault.exportOfferToExcel.Ignores the call when there is no offerId or an export for that offer is already running.
Clears existing toasts, then tracks the offer id in exportingOfferIds for the duration so each
row can show its own pending state; the id is always removed again in a finally block.
Builds the file name from the offer title, stripping anything that is not a letter, number, - or
_, and falls back to offer when nothing usable remains.
Shows an error toast with the caller-supplied errorMessage when the response is missing,
unsuccessful, or carries a non-2xx status.
redirectToState#
Builds query-string state (offerPage, offerStatus, offerSort) and redirects to the same path.Global Alpine stores#
Alpine.store("toast") — removeAll() before an export starts, and add(...) to report a failed
export.
Services / API calls#
servicesreusabledefault.exportOfferToExcel(offerId, fileName) — see Reusables/Services/Default.
Dependencies#
Reusables/Offers/Default.liquid, Default.js, Default.json
Reusables/Services/Default (exportOfferToExcel)
Rendered from Components/Profile/Default.liquid
Notes#
The reusable keeps filtering/pagination state in URL params, so refresh/share preserves current view.
Translation labels are read from Reusables/Offers/Default.json (Reusables.Offers.Translations.*).
Modified at 2026-09-17 09:32:26