Skip to content

Commit b065771

Browse files
Zeff01claude
andcommitted
feat: enhance job management and application tracking system
Major updates to job listings and application workflow: - Add GitHub profile and years of experience fields to job applications - Convert referral system from dropdown to text input for flexibility - Filter out CEO/Founder from position selection dropdown - Fix application backend fetching to use real database data - Remove department column from hire table for cleaner UI - Add missing database columns (experience, github, years_of_experience, referred_by) - Update application display to show all new fields with proper icons - Fix resume download handling for Supabase storage URLs - Implement real-time status updates with server actions Database schema updates required: - ALTER TABLE job_applications ADD COLUMN experience TEXT - ALTER TABLE job_applications ADD COLUMN github VARCHAR(255) - ALTER TABLE job_applications ADD COLUMN years_of_experience INTEGER - ALTER TABLE job_applications ADD COLUMN referred_by UUID REFERENCES codev(id) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 48b77e3 commit b065771

29 files changed

Lines changed: 3904 additions & 736 deletions

‎CLAUDE.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ This is a Turborepo monorepo with pnpm workspaces containing multiple Next.js ap
9393
- `pnpm-workspace.yaml` - Workspace package definitions
9494
- `middleware.ts` - Authentication and route protection logic
9595
- `.env.example` files in each app for required environment variables
96+
- `database-schema.md` - Complete database schema documentation with table relationships
9697

9798
### Environment Setup
9899
1. Copy `.env.example` to `.env.local` in the target app directory
@@ -113,4 +114,14 @@ This is a Turborepo monorepo with pnpm workspaces containing multiple Next.js ap
113114
- Responsive design with mobile-first Tailwind CSS approach
114115

115116
### Package Naming Convention
116-
All shared packages must be prefixed with `@codevs/` (e.g., `@codevs/ui`, `@codevs/eslint-config`).
117+
All shared packages must be prefixed with `@codevs/` (e.g., `@codevs/ui`, `@codevs/eslint-config`).
118+
119+
### Database Schema
120+
The project uses Supabase (PostgreSQL) with the following key tables:
121+
- **Core**: `codev` (users), `roles` (permissions), `project`, `project_members`
122+
- **Job System**: `job_listings`, `job_applications`
123+
- **Attendance**: `attendance`, `attendance_summary`
124+
- **Gamification**: `skill_categories`, `codev_points`
125+
- **Kanban**: `kanban_board`, `kanban_column`, `kanban_sprint`, `task`
126+
127+
For detailed schema information, relationships, and SQL examples, see `database-schema.md` in the root directory.

‎apps/codebility/app/(marketing)/careers/_components/JobApplicationModal.tsx‎

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { useState } from "react";
3+
import { useState, useEffect } from "react";
44
import { useForm } from "react-hook-form";
55
import { zodResolver } from "@hookform/resolvers/zod";
66
import { z } from "zod";
@@ -17,16 +17,20 @@ import { Label } from "@codevs/ui/label";
1717
import { Textarea } from "@codevs/ui/textarea";
1818
import { useToast } from "@/components/ui/use-toast";
1919
import { JobListing } from "../_types/job-listings";
20+
import { createClientClientComponent } from "@/utils/supabase/client";
2021

2122
const applicationSchema = z.object({
2223
firstName: z.string().min(2, "First name must be at least 2 characters"),
2324
lastName: z.string().min(2, "Last name must be at least 2 characters"),
2425
email: z.string().email("Invalid email address"),
2526
phone: z.string().min(10, "Phone number must be at least 10 digits"),
2627
linkedIn: z.string().url("Invalid LinkedIn URL").optional().or(z.literal("")),
28+
github: z.string().url("Invalid GitHub URL").optional().or(z.literal("")),
2729
portfolio: z.string().url("Invalid portfolio URL").optional().or(z.literal("")),
30+
yearsOfExperience: z.string().min(1, "Years of experience is required"),
2831
coverLetter: z.string().min(50, "Cover letter must be at least 50 characters"),
2932
experience: z.string().min(20, "Please describe your relevant experience"),
33+
referredBy: z.string().optional(),
3034
resume: z.any().optional(),
3135
});
3236

