more update in css and templates

This commit is contained in:
ismail 2025-10-15 13:13:59 +03:00
parent 6b74990791
commit 3682657527
12 changed files with 46 additions and 164 deletions

View File

@ -41,11 +41,11 @@ urlpatterns = [
path('training/<slug:slug>/delete/', views_frontend.TrainingDeleteView.as_view(), name='training_delete'), path('training/<slug:slug>/delete/', views_frontend.TrainingDeleteView.as_view(), name='training_delete'),
# Meeting URLs # Meeting URLs
path('', views.ZoomMeetingListView.as_view(), name='list_meetings'), path('meetings/', views.ZoomMeetingListView.as_view(), name='list_meetings'),
path('create-meeting/', views.ZoomMeetingCreateView.as_view(), name='create_meeting'), path('meetings/create-meeting/', views.ZoomMeetingCreateView.as_view(), name='create_meeting'),
path('meeting-details/<slug:slug>/', views.ZoomMeetingDetailsView.as_view(), name='meeting_details'), path('meetings/meeting-details/<slug:slug>/', views.ZoomMeetingDetailsView.as_view(), name='meeting_details'),
path('update-meeting/<slug:slug>/', views.ZoomMeetingUpdateView.as_view(), name='update_meeting'), path('meetings/update-meeting/<slug:slug>/', views.ZoomMeetingUpdateView.as_view(), name='update_meeting'),
path('delete-meeting/<slug:slug>/', views.ZoomMeetingDeleteView, name='delete_meeting'), path('meetings/delete-meeting/<slug:slug>/', views.ZoomMeetingDeleteView, name='delete_meeting'),
# JobPosting functional views URLs (keeping for compatibility) # JobPosting functional views URLs (keeping for compatibility)
path('api/create/', views.create_job, name='create_job_api'), path('api/create/', views.create_job, name='create_job_api'),
@ -105,7 +105,6 @@ urlpatterns = [
path('jobs/<slug:slug>/candidates/<int:candidate_pk>/schedule-meeting-page/', views.schedule_meeting_for_candidate, name='schedule_meeting_for_candidate'), path('jobs/<slug:slug>/candidates/<int:candidate_pk>/schedule-meeting-page/', views.schedule_meeting_for_candidate, name='schedule_meeting_for_candidate'),
path('jobs/<slug:slug>/candidates/<int:candidate_pk>/delete_meeting_for_candidate/<int:meeting_id>/', views.delete_meeting_for_candidate, name='delete_meeting_for_candidate'), path('jobs/<slug:slug>/candidates/<int:candidate_pk>/delete_meeting_for_candidate/<int:meeting_id>/', views.delete_meeting_for_candidate, name='delete_meeting_for_candidate'),
# users urls # users urls
path('user/<int:pk>',views.user_detail,name='user_detail') path('user/<int:pk>',views.user_detail,name='user_detail')
] ]

View File

