🚀 Online Job Portal – Project Overview



A platform where job seekers can create profiles, upload resumes, and apply for jobs, while employers/recruiters can post job listings, manage applications, and shortlist candidates.


 Tech Stack

  • Frontend: Next.js (React-based framework), ShadCN (UI components), TailwindCSS (styling), Redux Toolkit (state management)

  • Backend & Database: Appwrite (auth, database, storage, serverless functions)

  • Hosting/Deployment: Vercel (frontend) + Appwrite Cloud/Self-hosted


 For Job Seekers:

  • Signup/Login with Appwrite Auth

  • Create & update profile (resume, skills, experience)

  • Search & filter jobs (by role, location, salary, company)

  • Apply for jobs (store in Appwrite DB)

  • Track application status

 For Employers:

  • Post new jobs (title, description, salary, requirements, location)

  • Manage job listings

  • View applicants & shortlist candidates

 General Features:

  • Modern UI with ShadCN & Tailwind

  • State management with Redux Toolkit

  • Serverless functions for application workflows

  • Notifications (optional: email via Appwrite functions)

  • Role-based access (job seeker vs employer)


 Key Integrations

  1. Authentication: Appwrite (OAuth or email/password)

  2. Database: Appwrite collections (Users, Jobs, Applications)

  3. Storage: Appwrite file storage for resumes

  4. UI: ShadCN components (cards, forms, modals, tables)

  5. State: Redux Toolkit slices for user, jobs, applications


📌 Header Component

import React from "react"; import Link from "next/link"; import { Button } from "../ui/button"; import Navlinks from "./Navlinks"; import { RxHamburgerMenu } from "react-icons/rx"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; const Header = () => { return ( <header className="bg-[#2a1b3d] px-4 sm:px-10 py-3 sm:py-5 flex justify-between items-center"> {/* Logo */} <div className="logo"> <Link href={"/"}> <h1 className="text-xl sm:text-3xl font-semibold text-white"> Online Job Portal </h1> </Link> </div> {/* Navigation Links */} <Navlinks /> {/* Right Section */} <div className="flex items-center gap-4"> {/* Login / Signup Button */} <Button className="border-none bg-[#D83F87] hover:bg-[#f54698] text-white"> Sign Up </Button> {/* Example Avatar */} <Avatar className="cursor-pointer hidden"> <AvatarImage src="" alt="User" /> <AvatarFallback>U</AvatarFallback> </Avatar> {/* Hamburger Menu for Mobile */} <RxHamburgerMenu color="white" size={32} className="lg:hidden cursor-pointer" /> </div> </header> ); }; export default Header;

 Hero Section Component

import React from "react"; const Herosection = () => { return ( <section className="relative flex flex-col justify-center items-center w-full h-[450px] sm:h-[350px] p-5 md:p-10"> {/* Background Image with Overlay */} <div className="absolute inset-0 -z-10"> <img src="https://images.unsplash.com/photo-1516534775068-ba3e7458af70?w=1200&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8OHx8b25saW5lJTIwam9ifGVufDB8fDB8fHww" alt="Hero Background" className="w-full h-full object-cover" /> <div className="absolute inset-0 bg-[#190572ad]" /> </div> {/* Hero Content */} <div className="z-10 max-w-3xl text-center"> <h1 className="text-white text-2xl md:text-3xl lg:text-4xl font-bold leading-snug"> “Connecting Employers with Top Talent Globally.” </h1> <h2 className="text-white text-lg md:text-2xl lg:text-3xl mt-3 leading-snug"> Join millions of job seekers finding new opportunities every day. </h2> {/* Searchbox Placeholder */} {/* <div className="my-5"> <Searchbox /> </div> */} </div> {/* Chatbot Floating Button */} <div className="fixed right-5 bottom-10 md:top-56 z-30 flex flex-col items-end"> {/* Example chatbot icon (replace with your actual asset) */} <img src="./Reddit.png" alt="chatbot" className="w-12 h-12 cursor-pointer hover:scale-110 transition-transform" /> </div> </section> ); }; export default Herosection;

 Job Section Component

import React from "react"; import Jobcard from "./Jobcard"; import Link from "next/link"; const Jobsection = () => { return ( <section className="bg-[#2E2835] w-full h-auto px-2 py-5 sm:p-10"> <h1 className="text-xl sm:text-3xl uppercase font-semibold text-center text-white p-10"> Recent Jobs </h1> <div className="job-container flex flex-wrap justify-center gap-5"> {/* Example Job Cards (Replace with dynamic jobs later) */} <Link href="/jobs/frontend-developer_123"> <Jobcard data={{ title: "Frontend Developer", company: "Tech Corp", location: "Remote", description: "Work on modern web applications with React & Next.js.", }} /> </Link> <Link href="/jobs/backend-developer_456"> <Jobcard data={{ title: "Backend Developer", company: "CodeWorks", location: "Kathmandu, Nepal", description: "Build scalable backend services with Node.js and Django.", }} /> </Link> <Link href="/jobs/ui-ux-designer_789"> <Jobcard data={{ title: "UI/UX Designer", company: "Design Studio", location: "Hybrid", description: "Create intuitive designs and user experiences.", }} /> </Link> </div> </section> ); }; export default Jobsection;

 Searchbox Component

import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; const Searchbox = () => { return ( <div className="search flex flex-col sm:flex-row w-full max-w-4xl mx-auto border-2 border-white rounded-lg overflow-hidden"> {/* Job Title Input */} <Input type="text" placeholder="Search your Job title" className="text-white text-lg border-none outline-none flex-1 bg-transparent placeholder:text-white px-4 py-3" /> {/* Location Selector */} <Select> <SelectTrigger className="w-full sm:w-[250px] text-white text-lg border-none bg-pink-600 hover:bg-pink-700 transition-colors"> <SelectValue placeholder="Select your location" /> </SelectTrigger> <SelectContent className="text-lg"> <SelectItem value="kathmandu">Kathmandu</SelectItem> <SelectItem value="pokhara">Pokhara</SelectItem> <SelectItem value="lalitpur">Lalitpur</SelectItem> <SelectItem value="bhaktapur">Bhaktapur</SelectItem> <SelectItem value="remote">Remote</SelectItem> </SelectContent> </Select> {/* Search Button */} <Button className="w-full sm:w-[200px] bg-[#D83F87] hover:bg-[#f54698] text-white text-lg font-medium transition-colors"> Search </Button> </div> ); }; export default Searchbox;

 Navigation Links Component

import React from "react"; import { Button } from "../ui/button"; import Link from "next/link"; const Navlinks = () => { const Linksbtn = [ { name: "about", link: "/" }, { name: "skill certification", link: "/" }, { name: "find job", link: "/" }, { name: "post job", link: "/" }, { name: "contact us", link: "/" }, ]; return ( <nav className="text-white flex flex-col lg:flex-row lg:items-center
gap-5 lg:gap-8 bg-[#af8dff20] lg:bg-transparent backdrop-blur-md px-10 py-8 lg:p-0
rounded-lg lg:rounded-none fixed lg:relative top-0 right-0 w-[250px] lg:w-auto h-full lg:h-auto z-50 lg:z-auto transition-all"> {Linksbtn.map((data) => ( <Link href={data.link} key={data.name}> <Button variant="link" className="text-white text-lg lg:text-base capitalize hover:text-pink-500
transition-colors" > {data.name} </Button> </Link> ))} </nav> ); }; export default Navlinks;



Footer Component

import React from "react"; import Link from "next/link"; import { FaFacebookF, FaTwitter, FaLinkedinIn } from "react-icons/fa"; const Footer = () => { return ( <footer className="bg-[#2a1b3d] text-white py-10 px-6 mt-10"> <div className="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-3 gap-8"> {/* About */} <div> <h2 className="text-xl font-semibold mb-3">Online Job Portal</h2> <p className="text-sm text-gray-300"> Helping job seekers and employers connect with ease. </p> </div> {/* Quick Links */} <div> <h2 className="text-lg font-semibold mb-3">Quick Links</h2> <ul className="space-y-2 text-sm"> <li> <Link href="/" className="hover:text-pink-400">Home</Link> </li> <li> <Link href="/jobs" className="hover:text-pink-400">Find Jobs</Link> </li> <li> <Link href="/post-job" className="hover:text-pink-400">Post a Job</Link> </li> <li> <Link href="/contact" className="hover:text-pink-400">Contact Us</Link> </li> </ul> </div> {/* Social Media */} <div> <h2 className="text-lg font-semibold mb-3">Follow Us</h2> <div className="flex gap-4"> <Link href="https://facebook.com" target="_blank" className="hover:text-pink-400"> <FaFacebookF size={20} /> </Link> <Link href="https://twitter.com" target="_blank" className="hover:text-pink-400"> <FaTwitter size={20} /> </Link> <Link href="https://linkedin.com" target="_blank" className="hover:text-pink-400"> <FaLinkedinIn size={20} /> </Link> </div> </div> </div> <div className="text-center text-gray-400 text-sm mt-8"> © {new Date().getFullYear()} Online Job Portal. All rights reserved. </div> </footer> ); }; export default Footer;


Chatbot Component

import React, { useState } from "react"; import { BsChatDotsFill } from "react-icons/bs"; const Chatbot = () => { const [isOpen, setIsOpen] = useState(false); const [messages, setMessages] = useState<{ sender: string; text: string }[]>([]); const [input, setInput] = useState(""); const toggleChat = () => setIsOpen(!isOpen); const handleSend = () => { if (input.trim() === "") return; setMessages([...messages, { sender: "user", text: input }]); setInput(""); // Fake bot reply setTimeout(() => { setMessages((prev) => [...prev, { sender: "bot", text: "Hello! How can I help you today?" }]); }, 1000); }; return ( <div className="fixed bottom-6 right-6"> {/* Chat Icon */} <button onClick={toggleChat} className="bg-[#D83F87] p-4 rounded-full shadow-lg text-white hover:bg-[#f54698] transition" > <BsChatDotsFill size={24} /> </button> {/* Chat Window */} {isOpen && ( <div className="bg-white w-80 h-96 shadow-xl rounded-xl flex flex-col mt-3"> {/* Header */} <div className="bg-[#2a1b3d] text-white px-4 py-3 rounded-t-xl"> <h3 className="font-semibold">Job Portal Assistant</h3> </div> {/* Messages */} <div className="flex-1 p-3 overflow-y-auto text-sm space-y-2"> {messages.map((msg, i) => ( <div key={i} className={`p-2 rounded-lg ${ msg.sender === "user" ? "bg-[#D83F87] text-white self-end" : "bg-gray-200 text-gray-800 self-start" }`} > {msg.text} </div> ))} </div> {/* Input */} <div className="p-3 border-t flex gap-2"> <input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleSend()} placeholder="Type a message..." className="flex-1 border rounded-lg px-3 py-2 text-sm focus:outline-none" /> <button onClick={handleSend} className="bg-[#D83F87] hover:bg-[#f54698] text-white px-3 rounded-lg" > Send </button> </div> </div> )} </div> ); }; export default Chatbot;

Category Signup Component

import React from "react";
import { GiCrossMark } from "react-icons/gi"; const Categorysignup = () => { return ( <div className="fixed inset-0 backdrop-blur-md z-50 flex justify-center items-center p-5"> {/* Form Container */} <div className="w-full sm:w-[500px] bg-[#af8dff65] p-5 sm:p-10 rounded-lg backdrop-blur-md relative"> {/* Close Button */} <GiCrossMark className="text-3xl text-white cursor-pointer hover:text-red-500 absolute right-4 top-4" /> <h2 className="text-center font-bold text-white text-3xl mb-5"> Select Signup Category </h2> {/* Jobseeker Option */} <div className="w-full sm:w-[80%] h-[100px] rounded-lg px-4 py-4 bg-white my-6 mx-auto flex items-center justify-center text-center text-xl text-pink-500 cursor-pointer hover:bg-pink-50 transition-colors"> <div> <p className="font-semibold">Jobseeker</p> <p className="text-sm mt-1">Create a free account to apply!</p> </div> </div> {/* Job Provider Option */} <div className="w-full sm:w-[80%] h-[100px] rounded-lg px-4 py-4 bg-white my-6 mx-auto flex items-center justify-center text-center text-xl text-pink-500 cursor-pointer hover:bg-pink-50 transition-colors"> <div> <p className="font-semibold">Job Provider</p> <p className="text-sm mt-1">Create a free account to post vacancies!</p> </div> </div> </div> </div> ); }; export default Categorysignup;

Login Form

import React, { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; const Login = () => { const [form, setForm] = useState({ email: "", password: "" }); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { setForm({ ...form, [e.target.name]: e.target.value }); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); console.log("Login Data:", form); }; return ( <div className="max-w-md mx-auto mt-16 bg-white shadow-lg rounded-xl p-6"> <h2 className="text-2xl font-semibold mb-4 text-center text-gray-900">Welcome Back</h2> <form onSubmit={handleSubmit} className="space-y-4"> <Input type="email" name="email" placeholder="Email Address" value={form.email} onChange={handleChange} required /> <Input type="password" name="password" placeholder="Password" value={form.password} onChange={handleChange} required /> <Button type="submit" className="w-full bg-[#D83F87] hover:bg-[#f54698] text-white"> Login </Button> </form> </div> ); }; export default Login;


Forget Password


import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import { Button } from "@/components/ui/button"
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { GiCrossMark } from "react-icons/gi"
import { useState } from "react"
import { toast } from "sonner"

// Schema for form validation
const formSchema = z.object({
  email: z.string().email({ message: "Invalid email format." }),
})

// Props for handling close action
interface ForgotPasswordProps {
  onClose: () => void
}

const ForgotPassword = ({ onClose }: ForgotPasswordProps) => {
  const [isLoading, setIsLoading] = useState(false)

  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      email: "",
    },
  })

  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    setIsLoading(true)

    // Simulate API call
    setTimeout(() => {
      toast.success("✅ Check your email for the reset link.")
      setIsLoading(false)
      form.reset()
    }, 1500)
  }

  return (
    <div className="fixed inset-0 backdrop-blur-md flex justify-center items-center z-50">
      <div className="w-full sm:w-[500px] bg-purple-200/50 px-8 py-10 rounded-lg relative backdrop-blur-md">
        {/* Close Icon */}
        <GiCrossMark
          className="absolute right-4 top-4 text-3xl text-white cursor-pointer hover:text-red-500"
          onClick={onClose}
        />

        <h2 className="text-center text-3xl font-bold text-white mb-6">
          Forgot Password
        </h2>

        <Form {...form}>
          <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
            <FormField
              control={form.control}
              name="email"
              render={({ field }) => (
                <FormItem>
                  <FormLabel className="text-white text-lg">Email</FormLabel>
                  <FormControl>
                    <Input
                      placeholder="Enter your email"
                      {...field}
                      className="placeholder:text-white text-white p-4 text-sm"
                    />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />

            <Button
              type="submit"
              disabled={isLoading}
              className="w-full bg-pink-400 hover:bg-pink-600 text-xl"
            >
              {isLoading ? "Submitting..." : "Submit"}
            </Button>
          </form>
        </Form>

        <div className="pt-4 text-center">
          <p className="text-white text-lg mb-1">Remember your password?</p>
          <Button
            variant="link"
            onClick={onClose}
            className="text-pink-500 text-lg p-0"
          >
            Go to Login
          </Button>
        </div>
      </div>
    </div>
  )
}

export default ForgotPassword


Job Card 


import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import Image from "next/image";
import { Button } from "../ui/button";

const Jobcard = () => {
  return (
    <Card className="w-full sm:w-[300px] h-[320px] p-0 overflow-hidden">
      {/* Card Header with Image */}
      <CardHeader className="p-0 w-full h-[180px] overflow-hidden relative">
        <Image
          src="/placeholder-job-image.jpg" // Placeholder image
          alt="Job Image"
          width={300}
          height={180}
          className="w-full h-full object-cover"
        />
        <Button className="bg-[#d83f8696] hover:bg-[#D83F87] hover:text-white absolute top-2 left-2">
          Full-time
        </Button>
      </CardHeader>

      {/* Card Content */}
      <CardContent className="py-2">
        <CardTitle className="text-xl capitalize mb-2">
          Frontend Developer
        </CardTitle>
        <p>Category: Web Development</p>
        <p>Salary: $500 - $1000</p>
      </CardContent>

      {/* Card Footer */}
      <CardFooter className="flex justify-center my-1 w-full">
        <Button
          variant="outline"
          className="bg-[#d83f8617] border-2 text-sm text-[#D83F87] border-[#D83F87] hover:bg-[#D83F87] hover:text-white w-full rounded-2xl"
        >
          See Description
        </Button>
      </CardFooter>
    </Card>
  );
};

export default Jobcard;


Job Description


import Image from "next/image";
import React from "react";
import { Button } from "../ui/button";

const Jobdescription = ({ classNames }: any) => {
  return (
    <div className={`jobdescription p-10 ${classNames}`}>
      {/* Job Image */}
      <div className="image w-full h-[300px]">
        <Image
          src="/demo.jpg" // Placeholder image
          alt="Job Description"
          width={1000}
          height={300}
          className="w-full h-full object-cover object-center"
        />
      </div>

      {/* Job Title and Metadata */}
      <div className="job-title sm:flex justify-between py-3">
        <h1 className="text-3xl font-bold">Frontend Developer</h1>
        <h2>View 234 | Apply before: Two weeks from now</h2>
      </div>

      {/* Job Category and Total Vacancy */}
      <div className="text-xl font-semibold">
        <p>
          <strong>Category:</strong> Web Development
        </p>
        <p>
          <strong>Total Vacancy:</strong> 3
        </p>
      </div>

      {/* Job Description */}
      <div className="job-description mt-4">
        <h2 className="text-2xl font-bold">Job Description</h2>
        <div className="mt-2 text-lg">
          This is a demo job description. Here you can describe the job roles,
          responsibilities, and requirements in detail.
        </div>
      </div>

      {/* Apply Button */}
      <div className="py-4">
        <Button className="border-none sm:w-[200px] bg-[#D83F87] hover:bg-[#f54698]">
          Apply
        </Button>
      </div>

      {/* Application Form Modal Placeholder */}
      <div className="hidden">
        {/* Modal UI can be added here */}
      </div>
    </div>
  );
};

export default Jobdescription;


Job Provider Signup


import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { GiCrossMark } from "react-icons/gi";
import { useState } from "react";

const formSchema = z.object({
  fullname: z.string().min(2, {
    message: "Full Name must be at least 2 characters.",
  }),
  email: z.string().email({ message: "Invalid email address" }),
  password: z.string().min(8, {
    message: "Password must be at least 8 characters.",
  }),
});

const Jobprovideraccount = () => {
  const [isLoading] = useState(false);

  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      fullname: "",
      email: "",
      password: "",
    },
  });

  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    // Add your logic here after cleaning
  };

  return (
    <div className="main w-full fixed left-0 right-0 top-0 bottom-0 backdrop-blur-md z-50">
      <div className="formcontainer w-full sm:w-[500px] bg-[#af8dff65] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-50 px-5 sm:px-10 py-10 rounded-lg backdrop-blur-md">
        <h2 className="text-center font-bold text-white text-3xl mb-5">
          Create your free Job Provider Account
        </h2>
        <GiCrossMark
          className="text-3xl text-white cursor-pointer hover:text-red-500 absolute right-4 top-4"
        />
        <Form {...form}>
          <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
            {/* Full Name */}
            <FormField
              control={form.control}
              name="fullname"
              render={({ field }) => (
                <FormItem>
                  <FormLabel className="text-white text-lg">Full Name</FormLabel>
                  <FormControl>
                    <Input
                      placeholder="Enter your Full Name"
                      {...field}
                      className="placeholder:text-white text-white text-sm p-4"
                    />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            {/* Email */}
            <FormField
              control={form.control}
              name="email"
              render={({ field }) => (
                <FormItem>
                  <FormLabel className="text-white text-lg">Email</FormLabel>
                  <FormControl>
                    <Input
                      placeholder="Enter your Email"
                      {...field}
                      className="placeholder:text-white text-white text-sm p-4"
                    />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            {/* Password */}
            <FormField
              control={form.control}
              name="password"
              render={({ field }) => (
                <FormItem>
                  <FormLabel className="text-white text-lg">Password</FormLabel>
                  <FormControl>
                    <Input
                      type="password"
                      placeholder="Enter your Password"
                      {...field}
                      className="placeholder:text-white text-white text-sm p-4"
                    />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
            {/* Submit Button */}
            <div className="btn pt-2">
              <Button
                type="submit"
                className="w-full bg-pink-400 hover:bg-pink-600 text-xl"
                disabled={isLoading}
              >
                {isLoading ? "Creating account..." : "Submit"}
              </Button>
            </div>

            {/* Login Link */}
            <div className="btn pt-2 sm:flex gap-1 justify-center items-center">
              <p className="text-lg text-white">Already have a job seeker account?</p>
              <Button
                variant={"link"}
                className="text-pink-500 text-lg p-0"
              >
                Log in
              </Button>
            </div>
          </form>
        </Form>
      </div>
    </div>
  );
};

export default Jobprovideraccount;



Dashboard


Application Form 

import React from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";

// Define the form schema using Zod
const formSchema = z.object({
  jobId: z.string().min(1, {
    message: "Job ID is required.",
  }),
  candidateId: z.string().min(2, {
    message: "Candidate ID must be at least 2 characters long.",
  }),
  resumeFile: z
    .instanceof(File, {
      message: "A resume file is required.",
    })
    .refine((file) => file.size < 5 * 1024 * 1024, {
      message: "Resume file size must be less than 5MB.",
    })
    .refine(
      (file) =>
        ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"].includes(file.type),
      {
        message: "Only PDF, DOC, or DOCX files are allowed.",
      }
    ),
  applicationDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, {
    message: "Application date must be in YYYY-MM-DD format.",
  }),
});

const ApplicationForm = ({
  jobId,
  userid,
  onClose,
}: {
  jobId: string;
  userid: string | undefined;
  onClose: () => void;
}) => {
  const [isLoading, setIsLoading] = React.useState(false);

  // Initialize the form
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      jobId: jobId,
      candidateId: userid,
      resumeFile: undefined,
      applicationDate: new Date().toISOString().split("T")[0],
    },
  });

  // Handle form submission
  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    try {
      setIsLoading(true);
      // API call / Redux dispatch removed
      console.log("Form values submitted:", values);
      onClose(); // Close the modal after submission
    } catch (error: any) {
      console.error("Failed to submit application:", error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        {/* Candidate ID */}
        <FormField
          control={form.control}
          name="candidateId"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Candidate ID</FormLabel>
              <FormControl>
                <Input placeholder="Enter Candidate ID" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        {/* Resume File */}
        <FormField
          control={form.control}
          name="resumeFile"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Upload Resume</FormLabel>
              <FormControl>
                <Input
                  type="file"
                  accept=".pdf,.doc,.docx"
                  onChange={(e) => field.onChange(e.target.files?.[0])}
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        {/* Application Date */}
        <FormField
          control={form.control}
          name="applicationDate"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Application Date</FormLabel>
              <FormControl>
                <Input type="date" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        {/* Submit Button */}
        <Button type="submit" disabled={isLoading}>
          {isLoading ? "Submitting..." : "Submit"}
        </Button>
      </form>
    </Form>
  );
};

export default ApplicationForm;


CompanyForm Compponent

import React from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { useForm } from "react-hook-form";
// import { toast } from "sonner"; // Optional toast notifications
// import { useAppDispatch } from "@/Ruduxtoolkit/hook";
// import { addCompany, fetchCompanies } from "@/Ruduxtoolkit/companySlice";

// Define the form schema
const formSchema = z.object({
  name: z.string().min(2, { message: "Name must be at least 2 characters long." }),
  description: z.string().optional(),
  industry: z.string().min(2, { message: "Industry must be at least 2 characters long." }),
  website: z.string().url({ message: "Website must be a valid URL." }).optional(),
  logoUrl: z
    .instanceof(File)
    .optional()
    .refine(
      (file) => !file || ["image/jpeg", "image/png", "image/jpg"].includes(file.type),
      { message: "Only JPEG, PNG, or JPG images are allowed." }
    ),
});

const CompanyForm = () => {
  const [isLoading, setIsLoading] = React.useState(false);
  // const dispatch = useAppDispatch(); // Uncomment when using Redux

  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      name: "",
      description: "",
      industry: "",
      website: "",
      logoUrl: undefined,
    },
  });

  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    setIsLoading(true);

    try {
      // Uncomment below and add your API logic
      // const companyData: any = {
      //   name: values.name,
      //   description: values.description,
      //   industry: values.industry,
      //   website: values.website,
      //   logoUrl: values.logoUrl || undefined,
      // };
 

      console.log("Form values:", values); // For testing without API
      form.reset();
    } catch (error: any) {
      // toast.error(error.message || "Failed to submit company details.");
      console.error(error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="bg-[#5b3e8141] text-white p-6 rounded-lg w-[550px] mx-auto">
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="grid grid-cols-2 gap-6 items-center">

          {/* Name */}
          <FormField
            control={form.control}
            name="name"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Name</FormLabel>
                <FormControl>
                  <Input placeholder="Enter company name" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          {/* Description */}
          <FormField
            control={form.control}
            name="description"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Description</FormLabel>
                <FormControl>
                  <Input placeholder="Enter company description" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          {/* Industry */}
          <FormField
            control={form.control}
            name="industry"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Industry</FormLabel>
                <FormControl>
                  <Input placeholder="Enter industry" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          {/* Website */}
          <FormField
            control={form.control}
            name="website"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Website</FormLabel>
                <FormControl>
                  <Input placeholder="Enter website URL" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          {/* Logo */}
          <FormField
            control={form.control}
            name="logoUrl"
            render={({ field: { onChange, value, ...fieldProps } }) => (
              <FormItem>
                <FormLabel>Logo</FormLabel>
                <FormControl>
                  <Input
                    type="file"
                    accept="image/jpeg, image/png, image/jpg"
                    onChange={(event) => {
                      const file = event.target.files?.[0];
                      onChange(file);
                    }}
                    {...fieldProps}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          {/* Submit Button */}
          <Button
            className="col-span-2 w-full bg-primary hover:bg-primary-dark text-white"
            type="submit"
            disabled={isLoading}
          >
            {isLoading ? "Submitting..." : "Submit"}
          </Button>
        </form>
      </Form>
    </div>
  );
};

export default CompanyForm;


Conform Mail Component

import React, { useState } from 'react';
import { Button } from '../ui/button';
// import { toast } from 'sonner';

const Confirmemail = () => {
  // const dispatch = useAppDispatch();
  const [isButtonDisabled, setIsButtonDisabled] = useState(false);

  // Function to send verification email
  const sendVerificationEmail = async () => {
       
  };

  return (
    <div className="box absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] bg-[#af8dff56] w-[60%] h-[300px] rounded-md flex justify-center items-center flex-col">
      <h3 className="my-4 text-xl text-white">
        Verify your email to activate your account.
      </h3>
      <Button
        variant="secondary"
        className={`text-xl text-white ${
          isButtonDisabled
            ? 'bg-gray-500 cursor-not-allowed'
            : 'bg-[#FF0B7E] hover:bg-[#ff3d98]'
        }`}
        onClick={sendVerificationEmail}
        disabled={isButtonDisabled}
      >
        {isButtonDisabled ? "Email Sent" : "Send Verification Email"}
      </Button>
    </div>
  );
};

export default Confirmemail;


#DashBoard Page Component

import React, { useEffect, useState } from "react";
import Dashboardcard from "./dashboardcard";
import Dashboardtable from "./dashboradTable";


const Dashboardpage = () => {
  // const dispatch = useAppDispatch();
  const [appliedJobs, setAppliedJobs] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Simulate fetching data
    const fetchData = async () => {
 setLoading(true);
      try {
       

   

        // Placeholder data
        const data = [
          { id: 1, title: "Frontend Developer", company: "ABC Corp", status: "Accepted" },
          { id: 2, title: "Backend Developer", company: "XYZ Ltd", status: "Pending" },
        ];

        setAppliedJobs(data);
      } catch (error) {
        console.error("Failed to fetch applied jobs:", error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  // Get only the most recent job
  const recentJob = appliedJobs.length > 0 ? [appliedJobs[appliedJobs.length - 1]] : [];

  // Total number of applicants
  const totalApplicants = appliedJobs.length;

  // Count of selected candidates
  const totalSelectedCandidates = appliedJobs.filter((job: any) => job.status === "Accepted").length;

  return (
    <div className="w-full space-y-6">
      {/* Top Cards */}
      <div className="top flex flex-wrap gap-6">
        <Dashboardcard
          content="Total Applications"
          className="bg-blue-500"
          contentdata={totalApplicants}
        />
        <Dashboardcard
          content="Total Selected Candidates"
          className="bg-green-600"
          contentdata={totalSelectedCandidates}
        />
      </div>

      {/* Table Section */}
      <div className="table w-full">
        <h2 className="text-xl font-semibold text-white mb-4">Recent Job Applied</h2>
        {loading ? (
          <p className="text-center text-gray-500">Loading...</p>
        ) : recentJob.length > 0 ? (
          <Dashboardtable
            caption="Most recent job you have applied to."
            columns={[
              { header: "Job Title", accessor: "title" },
              { header: "Company", accessor: "company" },
              { header: "Status", accessor: "status" },
            ]}
            data={recentJob}
            isuser={true}
          />
        ) : (
          <div className="w-full bg-white p-6 rounded-lg shadow-md text-center text-gray-500">
            No jobs applied yet.
          </div>
        )}
      </div>
    </div>
  );
};

export default Dashboardpage;


DashBoard Card & Component

import React from 'react';

/**
 * Dashboardcard Component
 *
 * Props:
 * - content: string -> The title/label for the card.
 * - className: string -> Tailwind or custom classes for styling.
 * - contentdata?: number -> Optional numeric value to display (e.g., total applications).
 *
 * Example usage:
 * <Dashboardcard content="Total Applications" className="bg-blue-500" contentdata={10} />
 */
const Dashboardcard = ({
  content,
  className,
  contentdata,
}: {
  content: string;
  className: string;
  contentdata?: number;
}) => {
  return (
    <div
      className={`w-[300px] h-[150px] flex flex-col justify-center items-center p-4 rounded-lg ${className}`}
    >
      {/* Display the numeric content if available */}
      <p className="text-3xl">{contentdata !== undefined ? contentdata : '-'}</p>
      <p>{content}</p>
    </div>
  );
};

export default Dashboardcard;


DashBoard Chart

import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { ChartContainer, ChartTooltip, ChartTooltipContent, ChartConfig } from "@/components/ui/chart";
import { TrendingUp } from "lucide-react";

interface DashboardChartProps {
  data?: Array<{ month: string; [key: string]: number }>;
  config?: ChartConfig;
  title?: string;
  description?: string;
  footerText?: string;
}

// Dummy data fallback
const dummyData = [
  { month: "January", desktop: 186, mobile: 80 },
  { month: "February", desktop: 305, mobile: 200 },
  { month: "March", desktop: 237, mobile: 120 },
  { month: "April", desktop: 73, mobile: 190 },
  { month: "May", desktop: 209, mobile: 130 },
  { month: "June", desktop: 214, mobile: 140 },
];

const dummyConfig = {
  desktop: { label: "Desktop", color: "hsl(var(--chart-1))" },
  mobile: { label: "Mobile", color: "hsl(var(--chart-2))" },
} satisfies ChartConfig;

export function Dashboardchart({
  data = dummyData,
  config = dummyConfig,
  title = "Area Chart - Stacked",
  description = "Showing total visitors for the last 6 months",
  footerText = "Trending up by 5.2% this month",
}: DashboardChartProps) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
        <CardDescription>{description}</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer config={config} className="h-80 w-full">
          <AreaChart data={data} margin={{ left: 12, right: 12 }}>
            <CartesianGrid vertical={false} />
            <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
            <ChartTooltip cursor={false} content={<ChartTooltipContent indicator="dot" />} />
            {Object.keys(config).map((key) => (
              <Area
                key={key}
                dataKey={key}
                type="natural"
                fill={`var(--color-${key})`}
                fillOpacity={0.4}
                stroke={`var(--color-${key})`}
                stackId="a"
              />
            ))}
          </AreaChart>
        </ChartContainer>
      </CardContent>
      {footerText && (
        <CardFooter>
          <div className="flex items-center gap-2 text-sm font-medium">
            {footerText} <TrendingUp className="h-4 w-4" />
          </div>
        </CardFooter>
      )}
    </Card>
  );
}


DashBoard Table

import React, { useState } from "react";
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import Jobapplicationstatus from "@/components/dashboard/Jobapplicationstatus"; // Import Modal
import Link from "next/link";

// Dummy Columns
const dummyColumns = [
  { header: "Job Title", accessor: "title" },
  { header: "Company", accessor: "company" },
  { header: "Status", accessor: "status" },
];

// Dummy Data
const dummyData = [
  { title: "Frontend Developer", company: "ABC Corp", status: "Pending", $id: "1" },
  { title: "Backend Developer", company: "XYZ Ltd", status: "Accepted", $id: "2" },
  { title: "UI/UX Designer", company: "DesignPro", status: "Rejected", $id: "3" },
];

interface TableColumn {
  header: string;
  accessor: string;
  className?: string;
}

interface GenericTableProps {
  caption?: string;
  columns?: TableColumn[];
  data?: Record<string, any>[];
  footer?: { label: string; value: string };
  action?: boolean;
  isuser?: boolean;
}

export default function DashboardTable({
  caption,
  columns = dummyColumns,
  data = dummyData,
  footer,
  action,
  isuser,
}: GenericTableProps) {
  // Modal state
  const [selectedApplication, setSelectedApplication] = useState<any>(null);
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = (application: any) => {
    setSelectedApplication(application);
    setIsModalOpen(true);
  };

  const closeModal = () => {
    setIsModalOpen(false);
  };

  return (
    <>
      <Table>
        {caption && <TableCaption>{caption}</TableCaption>}

        <TableHeader>
          <TableRow>
            {columns.map((column, index) => (
              <TableHead key={index} className={`${column.className} text-white`}>
                {column.header}
              </TableHead>
            ))}
            {action && <TableHead className="text-white">Actions</TableHead>}
          </TableRow>
        </TableHeader>

        <TableBody>
          {data.length > 0 ? (
            data.map((row: any, rowIndex: number) => (
              <TableRow key={rowIndex}>
                {columns.map((column, colIndex) => (
                  <TableCell key={colIndex} className={column.className}>
                    {column.accessor === "status" ? (
                      <Button
                        variant="outline"
                        className={`px-3 py-1 rounded-md ${
                          row[column.accessor] === "Pending"
                            ? "bg-yellow-500 text-white"
                            : row[column.accessor] === "Accepted"
                            ? "bg-green-500 text-white"
                            : "bg-red-500 text-white"
                        }`}
                        onClick={() => isuser ? " " : openModal(row)}
                      >
                        {row[column.accessor]}
                      </Button>
                    ) : isValidURL(row[column.accessor]) ? (
                      <a
                        href={row[column.accessor]}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="bg-blue-500 text-white px-3 py-1 rounded-md hover:bg-blue-600"
                      >
                        Open Link
                      </a>
                    ) : column.accessor === "visit" ? (
                      <Link href={`/User/job/${row.title}_${row.$id}`}>
                        <Button variant="default">Visit</Button>
                      </Link>
                    ) : (
                      row[column.accessor]
                    )}
                  </TableCell>
                ))}
                {action && (
                  <TableCell>
                    <Button onClick={() => openModal(row)}>Edit Status</Button>
                  </TableCell>
                )}
              </TableRow>
            ))
          ) : (
            <TableRow>
              <TableCell colSpan={columns.length + (action ? 1 : 0)} className="text-center">
                No data available
              </TableCell>
            </TableRow>
          )}
        </TableBody>

        {footer && (
          <TableFooter>
            <TableRow>
              <TableCell colSpan={columns.length - 1}>{footer.label}</TableCell>
              <TableCell className="text-right">{footer.value}</TableCell>
            </TableRow>
          </TableFooter>
        )}
      </Table>

      {/* Status Modal */}
      {selectedApplication && (
        <Jobapplicationstatus
          isOpen={isModalOpen}
          onClose={closeModal}
          application={selectedApplication}
        />
      )}
    </>
  );
}

// Function to check if the value is a valid URL
function isValidURL(value: string) {
  try {
    new URL(value);
    return true;
  } catch (_) {
    return false;
  }
}


DashBoard Header

import React from "react";
import { Button } from "../ui/button";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
import { useRouter } from "next/navigation";

interface HeaderProps {
  user?: { name: string; avatarUrl?: string }; // Optional user prop
  onLogout?: () => void; // Optional logout callback
}

const Header: React.FC<HeaderProps> = ({ user, onLogout }) => {
  const router = useRouter();

  // Dummy user data if none provided
  const currentUser = user || { name: "John Doe", avatarUrl: undefined };

  const handleLogout = () => {
    if (onLogout) {
      onLogout();
    } else {
      // Default behavior: redirect to home
      router.push("/");
      alert("Logout successfully"); // Fallback notification
    }
  };

  return (
    <header className="flex justify-between items-center px-8 py-4 bg-[#5B3E81] sticky top-0 z-50">
      <div className="logo">
        <h2 className="text-3xl font-semibold font-mono text-[#D83F87] capitalize">
          online job portal
        </h2>
      </div>
      <div className="last flex items-center gap-6">
        <Button
          onClick={handleLogout}
          variant="secondary"
          className="bg-[#D83F87] text-white hover:bg-[#ff3bb1]"
        >
          Logout
        </Button>
        <Avatar>
          {currentUser.avatarUrl ? (
            <AvatarImage src={currentUser.avatarUrl} alt={currentUser.name} />
          ) : (
            <AvatarFallback>
              {currentUser.name
                .split(" ")
                .map((n) => n[0])
                .join("")
                .toUpperCase()}
            </AvatarFallback>
          )}
        </Avatar>
      </div>
    </header>
  );
};

export default Header;


Job Application

import { useState } from "react";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";

interface Application {
  $id: string;
  status: string;
}

interface StatusModalProps {
  isOpen: boolean;
  onClose: () => void;
  application?: Application; // Optional prop
  onUpdate?: (status: string) => void; // Optional callback for update
}

export default function JobApplicationStatus({
  isOpen,
  onClose,
  application,
  onUpdate,
}: StatusModalProps) {
  // Fallback dummy application if none provided
  const [status, setStatus] = useState<string>(
    application?.status || "Pending"
  );

  const handleUpdateStatus = () => {
    if (onUpdate) {
      onUpdate(status);
    } else {
      alert(`Status updated to ${status}`); // fallback notification
    }
    onClose();
  };

  return (
    <Dialog open={isOpen} onOpenChange={onClose}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Update Application Status</DialogTitle>
        </DialogHeader>
        <div className="space-y-4">
          <select
            className="w-full p-2 border rounded-md"
            value={status}
            onChange={(e) => setStatus(e.target.value)}
          >
            <option value="Pending">Pending</option>
            <option value="Accepted">Accepted</option>
            <option value="Cancelled">Cancelled</option>
          </select>
          <div className="flex justify-end space-x-2">
            <Button variant="outline" onClick={onClose}>
              Cancel
            </Button>
            <Button onClick={handleUpdateStatus}>Update</Button>
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}


Job Form

import React, { useState } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { z } from "zod";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { useForm } from "react-hook-form";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "../ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { CalendarIcon } from "@radix-ui/react-icons";
import { Calendar } from "../ui/calendar";
import TextEditor from "./TextEditor"; // assuming it's a controlled component

// Define the form schema using Zod
const formSchema = z.object({
  title: z.string().min(2, { message: "Title must be at least 2 characters long." }),
  category: z.string().min(2, { message: "Category must be at least 2 characters long." }),
  totalvacancy: z.string().min(1, { message: "Total vacancy at least 1." }),
  companyName: z.string().min(2, { message: "Company name must be at least 2 characters long." }),
  location: z.string().min(2, { message: "Location must be at least 2 characters long." }),
  salaryRange: z.string().optional(),
  jobType: z.enum(["full-time", "part-time", "contract", "internship"]),
  applicationDeadline: z.date({ message: "Application deadline must be a valid date." }),
  isActive: z.boolean(),
});

const JobForm = ({ onSubmitJob }: { onSubmitJob?: (data: any) => void }) => {
  const [applicationDeadline, setApplicationDeadline] = useState<Date | undefined>();
  const [isLoading, setIsLoading] = useState(false);
  const [content, setContent] = useState("");

  // Initialize the form
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      title: "",
      companyName: "",
      location: "",
      salaryRange: "",
      jobType: undefined,
      category: "",
      totalvacancy: "",
      applicationDeadline: undefined,
      isActive: true,
    },
  });

  // Handle form submission
  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    setIsLoading(true);
    try {
      const jobData = { ...values, description: content };
      if (onSubmitJob) {
        onSubmitJob(jobData); // call parent callback
      } else {
        alert("Job submitted! Check console for data.");
        console.log(jobData); // fallback
      }
      form.reset();
      setContent("");
    } catch (error: any) {
      console.error(error);
      alert("Failed to submit job.");
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="bg-[#5b3e8141] text-white p-6 rounded-lg w-full md:w-[80%] mx-auto">
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="grid grid-cols-2 gap-6 items-center">
          <FormField control={form.control} name="title" render={({ field }) => (
            <FormItem className="col-span-2">
              <FormLabel>Title</FormLabel>
              <FormControl>
                <Input placeholder="Enter job title" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )} />

          <div className="col-span-2 w-full">
            <TextEditor content={content} setContent={setContent} />
          </div>

          <FormField control={form.control} name="companyName" render={({ field }) => (
            <FormItem>
              <FormLabel>Company Name</FormLabel>
              <FormControl><Input placeholder="Enter company name" {...field} /></FormControl>
              <FormMessage />
            </FormItem>
          )} />

          <FormField control={form.control} name="location" render={({ field }) => (
            <FormItem>
              <FormLabel>Location</FormLabel>
              <FormControl><Input placeholder="Enter location" {...field} /></FormControl>
              <FormMessage />
            </FormItem>
          )} />

          <FormField control={form.control} name="salaryRange" render={({ field }) => (
            <FormItem>
              <FormLabel>Salary Range</FormLabel>
              <FormControl><Input placeholder="Enter salary range (optional)" {...field} /></FormControl>
              <FormMessage />
            </FormItem>
          )} />

          <FormField control={form.control} name="totalvacancy" render={({ field }) => (
            <FormItem>
              <FormLabel>Total Vacancy</FormLabel>
              <FormControl><Input placeholder="Enter total vacancy" {...field} /></FormControl>
              <FormMessage />
            </FormItem>
          )} />

          <FormField control={form.control} name="category" render={({ field }) => (
            <FormItem>
              <FormLabel>Category</FormLabel>
              <FormControl><Input placeholder="Enter category" {...field} /></FormControl>
              <FormMessage />
            </FormItem>
          )} />

          <FormField control={form.control} name="jobType" render={({ field }) => (
            <FormItem>
              <FormLabel>Job Type</FormLabel>
              <Select onValueChange={field.onChange} defaultValue={field.value}>
                <FormControl><SelectTrigger><SelectValue placeholder="Select job type" /></SelectTrigger></FormControl>
                <SelectContent>
                  <SelectItem value="full-time">Full-Time</SelectItem>
                  <SelectItem value="part-time">Part-Time</SelectItem>
                  <SelectItem value="contract">Contract</SelectItem>
                  <SelectItem value="internship">Internship</SelectItem>
                </SelectContent>
              </Select>
              <FormMessage />
            </FormItem>
          )} />

          <FormField control={form.control} name="applicationDeadline" render={({ field }) => (
            <FormItem>
              <FormLabel>Application Deadline</FormLabel>
              <Popover>
                <PopoverTrigger asChild>
                  <FormControl>
                    <Button variant="outline" className="w-full pl-3 text-left font-normal text-black">
                      {applicationDeadline ? format(applicationDeadline, "PPP") : "Pick a date"}
                      <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
                    </Button>
                  </FormControl>
                </PopoverTrigger>
                <PopoverContent className="w-auto p-0" align="start">
                  <Calendar
                    mode="single"
                    selected={applicationDeadline}
                    onSelect={(date) => {
                      setApplicationDeadline(date);
                      field.onChange(date);
                    }}
                  />
                </PopoverContent>
              </Popover>
              <FormMessage />
            </FormItem>
          )} />

          <Button className="col-span-2 w-full bg-primary text-white" type="submit" disabled={isLoading}>
            {isLoading ? "Submitting..." : "Submit"}
          </Button>
        </form>
      </Form>
    </div>
  );
};

export default JobForm;


DashBoard Sidebar

import React, { useState } from "react";
import { Button } from "../ui/button";
import Link from "next/link";
import { usePathname } from "next/navigation";

interface SidebarProps {
  menu?: string[];
  currentRoute?: string; // optional prop to simulate current path
}

const Sidebar: React.FC<SidebarProps> = ({ menu = ["Dashboard", "Jobs", "Profile"], currentRoute }) => {
  const path = currentRoute || usePathname() || "/dashboard"; // fallback dummy route
  const routename = path.split("/")[1] || "dashboard";
  const pathname = path.split("/")[2]?.toLowerCase().replace(/\s+/g, "") || "";

  const [isJobProvider, setIsJobProvider] = useState(false); // fallback state

  return (
    <aside>
      <div className="p-4 bg-[#5B3E81] min-h-screen py-10 w-[250px] sticky top-10 left-0">
        {menu.map((m: string) => {
          const normalizedMenuItem = m.toLowerCase().replace(/\s+/g, "");
          return (
            <Link
              href={`/${routename}/${normalizedMenuItem}`}
              className="block"
              key={m}
            >
              <Button
                variant="secondary"
                className={`${
                  normalizedMenuItem === pathname
                    ? "bg-[#FF0B7E]"
                    : "bg-[#ff0b7d61]"
                } hover:bg-[#FF0B7E] w-[200px] p-6 my-2 text-white text-xl`}
              >
                {m}
              </Button>
            </Link>
          );
        })}

        {/* Example fallback for job provider button */}
        {isJobProvider && (
          <Link href="/jobprovider/dashboard">
            <Button
              variant="secondary"
              className="bg-[#FF0B7E] hover:bg-[#FF0B7E] w-[200px] p-6 my-2 text-white text-xl"
            >
              Job Provider
            </Button>
          </Link>
        )}
      </div>
    </aside>
  );
};

export default Sidebar;


DashBoard Slider Component

import * as React from "react";
import { Card, CardContent, CardTitle } from "@/components/ui/card";
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from "@/components/ui/carousel";
import Link from "next/link";

interface Course {
  title: string;
  image: string;
  url?: string;
}

interface SliderCourseProps {
  courses?: Course[]; // optional prop
}

export function SliderCourse({ courses }: SliderCourseProps) {
  // Fallback dummy data
  const dummyCourses: Course[] = [
    { title: "Course 1", image: "/images/course1.jpg", url: "#" },
    { title: "Course 2", image: "/images/course2.jpg", url: "#" },
    { title: "Course 3", image: "/images/course3.jpg", url: "#" },
    { title: "Course 4", image: "/images/course4.jpg", url: "#" },
  ];

  const sliderData = courses && courses.length > 0 ? courses : dummyCourses;

  return (
    <Carousel
      opts={{ align: "start" }}
      className="w-full"
    >
      <CarouselContent>
        {sliderData.map((data, index) => (
          <CarouselItem key={index} className="md:basis-1/4">
            <Link href={data.url || "#"}>
              <div className="p-1">
                <Card className="h-[260px] overflow-hidden">
                  <img
                    src={data.image}
                    alt={data.title}
                    className="w-full h-[200px] object-cover object-center"
                  />
                  <CardContent className="flex justify-center">
                    <CardTitle className="p-2 text-xl leading-6">{data.title}</CardTitle>
                  </CardContent>
                </Card>
              </div>
            </Link>
          </CarouselItem>
        ))}
      </CarouselContent>
      <CarouselPrevious />
      <CarouselNext />
    </Carousel>
  );
}

DashBoard Text Editor

import React from "react";
import { Editor } from "@tinymce/tinymce-react";

interface TextEditorProps {
  content?: string; // optional initial content
  setContent: (value: string) => void;
}

export default function TextEditor({ content = "", setContent }: TextEditorProps) {
  return (
    <div className="p-5 w-full">
      <h1 className="text-xl font-bold mb-4">TinyMCE Editor</h1>
      <Editor
        apiKey="drop here api key"
        value={content} // Controlled value with default empty string
        onEditorChange={(newContent) => setContent(newContent)}
        init={{
          height: 600,
          width: "100%",
          menubar: false,
          plugins: [
            "anchor",
            "autolink",
            "charmap",
            "codesample",
            "emoticons",
            "image",
            "link",
            "lists",
            "media",
            "searchreplace",
            "table",
            "visualblocks",
            "wordcount",
          ],
          toolbar:
            "undo redo | bold italic underline strikethrough | " +
            "alignleft aligncenter alignright alignjustify | " +
            "bullist numlist outdent indent | link image media table | " +
            "codesample emoticons charmap | removeformat",
          toolbar_mode: "wrap",
          content_style:
            "body { font-family:Helvetica,Arial,sans-serif; font-size:16px }",
        }}
      />
    </div>
  );
}


DashBoard User Profile

import React from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { useForm } from "react-hook-form";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";

// Zod schema
const formSchema = z.object({
  firstname: z.string().min(2),
  lastname: z.string().min(2),
  contact: z.string().length(10).regex(/^\d+$/),
  address: z.string().min(2),
  gender: z.enum(["male", "female", "other"]),
  education: z.string().min(2),
  skills: z.string().min(2),
  dateofbirth: z.string(),
  experience: z.string().min(2),
  nationality: z.string().min(2),
  image: z.instanceof(File).optional(),
});

interface UserProfileFormProps {
  initialValues?: Partial<z.infer<typeof formSchema>>;
  onSubmit?: (values: z.infer<typeof formSchema>) => Promise<void>;
}

const UserProfileForm: React.FC<UserProfileFormProps> = ({
  initialValues = {},
  onSubmit = async (values) => {
    console.log("Form submitted:", values);
    alert("Form submitted! Check console for details.");
  },
}) => {
  const [isLoading, setIsLoading] = React.useState(false);

  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      firstname: "",
      lastname: "",
      contact: "",
      address: "",
      gender: undefined,
      education: "",
      skills: "",
      dateofbirth: "",
      experience: "",
      nationality: "",
      image: undefined,
      ...initialValues, // Merge fallback and passed-in values
    },
  });

  const handleSubmit = async (values: z.infer<typeof formSchema>) => {
    setIsLoading(true);
    try {
      await onSubmit(values);
      form.reset();
    } catch (err) {
      console.error(err);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="bg-[#5b3e8141] text-white p-6 rounded-lg w-[550px] mx-auto">
      <Form {...form}>
        <form
          onSubmit={form.handleSubmit(handleSubmit)}
          className="grid grid-cols-2 gap-6 items-center"
        >
          <FormField
            control={form.control}
            name="firstname"
            render={({ field }) => (
              <FormItem>
                <FormLabel>First Name</FormLabel>
                <FormControl>
                  <Input placeholder="Enter your first name" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="lastname"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Last Name</FormLabel>
                <FormControl>
                  <Input placeholder="Enter your last name" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="contact"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Contact Number</FormLabel>
                <FormControl>
                  <Input placeholder="Enter contact number" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="address"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Address</FormLabel>
                <FormControl>
                  <Input placeholder="Enter address" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="gender"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Gender</FormLabel>
                <Select onValueChange={field.onChange} defaultValue={field.value}>
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue placeholder="Select your gender" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    <SelectItem value="male">Male</SelectItem>
                    <SelectItem value="female">Female</SelectItem>
                    <SelectItem value="other">Other</SelectItem>
                  </SelectContent>
                </Select>
                <FormMessage />
              </FormItem>
            )}
          />
          {/* Add remaining fields like education, skills, dateofbirth, experience, nationality, image here similarly */}

          <Button
            className="col-span-2 w-full bg-primary hover:bg-primary-dark text-white"
            type="submit"
            disabled={isLoading}
          >
            {isLoading ? "Submitting..." : "Submit"}
          </Button>
        </form>
      </Form>
    </div>
  );
};

export default UserProfileForm;


No comments:

If you have any doubts please let's me know

Powered by Blogger.