Compare commits
9 Commits
2153de3446
...
3a1307a7a4
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a1307a7a4 | |||
| e9800a7ec7 | |||
| 0bfbd80e15 | |||
| 973497097a | |||
| f45e9b75c4 | |||
| b158cb3e7b | |||
| f168ab4ba8 | |||
| a3348e1199 | |||
| 3749fbd3ef |
@ -2804,3 +2804,51 @@ class OnsiteInterviewForm(forms.Form):
|
||||
# instance.save()
|
||||
|
||||
# return instance
|
||||
|
||||
class ScheduledInterviewForm(forms.Form):
|
||||
topic = forms.CharField(
|
||||
max_length=255,
|
||||
required=False,
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': 'e.g., Interview Topic'
|
||||
}),
|
||||
label=_('Interview Topic')
|
||||
)
|
||||
start_time = forms.DateTimeField(
|
||||
widget=forms.DateTimeInput(attrs={
|
||||
'class': 'form-control',
|
||||
'type': 'datetime-local',
|
||||
'required': True
|
||||
}),
|
||||
label=_('Start Time')
|
||||
)
|
||||
duration = forms.IntegerField(
|
||||
min_value=1,
|
||||
required=False,
|
||||
widget=forms.NumberInput(attrs={
|
||||
'class': 'form-control',
|
||||
'placeholder': 'Duration in minutes'
|
||||
}),
|
||||
label=_('Duration (minutes)')
|
||||
)
|
||||
|
||||
def clean_start_time(self):
|
||||
"""Validate start time is not in the past"""
|
||||
start_time = self.cleaned_data.get('start_time')
|
||||
if start_time and start_time < timezone.now():
|
||||
raise forms.ValidationError(_('Start time cannot be in the past.'))
|
||||
return start_time
|
||||
|
||||
class ScheduledInterviewUpdateStatusForm(forms.Form):
|
||||
status = forms.ChoiceField(
|
||||
choices=ScheduledInterview.InterviewStatus.choices,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'form-control',
|
||||
'required': True
|
||||
}),
|
||||
label=_('Interview Status')
|
||||
)
|
||||
class Meta:
|
||||
model = ScheduledInterview
|
||||
fields = ['status']
|
||||
@ -391,18 +391,18 @@ class JobPosting(Base):
|
||||
@property
|
||||
def all_applications(self):
|
||||
# 1. Define the safe JSON extraction and conversion expression
|
||||
safe_score_expression = Cast(
|
||||
safe_score_expression = Cast(
|
||||
Coalesce(
|
||||
# Extract the score explicitly as a text string (KeyTextTransform)
|
||||
KeyTextTransform(
|
||||
'match_score',
|
||||
'match_score',
|
||||
KeyTransform('analysis_data_en', 'ai_analysis_data')
|
||||
),
|
||||
Value('0'), # Replace SQL NULL (from missing score) with the string '0'
|
||||
),
|
||||
output_field=IntegerField() # Cast the resulting string ('90' or '0') to an integer
|
||||
)
|
||||
|
||||
|
||||
# 2. Annotate the score using the safe expression
|
||||
return self.applications.annotate(
|
||||
sortable_score=safe_score_expression
|
||||
@ -440,7 +440,7 @@ class JobPosting(Base):
|
||||
@property
|
||||
def all_applications_count(self):
|
||||
return self.all_applications.count()
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def screening_applications_count(self):
|
||||
@ -795,7 +795,7 @@ class Application(Base):
|
||||
@property
|
||||
def resume_data_en(self):
|
||||
return self.ai_analysis_data.get("resume_data_en", {})
|
||||
|
||||
|
||||
@property
|
||||
def resume_data_ar(self):
|
||||
return self.ai_analysis_data.get("resume_data_ar", {})
|
||||
@ -882,7 +882,7 @@ class Application(Base):
|
||||
def recommendation(self) -> str:
|
||||
"""9. Provide a detailed final recommendation for the candidate."""
|
||||
return self.analysis_data_en.get("recommendation", "")
|
||||
|
||||
|
||||
#for arabic
|
||||
|
||||
@property
|
||||
@ -939,7 +939,7 @@ class Application(Base):
|
||||
def recommendation_ar(self) -> str:
|
||||
"""9. Provide a detailed final recommendation for the candidate."""
|
||||
return self.analysis_data_ar.get("recommendation", "")
|
||||
|
||||
|
||||
|
||||
# ====================================================================
|
||||
# 🔄 HELPER METHODS
|
||||
@ -1334,6 +1334,7 @@ class Interview(Base):
|
||||
)
|
||||
password = models.CharField(max_length=20, blank=True, null=True)
|
||||
zoom_gateway_response = models.JSONField(blank=True, null=True)
|
||||
details_url = models.JSONField(blank=True, null=True)
|
||||
participant_video = models.BooleanField(default=True)
|
||||
join_before_host = models.BooleanField(default=False)
|
||||
host_email = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
@ -363,7 +363,7 @@ def safe_cast_to_float(value, default=0.0):
|
||||
# return
|
||||
# # Ensure the result is parsed as a Python dict (if ai_handler returns a JSON string)
|
||||
# data = result['data']
|
||||
|
||||
|
||||
# if isinstance(data, str):
|
||||
# data = json.loads(data)
|
||||
# print(data)
|
||||
@ -634,7 +634,7 @@ def handle_resume_parsing_and_scoring(pk: int):
|
||||
logger.error(f"AI handler returned error for candidate {instance.pk}")
|
||||
print(f"AI handler returned error for candidate {instance.pk}")
|
||||
return
|
||||
|
||||
|
||||
# Ensure the result is parsed as a Python dict
|
||||
data = result['data']
|
||||
if isinstance(data, str):
|
||||
@ -711,8 +711,8 @@ def create_interview_and_meeting(
|
||||
password=result["meeting_details"]["password"],
|
||||
location_type="Remote"
|
||||
)
|
||||
schedule.interviews = interview
|
||||
schedule.status = "Remote"
|
||||
schedule.interview = interview
|
||||
schedule.status = "scheduled"
|
||||
|
||||
schedule.save()
|
||||
|
||||
|
||||
@ -205,13 +205,11 @@ urlpatterns = [
|
||||
views_frontend.test_source_connection,
|
||||
name="test_source_connection",
|
||||
),
|
||||
|
||||
|
||||
# path(
|
||||
# "jobs/<slug:slug>/<int:application_id>/reschedule_meeting_for_application/<int:meeting_id>/",
|
||||
# views.reschedule_meeting_for_application,
|
||||
# name="reschedule_meeting_for_application",
|
||||
# ),
|
||||
path(
|
||||
"jobs/<slug:slug>/reschedule_meeting_for_application/",
|
||||
views.reschedule_meeting_for_application,
|
||||
name="reschedule_meeting_for_application",
|
||||
),
|
||||
path(
|
||||
"jobs/<slug:slug>/update_application_exam_status/",
|
||||
views.update_application_exam_status,
|
||||
@ -573,11 +571,13 @@ urlpatterns = [
|
||||
# Interview URLs
|
||||
path('interviews/', views.interview_list, name='interview_list'),
|
||||
path('interviews/<slug:slug>/', views.interview_detail, name='interview_detail'),
|
||||
path('interviews/<slug:slug>/update_interview_status', views.update_interview_status, name='update_interview_status'),
|
||||
path('interviews/<slug:slug>/cancel_interview_for_application', views.cancel_interview_for_application, name='cancel_interview_for_application'),
|
||||
|
||||
# Interview Creation URLs
|
||||
path('interviews/create/<slug:candidate_slug>/', views.interview_create_type_selection, name='interview_create_type_selection'),
|
||||
path('interviews/create/<slug:candidate_slug>/remote/', views.interview_create_remote, name='interview_create_remote'),
|
||||
path('interviews/create/<slug:candidate_slug>/onsite/', views.interview_create_onsite, name='interview_create_onsite'),
|
||||
path('interviews/create/<slug:application_slug>/', views.interview_create_type_selection, name='interview_create_type_selection'),
|
||||
path('interviews/create/<slug:application_slug>/remote/', views.interview_create_remote, name='interview_create_remote'),
|
||||
path('interviews/create/<slug:application_slug>/onsite/', views.interview_create_onsite, name='interview_create_onsite'),
|
||||
path('interviews/<slug:job_slug>/get_interview_list', views.get_interview_list, name='get_interview_list'),
|
||||
|
||||
# # --- SCHEDULED INTERVIEW URLS (New Centralized Management) ---
|
||||
|
||||
@ -586,7 +586,7 @@ def update_meeting(instance, updated_data):
|
||||
if result["status"] == "success":
|
||||
# Fetch the latest details from Zoom after successful update
|
||||
details_result = get_zoom_meeting_details(instance.meeting_id)
|
||||
|
||||
|
||||
if details_result["status"] == "success":
|
||||
zoom_details = details_result["meeting_details"]
|
||||
# Update instance with fetched details
|
||||
@ -594,7 +594,7 @@ def update_meeting(instance, updated_data):
|
||||
instance.topic = zoom_details.get("topic", instance.topic)
|
||||
|
||||
instance.duration = zoom_details.get("duration", instance.duration)
|
||||
instance.details_url = zoom_details.get("join_url", instance.details_url)
|
||||
# instance.details_url = zoom_details.get("join_url", instance.details_url)
|
||||
instance.password = zoom_details.get("password", instance.password)
|
||||
# Corrected status assignment: instance.status, not instance.password
|
||||
instance.status = zoom_details.get("status")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="fas fa-building me-2"></i>
|
||||
{% blocktrans %}Create Onsite Interview for {{ application.name }}{% endblocktrans %}
|
||||
Create Onsite Interview for {{ application.name }}
|
||||
</h4>
|
||||
<a href="{% url 'interview_create_type_selection' application.slug %}"
|
||||
class="btn btn-outline-primary">
|
||||
@ -21,8 +21,8 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">
|
||||
{% blocktrans %}Schedule an onsite interview for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.{% endblocktrans %}
|
||||
Schedule an onsite interview for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.
|
||||
</p>
|
||||
|
||||
{% if messages %}
|
||||
@ -34,7 +34,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{% url 'interview_create_onsite' application_slug=application.slug %}">
|
||||
<form method="post" action="{% url 'interview_create_onsite' application.slug %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row">
|
||||
@ -100,36 +100,8 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% comment %} <div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.interviewer.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-user me-1"></i>
|
||||
Interviewer
|
||||
</label>
|
||||
{{ form.interviewer }}
|
||||
{% if form.interviewer.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.interviewer.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div> {% endcomment %}
|
||||
</div>
|
||||
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="{{ form.topic.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-comment me-1"></i>
|
||||
Meeting Topic
|
||||
</label>
|
||||
{{ form.topic }}
|
||||
{% if form.topic.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.topic.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> {% endcomment %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.physical_address.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-map-marker-alt me-1"></i>
|
||||
@ -159,48 +131,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% comment %} <div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.floor_number.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-layer-group me-1"></i>
|
||||
Floor Number
|
||||
</label>
|
||||
{{ form.floor_number }}
|
||||
{% if form.floor_number.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.floor_number.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div> {% endcomment %}
|
||||
{% comment %} </div> {% endcomment %}
|
||||
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="{{ form.parking_info.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-parking me-1"></i>
|
||||
Parking Information
|
||||
</label>
|
||||
{{ form.parking_info }}
|
||||
{% if form.parking_info.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.parking_info.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> {% endcomment %}
|
||||
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="{{ form.notes.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-sticky-note me-1"></i>
|
||||
Notes
|
||||
</label>
|
||||
{{ form.notes }}
|
||||
{% if form.notes.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.notes.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> {% endcomment %}
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="submit" class="btn btn-main-action">
|
||||
<i class="fas fa-save me-2"></i>
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="fas fa-video me-2"></i>
|
||||
{% blocktrans %}Create Remote Interview for {{ application.name }}{% endblocktrans %}
|
||||
Create Remote Interview for {{ application.name }}
|
||||
</h4>
|
||||
<a href="{% url 'interview_create_type_selection' application.slug %}"
|
||||
class="btn btn-outline-primary">
|
||||
@ -21,8 +21,8 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">
|
||||
{% blocktrans %}Schedule a remote interview for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.{% endblocktrans %}
|
||||
Schedule a remote interview for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.
|
||||
</p>
|
||||
|
||||
{% if messages %}
|
||||
@ -34,7 +34,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{% url 'interview_create_remote' application_slug=application.slug %}">
|
||||
<form method="post" action="{% url 'interview_create_remote' application.slug %}">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
@ -11,17 +11,17 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="fas fa-calendar-plus me-2"></i>
|
||||
{% blocktrans %}Create Interview for {{ application.name }}{% endblocktrans %}
|
||||
Create Interview for {{ application.name }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body" hx-boost="true" hx-push-url="false" hx-select=".card-body" hx-swap="innerHTML" hx-target="#candidateviewModalBody">
|
||||
<p class="text-muted mb-3">
|
||||
{% blocktrans %}Select the type of interview you want to schedule for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.{% endblocktrans %}
|
||||
Select the type of interview you want to schedule for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.
|
||||
</p>
|
||||
|
||||
<div class="d-grid gap-3" style="grid-template-columns: 1fr 1fr;">
|
||||
<a href="{% url 'interview_create_remote' application_slug=application.slug %}"
|
||||
<a href="{% url 'interview_create_remote' application.slug %}"
|
||||
class="btn btn-outline-primary btn-lg h-100 p-3 text-decoration-none">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-video me-2"></i>
|
||||
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'interview_create_onsite' application_slug=application.slug %}"
|
||||
<a href="{% url 'interview_create_onsite' application.slug %}"
|
||||
class="btn btn-outline-primary btn-lg h-100 p-3 text-decoration-none">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-building me-2"></i>
|
||||
@ -42,7 +42,7 @@
|
||||
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<a href="{% url 'applications_interview_view' slug=job.slug %}"
|
||||
<a href="#"
|
||||
class="btn btn-outline-primary">
|
||||
<i class="fas fa-arrow-left me-2"></i>
|
||||
{% trans "Back to application List" %}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static i18n %}
|
||||
{% load static i18n crispy_forms_tags %}
|
||||
|
||||
{% block title %}{{ interview.application.name }} - {% trans "Interview Details" %} - ATS{% endblock %}
|
||||
|
||||
@ -224,6 +224,11 @@
|
||||
<a href="{% url 'job_detail' interview.job.slug %}" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-briefcase me-1"></i> {% trans "View Job" %}
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-secondary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#statusModal">
|
||||
<i class="fas fa-redo-alt me-1"></i> {% trans "Update Interview status" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -245,7 +250,7 @@
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#candidateModal"
|
||||
hx-get="{% url 'candidate_criteria_view_htmx' interview.application.pk %}"
|
||||
hx-get="#"
|
||||
hx-target="#candidateModalBody">
|
||||
<i class="fas fa-eye me-1"></i> {% trans "AI Scoring" %}
|
||||
</button>
|
||||
@ -323,6 +328,13 @@
|
||||
<span class="detail-label">{% trans "Duration:" %}</span>
|
||||
<span class="detail-value">{{ interview.interview.duration }} {% trans "minutes" %}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">{% trans "Status:" %}</span>
|
||||
<span class="detail-value">
|
||||
<span class="badge bg-primary-theme">
|
||||
{{ interview.status }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
@ -643,21 +655,21 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="#">
|
||||
<form method="post" action="{% url 'reschedule_meeting_for_application' interview.slug %}">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<label for="new_date" class="form-label">{% trans "New Date" %}</label>
|
||||
<input type="date" class="form-control" id="new_date" name="new_date" required>
|
||||
{{reschedule_form|crispy}}
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="topic" class="form-label">{% trans "topic" %}</label>
|
||||
<input type="text" class="form-control" id="topic" name="topic" value="{{interview.interview.topic}}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_time" class="form-label">{% trans "New Time" %}</label>
|
||||
<input type="time" class="form-control" id="new_time" name="new_time" required>
|
||||
<label for="start_time" class="form-label">{% trans "Start Time" %}</label>
|
||||
<input type="datetime-local" class="form-control" id="start_time" name="start_time" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="reschedule_reason" class="form-label">{% trans "Reason for Rescheduling" %}</label>
|
||||
<textarea class="form-control" id="reschedule_reason" name="reason" rows="3"
|
||||
placeholder="{% trans 'Optional: Provide reason for rescheduling' %}"></textarea>
|
||||
</div>
|
||||
<label for="duration" class="form-label">{% trans "Duration" %}</label>
|
||||
<input type="number" class="form-control" id="duration" name="duration" required>
|
||||
</div> {% endcomment %}
|
||||
<button type="submit" class="btn btn-main-action btn-sm">
|
||||
<i class="fas fa-redo-alt me-1"></i> {% trans "Reschedule" %}
|
||||
</button>
|
||||
@ -678,17 +690,12 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="#">
|
||||
<form method="post" action="{% url 'cancel_interview_for_application' interview.slug %}">
|
||||
{% csrf_token %}
|
||||
<div class="alert alert-warning">
|
||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
||||
{% trans "Are you sure you want to cancel this interview? This action cannot be undone." %}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cancel_reason" class="form-label">{% trans "Reason for Cancellation" %}</label>
|
||||
<textarea class="form-control" id="cancel_reason" name="reason" rows="3" required
|
||||
placeholder="{% trans 'Please provide a reason for cancellation' %}"></textarea>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-danger btn-sm">
|
||||
<i class="fas fa-times me-1"></i> {% trans "Cancel Interview" %}
|
||||
@ -739,6 +746,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Update Status Modal -->
|
||||
<div class="modal fade" id="statusModal" tabindex="-1" aria-labelledby="statusModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content kaauh-card">
|
||||
<div class="modal-header" style="border-bottom: 1px solid var(--kaauh-border);">
|
||||
<h5 class="modal-title" id="statusModalLabel" style="color: var(--kaauh-teal-dark);">
|
||||
<i class="fas fa-sync-alt me-2"></i> {% trans "Update Interview Status" %}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="{% url 'update_interview_status' interview.slug %}">
|
||||
{% csrf_token %}
|
||||
{{interview_status_form|crispy}}
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-main-action">
|
||||
<i class="fas fa-check me-1"></i> {% trans "Update Status" %}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
{% trans "Close" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block customJS %}
|
||||
|
||||
@ -230,9 +230,8 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{meetings}}
|
||||
{# Using 'meetings' based on the context_object_name provided #}
|
||||
{% if meetings %}
|
||||
{% if interviews %}
|
||||
<div id="meetings-list">
|
||||
{# View Switcher (kept the name for simplicity) #}
|
||||
{% include "includes/_list_view_switcher.html" with list_id="meetings-list" %}
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
<table class="table candidate-table align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40%;"><i class="fas fa-user me-1"></i> {% trans "Topic" %}</th>
|
||||
<th style="width: 35%;"><i class="fas fa-user me-1"></i> {% trans "Topic" %}</th>
|
||||
<th style="width: 15%;"><i class="fas fa-calendar-alt me-1"></i> {% trans "Date" %}</th>
|
||||
<th style="width: 5%;"><i class="fas fa-map-marker-alt me-1"></i> {% trans "Duration" %}</th>
|
||||
<th style="width: 10%;"><i class="fas fa-map-marker-alt me-1"></i> {% trans "Location" %}</th>
|
||||
<th style="width: 10%;"><i class="fas fa-hourglass-half me-1"></i> {% trans "Duration" %}</th>
|
||||
<th style="width: 10%;"><i class="fas fa-location-dot me-1"></i> {% trans "Location" %}</th>
|
||||
<th style="width: 10%;"><i class="fas fa-info-circle me-1"></i> {% trans "Status" %}</th>
|
||||
<th style="width: 10%;"><i class="fas fa-ellipsis-h me-1"></i> {% trans "Actions" %}</th>
|
||||
<th style="width: 10%;"> {% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@ -287,7 +287,7 @@
|
||||
|
||||
<tr class="nested-metrics-row">
|
||||
<th scope="col">{% trans "All" %}</th>
|
||||
<th scope="col">{% trans "Screened" %}</th>
|
||||
<th scope="col">{% trans "Screening" %}</th>
|
||||
<th scope="col">{% trans "Exam" %}</th>
|
||||
<th scope="col">{% trans "Interview" %}</th>
|
||||
<th scope="col">{% trans "DOC Review" %}</th>
|
||||
|
||||
@ -227,7 +227,7 @@
|
||||
<div class="vr" style="height: 28px;"></div>
|
||||
|
||||
{# Form 2: Schedule Interviews #}
|
||||
<form hx-boost="true" hx-include="#application-form" action="{% url 'schedule_interviews' job.slug %}" method="get" class="action-group">
|
||||
<form hx-boost="true" hx-include="#application-form" action="#" method="get" class="action-group">
|
||||
<button type="submit" class="btn btn-main-action btn-sm">
|
||||
<i class="fas fa-calendar-plus me-1"></i> {% trans "Schedule Interviews" %}
|
||||
</button>
|
||||
@ -266,12 +266,13 @@
|
||||
</th>
|
||||
<th style="width: 13%"><i class="fas fa-user me-1"></i> {% trans "Name" %}</th>
|
||||
<th style="width: 15%"><i class="fas fa-phone me-1"></i> {% trans "Contact" %}</th>
|
||||
<th style="width: 15%"><i class="fas fa-tag me-1"></i> {% trans "Topic" %}</th>
|
||||
{% comment %} <th style="width: 15%"><i class="fas fa-tag me-1"></i> {% trans "Topic" %}</th>
|
||||
<th style="width: 15%"><i class="fas fa-clock me-1"></i> {% trans "Duration" %}</th>
|
||||
<th style="width: 10%"><i class="fas fa-calendar me-1"></i> {% trans "Meeting Date" %}</th>
|
||||
<th style="width: 7%"><i class="fas fa-video me-1"></i> {% trans "Link" %}</th>
|
||||
<th style="width: 8%"><i class="fas fa-check-circle me-1"></i> {% trans "Meeting Status" %}</th>
|
||||
<th style="width: 5%"><i class="fas fa-check-circle me-1"></i> {% trans "Interview Result"%}</th>
|
||||
<th style="width: 8%"><i class="fas fa-check-circle me-1"></i> {% trans "Meeting Status" %}</th> {% endcomment %}
|
||||
<th style="width: 15%"><i class="fas fa-check-circle me-1"></i> {% trans "Interview Result"%}</th>
|
||||
<th style="width: 15%"><i class="fas fa-check-circle me-1"></i> {% trans "Interview List"%}</th>
|
||||
<th style="width: 10%"><i class="fas fa-cog me-1"></i> {% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -301,7 +302,7 @@
|
||||
<i class="fas fa-phone me-1"></i> {{ application.phone }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="application-details text-muted">
|
||||
{% comment %} <td class="application-details text-muted">
|
||||
{% if application.get_latest_meeting %}
|
||||
{{ application.get_latest_meeting }}
|
||||
{% else %}
|
||||
@ -323,8 +324,8 @@
|
||||
<span class="text-muted">--</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td>
|
||||
</td> {% endcomment %}
|
||||
{% comment %} <td>
|
||||
{% with latest_meeting=application.get_latest_meeting %}
|
||||
{% if latest_meeting and latest_meeting.details_url %}
|
||||
<a href="{{ latest_meeting.details_url }}" target="_blank" class="btn btn-sm bg-primary-theme text-white" title="Join Interview"
|
||||
@ -336,8 +337,8 @@
|
||||
<span class="text-muted">--</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td>
|
||||
</td> {% endcomment %}
|
||||
{% comment %} <td>
|
||||
{{ latest_meeting.status }}
|
||||
{% with latest_meeting=application.get_latest_meeting %}
|
||||
{% if latest_meeting %}
|
||||
@ -351,7 +352,7 @@
|
||||
<span class="text-muted">--</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
</td> {% endcomment %}
|
||||
<td class="text-center" id="interview-result-{{ application.pk }}">
|
||||
{% if not application.interview_status %}
|
||||
<button type="button" class="btn btn-warning btn-sm"
|
||||
@ -377,6 +378,17 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#candidateviewModal"
|
||||
hx-get="{% url 'get_interview_list' application.slug %}"
|
||||
hx-target="#candidateviewModalBody">
|
||||
Interview List
|
||||
<i class="fas fa-list"></i>
|
||||
{{candidate.get_interviews}}
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
{% if application.get_latest_meeting %}
|
||||
@ -422,37 +434,19 @@
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{% comment %} <a href="{% url 'interview_create_type_selection' candidate_slug=candidate.slug %}"
|
||||
class="btn btn-main-action btn-sm"
|
||||
title="Schedule Interview">
|
||||
<i class="fas fa-calendar-plus me-1"></i>
|
||||
Schedule
|
||||
</a> {% endcomment %}
|
||||
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#candidateviewModal"
|
||||
hx-get="{% url 'interview_create_type_selection' application_slug=application.slug %}"
|
||||
hx-get="{% url 'interview_create_type_selection' application.slug %}"
|
||||
hx-select=".card-body"
|
||||
hx-swap="innerHTML"
|
||||
hx-target="#candidateviewModalBody">
|
||||
<i class="fas fa-calendar-plus me-1"></i>
|
||||
Schedule
|
||||
Schedule Interview
|
||||
</button>
|
||||
{% comment %} <a href="{% url 'interview_create_type_selection' candidate_slug=candidate.slug %}"
|
||||
class="btn btn-main-action btn-sm"
|
||||
title="Schedule Interview">
|
||||
<i class="fas fa-calendar-plus me-1"></i>
|
||||
Schedule
|
||||
</a> {% endcomment %}
|
||||
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#candidateviewModal"
|
||||
hx-get="{% url 'get_interview_list' application.slug %}"
|
||||
hx-target="#candidateviewModalBody">
|
||||
<i class="fas fa-list"></i>
|
||||
</button>
|
||||
{{candidate.get_interviews}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user