@ -239,75 +239,14 @@ def candidate_detail(request, slug):
def candidate_update_stage(request, slug): def candidate_update_stage(request, slug):
"""Handle HTMX stage update requests""" """Handle HTMX stage update requests"""
try: candidate = get_object_or_404(models.Candidate, slug=slug)
if not request.user.is_staff: form = forms.CandidateStageForm(request.POST, candidate=candidate)
return render(request, 'recruitment/partials/error.html', {'error': 'Permission denied'}, status=403) if form.is_valid():
stage_value = form.cleaned_data['stage']
candidate = get_object_or_404(models.Candidate, slug=slug) candidate.stage = stage_value
candidate.save(update_fields=['stage'])
if request.method != 'POST': messages.success(request,"Candidate Stage Updated")
return render(request, 'recruitment/partials/error.html', {'error': 'Only POST method is allowed'}, status=405) return redirect("candidate_detail",slug=candidate.slug)
# Handle form data
form = forms.CandidateStageForm(request.POST, candidate=candidate)
if form.is_valid():
stage_value = form.cleaned_data['stage']
# Validate stage value
valid_stages = [choice[0] for choice in models.Candidate.Stage.choices]
if stage_value not in valid_stages:
return render(request, 'recruitment/partials/error.html', {'error': f'Invalid stage value. Must be one of: {", ".join(valid_stages)}'}, status=400)
# Check transition rules
if candidate.pk and stage_value != candidate.stage:
old_stage = candidate.stage
if not candidate.can_transition_to(stage_value):
return render(request, 'recruitment/partials/error.html', {'error': f'Cannot transition from "{old_stage}" to "{stage_value}". Transition not allowed.'}, status=400)
# Update the stage
old_stage = candidate.stage
candidate.stage = stage_value
candidate.save()
# Return success template
context = {
'form': form,
'success': True,
'message': f'Stage updated from "{old_stage}" to "{candidate.stage}"',
'new_stage': candidate.stage,
'new_stage_display': candidate.get_stage_display(),
'candidate': candidate
}
messages.success(request,"Candidate Stage Updated")
return redirect("candidate_detail",slug=candidate.slug)
def response():
stage_form = forms.CandidateStageForm(candidate=candidate)
context['stage_form'] = stage_form
stage_form_partial = render_to_string('recruitment/partials/stage_update_modal.html#id-stage', context)
success_html = render_to_string('recruitment/partials/stage_update_success.html', context)
yield SSE.patch_elements(stage_form_partial,"#id_stage")
yield SSE.patch_elements(success_html,"#availableStagesInfo")
yield SSE.patch_signals({'stage':candidate.stage})
return DatastarResponse(response())
# return render(request, 'recruitment/partials/stage_update_success.html', context)
else:
# Return form with errors
context = {
'form': form,
'candidate': candidate,
'stage_form': forms.CandidateStageForm(candidate=candidate)
}
return render(request, 'recruitment/partials/stage_update_form.html', context)
except Exception as e:
# Log the error for debugging
import traceback
error_details = traceback.format_exc()
print(f"Error in candidate_update_stage: {error_details}")
return render(request, 'partials/error.html', {'error': f'Internal server error: {str(e)}'}, status=500)
class TrainingListView(LoginRequiredMixin, ListView): class TrainingListView(LoginRequiredMixin, ListView):
model = models.TrainingMaterial model = models.TrainingMaterial

View File

@ -15,10 +15,4 @@
value="{{ search_query }}" value="{{ search_query }}"
aria-label="{% trans 'Search' %}"> aria-label="{% trans 'Search' %}">
</div> </div>
{% comment %} <button type="submit" class="btn btn-primary">
<svg class="heroicon icon-sm" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
{% trans "Search" %}
</button> {% endcomment %}
</form> </form>

View File

@ -184,7 +184,7 @@
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %} <i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
</button> </button>
{% if status_filter or search_query %} {% if status_filter or search_query %}
<a href="{% url 'meeting_list' %}" class="btn btn-outline-secondary btn-lg"> <a href="{% url 'list_meetings' %}" class="btn btn-outline-secondary btn-lg">
<i class="fas fa-times me-1"></i> {% trans "Clear" %} <i class="fas fa-times me-1"></i> {% trans "Clear" %}
</a> </a>
{% endif %} {% endif %}

View File

