"use client"; import React, { useState, useEffect, useCallback } from "react"; import FormPage from './FormPage'; import { ChatSetting } from "../exportType/types"; import { FormData, PROFICIENCY_LEVELS } from './formTypes'; // --- Helper function to get default form data --- const getDefaultFormData = (): FormData => ({ Hackathon: '', mainTheme: '', tracksStack: [''], students: [{ studentName: '', skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }] }], }); // --- New Initializer Function --- const getInitialState = () => { if (typeof window === 'undefined') { return { data: getDefaultFormData(), showForm: true, runEffect: false }; } const storedFormData = localStorage.getItem('formData'); if (storedFormData) { localStorage.removeItem('formData'); return { data: JSON.parse(storedFormData) as FormData, showForm: false, runEffect: true, }; } return { data: getDefaultFormData(), showForm: true, runEffect: false }; }; <<<<<<< HEAD const [ideaResponse, setIdeaResponse] = useState(""); const [generatedCards, setGeneratedCards] = useState([]); // New state for parsed cards const [settings] = useState({ temperature: 1, model: "gemini-2.5-flash-lite", systemInstruction: `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. ======= // FIX 1 (Memoization): Moved settings OUTSIDE the component. // This makes it a true constant. 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. >>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a The output MUST be in Markdown format and strictly follow this structure: ### Project Idea Title <<<<<<< HEAD **Track** [print out the track you used] **Concept:** [A concise, single paragraph description of the product and its primary function.]`, }); 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) => { // Match title: anything from the start of the block until the first newline or the start of "**Track**" const titleMatch = block.match(/^(.*?)(?=\n\*\*Track\*\*|$)/s); // Match track: "**Track**" followed by optional whitespace and then capture everything until the next "**Concept**" or end of block/line const trackMatch = block.match(/\*\*Track\*\*\s*:\s*(.*?)(?=\n\*\*Concept\*\*|$)/s); // Added ':' and made whitespace more flexible // Match concept: "**Concept:**" followed by optional whitespace and then capture everything until the end of the block 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() : ""; console.log("tracksRaw:", tracksRaw); // Added console.log for debugging 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; }; ======= **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.]`, }; >>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105 // ------------------------------------------------ export default function Home() { const [initialState] = useState(getInitialState); const [showForm, setShowForm] = useState(initialState.showForm); const [formData, setFormData] = useState(initialState.data); const [ideaResponse, setIdeaResponse] = useState(""); // The 'settings' state [useState] is now removed from here. const handleFormSubmitFromFormPage = (submittedData: FormData) => { setFormData(submittedData); setShowForm(false); generateIdeas(submittedData); }; // Wrapped generateIdeas in useCallback const generateIdeas = useCallback(async (dataToProcess: FormData) => { // 1. Data Cleaning const submissionData: FormData = { ...dataToProcess, tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''), students: dataToProcess.students .map(student => ({ ...student, skills: student.skills.filter(skill => skill.skillName.trim() !== ''), })) .filter(student => student.studentName.trim() !== '' || student.skills.length > 0), }; // 2. Prompt Construction const prompt = ` Hackathon: ${submissionData.Hackathon} Main Theme: ${submissionData.mainTheme} Required Tracks Stack: ${submissionData.tracksStack.join(', ')} Team Members and Skills: ${submissionData.students.map(s => `${s.studentName || 'Unamed Member'} (Skills: ${s.skills.map(sk => `${sk.skillName} - ${sk.proficiency}`).join(', ')})` ).join('; ')} Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`; // 3. API Call try { setIdeaResponse("Generating ideas... Please wait."); <<<<<<< HEAD setGeneratedCards([]); // Clear previous cards const response = await fetch("/api/generate-idea", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ prompt: prompt, settings: settings, }), }); const data = await response.json(); ======= const response = await fetch("/api/generate-idea", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt: prompt, settings: AI_SETTINGS, // Use the constant }), }); const data = await response.json(); >>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105 if (data.error || !response.ok) { console.error("AI Error:", data.error); setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`); return; <<<<<<< HEAD } setIdeaResponse(data.response); const parsedCards = parseAiResponse(data.response); setGeneratedCards(parsedCards); } catch (error) { console.error("Request Failed:", error); let errorMessage = "An unknown error occurred."; if (error instanceof Error) { errorMessage = error.message; } else if (typeof error === 'string') { errorMessage = error; } setIdeaResponse(`A network error occurred. Please try again. Details: ${errorMessage}`); } }, [setIdeaResponse, setGeneratedCards, settings, parseAiResponse]); useEffect(() => { if (typeof window !== 'undefined') { const storedFormData = localStorage.getItem('formData'); if (storedFormData) { const parsedData: FormData = JSON.parse(storedFormData); setTimeout(() => setShowForm(false), 0); generateIdeas(parsedData); localStorage.removeItem('formData'); ======= >>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105 } setIdeaResponse(data.response); // FIX 2 (Unexpected any): Changed 'any' to 'unknown' and added a type check. } catch (error: unknown) { console.error("Request Failed:", error); let errorMessage = "A network error occurred. Please try again."; if (error instanceof Error) { errorMessage += ` Details: ${error.message}`; } setIdeaResponse(errorMessage); } // FIX 3 (Linter): Disable the faulty memoization rule. // The empty array is correct because setIdeaResponse is a stable state setter. // eslint-disable-next-line react-hooks/preserve-manual-memoization }, []); // Replaced useEffect useEffect(() => { if (initialState.runEffect) { generateIdeas(initialState.data); } }, [initialState, generateIdeas]); // --- JSX Rendering --- return (
{showForm ? ( ) : ( <> <<<<<<< HEAD {generatedCards.length > 0 ? ( ) : ( <>

Generated Project Idea 💡

Generated Ideas:

') }} /> {ideaResponse === "" &&

Submit the form to generate project ideas.

}
)} =======

Generated Project Idea 💡

Generated Ideas:

') }} /> {ideaResponse === "" &&

Submit the form to generate project ideas.

}
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105 )}
); }