formatting

This commit is contained in:
PawelC4
2025-11-09 00:07:25 -05:00
parent 3686ae72da
commit 972df9b70b
15 changed files with 1283 additions and 1107 deletions
+160 -176
View File
@@ -1,188 +1,172 @@
// File: Home.tsx (Renamed from form.tsx for export consistency)
// "use client";
// import React, { useState, useEffect, useCallback } from "react";
// import FormPage from './FormPage';
// import { ChatSetting } from "../exportType/types";
// import { FormData, PROFICIENCY_LEVELS } from './formTypes';
"use client";
import React, { useState, useEffect, useCallback } from "react";
import FormPage from './FormPage';
import { ChatSetting, CardData } from "@/app/exportType/types";
import { FormData, PROFICIENCY_LEVELS } from './formTypes';
import SwipeCards from '../cards/page';
// // --- Helper function to get default form data ---
// const getDefaultFormData = (): FormData => ({
// Hackathon: '',
// mainTheme: '',
// tracksStack: [''],
// students: [{
// studentName: '',
// skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
// }],
// });
export default function Home() {
const [showForm, setShowForm] = useState(true);
const [formData, setFormData] = useState<FormData>(() => {
if (typeof window !== 'undefined') {
const storedFormData = localStorage.getItem('formData');
if (storedFormData) {
const parsedData: FormData = JSON.parse(storedFormData);
return parsedData;
}
}
return {
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
// };
// };
const [ideaResponse, setIdeaResponse] = useState<string>("");
const [generatedCards, setGeneratedCards] = useState<CardData[]>([]); // New state for parsed cards
// // 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.
// 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.]`,
// };
const [settings] = useState<ChatSetting>({
temperature: 1,
model: "gemini-2.5-flash-lite",
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.
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 parseAiResponse = (markdownString: string): CardData[] => {
console.log("Raw AI Response:", markdownString);
const ideas: CardData[] = [];
const ideaBlocks = markdownString.split("### ").filter(block => block.trim() !== "");
// export default function Home() {
// const [initialState] = useState(getInitialState);
// const [showForm, setShowForm] = useState(initialState.showForm);
// const [formData, setFormData] = useState<FormData>(initialState.data);
// const [ideaResponse, setIdeaResponse] = useState<string>("");
// // The 'settings' state [useState] is now removed from here.
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 handleFormSubmitFromFormPage = (submittedData: FormData) => {
// setFormData(submittedData);
// setShowForm(false);
// generateIdeas(submittedData);
// };
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 !== '');
// // 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),
// };
ideas.push({
id: index + 1,
title,
tracks,
summary,
});
});
console.log("Parsed Cards:", ideas);
return ideas;
};
// // 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.`;
const handleFormSubmitFromFormPage = (submittedData: FormData) => {
setFormData(submittedData);
setShowForm(false);
generateIdeas(submittedData);
};
// // 3. API Call
// try {
// setIdeaResponse("Generating ideas... Please wait.");
// 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
// }),
// });
// eslint-disable-next-line react-hooks/preserve-manual-memoization
const generateIdeas = useCallback(async (dataToProcess: FormData) => {
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),
};
// const data = await response.json();
// if (data.error || !response.ok) {
// console.error("AI Error:", data.error);
// setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
// return;
// }
// 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
// }, []);
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('; ')}
// // Replaced useEffect
// useEffect(() => {
// if (initialState.runEffect) {
// generateIdeas(initialState.data);
// }
// }, [initialState, generateIdeas]);
Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`;
try {
setIdeaResponse("Generating ideas... Please wait.");
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();
if (data.error || !response.ok) {
console.error("AI Error:", data.error);
setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
return;
}
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');
}
}
}, [generateIdeas]);
return (
<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">
{showForm ? (
<FormPage onFormSubmit={handleFormSubmitFromFormPage} />
) : (
<>
{generatedCards.length > 0 ? (
<SwipeCards initialCards={generatedCards} />
) : (
<>
<h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
Generated Project Idea 💡
</h1>
<div className="mt-8 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
<h2 className="text-xl font-bold text-gray-700 mb-2">Generated Ideas:</h2>
<div
className="prose max-w-none"
dangerouslySetInnerHTML={{ __html: ideaResponse.replace(/\n/g, '<br/>') }}
/>
{ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>}
</div>
</>
)}
<button
onClick={() => setShowForm(true)}
className="mt-6 w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition duration-150"
>
Go Back to Form
</button>
</>
)}
</div>
</main>
);
}
// // --- JSX Rendering ---
// return (
// <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">
// {showForm ? (
// <FormPage onFormSubmit={handleFormSubmitFromFormPage} />
// ) : (
// <>
// <h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
// Generated Project Idea 💡
// </h1>
// <div className="mt-8 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
// <h2 className="text-xl font-bold text-gray-700 mb-2">Generated Ideas:</h2>
// <div
// className="prose max-w-none"
// dangerouslySetInnerHTML={{ __html: ideaResponse.replace(/\n/g, '<br/>') }}
// />
// {ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>}
// </div>
// <button
// onClick={() => setShowForm(true)}
// className="mt-6 w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition duration-150"
// >
// Go Back to Form
// </button>
// </>
// )}
// </div>
// </main>
// );
// }