# Fixes - 13th February 2026

## Files to Deploy

### 1. public/inactive_job.php (NEW)
- **Action:** Upload new file
- **Purpose:** Endpoint to set job status to Inactive (3)
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/inactive_job.php`

### 2. app/views/jobs.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Added Inactive/Delete action buttons (lines 434-451)
  - Added "Post a Job" button next to page title with gradient purple styling
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/jobs.php`

### 3. app/helpers/db_mapping.php (MODIFIED)
- **Action:** Replace file
- **Changes:** Fixed status codes 3-6 mapping, updated constants
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/helpers/db_mapping.php`

### 4. app/Services/ProductionDBAdapter.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Fixed mapStatusNameToCode() reverse mapping
  - Added audit logging to updateApplicationStatus() - tracks all status changes to audit_log table
  - Interview scheduling fallback now uses NotificationService (sends WhatsApp + Firebase push + in-app)
  - Interview cancellation now uses NotificationService (sends in-app + Firebase push)
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/Services/ProductionDBAdapter.php`

### 5. app/views/partials/candidates_table.php (NEW)
- **Action:** Upload new file
- **Purpose:** Shared partial for candidates table - ensures consistency between page load and AJAX tab switching
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/partials/candidates_table.php`

### 6. public/ajax/get-candidates-by-tab-production.php (MODIFIED)
- **Action:** Replace file
- **Changes:** Now uses shared partial instead of inline HTML - fixes missing Shortlist button on Auto-Match tab via AJAX
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/ajax/get-candidates-by-tab-production.php`

### 7. app/views/job_detail.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Added beautiful status update notification popups (replaces browser alert())
  - Fixed CSS class mismatch for confirm modal buttons
  - Fixed status column consistency: initial page load now shows clickable Scheduled button with date (same as AJAX)
  - Notification popup now shows candidate name, job title, and status change (from → to) instead of counters
  - Interview scheduling: past time slots for today are now disabled/greyed out with strikethrough
  - Fixed time slot ID mapping bug (4pm was saving as 5pm due to mismatched IDs with schedule_slot_master table)
  - Interview notes now saved to DB and displayed in interview details popover
  - Search is now tab-specific with debounced AJAX (searches within current tab as you type)
  - Share modal with social buttons (Facebook, X, WhatsApp, LinkedIn) and copy link
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/job_detail.php`

### 8. app/Services/BranchIOService.php (NEW)
- **Action:** Upload new file
- **Purpose:** Generates Branch.io app links (kaabil.app.link) for job sharing
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/Services/BranchIOService.php`

### 9. public/ajax/generate-share-link.php (NEW)
- **Action:** Upload new file
- **Purpose:** AJAX endpoint to generate app links for share modal
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/ajax/generate-share-link.php`

### 10. app/views/layout/navbar.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Fixed mobile navbar text visibility - "Company", "Interviews" etc. now visible in slide-out menu
  - Removed hover transforms on mobile (was causing elements to jump/shift left)
  - Fixed dropdown menu transforms on mobile view
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/layout/navbar.php`

### 11. app/views/add_job.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Employment Type: Removed Contract and Freelance options (now only Full-time, Part-time, Internship)
  - Salary Period: Removed Per Hour and Per Day options (now only Per Month, Per Year)
  - Added "As per Industry Standards" checkbox - disables salary fields only (not experience)
  - Salary Benchmark: Added "Per Year" label badge to clarify benchmark is annual
  - Salary Benchmark: Now shows LPA format (e.g., "₹5 LPA" instead of "₹5,00,000") for readability
  - Salary Benchmark: Added monthly equivalent display below each value (e.g., "₹41.7K/mo")
  - Post Job: Added beautiful confirmation popup with job details summary before posting
  - Post Job: Added full-screen loading overlay with spinner while posting
  - Post Job: Added success/error notification popups matching platform design
  - Profession/Category: Made searchable with Tom Select (type to filter)
  - Department: Made searchable with Tom Select (type to filter)
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/add_job.php`

### 12. app/views/edit_job.php (MODIFIED)
- **Action:** Replace file
- **Changes:** Same as add_job.php - Employment types, salary period, industry standard checkbox, and searchable dropdowns
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/edit_job.php`

### 13. public/ajax/get-skill-recommendations.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Fixed skill recommendations not showing when department selected
  - Department filter now falls back to profession-only if no skills found with department
  - Previously: profession+department returned 0 results because skill_mapping has department_id=0
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/ajax/get-skill-recommendations.php`

### 14. public/add_job.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Education dropdown now sorted by order_no (Below 10th first, then 10th, 12th, etc.)
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/add_job.php`

### 15. public/edit_job.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Education dropdown now sorted by order_no (same as add_job.php)
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/edit_job.php`

### 16. public/ajax/search-job-titles.php (NEW)
- **Action:** Upload new file
- **Purpose:** AJAX endpoint for job title autocomplete suggestions
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/ajax/search-job-titles.php`

### 17. app/views/interviews.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Refactored schedule interview modal with multi-step wizard matching job_detail.php
  - Added Tom Select for searchable candidate selection with remote search
  - Fixed Tom Select CSS overlap (removed form-control class conflicts)
  - Candidate dropdown shows name, phone, profession, and jobs applied count
  - Job dropdown now shows company name, position, location, and status
  - Jobs with scheduled interviews show ⏰ indicator
  - Reschedule detection: shows warning when selecting job with existing interview
  - Reschedule confirmation dialog before rescheduling
  - Interview locations loaded from job's company_jobs_location (no extra API call)
  - Step 1: Interview Type selection (Virtual/Face-to-Face buttons)
  - Step 2: Location selection from job locations or add custom
  - Step 3: 7-day date accordion with time slot grid
  - Step 4: Notes field
  - Summary section showing all selections before confirming
  - Fixed location.reload() bug (variable name conflict)
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/app/views/interviews.php`

### 18. public/get_candidates_for_interview.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - Added remote search support for Tom Select (search parameter)
  - Now returns phone number for display
  - Returns multiple preferred roles (up to 3) formatted as "Role1 · Role2 · Role3"
  - Added HAVING clause to ensure only candidates with actual job applications appear
  - **Multi-company fix:** Now fetches recruiter's companies first, then uses IN clause
  - This ensures consistent results between candidate search and job fetch
  - Returns jobs applied count
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/get_candidates_for_interview.php`

### 19. public/get_candidate_jobs.php (MODIFIED)
- **Action:** Replace file
- **Changes:**
  - **Multi-company fix:** Fetches recruiter's companies first, then uses IN clause
  - Simplified query - removed problematic GROUP BY with location fields
  - Locations now fetched separately per job (cleaner approach)
  - Added debug info: recruiter_id, companies_managed, jobs_found
  - Now returns application_id (users_job.id) for database operations
  - Added company_name and company_id from company_master
  - Returns all job_locations array for each job (for interview location picker)
  - Returns existing interview info (date, time, is_virtual, location)
  - Returns has_scheduled_interview flag for reschedule detection
- **Path on server:** `/var/www/tools.kaabil.cc/recruiter/public/get_candidate_jobs.php`

---

## Quick Deploy Commands

```bash
# Upload files
scp -i /Users/apple/Projects/kaam-ec2/kaabil-cc-key-pair.pem \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/inactive_job.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/jobs.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/job_detail.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/add_job.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/edit_job.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/interviews.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/helpers/db_mapping.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/Services/ProductionDBAdapter.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/Services/BranchIOService.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/partials/candidates_table.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/app/views/layout/navbar.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/ajax/get-candidates-by-tab-production.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/ajax/generate-share-link.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/ajax/get-skill-recommendations.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/ajax/search-job-titles.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/add_job.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/edit_job.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/get_candidates_for_interview.php \
  /Users/apple/Projects/kaabil-recruiter-new/recruiter/public/get_candidate_jobs.php \
  ubuntu@65.1.107.228:/tmp/

# SSH and move files
ssh -i /Users/apple/Projects/kaam-ec2/kaabil-cc-key-pair.pem ubuntu@65.1.107.228

sudo mkdir -p /var/www/tools.kaabil.cc/recruiter/app/views/partials/
sudo cp /tmp/inactive_job.php /var/www/tools.kaabil.cc/recruiter/public/
sudo cp /tmp/jobs.php /var/www/tools.kaabil.cc/recruiter/app/views/
sudo cp /tmp/job_detail.php /var/www/tools.kaabil.cc/recruiter/app/views/
sudo cp /tmp/add_job.php /var/www/tools.kaabil.cc/recruiter/app/views/
sudo cp /tmp/edit_job.php /var/www/tools.kaabil.cc/recruiter/app/views/
sudo cp /tmp/interviews.php /var/www/tools.kaabil.cc/recruiter/app/views/
sudo cp /tmp/navbar.php /var/www/tools.kaabil.cc/recruiter/app/views/layout/
sudo cp /tmp/db_mapping.php /var/www/tools.kaabil.cc/recruiter/app/helpers/
sudo cp /tmp/ProductionDBAdapter.php /var/www/tools.kaabil.cc/recruiter/app/Services/
sudo cp /tmp/BranchIOService.php /var/www/tools.kaabil.cc/recruiter/app/Services/
sudo cp /tmp/candidates_table.php /var/www/tools.kaabil.cc/recruiter/app/views/partials/
sudo cp /tmp/get-candidates-by-tab-production.php /var/www/tools.kaabil.cc/recruiter/public/ajax/
sudo cp /tmp/generate-share-link.php /var/www/tools.kaabil.cc/recruiter/public/ajax/
sudo cp /tmp/get-skill-recommendations.php /var/www/tools.kaabil.cc/recruiter/public/ajax/
sudo cp /tmp/search-job-titles.php /var/www/tools.kaabil.cc/recruiter/public/ajax/
sudo cp /tmp/add_job.php /var/www/tools.kaabil.cc/recruiter/public/
sudo cp /tmp/edit_job.php /var/www/tools.kaabil.cc/recruiter/public/
sudo cp /tmp/get_candidates_for_interview.php /var/www/tools.kaabil.cc/recruiter/public/
sudo cp /tmp/get_candidate_jobs.php /var/www/tools.kaabil.cc/recruiter/public/
sudo chmod 755 /var/www/tools.kaabil.cc/recruiter/public/inactive_job.php
```

---

## Summary of Changes

| Fix | Description |
|-----|-------------|
| Status mapping bug | Codes 3-6 were incorrectly mapped (3=Inactive, 4=Expired, 5=Deleted, 6=Draft) |
| Inactive button | Added to jobs.php for Active/Expired jobs |
| Delete button | Only shows for already Inactive/Closed jobs |
| Auto-Match tab buttons | Created shared partial - AJAX now shows same buttons as page reload (Shortlist, View, Chat, WhatsApp) |
| Status update UI | Beautiful popup notifications replace browser alert() - shows candidate name, job, and status change (from → to) |
| Confirm button colors | Fixed CSS class mismatch (.reject → .rejected, etc.) for confirmation modal buttons |
| Audit logging | Status changes now logged to audit_log table (who changed what status, when, for which candidate/job) |
| Status column consistency | Initial page load now shows clickable Scheduled button with date (same as AJAX-loaded tabs) |
| Interview notifications | Scheduling/cancellation now sends WhatsApp + Firebase push + in-app (not just in-app) |
| Past time slots | Interview scheduling modal disables time slots that have already passed for today |
| Time slot ID bug | Fixed mapping mismatch - 4pm was being saved as 5pm due to incorrect slot ID calculation |
| Interview notes | Notes now saved to `interview_feedback` column and displayed in interview details popover |
| Tab-specific search | Search now filters within current tab with 300ms debounce (no button needed) |
| Expanded search fields | Search now includes: name, email, phone, profession, experience, match %, status, applied date |
| Status tooltips | Hover over status badges to see when status was last updated (date & time) |
| Search numeric fix | Fixed search for numeric values (experience "12", match %) - HAVING clause was ANDing instead of ORing |
| Share modal | Beautiful share popup with Facebook, X, WhatsApp, LinkedIn buttons + Branch.io app link (kaabil.app.link) |
| Mobile navbar text | Fixed "Company", "Interviews" etc. not visible in mobile slide-out menu |
| Mobile navbar hover | Removed hover transforms on mobile - was causing elements to jump/shift left |
| Employment types | Reduced to 3 options: Full-time, Part-time, Internship (removed Contract, Freelance) |
| Salary period | Reduced to 2 options: Per Month, Per Year (removed Per Hour, Per Day) |
| Industry standard | "As per Industry Standards" checkbox - disables salary fields only (not experience), matching org-recruiter behavior |
| Salary benchmark clarity | Added "Per Year" badge, LPA format (₹5 LPA), and monthly equivalent below each value |
| Skill recommendations relevance | Skills now ranked by actual job usage (how often they appear in job postings for the profession), not alphabetically. Falls back to skill_mapping if no job data exists |
| Education dropdown order | Now sorted by order_no (Below 10th → 10th → 12th → Diploma → ITI → Graduate → Post Graduate) |
| Post Job confirmation | Beautiful confirmation popup shows job details (title, company, location) before posting |
| Post Job loading | Full-screen loading overlay with spinner while job is being posted |
| Post Job notifications | Success/error popups match platform design (same style as job_detail.php status updates) |
| Jobs page Post button | Added "Post a Job" button next to Jobs heading with gradient purple styling |
| Searchable dropdowns | Profession and Department fields now searchable with Tom Select (type to filter options) |
| Soft skills auto-add | Clicking soft skill in dropdown directly adds it (no Add button needed). Hard skills still require Add button for level selection |
| Industry standard save | is_industry_standard field now saved in add_job.php and edit_job.php |
| Industry standard display | job_detail.php now shows "As per Industry Standards" when is_industry_standard=1 instead of empty salary |
| Job title suggestions | Autocomplete dropdown for Job Title field showing unique titles from platform, ordered by usage count |
| Interviews modal wizard | Schedule interview modal refactored to multi-step wizard matching job_detail.php (type → location → date/time → notes) |
| Interviews candidate search | Tom Select searchable candidate dropdown with remote search, shows name, phone, profession, jobs applied |
| Interviews job selection | Job dropdown now shows company name, position, and location; only shows jobs candidate has applied for |
| Interviews time slots | 7-day date accordion with time slot grid, hour-to-slot ID mapping matching schedule_slot_master |
| Interviews Tom Select CSS fix | Fixed CSS overlap issue with form-control class that was breaking the dropdown styling |
| Interviews profession fallback | Candidate profession now falls back to user_job_role then 'Candidate' instead of 'Unknown Role' |
| Interviews location loading | Interview locations loaded from job's company_jobs_location table (no extra API call needed) |
| Interviews reschedule detection | Jobs with existing scheduled interviews now show ⏰ indicator and reschedule warning |
| Interviews reschedule flow | Full reschedule support: confirmation dialog, updates existing interview, notifies candidate of change |
| Interviews multiple roles | Candidate dropdown now shows up to 3 preferred roles formatted as "Role1 · Role2 · Role3" |
| Interviews candidate filter bug | Fixed bug where candidates appeared in dropdown but had no jobs - added HAVING clause to enforce at least 1 job application |
| Multi-company consistency | Both candidate search and job fetch now use same approach: fetch recruiter's companies first, then use IN clause for filtering |
| Interviews job query fix | Simplified get_candidate_jobs.php query - removed problematic GROUP BY with location fields, locations fetched separately |

