Skip to content
Open
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
f994faa
feat(orders): ORDERS-7706 add new return page layout
jpajar May 4, 2026
c0b3a94
feat(returns): ORDERS-7704 condition for new returns on orders page (…
bc-vivekaggarwal May 12, 2026
1000b66
Merge pull request #2649 from bigcommerce/ORDERS-7706
jpajar May 8, 2026
536ef54
feat(returns): ORDERS-7705 condition for new returns on order details…
bc-vivekaggarwal May 12, 2026
2a2a8ce
feat(orders): ORDERS-7734 add template for guest return portal
BC-SEven Apr 28, 2026
767352c
feat(returns): ORDERS-7708 new-return page — render items from order …
bc-vivekaggarwal May 27, 2026
73a69a1
feat(orders): ORDERS-7331 add template for create return page
May 28, 2026
54cbfa5
Merge pull request #2649 from bigcommerce/ORDERS-7706
jpajar May 8, 2026
32f8491
feat(returns): ORDERS-7717 - add new returns list ui
bc-bryan May 26, 2026
9baaa59
feat(returns): ORDERS-7717 - use rma number
bc-bryan May 27, 2026
6b624ab
feat(returns): ORDERS-7717 - add CHANGELOG item
bc-bryan May 28, 2026
801da23
feat(returns): ORDERS-7717 - address copilot review
bc-bryan May 28, 2026
840d395
feat(orders): ORDERS-7718 add return details page layout
jpajar Jun 5, 2026
c3feda4
feat(orders): ORDERS-7718 add status mappping from enum
jpajar Jun 9, 2026
c74e28a
Orders 7764 render create return page with context (#2673)
bc-vivekaggarwal Jun 11, 2026
5ca884d
feat(orders): ORDERS-7707 improve create return page design for mobil…
jpajar Jun 16, 2026
c7223e7
feat(orders): ORDERS-7715 add createReturn mutation and confirmation …
jpajar Jun 22, 2026
1240602
feat(orders): ORDERS-7715 handle double submissions
jpajar Jun 22, 2026
4fde392
feat(orders): ORDERS-7859 add error message on failed return creation
jpajar Jun 23, 2026
ba1bf2e
feat(returns): ORDERS-7857 add loading state as return submission (#2…
bc-vivekaggarwal Jun 25, 2026
3a22d2f
feat(returns): ORDERS-7751 - add return details page data
bc-bryan Jun 15, 2026
bede560
feat(orders): ORDERS-7751 add placeholder image
bc-bryan Jun 19, 2026
cc3b1aa
feat(returns): ORDERS-7751 check resolution and requested exist
bc-bryan Jun 19, 2026
83f7f80
feat(returns): ORDERS-7751 use handlebars for details templates
bc-bryan Jun 25, 2026
96876d3
feat(returns): ORDERS-7751 update thumbnail image TODO with id
bc-bryan Jun 25, 2026
0076e8a
feat(returns): ORDERS-7751 remove unused localization keys and markup
bc-bryan Jun 25, 2026
b38c833
feat(returns): ORDERS-7751 use span tag instead of dt tag
bc-bryan Jun 25, 2026
d716a62
feat(returns): ORDERS-7751 output localized string instead of status …
bc-bryan Jun 26, 2026
dd3c25f
feat(returns): ORDERS-7751 add sr-only label for orderId
bc-bryan Jun 26, 2026
d38329f
feat(returns): ORDERS-7751 remove per item status
bc-bryan Jun 30, 2026
a630176
feat(returns): ORDERS-7751 add order_number_label key
bc-bryan Jun 30, 2026
04e116a
feat(returns): ORDERS-7751 reference correct object for thumbnail fal…
bc-bryan Jun 30, 2026
ead5f2a
feat(orders): ORDERS-7681 add Cancel return button and handler to ret…
jpajar Jun 24, 2026
dea2b90
feat(orders): ORDERS-7681 extend Account module for ReturnDetails module
jpajar Jul 1, 2026
a7ead4c
feat(returns): ORDERS-7771 tighten spacing on mobile and tablet viewp…
bc-bryan Jul 1, 2026
d2023be
feat(returns): ORDERS-7771 update changelog
bc-bryan Jul 1, 2026
2e345cd
feat(returns): ORDERS-7771 scope shared account css changes to return…
bc-bryan Jul 1, 2026
b2f24e0
feat(returns): ORDERS-7771 fix mobile stacking for detail items
bc-bryan Jul 1, 2026
b49e72e
feat(returns): ORDERS-7771 remove invalid margin value
bc-bryan Jul 1, 2026
c33cfc2
feat(returns): ORDERS-7771 move returns list specific styles to it's …
bc-bryan Jul 1, 2026
1972c92
feat(returns): ORDERS-7771 address copilot feedback
bc-bryan Jul 2, 2026
a5ab199
feat(orders): ORDERS-7736 implement guest return portal page (#2696)
BC-SEven Jul 8, 2026
d19c9de
feat(orders): ORDERS-7886 Update error message to generic message wit…
BC-SEven Jul 12, 2026
8e2b379
feat(orders): ORDERS-7736 add client side validation for guest return…
BC-SEven Jul 15, 2026
32387b7
feat(orders): ORDERS-7935 add badge for CANCELLED order returns
jpajar Jul 15, 2026
c887c9d
feat(returns): ORDERS-7900: strike requested with resolved resolution…
bc-vivekaggarwal Jul 16, 2026
012e687
feat(returns): ORDERS-7752 add cursor pagination to returns
bc-bryan Jul 15, 2026
2d20302
feat(returns): ORDERS-7752 use pagination.<resource> key
bc-bryan Jul 15, 2026
a1a7634
feat(returns): ORDERS-7752 use div with region role
bc-bryan Jul 16, 2026
94764cc
feat(orders): ORDERS-7770 add responsive styling for returns details …
jpajar Jul 16, 2026
ddee220
feat(orders): ORDERS-7837 add additional note field to mutation when …
jpajar Jul 21, 2026
e996195
feat(orders): ORDERS-7838 add additional note section to new shopper …
jpajar Jul 22, 2026
fdcd5cb
feat(orders): ORDERS-7647 update return list navigation to work with …
BC-SEven Jul 23, 2026
4f7dccc
feat(orders): ORDERS-7890 add product images to return details page (…
BC-SEven Jul 23, 2026
f546f15
chore(common): PROJECT-7525 move CHANGELOG items back to draft after …
BC-SEven Jul 27, 2026
341d6bb
feat(returns): ORDER-7874 add accessibility to create return page (#2…
bc-vivekaggarwal Jul 27, 2026
bb5e0fa
Merge pull request #2649 from bigcommerce/ORDERS-7706
jpajar May 8, 2026
3ce9674
Merge pull request #2649 from bigcommerce/ORDERS-7706
jpajar May 8, 2026
60f0e5a
fix(returns): ORDERS-7752 rename keys to be snake_case for consistency
bc-bryan Jul 22, 2026
857086f
Merge pull request #2711 from bigcommerce/ORDERS-7752-rename-returns-…
bc-bryan Jul 28, 2026
61cc4ec
feat(returns): ORDERS-7878 add accessibility to returns list page
bc-vivekaggarwal Jul 30, 2026
f8a0a11
chore(other): add Bugbot config
bc-vivekaggarwal Jul 31, 2026
0aad70a
Merge pull request #2716 from bigcommerce/ORDERS-7878-accessibility-f…
bc-vivekaggarwal Aug 2, 2026
e35b936
feat(orders): ORDERS-7961 fix styling for Warm and Bold themes for St…
jpajar Aug 3, 2026
092c8c1
Merge pull request #2717 from bigcommerce/ORDERS-7961
jpajar Aug 4, 2026
913dec5
fix(returns): ORDERS-7719 align return detail page with design and sn…
bc-vivekaggarwal Aug 4, 2026
913a6f2
feat(returns): ORDERS-7875 add accessibility to return detail page
bc-vivekaggarwal Aug 4, 2026
17c7530
Merge pull request #2719 from bigcommerce/ORDERS-7875-accesibility-fe…
bc-vivekaggarwal Aug 4, 2026
3668a6d
feat(returns): ORDERS-7877 add order-scoped aria-labels to returns en…
bc-vivekaggarwal Aug 12, 2026
5b74b7d
Merge pull request #2725 from bigcommerce/ORDERS-7877-accessibility-r…
bc-vivekaggarwal Aug 12, 2026
86db5ab
feat(orders): ORDERS-7876 improve accessibility for guest-return page
jpajar Aug 11, 2026
339dd87
feat(orders): ORDERS-7876 clear errors to prevent announcing errors t…
jpajar Aug 12, 2026
4dda924
Merge pull request #2724 from bigcommerce/ORDERS-7876
jpajar Aug 13, 2026
6132a25
feat(orders): ORDERS-7966 add items total to returns detail and listi…
jpajar Aug 14, 2026
1d797b2
feat(returns): ORDERS-7945 add page title to returns related pages fo…
bc-vivekaggarwal Aug 14, 2026
2891af6
feat(orders): ORDERS-7966 rename labels as per feedback
jpajar Aug 14, 2026
1ef3c25
Merge pull request #2727 from bigcommerce/ORDERS-7966
jpajar Aug 20, 2026
251094a
feat(orders): ORDERS-7965 fix return listing page quantity displayed
jpajar Aug 24, 2026
699bbfe
feat(orders): ORDERS-7965 align date format and status badge between …
jpajar Aug 25, 2026
dddbc24
feat(orders): ORDERS-7959 add "go to return portal link" in webpages …
BC-SEven Aug 25, 2026
cf40115
Merge pull request #2729 from bigcommerce/ORDERS-7965
jpajar Aug 26, 2026
5b6890b
Merge pull request #2732 from bigcommerce/ORDERS-7965_2
jpajar Aug 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Draft
- Add accessibility to create return page (ORDERS-7874) [#2712](https://github.com/bigcommerce/cornerstone/pull/2712)
- Add product images to return detail page (ORDERS-7890) [#2713](https://github.com/bigcommerce/cornerstone/pull/2713)
- Update returns navigation to support returns_v2_enabled [#2714](https://github.com/bigcommerce/cornerstone/pull/2714/changes)
- Add client side validation on guest return portal (ORDERS-7736) [#2703](https://github.com/bigcommerce/cornerstone/pull/2703)
- Update error message for create return page (ORDERS-7886) [#2698](https://github.com/bigcommerce/cornerstone/pull/2698)
- Implement guest return portal page (ORDERS-7736) [#2696](https://github.com/bigcommerce/cornerstone/pull/2696)
- Add mobile and tablet responsiveness for returns list page (ORDERS-7771)
- Add return details page (ORDERS-7751)
- Add new create-return page [#2669](https://github.com/bigcommerce/cornerstone/pull/2669)
- Gate Order Details "Return" button on `settings.returns_v2_enabled` with `settings.returns_enabled` fallback (ORDERS-7705)
- Gate account orders list "Return Items" link on returns settings (ORDERS-7704) [#2653](https://github.com/bigcommerce/cornerstone/pull/2653)
- Added new Return list view (ORDERS-7717) [#2664](https://github.com/bigcommerce/cornerstone/pull/2664)
- Added requested and resolved resolution view on return details page (ORDERS-7900) [#2697](https://github.com/bigcommerce/cornerstone/pull/2697)
- Adds new guest-return-portal page. [2645](https://github.com/bigcommerce/cornerstone/pull/2645)

## 6.21.0 (07-21-2026)
- Display featured promotion callouts on product listing pages (product cards and list view) and the PDP, gated by the new `show_featured_promotions` theme setting and the `featured_promotions` context [#2695](https://github.com/bigcommerce/cornerstone/pull/2695)
Expand Down
7 changes: 7 additions & 0 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ __webpack_public_path__ = window.__webpack_public_path__; // eslint-disable-line
import Global from './theme/global';

const getAccount = () => import('./theme/account');
const getCreateReturn = () => import('./theme/create-return');
const getReturnDetails = () => import('./theme/return-details');
const getGuestReturnPortal = () => import('./theme/guest-return-portal');
const getLogin = () => import('./theme/auth');
const noop = null;

Expand All @@ -12,13 +15,17 @@ const pageClasses = {
account_addressbook: getAccount,
shippingaddressform: getAccount,
account_new_return: getAccount,
create_return: getCreateReturn,
guest_return_portal: getGuestReturnPortal,
'add-wishlist': () => import('./theme/wishlist'),
Comment on lines 14 to 20
account_recentitems: getAccount,
account_downloaditem: getAccount,
editaccount: getAccount,
account_inbox: getAccount,
account_saved_return: getAccount,
account_returns: getAccount,
account_return_detail: getReturnDetails,
return_detail: getReturnDetails,
account_paymentmethods: getAccount,
account_addpaymentmethod: getAccount,
account_editpaymentmethod: getAccount,
Expand Down
247 changes: 247 additions & 0 deletions assets/js/theme/create-return.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import PageManager from './page-manager';

const MAX_ADDITIONAL_NOTE_LENGTH = 1000;

export default class CreateReturn extends PageManager {
onReady() {
const form = document.querySelector('[data-new-return-form]');
if (!form) return;

this.focusOnLoad();
this.bindOrderLineItemEvents();
this.bindAdditionalNoteEvents();
this.bindSubmit(form);
}

// Focus the page heading on load so screen-reader/keyboard users start at the page context.
focusOnLoad() {
document.getElementById('newReturn-heading')?.focus({ preventScroll: true });
}

announce(message) {
const liveRegion = document.querySelector('[data-new-return-status]');
if (liveRegion) liveRegion.textContent = message || '';
}

bindOrderLineItemEvents() {
// All three selects per row (qty, resolution, reason) trigger a submit-state check.
document.querySelectorAll('.newReturn-orderLineItem select').forEach(sel => {
sel.addEventListener('change', () => this.updateSubmitState());
});
}

bindAdditionalNoteEvents() {
const noteEl = document.querySelector('[data-new-return-note]');
if (!noteEl) return;

noteEl.addEventListener('input', () => {
this.renderAdditionalNoteValidation();
this.updateSubmitState();
});
}

updateSubmitState() {
const selectedItems = this.getSelectedItems();
const hasValidItems = selectedItems.length > 0 && selectedItems.every(itemRow => {
const itemId = itemRow.dataset?.itemId;
if (!itemId) return false;
const resolutionEl = document.getElementById(`resolution-${itemId}`);
const reasonEl = document.getElementById(`reason-${itemId}`);
return resolutionEl && resolutionEl.value && reasonEl && reasonEl.value;
});

const submitBtn = document.getElementById('return-new-submitBtn');
if (!submitBtn) return;

// aria-disabled (not the native disabled attr) keeps the button keyboard/SR reachable while invalid.
// The described-by hint swaps between "what to select" and "press Enter to submit".
const isValid = hasValidItems && this.isAdditionalNoteValid();
submitBtn.setAttribute('aria-disabled', String(!isValid));
submitBtn.setAttribute('aria-describedby', isValid ? 'return-new-submitHint-enabled' : 'return-new-submitHint-disabled');
}

bindSubmit(form) {
form.addEventListener('submit', async event => {
event.preventDefault();

// Block submission when the additional note exceeds the max length.
this.renderAdditionalNoteValidation();
if (!this.isAdditionalNoteValid()) return;

const submitBtn = document.getElementById('return-new-submitBtn');
// aria-disabled doesn't block submit/Enter the way the native attr would, so gate here.
if (submitBtn?.getAttribute('aria-disabled') === 'true') return;
if (this.isSubmitting) return;
this.isSubmitting = true;

const overlay = document.querySelector('[data-new-return-view] .loadingOverlay');
if (submitBtn) submitBtn.setAttribute('aria-disabled', 'true');
if (overlay) overlay.style.display = 'block';
form.setAttribute('aria-busy', 'true');
this.announce(this.context.submittingMessage);
this.clearError();

try {
const response = await this.createReturn(this.buildReturnInput());
const errorMessages = this.getErrorMessages(response);

if (errorMessages.length) {
this.showError();
return;
}

this.showConfirmation();
Comment thread
cursor[bot] marked this conversation as resolved.
} catch (error) {
this.showError();
} finally {
this.isSubmitting = false;
this.updateSubmitState();
if (overlay) overlay.style.display = '';
Comment thread
cursor[bot] marked this conversation as resolved.
form.removeAttribute('aria-busy');
}
});
}

getErrorMessages(response) {
const transportErrors = Array.isArray(response?.errors) ? response.errors : [];
const returnErrors = Array.isArray(response?.data?.order?.return?.createReturn?.errors)
? response.data.order.return.createReturn.errors
: [];

return transportErrors
.concat(returnErrors)
.map(error => error.message)
.filter(Boolean);
}

showError() {
// The error box has role="alert" (announced on display); clear the in-flight status and
// move focus to the summary so keyboard users land on the error.
this.announce('');

const errorBox = document.getElementById('return-new-error');
if (!errorBox) return;

errorBox.style.display = '';
errorBox.focus();
}
Comment thread
cursor[bot] marked this conversation as resolved.

clearError() {
const errorBox = document.getElementById('return-new-error');
if (errorBox) errorBox.style.display = 'none';
}

// Storefront GraphQL `createReturn` mutation
createReturn(input) {
return fetch('/graphql', {
Comment thread
cursor[bot] marked this conversation as resolved.
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.context.storefrontApiToken}`,
},
body: JSON.stringify({
query: `mutation CreateReturn($input: CreateOrderReturnInput!) {
order {
return {
createReturn(input: $input) {
entityId
errors {
__typename
... on Error {
message
}
}
}
}
}
}`,
variables: { input },
}),
}).then(response => response.json());
}

// Focus moves to the confirmation heading, which is what announces success to SR users.
showConfirmation() {
const formView = document.querySelector('[data-new-return-view]');
const confirmation = document.querySelector('[data-new-return-confirmation]');

if (formView) formView.style.display = 'none';
if (confirmation) confirmation.style.display = '';

document.querySelector('[data-new-return-confirmation-heading]')?.focus();
}

/**
* Builds the `CreateOrderReturnInput` payload from the selected line items.
*
* @returns {{ orderEntityId: number, items: Array }}
*/
buildReturnInput() {
const input = {
orderEntityId: parseInt(this.context.order?.id, 10),
items: this.getSelectedItems().flatMap(itemRow => {
const itemId = itemRow.dataset?.itemId;
if (!itemId) return [];
return [{
lineItemEntityId: parseInt(itemId, 10),
quantity: parseInt(document.getElementById(`qty-${itemId}`)?.value, 10),
reasonEntityId: document.getElementById(`reason-${itemId}`)?.value,
requestedResolution: this.buildRequestedResolution(document.getElementById(`resolution-${itemId}`)?.value),
}];
Comment thread
cursor[bot] marked this conversation as resolved.
}),
};
Comment thread
cursor[bot] marked this conversation as resolved.

// Do not send the note when it is empty or a whitespace
const additionalNote = this.getAdditionalNote();
if (additionalNote) {
input.note = additionalNote;
}

return input;
}

// Trimmed value of the additional-note textarea (empty string when absent).
getAdditionalNote() {
const noteEl = document.querySelector('[data-new-return-note]');
return noteEl ? noteEl.value.trim() : '';
}

isAdditionalNoteValid() {
return this.getAdditionalNote().length <= MAX_ADDITIONAL_NOTE_LENGTH;
}

// Toggles the inline error state on the additional-note field.
renderAdditionalNoteValidation() {
const field = document.querySelector('[data-new-return-note-field]');
const errorEl = document.querySelector('[data-new-return-note-error]');
const isValid = this.isAdditionalNoteValid();

if (field) field.classList.toggle('form-field--error', !isValid);
if (errorEl) {
errorEl.textContent = isValid ? '' : (this.context.additionalNoteTooLongError || '');
errorEl.style.display = isValid ? 'none' : '';
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note field missing aria-invalid

Medium Severity

Accessibility: forms/errors — renderAdditionalNoteValidation toggles the visible error but never sets aria-invalid on the additional-note control. Invalid state is not exposed to assistive tech on the field itself (see .claude/skills/accessibility/SKILL.md).

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by project rule: Accessibility (WCAG 2.2 AA) for Cornerstone storefront UI

Reviewed by Cursor Bugbot for commit 0aad70a. Configure here.


// Maps a selected resolution value to a `RequestedResolutionInput`
buildRequestedResolution(value) {
const systemResolutionTypes = ['EXCHANGE', 'REFUND', 'STORE_CREDIT'];

if (systemResolutionTypes.includes(value)) {
return { type: value };
}

return { type: 'CUSTOM', customResolutionEntityId: value };
}

// Returns only row containers with a non-zero quantity selected.
getSelectedItems() {
return Array.from(document.querySelectorAll('.newReturn-orderLineItem')).filter(itemRow => {
const itemId = itemRow.dataset?.itemId;
if (!itemId) return false;
const qtyInput = document.getElementById(`qty-${itemId}`);
return qtyInput && parseInt(qtyInput.value, 10) > 0;
});
}
}
Loading
Loading