Browse Source

fix(dashboard): Improve display of description columns

Michael Bromley 3 months ago
parent
commit
ef828f9c2f

+ 1 - 0
packages/dashboard/src/app/routes/_authenticated/_collections/collections.graphql.ts

@@ -20,6 +20,7 @@ export const collectionListDocument = graphql(
                     }
                     name
                     slug
+                    description
                     breadcrumbs {
                         id
                         name

+ 5 - 0
packages/dashboard/src/app/routes/_authenticated/_collections/collections.tsx

@@ -13,6 +13,7 @@ import { ResultOf } from 'gql.tada';
 import { Folder, FolderOpen, PlusIcon } from 'lucide-react';
 import { useState } from 'react';
 
+import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
 import { Badge } from '@/vdb/components/ui/badge.js';
 import { collectionListDocument } from './collections.graphql.js';
 import {
@@ -123,6 +124,9 @@ function CollectionListPage() {
                             );
                         },
                     },
+                    description: {
+                        cell: RichTextDescriptionCell,
+                    },
                     breadcrumbs: {
                         cell: ({ cell }) => {
                             const value = cell.getValue();
@@ -204,6 +208,7 @@ function CollectionListPage() {
                     position: false,
                     parentId: false,
                     children: false,
+                    description: false,
                 }}
                 onSearchTermChange={searchTerm => {
                     return {

+ 4 - 0
packages/dashboard/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx

@@ -1,6 +1,7 @@
 import { BooleanDisplayBadge } from '@/vdb/components/data-display/boolean.js';
 import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
 import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
+import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
 import { Button } from '@/vdb/components/ui/button.js';
 import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
 import { ListPage } from '@/vdb/framework/page/list-page.js';
@@ -53,6 +54,9 @@ function PaymentMethodListPage() {
                 enabled: {
                     cell: ({ row }) => <BooleanDisplayBadge value={row.original.enabled} />,
                 },
+                description: {
+                    cell: RichTextDescriptionCell,
+                },
             }}
             bulkActions={[
                 {

+ 4 - 0
packages/dashboard/src/app/routes/_authenticated/_products/products.tsx

@@ -1,5 +1,6 @@
 import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
 import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
+import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
 import { Button } from '@/vdb/components/ui/button.js';
 import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
 import { ListPage } from '@/vdb/framework/page/list-page.js';
@@ -48,6 +49,9 @@ function ProductListPage() {
                 name: {
                     cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
                 },
+                description: {
+                    cell: RichTextDescriptionCell,
+                },
             }}
             onSearchTermChange={searchTerm => {
                 return {

+ 4 - 0
packages/dashboard/src/app/routes/_authenticated/_promotions/promotions.tsx

@@ -1,6 +1,7 @@
 import { BooleanDisplayBadge } from '@/vdb/components/data-display/boolean.js';
 import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
 import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
+import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
 import { Button } from '@/vdb/components/ui/button.js';
 import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
 import { ListPage } from '@/vdb/framework/page/list-page.js';
@@ -47,6 +48,9 @@ function PromotionListPage() {
                 enabled: {
                     cell: ({ row }) => <BooleanDisplayBadge value={row.original.enabled} />,
                 },
+                description: {
+                    cell: RichTextDescriptionCell,
+                },
             }}
             bulkActions={[
                 {

+ 4 - 0
packages/dashboard/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx

@@ -1,5 +1,6 @@
 import { DetailPageButton } from '@/vdb/components/shared/detail-page-button.js';
 import { PermissionGuard } from '@/vdb/components/shared/permission-guard.js';
+import { RichTextDescriptionCell } from '@/vdb/components/shared/table-cell/order-table-cell-components.js';
 import { Button } from '@/vdb/components/ui/button.js';
 import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
 import { ListPage } from '@/vdb/framework/page/list-page.js';
@@ -35,6 +36,9 @@ function ShippingMethodListPage() {
                 name: {
                     cell: ({ row }) => <DetailPageButton id={row.original.id} label={row.original.name} />,
                 },
+                description: {
+                    cell: RichTextDescriptionCell,
+                },
             }}
             onSearchTermChange={searchTerm => {
                 return {

+ 40 - 0
packages/dashboard/src/lib/components/shared/table-cell/order-table-cell-components.tsx

@@ -4,6 +4,8 @@ import { Badge } from '@/vdb/components/ui/badge.js';
 import { Button } from '@/vdb/components/ui/button.js';
 import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
 import { Link } from '@tanstack/react-router';
+import { ChevronDown, ChevronUp } from 'lucide-react';
+import { useMemo, useState } from 'react';
 
 type CustomerCellData = {
     customer: {
@@ -38,3 +40,41 @@ export const OrderMoneyCell: DataTableCellComponent<{ currencyCode: string }> =
     const currencyCode = row.original.currencyCode;
     return <Money value={value} currency={currencyCode} />;
 };
+
+export const RichTextDescriptionCell: DataTableCellComponent<{ description: string }> = ({ cell }) => {
+    const [isExpanded, setIsExpanded] = useState(false);
+    const value = cell.getValue();
+
+    // Strip HTML tags and decode HTML entities
+    const textContent = useMemo(() => {
+        const stripped = value?.replace(/<[^>]*>/g, '') || '';
+        const textArea = document.createElement('textarea');
+        textArea.innerHTML = stripped;
+        return textArea.value;
+    }, [value]);
+
+    const shortLength = 100;
+    const maxLength = 500;
+    const isTooLong = textContent.length > shortLength;
+
+    const displayText = isExpanded ? textContent.slice(0, maxLength) : textContent.slice(0, shortLength);
+
+    return (
+        <div>
+            <div>
+                {displayText}
+                {!isExpanded && isTooLong && '...'}
+            </div>
+            {!isExpanded && isTooLong && (
+                <Button onClick={() => setIsExpanded(true)} variant="ghost" size="xs">
+                    <ChevronDown />
+                </Button>
+            )}
+            {isExpanded && (
+                <Button onClick={() => setIsExpanded(false)} variant="ghost" size="xs">
+                    <ChevronUp />
+                </Button>
+            )}
+        </div>
+    );
+};