lot of updates

This commit is contained in:
ismail 2025-10-21 19:24:42 +03:00
parent ef8616c088
commit 3086b38a23
18 changed files with 93 additions and 53 deletions

View File

@ -16,25 +16,25 @@ urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
path('accounts/', include('allauth.urls')),
path('i18n/', include('django.conf.urls.i18n')),
# path('summernote/', include('django_summernote.urls')),
# path('', include('recruitment.urls')),
path("ckeditor5/", include('django_ckeditor_5.urls')),
path('<int:template_id>/', views.form_wizard_view, name='form_wizard'),
path('<int:template_id>/submit/', views.submit_form, name='submit_form'),
path('<slug:template_slug>/', views.form_wizard_view, name='form_wizard'),
path('<slug:template_slug>/submit/', views.submit_form, name='submit_form'),
path('api/templates/', views.list_form_templates, name='list_form_templates'),
path('api/templates/save/', views.save_form_template, name='save_form_template'),
path('api/templates/<int:template_id>/', views.load_form_template, name='load_form_template'),
path('api/templates/<int:template_id>/delete/', views.delete_form_template, name='delete_form_template'),
path('api/templates/<slug:template_slug>/', views.load_form_template, name='load_form_template'),
path('api/templates/<slug:template_slug>/delete/', views.delete_form_template, name='delete_form_template'),
path('api/webhook/',views.zoom_webhook_view,name='zoom_webhook_view')
]
urlpatterns += i18n_patterns(
path('', include('recruitment.urls')),
)
# 2. URLs that DO have a language prefix (user-facing views)
# This includes the root path (''), which is handled by 'recruitment.urls'

View File

@ -82,14 +82,14 @@ def create_default_stages(sender, instance, created, **kwargs):
order=4,
is_predefined=True
)
# FormField.objects.create(
# stage=contact_stage,
# label='National ID / Iqama Number',
# field_type='text',
# required=False,
# order=5,
# is_predefined=True
# )
FormField.objects.create(
stage=contact_stage,
label='National ID / Iqama Number',
field_type='text',
required=False,
order=5,
is_predefined=True
)
FormField.objects.create(
stage=contact_stage,
label='Resume Upload',

View File

@ -96,11 +96,11 @@ urlpatterns = [
# path('api/forms/save/', views.save_form_builder, name='save_form_builder'),
# path('api/forms/<int:form_id>/load/', views.load_form, name='load_form'),
# path('api/forms/<int:form_id>/update/', views.update_form_builder, name='update_form_builder'),
path('api/templates/', views.list_form_templates, name='list_form_templates'),
path('api/templates/save/', views.save_form_template, name='save_form_template'),
path('api/templates/<int:template_id>/', views.load_form_template, name='load_form_template'),
path('api/templates/<int:template_id>/delete/', views.delete_form_template, name='delete_form_template'),
# path('api/templates/', views.list_form_templates, name='list_form_templates'),
# path('api/templates/save/', views.save_form_template, name='save_form_template'),
# path('api/templates/<slug:template_slug>/', views.load_form_template, name='load_form_template'),
# path('api/templates/<slug:template_slug>/delete/', views.delete_form_template, name='delete_form_template'),
path('jobs/<slug:slug>/calendar/', views.interview_calendar_view, name='interview_calendar'),
path('jobs/<slug:slug>/calendar/interview/<int:interview_id>/', views.interview_detail_view, name='interview_detail'),

View File

@ -637,10 +637,10 @@ def form_builder(request, template_slug=None):
context = {}
if template_slug:
template = get_object_or_404(
FormTemplate, slug=template_slug, created_by=request.user
FormTemplate, slug=template_slug
)
context['template']=template
context["template_id"] = template.id
context["template_slug"] = template.slug
context["template_name"] = template.name
return render(request, "forms/form_builder.html", context)
@ -653,12 +653,12 @@ def save_form_template(request):
data = json.loads(request.body)
template_name = data.get("name", "Untitled Form")
stages_data = data.get("stages", [])
template_id = data.get("template_id")
template_slug = data.get("template_slug")
if template_id:
if template_slug:
# Update existing template
template = get_object_or_404(
FormTemplate, id=template_id, created_by=request.user
FormTemplate, slug=template_slug
)
template.name = template_name
template.save()
@ -667,7 +667,7 @@ def save_form_template(request):
else:
# Create new template
template = FormTemplate.objects.create(
name=template_name, created_by=request.user
name=template_name
)
# Create stages and fields
@ -703,7 +703,7 @@ def save_form_template(request):
return JsonResponse(
{
"success": True,
"template_id": template.id,
"template_slug": template.slug,
"message": "Form template saved successfully!",
}
)
@ -712,9 +712,9 @@ def save_form_template(request):
@require_http_methods(["GET"])
def load_form_template(request, template_id):
def load_form_template(request, template_slug):
"""Load an existing form template"""
template = get_object_or_404(FormTemplate, id=template_id, created_by=request.user)
template = get_object_or_404(FormTemplate, slug=template_slug)
stages = []
for stage in template.stages.all():
@ -747,6 +747,7 @@ def load_form_template(request, template_id):
"success": True,
"template": {
"id": template.id,
"template_slug": template.slug,
"name": template.name,
"description": template.description,
"is_active": template.is_active,
@ -844,6 +845,7 @@ def form_wizard_view(request, template_slug):
)
@csrf_exempt
@require_POST
def submit_form(request, template_slug):
"""Handle form submission"""
@ -862,6 +864,7 @@ def submit_form(request, template_slug):
{"success": False, "message": "Application limit reached for this job."}
)
submission = FormSubmission.objects.create(template=template)
# Process field responses
for field_id, value in request.POST.items():
if field_id.startswith("field_"):
@ -906,7 +909,7 @@ def submit_form(request, template_slug):
)
submission.applicant_email = email.display_value
submission.save()
time=timezone.now()
# time=timezone.now()
Candidate.objects.create(
first_name=first_name.display_value,
last_name=last_name.display_value,
@ -914,10 +917,16 @@ def submit_form(request, template_slug):
phone=phone.display_value,
address=address.display_value,
resume=resume.get_file if resume.is_file else None,
job=submission.template.job,
job=job
)
return redirect('application_success',slug=job.slug)
return JsonResponse(
{
"success": True,
"message": "Form submitted successfully!",
"redirect_url": reverse('application_success',kwargs={'slug':job.slug}),
}
)
# return redirect('application_success',slug=job.slug)
except Exception as e:
logger.error(f"Candidate creation failed,{e}")

