fix(dashboard): show correct color indicators for payment and fulfillment status columns for view_configuration feature flag (#14215)
## 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
This commit is contained in:
@@ -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<TData = any> = (
|
||||
value: any,
|
||||
@@ -27,96 +30,104 @@ export type RendererRegistry = Map<string, CellRenderer>
|
||||
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 <ProductStatusCell status={row.status} />
|
||||
}
|
||||
|
||||
// Generic status badge
|
||||
if (column.context === "payment" && t) {
|
||||
const { label, color } = getOrderPaymentStatus(t, value)
|
||||
return <StatusBadge color={color}>{label}</StatusBadge>
|
||||
}
|
||||
|
||||
if (column.context === "fulfillment" && t) {
|
||||
const { label, color } = getOrderFulfillmentStatus(t, value)
|
||||
return <StatusBadge color={color}>{label}</StatusBadge>
|
||||
}
|
||||
|
||||
// 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 (
|
||||
<StatusBadge color={getStatusColor(value)}>
|
||||
{translatedValue}
|
||||
</StatusBadge>
|
||||
<StatusBadge color={getStatusColor(value)}>{translatedValue}</StatusBadge>
|
||||
)
|
||||
}
|
||||
|
||||
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 <SalesChannelsCell salesChannels={row.sales_channels} />
|
||||
}
|
||||
|
||||
// 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) => {
|
||||
<div className="flex gap-1">
|
||||
{items.map((item, index) => (
|
||||
<Badge key={index} size="xsmall">
|
||||
{typeof item === 'string' ? item : item.name || item.title || '-'}
|
||||
{typeof item === "string" ? item : item.name || item.title || "-"}
|
||||
</Badge>
|
||||
))}
|
||||
{remaining > 0 && (
|
||||
<Badge size="xsmall" color="grey">
|
||||
{t ? t('general.plusCountMore', '+ {{count}} more', { count: remaining }) : `+${remaining}`}
|
||||
{t
|
||||
? t("general.plusCountMore", "+ {{count}} more", {
|
||||
count: remaining,
|
||||
})
|
||||
: `+${remaining}`}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
@@ -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 <MoneyAmountCell currencyCode={currencyCode} amount={value} align="right" />
|
||||
const currencyCode = row.currency_code || "USD"
|
||||
return (
|
||||
<MoneyAmountCell currencyCode={currencyCode} amount={value} align="right" />
|
||||
)
|
||||
}
|
||||
|
||||
const TotalRenderer: CellRenderer = (value, row, _column, _t) => {
|
||||
const currencyCode = row.currency_code || 'USD'
|
||||
const currencyCode = row.currency_code || "USD"
|
||||
return <TotalCell currencyCode={currencyCode} total={value} />
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user