diff --git a/.gitignore b/.gitignore index e62a663..1d8ad5f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,6 @@ venv/ .env applyai-475622-6ebc0281eea9.json -# Learning files -learning/ \ No newline at end of file +# Mics +learning/ +cli.txt \ No newline at end of file diff --git a/client/app/chat/page.tsx b/client/app/chat/page.tsx new file mode 100644 index 0000000..57ac8f2 --- /dev/null +++ b/client/app/chat/page.tsx @@ -0,0 +1,21 @@ +import Chat from "@/components/Chat"; +import Link from "next/link"; + +export default function ChatPage() { + return ( +
+ {/* Navigation Header */} +
+ + ← Back + +

AI Career Chat

+
+ + +
+ ); +} \ No newline at end of file diff --git a/client/app/globals.css b/client/app/globals.css index ab19ef9..4701b22 100644 --- a/client/app/globals.css +++ b/client/app/globals.css @@ -1,2 +1,31 @@ @import "tailwindcss"; -@plugin "@tailwindcss/typography"; \ No newline at end of file +@plugin "@tailwindcss/typography"; + +@theme { +/* MAIN BRAND COLORS */ + --color-primary: #E55934; /* High-Vis Orange (The Hero Color) */ + --color-secondary: #8C8787; /* Brand Gray (Supporting Elements) */ + + /* UI COLORS */ + --color-background: #0a0a0a; /* Very Dark Gray (Not pure black, softer) */ + --color-surface: #1a1a1a; /* Lighter Dark Gray (Cards/Inputs) */ + --color-text-main: #FFFFFF; /* Main Text */ + --color-text-muted: #a3a3a3; /* Secondary Text */ +} + +/* Apply the background color globally */ +body { + background-color: var(--color-background); + color: var(--color-text-main); + font-family: Arial, Helvetica, sans-serif; +} + +/* Custom Utilities */ +@utility animate-in { + animation: fade-in 0.5s ease-out forwards; +} + +@keyframes fade-in { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} \ No newline at end of file diff --git a/client/app/layout.tsx b/client/app/layout.tsx index 9c85130..8353817 100644 --- a/client/app/layout.tsx +++ b/client/app/layout.tsx @@ -1,22 +1,15 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +// import { Geist, Geist_Mono } from "next/font/google"; +import { Inter } from "next/font/google"; import "./globals.css"; import { AuthProvider } from "@/context/AuthContext"; import Navbar from "@/components/Navbar"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); +const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "ApplyAI - Job Assistant", + description: "AI-powered resume tailoring and career coaching", }; export default function RootLayout({ @@ -26,13 +19,10 @@ export default function RootLayout({ }>) { return ( - + -
+
{children}
diff --git a/client/app/page.tsx b/client/app/page.tsx index 4e64464..1d3d99d 100644 --- a/client/app/page.tsx +++ b/client/app/page.tsx @@ -1,10 +1,50 @@ -import Chat from "@/components/Chat"; +import Link from "next/link"; export default function Home() { return ( -
-

ApplyAI

- +
+ +
+ {/* The Title - Now using Text-Main or Primary explicitly */} +

+ ApplyAI +

+

+ Your intelligent career companion. Tailor resumes and practice interviews in seconds. +

+
+ + {/* NAVIGATION CARDS */} +
+ + {/* Link 1: Chat */} + +
💬
+

+ AI Career Chat +

+

+ Chat with an expert agent about your career goals and interview prep. +

+ + + {/* Link 2: Resume */} + +
📄
+

+ Tailor Resume +

+

+ Instant resume rewriting based on job descriptions. +

+ +
); -} +} \ No newline at end of file diff --git a/client/app/resume/page.tsx b/client/app/resume/page.tsx new file mode 100644 index 0000000..04a15bb --- /dev/null +++ b/client/app/resume/page.tsx @@ -0,0 +1,21 @@ +import ResumeBuilder from "@/components/ResumeBuilder"; +import Link from "next/link"; + +export default function ResumePage() { + return ( +
+ {/* Navigation Header */} +
+ + ← Back + +

Resume Tailor

+
+ + +
+ ); +} \ No newline at end of file diff --git a/client/components/Chat.tsx b/client/components/Chat.tsx index de367f2..66a90d8 100644 --- a/client/components/Chat.tsx +++ b/client/components/Chat.tsx @@ -1,123 +1,105 @@ "use client"; import { useState } from "react"; -import type { MouseEvent } from "react"; -import ResumeDisplay from "./ResumeDisplay" +import ReactMarkdown from "react-markdown"; -// The URL for the deployed backend. -const API_URL = process.env.NEXT_PUBLIC_API_URL; - -export default function Chat() { - // State for the user's input - const [resume, setResume] = useState(""); - const [jobDescription, setJobDescription] = useState(""); +interface Message { + role: "user" | "ai"; + content: string; +} - // State for the API response - const [tailoredResume, setTailoredResume] = useState(""); +export default function Chat(){ + const [input, setInput] = useState(""); + const [messages, setMessages] = useState([]) const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); + const handleSend = async () => { + if (!input.trim()) return; - - const handleSubmit = async (e : MouseEvent) => { - e.preventDefault(); + const userMessage: Message = { role: "user", content: input }; + setMessages((prev) => [...prev, userMessage]); + setInput(""); setIsLoading(true); - setError(null); - setTailoredResume(""); // Clear previous results - - // Use FormData because FastAPI endpoint expects Form() - const formData = new FormData(); - formData.append("base_resume", resume); - formData.append("job_description", jobDescription); - try{ - // Make the API call to /resumes endpoint - const response = await fetch(`${API_URL}/resumes`, { + try { + const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/chat`, { method: "POST", - body: formData, + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ message: userMessage.content }), }); - if (!response.ok) { - // Handle HTTP errors (e.g., 500 from the server) - throw new Error(`API Error: ${response.status} ${response.statusText}`); - } - - const data = await response.json(); - - // Update state with the AI's response - setTailoredResume(data.tailored_resume); - } catch (err){ - console.error("Fetch error:", err); - if (err instanceof Error) { - setError(err.message); - } else { - setError("An unknown error occurred."); - } + if (!res.ok) throw new Error("Failed to fetch response"); + + const data = await res.json(); + const aiMessage: Message = { role: "ai", content: data.reply || data.response }; + setMessages((prev) => [...prev, aiMessage]); + } catch (error) { + console.error(error); + setMessages((prev) => [ + ...prev, + { role: "ai", content: "Sorry, I encountered an error. Please try again." }, + ]); } finally { - // Whether it worked or failed, we're done loading setIsLoading(false); - }; - + } }; - return ( -
- {/* Resume Text Area */} -
- -