diff --git a/djangorota/djangorota/templates/rota/leave_request.html b/djangorota/djangorota/templates/rota/leave_request.html new file mode 100644 index 0000000..38f8116 --- /dev/null +++ b/djangorota/djangorota/templates/rota/leave_request.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block content %} +
+

Request leave{% if worker %} for {{ worker.name }}{% endif %}

+
+ {% csrf_token %} + {{ form|crispy }} +
+
+ +
+
+
+
+{% endblock %} diff --git a/djangorota/djangorota/templates/rota/partials/leave_request_modal.html b/djangorota/djangorota/templates/rota/partials/leave_request_modal.html new file mode 100644 index 0000000..0f7bd10 --- /dev/null +++ b/djangorota/djangorota/templates/rota/partials/leave_request_modal.html @@ -0,0 +1,25 @@ +{% load crispy_forms_tags %} + diff --git a/djangorota/djangorota/templates/rota/partials/worker_form_modal.html b/djangorota/djangorota/templates/rota/partials/worker_form_modal.html index c555f4e..8c1603b 100644 --- a/djangorota/djangorota/templates/rota/partials/worker_form_modal.html +++ b/djangorota/djangorota/templates/rota/partials/worker_form_modal.html @@ -124,6 +124,140 @@ // initial render try{ render(); }catch(e){ console && console.error && console.error(e); } + })(); + + +
+

Other structured fields

+

Quick editors for common lists so you don't need to edit JSON manually.

+ +
+
+
Out of programme
+
+ +
+ +
+
Not available to work
+ + +
+ +
+
Preferences not to work
+
+ +
+ +
+
Work requests
+
+ +
+ +
+
Locum availability
+
+ +
+ +
+
Forced assignments (week,day,shift)
+
+ +
+ +
+
Forced assignments by date
+
+ +
+ +
+
Hard day dependencies
+
+ +
+ +
+
Hard day exclusions
+
+ +
+ +
+
Allowed multi-shift sets
+
+ +
+
+
+ +
diff --git a/djangorota/rota/urls.py b/djangorota/rota/urls.py index 45507d7..e87783c 100644 --- a/djangorota/rota/urls.py +++ b/djangorota/rota/urls.py @@ -16,6 +16,7 @@ urlpatterns = [ path("worker///edit/", views.worker_edit, name="worker_edit"), path("worker///delete/", views.worker_delete, name="worker_delete"), path("worker//", views.worker_detail, name="worker_detail"), + path("leave/request/", views.request_leave, name="request_leave"), path("run//", views.rota_run_detail, name="rota_run_detail"), path("run//export/html/", views.rota_run_export_html, name="rota_run_export_html"), path("run//export/download/", views.rota_run_export_download, name="rota_run_export_download"), diff --git a/djangorota/rota/views.py b/djangorota/rota/views.py index 9bb6b6f..4aa9807 100644 --- a/djangorota/rota/views.py +++ b/djangorota/rota/views.py @@ -420,6 +420,68 @@ def rota_options_update(request, rota_id): return redirect("rota:rota_detail", rota_id=rota.id) +@require_http_methods(["GET", "POST"]) +def request_leave(request): + """Allow a worker to request leave for themselves. + + Resolution strategy: + - If the user is authenticated, try to find a `Worker` with matching + email (first match). If found, use that worker. + - Otherwise, fall back to `worker_id` provided via GET/POST. + + Supports HTMX modal flow when `HX-Request` header is present. + """ + is_hx = request.headers.get("HX-Request", "false").lower() == "true" + + worker = None + # try authenticated user -> worker by email + try: + if request.user and request.user.is_authenticated and getattr(request.user, "email", None): + worker = Worker.objects.filter(email=request.user.email).first() + except Exception: + worker = None + + # fallback to explicit worker_id + if worker is None: + worker_id = request.GET.get("worker_id") or request.POST.get("worker_id") + if worker_id: + try: + worker = get_object_or_404(Worker, pk=int(worker_id)) + except Exception: + worker = None + + if request.method == "POST": + form = LeaveForm(request.POST) + if form.is_valid(): + leave = form.save(commit=False) + if worker is None: + return HttpResponseBadRequest("Worker not specified or not found") + leave.worker = worker + leave.save() + # On HTMX modal post, return an OOB swap to close modal and optionally + # update worker detail partial if present. + if is_hx: + resp = '' + # optionally include trigger + response = HttpResponse(resp) + response["HX-Trigger"] = "closeModal" + return response + return redirect("rota:worker_detail", worker_id=worker.id) + else: + form = LeaveForm() + + # Render modal or full page + if is_hx: + modal_html = render_to_string( + "rota/partials/leave_request_modal.html", + {"form": form, "form_action": request.get_full_path(), "worker": worker}, + request=request, + ) + return HttpResponse(modal_html) + + return render(request, "rota/leave_request.html", {"form": form, "worker": worker}) + + def rota_options(request, rota_id): """HTMX-aware modal edit for rota.options JSON.