diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx
index 5e9f32b8..6e739fb4 100644
--- a/packages/ui/src/App.tsx
+++ b/packages/ui/src/App.tsx
@@ -62,7 +62,6 @@ const I18nPlayground = React.lazy(() => import("./components/playground/I18nPlay
const VersionMap = React.lazy(() => import("./pages/VersionMap"));
-
//
import { EcommerceBundleWrapper } from "./bundles/ecommerce";
diff --git a/packages/ui/src/bundles/ecommerce.tsx b/packages/ui/src/bundles/ecommerce.tsx
index 9773f4d0..2af63469 100644
--- a/packages/ui/src/bundles/ecommerce.tsx
+++ b/packages/ui/src/bundles/ecommerce.tsx
@@ -2,11 +2,14 @@ import React from "react";
import { useNavigate } from "react-router-dom";
import { useAuth } from "@/hooks/useAuth";
+import { getCurrentLang } from "@/i18n";
+
const EcommerceBundle = React.lazy(() => import("@polymech/ecommerce").then(m => ({ default: m.EcommerceBundle })));
export const EcommerceBundleWrapper = () => {
- const { user } = useAuth();
+ const { user, session } = useAuth();
const navigate = useNavigate();
+ const locale = getCurrentLang();
// Memoize dependencies to prevent re-renders
const dependencies = React.useMemo(() => {
@@ -51,6 +54,9 @@ export const EcommerceBundleWrapper = () => {
})),
total_amount: subtotal,
payment_provider: data.paymentMethod,
+ // Stripe-specific fields (undefined for non-Stripe payments)
+ external_order_id: data.external_order_id,
+ metadata: data.metadata,
});
useCartStore.getState().clearCart();
},
@@ -60,9 +66,13 @@ export const EcommerceBundleWrapper = () => {
},
onNavigate: (path: string) => navigate(path),
siteName: "PolyMech",
- contactEmail: "legal@polymech.org"
+ contactEmail: "sales@plastic-hub.com",
+ stripePublishableKey: import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY,
+ apiBaseUrl: import.meta.env.VITE_SERVER_IMAGE_API_URL || "",
+ getAuthToken: async () => session?.access_token ?? null,
+ locale,
};
- }, [user, navigate]);
+ }, [user, session, navigate, locale]);
return (
Loading...}>
diff --git a/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx b/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx
index 0b4c100c..4c217928 100644
--- a/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx
+++ b/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx
@@ -236,6 +236,7 @@ interface CompactAction {
disabled?: boolean;
iconColor?: string;
onDelete?: () => void;
+ testId?: string;
}
const CompactFlowGroup = ({
@@ -266,6 +267,7 @@ const CompactFlowGroup = ({
disabled={action.disabled}
iconColor={action.iconColor}
onDelete={action.onDelete}
+ {...(action.testId ? { 'data-testid': action.testId } : {})}
/>
))}
{shouldOverflow && (
@@ -738,14 +740,16 @@ export const PageRibbonBar = ({
label: page.visible ? "Visible" : "Hidden",
active: !page.visible,
onClick: () => handleToggleVisibility(),
- iconColor: page.visible ? "text-emerald-500" : "text-gray-400"
+ iconColor: page.visible ? "text-emerald-500" : "text-gray-400",
+ testId: 'page-visibility-toggle'
},
{
icon: page.is_public ? GitMerge : Settings,
label: page.is_public ? "Public" : "Private",
active: !page.is_public,
onClick: () => handleTogglePublic(),
- iconColor: page.is_public ? "text-amber-500" : "text-gray-400"
+ iconColor: page.is_public ? "text-amber-500" : "text-gray-400",
+ testId: 'page-public-toggle'
},
{
icon: FolderTree,
diff --git a/packages/ui/src/pages/Profile.tsx b/packages/ui/src/pages/Profile.tsx
index 519dbce2..a1a10dfd 100644
--- a/packages/ui/src/pages/Profile.tsx
+++ b/packages/ui/src/pages/Profile.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect } from "react";
+import React, { useState, useEffect } from "react";
import { useAuth } from "@/hooks/useAuth";
import ImageGallery from "@/components/ImageGallery";
import { ImageFile } from "@/types";
@@ -10,7 +10,7 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { User, Images, Save, Camera, Upload, Check, Key, Globe, Hash, MapPin, Building2 } from "lucide-react";
+import { User, Images, Save, Camera, Upload, Check, Key, Globe, Hash, MapPin, Building2, ShoppingBag } from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
@@ -33,7 +33,11 @@ import {
useSidebar
} from "@/components/ui/sidebar";
-type ActiveSection = 'general' | 'api-keys' | 'variables' | 'addresses' | 'vendor' | 'gallery';
+const LazyPurchasesList = React.lazy(() =>
+ import("@polymech/ecommerce").then(m => ({ default: m.PurchasesList }))
+);
+
+type ActiveSection = 'general' | 'api-keys' | 'variables' | 'addresses' | 'vendor' | 'gallery' | 'purchases';
const Profile = () => {
const { user, loading } = useAuth();
@@ -560,6 +564,26 @@ const Profile = () => {
)}
+ {activeSection === 'purchases' && (
+
+
+ My Purchases
+
+
+ Loading...}>
+ {
+ const { listTransactions } = await import('@/modules/ecommerce/client-ecommerce');
+ return listTransactions();
+ }}
+ onNavigate={navigate}
+ toast={{ error: (msg: string) => toast.error(msg) }}
+ />
+
+
+
+ )}
+
{activeSection === 'analytics' && roles.includes('admin') && (
@@ -622,6 +646,7 @@ const ProfileSidebar = ({
{ id: 'variables' as ActiveSection, label: translate('Variables'), icon: Hash },
{ id: 'addresses' as ActiveSection, label: translate('Shipping Addresses'), icon: MapPin },
{ id: 'vendor' as ActiveSection, label: translate('Vendor Profiles'), icon: Building2 },
+ { id: 'purchases' as ActiveSection, label: translate('Purchases'), icon: ShoppingBag },
];
diff --git a/packages/ui/src/pages/UserProfile.tsx b/packages/ui/src/pages/UserProfile.tsx
index bb28f1f6..a933f574 100644
--- a/packages/ui/src/pages/UserProfile.tsx
+++ b/packages/ui/src/pages/UserProfile.tsx
@@ -342,6 +342,7 @@ const UserProfile = () => {
+ {/* Photos Grid - Using PhotoGrid with customPictures */}
{/* Photos Grid - Using PhotoGrid with customPictures */}
{
setData(events.map((e: any, index: number) => ({ ...e, id: `init-${index}` })));
- // Start Streaming
- eventSource = new EventSource('/api/analytics/stream');
+ // Start Streaming (with auth token as query param — EventSource doesn't support headers)
+ const { data: sessionData } = await supabase.auth.getSession();
+ const token = sessionData.session?.access_token;
+ const streamUrl = token
+ ? `/api/analytics/stream?token=${encodeURIComponent(token)}`
+ : '/api/analytics/stream';
+ eventSource = new EventSource(streamUrl);
eventSource.addEventListener('log', (event: any) => {
if (!isMounted) return;