View File

@ -16,9 +16,9 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
{% endif %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="{% static 'css/main.css' %}">
@ -120,7 +120,7 @@
{% endif %}
</button>
<ul
class="dropdown-menu dropdown-menu-end py-0 shadow border-0 rounded-3"
style="min-width: 240px;"
>
@ -324,6 +324,34 @@
});
}
});
function form_loader(){
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
const submitButton = form.querySelector('button[type="submit"], input[type="submit"]');
if (submitButton) {
submitButton.disabled = true;
submitButton.classList.add('loading');
window.addEventListener('unload', function() {
submitButton.disabled = false;
submitButton.classList.remove('loading');
});
}
});
});
}
form_loader();
try{
document.addEventListener('htmx:afterSwap', form_loader);
}catch(e){
console.error(e)
}
</script>
{% block customJS %}{% endblock %}

View File

@ -5,9 +5,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ATS Form Builder - Vanilla JS</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Updated CSS styles with a new Teal/Aqua theme */
:root {
@ -678,8 +678,8 @@
const djangoConfig = {
csrfToken: "{{ csrf_token }}",
saveUrl: "{% url 'save_form_template' %}",
loadUrl: {% if template_id %}"{% url 'load_form_template' template_id %}"{% else %}null{% endif %},
templateId: {% if template_id %}{{ template_id }}{% else %}null{% endif %},
loadUrl: {% if template_slug %}"{% url 'load_form_template' template_slug %}"{% else %}null{% endif %},
templateId: {% if template_slug %}'{{ template_slug }}'{% else %}null{% endif %},
jobId: {% if job_id %}{{ job_id }}{% else %}null{% endif %} // Add this if you need it
};
</script>
@ -779,7 +779,7 @@
<a href="{% url 'dashboard' %}" style="color: #6c757d !important; text-decoration: none !important;">Home</a>
/
</span>
<span class="me-2">
<a href="{% url 'job_list' %}" style="color: #6c757d !important; text-decoration: none !important;">Jobs</a>
/
@ -793,7 +793,7 @@
</nav>
<div class="toolbar">
<h1 id="formTitle">Resume Application Form</h1>
<div>
<button class="btn btn-outline" id="formSettingsBtn">
<i class="fas fa-cog"></i> Settings
@ -982,9 +982,9 @@
</div>
</div>
</div>
<script>
// Application State
const state = {
draggedStageIndex: null,
@ -1212,7 +1212,7 @@ const elements = {
name: state.formName,
description: state.formDescription,
is_active: state.formActive,
template_id: state.templateId,
template_slug: state.templateId,
stages: state.stages.map(stage => ({
name: stage.name,
predefined: stage.predefined,
@ -1248,7 +1248,7 @@ const elements = {
const result = await response.json();
if (result.success) {
state.templateId = result.template_id;
state.templateId = result.template_slug;
window.location.href = "{% url 'form_templates_list' %}";
} else {
@ -1280,7 +1280,7 @@ const elements = {
// Set stages (this is where your actual stages come from)
state.stages = templateData.stages;
state.templateId = templateData.id;
state.templateId = templateData.template_slug;
// Update next IDs to avoid conflicts
let maxFieldId = 0;

View File

@ -538,7 +538,7 @@
const csrfToken = '{{ csrf_token }}';
const state = {
templateId: {{ template_slug }},
templateId: '{{ template_slug }}',
stages: [],
currentStage: 0,
formData: {},
@ -838,20 +838,23 @@
const result = await response.json();
if (result.success) {
alert('Application submitted successfully! Thank you for your submission.');
window.location.href = '/applications/'; // Redirect to applications list
console.log('Application submitted successfully! Thank you for your submission.');
const redirect_url = result['redirect_url']
window.location.href = redirect_url; // Redirect to applications list
} else {
alert('Error submitting form: ' + (result.error || 'Unknown error'));
console.log(result)
console.log('Error submitting form: ' + (result.error || 'Unknown error'));
}
} catch (error) {
console.error('Submission error:', error);
console.log(error)
//console.error('Submission error:', error);
// Try to get response text for debugging
try {
const errorText = await response.text();
console.error('Response text:', errorText);
alert('Error submitting form. Server response: ' + errorText);
console.log('Error submitting form. Server response: ' + errorText);
} catch (e) {
alert('Error submitting form: ' + error.message);
console.log('Error submitting form: ' + error.message);
}
}
}