feat(admin): fixed job listing

This commit is contained in:
Unchanted
2025-08-21 13:55:24 +05:30
parent 8ebf952f74
commit 8bfe681dd4
4 changed files with 67 additions and 27 deletions

View File

@@ -66,10 +66,30 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
}, },
}) })
async function handleSubmit(formData: FormData) { async function handleSubmit(data: JobFormData) {
setError(null) setError(null)
setSuccess(false) setSuccess(false)
startTransition(async () => { startTransition(async () => {
// Convert React Hook Form data to FormData for the server action
const formData = new FormData()
formData.append('companyId', String(data.companyId))
formData.append('title', data.title)
formData.append('link', data.link)
formData.append('description', data.description)
formData.append('location', data.location)
formData.append('imageURL', data.imageURL || '')
formData.append('salary', data.salary)
// Convert Date to ISO string for the server
const deadline = data.applicationDeadline instanceof Date
? data.applicationDeadline.toISOString().slice(0, 10)
: new Date(data.applicationDeadline).toISOString().slice(0, 10)
formData.append('applicationDeadline', deadline)
formData.append('minCGPA', String(data.minCGPA))
formData.append('minSSC', String(data.minSSC))
formData.append('minHSC', String(data.minHSC))
formData.append('allowDeadKT', String(data.allowDeadKT))
formData.append('allowLiveKT', String(data.allowLiveKT))
const result = await createJob(formData) const result = await createJob(formData)
if (result?.success) { if (result?.success) {
setSuccess(true) setSuccess(true)
@@ -128,7 +148,7 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
<Card className="shadow-xl border-0 bg-white/80 backdrop-blur-sm"> <Card className="shadow-xl border-0 bg-white/80 backdrop-blur-sm">
<CardContent className="p-8"> <CardContent className="p-8">
<Form {...form}> <Form {...form}>
<form action={handleSubmit} className="space-y-8"> <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-8">
{/* Success/Error Messages */} {/* Success/Error Messages */}
{success && ( {success && (
<Alert className="border-green-200 bg-green-50"> <Alert className="border-green-200 bg-green-50">
@@ -319,25 +339,24 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
control={form.control} control={form.control}
name="applicationDeadline" name="applicationDeadline"
render={({ field }) => { render={({ field }) => {
const getDisplayDate = (value: string) => { const getDisplayDate = (value: Date | string) => {
if (!value) return "" if (!value) return ""
try { try {
return format(new Date(value), "PPP") const date = value instanceof Date ? value : new Date(value)
return format(date, "PPP")
} catch { } catch {
return value return ""
} }
} }
const selectedDate = field.value ? new Date(field.value) : undefined const selectedDate = field.value ? (field.value instanceof Date ? field.value : new Date(field.value)) : undefined
const handleSelect = (date: Date | undefined) => { const handleSelect = (date: Date | undefined) => {
setTimeout(() => {
if (date) { if (date) {
field.onChange(date.toISOString().slice(0, 10)) field.onChange(date)
} else { } else {
field.onChange("") field.onChange(new Date())
} }
}, 0)
} }
return ( return (
@@ -354,9 +373,7 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
)} )}
type="button" type="button"
> >
{getDisplayDate(typeof field.value === "string" ? field.value : "") || ( {field.value ? getDisplayDate(field.value) : <span>Pick a date</span>}
<span>Pick a date</span>
)}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" /> <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button> </Button>
</FormControl> </FormControl>
@@ -367,7 +384,6 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
selected={selectedDate} selected={selectedDate}
onSelect={handleSelect} onSelect={handleSelect}
captionLayout="dropdown" captionLayout="dropdown"
key={typeof field.value === "string" ? field.value : "empty"}
/> />
</PopoverContent> </PopoverContent>
</Popover> </Popover>
@@ -445,7 +461,15 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
<FormItem> <FormItem>
<FormLabel className="text-sm font-medium text-gray-700">Minimum CGPA</FormLabel> <FormLabel className="text-sm font-medium text-gray-700">Minimum CGPA</FormLabel>
<FormControl> <FormControl>
<Input type="number" step="0.01" placeholder="0.00" {...field} className="h-11" /> <Input
type="number"
step="0.01"
placeholder="0.00"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => field.onChange(e.target.value ? parseFloat(e.target.value) : 0)}
className="h-11"
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -459,7 +483,15 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
<FormItem> <FormItem>
<FormLabel className="text-sm font-medium text-gray-700">Minimum SSC %</FormLabel> <FormLabel className="text-sm font-medium text-gray-700">Minimum SSC %</FormLabel>
<FormControl> <FormControl>
<Input type="number" step="0.01" placeholder="0.00" {...field} className="h-11" /> <Input
type="number"
step="0.01"
placeholder="0.00"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => field.onChange(e.target.value ? parseFloat(e.target.value) : 0)}
className="h-11"
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -473,7 +505,15 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] }
<FormItem> <FormItem>
<FormLabel className="text-sm font-medium text-gray-700">Minimum HSC %</FormLabel> <FormLabel className="text-sm font-medium text-gray-700">Minimum HSC %</FormLabel>
<FormControl> <FormControl>
<Input type="number" step="0.01" placeholder="0.00" {...field} className="h-11" /> <Input
type="number"
step="0.01"
placeholder="0.00"
{...field}
value={field.value?.toString() || ''}
onChange={(e) => field.onChange(e.target.value ? parseFloat(e.target.value) : 0)}
className="h-11"
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>

View File

@@ -6,12 +6,12 @@ export const jobSchema = z.object({
link: z.string().url('Invalid URL'), link: z.string().url('Invalid URL'),
description: z.string().min(1, 'Description is required'), description: z.string().min(1, 'Description is required'),
location: z.string().min(1, 'Location is required'), location: z.string().min(1, 'Location is required'),
imageURL: z.string().url('Invalid URL'), imageURL: z.string().url('Invalid URL').or(z.literal('')).optional(),
salary: z.string().min(1, 'Salary is required'), salary: z.string().min(1, 'Salary is required'),
applicationDeadline: z.date(), applicationDeadline: z.date(),
minCGPA: z.number().min(0), minCGPA: z.coerce.number().min(0, 'Minimum CGPA must be 0 or greater'),
minSSC: z.number().min(0), minSSC: z.coerce.number().min(0, 'Minimum SSC must be 0 or greater'),
minHSC: z.number().min(0), minHSC: z.coerce.number().min(0, 'Minimum HSC must be 0 or greater'),
allowDeadKT: z.boolean(), allowDeadKT: z.boolean(),
allowLiveKT: z.boolean(), allowLiveKT: z.boolean(),
}); });

View File

@@ -684,7 +684,7 @@ export default function ProfilePage() {
<SelectValue placeholder="Select branch" /> <SelectValue placeholder="Select branch" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="Computer Science">Computer Science</SelectItem> <SelectItem value="Computer Engineering">Computer Engineering</SelectItem>
<SelectItem value="Information Technology">Information Technology</SelectItem> <SelectItem value="Information Technology">Information Technology</SelectItem>
<SelectItem value="Electronics & Communication">Electronics & Communication</SelectItem> <SelectItem value="Electronics & Communication">Electronics & Communication</SelectItem>
<SelectItem value="Mechanical Engineering">Mechanical Engineering</SelectItem> <SelectItem value="Mechanical Engineering">Mechanical Engineering</SelectItem>

View File

@@ -22,7 +22,7 @@ export default function AcademicDetailsStep({ form }: { form: any }) {
]; ];
const branchOptions = [ const branchOptions = [
{ value: 'cse', label: 'Computer Science' }, { value: 'cse', label: 'Computer Engineering' },
{ value: 'it', label: 'Information Technology' }, { value: 'it', label: 'Information Technology' },
{ value: 'ece', label: 'Electronics & Communication' }, { value: 'ece', label: 'Electronics & Communication' },
{ value: 'mechanical', label: 'Mechanical' }, { value: 'mechanical', label: 'Mechanical' },