From 0ac4865e47a789f4fcd919a3f05d538227500d29 Mon Sep 17 00:00:00 2001 From: Om Lanke Date: Sat, 5 Jul 2025 00:06:38 +0530 Subject: [PATCH] dashboard and new jobs page --- .../app/(main)/jobs/new/new-job-form.tsx | 803 +++++++++++------- apps/admin/app/(main)/page.tsx | 296 ++----- packages/ui/package.json | 1 + packages/ui/src/components/alert.tsx | 66 ++ packages/ui/src/components/checkbox.tsx | 32 + pnpm-lock.yaml | 32 + 6 files changed, 711 insertions(+), 519 deletions(-) create mode 100644 packages/ui/src/components/alert.tsx create mode 100644 packages/ui/src/components/checkbox.tsx diff --git a/apps/admin/app/(main)/jobs/new/new-job-form.tsx b/apps/admin/app/(main)/jobs/new/new-job-form.tsx index a28e862..f203c88 100644 --- a/apps/admin/app/(main)/jobs/new/new-job-form.tsx +++ b/apps/admin/app/(main)/jobs/new/new-job-form.tsx @@ -1,57 +1,62 @@ -'use client'; -import { useState, useTransition } from 'react'; -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { Input } from '@workspace/ui/components/input'; -import { Textarea } from '@workspace/ui/components/textarea'; -import { Button } from '@workspace/ui/components/button'; +"use client" + +import type React from "react" + +import { useState, useTransition } from "react" +import { useForm } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { Input } from "@workspace/ui/components/input" +import { Textarea } from "@workspace/ui/components/textarea" +import { Button } from "@workspace/ui/components/button" +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@workspace/ui/components/form" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@workspace/ui/components/select" +import { Card, CardContent } from "@workspace/ui/components/card" +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@workspace/ui/components/dialog" +import { Checkbox } from "@workspace/ui/components/checkbox" +import { jobSchema, type JobFormData } from "./schema" +import { createJob, createCompany } from "./actions" +import { Popover, PopoverTrigger, PopoverContent } from "@workspace/ui/components/popover" +import { Calendar } from "@workspace/ui/components/calendar" +import { format } from "date-fns" import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@workspace/ui/components/form'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@workspace/ui/components/select'; -import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card'; -import { jobSchema, JobFormData } from './schema'; -import { createJob, createCompany } from './actions'; -import { Popover, PopoverTrigger, PopoverContent } from '@workspace/ui/components/popover'; -import { Calendar } from '@workspace/ui/components/calendar'; -import { format } from 'date-fns'; -import { Calendar as CalendarIcon } from 'lucide-react'; -import { cn } from '@workspace/ui/lib/utils'; + CalendarIcon, + Plus, + Building2, + Briefcase, + MapPin, + DollarSign, + GraduationCap, + CheckCircle, + AlertCircle, + LinkIcon, +} from "lucide-react" +import { cn } from "@workspace/ui/lib/utils" +import { Alert, AlertDescription } from "@workspace/ui/components/alert" function NewJobForm({ companies }: { companies: { id: number; name: string }[] }) { - const [success, setSuccess] = useState(false); - const [error, setError] = useState(null); - const [isPending, startTransition] = useTransition(); - const [showModal, setShowModal] = useState(false); - const [addingCompany, setAddingCompany] = useState(false); - const [companyList, setCompanyList] = useState(companies); - const [newCompanyName, setNewCompanyName] = useState(''); - const [newCompanyEmail, setNewCompanyEmail] = useState(''); - const [newCompanyLink, setNewCompanyLink] = useState(''); - const [newCompanyDescription, setNewCompanyDescription] = useState(''); - const [newCompanyImageURL, setNewCompanyImageURL] = useState(''); - const [companyError, setCompanyError] = useState(null); + const [success, setSuccess] = useState(false) + const [error, setError] = useState(null) + const [isPending, startTransition] = useTransition() + const [showModal, setShowModal] = useState(false) + const [addingCompany, setAddingCompany] = useState(false) + const [companyList, setCompanyList] = useState(companies) + const [newCompanyName, setNewCompanyName] = useState("") + const [newCompanyEmail, setNewCompanyEmail] = useState("") + const [newCompanyLink, setNewCompanyLink] = useState("") + const [newCompanyDescription, setNewCompanyDescription] = useState("") + const [newCompanyImageURL, setNewCompanyImageURL] = useState("") + const [companyError, setCompanyError] = useState(null) + const form = useForm({ resolver: zodResolver(jobSchema), defaultValues: { companyId: companies[0]?.id ?? 0, - title: '', - link: '', - description: '', - location: '', - imageURL: '', - salary: '', + title: "", + link: "", + description: "", + location: "", + imageURL: "", + salary: "", applicationDeadline: new Date(), minCGPA: 0, minSSC: 0, @@ -59,289 +64,364 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] } allowDeadKT: true, allowLiveKT: true, }, - }); + }) async function handleSubmit(formData: FormData) { - setError(null); - setSuccess(false); + setError(null) + setSuccess(false) startTransition(async () => { - const result = await createJob(formData); + const result = await createJob(formData) if (result?.success) { - setSuccess(true); - form.reset(form.formState.defaultValues); + setSuccess(true) + form.reset(form.formState.defaultValues) } else { - setError(result?.error || 'Failed to create job'); + setError(result?.error || "Failed to create job") } - }); + }) } async function handleAddCompany(e: React.FormEvent) { - e.preventDefault(); - setCompanyError(null); - if (!newCompanyName.trim() || !newCompanyEmail.trim() || !newCompanyLink.trim() || !newCompanyDescription.trim()) return; - setAddingCompany(true); - const formData = new FormData(); - formData.append('name', newCompanyName.trim()); - formData.append('email', newCompanyEmail.trim()); - formData.append('link', newCompanyLink.trim()); - formData.append('description', newCompanyDescription.trim()); - formData.append('imageURL', newCompanyImageURL.trim()); - const result = await createCompany(formData); - if (result?.success && result.company) { - setCompanyList((prev) => [...prev, result.company]); - form.setValue('companyId', result.company.id); - setNewCompanyName(''); - setNewCompanyEmail(''); - setNewCompanyLink(''); - setNewCompanyDescription(''); - setNewCompanyImageURL(''); - setShowModal(false); - } else { - setCompanyError(result?.error || 'Failed to add company'); + e.preventDefault() + setCompanyError(null) + + if (!newCompanyName.trim() || !newCompanyEmail.trim() || !newCompanyLink.trim() || !newCompanyDescription.trim()) { + setCompanyError("Please fill in all required fields") + return } - setAddingCompany(false); + + setAddingCompany(true) + const formData = new FormData() + formData.append("name", newCompanyName.trim()) + formData.append("email", newCompanyEmail.trim()) + formData.append("link", newCompanyLink.trim()) + formData.append("description", newCompanyDescription.trim()) + formData.append("imageURL", newCompanyImageURL.trim()) + + const result = await createCompany(formData) + if (result?.success && result.company) { + setCompanyList((prev) => [...prev, result.company]) + form.setValue("companyId", result.company.id) + setNewCompanyName("") + setNewCompanyEmail("") + setNewCompanyLink("") + setNewCompanyDescription("") + setNewCompanyImageURL("") + setShowModal(false) + } else { + setCompanyError(result?.error || "Failed to add company") + } + setAddingCompany(false) } return ( -
-
- - - Create a New Job - - +
+
+ {/* Header */} +
+
+ +
+

Create New Job Listing

+

Fill in the details below to post a new job opportunity

+
+ + +
- - ( - - Company * - - - - )} - /> - ( - - Title * - - - - - - )} - /> - ( - - Job Link * - - - - - - )} - /> - ( - - Description * - -