463 lines
18 KiB
HTML
463 lines
18 KiB
HTML
<div class="career-layout">
|
|
<!-- Sidebar -->
|
|
<app-menu class="sidebar"></app-menu>
|
|
|
|
<!-- Main Content -->
|
|
<div class="career-content">
|
|
<!-- Header Section -->
|
|
<div class="career-header">
|
|
<div class="header-left">
|
|
<h1 class="page-title">Career Management</h1>
|
|
<p class="page-subtitle">Manage job postings and applications</p>
|
|
</div>
|
|
<div class="header-actions">
|
|
<button *ngIf="!showJobForm && !showApplications" class="btn-primary" (click)="showJobFormModal()">
|
|
<i class="fa fa-plus"></i>
|
|
<span>New Job</span>
|
|
</button>
|
|
<button *ngIf="showJobForm" class="btn-secondary" (click)="hideJobForm()">
|
|
<i class="fa fa-arrow-left"></i>
|
|
<span>Back to Jobs</span>
|
|
</button>
|
|
<button *ngIf="showApplications" class="btn-secondary" (click)="hideApplications()">
|
|
<i class="fa fa-arrow-left"></i>
|
|
<span>Back to Jobs</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats Bar -->
|
|
<div *ngIf="!showJobForm && !showApplications" class="stats-bar">
|
|
<div class="stat-item">
|
|
<div class="stat-icon stat-icon-blue">
|
|
<i class="fa fa-briefcase"></i>
|
|
</div>
|
|
<div class="stat-details">
|
|
<span class="stat-label">Total Jobs</span>
|
|
<span class="stat-value">{{ jobs.length }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-icon stat-icon-orange">
|
|
<i class="fa fa-file-alt"></i>
|
|
</div>
|
|
<div class="stat-details">
|
|
<span class="stat-label">Total Applications</span>
|
|
<span class="stat-value">{{ applications.length }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Job Form Section -->
|
|
<div *ngIf="showJobForm" class="form-container">
|
|
<div class="form-card">
|
|
<div class="form-card-header">
|
|
<h3>{{ editing ? 'Edit Job Posting' : 'Create New Job' }}</h3>
|
|
</div>
|
|
<div class="form-card-body">
|
|
<form [formGroup]="jobForm" (ngSubmit)="saveJob()">
|
|
<!-- Basic Information -->
|
|
<div class="form-section">
|
|
<h4 class="section-title">Basic Information</h4>
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="title">
|
|
<i class="fa fa-briefcase"></i>
|
|
Job Title
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="title"
|
|
class="form-input"
|
|
formControlName="title"
|
|
placeholder="e.g., Senior Software Engineer">
|
|
<div *ngIf="jobForm.get('title')?.invalid && jobForm.get('title')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Job title is required.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="department">
|
|
<i class="fa fa-building"></i>
|
|
Department
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="department"
|
|
class="form-input"
|
|
formControlName="department"
|
|
placeholder="e.g., Engineering">
|
|
<div *ngIf="jobForm.get('department')?.invalid && jobForm.get('department')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Department is required.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="location">
|
|
<i class="fa fa-map-marker-alt"></i>
|
|
Location
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="location"
|
|
class="form-input"
|
|
formControlName="location"
|
|
placeholder="e.g., New York, NY">
|
|
<div *ngIf="jobForm.get('location')?.invalid && jobForm.get('location')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Location is required.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="type">
|
|
<i class="fa fa-clock"></i>
|
|
Job Type
|
|
</label>
|
|
<select id="type" class="form-select" formControlName="type">
|
|
<option value="">Select job type</option>
|
|
<option value="Full-time">Full-time</option>
|
|
<option value="Part-time">Part-time</option>
|
|
<option value="Contract">Contract</option>
|
|
<option value="Rotational">Rotational</option>
|
|
<option value="Observership">Observership</option>
|
|
</select>
|
|
<div *ngIf="jobForm.get('type')?.invalid && jobForm.get('type')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Job type is required.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="experience">
|
|
<i class="fa fa-user-graduate"></i>
|
|
Experience Required
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="experience"
|
|
class="form-input"
|
|
formControlName="experience"
|
|
placeholder="e.g., MBBS + MS preferred, 3-5 years">
|
|
<div *ngIf="jobForm.get('experience')?.invalid && jobForm.get('experience')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Experience requirement is required.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="salary">
|
|
<i class="fa fa-dollar-sign"></i>
|
|
Salary
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="salary"
|
|
class="form-input"
|
|
formControlName="salary"
|
|
placeholder="e.g., As per hospital norms, $80,000 - $100,000">
|
|
<div *ngIf="jobForm.get('salary')?.invalid && jobForm.get('salary')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Salary information is required.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Job Details -->
|
|
<div class="form-section">
|
|
<h4 class="section-title">Job Details</h4>
|
|
|
|
<div class="form-group">
|
|
<label for="description">
|
|
<i class="fa fa-align-left"></i>
|
|
Job Description
|
|
</label>
|
|
<textarea
|
|
id="description"
|
|
class="form-textarea"
|
|
formControlName="description"
|
|
rows="4"
|
|
placeholder="Describe the role, responsibilities, and what makes this position unique..."></textarea>
|
|
<div *ngIf="jobForm.get('description')?.invalid && jobForm.get('description')?.touched" class="error-message">
|
|
<i class="fa fa-exclamation-circle"></i>
|
|
Job description is required.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="requirements">
|
|
<i class="fa fa-check-circle"></i>
|
|
Requirements
|
|
</label>
|
|
<textarea
|
|
id="requirements"
|
|
class="form-textarea"
|
|
formControlName="requirements"
|
|
rows="3"
|
|
placeholder="Bachelor's degree in relevant field, 3+ years experience, Strong communication skills..."></textarea>
|
|
<small class="form-hint">Separate multiple requirements with commas</small>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="responsibilities">
|
|
<i class="fa fa-tasks"></i>
|
|
Responsibilities
|
|
</label>
|
|
<textarea
|
|
id="responsibilities"
|
|
class="form-textarea"
|
|
formControlName="responsibilities"
|
|
rows="3"
|
|
placeholder="Lead team meetings, Develop strategic plans, Collaborate with stakeholders..."></textarea>
|
|
<small class="form-hint">Separate multiple responsibilities with commas</small>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div class="form-section">
|
|
<div class="checkbox-wrapper">
|
|
<input type="checkbox" id="isActive" formControlName="isActive" class="checkbox-input">
|
|
<label for="isActive" class="checkbox-label">
|
|
<span class="checkbox-custom"></span>
|
|
<span class="checkbox-text">
|
|
<i class="fa fa-eye"></i>
|
|
Active (visible to job seekers)
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<small class="form-hint">Uncheck to hide this job from public view</small>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn-primary" [disabled]="jobForm.invalid">
|
|
<i class="fa fa-save"></i>
|
|
<span>{{ editing ? 'Update Job' : 'Create Job' }}</span>
|
|
</button>
|
|
<button type="button" class="btn-cancel" (click)="resetJobForm()">
|
|
<i class="fa fa-times"></i>
|
|
<span>Cancel</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Applications View -->
|
|
<!-- Applications View -->
|
|
<div *ngIf="showApplications && selectedJobForApplications" class="applications-container">
|
|
<div class="applications-card">
|
|
<div class="applications-header">
|
|
<div class="header-info">
|
|
<h3>Applications</h3>
|
|
<p>{{ selectedJobForApplications.title }}</p>
|
|
</div>
|
|
<span class="application-count">{{ applications.length }} {{ applications.length === 1 ? 'Application' : 'Applications' }}</span>
|
|
</div>
|
|
|
|
<div class="applications-body">
|
|
<div *ngIf="applications.length > 0" class="table-wrapper">
|
|
<table class="applications-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Applicant</th>
|
|
<th>Contact</th>
|
|
<th>Experience</th>
|
|
<th>Resume</th>
|
|
<th>Status</th>
|
|
<th>Applied Date</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr *ngFor="let application of applications; let i = index">
|
|
<td>
|
|
<div class="applicant-info">
|
|
<div class="applicant-avatar">
|
|
<i class="fa fa-user"></i>
|
|
</div>
|
|
<span class="applicant-name">{{ application.fullName }}</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="contact-info">
|
|
<div class="contact-item">
|
|
<i class="fa fa-envelope"></i>
|
|
<span>{{ application.email }}</span>
|
|
</div>
|
|
<div class="contact-item">
|
|
<i class="fa fa-phone"></i>
|
|
<span>{{ application.phone }}</span>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="experience-badge">{{ application.experience }}</span>
|
|
</td>
|
|
<td>
|
|
<div class="resume-actions" *ngIf="hasResume(application)">
|
|
<button class="btn-resume btn-view" (click)="viewResume(application)" title="View Resume">
|
|
<i class="fa fa-eye"></i>
|
|
<span>View</span>
|
|
</button>
|
|
<button class="btn-resume btn-download" (click)="downloadResume(application)" title="Download Resume">
|
|
<i class="fa fa-download"></i>
|
|
<span>Download</span>
|
|
</button>
|
|
</div>
|
|
<div class="no-resume" *ngIf="!hasResume(application)">
|
|
<i class="fa fa-file-excel"></i>
|
|
<span>No Resume</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="status-badge" [ngClass]="getStatusBadgeClass(application.status || 'pending')">
|
|
{{ application.status || 'PENDING' }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="date-text">{{ application.createdDate | date:'MMM d, y' }}</span>
|
|
</td>
|
|
<td>
|
|
<div class="action-buttons">
|
|
<div class="dropdown" [class.active]="activeDropdownIndex === i">
|
|
<button class="btn-action btn-status" (click)="toggleDropdown(i, $event)">
|
|
<i class="fa fa-edit"></i>
|
|
<span>Status</span>
|
|
<i class="fa fa-chevron-down"></i>
|
|
</button>
|
|
<div class="dropdown-menu">
|
|
<button class="dropdown-item" (click)="updateApplicationStatus(application, 'PENDING')">
|
|
<i class="fa fa-clock"></i>
|
|
Pending
|
|
</button>
|
|
<button class="dropdown-item" (click)="updateApplicationStatus(application, 'REVIEWED')">
|
|
<i class="fa fa-eye"></i>
|
|
Reviewed
|
|
</button>
|
|
<button class="dropdown-item" (click)="updateApplicationStatus(application, 'SHORTLISTED')">
|
|
<i class="fa fa-star"></i>
|
|
Shortlisted
|
|
</button>
|
|
<button class="dropdown-item" (click)="updateApplicationStatus(application, 'INTERVIEWED')">
|
|
<i class="fa fa-comments"></i>
|
|
Interviewed
|
|
</button>
|
|
<button class="dropdown-item" (click)="updateApplicationStatus(application, 'HIRED')">
|
|
<i class="fa fa-check-circle"></i>
|
|
Hired
|
|
</button>
|
|
<button class="dropdown-item item-danger" (click)="updateApplicationStatus(application, 'REJECTED')">
|
|
<i class="fa fa-times-circle"></i>
|
|
Rejected
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<button class="btn-action btn-delete" (click)="deleteApplication(application)">
|
|
<i class="fa fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Empty State for Applications -->
|
|
<div *ngIf="applications.length === 0" class="empty-state">
|
|
<div class="empty-icon">
|
|
<i class="fa fa-inbox"></i>
|
|
</div>
|
|
<h3>No applications yet</h3>
|
|
<p>This job hasn't received any applications</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Jobs List -->
|
|
<div *ngIf="!showJobForm && !showApplications" class="jobs-list-container">
|
|
<div *ngIf="jobs.length > 0" class="table-wrapper">
|
|
<table class="jobs-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Job Details</th>
|
|
<th>Department</th>
|
|
<th>Location</th>
|
|
<th>Type</th>
|
|
<th>Status</th>
|
|
<th>Applications</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr *ngFor="let job of jobs">
|
|
<td>
|
|
<div class="job-details">
|
|
<h4>{{ job.title }}</h4>
|
|
<p>{{ job.experience }}</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="department-text">{{ job.department }}</span>
|
|
</td>
|
|
<td>
|
|
<div class="location-cell">
|
|
<i class="fa fa-map-marker-alt"></i>
|
|
<span>{{ job.location }}</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="type-badge">{{ job.type }}</span>
|
|
</td>
|
|
<td>
|
|
<span class="status-badge" [class.status-active]="job.isActive" [class.status-inactive]="!job.isActive">
|
|
<i class="fa" [class.fa-check-circle]="job.isActive" [class.fa-times-circle]="!job.isActive"></i>
|
|
{{ job.isActive ? 'Active' : 'Inactive' }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<button class="btn-applications" (click)="viewApplications(job)">
|
|
<i class="fa fa-file-alt"></i>
|
|
<span>View</span>
|
|
<span class="app-count">{{ getApplicationCount(job.id) }}</span>
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<div class="action-buttons">
|
|
<button class="btn-action btn-edit" (click)="editJob(job)" title="Edit">
|
|
<i class="fa fa-edit"></i>
|
|
</button>
|
|
<button class="btn-action btn-delete" (click)="deleteJob(job)" title="Delete">
|
|
<i class="fa fa-trash-alt"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Empty State for Jobs -->
|
|
<div *ngIf="jobs.length === 0" class="empty-state">
|
|
<div class="empty-icon">
|
|
<i class="fa fa-briefcase"></i>
|
|
</div>
|
|
<h3>No jobs posted yet</h3>
|
|
<p>Get started by creating your first job posting</p>
|
|
<button class="btn-primary" (click)="showJobFormModal()">
|
|
<i class="fa fa-plus"></i>
|
|
<span>Create First Job</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> |