Commit a7138bea by Mac Stephens

convert Units/Complaints to modal overlays over Map; add details overlay,…

convert Units/Complaints to modal overlays over Map; add details overlay, bottom-nav-safe height, and refresh/navigation fixes
parent 2366105b
[Settings]
LogFileNum=627
LogFileNum=629
webClientVersion=0.1.0
......@@ -107,8 +107,8 @@ object FViewMain: TFViewMain
WidthPercent = 100.000000000000000000
end
object btnMap: TWebButton
Left = 148
Top = 58
Left = 212
Top = 580
Width = 59
Height = 25
Caption = 'Map'
......@@ -121,8 +121,8 @@ object FViewMain: TFViewMain
OnClick = btnMapClick
end
object btnComplaints: TWebButton
Left = 213
Top = 58
Left = 285
Top = 580
Width = 68
Height = 25
Caption = 'Complaints'
......@@ -135,8 +135,8 @@ object FViewMain: TFViewMain
OnClick = btnComplaintsClick
end
object btnUnits: TWebButton
Left = 294
Top = 58
Left = 364
Top = 580
Width = 59
Height = 25
Caption = 'Units'
......@@ -149,31 +149,75 @@ object FViewMain: TFViewMain
OnClick = btnUnitsClick
end
object pnlMap: TWebPanel
Left = 660
Top = 337
Width = 335
Height = 221
Left = 708
Top = 99
Width = 237
Height = 436
ElementID = 'pnl_map'
ChildOrder = 3
TabOrder = 6
end
object pnlUnits: TWebPanel
Left = 660
Top = 110
Width = 335
Height = 221
Left = 752
Top = 114
Width = 227
Height = 139
ElementID = 'pnl_units'
ChildOrder = 3
TabOrder = 7
object btnUnitsModalClose: TWebButton
Left = 190
Top = 8
Width = 28
Height = 23
ElementID = 'btn_units_modal_close'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
end
object pnlComplaints: TWebPanel
Left = 660
Top = 574
Width = 335
Height = 221
Left = 752
Top = 268
Width = 227
Height = 145
ElementID = 'pnl_complaints'
ChildOrder = 3
TabOrder = 8
object btnComplaintsModalClose: TWebButton
Left = 192
Top = 10
Width = 28
Height = 23
ElementID = 'btn_complaints_modal_close'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
end
object pnlDetails: TWebPanel
Left = 992
Top = 195
Width = 163
Height = 114
ElementID = 'pnl_details'
ChildOrder = 15
ElementFont = efCSS
TabOrder = 9
object WebButton1: TWebButton
Left = 127
Top = 8
Width = 28
Height = 23
ElementClassName = 'btn btn-light'
ElementID = 'btn_units_modal_close'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
end
object xdwcBadgeCounts: TXDataWebClient
Connection = DMConnection.ApiConnection
......
......@@ -13,17 +13,60 @@
<!-- Right: Connection label -->
<span id="view.main.lblconnection" class="navbar-text text-light ms-auto"></span>
</div>
</div>
</nav>
<!-- Main content: fills space between navbars -->
<div id="pnl_main" class="flex-grow-1 position-relative p-0 overflow-hidden d-none" style="min-height:0;"></div>
<div id="pnl_map" class="flex-grow-1 position-relative p-0 overflow-hidden" style="min-height:0;"></div>
<div id="pnl_units" class="flex-grow-1 position-relative p-0 overflow-hidden d-none" style="min-height:0;"></div>
<div id="pnl_complaints" class="flex-grow-1 position-relative p-0 overflow-hidden d-none" style="min-height:0;"></div>
<!-- Units modal (panel kept as-is; now acts as modal backdrop container) -->
<div id="pnl_units"
class="position-fixed top-0 start-0 w-100 d-none d-flex justify-content-center align-items-center"
style="height: calc(100% - var(--bottom-nav-h)); background: rgba(0,0,0,0.5); z-index:1050;">
<div class="card shadow-lg w-100 mx-2 d-flex flex-column" style="max-width: 96vw; height: 96%;">
<div class="card-header d-flex align-items-center justify-content-between">
<h5 class="card-title mb-0">Units</h5>
<button id="btn_units_modal_close" type="button" class="btn-close" aria-label="Close"></button>
</div>
<div class="card-body p-0 flex-grow-1 overflow-hidden" style="min-height:0;">
<div id="pnl_units_host" class="h-100"></div>
</div>
</div>
</div>
<!-- Complaints modal (panel kept as-is; now acts as modal backdrop container) -->
<div id="pnl_complaints"
class="position-fixed top-0 start-0 w-100 d-none d-flex justify-content-center align-items-center"
style="height: calc(100% - var(--bottom-nav-h)); background: rgba(0,0,0,0.5); z-index:1050;">
<div class="card shadow-lg w-100 mx-2 d-flex flex-column" style="max-width: 96vw; height: 96%;">
<div class="card-header d-flex align-items-center justify-content-between">
<h5 class="card-title mb-0">Complaints</h5>
<button id="btn_complaints_modal_close" type="button" class="btn-close" aria-label="Close"></button>
</div>
<div class="card-body p-0 flex-grow-1 overflow-hidden" style="min-height:0;">
<div id="pnl_complaints_host" class="h-100"></div>
</div>
</div>
</div>
<!-- Details modal (new panel pnl_details) -->
<div id="pnl_details"
class="position-fixed top-0 start-0 w-100 d-none d-flex justify-content-center align-items-center"
style="height: calc(100% - var(--bottom-nav-h)); background: rgba(0,0,0,0.5); z-index:1060;">
<div class="card shadow-lg w-100 mx-2 d-flex flex-column" style="max-width: 98vw; height: 96%;">
<div class="card-header d-flex align-items-center justify-content-between">
<h5 class="card-title mb-0" id="lbl_details_title">Details</h5>
<button id="btn_details_modal_close" type="button" class="btn-close" aria-label="Close"></button>
</div>
<div class="card-body p-0 flex-grow-1 overflow-hidden" style="min-height:0;">
<div id="pnl_details_host" class="h-100"></div>
</div>
</div>
</div>
<!-- Bottom Nav -->
<nav class="navbar navbar-dark bg-primary py-2 flex-shrink-0">
<nav id="bottom_nav" class="navbar navbar-dark bg-primary py-2 flex-shrink-0">
<div class="container-fluid">
<div class="d-flex justify-content-center gap-3 w-100">
<button id="view.main.btnmap" type="button" class="btn btn-primary">
......@@ -87,4 +130,3 @@
</div>
</div>
</div>
......@@ -28,6 +28,10 @@ type
pnlUnits: TWebPanel;
pnlComplaints: TWebPanel;
tmrGlobalRefresh: TWebTimer;
pnlDetails: TWebPanel;
btnUnitsModalClose: TWebButton;
btnComplaintsModalClose: TWebButton;
WebButton1: TWebButton;
procedure WebFormCreate(Sender: TObject);
procedure mnuLogoutClick(Sender: TObject);
procedure wllblLogoutClick(Sender: TObject);
......@@ -43,10 +47,16 @@ type
FMapForm: TFViewMap;
FUnitsForm: TFViewUnits;
FComplaintsForm: TFViewComplaints;
FDetailsForm: TWebForm;
FLogoutProc: TLogoutProc;
[async] procedure RefreshBadgesAsync;
procedure ShowUnitDetails(UnitId: string);
procedure SetHeaderTitle(const title: string);
procedure HideDetailsModal;
procedure HideListModals;
procedure ShowComplaintsModal;
procedure ShowDetailsModal(const titleText: string);
procedure ShowUnitsModal;
type TActivePanel = (apNone, apMap, apUnits, apComplaints);
var
......@@ -91,6 +101,11 @@ uses
{$R *.dfm}
const
UNITS_HOST_ID = 'pnl_units_host';
COMPLAINTS_HOST_ID = 'pnl_complaints_host';
DETAILS_HOST_ID = 'pnl_details_host';
procedure TFViewMain.WebFormCreate(Sender: TObject);
var
userName: string;
......@@ -98,6 +113,7 @@ begin
userName := JS.toString(AuthService.TokenPayload.Properties['user_name']);
lblUsername.Caption := ' ' + userName.ToLower + ' ';
FChildForm := nil;
FDetailsForm := nil;
FActivePanel := apNone;
FGlobalRefreshTick := 0;
......@@ -105,10 +121,28 @@ begin
FUnitsRefreshTick := 0;
FComplaintsRefreshTick := 0;
if (not (JS.toBoolean(AuthService.TokenPayload.Properties['user_admin']))) then
if (not (JS.toBoolean(AuthService.TokenPayload.Properties['user_admin']))) then
lblUsers.Visible := false;
Utils.HideSpinner('spinner');
ShowForm(TFViewMap);
// ensure map exists and is visible under everything
ShowPanel(pnlMap);
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
HidePanel(pnlDetails);
HidePanel(pnlMain);
if not Assigned(FMapForm) then
begin
Application.CreateForm(TFViewMap, pnlMap.ElementID, TWebForm(FMapForm));
MarkPanelCreatedUpToDate(apMap);
end;
SetHeaderTitle('Map');
SetActiveNavButton('view.main.btnmap');
SetActivePanel(apMap);
RefreshBadgesAsync;
end;
......@@ -148,15 +182,17 @@ begin
Console.Log('GlobalRefresh: refreshing panel=' + IntToStr(Ord(panel)) + ' at tick=' + IntToStr(FGlobalRefreshTick));
case panel of
apMap:
if Assigned(FMapForm) then
FMapForm.RefreshData; // ADD THIS DELETE BEFORE DEPLOY
apUnits:
if Assigned(FUnitsForm) then
FUnitsForm.RefreshData;
apComplaints:
if Assigned(FComplaintsForm) then
FComplaintsForm.RefreshData;
apMap:
if Assigned(FMapForm) then
FMapForm.RefreshData;
if Assigned(FComplaintsForm) then
FComplaintsForm.RefreshData;
end;
case panel of
......@@ -197,19 +233,21 @@ end;
procedure TFViewMain.btnComplaintsClick(Sender: TObject);
begin
ShowForm(TFViewComplaints);
ShowComplaintsModal;
end;
procedure TFViewMain.btnMapClick(Sender: TObject);
begin
ShowForm(TFViewMap);
HideListModals;
SetHeaderTitle('Map');
SetActiveNavButton('view.main.btnmap');
end;
procedure TFViewMain.btnUnitsClick(Sender: TObject);
begin
ShowForm(TFViewUnits);
ShowUnitsModal;
end;
......@@ -224,84 +262,31 @@ end;
procedure TFViewMain.ShowForm(AFormClass: TWebFormClass);
begin
// Map Panel
if AFormClass = TFViewMap then
begin
HidePanel(pnlMain);
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
ShowPanel(pnlMap);
SetHeaderTitle('Map');
SetActiveNavButton('view.main.btnmap');
SetActivePanel(apMap);
if not Assigned(FMapForm) then
begin
Application.CreateForm(TFViewMap, pnlMap.ElementID, TWebForm(FMapForm));
MarkPanelCreatedUpToDate(apMap);
end
else
RefreshPanelIfNeeded(apMap);
FChildForm := FMapForm;
HideListModals;
Exit;
end;
// Units Panel
if AFormClass = TFViewUnits then
begin
HidePanel(pnlMain);
HidePanel(pnlMap);
HidePanel(pnlComplaints);
ShowPanel(pnlUnits);
SetHeaderTitle('Units');
SetActiveNavButton('view.main.btnunits');
SetActivePanel(apUnits);
if not Assigned(FUnitsForm) then
begin
Application.CreateForm(TFViewUnits, pnlUnits.ElementID, TWebForm(FUnitsForm));
MarkPanelCreatedUpToDate(apUnits);
end
else
RefreshPanelIfNeeded(apUnits);
FChildForm := FUnitsForm;
ShowUnitsModal;
Exit;
end;
// Complaints Panel
if AFormClass = TFViewComplaints then
begin
HidePanel(pnlMain);
HidePanel(pnlMap);
HidePanel(pnlUnits);
ShowPanel(pnlComplaints);
SetHeaderTitle('Complaints');
SetActiveNavButton('view.main.btncomplaints');
SetActivePanel(apComplaints);
if not Assigned(FComplaintsForm) then
begin
Application.CreateForm(TFViewComplaints, pnlComplaints.ElementID, TWebForm(FComplaintsForm));
MarkPanelCreatedUpToDate(apComplaints);
end
else
RefreshPanelIfNeeded(apComplaints);
FChildForm := FComplaintsForm;
ShowComplaintsModal;
Exit;
end;
// Everything else: use pnlMain
// everything else (admin/users/etc) can still use pnlMain
SetActivePanel(apNone);
HidePanel(pnlMap);
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
HidePanel(pnlDetails);
ShowPanel(pnlMain);
if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then
......@@ -334,34 +319,27 @@ end;
procedure TFViewMain.ShowComplaintDetails(ComplaintId: string);
begin
SetActivePanel(apNone);
SetHeaderTitle('Complaint Details');
// ensure complaints list is visible underneath
ShowComplaintsModal;
HidePanel(pnlMap);
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
ShowPanel(pnlMain);
ShowDetailsModal('Complaint Details');
if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then
FChildForm.Free;
if Assigned(FDetailsForm) then
FDetailsForm.Free;
FChildForm := TFViewComplaintDetails.CreateForm(pnlMain.ElementID, ComplaintId);
FDetailsForm := TFViewComplaintDetails.CreateForm(DETAILS_HOST_ID, ComplaintId);
end;
procedure TFViewMain.ShowUnitDetails(UnitId: string);
begin
SetActivePanel(apNone);
SetHeaderTitle('Unit Details');
ShowUnitsModal;
HidePanel(pnlMap);
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
ShowPanel(pnlMain);
ShowDetailsModal('Unit Details');
if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then
FChildForm.Free;
if Assigned(FDetailsForm) then
FDetailsForm.Free;
FChildForm := TFViewUnitDetails.CreateForm(pnlMain.ElementID, UnitId);
FDetailsForm := TFViewUnitDetails.CreateForm(DETAILS_HOST_ID, UnitId);
end;
......@@ -434,15 +412,15 @@ procedure TFViewMain.ShowMapFocusUnit(const unitId: string);
var
pendingUnitId: string;
begin
ShowForm(TFViewMap);
HideListModals;
pendingUnitId := unitId;
window.setTimeout(
procedure
begin
if (FChildForm <> nil) and (FChildForm is TFViewMap) then
TFViewMap(FChildForm).FocusUnit(pendingUnitId);
if Assigned(FMapForm) then
FMapForm.FocusUnit(pendingUnitId);
end, 50);
end;
......@@ -450,17 +428,90 @@ procedure TFViewMain.ShowMapFocusComplaint(const complaintId: string);
var
pendingComplaintId: string;
begin
ShowForm(TFViewMap);
HideListModals;
pendingComplaintId := complaintId;
pendingComplaintId := complaintId;
window.setTimeout(
procedure
begin
if (FChildForm <> nil) and (FChildForm is TFViewMap) then
TFViewMap(FChildForm).FocusComplaint(pendingComplaintId);
if Assigned(FMapForm) then
FMapForm.FocusComplaint(pendingComplaintId);
end, 50);
end;
//------------------------------------------------------------------------------
procedure TFViewMain.HideDetailsModal;
begin
HidePanel(pnlDetails);
if Assigned(FDetailsForm) then
begin
FDetailsForm.Free;
FDetailsForm := nil;
end;
end;
procedure TFViewMain.HideListModals;
begin
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
HideDetailsModal;
SetHeaderTitle('Map');
SetActiveNavButton('view.main.btnmap');
SetActivePanel(apMap);
end;
procedure TFViewMain.ShowUnitsModal;
begin
// show units, hide complaints, keep map visible underneath
HidePanel(pnlComplaints);
ShowPanel(pnlUnits);
SetHeaderTitle('Units');
SetActiveNavButton('view.main.btnunits');
SetActivePanel(apUnits);
if not Assigned(FUnitsForm) then
begin
Application.CreateForm(TFViewUnits, UNITS_HOST_ID, TWebForm(FUnitsForm));
MarkPanelCreatedUpToDate(apUnits);
end
else
RefreshPanelIfNeeded(apUnits);
end;
procedure TFViewMain.ShowComplaintsModal;
begin
HidePanel(pnlUnits);
ShowPanel(pnlComplaints);
SetHeaderTitle('Complaints');
SetActiveNavButton('view.main.btncomplaints');
SetActivePanel(apComplaints);
if not Assigned(FComplaintsForm) then
begin
Application.CreateForm(TFViewComplaints, COMPLAINTS_HOST_ID, TWebForm(FComplaintsForm));
MarkPanelCreatedUpToDate(apComplaints);
end
else
RefreshPanelIfNeeded(apComplaints);
end;
procedure TFViewMain.ShowDetailsModal(const titleText: string);
var
el: TJSElement;
begin
ShowPanel(pnlDetails);
el := Document.getElementById('lbl_details_title');
if el <> nil then
el.innerHTML := titleText;
end;
end.
......@@ -4,6 +4,10 @@ span.card {
border: none;
}
:root {
--bottom-nav-h: 54px;
}
/* --- Login Screen Styling --- */
.login-card {
display: inline-block; /* Or use d-flex on the parent to center it */
......@@ -85,3 +89,5 @@ html, body {
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment