From 2e593e4b9d6107efb292c3d96924f329b555b7ae Mon Sep 17 00:00:00 2001
From: larryro <371767072@qq.com>
Date: Sun, 15 Mar 2026 19:10:57 +0800
Subject: [PATCH 1/2] feat: remove standalone approvals page and consolidate
 into chat

Remove the dedicated approvals route, components, hooks, and types.
Move approval mutation/query logic into the chat feature and update
navigation items accordingly.
---
 .../components/approval-detail-dialog.tsx     | 251 --------------
 .../components/approvals-navigation.tsx       |  33 --
 .../approvals/components/approvals.tsx        | 221 ------------
 .../approvals/get-approval-detail.ts          | 103 ------
 .../approvals/product-list-cell.tsx           | 138 --------
 .../approvals/use-approval-columns.tsx        | 317 ------------------
 .../approvals/components/product-card.tsx     | 144 --------
 .../app/features/approvals/hooks/actions.ts   |  20 --
 .../app/features/approvals/hooks/mutations.ts |  10 -
 .../app/features/approvals/hooks/queries.ts   |  54 ---
 .../approvals/types/approval-detail.ts        |  50 ---
 .../components/integration-approval-card.tsx  |   6 +-
 .../workflow-creation-approval-card.tsx       |   6 +-
 .../components/workflow-run-approval-card.tsx |   6 +-
 .../workflow-update-approval-card.tsx         |   6 +-
 .../app/features/chat/hooks/mutations.ts      |  23 ++
 .../app/features/chat/hooks/queries.ts        |  13 +-
 .../app/hooks/use-navigation-items.ts         |  34 +-
 services/platform/app/routeTree.gen.ts        |  52 ---
 .../app/routes/dashboard/$id/approvals.tsx    |  65 ----
 .../dashboard/$id/approvals/$status.tsx       |  85 -----
 services/platform/messages/en.json            |  80 -----
 22 files changed, 53 insertions(+), 1664 deletions(-)
 delete mode 100644 services/platform/app/features/approvals/components/approval-detail-dialog.tsx
 delete mode 100644 services/platform/app/features/approvals/components/approvals-navigation.tsx
 delete mode 100644 services/platform/app/features/approvals/components/approvals.tsx
 delete mode 100644 services/platform/app/features/approvals/components/approvals/get-approval-detail.ts
 delete mode 100644 services/platform/app/features/approvals/components/approvals/product-list-cell.tsx
 delete mode 100644 services/platform/app/features/approvals/components/approvals/use-approval-columns.tsx
 delete mode 100644 services/platform/app/features/approvals/components/product-card.tsx
 delete mode 100644 services/platform/app/features/approvals/hooks/actions.ts
 delete mode 100644 services/platform/app/features/approvals/hooks/mutations.ts
 delete mode 100644 services/platform/app/features/approvals/hooks/queries.ts
 delete mode 100644 services/platform/app/features/approvals/types/approval-detail.ts
 delete mode 100644 services/platform/app/routes/dashboard/$id/approvals.tsx
 delete mode 100644 services/platform/app/routes/dashboard/$id/approvals/$status.tsx

diff --git a/services/platform/app/features/approvals/components/approval-detail-dialog.tsx b/services/platform/app/features/approvals/components/approval-detail-dialog.tsx
deleted file mode 100644
index aae872e4d2..0000000000
--- a/services/platform/app/features/approvals/components/approval-detail-dialog.tsx
+++ /dev/null
@@ -1,251 +0,0 @@
-'use client';
-
-import { Sparkles } from 'lucide-react';
-import { useState, useMemo } from 'react';
-
-import {
-  type StatGridItem,
-  StatGrid,
-} from '@/app/components/ui/data-display/stat-grid';
-import { Dialog } from '@/app/components/ui/dialog/dialog';
-import { Badge } from '@/app/components/ui/feedback/badge';
-import { HStack, Stack } from '@/app/components/ui/layout/layout';
-import { PageSection } from '@/app/components/ui/layout/page-section';
-import { SectionHeader } from '@/app/components/ui/layout/section-header';
-import { Button } from '@/app/components/ui/primitives/button';
-import { Text } from '@/app/components/ui/typography/text';
-import { CustomerInfoDialog } from '@/app/features/customers/components/customer-info-dialog';
-import {
-  useCustomerByEmail,
-  useCustomers,
-} from '@/app/features/customers/hooks/queries';
-import { useFormatDate } from '@/app/hooks/use-format-date';
-import { useT } from '@/lib/i18n/client';
-import { cn } from '@/lib/utils/cn';
-
-import { ApprovalDetail } from '../types/approval-detail';
-import { ProductCard } from './product-card';
-
-const RecommendationIcon = () => (
-  <Sparkles className="text-muted-foreground size-4" />
-);
-
-interface ApprovalDetailDialogProps {
-  open: boolean;
-  onOpenChange: (open: boolean) => void;
-  approvalDetail: ApprovalDetail | null;
-  onApprove?: (approvalId: string) => void;
-  onReject?: (approvalId: string) => void;
-  isApproving?: boolean;
-  isRejecting?: boolean;
-  onRemoveRecommendation?: (approvalId: string, productId: string) => void;
-  removingProductId?: string | null;
-}
-
-export function ApprovalDetailDialog({
-  open,
-  onOpenChange,
-  approvalDetail,
-  onApprove,
-  onReject,
-  isApproving,
-  isRejecting,
-  onRemoveRecommendation,
-  removingProductId,
-}: ApprovalDetailDialogProps) {
-  const { t } = useT('approvals');
-  const { formatDate } = useFormatDate();
-  const [customerInfoOpen, setCustomerInfoOpen] = useState(false);
-
-  const { customers } = useCustomers(approvalDetail?.organizationId ?? '');
-  const customerRecord = useCustomerByEmail(
-    customers,
-    approvalDetail?.customer.email,
-  );
-
-  // Sort products by confidence (high to low) and get first product
-  const approvalStatItems = useMemo<StatGridItem[]>(
-    () => [
-      {
-        label: t('detail.status'),
-        value: (
-          <Badge
-            dot
-            variant={
-              (approvalDetail?.status === 'pending' && 'orange') ||
-              (approvalDetail?.status === 'approved' && 'green') ||
-              (approvalDetail?.status === 'rejected' && 'destructive') ||
-              'outline'
-            }
-          >
-            {(approvalDetail?.status === 'pending' &&
-              t('detail.statusPending')) ||
-              (approvalDetail?.status === 'approved' &&
-                t('detail.statusApproved')) ||
-              (approvalDetail?.status === 'rejected' &&
-                t('detail.statusRejected')) ||
-              t('detail.statusPending')}
-          </Badge>
-        ),
-      },
-      {
-        label: t('detail.type'),
-        value: (
-          <Badge variant="outline" icon={RecommendationIcon}>
-            {t('detail.typeProductRecommendation')}
-          </Badge>
-        ),
-      },
-      {
-        label: t('detail.createdAt'),
-        value: (
-          <Text>
-            {approvalDetail?.createdAt
-              ? formatDate(new Date(approvalDetail.createdAt), 'long')
-              : ''}
-          </Text>
-        ),
-      },
-      ...(approvalDetail?.confidence !== undefined
-        ? [
-            {
-              label: t('detail.confidence'),
-              value: (
-                <Badge variant="outline">{approvalDetail.confidence}%</Badge>
-              ),
-            },
-          ]
-        : []),
-    ],
-    [approvalDetail, t, formatDate],
-  );
-
-  const sortedProducts = useMemo(() => {
-    if (!approvalDetail) return [];
-    return [...approvalDetail.recommendedProducts].sort((a, b) => {
-      const confA = a.confidence ?? 0;
-      const confB = b.confidence ?? 0;
-      return confB - confA;
-    });
-  }, [approvalDetail]);
-
-  if (!approvalDetail) return null;
-
-  const handleRemoveRecommendation = (productId: string) => {
-    if (!onRemoveRecommendation) return;
-    onRemoveRecommendation(approvalDetail._id, productId);
-  };
-
-  const visibleProducts = sortedProducts.slice(0, 3);
-
-  const footer =
-    approvalDetail.status === 'pending' ? (
-      <HStack gap={3} className="w-full">
-        <Button
-          onClick={() => onReject?.(approvalDetail._id)}
-          disabled={isApproving || isRejecting}
-          variant="secondary"
-          className="flex-1"
-        >
-          {t('detail.reject')}
-        </Button>
-        <Button
-          onClick={() => onApprove?.(approvalDetail._id)}
-          disabled={isApproving || isRejecting}
-          className="flex-1"
-        >
-          {t('detail.approve')}
-        </Button>
-      </HStack>
-    ) : undefined;
-
-  return (
-    <>
-      <Dialog
-        open={open}
-        size="md"
-        onOpenChange={onOpenChange}
-        title={t('detail.title')}
-        className="flex max-h-[90vh] w-full flex-col gap-0 overflow-hidden p-0 sm:p-0"
-        footer={footer}
-        footerClassName="p-4 border-t border-border bg-background"
-        customHeader={
-          <div className="border-border border-b px-4 py-6">
-            <SectionHeader title={t('detail.title')} />
-          </div>
-        }
-      >
-        {/* Content */}
-        <Stack
-          gap={10}
-          className={cn(
-            'p-4 max-h-[calc(100%-88px)] overflow-y-auto',
-            approvalDetail.status === 'pending' && 'pb-4',
-          )}
-        >
-          {/* Customer Info */}
-          <Stack gap={8}>
-            <SectionHeader
-              as="h3"
-              weight="medium"
-              title={approvalDetail.customer.name}
-              description={approvalDetail.customer.email}
-            />
-
-            <StatGrid items={approvalStatItems} />
-          </Stack>
-
-          {/* Recommended Products */}
-          {visibleProducts.length > 0 && (
-            <PageSection
-              as="h3"
-              titleSize="lg"
-              title={t('detail.recommendedProducts')}
-            >
-              <div className="border-border overflow-hidden rounded-[10px] border">
-                {visibleProducts.map((product) => (
-                  <ProductCard
-                    key={product.id}
-                    product={product}
-                    type="recommended"
-                    canRemove={approvalDetail.status === 'pending'}
-                    onRemove={handleRemoveRecommendation}
-                    isRemoving={removingProductId === product.id}
-                  />
-                ))}
-              </div>
-            </PageSection>
-          )}
-
-          {/* Previous Purchases */}
-          {approvalDetail.previousPurchases.length > 0 && (
-            <PageSection
-              as="h3"
-              titleSize="lg"
-              title={t('detail.userPurchased')}
-            >
-              <div className="border-border overflow-hidden rounded-[10px] border">
-                {approvalDetail.previousPurchases.map((purchase) => (
-                  <ProductCard
-                    key={purchase.id || purchase.productName}
-                    purchase={purchase}
-                    type="purchase"
-                  />
-                ))}
-              </div>
-            </PageSection>
-          )}
-        </Stack>
-      </Dialog>
-
-      {/* Nested dialog for Customer Information */}
-      {customerRecord && (
-        <CustomerInfoDialog
-          customer={customerRecord}
-          open={customerInfoOpen}
-          onOpenChange={setCustomerInfoOpen}
-        />
-      )}
-    </>
-  );
-}
diff --git a/services/platform/app/features/approvals/components/approvals-navigation.tsx b/services/platform/app/features/approvals/components/approvals-navigation.tsx
deleted file mode 100644
index a2c7c4201f..0000000000
--- a/services/platform/app/features/approvals/components/approvals-navigation.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-'use client';
-
-import {
-  TabNavigation,
-  type TabNavigationItem,
-} from '@/app/components/ui/navigation/tab-navigation';
-import { useT } from '@/lib/i18n/client';
-
-interface ApprovalsNavigationProps {
-  organizationId: string;
-}
-
-const STATUSES = ['pending', 'resolved'] as const;
-
-export function ApprovalsNavigation({
-  organizationId,
-}: ApprovalsNavigationProps) {
-  const { t } = useT('approvals');
-
-  const navigationItems: TabNavigationItem[] = STATUSES.map((status) => ({
-    label: t(`status.${status}`),
-    href: `/dashboard/${organizationId}/approvals/${status}`,
-  }));
-
-  return (
-    <TabNavigation
-      items={navigationItems}
-      standalone={false}
-      className="py-2"
-      prefetch
-    />
-  );
-}
diff --git a/services/platform/app/features/approvals/components/approvals.tsx b/services/platform/app/features/approvals/components/approvals.tsx
deleted file mode 100644
index ddd05b184a..0000000000
--- a/services/platform/app/features/approvals/components/approvals.tsx
+++ /dev/null
@@ -1,221 +0,0 @@
-'use client';
-
-import type { UsePaginatedQueryResult } from 'convex/react';
-
-import { GitCompare } from 'lucide-react';
-import { useState, useCallback, useMemo } from 'react';
-
-import type { Doc } from '@/convex/_generated/dataModel';
-
-import { DataTable } from '@/app/components/ui/data-table/data-table';
-import { useListPage } from '@/app/hooks/use-list-page';
-import { toast } from '@/app/hooks/use-toast';
-import { toId } from '@/convex/lib/type_cast_helpers';
-import { useT } from '@/lib/i18n/client';
-
-import {
-  useRemoveRecommendedProduct,
-  useUpdateApprovalStatus,
-} from '../hooks/mutations';
-import { ApprovalDetailDialog } from './approval-detail-dialog';
-import { getApprovalDetail } from './approvals/get-approval-detail';
-import { useApprovalColumns } from './approvals/use-approval-columns';
-
-type ApprovalItem = Doc<'approvals'>;
-
-interface ApprovalsProps {
-  status?: 'pending' | 'resolved';
-  search?: string;
-  paginatedResult: UsePaginatedQueryResult<ApprovalItem>;
-  approxCount?: number;
-}
-
-export function Approvals({
-  status,
-  search,
-  paginatedResult,
-  approxCount,
-}: ApprovalsProps) {
-  const { t } = useT('approvals');
-
-  const [approving, setApproving] = useState<string | null>(null);
-  const [rejecting, setRejecting] = useState<string | null>(null);
-  const [selectedApprovalId, setSelectedApprovalId] = useState<string | null>(
-    null,
-  );
-  const [removingProductId, setRemovingProductId] = useState<string | null>(
-    null,
-  );
-  const [approvalDetailDialogOpen, setApprovalDetailDialogOpen] =
-    useState(false);
-  const pageSize = 30;
-
-  const allApprovals = useMemo(() => {
-    if (!search) return paginatedResult.results;
-    const lowerSearch = search.toLowerCase();
-    return paginatedResult.results.filter((a) => {
-      const metadata = a.metadata ?? {};
-      const customerName =
-        typeof metadata['customerName'] === 'string'
-          ? metadata['customerName']
-          : '';
-      const customerEmail =
-        typeof metadata['customerEmail'] === 'string'
-          ? metadata['customerEmail']
-          : '';
-      return (
-        customerName.toLowerCase().includes(lowerSearch) ||
-        customerEmail.toLowerCase().includes(lowerSearch)
-      );
-    });
-  }, [paginatedResult.results, search]);
-
-  const list = useListPage<ApprovalItem>({
-    dataSource: {
-      type: 'paginated',
-      results: allApprovals,
-      status: paginatedResult.status,
-      loadMore: paginatedResult.loadMore,
-      isLoading: paginatedResult.isLoading,
-    },
-    pageSize,
-    getRowId: (row) => row._id,
-    approxRowCount: approxCount,
-  });
-
-  const { mutateAsync: updateApprovalStatus } = useUpdateApprovalStatus();
-  const { mutateAsync: removeRecommendedProduct } =
-    useRemoveRecommendedProduct();
-
-  const handleApprove = useCallback(
-    async (approvalId: string) => {
-      setApproving(approvalId);
-
-      try {
-        await updateApprovalStatus({
-          approvalId: toId<'approvals'>(approvalId),
-          status: 'approved',
-          comments: 'Approved via UI',
-        });
-      } catch (error) {
-        console.error('Failed to approve:', error);
-        toast({
-          title: t('toast.approveFailed'),
-          variant: 'destructive',
-        });
-      } finally {
-        setApproving(null);
-      }
-    },
-    [updateApprovalStatus, t],
-  );
-
-  const handleReject = useCallback(
-    async (approvalId: string) => {
-      setRejecting(approvalId);
-
-      try {
-        await updateApprovalStatus({
-          approvalId: toId<'approvals'>(approvalId),
-          status: 'rejected',
-          comments: 'Rejected via UI',
-        });
-      } catch (error) {
-        console.error('Failed to reject:', error);
-        toast({
-          title: t('toast.rejectFailed'),
-          variant: 'destructive',
-        });
-      } finally {
-        setRejecting(null);
-      }
-    },
-    [updateApprovalStatus, t],
-  );
-
-  const handleRemoveRecommendation = useCallback(
-    async (approvalId: string, productId: string) => {
-      setRemovingProductId(productId);
-
-      try {
-        await removeRecommendedProduct({
-          approvalId: toId<'approvals'>(approvalId),
-          productId,
-        });
-      } catch (error) {
-        console.error('Failed to remove recommendation:', error);
-        toast({
-          title: t('toast.removeRecommendationFailed'),
-          variant: 'destructive',
-        });
-      } finally {
-        setRemovingProductId(null);
-      }
-    },
-    [removeRecommendedProduct, t],
-  );
-
-  const handleApprovalRowClick = useCallback((approvalId: string) => {
-    setSelectedApprovalId(approvalId);
-    setApprovalDetailDialogOpen(true);
-  }, []);
-
-  const handleApprovalDetailOpenChange = useCallback((open: boolean) => {
-    setApprovalDetailDialogOpen(open);
-    if (!open) {
-      setSelectedApprovalId(null);
-    }
-  }, []);
-
-  const { pendingColumns, resolvedColumns } = useApprovalColumns({
-    approving,
-    rejecting,
-    onApprove: handleApprove,
-    onReject: handleReject,
-  });
-
-  const selectedApprovalDetail = useMemo(() => {
-    if (!selectedApprovalId || !allApprovals) return null;
-    const approval = allApprovals.find(
-      (a: ApprovalItem) => a._id === selectedApprovalId,
-    );
-    if (!approval) return null;
-    return getApprovalDetail(approval);
-  }, [selectedApprovalId, allApprovals]);
-
-  const columns = status === 'pending' ? pendingColumns : resolvedColumns;
-
-  return (
-    <>
-      <DataTable
-        columns={columns}
-        stickyLayout
-        onRowClick={(row) => handleApprovalRowClick(row.original._id)}
-        rowClassName="cursor-pointer"
-        emptyState={{
-          icon: GitCompare,
-          title:
-            status === 'pending'
-              ? t('emptyState.pending.title')
-              : t('emptyState.resolved.title'),
-          description:
-            status === 'pending'
-              ? t('emptyState.pending.description')
-              : undefined,
-        }}
-        {...list.tableProps}
-      />
-      <ApprovalDetailDialog
-        open={approvalDetailDialogOpen}
-        onOpenChange={handleApprovalDetailOpenChange}
-        approvalDetail={selectedApprovalDetail}
-        onApprove={handleApprove}
-        onReject={handleReject}
-        isApproving={approving === selectedApprovalId}
-        isRejecting={rejecting === selectedApprovalId}
-        onRemoveRecommendation={handleRemoveRecommendation}
-        removingProductId={removingProductId}
-      />
-    </>
-  );
-}
diff --git a/services/platform/app/features/approvals/components/approvals/get-approval-detail.ts b/services/platform/app/features/approvals/components/approvals/get-approval-detail.ts
deleted file mode 100644
index d41557ff2d..0000000000
--- a/services/platform/app/features/approvals/components/approvals/get-approval-detail.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-import type { ApprovalDetail } from '@/app/features/approvals/types/approval-detail';
-import type { Doc } from '@/convex/_generated/dataModel';
-
-import { toId } from '@/convex/lib/type_cast_helpers';
-import {
-  safeGetString,
-  safeGetNumber,
-  safeGetArray,
-} from '@/lib/utils/safe-parsers';
-
-type ApprovalItem = Doc<'approvals'>;
-
-export function getApprovalDetail(approval: ApprovalItem): ApprovalDetail {
-  const metadata: Record<string, unknown> = approval.metadata ?? {};
-
-  const recommendedProducts = safeGetArray(
-    metadata,
-    'recommendedProducts',
-    [],
-  ).map((product, index: number) => {
-    const id = safeGetString(product, 'productId', `rec-${index}`);
-    const name = safeGetString(product, 'productName', '');
-    const image = safeGetString(
-      product,
-      'imageUrl',
-      '/assets/placeholder-image.png',
-    );
-    const relationshipType = safeGetString(
-      product,
-      'relationshipType',
-      undefined,
-    );
-    const reasoning = safeGetString(product, 'reasoning', undefined);
-    const confidence = safeGetNumber(product, 'confidence', undefined);
-    return { id, name, image, relationshipType, reasoning, confidence };
-  });
-
-  const previousPurchases = safeGetArray(metadata, 'eventProducts', []).map(
-    (product, index: number) => {
-      const id = safeGetString(product, 'id', `prev-${index}`);
-      const productName =
-        safeGetString(product, 'productName', '') ||
-        safeGetString(product, 'name', '') ||
-        safeGetString(product, 'product_name', '');
-      const image =
-        safeGetString(product, 'image', '') ||
-        safeGetString(product, 'imageUrl', '') ||
-        safeGetString(product, 'image_url', '') ||
-        '/assets/placeholder-image.png';
-      const purchaseDate = safeGetString(product, 'purchaseDate', undefined);
-      const statusValue = safeGetString(product, 'status', undefined);
-      const purchaseStatus: 'active' | 'cancelled' | undefined =
-        statusValue === 'active' || statusValue === 'cancelled'
-          ? statusValue
-          : undefined;
-      return {
-        id,
-        productName,
-        image,
-        purchaseDate,
-        status: purchaseStatus,
-      };
-    },
-  );
-
-  const metaConfidence = (() => {
-    const raw =
-      typeof metadata['confidence'] === 'number'
-        ? metadata['confidence']
-        : undefined;
-    if (typeof raw !== 'number' || !Number.isFinite(raw)) return undefined;
-    return raw <= 1 ? Math.round(raw * 100) : Math.round(raw);
-  })();
-
-  const customerId = safeGetString(metadata, 'customerId', undefined);
-
-  return {
-    _id: approval._id,
-    organizationId: approval.organizationId,
-    customer: {
-      id: customerId ? toId<'customers'>(customerId) : undefined,
-      name:
-        typeof metadata['customerName'] === 'string'
-          ? metadata['customerName'].trim()
-          : '',
-      email:
-        typeof metadata['customerEmail'] === 'string'
-          ? metadata['customerEmail']
-          : '',
-    },
-    resourceType: approval.resourceType,
-    status: approval.status,
-    priority: approval.priority,
-    confidence: metaConfidence,
-    createdAt: approval._creationTime,
-    reviewer: safeGetString(metadata, 'approverName', undefined),
-    reviewedAt: approval.reviewedAt,
-    decidedAt: approval.reviewedAt,
-    comments: safeGetString(metadata, 'comments', undefined),
-    recommendedProducts,
-    previousPurchases,
-  };
-}
diff --git a/services/platform/app/features/approvals/components/approvals/product-list-cell.tsx b/services/platform/app/features/approvals/components/approvals/product-list-cell.tsx
deleted file mode 100644
index 44c7dbb87a..0000000000
--- a/services/platform/app/features/approvals/components/approvals/product-list-cell.tsx
+++ /dev/null
@@ -1,138 +0,0 @@
-import { Image } from '@/app/components/ui/data-display/image';
-import { Stack, HStack } from '@/app/components/ui/layout/layout';
-import { Text } from '@/app/components/ui/typography/text';
-import { useT } from '@/lib/i18n/client';
-import { safeGetString, safeGetNumber } from '@/lib/utils/safe-parsers';
-
-interface ProductListCellProps {
-  products: unknown;
-  isRecommendation?: boolean;
-}
-
-export function ProductListCell({
-  products,
-  isRecommendation = false,
-}: ProductListCellProps) {
-  const { t } = useT('approvals');
-  const list = Array.isArray(products) ? products : [];
-
-  if (list.length === 0) return null;
-
-  if (isRecommendation) {
-    return <RecommendationProductList products={list} t={t} />;
-  }
-
-  return (
-    <Stack gap={1}>
-      {list.map((p, index) => {
-        const id =
-          safeGetString(p, 'productId', '') ||
-          safeGetString(p, 'id', '') ||
-          String(index);
-        const name =
-          safeGetString(p, 'name', '') || safeGetString(p, 'productName', '');
-        const image =
-          safeGetString(p, 'image', '') ||
-          safeGetString(p, 'imageUrl', '') ||
-          '/assets/placeholder-image.png';
-
-        return (
-          <HStack key={id} gap={2}>
-            <div className="bg-muted size-5 shrink-0 overflow-hidden rounded">
-              <Image
-                src={image}
-                alt={name}
-                width={20}
-                height={20}
-                className="h-full w-full object-cover"
-              />
-            </div>
-            <Text
-              as="span"
-              variant="caption"
-              className="leading-normal whitespace-nowrap"
-            >
-              {name}
-            </Text>
-          </HStack>
-        );
-      })}
-    </Stack>
-  );
-}
-
-function RecommendationProductList({
-  products,
-  t,
-}: {
-  products: unknown[];
-  t: ReturnType<typeof useT>['t'];
-}) {
-  const sortedList = [...products].sort((a, b) => {
-    const confA = safeGetNumber(a, 'confidence', 0) ?? 0;
-    const confB = safeGetNumber(b, 'confidence', 0) ?? 0;
-    return confB - confA;
-  });
-
-  const firstProduct = sortedList[0];
-  const remainingCount = sortedList.length - 1;
-  const secondProduct = sortedList[1];
-
-  const firstName =
-    safeGetString(firstProduct, 'name', '') ||
-    safeGetString(firstProduct, 'productName', '');
-  const firstImage =
-    safeGetString(firstProduct, 'image', '') ||
-    safeGetString(firstProduct, 'imageUrl', '') ||
-    '/assets/placeholder-image.png';
-
-  return (
-    <Stack gap={1}>
-      <HStack gap={2}>
-        <div className="bg-muted size-5 shrink-0 overflow-hidden rounded">
-          <Image
-            src={firstImage}
-            alt={firstName}
-            width={20}
-            height={20}
-            className="h-full w-full object-cover"
-          />
-        </div>
-        <Text
-          as="span"
-          variant="caption"
-          className="leading-normal whitespace-nowrap"
-        >
-          {firstName}
-        </Text>
-      </HStack>
-      {remainingCount > 0 && secondProduct != null && (
-        <HStack gap={2}>
-          <div className="bg-muted size-5 shrink-0 overflow-hidden rounded">
-            <Image
-              src={
-                safeGetString(secondProduct, 'image', '') ||
-                safeGetString(secondProduct, 'imageUrl', '') ||
-                '/assets/placeholder-image.png'
-              }
-              alt={
-                safeGetString(secondProduct, 'name', '') ||
-                safeGetString(secondProduct, 'productName', '')
-              }
-              width={20}
-              height={20}
-              className="h-full w-full object-cover"
-            />
-          </div>
-          <Text
-            as="span"
-            variant="caption"
-            className="leading-normal whitespace-nowrap"
-          >
-            {t('labels.otherProducts', { count: remainingCount })}
-          </Text>
-        </HStack>
-      )}
-    </Stack>
-  );
-}
diff --git a/services/platform/app/features/approvals/components/approvals/use-approval-columns.tsx b/services/platform/app/features/approvals/components/approvals/use-approval-columns.tsx
deleted file mode 100644
index 91cd864728..0000000000
--- a/services/platform/app/features/approvals/components/approvals/use-approval-columns.tsx
+++ /dev/null
@@ -1,317 +0,0 @@
-import type { ColumnDef } from '@tanstack/react-table';
-
-import { CheckIcon, Info, Loader2, X } from 'lucide-react';
-import { useMemo, useCallback } from 'react';
-
-import type { Doc } from '@/convex/_generated/dataModel';
-
-import { CellErrorBoundary } from '@/app/components/error-boundaries/boundaries/cell-error-boundary';
-import { Button } from '@/app/components/ui/primitives/button';
-import { Text } from '@/app/components/ui/typography/text';
-import { useFormatDate } from '@/app/hooks/use-format-date';
-import { useT } from '@/lib/i18n/client';
-import {
-  safeGetString,
-  safeGetNumber,
-  safeGetArray,
-} from '@/lib/utils/safe-parsers';
-
-import { ProductListCell } from './product-list-cell';
-
-type ApprovalItem = Doc<'approvals'>;
-type ApprovalsT = ReturnType<typeof useT<'approvals'>>['t'];
-
-interface UseApprovalColumnsParams {
-  approving: string | null;
-  rejecting: string | null;
-  onApprove: (approvalId: string) => void;
-  onReject: (approvalId: string) => void;
-}
-
-function createSharedColumns(
-  t: ApprovalsT,
-  getCustomerLabel: (approval: ApprovalItem) => string,
-  getLabel: (resourceType: string) => string,
-): ColumnDef<ApprovalItem>[] {
-  return [
-    {
-      id: 'approval',
-      header: t('columns.approvalRecipient'),
-      size: 256,
-      meta: { skeleton: { type: 'avatar-text' as const } },
-      cell: ({ row }) => (
-        <div className="flex min-h-[41px] flex-col gap-1.5">
-          <div className="flex items-center gap-3">
-            <Text as="span" variant="label" className="tracking-tight">
-              {getLabel(row.original.resourceType)}
-            </Text>
-            <Info className="text-muted-foreground size-4 shrink-0 grow-0" />
-          </div>
-          <Text as="div" variant="muted" className="tracking-tight">
-            {getCustomerLabel(row.original)}
-          </Text>
-        </div>
-      ),
-    },
-    {
-      id: 'event',
-      header: t('columns.event'),
-      size: 256,
-      meta: { skeleton: { type: 'text' as const } },
-      cell: ({ row }) => {
-        const metadata = row.original.metadata ?? {};
-        return (
-          <div className="flex flex-col gap-1.5">
-            <Text as="div" variant="label-sm">
-              {t('labels.purchase')}
-            </Text>
-            <CellErrorBoundary
-              fallback={
-                <Text as="span" variant="caption">
-                  —
-                </Text>
-              }
-            >
-              <ProductListCell
-                products={safeGetArray(metadata, 'eventProducts', [])}
-              />
-            </CellErrorBoundary>
-          </div>
-        );
-      },
-    },
-    {
-      id: 'action',
-      header: t('columns.action'),
-      size: 256,
-      meta: { skeleton: { type: 'text' as const } },
-      cell: ({ row }) => {
-        const metadata = row.original.metadata ?? {};
-        return (
-          <div className="flex flex-col gap-1.5">
-            <Text as="div" variant="label-sm">
-              {t('labels.recommendation')}
-            </Text>
-            <CellErrorBoundary
-              fallback={
-                <Text as="span" variant="caption">
-                  —
-                </Text>
-              }
-            >
-              <ProductListCell
-                products={safeGetArray(metadata, 'recommendedProducts', [])}
-                isRecommendation
-              />
-            </CellErrorBoundary>
-          </div>
-        );
-      },
-    },
-  ];
-}
-
-export function useApprovalColumns({
-  approving,
-  rejecting,
-  onApprove,
-  onReject,
-}: UseApprovalColumnsParams) {
-  const { t } = useT('approvals');
-  const { formatDate } = useFormatDate();
-
-  const getApprovalTypeLabel = useCallback(
-    (resourceType: string): string => {
-      switch (resourceType) {
-        case 'conversations':
-          return t('types.reviewReply');
-        case 'product_recommendation':
-          return t('types.recommendProduct');
-        case 'workflow_run':
-          return t('types.runWorkflow');
-        case 'workflow_update':
-          return t('types.updateWorkflow');
-        default:
-          return t('types.review');
-      }
-    },
-    [t],
-  );
-
-  const getCustomerLabel = useCallback(
-    (approval: ApprovalItem) => {
-      const metadata = approval.metadata ?? {};
-      return (
-        safeGetString(metadata, 'customerName', '').trim() ||
-        safeGetString(metadata, 'customerEmail', '').trim() ||
-        t('columns.unknownCustomer')
-      );
-    },
-    [t],
-  );
-
-  const getConfidencePercent = useCallback((approval: ApprovalItem) => {
-    const metadata = approval.metadata ?? {};
-    const recs = safeGetArray(metadata, 'recommendedProducts', []);
-    const firstConf =
-      recs.length > 0 ? safeGetNumber(recs[0], 'confidence', 0) : 0;
-    const raw = safeGetNumber(metadata, 'confidence', firstConf);
-    const n = Number(raw);
-    return !Number.isFinite(n)
-      ? 0
-      : n <= 1
-        ? Math.round(n * 100)
-        : Math.round(n);
-  }, []);
-
-  const pendingColumns = useMemo(
-    (): ColumnDef<ApprovalItem>[] => [
-      ...createSharedColumns(t, getCustomerLabel, getApprovalTypeLabel),
-      {
-        id: 'confidence',
-        header: () => (
-          <Text as="span" align="right" className="block w-full">
-            {t('columns.confidence')}
-          </Text>
-        ),
-        size: 100,
-        meta: { headerLabel: t('columns.confidence') },
-        cell: ({ row }) => (
-          <Text
-            as="span"
-            variant="caption"
-            align="right"
-            className="block font-medium"
-          >
-            {getConfidencePercent(row.original)}%
-          </Text>
-        ),
-      },
-      {
-        id: 'actions',
-        header: () => (
-          <Text as="span" align="center" className="block w-full">
-            {t('columns.approved')}
-          </Text>
-        ),
-        size: 100,
-        meta: {
-          headerLabel: t('columns.approved'),
-          skeleton: { type: 'action' as const },
-        },
-        cell: ({ row }) => (
-          <div className="flex justify-center gap-1">
-            <Button
-              size="icon"
-              onClick={(e) => {
-                e.stopPropagation();
-                onApprove(row.original._id);
-              }}
-              disabled={
-                approving === row.original._id || rejecting === row.original._id
-              }
-              aria-label={t('actions.approve')}
-            >
-              {approving === row.original._id ? (
-                <Loader2 className="size-4 animate-spin" />
-              ) : (
-                <CheckIcon className="size-4" />
-              )}
-            </Button>
-            <Button
-              size="icon"
-              variant="secondary"
-              onClick={(e) => {
-                e.stopPropagation();
-                onReject(row.original._id);
-              }}
-              disabled={
-                approving === row.original._id || rejecting === row.original._id
-              }
-              aria-label={t('actions.reject')}
-            >
-              {rejecting === row.original._id ? (
-                <div className="border-foreground size-3 animate-spin rounded-full border-b" />
-              ) : (
-                <X className="text-foreground size-4" />
-              )}
-            </Button>
-          </div>
-        ),
-      },
-    ],
-    [
-      t,
-      getApprovalTypeLabel,
-      getCustomerLabel,
-      getConfidencePercent,
-      approving,
-      rejecting,
-      onApprove,
-      onReject,
-    ],
-  );
-
-  const resolvedColumns = useMemo(
-    (): ColumnDef<ApprovalItem>[] => [
-      ...createSharedColumns(t, getCustomerLabel, () =>
-        t('types.recommendProduct'),
-      ),
-      {
-        id: 'reviewer',
-        header: t('columns.reviewer'),
-        meta: { skeleton: { type: 'text' as const } },
-        cell: ({ row }) => {
-          const metadata = row.original.metadata ?? {};
-          return (
-            <Text as="div" variant="body">
-              {safeGetString(metadata, 'approverName', '') ||
-                t('columns.unknown')}
-            </Text>
-          );
-        },
-      },
-      {
-        id: 'reviewedAt',
-        header: () => (
-          <Text as="span" align="right" className="block w-full">
-            {t('columns.reviewedAt')}
-          </Text>
-        ),
-        meta: { headerLabel: t('columns.reviewedAt') },
-        cell: ({ row }) => (
-          <Text as="span" variant="body" align="right" className="block">
-            {row.original.reviewedAt
-              ? formatDate(new Date(row.original.reviewedAt), 'short')
-              : ''}
-          </Text>
-        ),
-      },
-      {
-        id: 'status',
-        header: () => (
-          <Text as="span" align="right" className="block w-full">
-            {t('columns.approved')}
-          </Text>
-        ),
-        size: 100,
-        meta: {
-          headerLabel: t('columns.approved'),
-          skeleton: { type: 'action' as const },
-        },
-        cell: ({ row }) => (
-          <div className="px-4 text-center">
-            {row.original.status === 'approved' ? (
-              <CheckIcon className="inline-block size-4 text-green-600" />
-            ) : (
-              <X className="inline-block size-4 text-red-600" />
-            )}
-          </div>
-        ),
-      },
-    ],
-    [t, getCustomerLabel, formatDate],
-  );
-
-  return { pendingColumns, resolvedColumns };
-}
diff --git a/services/platform/app/features/approvals/components/product-card.tsx b/services/platform/app/features/approvals/components/product-card.tsx
deleted file mode 100644
index 87ac74f944..0000000000
--- a/services/platform/app/features/approvals/components/product-card.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-'use client';
-
-import { X } from 'lucide-react';
-
-import { Image } from '@/app/components/ui/data-display/image';
-import { Badge } from '@/app/components/ui/feedback/badge';
-import { Stack, HStack } from '@/app/components/ui/layout/layout';
-import { Button } from '@/app/components/ui/primitives/button';
-import { Heading } from '@/app/components/ui/typography/heading';
-import { Text } from '@/app/components/ui/typography/text';
-import { useFormatDate } from '@/app/hooks/use-format-date';
-import { useT } from '@/lib/i18n/client';
-
-import { RecommendedProduct, PreviousPurchase } from '../types/approval-detail';
-
-interface ProductCardProps {
-  product?: RecommendedProduct;
-  purchase?: PreviousPurchase;
-  type: 'recommended' | 'purchase';
-  onRemove?: (productId: string) => void;
-  isRemoving?: boolean;
-  canRemove?: boolean;
-}
-
-export function ProductCard({
-  product,
-  purchase,
-  type,
-  onRemove,
-  isRemoving,
-  canRemove,
-}: ProductCardProps) {
-  const { formatDate } = useFormatDate();
-  const { t } = useT('approvals');
-
-  if (type === 'recommended' && product) {
-    return (
-      <HStack
-        gap={3}
-        align="start"
-        className="border-border border-b p-3 last:border-b-0"
-      >
-        <div className="bg-muted h-[72px] w-[72px] shrink-0 overflow-hidden rounded-lg">
-          <Image
-            src={product.image}
-            alt={product.name}
-            width={72}
-            height={72}
-            className="h-full w-full object-cover"
-          />
-        </div>
-        <div className="min-w-0 flex-1">
-          <Stack gap={3}>
-            <Stack gap={1}>
-              <Heading
-                level={4}
-                size="sm"
-                weight="medium"
-                className="leading-normal"
-              >
-                {product.name}
-              </Heading>
-              {product.description && (
-                <Text variant="muted" className="line-clamp-2 leading-5">
-                  {product.description}
-                </Text>
-              )}
-              {product.reasoning && (
-                <Text variant="muted" className="leading-5">
-                  {product.reasoning}
-                </Text>
-              )}
-            </Stack>
-            <HStack gap={2}>
-              {product.relationshipType && (
-                <Badge variant="outline">{product.relationshipType}</Badge>
-              )}
-              {product.confidence !== undefined && (
-                <Badge variant="outline">
-                  {t('confidenceBadge', {
-                    percent: Math.round(product.confidence * 100),
-                  })}
-                </Badge>
-              )}
-            </HStack>
-          </Stack>
-        </div>
-        {canRemove && onRemove && (
-          <Button
-            size="icon"
-            variant="ghost"
-            onClick={() => onRemove(product.id)}
-            disabled={isRemoving}
-            className="size-8 shrink-0"
-            aria-label={t('actions.removeProduct', { name: product.name })}
-          >
-            {isRemoving ? (
-              <div className="border-foreground size-4 animate-spin rounded-full border-b" />
-            ) : (
-              <X className="text-muted-foreground hover:text-foreground size-4" />
-            )}
-          </Button>
-        )}
-      </HStack>
-    );
-  }
-
-  if (type === 'purchase' && purchase) {
-    return (
-      <HStack gap={3} className="border-border border-b p-3 last:border-b-0">
-        <HStack gap={2} className="flex-1">
-          <div className="bg-muted size-10 shrink-0 overflow-hidden rounded-md">
-            <Image
-              src={purchase.image}
-              alt={purchase.productName}
-              width={40}
-              height={40}
-              className="h-full w-full object-cover"
-            />
-          </div>
-          <Stack gap={1}>
-            <Heading level={4} size="sm" weight="medium">
-              {purchase.productName}
-            </Heading>
-            {purchase.purchaseDate && (
-              <Text variant="caption">{formatDate(purchase.purchaseDate)}</Text>
-            )}
-          </Stack>
-        </HStack>
-        {purchase.status && (
-          <Badge
-            variant={purchase.status === 'active' ? 'green' : 'destructive'}
-          >
-            {purchase.status === 'active'
-              ? t('productStatus.active')
-              : t('productStatus.cancelled')}
-          </Badge>
-        )}
-      </HStack>
-    );
-  }
-
-  return null;
-}
diff --git a/services/platform/app/features/approvals/hooks/actions.ts b/services/platform/app/features/approvals/hooks/actions.ts
deleted file mode 100644
index 6cad229539..0000000000
--- a/services/platform/app/features/approvals/hooks/actions.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { useConvexAction } from '@/app/hooks/use-convex-action';
-import { api } from '@/convex/_generated/api';
-
-export function useExecuteApprovedIntegrationOperation() {
-  return useConvexAction(
-    api.approvals.actions.executeApprovedIntegrationOperation,
-  );
-}
-
-export function useExecuteApprovedWorkflowCreation() {
-  return useConvexAction(api.approvals.actions.executeApprovedWorkflowCreation);
-}
-
-export function useExecuteApprovedWorkflowRun() {
-  return useConvexAction(api.approvals.actions.executeApprovedWorkflowRun);
-}
-
-export function useExecuteApprovedWorkflowUpdate() {
-  return useConvexAction(api.approvals.actions.executeApprovedWorkflowUpdate);
-}
diff --git a/services/platform/app/features/approvals/hooks/mutations.ts b/services/platform/app/features/approvals/hooks/mutations.ts
deleted file mode 100644
index f34667d35c..0000000000
--- a/services/platform/app/features/approvals/hooks/mutations.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { useConvexMutation } from '@/app/hooks/use-convex-mutation';
-import { api } from '@/convex/_generated/api';
-
-export function useRemoveRecommendedProduct() {
-  return useConvexMutation(api.approvals.mutations.removeRecommendedProduct);
-}
-
-export function useUpdateApprovalStatus() {
-  return useConvexMutation(api.approvals.mutations.updateApprovalStatus);
-}
diff --git a/services/platform/app/features/approvals/hooks/queries.ts b/services/platform/app/features/approvals/hooks/queries.ts
deleted file mode 100644
index 8469469276..0000000000
--- a/services/platform/app/features/approvals/hooks/queries.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import type { ConvexItemOf } from '@/lib/types/convex-helpers';
-
-import { useCachedPaginatedQuery } from '@/app/hooks/use-cached-paginated-query';
-import { useConvexQuery } from '@/app/hooks/use-convex-query';
-import { api } from '@/convex/_generated/api';
-
-export type Approval = ConvexItemOf<
-  typeof api.approvals.queries.listApprovalsByOrganization
->;
-
-export function useApproxApprovalCountByStatus(
-  organizationId: string,
-  status: 'pending' | 'resolved',
-) {
-  return useConvexQuery(api.approvals.queries.approxCountApprovalsByStatus, {
-    organizationId,
-    status,
-  });
-}
-
-export function useApprovals(organizationId: string) {
-  const { data, isLoading } = useConvexQuery(
-    api.approvals.queries.listApprovalsByOrganization,
-    { organizationId },
-  );
-
-  return {
-    approvals: data ?? [],
-    isLoading,
-  };
-}
-
-interface ListApprovalsPaginatedArgs {
-  organizationId: string;
-  status?: 'pending' | 'approved' | 'rejected';
-  resourceType?:
-    | 'conversations'
-    | 'product_recommendation'
-    | 'integration_operation'
-    | 'workflow_creation'
-    | 'workflow_run'
-    | 'human_input_request';
-  excludeStatus?: 'pending' | 'approved' | 'rejected';
-  initialNumItems: number;
-}
-
-export function useListApprovalsPaginated(args: ListApprovalsPaginatedArgs) {
-  const { initialNumItems, ...queryArgs } = args;
-  return useCachedPaginatedQuery(
-    api.approvals.queries.listApprovalsPaginated,
-    queryArgs,
-    { initialNumItems },
-  );
-}
diff --git a/services/platform/app/features/approvals/types/approval-detail.ts b/services/platform/app/features/approvals/types/approval-detail.ts
deleted file mode 100644
index db882e558b..0000000000
--- a/services/platform/app/features/approvals/types/approval-detail.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import type { Id } from '@/convex/_generated/dataModel';
-
-/**
- * Recommended product for UI display
- */
-export interface RecommendedProduct {
-  id: string;
-  name: string;
-  image: string;
-  description?: string;
-  relationshipType?: string;
-  reasoning?: string;
-  confidence?: number;
-}
-
-/**
- * Previous purchase for UI display
- */
-export interface PreviousPurchase {
-  id: string;
-  productName: string;
-  image: string;
-  purchaseDate?: string;
-  status?: 'active' | 'cancelled';
-}
-
-/**
- * Enriched approval detail for UI display.
- * This is derived from Doc<'approvals'> with processed/formatted data.
- */
-export interface ApprovalDetail {
-  _id: string;
-  organizationId: string;
-  customer: {
-    id?: Id<'customers'>;
-    name: string;
-    email: string;
-  };
-  resourceType: string;
-  status: 'pending' | 'approved' | 'rejected';
-  priority: 'low' | 'medium' | 'high' | 'urgent';
-  confidence?: number;
-  createdAt: number;
-  reviewer?: string;
-  reviewedAt?: number;
-  decidedAt?: number;
-  comments?: string;
-  recommendedProducts: RecommendedProduct[];
-  previousPurchases: PreviousPurchase[];
-}
diff --git a/services/platform/app/features/chat/components/integration-approval-card.tsx b/services/platform/app/features/chat/components/integration-approval-card.tsx
index 048ce8e31a..5c35f59a4f 100644
--- a/services/platform/app/features/chat/components/integration-approval-card.tsx
+++ b/services/platform/app/features/chat/components/integration-approval-card.tsx
@@ -16,8 +16,10 @@ import { HStack, Stack } from '@/app/components/ui/layout/layout';
 import { Tooltip } from '@/app/components/ui/overlays/tooltip';
 import { Button } from '@/app/components/ui/primitives/button';
 import { Text } from '@/app/components/ui/typography/text';
-import { useExecuteApprovedIntegrationOperation } from '@/app/features/approvals/hooks/actions';
-import { useUpdateApprovalStatus } from '@/app/features/approvals/hooks/mutations';
+import {
+  useExecuteApprovedIntegrationOperation,
+  useUpdateApprovalStatus,
+} from '@/app/features/chat/hooks/mutations';
 import { useAuth } from '@/app/hooks/use-convex-auth';
 import { Id } from '@/convex/_generated/dataModel';
 import { IntegrationOperationMetadata } from '@/convex/approvals/types';
diff --git a/services/platform/app/features/chat/components/workflow-creation-approval-card.tsx b/services/platform/app/features/chat/components/workflow-creation-approval-card.tsx
index 4905d0a7a6..de88130903 100644
--- a/services/platform/app/features/chat/components/workflow-creation-approval-card.tsx
+++ b/services/platform/app/features/chat/components/workflow-creation-approval-card.tsx
@@ -20,8 +20,10 @@ import { HStack, Stack } from '@/app/components/ui/layout/layout';
 import { Tooltip } from '@/app/components/ui/overlays/tooltip';
 import { Button } from '@/app/components/ui/primitives/button';
 import { Text } from '@/app/components/ui/typography/text';
-import { useExecuteApprovedWorkflowCreation } from '@/app/features/approvals/hooks/actions';
-import { useUpdateApprovalStatus } from '@/app/features/approvals/hooks/mutations';
+import {
+  useExecuteApprovedWorkflowCreation,
+  useUpdateApprovalStatus,
+} from '@/app/features/chat/hooks/mutations';
 import { useAuth } from '@/app/hooks/use-convex-auth';
 import { useCopyButton } from '@/app/hooks/use-copy';
 import { Id } from '@/convex/_generated/dataModel';
diff --git a/services/platform/app/features/chat/components/workflow-run-approval-card.tsx b/services/platform/app/features/chat/components/workflow-run-approval-card.tsx
index 8c30ccf426..f714216a2f 100644
--- a/services/platform/app/features/chat/components/workflow-run-approval-card.tsx
+++ b/services/platform/app/features/chat/components/workflow-run-approval-card.tsx
@@ -22,8 +22,10 @@ import { HStack, Stack } from '@/app/components/ui/layout/layout';
 import { Tooltip } from '@/app/components/ui/overlays/tooltip';
 import { Button } from '@/app/components/ui/primitives/button';
 import { Text } from '@/app/components/ui/typography/text';
-import { useExecuteApprovedWorkflowRun } from '@/app/features/approvals/hooks/actions';
-import { useUpdateApprovalStatus } from '@/app/features/approvals/hooks/mutations';
+import {
+  useExecuteApprovedWorkflowRun,
+  useUpdateApprovalStatus,
+} from '@/app/features/chat/hooks/mutations';
 import {
   useCancelExecution,
   useExecutionStatus,
diff --git a/services/platform/app/features/chat/components/workflow-update-approval-card.tsx b/services/platform/app/features/chat/components/workflow-update-approval-card.tsx
index cbf22d51c3..b8a596f0e4 100644
--- a/services/platform/app/features/chat/components/workflow-update-approval-card.tsx
+++ b/services/platform/app/features/chat/components/workflow-update-approval-card.tsx
@@ -22,8 +22,10 @@ import { HStack, Stack } from '@/app/components/ui/layout/layout';
 import { Tooltip } from '@/app/components/ui/overlays/tooltip';
 import { Button } from '@/app/components/ui/primitives/button';
 import { Text } from '@/app/components/ui/typography/text';
-import { useExecuteApprovedWorkflowUpdate } from '@/app/features/approvals/hooks/actions';
-import { useUpdateApprovalStatus } from '@/app/features/approvals/hooks/mutations';
+import {
+  useExecuteApprovedWorkflowUpdate,
+  useUpdateApprovalStatus,
+} from '@/app/features/chat/hooks/mutations';
 import { useAuth } from '@/app/hooks/use-convex-auth';
 import { useCopyButton } from '@/app/hooks/use-copy';
 import { Id } from '@/convex/_generated/dataModel';
diff --git a/services/platform/app/features/chat/hooks/mutations.ts b/services/platform/app/features/chat/hooks/mutations.ts
index 5da99958b3..5d5818a327 100644
--- a/services/platform/app/features/chat/hooks/mutations.ts
+++ b/services/platform/app/features/chat/hooks/mutations.ts
@@ -1,3 +1,4 @@
+import { useConvexAction } from '@/app/hooks/use-convex-action';
 import { useConvexMutation } from '@/app/hooks/use-convex-mutation';
 import { api } from '@/convex/_generated/api';
 
@@ -11,6 +12,28 @@ export function useSubmitHumanInputResponse() {
   );
 }
 
