"use client"; import React, { useState, useEffect, Suspense } from "react"; import { motion, useMotionValue, useTransform, useAnimation } from "framer-motion"; import { useRouter, useSearchParams } from "next/navigation"; import { CardData } from "@/app/exportType/types"; interface ColorWay { card: string; text: string; titleColor: string; } const COLOR_WAYS: ColorWay[] = [ { card: "#FEEEDF", text: "#173C46", titleColor: "#173C46" }, { card: "#FEEEDF", text: "#EA627F", titleColor: "#173C46" }, { card: "#DEE5D4", text: "#173C46", titleColor: "#EA627F" }, { card: "#DEE5D4", text: "#EA627F", titleColor: "#173C46" }, { card: "#B8C0AD", text: "#173C46", titleColor: "#173C46" }, { card: "#B8C0AD", text: "#173C46", titleColor: "#EA627F" }, ]; const parseAiResponse = (markdownString: string): CardData[] => { const ideas: CardData[] = []; const ideaBlocks = markdownString.split("### ").filter(block => block.trim() !== ""); ideaBlocks.forEach((block, index) => { const titleMatch = block.match(/^(.*?)\n/); const conceptMatch = block.match(/\*\*Concept:\*\*\s*([\s\S]*?)(?=\n\*\*|$)/s); // Improved summary regex // --- THIS IS THE FIX --- // It now looks for "**Core Technology:**" and splits the technologies by comma const techMatch = block.match(/\*\*Core Technology:\*\*\s*(.*)/); const tracks = techMatch ? techMatch[1].split(',').map(t => t.trim()) : ["General"]; // ----------------------- ideas.push({ id: index + 1, title: titleMatch ? titleMatch[1].trim() : `Idea ${index + 1}`, summary: conceptMatch ? conceptMatch[1].trim() : "No concept provided.", tracks: tracks.length > 0 ? tracks : ["General"], }); }); return ideas; }; export default function CardsPageWrapper(){ return (

Loading cards...

}>
); } function CardsPage() { const [cards, setCards] = useState([]); const [initialCards, setInitialCards] = useState([]); const [isLoading, setIsLoading] = useState(true); const router = useRouter(); const searchParams = useSearchParams(); const projectId = searchParams.get('projectId'); const projectTitle = searchParams.get('projectTitle'); useEffect(() => { if (typeof window === 'undefined') return; const aiResponse = localStorage.getItem('temp_aiResponse'); if (aiResponse) { localStorage.removeItem('temp_aiResponse'); const parsedCards = parseAiResponse(aiResponse); setCards(parsedCards.reverse()); setInitialCards(parsedCards.reverse()); } else { // If no AI response is found, we do nothing. // The 'cards' state will remain empty, showing the "No more cards!" UI. console.warn("No 'temp_aiResponse' found in localStorage. Displaying empty deck."); } setIsLoading(false); }, []); if (isLoading) { return

Loading cards...

} if (!projectId || !projectTitle) { return (

Missing project information. Please start a new project.

) } return ( ) } interface SwipeCardsProps { initialCards: CardData[]; currentCards: CardData[]; setCards: React.Dispatch>; projectId: string; projectTitle: string; } const SwipeCards: React.FC = ({ initialCards, currentCards, setCards, projectId, projectTitle }) => { const router = useRouter(); const removeCard = () => { setCards((prev) => prev.slice(0, prev.length - 1)); }; const handleAccept = (cardData: CardData) => { removeCard(); router.push(`/chatbot?projectId=${encodeURIComponent(projectId)}&projectTitle=${encodeURIComponent(projectTitle)}&cardTitle=${encodeURIComponent(cardData.title)}&cardSummary=${encodeURIComponent(cardData.summary)}`); }; const handleReject = () => { removeCard(); }; const handleReset = () => { setCards(initialCards); }; return (
{currentCards.length > 0 ? ( currentCards.map((card, index) => { const colorWay = COLOR_WAYS[card.id % COLOR_WAYS.length]; return ( ); }) ) : (

No more cards!

You've swiped through them all.

)}
); }; interface CardProps { cardData: CardData; colorWay: ColorWay; isFront: boolean; onAccept: (cardData: CardData) => void; onReject: () => void; } const Card: React.FC = ({ cardData, colorWay, isFront, onAccept, onReject }) => { const { title, summary, tracks } = cardData; const controls = useAnimation(); const x = useMotionValue(0); const rotate = useTransform(x, [-250, 250], [-25, 25]); const opacity = useTransform( x, [-250, -100, 0, 100, 250], [0, 1, 1, 1, 0], ); const acceptOpacity = useTransform(x, [50, 150], [0, 1]); const rejectOpacity = useTransform(x, [-150, -50], [1, 0]); const badgeRotate = useTransform(x, [-150, 150], [-15, 15]); const handleDragEnd = async (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => { if (info.offset.x > 100) { await controls.start({ x: 1000, opacity: 0, transition: { duration: 0.1 } }); onAccept(cardData); } else if (info.offset.x < -100) { await controls.start({ x: -1000, opacity: 0, transition: { duration: 0.1 } }); onReject(); } else { controls.start({ x: 0, rotate: 0, opacity: 1, transition: { type: "spring", stiffness: 300, damping: 30 } }); } }; return (

Accept

Reject

{title}

{summary}

Tracks

{tracks.map((track) => ( {track} ))}
); };