Enhance worker creation modal to include rota-specific choices and shift options, improving user experience and data handling.
This commit is contained in:
@@ -378,17 +378,39 @@
|
||||
control.appendChild(box);
|
||||
field.appendChild(control); col.appendChild(field); row.appendChild(col);
|
||||
} else {
|
||||
let input;
|
||||
if(f.type==='date'){
|
||||
input = document.createElement('input'); input.type='date'; input.className='datepicker input'; input.setAttribute('autocomplete','off'); input.value = item[f.name] || '';
|
||||
} else if(f.type==='int'){
|
||||
input = document.createElement('input'); input.type='number'; input.className='input'; input.value = item[f.name] || '';
|
||||
} else {
|
||||
input = document.createElement('input'); input.type='text'; input.className='input'; input.value = item[f.name] || '';
|
||||
}
|
||||
let input;
|
||||
if(f.type==='date'){
|
||||
input = document.createElement('input'); input.type='date'; input.className='datepicker input'; input.setAttribute('autocomplete','off'); input.value = item[f.name] || '';
|
||||
} else if(f.type==='int'){
|
||||
input = document.createElement('input'); input.type='number'; input.className='input'; input.value = item[f.name] || '';
|
||||
} else if(f.type==='shift'){
|
||||
// render a select populated with shift options passed via cfg
|
||||
input = document.createElement('select'); input.className='select';
|
||||
// wrap select in a div.select to match Bulma styling
|
||||
const selWrap = document.createElement('div'); selWrap.className = 'select';
|
||||
const sel = document.createElement('select');
|
||||
const emptyOpt = document.createElement('option'); emptyOpt.value = ''; emptyOpt.text = '(any)'; sel.appendChild(emptyOpt);
|
||||
const opts = (cfg && cfg.shiftOptions) ? cfg.shiftOptions : (typeof _shiftOptions !== 'undefined' ? _shiftOptions : []);
|
||||
if(Array.isArray(opts)){
|
||||
opts.forEach(o=>{ const op = document.createElement('option'); op.value = o; op.text = o; if(item[f.name] === o) op.selected = true; sel.appendChild(op); });
|
||||
}
|
||||
sel.value = item[f.name] || '';
|
||||
sel.onchange = ()=>{ sync(idx); };
|
||||
sel.setAttribute('data-field', f.name);
|
||||
selWrap.appendChild(sel);
|
||||
// set 'input' variable to the wrapper so downstream code appends it
|
||||
input = selWrap;
|
||||
} else {
|
||||
input = document.createElement('input'); input.type='text'; input.className='input'; input.value = item[f.name] || '';
|
||||
}
|
||||
// tag this control with the field name so sync() can find it reliably
|
||||
input.setAttribute('data-field', f.name);
|
||||
input.onchange = ()=>{ sync(idx); };
|
||||
if(input.tagName === 'DIV' && input.querySelector('select')){
|
||||
// wrapper created for select; the inner select already has data-field
|
||||
// nothing to do here
|
||||
} else {
|
||||
input.setAttribute('data-field', f.name);
|
||||
input.onchange = ()=>{ sync(idx); };
|
||||
}
|
||||
control.appendChild(input); field.appendChild(control); col.appendChild(field); row.appendChild(col);
|
||||
}
|
||||
});
|
||||
@@ -418,12 +440,12 @@
|
||||
if(vals.length) obj[f.name] = vals;
|
||||
} else {
|
||||
// single input control
|
||||
if(fld.tagName === 'INPUT'){
|
||||
if(fld.tagName === 'INPUT' || fld.tagName === 'SELECT'){
|
||||
const v = fld.value;
|
||||
if(v !== '') obj[f.name] = f.type==='int'?parseInt(v,10):v;
|
||||
} else {
|
||||
// container wrapping an input
|
||||
const inp = fld.querySelector('input');
|
||||
// container wrapping an input (e.g. div.select wrapper or custom control)
|
||||
const inp = fld.querySelector('input') || fld.querySelector('select');
|
||||
if(inp && inp.value !== '') obj[f.name] = f.type==='int'?parseInt(inp.value,10):inp.value;
|
||||
}
|
||||
}
|
||||
@@ -442,10 +464,16 @@
|
||||
makeSimpleListEditor({textarea:'id_oop', container:'oop-list', addButton:'add-oop', fields:[{name:'start_date',label:'Start date',type:'date'},{name:'end_date',label:'End date',type:'date'},{name:'reason',label:'Reason',type:'text'}]});
|
||||
makeSimpleListEditor({textarea:'id_not_available_to_work', container:'nav-list', addButton:'add-nav', fields:[{name:'date',label:'Date',type:'date'},{name:'reason',label:'Reason',type:'text'}]});
|
||||
makeSimpleListEditor({textarea:'id_pref_not_to_work', container:'pref-list', addButton:'add-pref', fields:[{name:'date',label:'Date',type:'date'},{name:'reason',label:'Reason',type:'text'}]});
|
||||
makeSimpleListEditor({textarea:'id_work_requests', container:'wr-list', addButton:'add-wr', fields:[{name:'date',label:'Date',type:'date'},{name:'shift',label:'Shift',type:'text'}]});
|
||||
makeSimpleListEditor({textarea:'id_locum_availability', container:'loc-list', addButton:'add-loc', fields:[{name:'date',label:'Date',type:'date'},{name:'shift',label:'Shift',type:'text'}]});
|
||||
makeSimpleListEditor({textarea:'id_forced_assignments', container:'fa-list', addButton:'add-fa', fields:[{name:'week',label:'Week',type:'int'},{name:'day',label:'Day',type:'text'},{name:'shift',label:'Shift',type:'text'}]});
|
||||
makeSimpleListEditor({textarea:'id_forced_assignments_by_date', container:'fabd-list', addButton:'add-fabd', fields:[{name:'date',label:'Date',type:'date'},{name:'shift',label:'Shift',type:'text'}]});
|
||||
// If the server provided shift names for the current rota, use them
|
||||
var _shiftOptions = [];
|
||||
try{
|
||||
_shiftOptions = {{ shift_names_json|default:'[]'|safe }};
|
||||
}catch(e){ _shiftOptions = []; }
|
||||
|
||||
makeSimpleListEditor({textarea:'id_work_requests', container:'wr-list', addButton:'add-wr', fields:[{name:'date',label:'Date',type:'date'},{name:'shift',label:'Shift',type:'shift'}], shiftOptions:_shiftOptions});
|
||||
makeSimpleListEditor({textarea:'id_locum_availability', container:'loc-list', addButton:'add-loc', fields:[{name:'date',label:'Date',type:'date'},{name:'shift',label:'Shift',type:'shift'}], shiftOptions:_shiftOptions});
|
||||
makeSimpleListEditor({textarea:'id_forced_assignments', container:'fa-list', addButton:'add-fa', fields:[{name:'week',label:'Week',type:'int'},{name:'day',label:'Day',type:'text'},{name:'shift',label:'Shift',type:'shift'}], shiftOptions:_shiftOptions});
|
||||
makeSimpleListEditor({textarea:'id_forced_assignments_by_date', container:'fabd-list', addButton:'add-fabd', fields:[{name:'date',label:'Date',type:'date'},{name:'shift',label:'Shift',type:'shift'}], shiftOptions:_shiftOptions});
|
||||
makeSimpleListEditor({textarea:'id_allowed_multi_shift_sets', container:'ams-list', addButton:'add-ams', fields:[{name:'shifts',label:'Shifts (comma-separated)',type:'text'}]});
|
||||
|
||||
// Hard day deps/exclusions need days/weeks/start/end
|
||||
|
||||
@@ -373,9 +373,35 @@ def worker_create(request):
|
||||
|
||||
# HTMX GET: return modal partial
|
||||
if is_hx:
|
||||
# If a rota_id query param is provided, include the rota in the
|
||||
# modal context so the template can offer rota-specific choices
|
||||
rota = None
|
||||
rota_id = request.GET.get("rota_id") or request.POST.get("rota_id")
|
||||
if rota_id:
|
||||
try:
|
||||
rota = get_object_or_404(RotaSchedule, pk=int(rota_id))
|
||||
except Exception:
|
||||
rota = None
|
||||
|
||||
# Prepare a JSON-encoded list of shift names for client-side use
|
||||
shift_names_json = '[]'
|
||||
try:
|
||||
import json as _json
|
||||
if rota is not None and getattr(rota, 'shifts', None):
|
||||
# rota.shifts is stored as list of dicts
|
||||
names = []
|
||||
for s in (rota.shifts or []):
|
||||
try:
|
||||
names.append(s.get('name'))
|
||||
except Exception:
|
||||
continue
|
||||
shift_names_json = _json.dumps(names)
|
||||
except Exception:
|
||||
shift_names_json = '[]'
|
||||
|
||||
modal_html = render_to_string(
|
||||
"rota/partials/worker_form_modal.html",
|
||||
{"form": form, "form_action": request.get_full_path()},
|
||||
{"form": form, "form_action": request.get_full_path(), "rota": rota, "shift_names_json": shift_names_json},
|
||||
request=request,
|
||||
)
|
||||
return HttpResponse(modal_html)
|
||||
|
||||
Reference in New Issue
Block a user