@@ -52,10 +56,12 @@ export default function JobApplicationModal({
5256
handleSubmit,
5357
formState: { errors },
5458
reset,
59+
setValue,
5560
} = useForm<ApplicationFormData>({
5661
resolver: zodResolver(applicationSchema),
5762
});
5863

64+
5965
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
6066
const file = e.target.files?.[0];
6167
if (file) {
@@ -77,19 +83,48 @@ export default function JobApplicationModal({
7783
setIsSubmitting(true);
7884

7985
try {
80-
// Simulate API call
81-
await new Promise(resolve => setTimeout(resolve, 2000));
86+
const supabase = createClientClientComponent();
87+
88+
// Upload resume if provided
89+
let resumeUrl = null;
90+
if (resumeFile) {
91+
const fileExt = resumeFile.name.split('.').pop();
92+
const fileName = `${data.email.replace('@', '_')}_${Date.now()}.${fileExt}`;
93+
94+
const { data: uploadData, error: uploadError } = await supabase.storage
95+
.from('resumes')
96+
.upload(fileName, resumeFile);
97+
98+
if (uploadError) {
99+
console.error('Resume upload error:', uploadError);
100+
} else {
101+
resumeUrl = uploadData.path;
102+
}
103+
}
82104

83-
// Here you would typically send the application to your backend
84-
const applicationData = {
85-
...data,
86-
jobId: job.id,
87-
jobTitle: job.title,
88-
resume: resumeFile?.name,
89-
appliedAt: new Date().toISOString(),
90-
};
105+
// Save application to database
106+
const { error } = await supabase
107+
.from('job_applications')
108+
.insert({
109+
job_id: job.id,
110+
first_name: data.firstName,
111+
last_name: data.lastName,
112+
email: data.email,
113+
phone: data.phone,
114+
linkedin: data.linkedIn || null,
115+
github: data.github || null,
116+
portfolio: data.portfolio || null,
117+
years_of_experience: parseInt(data.yearsOfExperience),
118+
cover_letter: data.coverLetter,
119+
experience: data.experience,
120+
resume_url: resumeUrl,
121+
status: 'pending',
122+
notes: data.referredBy ? `Referred by: ${data.referredBy}` : 'Direct Application'
123+
});
91124

92-
console.log("Application submitted:", applicationData);
125+
if (error) {
126+
throw error;
127+
}
93128

94129
toast({
95130
title: "Application Submitted!",
@@ -100,6 +135,7 @@ export default function JobApplicationModal({
100135
setResumeFile(null);
101136
onClose();
102137
} catch (error) {
138+
console.error('Application submission error:', error);
103139
toast({
104140
title: "Submission failed",
105141
description: "Please try again later.",
@@ -189,6 +225,40 @@ export default function JobApplicationModal({
189225
<p className="text-sm text-red-400">{errors.phone.message}</p>
190226
)}
191227
</div>
228+
229+
<div className="grid grid-cols-2 gap-4">
230+
<div className="space-y-2">
231+
<Label htmlFor="yearsOfExperience" className="text-gray-300">
232+
Years of Experience *
233+
</Label>
234+
<Input
235+
id="yearsOfExperience"
236+
type="number"
237+
min="0"
238+
{...register("yearsOfExperience")}
239+
className="bg-gray-800 border-gray-700 text-white placeholder:text-gray-500"
240+
placeholder="5"
241+
/>
242+
{errors.yearsOfExperience && (
243+
<p className="text-sm text-red-400">{errors.yearsOfExperience.message}</p>
244+
)}
245+
</div>
246+
247+
<div className="space-y-2">
248+
<Label htmlFor="referredBy" className="text-gray-300">
249+
Referred By (Optional)
250+
</Label>
251+
<Input
252+
id="referredBy"
253+
{...register("referredBy")}
254+
className="bg-gray-800 border-gray-700 text-white placeholder:text-gray-500"
255+
placeholder="Name of referrer (if any)"
256+
/>
257+
{errors.referredBy && (
258+
<p className="text-sm text-red-400">{errors.referredBy.message}</p>
259+
)}
260+
</div>
261+
</div>
192262
</div>
193263

194264
{/* Professional Links */}
@@ -211,6 +281,22 @@ export default function JobApplicationModal({
211281
)}
212282
</div>
213283

284+
<div className="space-y-2">
285+
<Label htmlFor="github" className="text-gray-300">
286+
GitHub Profile
287+
</Label>
288+
<Input
289+
id="github"
290+
type="url"
291+
{...register("github")}
292+
className="bg-gray-800 border-gray-700 text-white placeholder:text-gray-500"
293+
placeholder="https://github.com/johndoe"
294+
/>
295+
{errors.github && (
296+
<p className="text-sm text-red-400">{errors.github.message}</p>
297+
)}
298+
</div>
299+
214300
<div className="space-y-2">
215301
<Label htmlFor="portfolio" className="text-gray-300">
216302
Portfolio/Website

0 commit comments

Comments
 (0)