From 506766b6ca5df1831eb179fb016dc0d189faac7f Mon Sep 17 00:00:00 2001 From: Faheed Date: Wed, 19 Nov 2025 12:30:44 +0300 Subject: [PATCH] meetings detail --- recruitment/__pycache__/forms.cpython-312.pyc | Bin 84337 -> 85594 bytes recruitment/__pycache__/urls.cpython-312.pyc | Bin 22793 -> 22927 bytes recruitment/__pycache__/views.cpython-312.pyc | Bin 194318 -> 195688 bytes recruitment/forms.py | 282 +++++-- recruitment/urls.py | 3 +- recruitment/views.py | 188 ++--- templates/interviews/detail_interview.html | 778 ++++++------------ templates/meetings/list_meetings.html | 8 +- 8 files changed, 544 insertions(+), 715 deletions(-) diff --git a/recruitment/__pycache__/forms.cpython-312.pyc b/recruitment/__pycache__/forms.cpython-312.pyc index 782d847af224e34a6dca985751462f6a177cced4..c933fed5983c406059b772d4a2c0ccc23dd8b6b9 100644 GIT binary patch delta 4242 zcmZ`+3vg3a8ovL{qj|S!(uO|L-ZpJXYDp^(MdV?D7Hg#l#T6N)gx=dWkld7;6lhHd zC~E62qTXRHb!EZzg$v`h%dEliG2q+PU6Z!EiQRQY*T=Z-YH+&)IHT@=ZWFAtl9_z@ z&wtMU{g3mXn|sbZq?&w0WqR9a)KU2P@@~7g@3v9Xb81mRm+Cjt)GCU-Wgo?E5PQ|- zCyhB@q`@Tp$q2WIH(h8Kcbu}S6epC&LEP^xn@dxifmIy`LPSv~)W?<6(nh09lY=yx z<8(%6>esq-qUIuFm{bKrp02K^L0CbHH5ZSmcH)|o;`qgCvFfZ@>R1jc(e#bOa35L< z4Fq=4;%~39iEF;ms-IL-RIp#%^i8XwDq*fVwli+78aH1pj(oFN{9so@%&LV~K@~>E zQR#gh-02)ZQ6MmqgO&!Q+ee+J^HsX9DFk5|;V0AL11}Y-eulZ+E5(iApjnVUTmnU6 z-ke#F@Kv?danV@h7+1>-WxR%)Pw!fl#)z|z6*>J>!T3O+X`fh=nM

lvx`S&Een+U8X(2n4u1qs6x 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 delta 3222 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 Xj`~KQ(2}DQemq~CBQ6yD8|?oNd9&;C diff --git a/recruitment/forms.py b/recruitment/forms.py index e356e97..ea32ac2 100644 --- a/recruitment/forms.py +++ b/recruitment/forms.py @@ -1698,6 +1698,7 @@ class CandidateEmailForm(forms.Form): return message + class InterviewParticpantsForm(forms.ModelForm): participants = forms.ModelMultipleChoiceField( queryset=Participants.objects.all(), @@ -1706,7 +1707,7 @@ class InterviewParticpantsForm(forms.ModelForm): ) system_users=forms.ModelMultipleChoiceField( - queryset=User.objects.all(), + queryset=User.objects.filter(user_type='staff'), widget=forms.CheckboxSelectMultiple, required=False, label=_("Select Users")) @@ -1861,107 +1862,107 @@ class InterviewParticpantsForm(forms.ModelForm): # self.initial['message_for_participants'] = participants_message.strip() -class InterviewEmailForm(forms.Form): - # ... (Field definitions) +# class InterviewEmailForm(forms.Form): +# # ... (Field definitions) - def __init__(self, *args, candidate, external_participants, system_participants, meeting, job, **kwargs): - super().__init__(*args, **kwargs) +# def __init__(self, *args, candidate, external_participants, system_participants, meeting, job, **kwargs): +# super().__init__(*args, **kwargs) - location = meeting.interview_location +# location = meeting - # --- Data Preparation --- +# # --- Data Preparation --- - # Safely access details through the related InterviewLocation object - if location and location.start_time: - formatted_date = location.start_time.strftime('%Y-%m-%d') - formatted_time = location.start_time.strftime('%I:%M %p') - duration = location.duration - meeting_link = location.details_url if location.details_url else "N/A (See Location Topic)" - else: - # Handle case where location or time is missing/None - formatted_date = "TBD - Awaiting Scheduling" - formatted_time = "TBD" - duration = "N/A" - meeting_link = "Not Available" +# # Safely access details through the related InterviewLocation object +# if location and location.start_time: +# formatted_date = location.start_time.strftime('%Y-%m-%d') +# formatted_time = location.start_time.strftime('%I:%M %p') +# duration = location.duration +# meeting_link = location.details_url if location.details_url else "N/A (See Location Topic)" +# else: +# # Handle case where location or time is missing/None +# formatted_date = "TBD - Awaiting Scheduling" +# formatted_time = "TBD" +# duration = "N/A" +# meeting_link = "Not Available" - job_title = job.title - agency_name = candidate.hiring_agency.name if candidate.belong_to_an_agency and candidate.hiring_agency else "Hiring Agency" +# job_title = job.title +# agency_name = candidate.hiring_agency.name if candidate.belong_to_an_agency and candidate.hiring_agency else "Hiring Agency" - # --- Combined Participants List for Internal Email --- - external_participants_names = ", ".join([p.name for p in external_participants ]) - system_participants_names = ", ".join([p.first_name for p in system_participants ]) - participant_names = ", ".join(filter(None, [external_participants_names, system_participants_names])) +# # --- Combined Participants List for Internal Email --- +# external_participants_names = ", ".join([p.name for p in external_participants ]) +# system_participants_names = ", ".join([p.first_name for p in system_participants ]) +# participant_names = ", ".join(filter(None, [external_participants_names, system_participants_names])) - # --- 1. Candidate Message (Use meeting_link) --- - candidate_message = f""" -Dear {candidate.full_name}, +# # --- 1. Candidate Message (Use meeting_link) --- +# candidate_message = f""" +# Dear {candidate.full_name}, -Thank you for your interest in the **{job_title}** position at KAAUH. We're pleased to invite you to an interview! +# Thank you for your interest in the **{job_title}** position at KAAUH. We're pleased to invite you to an interview! -The details of your virtual interview are as follows: +# The details of your virtual interview are as follows: -- **Date:** {formatted_date} -- **Time:** {formatted_time} (RIYADH TIME) -- **Duration:** {duration} -- **Meeting Link:** {meeting_link} +# - **Date:** {formatted_date} +# - **Time:** {formatted_time} (RIYADH TIME) +# - **Duration:** {duration} +# - **Meeting Link:** {meeting_link} -Please click the link at the scheduled time to join the interview. +# Please click the link at the scheduled time to join the interview. -Kindly reply to this email to **confirm your attendance** or to propose an alternative time if necessary. +# Kindly reply to this email to **confirm your attendance** or to propose an alternative time if necessary. -We look forward to meeting you. +# We look forward to meeting you. -Best regards, -KAAUH Hiring Team -""" - # ... (Messages for agency and participants remain the same, using the updated safe variables) +# Best regards, +# KAAUH Hiring Team +# """ +# # ... (Messages for agency and participants remain the same, using the updated safe variables) - # --- 2. Agency Message (Professional and clear details) --- - agency_message = f""" -Dear {agency_name}, -... -**Interview Details:** -... -- **Date:** {formatted_date} -- **Time:** {formatted_time} (RIYADH TIME) -- **Duration:** {duration} -- **Meeting Link:** {meeting_link} -... -""" +# # --- 2. Agency Message (Professional and clear details) --- +# agency_message = f""" +# Dear {agency_name}, +# ... +# **Interview Details:** +# ... +# - **Date:** {formatted_date} +# - **Time:** {formatted_time} (RIYADH TIME) +# - **Duration:** {duration} +# - **Meeting Link:** {meeting_link} +# ... +# """ - # --- 3. Participants Message (Action-oriented and informative) --- - participants_message = f""" -Hi Team, -... -**Interview Summary:** +# # --- 3. Participants Message (Action-oriented and informative) --- +# participants_message = f""" +# Hi Team, +# ... +# **Interview Summary:** -- **Candidate:** {candidate.full_name} -- **Date:** {formatted_date} -- **Time:** {formatted_time} (RIYADH TIME) -- **Duration:** {duration} -- **Your Fellow Interviewers:** {participant_names} +# - **Candidate:** {candidate.full_name} +# - **Date:** {formatted_date} +# - **Time:** {formatted_time} (RIYADH TIME) +# - **Duration:** {duration} +# - **Your Fellow Interviewers:** {participant_names} -**Action Items:** +# **Action Items:** -1. Please review **{candidate.full_name}'s** resume and notes. -2. The official calendar invite contains the meeting link ({meeting_link}) and should be used to join. -3. Be ready to start promptly at the scheduled time. -... -""" - # Set initial data - self.initial['subject'] = f"Interview Invitation: {job_title} at KAAUH - {candidate.full_name}" - self.initial['message_for_candidate'] = candidate_message.strip() - self.initial['message_for_agency'] = agency_message.strip() - self.initial['message_for_participants'] = participants_message.strip() +# 1. Please review **{candidate.full_name}'s** resume and notes. +# 2. The official calendar invite contains the meeting link ({meeting_link}) and should be used to join. +# 3. Be ready to start promptly at the scheduled time. +# ... +# """ +# # Set initial data +# self.initial['subject'] = f"Interview Invitation: {job_title} at KAAUH - {candidate.full_name}" +# self.initial['message_for_candidate'] = candidate_message.strip() +# self.initial['message_for_agency'] = agency_message.strip() +# self.initial['message_for_participants'] = participants_message.strip() -# class OnsiteLocationForm(forms.ModelForm): -# class Meta: -# model= -# fields=['location'] -# widgets={ -# 'location': forms.TextInput(attrs={'placeholder': 'Enter Interview Location'}), -# } +# # class OnsiteLocationForm(forms.ModelForm): +# # class Meta: +# # model= +# # fields=['location'] +# # widgets={ +# # 'location': forms.TextInput(attrs={'placeholder': 'Enter Interview Location'}), +# # } #during bulk schedule class OnsiteLocationForm(forms.ModelForm): @@ -1986,6 +1987,125 @@ class OnsiteLocationForm(forms.ModelForm): } +class InterviewEmailForm(forms.Form): + subject = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class': 'form-control'})) + message_for_candidate = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 6})) + message_for_agency = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 6})) + message_for_participants = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 6})) + + def __init__(self, *args, candidate, external_participants, system_participants, meeting, job, **kwargs): + """ + meeting: an InterviewLocation instance (e.g., ZoomMeetingDetails or OnsiteLocationDetails) + """ + super().__init__(*args, **kwargs) + + # ✅ meeting is already the InterviewLocation — do NOT use .interview_location + location = meeting + + # --- Determine concrete details (Zoom or Onsite) --- + if location.location_type == location.LocationType.REMOTE: + details = getattr(location, 'zoommeetingdetails', None) + elif location.location_type == location.LocationType.ONSITE: + details = getattr(location, 'onsitelocationdetails', None) + else: + details = None + + # --- Extract meeting info safely --- + if details and details.start_time: + formatted_date = details.start_time.strftime('%Y-%m-%d') + formatted_time = details.start_time.strftime('%I:%M %p') + duration = details.duration + meeting_link = location.details_url or "N/A (See Location Topic)" + else: + formatted_date = "TBD - Awaiting Scheduling" + formatted_time = "TBD" + duration = "N/A" + meeting_link = "Not Available" + + job_title = job.title + agency_name = ( + candidate.hiring_agency.name + if candidate.belong_to_agency and candidate.hiring_agency + else "Hiring Agency" + ) + + # --- Participant names for internal email --- + external_names = ", ".join([p.name for p in external_participants]) + system_names = ", ".join([u.get_full_name() or u.username for u in system_participants]) + participant_names = ", ".join(filter(None, [external_names, system_names])) + + # --- Candidate Message --- + candidate_message = f""" +Dear {candidate.full_name}, + +Thank you for your interest in the **{job_title}** position at KAAUH. We're pleased to invite you to an interview! + +The details of your interview are as follows: + +- **Date:** {formatted_date} +- **Time:** {formatted_time} (RIYADH TIME) +- **Duration:** {duration} minutes +- **Meeting Link/Location:** {meeting_link} + +Please be ready at the scheduled time. + +Kindly reply to confirm your attendance or propose an alternative if needed. + +We look forward to meeting you. + +Best regards, +KAAUH Hiring Team +""".strip() + + # --- Agency Message --- + agency_message = f""" +Dear {agency_name}, + +This is to inform you that your candidate, **{candidate.full_name}**, has been scheduled for an interview for the **{job_title}** position. + +**Interview Details:** +- **Date:** {formatted_date} +- **Time:** {formatted_time} (RIYADH TIME) +- **Duration:** {duration} minutes +- **Meeting Link/Location:** {meeting_link} + +Please ensure the candidate is informed and prepared. + +Best regards, +KAAUH Hiring Team +""".strip() + + # --- Participants (Interview Panel) Message --- + participants_message = f""" +Hi Team, + +You are scheduled to interview **{candidate.full_name}** for the **{job_title}** role. + +**Interview Summary:** +- **Candidate:** {candidate.full_name} +- **Date:** {formatted_date} +- **Time:** {formatted_time} (RIYADH TIME) +- **Duration:** {duration} minutes +- **Location/Link:** {meeting_link} +- **Fellow Interviewers:** {participant_names} + +**Action Items:** +1. Review the candidate’s resume and application notes. +2. Join via the link above (or be at the physical location) on time. +3. Coordinate among yourselves for role coverage. + +Thank you! +""".strip() + + # --- Set initial values --- + self.initial.update({ + 'subject': f"Interview Invitation: {job_title} - {candidate.full_name}", + 'message_for_candidate': candidate_message, + 'message_for_agency': agency_message, + 'message_for_participants': participants_message, + }) + + class OnsiteReshuduleForm(forms.ModelForm): class Meta: model = OnsiteLocationDetails diff --git a/recruitment/urls.py b/recruitment/urls.py index 0e57def..c72eff2 100644 --- a/recruitment/urls.py +++ b/recruitment/urls.py @@ -656,5 +656,6 @@ urlpatterns = [ # Detail View (assuming slug is on ScheduledInterview) - # path("interviews/meetings//", views.MeetingDetailView.as_view(), name="meeting_details"), + path("interviews/meetings//", views.meeting_details, name="meeting_details"), + ] diff --git a/recruitment/views.py b/recruitment/views.py index ba422ff..5b09078 100644 --- a/recruitment/views.py +++ b/recruitment/views.py @@ -129,7 +129,8 @@ from .models import ( Message, Document, OnsiteLocationDetails, - InterviewLocation + InterviewLocation, + InterviewNote ) @@ -249,123 +250,7 @@ class ZoomMeetingCreateView(StaffRequiredMixin, CreateView): messages.error(self.request, f"Error creating meeting: {e}") return redirect(reverse("create_meeting", kwargs={"slug": instance.slug})) - -# class ZoomMeetingListView(StaffRequiredMixin, ListView): -# model = ZoomMeetingDetails -# template_name = "meetings/list_meetings.html" -# context_object_name = "meetings" -# paginate_by = 10 - -# def get_queryset(self): -# queryset = super().get_queryset().order_by("-start_time") - -# # Prefetch related interview data efficiently - -# queryset = queryset.prefetch_related( -# Prefetch( -# "interview", # related_name from ZoomMeeting to ScheduledInterview -# queryset=ScheduledInterview.objects.select_related("application", "job"), -# to_attr="interview_details", # Changed to not start with underscore -# ) -# ) - -# # Handle search by topic or meeting_id -# search_query = self.request.GET.get( -# "q", "" -# ) # Renamed from 'search' to 'q' for consistency -# if search_query: -# queryset = queryset.filter( -# Q(topic__icontains=search_query) | Q(meeting_id__icontains=search_query) -# ) - -# # Handle filter by status -# status_filter = self.request.GET.get("status", "") -# if status_filter: -# queryset = queryset.filter(status=status_filter) - -# # Handle search by candidate name -# candidate_name = self.request.GET.get("candidate_name", "") -# if candidate_name: -# # Filter based on the name of the candidate associated with the meeting's interview -# queryset = queryset.filter( -# Q(interview__application__first_name__icontains=candidate_name) -# | Q(interview__application__last_name__icontains=candidate_name) -# ) - -# return queryset - -# def get_context_data(self, **kwargs): -# context = super().get_context_data(**kwargs) -# context["search_query"] = self.request.GET.get("q", "") -# context["status_filter"] = self.request.GET.get("status", "") -# context["candidate_name_filter"] = self.request.GET.get("candidate_name", "") -# return context - - - -# @login_required -# def InterviewListView(request): -# # interview_type=request.GET.get('interview_type','Remote') -# # print(interview_type) -# interview_type='Onsite' -# meetings=ScheduledInterview.objects.filter(schedule__interview_type=interview_type) -# return render(request, "meetings/list_meetings.html",{ -# 'meetings':meetings, -# }) - - -# search_query = request.GET.get("q", "") # Renamed from 'search' to 'q' for consistency -# if search_query: -# interviews = interviews.filter( -# Q(topic__icontains=search_query) | Q(meeting_id__icontains=search_query) -# ) - -# # Handle filter by status -# status_filter = request.GET.get("status", "") -# if status_filter: -# queryset = queryset.filter(status=status_filter) - -# # Handle search by candidate name -# candidate_name = request.GET.get("candidate_name", "") -# if candidate_name: -# # Filter based on the name of the candidate associated with the meeting's interview -# queryset = queryset.filter( -# Q(interview__candidate__first_name__icontains=candidate_name) | -# Q(interview__candidate__last_name__icontains=candidate_name) -# ) - - -# @login_required -# def InterviewListView(request): -# # interview_type=request.GET.get('interview_type','Remote') -# # print(interview_type) -# interview_type='Onsite' -# meetings=ScheduledInterview.objects.filter(schedule__interview_type=interview_type) -# return render(request, "meetings/list_meetings.html",{ -# 'meetings':meetings, -# }) - - -# search_query = request.GET.get("q", "") # Renamed from 'search' to 'q' for consistency -# if search_query: -# interviews = interviews.filter( -# Q(topic__icontains=search_query) | Q(meeting_id__icontains=search_query) -# ) - -# # Handle filter by status -# status_filter = request.GET.get("status", "") -# if status_filter: -# queryset = queryset.filter(status=status_filter) - -# # Handle search by candidate name -# candidate_name = request.GET.get("candidate_name", "") -# if candidate_name: -# # Filter based on the name of the candidate associated with the meeting's interview -# queryset = queryset.filter( -# Q(interview__candidate__first_name__icontains=candidate_name) | -# Q(interview__candidate__last_name__icontains=candidate_name) -# ) - + class ZoomMeetingDetailsView(StaffRequiredMixin, DetailView): model = ZoomMeetingDetails @@ -3122,7 +3007,7 @@ def add_meeting_comment(request, slug): meeting = get_object_or_404(ZoomMeetingDetails, slug=slug) if request.method == "POST": - form = MeetingCommentForm(request.POST) + form = InterviewNoteForm(request.POST) if form.is_valid(): comment = form.save(commit=False) comment.meeting = meeting @@ -3143,7 +3028,7 @@ def add_meeting_comment(request, slug): return redirect("meeting_details", slug=slug) else: - form = MeetingCommentForm() + form = InterviewNoteForm() context = { "form": form, @@ -3169,7 +3054,7 @@ def edit_meeting_comment(request, slug, comment_id): return redirect("meeting_details", slug=slug) if request.method == "POST": - form = MeetingCommentForm(request.POST, instance=comment) + form = InterviewNoteForm(request.POST, instance=comment) if form.is_valid(): comment = form.save() messages.success(request, "Comment updated successfully!") @@ -3187,7 +3072,7 @@ def edit_meeting_comment(request, slug, comment_id): return redirect("meeting_details", slug=slug) else: - form = MeetingCommentForm(instance=comment) + form = InterviewNoteForm(instance=comment) context = {"form": form, "meeting": meeting, "comment": comment} return render(request, "includes/edit_comment_form.html", context) @@ -5773,7 +5658,7 @@ class MeetingListView(ListView): 'details': details, 'type': location.location_type, 'topic': location.topic, - 'slug': interview.slug, + # 'slug': interview.slug, 'start_time': start_datetime, # Combined datetime object # Duration should ideally be on ScheduledInterview or fetched from details 'duration': getattr(details, 'duration', 'N/A'), @@ -5947,3 +5832,60 @@ def schedule_onsite_meeting_for_candidate(request, slug, candidate_pk): return render(request, "meetings/schedule_onsite_meeting_form.html", context) + + +from django.http import Http404 + + +def meeting_details(request, slug): + # Fetch the meeting (InterviewLocation or subclass) by slug + meeting = get_object_or_404( + InterviewLocation.objects.select_related( + 'scheduled_interview__application__person', + 'scheduled_interview__job', + 'zoommeetingdetails', + 'onsitelocationdetails', + ).prefetch_related( + 'scheduled_interview__participants', + 'scheduled_interview__system_users', + 'scheduled_interview__notes', + ), + slug=slug + ) + + try: + interview = meeting.scheduled_interview + except ScheduledInterview.DoesNotExist: + raise Http404("No interview is associated with this meeting.") + + candidate = interview.application + job = interview.job + + external_participants = interview.participants.all() + system_participants = interview.system_users.all() + total_participants = external_participants.count() + system_participants.count() + + # Forms for modals + participant_form = InterviewParticpantsForm(instance=interview) + # email_form = InterviewEmailForm( + # candidate=candidate, + # external_participants=external_participants, # QuerySet of Participants + # system_participants=system_participants, # QuerySet of Users + # meeting=meeting, # ← This is InterviewLocation (e.g., ZoomMeetingDetails) + # job=job, + # ) + + context = { + 'meeting': meeting, + 'interview': interview, + 'candidate': candidate, + 'job': job, + 'external_participants': external_participants, + 'system_participants': system_participants, + 'total_participants': total_participants, + 'form': participant_form, + # 'email_form': email_form, + } + + return render(request, 'interviews/detail_interview.html', context) + diff --git a/templates/interviews/detail_interview.html b/templates/interviews/detail_interview.html index 2843437..0739575 100644 --- a/templates/interviews/detail_interview.html +++ b/templates/interviews/detail_interview.html @@ -1,12 +1,9 @@ {% extends 'base.html' %} {% load static i18n %} {% load widget_tweaks %} + {% block customCSS %} {% endblock %} - {% block content %} -{% comment %} - NOTE: The variable 'meeting' has been renamed to 'interview' (ScheduledInterview) - NOTE: The variable 'meeting.slug' has been renamed to 'interview.slug' - NOTE: All 'meeting' URL names (update_meeting, delete_meeting, etc.) have been renamed -{% endcomment %} -

- {# --- TOP BAR / BACK BUTTON & ACTIONS (EDIT/DELETE) --- #} + {# --- TOP BAR --- #}
- {# Back Button #} - - {% trans "Back to Interviews" %} + + {% trans "Back to Meetings" %} - - {# Edit and Delete Buttons #}
- - {% trans "Edit Interview" %} + + {% trans "Edit Meeting" %} - {# DELETE MEETING FORM #} -
+ {% csrf_token %} -
- {# ========================================================= #} - {# --- MAIN TITLE AT TOP --- #} - {# ========================================================= #} - {% with zoom_details=interview.zoom_details.0 %} + {# --- MAIN TITLE --- #}

- {% if interview.schedule.interview_type == 'Remote' %} - - {{ zoom_details.topic|default:"[Remote Interview]" }} - {% else %} - - {{ interview.schedule.location|default:"[Onsite Interview]" }} - {% endif %} - - - {{ interview.status|title|default:'N/A' }} ({{ interview.schedule.interview_type }}) + + {{ meeting.topic|default:"[Meeting Topic]" }} + + {{ interview.get_status_display|default:"Scheduled" }}

- {# ========================================================= #} - {# --- SECTION 1: INTERVIEW & CONNECTION/LOCATION CARDS SIDE BY SIDE --- #} - {# ========================================================= #} + {# --- INTERVIEW & CONNECTION CARDS --- #}
- - {# --- LEFT HALF: INTERVIEW DETAIL CARD --- #} + {# Interview Detail #}
-

{% trans "Candidate & Job" %}

+

{% trans "Interview Detail" %}

- {# NOTE: Assuming ScheduledInterview has direct relations to candidate and job #} - - -
{% trans "Candidate Email" %}:
-
{% trans "Job Type" %}:
{{ interview.job.job_type|default:"N/A" }}
- {% if interview.candidate.belong_to_agency %} - +
+
{% trans "Job Title" %}:
+
{{ job.title|default:"N/A" }}
+
+
+
{% trans "Candidate Name" %}:
+
{{ candidate.full_name|default:"N/A" }}
+
+
+
{% trans "Candidate Email" %}:
+
{{ candidate.email|default:"N/A" }}
+
+
+
{% trans "Job Type" %}:
+
{{ job.job_type|default:"N/A" }}
+
+ {% if candidate.belong_to_agency %} +
+
{% trans "Agency" %}:
+
{{ candidate.hiring_agency.name|default:"N/A" }}
+
{% endif %}
- {# --- RIGHT HALF: CONNECTION/LOCATION DETAILS CARD --- #} + {# Connection Details #}
-

{% trans "Time & Location" %}

+

{% trans "Connection Details" %}

-
{% trans "Date & Time" %}:
{{ interview.interview_date|date:"M d, Y"|default:"N/A" }} @ {{ interview.interview_time|time:"H:i"|default:"N/A" }}
-
{% trans "Duration" %}:
{{ interview.schedule.interview_duration|default:"N/A" }} {% trans "minutes" %}
- - {% if interview.schedule.interview_type == 'Onsite' %} - {# --- Onsite Details --- #} -
{% trans "Location" %}:
{{ interview.schedule.location|default:"TBD" }}
+
+
{% trans "Date & Time" %}:
+
+ {{ interview.interview_date }} {{ interview.interview_time }} ({{ meeting.timezone }}) +
+
+
+
{% trans "Duration" %}:
+
+ {% if meeting.location_type == "Remote" %} + {{ meeting.zoommeetingdetails.duration|default:"N/A" }} + {% elif meeting.location_type == "Onsite" %} + {{ meeting.onsitelocationdetails.duration|default:"N/A" }} + {% else %} + N/A + {% endif %} + {% trans "minutes" %} +
+
- {% elif interview.schedule.interview_type == 'Remote' and zoom_details %} - {# --- Remote/Zoom Details --- #} -

{% trans "Remote Details" %}

-
{% trans "Meeting ID" %}:
{{ zoom_details.meeting_id|default:"N/A" }}
-
{% trans "Host Email" %}:
{{ zoom_details.host_email|default:"N/A" }}
- - {% if zoom_details.join_url %} -
-
{% trans "Copied!" %}
- -
+ {% if meeting.location_type == "Remote" %} + {% with zoom=meeting.zoommeetingdetails %} +
+
{% trans "Meeting ID" %}:
+
{{ zoom.meeting_id|default:"N/A" }}
+
+
+
{% trans "Host Email" %}:
+
{{ zoom.host_email|default:"N/A" }}
+
+ {% if meeting.details_url %} +
+
+ {% trans "Copied!" %} +
+
{% trans "Join URL" %}: - {{ zoom_details.join_url }} + {{ meeting.details_url }}
{% endif %} - {% else %} -

{% trans "Location/Connection details are not available for this interview type." %}

+ {% endwith %} + {% elif meeting.location_type == "Onsite" %} + {% with onsite=meeting.onsitelocationdetails %} +
+
{% trans "Address" %}:
+
{{ onsite.physical_address|default:"N/A" }}
+
+
+
{% trans "Room" %}:
+
{{ onsite.room_number|default:"TBD" }}
+
+ {% endwith %} {% endif %}
- {% endwith %} - {# ========================================================= #} - {# --- SECTION 2: PERSONNEL TABLES --- #} - {# ========================================================= #} + {# --- PARTICIPANTS --- #}
- - - {# --- PARTICIPANTS TABLE --- #}
-
+

{% trans "Assigned Participants" %}

-
- - - +
+ +
-
+
- + - - + + - {# External Participants #} - {% for participant in interview.participants.all %} + {% for participant in external_participants %} - - - - - + + + + + {% endfor %} - {# System Users (Internal Participants) #} - {% for user in interview.system_users.all %} + {% for user in system_participants %} - - - - + + + + {% endfor %} -
{% trans "Name" %}{% trans "Role/Designation" %}{% trans "Role" %} {% trans "Email" %}{% trans "Phone Number" %}{% trans "Source Type" %}{% trans "Phone" %}{% trans "Type" %}
{{participant.name}}{{participant.designation}}{{participant.email}}{{participant.phone}}{% trans "External Participants" %}{{ participant.name }}{{ participant.designation|default:"Participant" }}{{ participant.email|default:"N/A" }}{{ participant.phone|default:"N/A" }}{% trans "External" %}
{{user.get_full_name}}{% trans "System User" %}{{user.email}}{{user.phone}}{{ user.get_full_name|default:user.username }}Admin{{ user.email|default:"N/A" }}{{ user.phone|default:"N/A" }} {% trans "System User" %}
- {# ========================================================= #} - {# --- SECTION 3: COMMENTS (CORRECTED) --- #} - {# ========================================================= #} + {# --- COMMENTS --- #}
-
-
+
-
+
- {% trans "Comments" %} ({% if interview.comments %}{{ interview.comments.count }}{% else %}0{% endif %}) + {% trans "Comments" %} ({{ interview.notes.count }})
-
- - {# 1. COMMENT DISPLAY & IN-PAGE EDIT FORMS #} +
- {# NOTE: Assuming comment model has a ForeignKey to ScheduledInterview called 'interview' #} - {% if interview.comments.all %} - {% for comment in interview.comments.all|dictsortreversed:"created_at" %} - -
- - {# Read-Only Comment View #} -
-
- - - {% if comment.author == user or user.is_staff %} -
- {# Edit Button: Toggles the hidden form #} - - - {# Delete Form: Submits a POST request #} -
- {% csrf_token %} - -
-
- {% endif %} -
-

{{ comment.content|linebreaksbr }}

+ {% for note in interview.notes.all|dictsortreversed:"created_at" %} +
+
+
+ - - {# Hidden Edit Form #} - - {% endfor %} - {% else %} -

{% trans "No comments yet. Be the first to comment!" %}

- {% endif %} +

{{ note.content|linebreaksbr }}

+
+ + +
+ {% empty %} +

{% trans "No comments yet. Be the first to comment!" %}

+ {% endfor %}

- - {# 2. NEW COMMENT SUBMISSION (Remains the same) #} -
{% trans "Add a New Comment" %}
- {% if user.is_authenticated %} -
- {% csrf_token %} - {% if comment_form %} - {{ comment_form.as_p }} - {% else %} -
- - -
- {% endif %} - -
- {% else %} -

{% trans "You must be logged in to add a comment." %}

- {% endif %} +
{% trans "Add a New Comment" %}
+
+ {% csrf_token %} +
+ + +
+ +
- -{# --- MODALS (Updated to use interview.slug) --- #} - -