diff --git a/assets/js/app.js b/assets/js/app.js
index b9e92bfdc8..2d95c5bef2 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -3,6 +3,7 @@ __webpack_public_path__ = window.__webpack_public_path__; // eslint-disable-line
import Global from './theme/global';
const getAccount = () => import('./theme/account');
+const getAddReturnNew = () => import('./theme/add-return-new');
const getLogin = () => import('./theme/auth');
const noop = null;
@@ -11,7 +12,7 @@ const pageClasses = {
account_order: getAccount,
account_addressbook: getAccount,
shippingaddressform: getAccount,
- account_new_return: getAccount,
+ account_new_return: getAddReturnNew,
'add-wishlist': () => import('./theme/wishlist'),
account_recentitems: getAccount,
account_downloaditem: getAccount,
diff --git a/assets/js/theme/add-return-new.js b/assets/js/theme/add-return-new.js
new file mode 100644
index 0000000000..44fe3cd0ef
--- /dev/null
+++ b/assets/js/theme/add-return-new.js
@@ -0,0 +1,253 @@
+import PageManager from './page-manager';
+
+export default class AddReturnNew extends PageManager {
+ onReady() {
+ const $form = $('[data-new-return-form]');
+ if (!$form.length) return;
+
+ // ---------------------------------------------------------------------------
+ // Hardcoded page data which mirrors the TypeScript returns-ui interface.
+ // Replace with Stencil context when it is available.
+ // ---------------------------------------------------------------------------
+ this.pageData = {
+ order: {
+ id: '101',
+ datePlaced: new Date('2024-01-01'),
+ status: 'Completed',
+ currency: 'AUD',
+ isTaxInclusive: true,
+ shipping: {
+ address: {
+ fullName: 'Jane Smith',
+ address1: '1-3 Smail Street',
+ city: 'Ultimo',
+ state: 'NSW',
+ zip: '2007',
+ country: 'Australia',
+ },
+ method: 'Australia Post',
+ dateShipped: 'May 15, 2024',
+ trackingNumber: '7E27315406641',
+ },
+ items: [
+ {
+ id: 'item-1',
+ name: 'Product Name',
+ variant: 'Blue / Black / Green',
+ sku: 'SKU-001',
+ quantity: 1,
+ returnableQuantity: 1,
+ thumbnailUrl: '',
+ totalIncTax: 123.99,
+ totalExTax: 110.71,
+ },
+ {
+ id: 'item-2',
+ name: 'Product Name',
+ variant: 'Blue / Black / Green',
+ sku: 'SKU-002',
+ quantity: 1,
+ returnableQuantity: 1,
+ thumbnailUrl: '',
+ totalIncTax: 123.99,
+ totalExTax: 110.71,
+ },
+ {
+ id: 'item-3',
+ name: 'Product Name',
+ variant: 'Blue / Black / Green',
+ sku: 'SKU-003',
+ quantity: 1,
+ returnableQuantity: 1,
+ thumbnailUrl: '',
+ totalIncTax: 123.99,
+ totalExTax: 110.71,
+ },
+ ],
+ },
+ reasons: [
+ { id: 'reason-1', nameForMerchant: 'Damaged or defective', active: true },
+ { id: 'reason-2', nameForMerchant: 'Wrong item received', active: true },
+ { id: 'reason-3', nameForMerchant: 'Changed my mind', active: true },
+ { id: 'reason-4', nameForMerchant: 'Item not as described', active: true },
+ { id: 'reason-5', nameForMerchant: 'Arrived too late', active: true },
+ ],
+ resolutions: [
+ { resolutionType: 'Refund' },
+ { resolutionType: 'Exchange' },
+ { resolutionType: 'Store Credit' },
+ ],
+ };
+
+ this.renderHeader();
+ this.renderShippingAddress();
+ this.renderShippingMethod();
+ this.renderOrderLineItems();
+ this.bindSubmit($form);
+ }
+
+ renderHeader() {
+ const { order } = this.pageData;
+ const dateLabel = order.datePlaced.toLocaleDateString('en-AU', { year: 'numeric', month: 'long', day: 'numeric' });
+
+ document.getElementById('return-new-orderId').textContent = order.id;
+ document.getElementById('return-new-statusBadge').textContent = order.status.toUpperCase();
+ document.getElementById('return-new-datePlaced').textContent = `Order date: ${dateLabel}`;
+ }
+
+ renderShippingAddress() {
+ const { address } = this.pageData.order.shipping;
+ const shippingAddressHtml = `
Shipping address
+ ${this.escHtml(address.fullName)}
+ ${this.escHtml(address.address1)}
+ ${this.escHtml(address.city)}, ${this.escHtml(address.state)} ${this.escHtml(address.zip)}
+ ${this.escHtml(address.country)}
`;
+
+ document.getElementById('return-new-shippingAddress').innerHTML = shippingAddressHtml;
+ }
+
+ renderShippingMethod() {
+ const { shipping } = this.pageData.order;
+ const shippingMethodHtml = `Shipping method
+ ${this.escHtml(shipping.method)}
+ Shipped on ${this.escHtml(shipping.dateShipped)}
+ ${this.escHtml(shipping.trackingNumber)}
`;
+
+ document.getElementById('return-new-shippingMethod').innerHTML = shippingMethodHtml;
+ }
+
+ renderOrderLineItems() {
+ const { order, reasons, resolutions } = this.pageData;
+
+ const resolutionOptions = [
+ '',
+ ...resolutions.map(resolution => {
+ const optionValue = this.isCustomResolution(resolution) ? this.escHtml(resolution.id) : this.escHtml(resolution.resolutionType);
+ const optionLabel = this.isCustomResolution(resolution) ? this.escHtml(resolution.nameForMerchant) : this.escHtml(resolution.resolutionType);
+ return ``;
+ }),
+ ].join('');
+
+ const reasonOptions = [
+ '',
+ ...reasons
+ .filter(reason => reason.active)
+ .map(reason => ``),
+ ].join('');
+
+ const orderLineItemsHtml = order.items.map(item => {
+ const price = new Intl.NumberFormat('en-AU', { style: 'currency', currency: order.currency }).format(item.totalIncTax);
+ const thumbnailHtml = item.thumbnailUrl
+ ? `
`
+ : 'No image
';
+
+ return `
+
+ ${thumbnailHtml}
+
+
${this.escHtml(item.name)}
+
${this.escHtml(item.variant)}
+
${price} x ${item.quantity}
+
+
+
+
+
+
+
+
+
+
+
`;
+ }).join('');
+
+ document.getElementById('return-new-itemsList').innerHTML = orderLineItemsHtml;
+ this.bindOrderLineItemEvents();
+ }
+
+ bindOrderLineItemEvents() {
+ document.querySelectorAll('.form-increment .button--icon').forEach(button => {
+ button.addEventListener('click', () => {
+ const itemId = button.getAttribute('data-item-id');
+ const action = button.getAttribute('data-action');
+ const item = this.pageData.order.items.find(orderLineItem => orderLineItem.id === itemId);
+ const quantityInput = document.getElementById(`qty-${itemId}`);
+ let quantity = parseInt(quantityInput.value, 10);
+
+ if (action === 'inc' && quantity < item.returnableQuantity) quantity++;
+ else if (action === 'dec' && quantity > 0) quantity--;
+
+ quantityInput.value = quantity;
+ document.querySelector(`[data-action="dec"][data-item-id="${itemId}"]`).disabled = quantity === 0;
+ document.querySelector(`[data-action="inc"][data-item-id="${itemId}"]`).disabled = quantity >= item.returnableQuantity;
+
+ this.updateSubmitState();
+ });
+ });
+
+ document.querySelectorAll('.newReturn-select').forEach(selectElement => {
+ selectElement.addEventListener('change', () => this.updateSubmitState());
+ });
+ }
+
+ updateSubmitState() {
+ const selectedItems = this.pageData.order.items.filter(item => parseInt(document.getElementById(`qty-${item.id}`).value, 10) > 0);
+
+ const isValid = selectedItems.length > 0 && selectedItems.every(item => (
+ document.getElementById(`resolution-${item.id}`).value
+ && document.getElementById(`reason-${item.id}`).value
+ ));
+
+ document.getElementById('return-new-submitBtn').disabled = !isValid;
+ }
+
+ bindSubmit($form) {
+ $form.on('submit', event => {
+ event.preventDefault();
+
+ const selectedItems = this.pageData.order.items.filter(item => parseInt(document.getElementById(`qty-${item.id}`).value, 10) > 0);
+
+ const newReturn = {
+ orderId: this.pageData.order.id,
+ items: selectedItems.map(item => ({
+ id: item.id,
+ quantity: parseInt(document.getElementById(`qty-${item.id}`).value, 10),
+ reasonId: document.getElementById(`reason-${item.id}`).value,
+ resolution: document.getElementById(`resolution-${item.id}`).value,
+ })),
+ };
+
+ // TODO: wire up API call when available
+ console.log('Submitting return:', JSON.stringify(newReturn, null, 2));
+ });
+ }
+
+ isCustomResolution(resolution) {
+ return 'id' in resolution;
+ }
+
+ escHtml(str) {
+ return String(str)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ }
+}
diff --git a/assets/scss/components/stencil/addReturn/_addReturn.scss b/assets/scss/components/stencil/addReturn/_addReturn.scss
index 1c120b9746..e5d41bf84c 100644
--- a/assets/scss/components/stencil/addReturn/_addReturn.scss
+++ b/assets/scss/components/stencil/addReturn/_addReturn.scss
@@ -1,6 +1,10 @@
// =============================================================================
// ADD RETURN REQUEST (CSS)
// =============================================================================
+//
+// Styles shared by both the legacy add-return page (.account--addReturn)
+// and the new add-return-new page (.newReturn).
+// =============================================================================
.account--addReturn {
@@ -137,3 +141,246 @@
width: grid-calc(6, $total-columns);
}
}
+
+
+// =============================================================================
+// NEW RETURN PAGE (.newReturn)
+// =============================================================================
+
+.newReturn {
+ color: color("link");
+ max-width: remCalc(1100px);
+ margin: 0 auto;
+ padding: 0 spacing("single") spacing("double");
+}
+
+.newReturn-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: spacing("eighth");
+}
+
+.newReturn-titleGroup {
+ display: flex;
+ align-items: center;
+ gap: spacing("half");
+}
+
+.newReturn-title {
+ font-size: remCalc(28px);
+ font-weight: fontWeight("bold");
+ margin: 0;
+}
+
+.newReturn-statusBadge {
+ display: inline-block;
+ padding: spacing("eighth") spacing("quarter");
+ border: remCalc(1.5px) solid color("orderStatus", "completed");
+ border-radius: remCalc(4px);
+ font-size: remCalc(11px);
+ font-weight: fontWeight("bold");
+ letter-spacing: remCalc(1px);
+ color: color("orderStatus", "completed");
+ text-transform: uppercase;
+}
+
+.newReturn-headerActions {
+ display: flex;
+ align-items: center;
+ gap: spacing("half");
+}
+
+.newReturn-btnBack {
+ padding: spacing("quarter") spacing("single") * 0.83;
+ border: remCalc(1.5px) solid color("link");
+ border-radius: remCalc(6px);
+ background: color("whites", "bright");
+ font-size: fontSize("smallest");
+ font-weight: fontWeight("medium");
+ cursor: pointer;
+ text-decoration: none;
+ color: color("link");
+}
+
+.newReturn-btnPolicy {
+ padding: spacing("quarter") spacing("single") * 0.83;
+ border: 0;
+ border-radius: remCalc(6px);
+ background: color("greys", "darkest");
+ color: color("whites", "bright");
+ font-size: fontSize("smallest");
+ font-weight: fontWeight("medium");
+ cursor: pointer;
+ text-decoration: none;
+}
+
+.newReturn-orderDate {
+ font-size: remCalc(13px);
+ color: color("greys", "base");
+ margin: spacing("eighth") 0 spacing("single") * 0.83;
+}
+
+.newReturn-divider {
+ border: 0;
+ border-top: container("border");
+ margin: spacing("single") 0;
+}
+
+
+.newReturn-shippingGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: remCalc(32px);
+}
+
+.newReturn-shippingSection {
+
+ h4 {
+ font-size: fontSize("smallest");
+ font-weight: fontWeight("semibold");
+ color: color("link");
+ margin: 0 0 spacing("quarter");
+ }
+
+ p,
+ a {
+ font-size: remCalc(13px);
+ margin: remCalc(2px) 0;
+ text-decoration: none;
+ }
+
+ p {
+ color: color("greys", "dark");
+ }
+}
+
+
+.newReturn-orderLineItem {
+ display: flex;
+ align-items: center;
+ gap: remCalc(16px);
+ padding: remCalc(16px) 0;
+ border-bottom: container("border");
+
+ &:last-child {
+ border-bottom: 0;
+ }
+}
+
+.newReturn-orderLineItemThumbnail {
+ width: remCalc(72px);
+ height: remCalc(72px);
+ object-fit: cover;
+ border-radius: remCalc(6px);
+ flex-shrink: 0;
+ background: color("greys", "lighter");
+}
+
+.newReturn-orderLineItemThumbnail--placeholder {
+ width: remCalc(72px);
+ height: remCalc(72px);
+ border-radius: remCalc(6px);
+ flex-shrink: 0;
+ background: color("greys", "light");
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: color("greys", "medium");
+ font-size: remCalc(11px);
+}
+
+.newReturn-orderLineItemInfo {
+ flex: 1;
+ min-width: 0;
+}
+
+.newReturn-orderLineItemName {
+ font-size: remCalc(15px);
+ font-weight: fontWeight("semibold");
+ margin: 0 0 remCalc(2px);
+}
+
+.newReturn-orderLineItemVariant {
+ font-size: remCalc(13px);
+ color: color("greys", "base");
+ margin: 0 0 remCalc(2px);
+}
+
+.newReturn-orderLineItemPrice {
+ font-size: remCalc(13px);
+ color: color("greys", "dark");
+ margin: 0;
+}
+
+.newReturn-orderLineItemControls {
+ display: flex;
+ align-items: center;
+ gap: spacing("half");
+ flex-shrink: 0;
+
+ //Override layout here so the counter sits in a horizontal row
+ // without touching the shared component.
+ .form-increment {
+ display: flex;
+ align-items: center;
+
+ }
+
+ .form-input--incrementTotal {
+ height: remCalc(36px);
+ line-height: remCalc(36px);
+ vertical-align: middle;
+ }
+}
+
+.newReturn-select {
+ height: remCalc(36px);
+ padding: 0 remCalc(28px) 0 spacing("quarter") * 1.67;
+ border: remCalc(1.5px) solid color("greys", "medium");
+ border-radius: remCalc(6px);
+ font-size: remCalc(13px);
+ color: color("greys", "dark");
+ // stylelint-disable-next-line function-url-quotes
+ background: color("whites", "bright") url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23798289'/%3E%3C/svg%3E") no-repeat right spacing("quarter") * 1.67 center;
+ background-size: remCalc(10px);
+ appearance: none;
+ cursor: pointer;
+ min-width: remCalc(180px);
+
+ &:disabled {
+ background-color: color("greys", "lighter");
+ color: color("greys", "medium");
+ cursor: not-allowed;
+ border-color: color("greys", "light");
+ }
+}
+
+.newReturn-submitRow {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: spacing("half");
+}
+
+.newReturn-submitBtn {
+ width: 100%;
+ max-width: remCalc(520px);
+ padding: remCalc(14px);
+ background: color("greys", "darkest");
+ color: color("whites", "bright");
+ border: 0;
+ border-radius: remCalc(8px);
+ font-size: remCalc(15px);
+ font-weight: fontWeight("semibold");
+ cursor: pointer;
+ transition: background 0.2s;
+
+ &:hover {
+ background: color("greys", "dark");
+ }
+
+ &:disabled {
+ background: color("greys", "medium");
+ cursor: not-allowed;
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 13d38eee83..6c6bd63f43 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"packages": {
"": {
"name": "bigcommerce-cornerstone",
- "version": "6.19.0",
+ "version": "6.19.1",
"license": "MIT",
"dependencies": {
"@bigcommerce/stencil-utils": "6.23.0",
diff --git a/templates/pages/account/add-return-new.html b/templates/pages/account/add-return-new.html
new file mode 100644
index 0000000000..24dcc3fa65
--- /dev/null
+++ b/templates/pages/account/add-return-new.html
@@ -0,0 +1,44 @@
+{{#partial "page"}}
+
+{{> components/common/breadcrumbs breadcrumbs=breadcrumbs}}
+{{> components/account/navigation account_page='returns'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{{/partial}}
+{{> layout/base}}