stripe 2/2

This commit is contained in:
lovebird 2026-02-21 20:21:13 +01:00
parent c580407163
commit d87afd8654
6 changed files with 56 additions and 11 deletions

View File

@ -62,7 +62,6 @@ const I18nPlayground = React.lazy(() => import("./components/playground/I18nPlay
const VersionMap = React.lazy(() => import("./pages/VersionMap"));
// <GlobalDebug />
import { EcommerceBundleWrapper } from "./bundles/ecommerce";

View File

@ -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 (
<React.Suspense fallback={<div className="flex items-center justify-center p-12">Loading...</div>}>

View File

@ -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,

View File

@ -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 = () => {
</Card>
)}
{activeSection === 'purchases' && (
<Card>
<CardHeader>
<CardTitle><T>My Purchases</T></CardTitle>
</CardHeader>
<CardContent>
<React.Suspense fallback={<div className="flex items-center justify-center py-12 text-muted-foreground">Loading...</div>}>
<LazyPurchasesList
onFetchTransactions={async () => {
const { listTransactions } = await import('@/modules/ecommerce/client-ecommerce');
return listTransactions();
}}
onNavigate={navigate}
toast={{ error: (msg: string) => toast.error(msg) }}
/>
</React.Suspense>
</CardContent>
</Card>
)}
{activeSection === 'analytics' && roles.includes('admin') && (
<Card>
<CardHeader>
@ -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 },
];

View File

@ -342,6 +342,7 @@ const UserProfile = () => {
</div>
</div>
{/* Photos Grid - Using PhotoGrid with customPictures */}
{/* Photos Grid - Using PhotoGrid with customPictures */}
<div>
<PhotoGrid

View File

@ -25,6 +25,7 @@ import { Label } from "@/components/ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { fetchAnalytics, clearAnalytics } from '@/lib/db';
import { supabase } from '@/integrations/supabase/client';
import {
filterModelToParams,
paramsToFilterModel,
@ -140,8 +141,13 @@ const AnalyticsDashboard = () => {
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;