@ -414,9 +414,6 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -19,66 +19,21 @@
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<i class="fas fa-info-circle me-2"></i> <i class="fas fa-info-circle me-2"></i>
<strong>Current Stage:</strong> <strong>Current Stage:</strong>
<span class="badge bg-primary ms-2" id="currentStageBadge" data-text="$stage"></span> <span class="badge bg-primary ms-2" id="currentStageBadge">{{candidate.stage}}</span>
</div>
</div>
<!-- Stage Progress Visualization -->
<div class="mb-4" >
<h6 class="text-muted mb-3">Application Pipeline</h6>
<div class="progress-stages">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="stage-item {% if candidate.stage == 'Applied' %}active{% endif %}" data-stage="Applied">
<div class="stage-icon">
<i class="fas fa-user-check"></i>
</div>
<div class="stage-label">Applied</div>
</div>
<div data-class="{active: $stage == 'Exam', completed: $stage == 'Interview' || $stage == 'Offer'}" class="stage-connector"></div>
<div data-class="{active: $stage == 'Exam', completed: $stage == 'Offer' || $stage == 'Interview'}" class="stage-item" data-stage="Exam">
<div class="stage-icon">
<i class="fas fa-clipboard-check"></i>
</div>
<div class="stage-label">Exam</div>
</div>
<div data-class="{active: $stage == 'Interview', completed: $stage == 'Offer'}" class="stage-connector"></div>
<div data-class="{active: $stage == 'Interview', completed: $stage == 'Offer'}" class="stage-item" data-stage="Interview">
<div class="stage-icon">
<i class="fas fa-comments"></i>
</div>
<div class="stage-label">Interview</div>
</div>
<div data-class="{active: $stage == 'Offer'}" class="stage-connector"></div>
<div data-class="{active: $stage == 'Offer', completed: $stage == 'Offer'}" class="stage-item" data-stage="Offer">
<div class="stage-icon">
<i class="fas fa-handshake"></i>
</div>
<div class="stage-label">Offer</div>
</div>
</div>
</div> </div>
</div> </div>
<!-- Form Container --> <!-- Form Container -->
<div id="stageUpdateFormContainer" data-show="$stage != 'Offer'"> <div id="stageUpdateFormContainer">
{% comment %} <form id="stageUpdateForm" hx-post="{% url 'candidate_update_stage' candidate.slug %}" hx-target="#stageUpdateFormContainer" hx-swap="outerHTML" hx-indicator="#loadingIndicator"> {% endcomment %} <form id="stageUpdateForm" action="{% url 'candidate_update_stage' candidate.slug %}" method="post">
{% url 'candidate_update_stage' candidate.slug as stage_update_url %}
<form id="stageUpdateForm" data-on-submit="@post('{{ stage_update_url }}',{
contentType: 'form',
headers: {'X-CSRFToken': '{{ csrf_token }}'}})" data-indicator-fetching>
{% csrf_token %} {% csrf_token %}
<!-- Stage Selection --> <!-- Stage Selection -->
<div class="mb-3"> <div class="mb-3">
<label for="id_stage" class="form-label"> <label for="id_stage" class="form-label">
<i class="fas fa-arrow-right me-1"></i>Move to Stage <i class="fas fa-arrow-right me-1"></i>Move to Stage
</label> </label>
{% partialdef id-stage %} {% partialdef id-stage %}
<select data-attr-disabled="$fetching" id="id_stage" name="stage" class="form-select" onchange="updateStageInfo(this.value, '{{ candidate.stage }}')"> <select id="id_stage" name="stage" class="form-select">
{% for value, label in stage_form.stage.field.choices %} {% for value, label in stage_form.stage.field.choices %}
<option value="{{ value }}">{{ label }}</option> <option value="{{ value }}">{{ label }}</option>
{% endfor %} {% endfor %}
@ -95,17 +50,15 @@
</small> </small>
</div> </div>
<!-- Form Actions --> <!-- Form Actions -->
<div class="d-flex justify-content-between mt-4"> <div class="d-flex justify-content-between mt-4">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-1"></i>Cancel <i class="fas fa-times me-1"></i>Cancel
</button> </button>
<button data-show="$stage != 'Offer'" type="submit" class="btn btn-primary" id="stageUpdateSubmit" data-attr-disabled="$fetching"> <button type="submit" class="btn btn-primary" id="stageUpdateSubmit">
<i class="fas fa-save me-1"></i> <i class="fas fa-save me-1"></i>
<span data-show="$fetching" class="spinner-border spinner-border-sm ms-2" role="status" aria-hidden="true"></span> <span class="ms-2">Update</span>
<span class="ms-2" data-text="$fetching ? 'Updating...' : 'Update'"></span>
</button> </button>
</div> </div>
</form> </form>