Browse Source

feat(dashboard): Product variant list

Michael Bromley 10 months ago
parent
commit
cd7bd1f52b

+ 2 - 2
packages/dashboard/src/components/layout/generated-breadcrumbs.tsx

@@ -10,7 +10,7 @@ import * as React from 'react';
 import { Fragment } from 'react';
 import { Fragment } from 'react';
 
 
 export interface BreadcrumbItem {
 export interface BreadcrumbItem {
-    label: string;
+    label: string | React.ReactNode;
     path: string;
     path: string;
 }
 }
 
 
@@ -20,7 +20,7 @@ export type PageBreadcrumb = BreadcrumbItem | BreadcrumbShorthand;
 
 
 export function GeneratedBreadcrumbs() {
 export function GeneratedBreadcrumbs() {
     const matches = useRouterState({ select: s => s.matches });
     const matches = useRouterState({ select: s => s.matches });
-    const breadcrumbs = matches
+    const breadcrumbs: BreadcrumbItem[] = matches
         .filter(match => match.loaderData?.breadcrumb)
         .filter(match => match.loaderData?.breadcrumb)
         .map(({ pathname, loaderData }) => {
         .map(({ pathname, loaderData }) => {
             if (typeof loaderData.breadcrumb === 'string') {
             if (typeof loaderData.breadcrumb === 'string') {

+ 1 - 1
packages/dashboard/src/components/shared/paginated-list-data-table.tsx

@@ -150,7 +150,7 @@ export function PaginatedListDataTable<
         );
         );
         
         
         const customFieldColumn = fields.find(field => field.name === 'customFields');
         const customFieldColumn = fields.find(field => field.name === 'customFields');
-        if (customFieldColumn) {
+        if (customFieldColumn && customFieldColumn.type !== 'JSON') {
             const customFieldFields = getTypeFieldInfo(customFieldColumn.type);
             const customFieldFields = getTypeFieldInfo(customFieldColumn.type);
             columnConfigs.push(
             columnConfigs.push(
                 ...customFieldFields.map(field => ({ fieldInfo: field, isCustomField: true })),
                 ...customFieldFields.map(field => ({ fieldInfo: field, isCustomField: true })),

+ 5 - 2
packages/dashboard/src/routes/_authenticated/_product-variants/product-variants.graphql.ts

@@ -3,8 +3,8 @@ import { graphql } from '@/graphql/graphql.js';
 
 
 export const productVariantListDocument = graphql(
 export const productVariantListDocument = graphql(
     `
     `
-        query ProductVariantList {
-            productVariants {
+        query ProductVariantLis($options: ProductVariantListOptions) {
+            productVariants(options: $options) {
                 items {
                 items {
                     id
                     id
                     createdAt
                     createdAt
@@ -14,6 +14,7 @@ export const productVariantListDocument = graphql(
                     }
                     }
                     name
                     name
                     sku
                     sku
+                    currencyCode
                     price
                     price
                     priceWithTax
                     priceWithTax
                     stockLevels {
                     stockLevels {
@@ -21,7 +22,9 @@ export const productVariantListDocument = graphql(
                         stockOnHand
                         stockOnHand
                         stockAllocated
                         stockAllocated
                     }
                     }
+                    customFields
                 }
                 }
+                totalItems
             }
             }
         }
         }
     `,
     `,

+ 49 - 8
packages/dashboard/src/routes/_authenticated/_product-variants/product-variants.tsx

@@ -1,29 +1,70 @@
-import { Button } from '@/components/ui/button.js';
 import { PageActionBar } from '@/framework/layout-engine/page-layout.js';
 import { PageActionBar } from '@/framework/layout-engine/page-layout.js';
 import { ListPage } from '@/framework/page/list-page.js';
 import { ListPage } from '@/framework/page/list-page.js';
+import { Trans } from '@lingui/react/macro';
 import { createFileRoute, Link } from '@tanstack/react-router';
 import { createFileRoute, Link } from '@tanstack/react-router';
 import { productVariantListDocument } from './product-variants.graphql.js';
 import { productVariantListDocument } from './product-variants.graphql.js';
+import { Button } from '@/components/ui/button.js';
+import { Money } from '@/components/data-type-components/money.js';
+import { useLocalFormat } from '@/hooks/use-local-format.js';
 
 
 export const Route = createFileRoute('/_authenticated/_product-variants/product-variants')({
 export const Route = createFileRoute('/_authenticated/_product-variants/product-variants')({
     component: ProductListPage,
     component: ProductListPage,
-    loader: () => ({ breadcrumb: 'Products' }),
+    loader: () => ({ breadcrumb: 'Product' }),
 });
 });
 
 
 export function ProductListPage() {
 export function ProductListPage() {
+    const { formatCurrencyName } = useLocalFormat();
     return (
     return (
         <ListPage
         <ListPage
-            title="Products"
+            title={<Trans>Product Variants</Trans>}
             customizeColumns={{
             customizeColumns={{
-               /*  name: {
+                name: {
                     header: 'Product Name',
                     header: 'Product Name',
                     cell: ({ row }) => {
                     cell: ({ row }) => {
                         return (
                         return (
-                            <Link to={`./${row.original.id}`}>
-                                <Button variant="ghost">{row.original.name}</Button>
-                            </Link>
+                            <Button asChild variant="ghost">
+                                <Link to={`./${row.original.id}`}>{row.original.name} </Link>
+                            </Button>
                         );
                         );
                     },
                     },
-                }, */
+                },
+                currencyCode: {
+                    cell: ({ cell, row }) => {
+                        const value = cell.getValue();
+                        return formatCurrencyName(value as string, 'full');
+                    },
+                },
+                price: {
+                    cell: ({ cell, row }) => {
+                        const value = cell.getValue();
+                        const currencyCode = row.original.currencyCode;
+                        if (typeof value === 'number') {
+                            return <Money value={value} currency={currencyCode} />;
+                        }
+                        return value;
+                    },
+                },
+                priceWithTax: {
+                    cell: ({ cell, row }) => {
+                        const value = cell.getValue();
+                        const currencyCode = row.original.currencyCode;
+                        if (typeof value === 'number') {
+                            return <Money value={value} currency={currencyCode} />;
+                        }
+                        return value;
+                    },
+                },
+                stockLevels: {
+                    cell: ({ cell, row }) => {
+                        const value = cell.getValue();
+                        if (Array.isArray(value)) {
+                            const totalOnHand = value.reduce((acc, curr) => acc + curr.stockOnHand, 0);
+                            const totalAllocated = value.reduce((acc, curr) => acc + curr.stockAllocated, 0);
+                            return <span>{totalOnHand} / {totalAllocated}</span>;
+                        }
+                        return value;
+                    },
+                },
             }}
             }}
             onSearchTermChange={searchTerm => {
             onSearchTermChange={searchTerm => {
                 return {
                 return {

+ 1 - 0
packages/dashboard/src/routes/_authenticated/_products/products.graphql.ts

@@ -43,6 +43,7 @@ export const productDetailFragment = graphql(
                 name
                 name
                 slug
                 slug
                 description
                 description
+                customFields
             }
             }
 
 
             facetValues {
             facetValues {

+ 1 - 1
packages/dashboard/src/routes/_authenticated/_products/products_.$id.tsx

@@ -91,7 +91,7 @@ export function ProductDetailPage() {
             toast(i18n.t('Successfully updated product'), {
             toast(i18n.t('Successfully updated product'), {
                 position: 'top-right',
                 position: 'top-right',
             });
             });
-            form.reset();
+            form.reset(form.getValues());
             if (creatingNewEntity) {
             if (creatingNewEntity) {
                 navigate({ to: `../${data.id}`, from: Route.id });
                 navigate({ to: `../${data.id}`, from: Route.id });
             }
             }