From 3e3e6c37bd325cd78370aa4783666117ea665bb8 Mon Sep 17 00:00:00 2001 From: Nicolas Gorga <62995075+NicolasGorga@users.noreply.github.com> Date: Fri, 5 Dec 2025 08:59:34 -0300 Subject: [PATCH] fix(dashboard): show correct color indicators for payment and fulfillment status columns for `view_configuration` feature flag (#14215) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary **What** — What changes are introduced in this PR? Show correct color indicator for payment and fulfillment status columns when `view_configuration` feature flag is enabled on order data table. **Why** — Why are these changes relevant or necessary? For non canceled status, grey default indicator was shown, as these columns weren't handled with their dedicated helper functions. **How** — How have these changes been implemented? Updated `StatusRenderer` to resolve the label and color for these columns with their helper functions, just like we do for the normal order table. **Testing** — How have these changes been tested, or how can the reviewer test the feature? Validated Admin UI shows correct color indicators when `view_configuration` is enabled. --- ## Examples Provide examples or code snippets that demonstrate how this feature works, or how it can be used in practice. This helps with documentation and ensures maintainers can quickly understand and verify the change. ```ts // Example usage ``` --- ## Checklist Please ensure the following before requesting a review: - [x] I have added a **changeset** for this PR - Every non-breaking change should be marked as a **patch** - To add a changeset, run `yarn changeset` and follow the prompts - [ ] The changes are covered by relevant **tests** - [x] I have verified the code works as intended locally - [x] I have linked the related issue(s) if applicable --- ## Additional Context Add any additional context, related issues, or references that might help the reviewer understand this PR. closes CORE-1309 --- .changeset/tough-jeans-shop.md | 5 + .../src/lib/table/cell-renderers.tsx | 185 ++++++++++-------- 2 files changed, 107 insertions(+), 83 deletions(-) create mode 100644 .changeset/tough-jeans-shop.md diff --git a/.changeset/tough-jeans-shop.md b/.changeset/tough-jeans-shop.md new file mode 100644 index 0000000000..5cf1859839 --- /dev/null +++ b/.changeset/tough-jeans-shop.md @@ -0,0 +1,5 @@ +--- +"@medusajs/dashboard": patch +--- + +fix(dashboard): show correct color indicators for payment and fulfillment status columns for `view_configuration` feature flag diff --git a/packages/admin/dashboard/src/lib/table/cell-renderers.tsx b/packages/admin/dashboard/src/lib/table/cell-renderers.tsx index d5f91ec76a..50675408e9 100644 --- a/packages/admin/dashboard/src/lib/table/cell-renderers.tsx +++ b/packages/admin/dashboard/src/lib/table/cell-renderers.tsx @@ -13,7 +13,10 @@ import { DisplayIdCell } from "../../components/table/table-cells/order/display- import { TotalCell } from "../../components/table/table-cells/order/total-cell" import { MoneyAmountCell } from "../../components/table/table-cells/common/money-amount-cell" import { TFunction } from "i18next" -import { toCamelCase } from "../common" +import { + getOrderPaymentStatus, + getOrderFulfillmentStatus, +} from "../order-helpers" export type CellRenderer = ( value: any, @@ -27,96 +30,104 @@ export type RendererRegistry = Map const cellRenderers: RendererRegistry = new Map() const getNestedValue = (obj: any, path: string) => { - return path.split('.').reduce((current, key) => current?.[key], obj) + return path.split(".").reduce((current, key) => current?.[key], obj) } const TextRenderer: CellRenderer = (value, _row, _column, _t) => { - if (value === null || value === undefined) return '-' + if (value === null || value === undefined) return "-" return String(value) } const CountRenderer: CellRenderer = (value, _row, _column, t) => { const items = value || [] const count = Array.isArray(items) ? items.length : 0 - return t('general.items', { count }) + return t("general.items", { count }) } const StatusRenderer: CellRenderer = (value, row, column, t) => { - if (!value) return '-' + if (!value) return "-" - if (column.field === 'status' && row.status && (row.handle || row.is_giftcard !== undefined)) { + if ( + column.field === "status" && + row.status && + (row.handle || row.is_giftcard !== undefined) + ) { return } - // Generic status badge + if (column.context === "payment" && t) { + const { label, color } = getOrderPaymentStatus(t, value) + return {label} + } + + if (column.context === "fulfillment" && t) { + const { label, color } = getOrderFulfillmentStatus(t, value) + return {label} + } + + // Generic status badge for other status types const getStatusColor = (status: string) => { switch (status?.toLowerCase()) { - case 'active': - case 'published': - case 'fulfilled': - case 'paid': - return 'green' - case 'pending': - case 'proposed': - case 'processing': - return 'orange' - case 'draft': - return 'grey' - case 'rejected': - case 'failed': - case 'canceled': - return 'red' + case "active": + case "published": + case "fulfilled": + case "paid": + return "green" + case "pending": + case "proposed": + case "processing": + return "orange" + case "draft": + return "grey" + case "rejected": + case "failed": + case "canceled": + return "red" default: - return 'grey' + return "grey" } } // Use existing translation keys where available - const getTranslatedStatus = (status: string, column: HttpTypes.AdminColumn): string => { + const getTranslatedStatus = (status: string): string => { if (!t) return status const lowerStatus = status.toLowerCase() - const camelCaseStatus = toCamelCase(lowerStatus) switch (lowerStatus) { - case 'active': - return t('general.active', 'Active') as string - case 'published': - return t('products.productStatus.published', 'Published') as string - case 'draft': - return t('orders.status.draft', 'Draft') as string - case 'pending': - return t('orders.status.pending', 'Pending') as string - case 'canceled': - return t('orders.status.canceled', 'Canceled') as string + case "active": + return t("general.active", "Active") as string + case "published": + return t("products.productStatus.published", "Published") as string + case "draft": + return t("orders.status.draft", "Draft") as string + case "pending": + return t("orders.status.pending", "Pending") as string + case "canceled": + return t("orders.status.canceled", "Canceled") as string default: - if (column.context === 'payment') { - return t(`orders.payment.status.${camelCaseStatus}`, status) as string - } - if (column.context === 'fulfillment') { - return t(`orders.fulfillment.status.${camelCaseStatus}`, status) as string - } // Try generic status translation with fallback return t(`status.${lowerStatus}`, status) as string } } - const translatedValue = getTranslatedStatus(value, column) + const translatedValue = getTranslatedStatus(value) return ( - - {translatedValue} - + {translatedValue} ) } const BadgeListRenderer: CellRenderer = (value, row, column, t) => { // For sales channels - if (column.field === 'sales_channels_display' || column.field === 'sales_channels') { + if ( + column.field === "sales_channels_display" || + column.field === "sales_channels" + ) { return } // Generic badge list - if (!Array.isArray(value)) return '-' + if (!Array.isArray(value)) return "-" const items = value.slice(0, 2) const remaining = value.length - 2 @@ -125,12 +136,16 @@ const BadgeListRenderer: CellRenderer = (value, row, column, t) => {
{items.map((item, index) => ( - {typeof item === 'string' ? item : item.name || item.title || '-'} + {typeof item === "string" ? item : item.name || item.title || "-"} ))} {remaining > 0 && ( - {t ? t('general.plusCountMore', '+ {{count}} more', { count: remaining }) : `+${remaining}`} + {t + ? t("general.plusCountMore", "+ {{count}} more", { + count: remaining, + }) + : `+${remaining}`} )}
@@ -152,7 +167,9 @@ const VariantsRenderer: CellRenderer = (_, row, _column, _t) => { // Order-specific renderers const CustomerNameRenderer: CellRenderer = (_, row, _column, t) => { if (row.customer?.first_name || row.customer?.last_name) { - const fullName = `${row.customer.first_name || ''} ${row.customer.last_name || ''}`.trim() + const fullName = `${row.customer.first_name || ""} ${ + row.customer.last_name || "" + }`.trim() if (fullName) return fullName } @@ -166,20 +183,20 @@ const CustomerNameRenderer: CellRenderer = (_, row, _column, t) => { return row.customer.phone } - return t ? t('customers.guest', 'Guest') : 'Guest' + return t ? t("customers.guest", "Guest") : "Guest" } const AddressSummaryRenderer: CellRenderer = (_, row, column, _t) => { let address = null - if (column.field === 'shipping_address_display') { + if (column.field === "shipping_address_display") { address = row.shipping_address - } else if (column.field === 'billing_address_display') { + } else if (column.field === "billing_address_display") { address = row.billing_address } else { address = row.shipping_address || row.billing_address } - if (!address) return '-' + if (!address) return "-" const parts = [] @@ -193,14 +210,14 @@ const AddressSummaryRenderer: CellRenderer = (_, row, column, _t) => { if (address.postal_code) locationParts.push(address.postal_code) if (locationParts.length > 0) { - parts.push(locationParts.join(', ')) + parts.push(locationParts.join(", ")) } if (address.country_code) { parts.push(address.country_code.toUpperCase()) } - return parts.join(' • ') || '-' + return parts.join(" • ") || "-" } const CountryCodeRenderer: CellRenderer = (_, row, _column, _t) => { @@ -239,36 +256,38 @@ const DisplayIdRenderer: CellRenderer = (value, _row, _column, _t) => { } const CurrencyRenderer: CellRenderer = (value, row, _column, _t) => { - const currencyCode = row.currency_code || 'USD' - return + const currencyCode = row.currency_code || "USD" + return ( + + ) } const TotalRenderer: CellRenderer = (value, row, _column, _t) => { - const currencyCode = row.currency_code || 'USD' + const currencyCode = row.currency_code || "USD" return } // Register built-in renderers -cellRenderers.set('text', TextRenderer) -cellRenderers.set('count', CountRenderer) -cellRenderers.set('status', StatusRenderer) -cellRenderers.set('badge_list', BadgeListRenderer) -cellRenderers.set('date', DateRenderer) -cellRenderers.set('timestamp', DateRenderer) -cellRenderers.set('currency', CurrencyRenderer) -cellRenderers.set('total', TotalRenderer) +cellRenderers.set("text", TextRenderer) +cellRenderers.set("count", CountRenderer) +cellRenderers.set("status", StatusRenderer) +cellRenderers.set("badge_list", BadgeListRenderer) +cellRenderers.set("date", DateRenderer) +cellRenderers.set("timestamp", DateRenderer) +cellRenderers.set("currency", CurrencyRenderer) +cellRenderers.set("total", TotalRenderer) // Register product-specific renderers -cellRenderers.set('product_info', ProductInfoRenderer) -cellRenderers.set('collection', CollectionRenderer) -cellRenderers.set('variants', VariantsRenderer) -cellRenderers.set('sales_channels_list', BadgeListRenderer) +cellRenderers.set("product_info", ProductInfoRenderer) +cellRenderers.set("collection", CollectionRenderer) +cellRenderers.set("variants", VariantsRenderer) +cellRenderers.set("sales_channels_list", BadgeListRenderer) // Register order-specific renderers -cellRenderers.set('customer_name', CustomerNameRenderer) -cellRenderers.set('address_summary', AddressSummaryRenderer) -cellRenderers.set('country_code', CountryCodeRenderer) -cellRenderers.set('display_id', DisplayIdRenderer) +cellRenderers.set("customer_name", CustomerNameRenderer) +cellRenderers.set("address_summary", AddressSummaryRenderer) +cellRenderers.set("country_code", CountryCodeRenderer) +cellRenderers.set("display_id", DisplayIdRenderer) export function getCellRenderer( renderType?: string, @@ -279,21 +298,21 @@ export function getCellRenderer( } switch (dataType) { - case 'number': - case 'string': + case "number": + case "string": return TextRenderer - case 'date': + case "date": return DateRenderer - case 'boolean': + case "boolean": return (value, _row, _column, t) => { if (t) { - return value ? t('fields.yes', 'Yes') : t('fields.no', 'No') + return value ? t("fields.yes", "Yes") : t("fields.no", "No") } - return value ? 'Yes' : 'No' + return value ? "Yes" : "No" } - case 'enum': + case "enum": return StatusRenderer - case 'currency': + case "currency": return CurrencyRenderer default: return TextRenderer