minor tweak to page.tsx

This commit is contained in:
Ivan Rudik
2025-11-09 10:04:21 +00:00
parent 0f583d4618
commit ae0ee812c5
+63 -28
View File
@@ -1,8 +1,8 @@
"use client"; "use client";
import React, { useState, useEffect, useCallback, useRef } from "react";
import React, { useState, useEffect, useCallback } from "react";
import FormPage from './FormPage'; import FormPage from './FormPage';
import { CardData } from "../exportType/types"; import { CardData } from "../exportType/types";
import SwipeCards from "../components/Cards";
import { ChatSetting } from "../exportType/types"; import { ChatSetting } from "../exportType/types";
import { FormData, PROFICIENCY_LEVELS } from './formTypes'; import { FormData, PROFICIENCY_LEVELS } from './formTypes';
import { saveProject } from '../utils/storage'; import { saveProject } from '../utils/storage';
@@ -42,35 +42,53 @@ const getInitialState = () => {
}; };
}; };
const AI_SETTINGS: ChatSetting = {
temperature: 1,
model: "gemini-2.5-pro",
systemInstructions: `You are an elite hackathon idea generator. Your task is to generate five different creative, feasible, and relevant project idea.
The output MUST be in Markdown format and strictly follow this structure:
### Project Idea Title
**Relevance to Theme:** [Explain briefly]
**Core Technology:** [List 3-5 primary technologies]
**Team Fit:** [How the team's skills apply]
**Concept:** [A concise, single paragraph description of the product and its primary function.]
**Bonus Feature:** [A single, ambitious feature to impress judges.]`
};
export default function Home() { export default function Home() {
const [formData, setFormData] = useState<FormData>(getDefaultFormData());
const [ideaResponse, setIdeaResponse] = useState<string>("");
const [generatedCards, setGeneratedCards] = useState<CardData[]>([]); // New state for parsed cards
const [initialState] = useState(getInitialState); const [initialState] = useState(getInitialState);
const [showForm, setShowForm] = useState(initialState.showForm); const [showForm, setShowForm] = useState(initialState.showForm);
const [formData, setFormData] = useState<FormData>(initialState.data); const initialIdeaGenerationAttempted = useRef(false);
const [ideaResponse, setIdeaResponse] = useState<string>("");
const router = useRouter();
const handleFormSubmitFromFormPage = (submittedData: FormData) => { const router = useRouter();
const savedProject = saveProject(submittedData); const [settings] = useState<ChatSetting>({
if (typeof window !== 'undefined') localStorage.removeItem('formData'); temperature: 1,
setFormData(submittedData); model: "gemini-2.5-flash-lite",
setShowForm(false); systemInstructions: `You are an elite hackathon idea generator. Your task is to choose at lease two track and generate five different creative, feasible, and relevant project idea.
generateIdeas(submittedData, savedProject.id); The output MUST be in Markdown format and strictly follow this structure:
### Project Idea Title
**Track** [print out the track you used]
**Concept:** [A concise, single paragraph description of the product and its primary function.]`,
});
const generateIdeas = useCallback(async (dataToProcess: FormData) => {
const parseAiResponse = (markdownString: string): CardData[] => {
console.log("Raw AI Response:", markdownString);
const ideas: CardData[] = [];
const ideaBlocks = markdownString.split("### ").filter(block => block.trim() !== "");
ideaBlocks.forEach((block, index) => {
const titleMatch = block.match(/^(.*?)(?=\n\*\*Track\*\*|$)/s);
const trackMatch = block.match(/\*\*Track\*\*\s*:\s*(.*?)(?=\n\*\*Concept\*\*|$)/s);
const conceptMatch = block.match(/\*\*Concept:\*\*\s*(.*)/s);
const title = titleMatch ? titleMatch[1].trim() : `Idea ${index + 1}`;
const summary = conceptMatch ? conceptMatch[1].trim() : "No concept provided.";
const tracksRaw = trackMatch ? trackMatch[1].trim() : "";
const tracks = tracksRaw.split(',').map(track => track.trim()).filter(track => track !== '');
ideas.push({
id: index + 1,
title,
tracks,
summary,
});
});
console.log("Parsed Cards:", ideas);
return ideas;
}; };
const generateIdeas = useCallback(async (dataToProcess: FormData, projectId: string) => {
const submissionData: FormData = { const submissionData: FormData = {
...dataToProcess, ...dataToProcess,
tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''), tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
@@ -94,13 +112,15 @@ export default function Home() {
try { try {
setIdeaResponse("Generating ideas... Please wait."); setIdeaResponse("Generating ideas... Please wait.");
setGeneratedCards([]);
const response = await fetch("/api/generate-idea", { const response = await fetch("/api/generate-idea", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ body: JSON.stringify({
prompt: prompt, prompt: prompt,
settings: AI_SETTINGS, settings: settings,
}), }),
}); });
@@ -113,6 +133,8 @@ export default function Home() {
} }
setIdeaResponse(data.response); setIdeaResponse(data.response);
const projectId = data.projectId ?? `p-${Date.now()}`;
if (typeof window !== 'undefined') localStorage.setItem('temp_aiResponse', data.response); if (typeof window !== 'undefined') localStorage.setItem('temp_aiResponse', data.response);
router.push(`/cards?projectId=${projectId}&projectTitle=${encodeURIComponent(dataToProcess.Hackathon)}`); router.push(`/cards?projectId=${projectId}&projectTitle=${encodeURIComponent(dataToProcess.Hackathon)}`);
@@ -127,17 +149,28 @@ export default function Home() {
} }
}, [router]); }, [router]);
// Replaced useEffect
useEffect(() => { useEffect(() => {
if (initialState.runEffect) { if (initialState.runEffect) {
//generateIdeas(initialState.data, "some-resumed-id"); //generateIdeas(initialState.data, "some-resumed-id");
} }
}, [initialState, generateIdeas]); }, [initialState, generateIdeas]);
const handleFormSubmitFromFormPage = (submittedData: FormData) => {
setShowForm(false);
generateIdeas(submittedData);
};
// --- JSX Rendering ---
return ( return (
<main className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter"> <main className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter">
<div className="w-full max-w-2xl bg-white p-8 shadow-2xl rounded-xl mt-8"> <div className="w-full max-w-2xl bg-white p-8 shadow-2xl rounded-xl mt-8">
{showForm ? ( {showForm ? (
<FormPage onFormSubmit={handleFormSubmitFromFormPage} /> <FormPage onFormSubmit={handleFormSubmitFromFormPage} />
) : (
<>
{generatedCards.length > 0 ? (
<SwipeCards initialCards={generatedCards} />
) : ( ) : (
<> <>
<h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight"> <h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
@@ -151,6 +184,8 @@ export default function Home() {
/> />
{ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>} {ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>}
</div> </div>
</>
)}
<button <button
onClick={() => { onClick={() => {
setShowForm(true); setShowForm(true);