diff --git a/app/Dashboard/page.tsx b/app/Dashboard/page.tsx
index a3a4eba..342cbc3 100644
--- a/app/Dashboard/page.tsx
+++ b/app/Dashboard/page.tsx
@@ -1,121 +1,174 @@
"use client";
import React, { useState } from "react";
-import { useRouter } from "next/navigation";
-import Link from 'next/link';
+// import { useRouter } from "next/navigation"; // Removed Next.js import
+// import Link from 'next/link'; // Removed Next.js import
export default function Dashboard() {
- const router = useRouter();
- const [query, setQuery] = useState("");
- const [sideBarOpen, setSidebarOpen] = useState(true);
+ // const router = useRouter(); // Removed Next.js hook
+ const [query, setQuery] = useState("");
+ const [sideBarOpen, setSidebarOpen] = useState(true);
+ // 1. Add state to track sort order
+ const [sortOrder, setSortOrder] = useState("newest"); // 'newest' or 'oldest'
- const projects = [
- { name: "Alpha Project", createdAt: "2025-01-01" },
- { name: "Beta Board", createdAt: "2025-02-15" },
- { name: "Gamma Tasl", createdAt: "2025-03-10" },
- ];
- const filtered = projects.filter((p) =>
- p.name.toLowerCase().includes(query.toLowerCase())
- );
+ const projects = [
+ { name: "Alpha Project", createdAt: "2025-01-01" },
+ { name: "Beta Board", createdAt: "2025-02-15" },
+ { name: "Gamma Tasl", createdAt: "2025-03-10" },
+ ];
- return (
-
-
-
- {sideBarOpen && (
-
- More
-
- )}
- setSidebarOpen(!sideBarOpen)}
- className="text-zinc-600 dark:text-zinc-300 hover:text-blue-500 transition-colors"
- title="Toggle Sidebar"
- >
- ☰
-
-
+ // 2. Update sorting logic to use the sortOrder state
+ const sortedProjects = [...projects].sort((a, b) => {
+ // Get numeric timestamps to avoid TypeScript error
+ const dateA = new Date(a.createdAt).getTime();
+ const dateB = new Date(b.createdAt).getTime();
-
+ p.name.toLowerCase().includes(query.toLowerCase())
+ );
+
+ // Helper function to handle navigation for the "Create" button
+ const handleCreateClick = () => {
+ // Use standard window navigation instead of Next.js router
+ // Also corrected typo from "dashbaord" to "dashboard"
+ window.location.href = "/dashboard/create";
+ };
+
+ // 4. Function to toggle the sort order
+ const toggleSortOrder = () => {
+ setSortOrder(currentOrder => (currentOrder === "newest" ? "oldest" : "newest"));
+ };
+
+ return (
+
-
- Home
-
-
- Settings
-
- {/* 3. Added the Logout link here */}
-
- Logout
-
-
-
-
-
-
-
-
-
- Project Names
-
-
-
- );
+ {sideBarOpen && (
+
+ More
+
+ )}
+
setSidebarOpen(!sideBarOpen)}
+ className="text-white hover:text-gray-200 transition-colors"
+ title="Toggle Sidebar"
+ >
+ ☰
+
+
+
+
+
+ Home
+
+
+ Settings
+
+
+ Logout
+
+
+
+
+
+
+
+
+
+
+ Project Names
+
+
+ Sort by: {sortOrder === 'newest' ? 'Newest' : 'Oldest'}
+
+
+
+
+
+ {filtered.map((project, index) => (
+
+ {project.name}
+
+ Created: {project.createdAt}
+
+
+ ))}
+ {filtered.length === 0 && (
+ No results found
+ )}
+
+
+
+
+
+ );
}
\ No newline at end of file
diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts
index 80e8c46..83d96ae 100644
--- a/app/api/chat/route.ts
+++ b/app/api/chat/route.ts
@@ -5,20 +5,25 @@ import { ChatHistory, ChatSetting } from "@/app/exportType/types";
export async function POST(request: Request) {
try {
- const { userMessage, history , settings } = await request.json() as {
- userMessage :string;
- history : ChatHistory;
- settings : ChatSetting;
+ const { userMessage, history, settings } = await request.json() as {
+ userMessage: string;
+ history: ChatHistory;
+ settings: ChatSetting;
};
- const aiResponse = await chatToGemini(userMessage , history, settings);
- return NextResponse.json({response : aiResponse});
+ const aiResponse = await chatToGemini(userMessage, history, settings);
+ return NextResponse.json({ response: aiResponse });
}
- catch(error){
+ catch (error) {
console.error(error);
return NextResponse.json(
+<<<<<<< HEAD
{error: "Error with the model response " + String(error)},
{status : 500}
+=======
+ { error: "Error with the model response " },
+ { status: 500 }
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
);
}
}
diff --git a/app/api/generate-idea/route.ts b/app/api/generate-idea/route.ts
index c135cd4..9a2a9f4 100644
--- a/app/api/generate-idea/route.ts
+++ b/app/api/generate-idea/route.ts
@@ -6,18 +6,18 @@ import { ChatSetting } from "@/app/exportType/types";
export async function POST(request: Request) {
try {
const { prompt, settings } = await request.json() as {
- prompt :string;
- settings : ChatSetting;
+ prompt: string;
+ settings: ChatSetting;
};
- const aiResponse = await chatToGemini(prompt , [], settings);
- return NextResponse.json({response : aiResponse});
+ const aiResponse = await chatToGemini(prompt, [], settings);
+ return NextResponse.json({ response: aiResponse });
}
- catch(error){
+ catch (error) {
console.error(error);
return NextResponse.json(
- {error: "Error with the model response "},
- {status : 500}
+ { error: "Error with the model response " },
+ { status: 500 }
);
}
}
diff --git a/app/cards/page.tsx b/app/cards/page.tsx
index 0da2c42..322b377 100644
--- a/app/cards/page.tsx
+++ b/app/cards/page.tsx
@@ -1,9 +1,10 @@
"use client";
-import React, { useState, useEffect } from "react";
-import { motion, useMotionValue, useTransform, useAnimation } from "framer-motion";
-import { useRouter } from "next/navigation";
+import React, { useState } from "react";
+import { motion, useMotionValue, useTransform } from "framer-motion";
+// Removed local fallback JSX declaration — use the official React type definitions instead:
+// install @types/react and @types/react-dom so JSX.IntrinsicElements is provided by those packages.
// 1. Updated ColorWay interface
interface ColorWay {
card: string;
@@ -28,40 +29,135 @@ interface CardData {
tracks: string[];
}
-const SwipeCards: React.FC<{ initialCards: CardData[] }> = ({ initialCards }) => {
- const [cards, setCards] = useState(initialCards);
- const router = useRouter();
+const cardData: CardData[] = [
+ {
- // Update cards state when initialCards prop changes
- useEffect(() => {
- setCards(initialCards);
- }, [initialCards]);
+ id: 1,
- const removeCard = () => {
+ title: " WEBSITE",
+
+ summary:
+
+ "FFind out what makes GoonMAXXER unique.With this innovative website you will be able to explore various features and functionalities that set GoonMAXXER apart from the rest.",
+
+ tracks: ["Gemini", "Auth0", "VibeCODING", "SmellyMaxxing", "shitposting"],
+
+ },
+
+ {
+
+ id: 2,
+
+ title: "Intro to React",
+
+ summary:
+
+ "Learn the fundamentals of React, including components, state, and props.",
+
+ tracks: ["React", "JS", "Frontend"],
+
+ },
+
+ {
+
+ id: 3,
+
+ title: "State Management",
+
+ summary:
+
+ "Explore complex state solutions with Zustand, Redux, and Context API.",
+
+ tracks: ["React", "Zustand", "State"],
+
+ },
+
+ {
+
+ id: 4,
+
+ title: "Next.js 14",
+
+ summary: "Master the app router, server actions, and data fetching.",
+
+ tracks: ["Next.js", "React", "Fullstack"],
+
+ },
+
+ {
+
+ id: 5,
+
+ title: "UI/UX Principles",
+
+ summary:
+
+ "A complete guide to user-centric design, prototyping, and testing.",
+
+ tracks: ["Design", "UI", "UX"],
+
+ },
+
+ {
+
+ id: 6,
+
+ title: "Node.js Essentials",
+
+ summary:
+
+ "Build scalable, high-performance backend applications with Node.js.",
+
+ tracks: ["Node", "Backend", "JS"],
+
+ },
+
+ {
+
+ id: 7,
+
+ title: "TypeScript",
+
+ summary:
+
+ "Add static typing to your JavaScript projects for robust, large-scale apps.",
+
+ tracks: ["TypeScript", "JS", "DevOps"],
+
+ },
+
+ {
+
+ id: 8,
+
+ title: "Framer Motion",
+
+ summary: "Create production-ready animations for your React applications.",
+
+ tracks: ["React", "Animation", "Framer"],
+
+ },
+
+].reverse();
+
+const SwipeCards: React.FC = () => {
+ const [cards, setCards] = useState(cardData);
+
+ const onSwipe = () => {
setCards((prev) => prev.slice(0, prev.length - 1));
};
- const handleAccept = (cardData: CardData) => {
- removeCard();
- // Redirect to chatbot with card data
- router.push(`/chatbot?title=${encodeURIComponent(cardData.title)}&summary=${encodeURIComponent(cardData.summary)}`);
- };
-
- const handleReject = () => {
- removeCard();
- };
-
const handleReset = () => {
- setCards([]); // Reset to initial cards
+ setCards(cardData);
};
return (
@@ -74,8 +170,7 @@ const SwipeCards: React.FC<{ initialCards: CardData[] }> = ({ initialCards }) =>
cardData={card}
colorWay={colorWay}
isFront={index === cards.length - 1}
- onAccept={handleAccept}
- onReject={handleReject}
+ onSwipe={onSwipe}
/>
);
})
@@ -104,11 +199,10 @@ interface CardProps {
cardData: CardData;
colorWay: ColorWay;
isFront: boolean;
- onAccept: (cardData: CardData) => void;
- onReject: () => void;
+ onSwipe: () => void;
}
-const Card: React.FC
= ({ cardData, colorWay, isFront, onAccept, onReject }) => {
+const Card: React.FC = ({ cardData, colorWay, isFront, onSwipe }) => {
const { title, summary, tracks } = cardData;
const x = useMotionValue(0);
@@ -118,30 +212,20 @@ const Card: React.FC = ({ cardData, colorWay, isFront, onAccept, onRe
[-250, -100, 0, 100, 250],
[0, 1, 1, 1, 0],
);
- const controls = useAnimation();
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) {
- // Card accepted
- await controls.start({ x: 1000, opacity: 0, transition: { duration: 0.1 } }); // Animate off-screen quickly
- onAccept(cardData); // Then call onAccept which removes the card and redirects
- } else if (info.offset.x < -100) {
- // Card rejected
- await controls.start({ x: -1000, opacity: 0, transition: { duration: 0.1 } }); // Animate off-screen quickly
- onReject(); // Then call onReject which removes the card
- } else {
- // Card not swiped far enough, snap back to center
- controls.start({ x: 0, rotate: 0, opacity: 1, transition: { type: "spring", stiffness: 300, damping: 30 } });
+ const handleDragEnd = (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => {
+ if (Math.abs(info.offset.x) > 100) {
+ onSwipe();
}
};
return (
= ({ cardData, colorWay, isFront, onAccept, onRe
zIndex: isFront ? 2 : 1,
pointerEvents: isFront ? "auto" : "none",
}}
- animate={controls}
+ animate={{
+ scale: isFront ? 1 : 0.95,
+ y: isFront ? 0 : -40,
+ }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
drag={isFront ? "x" : false}
dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
@@ -175,20 +262,24 @@ const Card: React.FC = ({ cardData, colorWay, isFront, onAccept, onRe
{/* 3. Applied the specific titleColor here */}
{title}
{/* This summary
will inherit colorWay.text from the parent */}
-
{summary}
+
{summary}
- {tracks.slice(0, 2).map((track, index) => (
+ {/* This
will also inherit colorWay.text */}
+
+ Tracks
+
+ {tracks.map((track) => (
= ({ cardData, colorWay, isFront, onAccept, onRe
}}
>
{track}
- {index === 0 && tracks.length > 1 && ", "}
))}
@@ -207,4 +297,4 @@ const Card: React.FC = ({ cardData, colorWay, isFront, onAccept, onRe
};
-export default SwipeCards;
+export default SwipeCards;
\ No newline at end of file
diff --git a/app/chatbot/page.tsx b/app/chatbot/page.tsx
index 6c5624c..4be1b08 100644
--- a/app/chatbot/page.tsx
+++ b/app/chatbot/page.tsx
@@ -4,17 +4,24 @@ import { useState, useEffect, useRef, useCallback } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import ChatInput from "../utils/component/ui/ChatInput";
import MessageWindow from "../utils/component/ui/MessageWindow";
-import { ChatHistory, ChatSetting, Message , MessageRole } from "@/app/exportType/types";
+import { ChatHistory, ChatSetting, Message, MessageRole } from "@/app/exportType/types";
-export default function Home(){
+export default function Home() {
const [history, setHistory] = useState([])
const [loading, setLoading] = useState(false);
const historyRef = useRef([]); // Create a ref for history
const [settings] = useState({
+<<<<<<< HEAD
temperature:1,
model:"gemini-2.5-pro",
systemInstruction:"you are a ai helper. Your goal is to expand the project idea and interact with the user on any problem or question they have with the project. You are not allow to code the project for them and stray away from your job"
+=======
+ temperature: 1,
+ model: "gemini-2.5-pro",
+ sysTemInstructions: "you are a ai helper. Your goal is to expand the project idea and interact with the user on any problem or question they have with the project. You are not allow to code the project for them and stray away from your job"
+
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
});
const router = useRouter();
const searchParams = useSearchParams();
@@ -24,23 +31,27 @@ export default function Home(){
historyRef.current = history; // Keep the ref updated with the latest history
}, [history]);
- const handleSend = useCallback(async(message:string)=>{
- const newUserMessage:Message = {
- role:"user",
- parts:[{text:message}],
+ const handleSend = useCallback(async (message: string) => {
+ const newUserMessage: Message = {
+ role: "user",
+ parts: [{ text: message }],
};
setHistory(prevHistory => {
const currentHistory = [...prevHistory, newUserMessage];
-
+
const sendApiRequest = async () => {
+<<<<<<< HEAD
setLoading(true);
try{
+=======
+ try {
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
const response = await fetch("/api/chat", {
method: "POST",
headers: {
- "Content-Type": "application/json",
- },
+ "Content-Type": "application/json",
+ },
body: JSON.stringify({
userMessage: message,
history: historyRef.current, // Use the ref for history
@@ -62,8 +73,8 @@ export default function Home(){
};
setHistory(prevHistory => [...prevHistory, aiMessage]);
-
- }
+
+ }
catch (error) {
console.error("Request Failed:", error);
}
@@ -82,7 +93,7 @@ export default function Home(){
if (title && summary) {
const message = `Explain the project titled '${title}' with the summary '${summary}' in detail, and suggest suitable roles for a team working on it.`;
-
+
const newUserMessage: Message = {
role: "user",
parts: [{ text: message }],
@@ -136,6 +147,7 @@ export default function Home(){
return (
+<<<<<<< HEAD
router.push('/Dashboard')}
className="absolute top-4 right-4 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
@@ -144,6 +156,10 @@ export default function Home(){
{}} />
+=======
+
+ { }} />
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
);
}
\ No newline at end of file
diff --git a/app/components/Cards.tsx b/app/components/Cards.tsx
new file mode 100644
index 0000000..322b377
--- /dev/null
+++ b/app/components/Cards.tsx
@@ -0,0 +1,300 @@
+"use client";
+
+import React, { useState } from "react";
+import { motion, useMotionValue, useTransform } from "framer-motion";
+
+// Removed local fallback JSX declaration — use the official React type definitions instead:
+// install @types/react and @types/react-dom so JSX.IntrinsicElements is provided by those packages.
+// 1. Updated ColorWay interface
+interface ColorWay {
+ card: string;
+ text: string;
+ titleColor: string; // Added title color
+}
+
+// 2. Updated COLOR_WAYS array
+const COLOR_WAYS: ColorWay[] = [
+ { card: "#FEEEDF", text: "#173C46", titleColor: "#173C46" },
+ { card: "#FEEEDF", text: "#EA627F", titleColor: "#173C46" }, // Example: Title is dark, text is pink
+ { card: "#DEE5D4", text: "#173C46", titleColor: "#EA627F" },
+ { card: "#DEE5D4", text: "#EA627F", titleColor: "#173C46" },
+ { card: "#B8C0AD", text: "#173C46", titleColor: "#173C46" },
+ { card: "#B8C0AD", text: "#173C46", titleColor: "#EA627F" },
+];
+
+interface CardData {
+ id: number;
+ title: string;
+ summary: string;
+ tracks: string[];
+}
+
+const cardData: CardData[] = [
+ {
+
+ id: 1,
+
+ title: " WEBSITE",
+
+ summary:
+
+ "FFind out what makes GoonMAXXER unique.With this innovative website you will be able to explore various features and functionalities that set GoonMAXXER apart from the rest.",
+
+ tracks: ["Gemini", "Auth0", "VibeCODING", "SmellyMaxxing", "shitposting"],
+
+ },
+
+ {
+
+ id: 2,
+
+ title: "Intro to React",
+
+ summary:
+
+ "Learn the fundamentals of React, including components, state, and props.",
+
+ tracks: ["React", "JS", "Frontend"],
+
+ },
+
+ {
+
+ id: 3,
+
+ title: "State Management",
+
+ summary:
+
+ "Explore complex state solutions with Zustand, Redux, and Context API.",
+
+ tracks: ["React", "Zustand", "State"],
+
+ },
+
+ {
+
+ id: 4,
+
+ title: "Next.js 14",
+
+ summary: "Master the app router, server actions, and data fetching.",
+
+ tracks: ["Next.js", "React", "Fullstack"],
+
+ },
+
+ {
+
+ id: 5,
+
+ title: "UI/UX Principles",
+
+ summary:
+
+ "A complete guide to user-centric design, prototyping, and testing.",
+
+ tracks: ["Design", "UI", "UX"],
+
+ },
+
+ {
+
+ id: 6,
+
+ title: "Node.js Essentials",
+
+ summary:
+
+ "Build scalable, high-performance backend applications with Node.js.",
+
+ tracks: ["Node", "Backend", "JS"],
+
+ },
+
+ {
+
+ id: 7,
+
+ title: "TypeScript",
+
+ summary:
+
+ "Add static typing to your JavaScript projects for robust, large-scale apps.",
+
+ tracks: ["TypeScript", "JS", "DevOps"],
+
+ },
+
+ {
+
+ id: 8,
+
+ title: "Framer Motion",
+
+ summary: "Create production-ready animations for your React applications.",
+
+ tracks: ["React", "Animation", "Framer"],
+
+ },
+
+].reverse();
+
+const SwipeCards: React.FC = () => {
+ const [cards, setCards] = useState(cardData);
+
+ const onSwipe = () => {
+ setCards((prev) => prev.slice(0, prev.length - 1));
+ };
+
+ const handleReset = () => {
+ setCards(cardData);
+ };
+
+ return (
+
+ {cards.length > 0 ? (
+ cards.map((card, index) => {
+ const colorWay = COLOR_WAYS[card.id % COLOR_WAYS.length];
+ return (
+
+ );
+ })
+ ) : (
+ // ... (empty state)
+
+
+ No more cards!
+
+
+ You've swiped through them all.
+
+
+ Reset Deck
+
+
+ )}
+
+ );
+};
+
+interface CardProps {
+ cardData: CardData;
+ colorWay: ColorWay;
+ isFront: boolean;
+ onSwipe: () => void;
+}
+
+const Card: React.FC = ({ cardData, colorWay, isFront, onSwipe }) => {
+ const { title, summary, tracks } = cardData;
+
+ 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 = (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => {
+ if (Math.abs(info.offset.x) > 100) {
+ onSwipe();
+ }
+ };
+
+ return (
+
+ {/* Accept/Reject Badges */}
+
+ Accept
+
+
+ Reject
+
+
+ {/* Card Content */}
+
+ {/* 3. Applied the specific titleColor here */}
+
+ {title}
+
+ {/* This summary
will inherit colorWay.text from the parent */}
+
{summary}
+
+
+
+ {/* This
will also inherit colorWay.text */}
+
+ Tracks
+
+ {tracks.map((track) => (
+
+ {track}
+
+ ))}
+
+
+ );
+
+};
+
+export default SwipeCards;
\ No newline at end of file
diff --git a/app/components/ProtectedNavButton.tsx b/app/components/ProtectedNavButton.tsx
new file mode 100644
index 0000000..5a5c48b
--- /dev/null
+++ b/app/components/ProtectedNavButton.tsx
@@ -0,0 +1,35 @@
+"use client";
+
+import React from "react";
+import { useRouter } from "next/navigation";
+
+export default function ProtectedNavButton({
+ children = "Go to Dashboard",
+ className = "mt-4 inline-block w-fit px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-md shadow-md transition-colors",
+}: {
+ children?: React.ReactNode;
+ className?: string;
+}) {
+ const router = useRouter();
+
+ const handleClick = () => {
+ // Simple client-side auth check.
+ // Assumption: if localStorage has 'token' (or 'auth'), user is signed in.
+ // Adjust key to match your real auth storage (cookie, localStorage key, etc.).
+ const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
+
+ if (token) {
+ // The app route folder is named `Dashboard` (capital D).
+ // Use the same path casing to avoid 404s on Next.js routes.
+ router.push("/Dashboard");
+ } else {
+ router.push("/auth/login");
+ }
+ };
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/exportType/types.ts b/app/exportType/types.ts
index b840e20..605e3ca 100644
--- a/app/exportType/types.ts
+++ b/app/exportType/types.ts
@@ -4,27 +4,28 @@ export type MessagePart = {
text: string;
}
-export interface Message{
+export interface Message {
role: MessageRole;
- parts:MessagePart[];
+ parts: MessagePart[];
}
export type ChatHistory = Message[];
-export interface GenerateConfig{
- temperature : number;
- topP : number;
- responseMimeType : string;
+export interface GenerateConfig {
+ temperature: number;
+ topP: number;
+ responseMimeType: string;
+ maxOutputTokens?: number;
}
-export interface ChatSetting{
- temperature :number;
+export interface ChatSetting {
+ temperature: number;
model: string;
systemInstruction: string;
}
export interface CardData {
- id: number;
- title: string;
- tracks: string[];
- summary: string;
+ id: number;
+ title: string;
+ tracks: string[];
+ summary: string;
}
\ No newline at end of file
diff --git a/app/formfile/FormPage.tsx b/app/formfile/FormPage.tsx
index 8059518..d9b8960 100644
--- a/app/formfile/FormPage.tsx
+++ b/app/formfile/FormPage.tsx
@@ -2,9 +2,9 @@
import React, { useState } from "react";
-import {
- FormData,
- PROFICIENCY_LEVELS
+import {
+ FormData,
+ PROFICIENCY_LEVELS
} from './formTypes'; // Ensure path is correct
interface FormPageProps {
@@ -16,9 +16,9 @@ const FormPage: React.FC = ({ onFormSubmit }) => {
Hackathon: '',
mainTheme: '',
tracksStack: [''],
- students: [{
- studentName: '',
- skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
+ students: [{
+ studentName: '',
+ skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
}],
});
@@ -121,12 +121,12 @@ const FormPage: React.FC = ({ onFormSubmit }) => {
Hackathon Name
- = ({ onFormSubmit }) => {
required
type="text"
placeholder="e.g., Sustainability or AI Ethics"
- name="mainTheme"
+ name="mainTheme"
value={formData.mainTheme}
onChange={handleChange}
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
@@ -161,7 +161,7 @@ const FormPage: React.FC = ({ onFormSubmit }) => {
type="text"
required
placeholder={`Tracks #${index + 1}`}
- name={`tracksStack-${index}`}
+ name={`tracksStack-${index}`}
value={tracks}
onChange={(e) => handleTracksChange(e, index)}
className="flex-grow px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-green-500 focus:border-green-500 transition duration-150"
diff --git a/app/formfile/formTypes.ts b/app/formfile/formTypes.ts
index e3d23c6..a4267eb 100644
--- a/app/formfile/formTypes.ts
+++ b/app/formfile/formTypes.ts
@@ -13,7 +13,7 @@ export interface Student {
// Updated main form interface
export interface FormData {
Hackathon: string;
- mainTheme: string;
+ mainTheme: string;
tracksStack: string[];
students: Student[]; // Array for dynamic students
}
diff --git a/app/formfile/generate-idea.ts b/app/formfile/generate-idea.ts
index c9f1f3f..791b19f 100644
--- a/app/formfile/generate-idea.ts
+++ b/app/formfile/generate-idea.ts
@@ -5,8 +5,8 @@ import type { NextApiRequest, NextApiResponse } from 'next';
// IMPORTANT: The GEMINI_API_KEY should be an environment variable.
const apiKey = process.env.GEMINI_API_KEY;
-if(!apiKey){
- throw new Error("api key not found");
+if (!apiKey) {
+ throw new Error("api key not found");
}
const ai = new GoogleGenerativeAI(apiKey);
@@ -24,7 +24,7 @@ export default async function handler(
// Destructure the data sent from the frontend
let { prompt, settings } = req.body;
-
+
// Basic validation
if (!prompt || typeof prompt !== 'string') {
return res.status(400).json({ error: 'Prompt is required' });
@@ -37,32 +37,32 @@ export default async function handler(
try {
// 1. Call the Gemini API using the correct method signature
-
+
const model = settings?.model || 'gemini-2.5-flash-lite';
const generativeModel = ai.getGenerativeModel({ model });
- // 1. Define the generation configuration object
+ // 1. Define the generation configuration object
const generationConfig = {
temperature: settings?.temperature || 0.9,
// The SDK property name for system instructions is 'systemInstruction'
- systemInstruction: settings?.sysTemInstructions,
+ systemInstruction: settings?.sysTemInstructions,
};
// 2. Call generateContent with the single GenerateContentRequest object.
const result = await generativeModel.generateContent({
// contents must be an array of Content objects
contents: [{
- role: "user",
+ role: "user",
parts: [{ text: prompt }]
- }],
-
+ }],
+
// The fixed property name that resolves the TypeScript error
- generationConfig: generationConfig,
+ generationConfig: generationConfig,
});
// 2. Extract the response text
// The result object now contains a property 'text' at the top level for simple text generation
- const geminiResponseText = result.response.text(); res.status(200).json({ response: geminiResponseText });
+ const geminiResponseText = result.response.text(); res.status(200).json({ response: geminiResponseText });
} catch (error) {
console.error("Gemini API Error:", error);
diff --git a/app/formfile/page.tsx b/app/formfile/page.tsx
index dbfd792..0c2366f 100644
--- a/app/formfile/page.tsx
+++ b/app/formfile/page.tsx
@@ -1,33 +1,46 @@
-// 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, CardData } from "@/app/exportType/types";
+import { ChatSetting } from "../exportType/types";
import { FormData, PROFICIENCY_LEVELS } from './formTypes';
-import SwipeCards from '../cards/page';
-export default function Home() {
- const [showForm, setShowForm] = useState(true);
- const [formData, setFormData] = useState(() => {
- if (typeof window !== 'undefined') {
- const storedFormData = localStorage.getItem('formData');
- if (storedFormData) {
- const parsedData: FormData = JSON.parse(storedFormData);
- return parsedData;
- }
- }
+// --- 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 {
- Hackathon: '',
- mainTheme: '',
- tracksStack: [''],
- students: [{
- studentName: '',
- skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
- }],
+ 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
@@ -35,41 +48,69 @@ export default function Home() {
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() !== "");
+ 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);
+ 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 !== '');
+ 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,
+ ideas.push({
+ id: index + 1,
+ title,
+ tracks,
+ summary,
+ });
});
- });
- console.log("Parsed Cards:", ideas);
- return ideas;
+ 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);
@@ -77,64 +118,82 @@ const parseAiResponse = (markdownString: string): CardData[] => {
generateIdeas(submittedData);
};
- // eslint-disable-next-line react-hooks/preserve-manual-memoization
+ // 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),
+ ...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(', ')})`
+ `${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.");
- 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,
- }),
- });
+ 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 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);
+ 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}`);
+ 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]);
@@ -146,10 +205,33 @@ const parseAiResponse = (markdownString: string): CardData[] => {
setTimeout(() => setShowForm(false), 0);
generateIdeas(parsedData);
localStorage.removeItem('formData');
+=======
+>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
}
- }
- }, [generateIdeas]);
+ 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 (
@@ -157,6 +239,7 @@ const parseAiResponse = (markdownString: string): CardData[] => {
) : (
<>
+<<<<<<< HEAD
{generatedCards.length > 0 ? (
) : (
@@ -165,15 +248,28 @@ const parseAiResponse = (markdownString: string): CardData[] => {
Generated Project Idea 💡
-
Generated Ideas:
-
') }}
- />
- {ideaResponse === "" &&
Submit the form to generate project ideas.
}
+
Generated Ideas:
+
') }}
+ />
+ {ideaResponse === "" &&
Submit the form to generate project ideas.
}
>
)}
+=======
+
+ Generated Project Idea 💡
+
+
+
Generated Ideas:
+
') }}
+ />
+ {ideaResponse === "" &&
Submit the form to generate project ideas.
}
+
+>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
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"
diff --git a/app/globals.css b/app/globals.css
index 89e0fba..63852fc 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,6 +1,35 @@
+<<<<<<< HEAD
+=======
+/* @import "tailwindcss";
+
+:root {
+ --background: #ffffff;
+ --foreground: #171717;
+}
+
+:root {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --font-sans: var(--font-geist-sans);
+ --font-mono: var(--font-geist-mono);
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --background: #0a0a0a;
+ --foreground: #ededed;
+ }
+}
+
+body {
+ background: var(--background);
+ color: var(--foreground);
+ font-family: Arial, Helvetica, sans-serif;
+} */
/* 1. Import BOTH fonts in one go */
@import url('https://fonts.googleapis.com/css2?family=Concert+One&family=Pixelify+Sans:wght@400;700&display=swap');
+>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
@import "tailwindcss";
:root {
@@ -13,13 +42,19 @@
--color-foreground: var(--foreground);
/* 3. Assign fonts to Tailwind's theme */
-
+
+<<<<<<< HEAD
+ /* Tell Tailwind to use the variables already defined in app/layout.tsx */
+ --font-sans: var(--font-sans);
+ --font-header: var(--font-header);
+=======
/* --font-sans is for regular text (Concert One) */
--font-sans: var(--font-concert-one);
-
+
/* We add a new font family for headers (Pixelify Sans) */
/* This also creates a 'font-header' utility class */
--font-header: var(--font-pixelify);
+>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
--font-mono: var(--font-geist-mono);
}
@@ -34,12 +69,17 @@
body {
background: var(--background);
color: var(--foreground);
-
+
/* 4. Body uses --font-sans (Concert One) by default */
font-family: var(--font-sans);
}
/* 5. (Optional but helpful) Apply header font to h-tags by default */
-h1, h2, h3, h4, h5, h6 {
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
font-family: var(--font-header);
}
\ No newline at end of file
diff --git a/app/layout.tsx b/app/layout.tsx
index a396698..a8674db 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,9 +1,8 @@
-// app/layout.tsx
-
import type { Metadata } from "next";
// 1. Import your two new fonts
import { Concert_One, Pixelify_Sans } from "next/font/google";
import "./globals.css";
+// import { Auth0Provider } from "@auth0/nextjs-auth0";
// 2. Set up Concert One as the body/sans font
const concertOne = Concert_One({
diff --git a/app/page.tsx b/app/page.tsx
index de9c3ba..c30bd5e 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,5 +1,7 @@
-"use client";
+import Image from "next/image";
+import Link from "next/link";
+<<<<<<< HEAD
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Image from 'next/image';
@@ -7,8 +9,36 @@ import ProtectedNavButton from "../components/ProtectedNavButton";
import Link from 'next/link';
import { style } from 'framer-motion/client';
+=======
+export default function Home() {
+ return (
+
+
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
+<<<<<<< HEAD
export default function Page() {
+<<<<<<< HEAD
return (
@@ -29,101 +59,370 @@ export default function Page() {
+=======
+ return (
+
+
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
-
-
-
-
-
- (project name)
-
-
- Looking for a starting point or more instructions? Head over to{" "}
-
- Templates
- {" "}
- or the{" "}
-
- Learning
- {" "}
- center.
-
+
+
+
+
+ (project name)
+
+
+ Looking for a starting point or more instructions? Head over to{" "}
+
+ Templates
+ {" "}
+ or the{" "}
+
+ Learning
+ {" "}
+ center.
+
-
-
- Image Placeholder
-
-
-
+ Get Started
+
-
-
-
- Guide:
-
-
+
+
+ Image Placeholder
+
+
+
-
-
-
- First Text Block
-
-
- This is the content for the first text block. You can write anything here.
-
-
-
-
- Image Placeholder
-
-
-
-
-
-
-
- Image Placeholder
-
-
+
+
+
+ Guide:
+
+
-
-
-
- Second Text Block
-
-
- This is the content for the second text block. You can write anything here.
-
-
-
-
+
+
+
+ First Text Block
+
+
+ This is the content for the first text block. You can write anything here.
+
+
+
+
+ Image Placeholder
+
+
+
-
-
-
- Third Text Block
-
-
- This is the content for the third text block. You can write anything here.
-
-
-
-
- Image Placeholder
-
-
-
-
-
-
- );
+
+
+
+ Image Placeholder
+
+
+
+
+
+
+ Second Text Block
+
+
+ This is the content for the second text block. You can write anything here.
+
+
+
+
+
+
+
+
+ Third Text Block
+
+
+ This is the content for the third text block. You can write anything here.
+
+
+
+
+ Image Placeholder
+
+
+
+
+
+
+ );
+=======
+
+
+
+
+ Welcome! This is HackSpark
+
+
+ Got a hackathon coming up? Tell us your track, your team’s skills, what you’re passionate about, and more — and we’ll provide you with the perfect project idea!{" "}
+
+
+
+ Get Started
+
+
+
+
+
+ Image Placeholder
+
+
+
+
+
+ {/*
*/}
+
+ {/* */}
+
+ Guide:
+
+ {/* */}
+
+
+
+
+ First Text Block
+
+
+ This is the content for the first text block. You can write anything here.
+
+
+
+
+ Image Placeholder
+
+
+
+
+
+
+
+ Image Placeholder
+
+
+
+
+
+ Second Text Block
+
+
+ This is the content for the second text block. You can write anything here.
+
+
+
+
+
+
+
+
+ Third Text Block
+
+
+ This is the content for the third text block. You can write anything here.
+
+
+
+
+ Image Placeholder
+
+
+
+
+
+
+
+ );
+>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
}
+
+
+// {/* */}
+
+
+// "use client";
+
+// import React, { use, useState } from "react";
+// import { useRouter } from "next/navigation";
+
+// export default function Dashboard() {
+// const router = useRouter();
+// const[query, setQuery] = useState("");
+// // const [projects, setProjects] = useState( [
+// // { id: 1, name: "Alpha Project", createdAt: new Date("2025-01-01")},
+// // { id: 2, name: "Beta Board", createdAt: new Date("2025-02-15")},
+// // { id: 3, name: "Gamma Task", createdAt: new Date("2025-03-10")}
+// // ]);
+// // const [newProjectName, setNewProjectName] = useState("");
+// // const filtered = projects.filter( (p) => p.name.toLowerCase().includes(query.toLowerCase()) );
+// // const handleCreate = () => {
+// // if(!newProjectName.trim()) return;
+// // const newProject = {
+// // id: projects.length+1, name: newProjectName, createdAt: new Date(),
+// // };
+// // };
+// const projects = [
+// {name: "Alpha Project", createdAt: "2025-01-01"},
+// {name: "Beta Board", createdAt: "2025-02-15"},
+// {name: "Gamma Tasl", createdAt: "2025-03-10"},
+// ]
+// const filtered = projects.filter(
+// (p) => p.name.toLowerCase().includes(query.toLowerCase())
+// );
+
+// return (
+//
+//
+
+//
+//
+// Project Names
+//
+
+//
+//
+// {filtered.map((project, index) => (
+//
+// {project.name}
+//
+// {/* {project.createdAt.toLocaleDateString()} */}
+// Created: {project.createdAt}
+//
+//
+// ))}
+
+// {filtered.length === 0 && (
+// No results found
+// )}
+//
+//
+//
+//
+// );
+// }
\ No newline at end of file
diff --git a/app/utils/component/ui/ChatInput.tsx b/app/utils/component/ui/ChatInput.tsx
index 53c5bf8..e7d5cb2 100644
--- a/app/utils/component/ui/ChatInput.tsx
+++ b/app/utils/component/ui/ChatInput.tsx
@@ -17,8 +17,8 @@ export default function ChatInput({ onSend, onOpenSettings }: ChatInputProps) {
const handleSend = () => {
if (message.trim()) {
- onSend(message.trim());
- setMessage("");
+ onSend(message.trim());
+ setMessage("");
}
};
@@ -34,62 +34,61 @@ export default function ChatInput({ onSend, onOpenSettings }: ChatInputProps) {
return (
-
-
-
-
-
- {message && (
-
-
-
- )}
-
-
-
-
-
-
-
-
-
+
+
+ {message && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
-
-
-
+ onClick={handleSend}
+ disabled={!message.trim()}
+ aria-label="Send message"
+ >
+
+
+
);
diff --git a/app/utils/component/ui/MessageWindow.tsx b/app/utils/component/ui/MessageWindow.tsx
index d59e721..b0083d3 100644
--- a/app/utils/component/ui/MessageWindow.tsx
+++ b/app/utils/component/ui/MessageWindow.tsx
@@ -1,8 +1,9 @@
"use client";
import { useRef, useEffect } from "react";
import { ChatHistory } from "@/app/exportType/types";
-import {User, Bot} from "lucide-react"
+import { User, Bot } from "lucide-react"
+<<<<<<< HEAD
interface MessageWindowProps{
history :ChatHistory;
isLoading: boolean;
@@ -10,22 +11,30 @@ interface MessageWindowProps{
export default function MessageWindow({history, isLoading}:MessageWindowProps){
const messageEndRef = useRef(null);
+=======
+interface MessageWindowProps {
+ history: ChatHistory
+}
- useEffect(() =>{
- messageEndRef.current?.scrollIntoView({behavior:"smooth"});
+export default function MessageWindow({ history }: MessageWindowProps) {
+ const messageEndRef = useRef(null);
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
+
+ useEffect(() => {
+ messageEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [history]);
- return(
+ return (
- {history.map((msg,index)=>{
+ {history.map((msg, index) => {
const isUser = msg.role === "user"
return (
-
- {!isUser &&(
+
+ {!isUser && (
@@ -42,14 +51,15 @@ export default function MessageWindow({history, isLoading}:MessageWindowProps){
{part.text} ))}
- {isUser && (
-
+<<<<<<< HEAD
);
})}
@@ -69,7 +79,14 @@ export default function MessageWindow({history, isLoading}:MessageWindowProps){
)}
{/* Invisible element to help scroll to bottom */}
+=======
+ );
+ })}
+
+ {/* Invisible element to help scroll to bottom */}
+
+
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
-
);
}
\ No newline at end of file
diff --git a/app/utils/geminiHelper.ts b/app/utils/geminiHelper.ts
index 3a78f30..741f563 100644
--- a/app/utils/geminiHelper.ts
+++ b/app/utils/geminiHelper.ts
@@ -1,15 +1,16 @@
import { GoogleGenerativeAI } from "@google/generative-ai";
-import { ChatHistory, GenerateConfig,ChatSetting } from "../exportType/types";
+import { ChatHistory, GenerateConfig, ChatSetting } from "../exportType/types";
const apiKey = process.env.GEMINI_API_KEY;
-if(!apiKey){
+if (!apiKey) {
throw new Error("api key not found");
}
const genAI = new GoogleGenerativeAI(apiKey);
export async function chatToGemini(
+<<<<<<< HEAD
userMessage:string ,
history:ChatHistory,
settings:ChatSetting
@@ -25,18 +26,35 @@ export async function chatToGemini(
responseMimeType: "text/plain",
maxOutputTokens: 1900, // Increased to allow for longer responses
}
+=======
+ userMessage: string,
+ history: ChatHistory,
+ settings: ChatSetting
+): Promise
{
+ const model = genAI.getGenerativeModel({
+ model: settings.model || "gemini-2.5-flash",
+ systemInstruction: settings.sysTemInstructions || "you are going to create a project idea, explain it in summery first before going to detail",
+ });
+>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
- const chatSession = model.startChat({
- generationConfig,
- history
- })
+ const generationConfig: GenerateConfig = {
+ temperature: settings.temperature || 1,
+ topP: 0.9,
+ responseMimeType: "text/plain",
+ maxOutputTokens: 1900, // Increased to allow for longer responses
+ }
- try {
- const result = await chatSession.sendMessage(userMessage);
- return result.response.text();
- }
- catch(error){
- console.error(error)
- throw error
- }
- }
\ No newline at end of file
+ const chatSession = model.startChat({
+ generationConfig,
+ history
+ })
+
+ try {
+ const result = await chatSession.sendMessage(userMessage);
+ return result.response.text();
+ }
+ catch (error) {
+ console.error(error)
+ throw error
+ }
+}
\ No newline at end of file
diff --git a/components/ProtectedNavButton.tsx b/components/ProtectedNavButton.tsx
deleted file mode 100644
index 34fa0e7..0000000
--- a/components/ProtectedNavButton.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-"use client";
-
-import React from "react";
-import { useRouter } from "next/navigation";
-
-export default function ProtectedNavButton({
- children = "Go to Dashboard",
- className = "mt-4 inline-block w-fit px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-md shadow-md transition-colors",
-}: {
- children?: React.ReactNode;
- className?: string;
-}) {
- const router = useRouter();
-
- const handleClick = () => {
- // Simple client-side auth check.
- // Assumption: if localStorage has 'token' (or 'auth'), user is signed in.
- // Adjust key to match your real auth storage (cookie, localStorage key, etc.).
- const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
-
- if (token) {
- router.push("/dashboard");
- } else {
- router.push("/auth/login");
- }
- };
-
- return (
-
- {children}
-
- );
-}