diff --git a/src/app/actions.ts b/src/app/actions.ts index 2924ac3..90f6ae0 100644 --- a/src/app/actions.ts +++ b/src/app/actions.ts @@ -5,6 +5,7 @@ import { prisma } from '@/lib/prisma'; import { upsertMailingListEntry } from '@/lib/mailingList'; import { verifyTurnstileToken } from '@/lib/turnstile'; import { getClientIp } from '@/lib/rateLimit'; +import { getCurrentCustomer } from '@/lib/auth'; const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; @@ -30,3 +31,8 @@ export async function subscribeToNewsletter(email: string, turnstileToken: strin return { ok: true, message: "Thanks — you're on the list." }; } + +export async function checkCustomerAuth() { + const customer = await getCurrentCustomer(); + return { isAuthenticated: !!customer }; +} diff --git a/src/components/DesignCanvas.tsx b/src/components/DesignCanvas.tsx index 760b0c8..c5855e4 100644 --- a/src/components/DesignCanvas.tsx +++ b/src/components/DesignCanvas.tsx @@ -6,8 +6,10 @@ import type Konva from 'konva'; import { v4 as uuid } from 'uuid'; import ProductMockup from './ProductMockup'; import Price from './Price'; +import LoginPromptModal from './LoginPromptModal'; import { useCart } from '@/lib/cartStore'; import { getEffectivePrice } from '@/lib/pricing'; +import { checkCustomerAuth } from '@/app/actions'; import type { DesignElement, PrintArea, ProductDTO } from '@/lib/types'; const DISPLAY = 560; // css px size the mockup + stage are rendered at @@ -310,6 +312,7 @@ export default function DesignCanvas({ product }: { product: ProductDTO }) { const [selectedId, setSelectedId] = useState(null); const [quantity, setQuantity] = useState(1); const [justAdded, setJustAdded] = useState(false); + const [showLoginPrompt, setShowLoginPrompt] = useState(false); const [nodeReadyTick, setNodeReadyTick] = useState(0); const stageFrontRef = useRef(null); @@ -462,7 +465,12 @@ export default function DesignCanvas({ product }: { product: ProductDTO }) { ).price : product.effectivePrice; - const handleAddToBag = () => { + const handleAddToBag = async () => { + const { isAuthenticated } = await checkCustomerAuth(); + if (!isAuthenticated) { + setShowLoginPrompt(true); + } + if (!canPersonalize) { const flatPhoto = product.colorPhotos[color] ?? product.imageUrl ?? ''; addItem({ @@ -861,6 +869,8 @@ export default function DesignCanvas({ product }: { product: ProductDTO }) { {justAdded &&

Added to your bag.

} + + setShowLoginPrompt(false)} /> ); } diff --git a/src/components/LoginPromptModal.tsx b/src/components/LoginPromptModal.tsx new file mode 100644 index 0000000..2ebdb61 --- /dev/null +++ b/src/components/LoginPromptModal.tsx @@ -0,0 +1,47 @@ +'use client'; + +import Link from 'next/link'; + +interface LoginPromptModalProps { + isOpen: boolean; + onClose: () => void; +} + +export default function LoginPromptModal({ isOpen, onClose }: LoginPromptModalProps) { + if (!isOpen) return null; + + return ( +
+
+

Create an account to shop

+

+ Add items to your bag and save your designs. You'll need an account to checkout. +

+ +
+ + Create account + + + Log in + +
+ + +
+
+ ); +} diff --git a/src/components/StandardProductView.tsx b/src/components/StandardProductView.tsx index 3e37def..db28829 100644 --- a/src/components/StandardProductView.tsx +++ b/src/components/StandardProductView.tsx @@ -4,8 +4,10 @@ import { useState } from 'react'; import { v4 as uuid } from 'uuid'; import ProductMockup from './ProductMockup'; import Price from './Price'; +import LoginPromptModal from './LoginPromptModal'; import { useCart } from '@/lib/cartStore'; import { getColorName } from '@/lib/colorNames'; +import { checkCustomerAuth } from '@/app/actions'; import type { ProductDTO } from '@/lib/types'; export default function StandardProductView({ product }: { product: ProductDTO }) { @@ -14,6 +16,7 @@ export default function StandardProductView({ product }: { product: ProductDTO } const [view, setView] = useState<'front' | 'back'>('front'); const [quantity, setQuantity] = useState(1); const [justAdded, setJustAdded] = useState(false); + const [showLoginPrompt, setShowLoginPrompt] = useState(false); const addItem = useCart((s) => s.addItem); const hasBack = Boolean(product.imageUrlBack); @@ -44,7 +47,12 @@ export default function StandardProductView({ product }: { product: ProductDTO } return {product.name}; } - const handleAddToBag = () => { + const handleAddToBag = async () => { + const { isAuthenticated } = await checkCustomerAuth(); + if (!isAuthenticated) { + setShowLoginPrompt(true); + } + addItem({ cartItemId: uuid(), productId: product.id, @@ -182,6 +190,8 @@ export default function StandardProductView({ product }: { product: ProductDTO } {justAdded &&

Added to your bag.

} + + setShowLoginPrompt(false)} /> ); }