---

## 16th February 2026 - Date Handling & Cancel Interview Fixes

### Deployed ✅

| File | Change | Status |
|------|--------|--------|
| `app/views/job_detail.php` | Fixed `toISOString()` date bug - dates were shifted back 1 day due to UTC conversion | ✅ Deployed |
| `app/views/kanban_production.php` | Fixed `toISOString()` date bug - replaced with local date function | ✅ Deployed |
| `app/views/kanban.php` | Fixed `toISOString()` date and datetime bugs (4 instances) | ✅ Deployed |
| `public/sysadmin/applicant-tracker.php` | Fixed `toISOString()` date bug in formatDate function | ✅ Deployed |
| `public/sysadmin/job-reports.php` | Fixed `toISOString()` date bug in formatDate function | ✅ Deployed |
| `public/cancel_interview.php` | Rewrote to use production `users_job` table instead of non-existent `interviews` table | ✅ Deployed |
| `public/api/kanban/cancel-interview.php` | Fixed notification format - uses correct `users_notification` column names | ✅ Deployed |
| `app/Services/ProductionDBAdapter.php` | Updated `cancelScheduledInterview()` to set `job_status=2` (shortlisted) on cancel | ✅ Deployed |

### Root Cause: JavaScript Date Issue

**Problem:** When scheduling interviews, selecting Feb 18 would save as Feb 17.

**Root Cause:** `toISOString()` converts dates to UTC, which shifts dates back by 1 day for timezones ahead of UTC (like IST at UTC+5:30).

**Wrong:**
```javascript
const dateStr = date.toISOString().split('T')[0]; // Converts to UTC - shifts date!
```

**Fixed:**
```javascript
function getLocalDateStr(date) {
    return date.getFullYear() + '-' +
           String(date.getMonth() + 1).padStart(2, '0') + '-' +
           String(date.getDate()).padStart(2, '0');
}
const dateStr = getLocalDateStr(date); // Uses local timezone
```

### Cancel Interview Fix

**Problem:** cancel_interview.php was using non-existent `interviews` table.

**Fix:** Rewrote to use `users_job` table with correct cancel logic from org-recruiter:
- Sets `job_status = 2` (shortlisted)
- Clears schedule fields (`schedule_call_date`, `schedule_slot_master_id`, etc.)
- Sends notification to candidate with correct `users_notification` columns

### Elasticsearch Sync for Job Delete/Inactive

| File | Change | Status |
|------|--------|--------|
| `app/Services/OrgRecruiterClient.php` | Added `changeJobStatus()` method to call org-recruiter API for ES sync | ✅ Deployed |
| `public/delete_job.php` | Now calls org-recruiter API before deleting - triggers ES sync via RabbitMQ | ✅ Deployed |
| `public/inactive_job.php` | Now calls org-recruiter API before inactivating - triggers ES sync via RabbitMQ | ✅ Deployed |

**Problem:** Deleted/inactive jobs in new recruiter still appeared on frontend (Elasticsearch not updated).

**Root Cause:** New recruiter only updated database directly, bypassing org-recruiter's RabbitMQ → ES sync pipeline.

**Fix:** Both delete_job.php and inactive_job.php now:
1. Call org-recruiter's `/App/V3/Company/changeJobStatus` API
2. API updates DB AND triggers RabbitMQ message
3. ES consumer picks up message and removes job from Elasticsearch
4. Falls back to direct DB update if API fails (but logs warning about ES not synced)