+export function useUpdateApprovalStatus() {
+  return useConvexMutation(api.approvals.mutations.updateApprovalStatus);
+}
+
+export function useExecuteApprovedIntegrationOperation() {
+  return useConvexAction(
+    api.approvals.actions.executeApprovedIntegrationOperation,
+  );
+}
+
+export function useExecuteApprovedWorkflowCreation() {
+  return useConvexAction(api.approvals.actions.executeApprovedWorkflowCreation);
+}
+
+export function useExecuteApprovedWorkflowRun() {
+  return useConvexAction(api.approvals.actions.executeApprovedWorkflowRun);
+}
+
+export function useExecuteApprovedWorkflowUpdate() {
+  return useConvexAction(api.approvals.actions.executeApprovedWorkflowUpdate);
+}
+
 export function useCreateThread() {
   return useConvexMutation(api.threads.mutations.createChatThread);
 }
diff --git a/services/platform/app/features/chat/hooks/queries.ts b/services/platform/app/features/chat/hooks/queries.ts
index 33426d19b9..febf078d9a 100644
--- a/services/platform/app/features/chat/hooks/queries.ts
+++ b/services/platform/app/features/chat/hooks/queries.ts
@@ -10,7 +10,6 @@ import type {
 import type { HumanInputRequestMetadata } from '@/lib/shared/schemas/approvals';
 import type { ConvexItemOf } from '@/lib/types/convex-helpers';
 
-import { useApprovals } from '@/app/features/approvals/hooks/queries';
 import { useCachedPaginatedQuery } from '@/app/hooks/use-cached-paginated-query';
 import { useConvexQuery } from '@/app/hooks/use-convex-query';
 import { useTeamFilter } from '@/app/hooks/use-team-filter';
@@ -112,6 +111,18 @@ export function useThreadMessages(threadId: string | null) {
   return results;
 }
 
+function useApprovals(organizationId: string) {
+  const { data, isLoading } = useConvexQuery(
+    api.approvals.queries.listApprovalsByOrganization,
+    { organizationId },
+  );
+
+  return {
+    approvals: data ?? [],
+    isLoading,
+  };
+}
+
 export interface HumanInputRequest {
   _id: Id<'approvals'>;
   status: 'pending' | 'approved' | 'rejected';
diff --git a/services/platform/app/hooks/use-navigation-items.ts b/services/platform/app/hooks/use-navigation-items.ts
index 80e00b9502..2194a5717c 100644
--- a/services/platform/app/hooks/use-navigation-items.ts
+++ b/services/platform/app/hooks/use-navigation-items.ts
@@ -1,13 +1,6 @@
 'use client';
 
-import {
-  MessageCircle,
-  CircleCheck,
-  Inbox,
-  BrainIcon,
-  Network,
-  Bot,
-} from 'lucide-react';
+import { MessageCircle, Inbox, BrainIcon, Network, Bot } from 'lucide-react';
 import { useMemo } from 'react';
 
 import { useT } from '@/lib/i18n/client';
@@ -29,8 +22,6 @@ export function useNavigationItems(businessId: string): NavItem[] {
   const { t: tNav } = useT('navigation');
   const { t: tKnowledge } = useT('knowledge');
   const { t: tConversations } = useT('conversations');
-  const { t: tApprovals } = useT('approvals');
-
   return useMemo(
     (): NavItem[] => [
       {
@@ -112,27 +103,6 @@ export function useNavigationItems(businessId: string): NavItem[] {
           },
         ],
       },
-      {
-        label: tNav('approvals'),
-        to: '/dashboard/$id/approvals/$status',
-        params: { id: businessId, status: 'pending' },
-        href: `/dashboard/${businessId}/approvals/pending`,
-        icon: CircleCheck,
-        subItems: [
-          {
-            label: tApprovals('status.pending'),
-            to: '/dashboard/$id/approvals/$status',
-            params: { id: businessId, status: 'pending' },
-            href: `/dashboard/${businessId}/approvals/pending`,
-          },
-          {
-            label: tApprovals('status.resolved'),
-            to: '/dashboard/$id/approvals/$status',
-            params: { id: businessId, status: 'resolved' },
-            href: `/dashboard/${businessId}/approvals/resolved`,
-          },
-        ],
-      },
       {
         label: tNav('customAgents'),
         to: '/dashboard/$id/custom-agents',
@@ -150,6 +120,6 @@ export function useNavigationItems(businessId: string): NavItem[] {
         can: ['write', 'wfDefinitions'],
       },
     ],
-    [businessId, tNav, tKnowledge, tConversations, tApprovals],
+    [businessId, tNav, tKnowledge, tConversations],
   );
 }
diff --git a/services/platform/app/routeTree.gen.ts b/services/platform/app/routeTree.gen.ts
index e963cd4bc4..0f61895b8f 100644
--- a/services/platform/app/routeTree.gen.ts
+++ b/services/platform/app/routeTree.gen.ts
@@ -25,7 +25,6 @@ import { Route as DashboardIdCustomAgentsRouteImport } from './routes/dashboard/
 import { Route as DashboardIdConversationsRouteImport } from './routes/dashboard/$id/conversations'
 import { Route as DashboardIdChatRouteImport } from './routes/dashboard/$id/chat'
 import { Route as DashboardIdAutomationsRouteImport } from './routes/dashboard/$id/automations'
-import { Route as DashboardIdApprovalsRouteImport } from './routes/dashboard/$id/approvals'
 import { Route as DashboardIdKnowledgeRouteImport } from './routes/dashboard/$id/_knowledge'
 import { Route as DashboardIdSettingsIndexRouteImport } from './routes/dashboard/$id/settings/index'
 import { Route as DashboardIdCustomAgentsIndexRouteImport } from './routes/dashboard/$id/custom-agents/index'
@@ -43,7 +42,6 @@ import { Route as DashboardIdCustomAgentsAgentIdRouteImport } from './routes/das
 import { Route as DashboardIdConversationsStatusRouteImport } from './routes/dashboard/$id/conversations/$status'
 import { Route as DashboardIdChatThreadIdRouteImport } from './routes/dashboard/$id/chat/$threadId'
 import { Route as DashboardIdAutomationsAmIdRouteImport } from './routes/dashboard/$id/automations/$amId'
-import { Route as DashboardIdApprovalsStatusRouteImport } from './routes/dashboard/$id/approvals/$status'
 import { Route as DashboardIdKnowledgeWebsitesRouteImport } from './routes/dashboard/$id/_knowledge/websites'
 import { Route as DashboardIdKnowledgeVendorsRouteImport } from './routes/dashboard/$id/_knowledge/vendors'
 import { Route as DashboardIdKnowledgeProductsRouteImport } from './routes/dashboard/$id/_knowledge/products'
@@ -140,11 +138,6 @@ const DashboardIdAutomationsRoute = DashboardIdAutomationsRouteImport.update({
   path: '/automations',
   getParentRoute: () => DashboardIdRoute,
 } as any)
-const DashboardIdApprovalsRoute = DashboardIdApprovalsRouteImport.update({
-  id: '/approvals',
-  path: '/approvals',
-  getParentRoute: () => DashboardIdRoute,
-} as any)
 const DashboardIdKnowledgeRoute = DashboardIdKnowledgeRouteImport.update({
   id: '/_knowledge',
   getParentRoute: () => DashboardIdRoute,
@@ -242,12 +235,6 @@ const DashboardIdAutomationsAmIdRoute =
     path: '/$amId',
     getParentRoute: () => DashboardIdAutomationsRoute,
   } as any)
-const DashboardIdApprovalsStatusRoute =
-  DashboardIdApprovalsStatusRouteImport.update({
-    id: '/$status',
-    path: '/$status',
-    getParentRoute: () => DashboardIdApprovalsRoute,
-  } as any)
 const DashboardIdKnowledgeWebsitesRoute =
   DashboardIdKnowledgeWebsitesRouteImport.update({
     id: '/websites',
@@ -343,7 +330,6 @@ export interface FileRoutesByFullPath {
   '/dashboard/$id': typeof DashboardIdKnowledgeRouteWithChildren
   '/dashboard/create-organization': typeof DashboardCreateOrganizationRoute
   '/dashboard/': typeof DashboardIndexRoute
-  '/dashboard/$id/approvals': typeof DashboardIdApprovalsRouteWithChildren
   '/dashboard/$id/automations': typeof DashboardIdAutomationsRouteWithChildren
   '/dashboard/$id/chat': typeof DashboardIdChatRouteWithChildren
   '/dashboard/$id/conversations': typeof DashboardIdConversationsRouteWithChildren
@@ -355,7 +341,6 @@ export interface FileRoutesByFullPath {
   '/dashboard/$id/products': typeof DashboardIdKnowledgeProductsRoute
   '/dashboard/$id/vendors': typeof DashboardIdKnowledgeVendorsRoute
   '/dashboard/$id/websites': typeof DashboardIdKnowledgeWebsitesRoute
-  '/dashboard/$id/approvals/$status': typeof DashboardIdApprovalsStatusRoute
   '/dashboard/$id/automations/$amId': typeof DashboardIdAutomationsAmIdRouteWithChildren
   '/dashboard/$id/chat/$threadId': typeof DashboardIdChatThreadIdRoute
   '/dashboard/$id/conversations/$status': typeof DashboardIdConversationsStatusRoute
@@ -391,14 +376,12 @@ export interface FileRoutesByTo {
   '/dashboard/create-organization': typeof DashboardCreateOrganizationRoute
   '/dashboard': typeof DashboardIndexRoute
   '/dashboard/$id': typeof DashboardIdIndexRoute
-  '/dashboard/$id/approvals': typeof DashboardIdApprovalsRouteWithChildren
   '/dashboard/$id/conversations': typeof DashboardIdConversationsRouteWithChildren
   '/dashboard/$id/customers': typeof DashboardIdKnowledgeCustomersRoute
   '/dashboard/$id/documents': typeof DashboardIdKnowledgeDocumentsRoute
   '/dashboard/$id/products': typeof DashboardIdKnowledgeProductsRoute
   '/dashboard/$id/vendors': typeof DashboardIdKnowledgeVendorsRoute
   '/dashboard/$id/websites': typeof DashboardIdKnowledgeWebsitesRoute
-  '/dashboard/$id/approvals/$status': typeof DashboardIdApprovalsStatusRoute
   '/dashboard/$id/automations/$amId': typeof DashboardIdAutomationsAmIdRouteWithChildren
   '/dashboard/$id/chat/$threadId': typeof DashboardIdChatThreadIdRoute
   '/dashboard/$id/conversations/$status': typeof DashboardIdConversationsStatusRoute
@@ -437,7 +420,6 @@ export interface FileRoutesById {
   '/dashboard/create-organization': typeof DashboardCreateOrganizationRoute
   '/dashboard/': typeof DashboardIndexRoute
   '/dashboard/$id/_knowledge': typeof DashboardIdKnowledgeRouteWithChildren
-  '/dashboard/$id/approvals': typeof DashboardIdApprovalsRouteWithChildren
   '/dashboard/$id/automations': typeof DashboardIdAutomationsRouteWithChildren
   '/dashboard/$id/chat': typeof DashboardIdChatRouteWithChildren
   '/dashboard/$id/conversations': typeof DashboardIdConversationsRouteWithChildren
@@ -449,7 +431,6 @@ export interface FileRoutesById {
   '/dashboard/$id/_knowledge/products': typeof DashboardIdKnowledgeProductsRoute
   '/dashboard/$id/_knowledge/vendors': typeof DashboardIdKnowledgeVendorsRoute
   '/dashboard/$id/_knowledge/websites': typeof DashboardIdKnowledgeWebsitesRoute
-  '/dashboard/$id/approvals/$status': typeof DashboardIdApprovalsStatusRoute
   '/dashboard/$id/automations/$amId': typeof DashboardIdAutomationsAmIdRouteWithChildren
   '/dashboard/$id/chat/$threadId': typeof DashboardIdChatThreadIdRoute
   '/dashboard/$id/conversations/$status': typeof DashboardIdConversationsStatusRoute
@@ -488,7 +469,6 @@ export interface FileRouteTypes {
     | '/dashboard/$id'
     | '/dashboard/create-organization'
     | '/dashboard/'
-    | '/dashboard/$id/approvals'
     | '/dashboard/$id/automations'
     | '/dashboard/$id/chat'
     | '/dashboard/$id/conversations'
@@ -500,7 +480,6 @@ export interface FileRouteTypes {
     | '/dashboard/$id/products'
     | '/dashboard/$id/vendors'
     | '/dashboard/$id/websites'
-    | '/dashboard/$id/approvals/$status'
     | '/dashboard/$id/automations/$amId'
     | '/dashboard/$id/chat/$threadId'
     | '/dashboard/$id/conversations/$status'
@@ -536,14 +515,12 @@ export interface FileRouteTypes {
     | '/dashboard/create-organization'
     | '/dashboard'
     | '/dashboard/$id'
-    | '/dashboard/$id/approvals'
     | '/dashboard/$id/conversations'
     | '/dashboard/$id/customers'
     | '/dashboard/$id/documents'
     | '/dashboard/$id/products'
     | '/dashboard/$id/vendors'
     | '/dashboard/$id/websites'
-    | '/dashboard/$id/approvals/$status'
     | '/dashboard/$id/automations/$amId'
     | '/dashboard/$id/chat/$threadId'
     | '/dashboard/$id/conversations/$status'
@@ -581,7 +558,6 @@ export interface FileRouteTypes {
     | '/dashboard/create-organization'
     | '/dashboard/'
     | '/dashboard/$id/_knowledge'
-    | '/dashboard/$id/approvals'
     | '/dashboard/$id/automations'
     | '/dashboard/$id/chat'
     | '/dashboard/$id/conversations'
@@ -593,7 +569,6 @@ export interface FileRouteTypes {
     | '/dashboard/$id/_knowledge/products'
     | '/dashboard/$id/_knowledge/vendors'
     | '/dashboard/$id/_knowledge/websites'
-    | '/dashboard/$id/approvals/$status'
     | '/dashboard/$id/automations/$amId'
     | '/dashboard/$id/chat/$threadId'
     | '/dashboard/$id/conversations/$status'
@@ -743,13 +718,6 @@ declare module '@tanstack/react-router' {
       preLoaderRoute: typeof DashboardIdAutomationsRouteImport
       parentRoute: typeof DashboardIdRoute
     }
-    '/dashboard/$id/approvals': {
-      id: '/dashboard/$id/approvals'
-      path: '/approvals'
-      fullPath: '/dashboard/$id/approvals'
-      preLoaderRoute: typeof DashboardIdApprovalsRouteImport
-      parentRoute: typeof DashboardIdRoute
-    }
     '/dashboard/$id/_knowledge': {
       id: '/dashboard/$id/_knowledge'
       path: ''
@@ -869,13 +837,6 @@ declare module '@tanstack/react-router' {
       preLoaderRoute: typeof DashboardIdAutomationsAmIdRouteImport
       parentRoute: typeof DashboardIdAutomationsRoute
     }
-    '/dashboard/$id/approvals/$status': {
-      id: '/dashboard/$id/approvals/$status'
-      path: '/$status'
-      fullPath: '/dashboard/$id/approvals/$status'
-      preLoaderRoute: typeof DashboardIdApprovalsStatusRouteImport
-      parentRoute: typeof DashboardIdApprovalsRoute
-    }
     '/dashboard/$id/_knowledge/websites': {
       id: '/dashboard/$id/_knowledge/websites'
       path: '/websites'
@@ -1008,17 +969,6 @@ const DashboardIdKnowledgeRouteChildren: DashboardIdKnowledgeRouteChildren = {
 const DashboardIdKnowledgeRouteWithChildren =
   DashboardIdKnowledgeRoute._addFileChildren(DashboardIdKnowledgeRouteChildren)
 
-interface DashboardIdApprovalsRouteChildren {
-  DashboardIdApprovalsStatusRoute: typeof DashboardIdApprovalsStatusRoute
-}
-
-const DashboardIdApprovalsRouteChildren: DashboardIdApprovalsRouteChildren = {
-  DashboardIdApprovalsStatusRoute: DashboardIdApprovalsStatusRoute,
-}
-
-const DashboardIdApprovalsRouteWithChildren =
-  DashboardIdApprovalsRoute._addFileChildren(DashboardIdApprovalsRouteChildren)
-
 interface DashboardIdAutomationsAmIdRouteChildren {
   DashboardIdAutomationsAmIdConfigurationRoute: typeof DashboardIdAutomationsAmIdConfigurationRoute
   DashboardIdAutomationsAmIdExecutionsRoute: typeof DashboardIdAutomationsAmIdExecutionsRoute
@@ -1161,7 +1111,6 @@ const DashboardIdSettingsRouteWithChildren =
 
 interface DashboardIdRouteChildren {
   DashboardIdKnowledgeRoute: typeof DashboardIdKnowledgeRouteWithChildren
-  DashboardIdApprovalsRoute: typeof DashboardIdApprovalsRouteWithChildren
   DashboardIdAutomationsRoute: typeof DashboardIdAutomationsRouteWithChildren
   DashboardIdChatRoute: typeof DashboardIdChatRouteWithChildren
   DashboardIdConversationsRoute: typeof DashboardIdConversationsRouteWithChildren
@@ -1172,7 +1121,6 @@ interface DashboardIdRouteChildren {
 
 const DashboardIdRouteChildren: DashboardIdRouteChildren = {
   DashboardIdKnowledgeRoute: DashboardIdKnowledgeRouteWithChildren,
-  DashboardIdApprovalsRoute: DashboardIdApprovalsRouteWithChildren,
   DashboardIdAutomationsRoute: DashboardIdAutomationsRouteWithChildren,
   DashboardIdChatRoute: DashboardIdChatRouteWithChildren,
   DashboardIdConversationsRoute: DashboardIdConversationsRouteWithChildren,
diff --git a/services/platform/app/routes/dashboard/$id/approvals.tsx b/services/platform/app/routes/dashboard/$id/approvals.tsx
deleted file mode 100644
index 40284d801c..0000000000
--- a/services/platform/app/routes/dashboard/$id/approvals.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { convexQuery } from '@convex-dev/react-query';
-import { createFileRoute, Outlet, redirect } from '@tanstack/react-router';
-
-import {
-  AdaptiveHeaderRoot,
-  AdaptiveHeaderTitle,
-} from '@/app/components/layout/adaptive-header';
-import { ContentArea } from '@/app/components/layout/content-area';
-import { PageLayout } from '@/app/components/layout/page-layout';
-import { ApprovalsNavigation } from '@/app/features/approvals/components/approvals-navigation';
-import { api } from '@/convex/_generated/api';
-import { useT } from '@/lib/i18n/client';
-import { seo } from '@/lib/utils/seo';
-
-export const Route = createFileRoute('/dashboard/$id/approvals')({
-  head: () => ({
-    meta: seo('approvals'),
-  }),
-  beforeLoad: ({ params, location }) => {
-    if (location.pathname === `/dashboard/${params.id}/approvals`) {
-      throw redirect({
-        to: '/dashboard/$id/approvals/$status',
-        params: { id: params.id, status: 'pending' },
-      });
-    }
-  },
-  loader: ({ context, params }) => {
-    void context.queryClient.prefetchQuery(
-      convexQuery(api.approvals.queries.approxCountApprovalsByStatus, {
-        organizationId: params.id,
-        status: 'resolved',
-      }),
-    );
-    void context.queryClient.prefetchQuery(
-      convexQuery(api.approvals.queries.approxCountApprovalsByStatus, {
-        organizationId: params.id,
-        status: 'pending',
-      }),
-    );
-  },
-  component: ApprovalsLayout,
-});
-
-function ApprovalsLayout() {
-  const { id: organizationId } = Route.useParams();
-  const { t } = useT('approvals');
-
-  return (
-    <PageLayout
-      organizationId={organizationId}
-      header={
-        <>
-          <AdaptiveHeaderRoot standalone={false}>
-            <AdaptiveHeaderTitle>{t('title')}</AdaptiveHeaderTitle>
-          </AdaptiveHeaderRoot>
-          <ApprovalsNavigation organizationId={organizationId} />
-        </>
-      }
-    >
-      <ContentArea className="min-h-0 flex-1">
-        <Outlet />
-      </ContentArea>
-    </PageLayout>
-  );
-}
diff --git a/services/platform/app/routes/dashboard/$id/approvals/$status.tsx b/services/platform/app/routes/dashboard/$id/approvals/$status.tsx
deleted file mode 100644
index 7bbb60c7d8..0000000000
--- a/services/platform/app/routes/dashboard/$id/approvals/$status.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { convexQuery } from '@convex-dev/react-query';
-import { createFileRoute, notFound } from '@tanstack/react-router';
-import { z } from 'zod';
-
-import { Approvals } from '@/app/features/approvals/components/approvals';
-import {
-  useApproxApprovalCountByStatus,
-  useListApprovalsPaginated,
-} from '@/app/features/approvals/hooks/queries';
-import { api } from '@/convex/_generated/api';
-
-const VALID_STATUSES = ['pending', 'resolved'] as const;
-type ValidStatus = (typeof VALID_STATUSES)[number];
-
-function isValidStatus(value: string): value is ValidStatus {
-  return VALID_STATUSES.some((s) => s === value);
-}
-
-const searchSchema = z.object({
-  search: z.string().optional(),
-});
-
-export const Route = createFileRoute('/dashboard/$id/approvals/$status')({
-  validateSearch: searchSchema,
-  beforeLoad: ({ params }) => {
-    if (!isValidStatus(params.status)) {
-      throw notFound();
-    }
-  },
-  loader: ({ context, params }) => {
-    if (isValidStatus(params.status)) {
-      const isPending = params.status === 'pending';
-
-      void context.queryClient.prefetchQuery(
-        convexQuery(api.approvals.queries.listApprovalsPaginated, {
-          organizationId: params.id,
-          ...(isPending
-            ? { status: 'pending', resourceType: 'product_recommendation' }
-            : {
-                resourceType: 'product_recommendation',
-                excludeStatus: 'pending',
-              }),
-          paginationOpts: { numItems: 30, cursor: null },
-        }),
-      );
-      void context.queryClient.prefetchQuery(
-        convexQuery(api.approvals.queries.approxCountApprovalsByStatus, {
-          organizationId: params.id,
-          status: params.status,
-        }),
-      );
-    }
-  },
-  component: ApprovalsStatusPage,
-});
-
-function ApprovalsStatusPage() {
-  const { id: organizationId, status } = Route.useParams();
-  const { search } = Route.useSearch();
-  const isPending = status === 'pending';
-  const resolvedStatus: ValidStatus = isPending ? 'pending' : 'resolved';
-
-  const { data: approxCount } = useApproxApprovalCountByStatus(
-    organizationId,
-    resolvedStatus,
-  );
-
-  const paginatedResult = useListApprovalsPaginated({
-    organizationId,
-    ...(isPending
-      ? { status: 'pending', resourceType: 'product_recommendation' }
-      : { resourceType: 'product_recommendation', excludeStatus: 'pending' }),
-    initialNumItems: 30,
-  });
-
-  return (
-    <Approvals
-      key={`${organizationId}-${status}`}
-      status={resolvedStatus}
-      search={search}
-      paginatedResult={paginatedResult}
-      approxCount={approxCount}
-    />
-  );
-}
diff --git a/services/platform/messages/en.json b/services/platform/messages/en.json
index ae2fd12508..d08a5c9687 100644
--- a/services/platform/messages/en.json
+++ b/services/platform/messages/en.json
@@ -218,7 +218,6 @@
     "chatWithAI": "Chat with AI",
     "conversations": "Conversations",
     "knowledge": "Knowledge",
-    "approvals": "Approvals",
     "automations": "Automations",
     "settings": "Settings",
     "settingsAndMore": "Settings and more",
@@ -277,10 +276,6 @@
       "title": "No examples yet",
       "description": "Add example messages to train the AI on your tone"
     },
-    "approvals": {
-      "title": "No approvals found",
-      "description": "There are no approvals matching your criteria"
-    },
     "conversations": {
       "title": "No conversations yet",
       "description": "Conversations will appear here"
@@ -2044,77 +2039,6 @@
       "connectEmail": "Connect email"
     }
   },
-  "approvals": {
-    "title": "Approvals",
-    "noApprovalsFound": "No approvals found",
-    "columns": {
-      "approvalRecipient": "Approval / Recipient",
-      "event": "Event",
-      "action": "Action",
-      "reviewer": "Reviewer",
-      "reviewedAt": "Reviewed at",
-      "approved": "Approved",
-      "confidence": "Confidence",
-      "unknown": "Unknown",
-      "unknownCustomer": "Unknown customer"
-    },
-    "types": {
-      "reviewReply": "Review reply",
-      "recommendProduct": "Recommend product",
-      "review": "Review",
-      "runWorkflow": "Run workflow",
-      "updateWorkflow": "Update workflow"
-    },
-    "labels": {
-      "purchase": "Purchase",
-      "recommendation": "Recommendation",
-      "otherProducts": "{count, plural, one {# other product} other {# other products}}"
-    },
-    "actions": {
-      "approve": "Approve",
-      "reject": "Reject",
-      "removeProduct": "Remove {name} from recommendations"
-    },
-    "confidenceBadge": "{percent}% confidence",
-    "productStatus": {
-      "active": "Active",
-      "cancelled": "Cancelled"
-    },
-    "status": {
-      "pending": "Pending",
-      "resolved": "Resolved"
-    },
-    "emptyState": {
-      "pending": {
-        "title": "No pending approvals",
-        "description": "When human input is needed, your AI will request it here"
-      },
-      "resolved": {
-        "title": "No resolved approvals"
-      }
-    },
-    "toast": {
-      "loginRequired": "You must be logged in to perform this action.",
-      "approveFailed": "Failed to approve. Please try again.",
-      "rejectFailed": "Failed to reject. Please try again.",
-      "removeRecommendationFailed": "Failed to remove recommendation. Please try again."
-    },
-    "detail": {
-      "title": "Approval details",
-      "status": "Status",
-      "statusPending": "Pending",
-      "statusApproved": "Approved",
-      "statusRejected": "Rejected",
-      "type": "Type",
-      "typeProductRecommendation": "Product recommendation",
-      "createdAt": "Created at",
-      "confidence": "Confidence",
-      "recommendedProducts": "Recommended products",
-      "userPurchased": "User purchased",
-      "reject": "Reject",
-      "approve": "Approve"
-    }
-  },
   "workflowRunApproval": {
     "approve": "Run workflow",
     "reject": "Cancel",
@@ -2956,10 +2880,6 @@
       "title": "Conversations",
       "description": "View and manage customer conversations."
     },
-    "approvals": {
-      "title": "Approvals",
-      "description": "Review and approve pending actions."
-    },
     "automations": {
       "title": "Automations",
       "description": "Manage your automation workflows."

From a59037b13617bbead89560f424b6ef2de4c40293 Mon Sep 17 00:00:00 2001
From: larryro <371767072@qq.com>
Date: Sun, 15 Mar 2026 19:14:05 +0800
Subject: [PATCH 2/2] fix: remove unused safe-parsers utility

No longer referenced after approvals feature removal.
---
 services/platform/lib/utils/safe-parsers.ts | 73 ---------------------
 1 file changed, 73 deletions(-)
 delete mode 100644 services/platform/lib/utils/safe-parsers.ts

diff --git a/services/platform/lib/utils/safe-parsers.ts b/services/platform/lib/utils/safe-parsers.ts
deleted file mode 100644
index e7bae3dd99..0000000000
--- a/services/platform/lib/utils/safe-parsers.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Safe parsing utilities for metadata, JSON, and complex data structures.
- *
- * These functions prevent runtime errors from malformed or unexpected data
- * by providing type-safe extraction with fallback values.
- *
- * Used primarily in:
- * - Approvals metadata parsing
- * - Complex table cell renderers
- * - API response handling
- *
- * @example
- * const metadata = approval.metadata as unknown;
- * const customerName = safeGetString(metadata, 'customerName', 'Unknown');
- * const products = safeParseProductList(metadata.recommendedProducts);
- */
-
-import { isRecord } from './type-guards';
-
-/**
- * Safely extract a string value from an object.
- *
- * @param obj - Object to extract from
- * @param key - Property key
- * @param fallback - Fallback value if extraction fails
- * @returns The string value or fallback
- */
-export function safeGetString(
-  obj: unknown,
-  key: string,
-  fallback = '',
-): string {
-  if (!isRecord(obj)) return fallback;
-  const value = obj[key];
-  return typeof value === 'string' ? value : fallback;
-}
-
-/**
- * Safely extract a number value from an object.
- *
- * @param obj - Object to extract from
- * @param key - Property key
- * @param fallback - Fallback value if extraction fails
- * @returns The number value or fallback
- */
-export function safeGetNumber(
-  obj: unknown,
-  key: string,
-  fallback?: number,
-): number | undefined {
-  if (!isRecord(obj)) return fallback;
-  const value = obj[key];
-  return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
-}
-
-/**
- * Safely extract an array from an object.
- *
- * @param obj - Object to extract from
- * @param key - Property key
- * @param fallback - Fallback array if extraction fails
- * @returns The array value or fallback
- */
-export function safeGetArray<T>(
-  obj: unknown,
-  key: string,
-  fallback: T[] = [],
-): T[] {
-  if (!isRecord(obj)) return fallback;
-  const value = obj[key];
-  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Array.isArray narrows to unknown[]; T[] not inferrable
-  return Array.isArray(value) ? (value as T[]) : fallback;
-}
