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] [Settings]
LogFileNum=627 LogFileNum=629
webClientVersion=0.1.0 webClientVersion=0.1.0
...@@ -107,8 +107,8 @@ object FViewMain: TFViewMain ...@@ -107,8 +107,8 @@ object FViewMain: TFViewMain
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
end end
object btnMap: TWebButton object btnMap: TWebButton
Left = 148 Left = 212
Top = 58 Top = 580
Width = 59 Width = 59
Height = 25 Height = 25
Caption = 'Map' Caption = 'Map'
...@@ -121,8 +121,8 @@ object FViewMain: TFViewMain ...@@ -121,8 +121,8 @@ object FViewMain: TFViewMain
OnClick = btnMapClick OnClick = btnMapClick
end end
object btnComplaints: TWebButton object btnComplaints: TWebButton
Left = 213 Left = 285
Top = 58 Top = 580
Width = 68 Width = 68
Height = 25 Height = 25
Caption = 'Complaints' Caption = 'Complaints'
...@@ -135,8 +135,8 @@ object FViewMain: TFViewMain ...@@ -135,8 +135,8 @@ object FViewMain: TFViewMain
OnClick = btnComplaintsClick OnClick = btnComplaintsClick
end end
object btnUnits: TWebButton object btnUnits: TWebButton
Left = 294 Left = 364
Top = 58 Top = 580
Width = 59 Width = 59
Height = 25 Height = 25
Caption = 'Units' Caption = 'Units'
...@@ -149,31 +149,75 @@ object FViewMain: TFViewMain ...@@ -149,31 +149,75 @@ object FViewMain: TFViewMain
OnClick = btnUnitsClick OnClick = btnUnitsClick
end end
object pnlMap: TWebPanel object pnlMap: TWebPanel
Left = 660 Left = 708
Top = 337 Top = 99
Width = 335 Width = 237
Height = 221 Height = 436
ElementID = 'pnl_map' ElementID = 'pnl_map'
ChildOrder = 3 ChildOrder = 3
TabOrder = 6 TabOrder = 6
end end
object pnlUnits: TWebPanel object pnlUnits: TWebPanel
Left = 660 Left = 752
Top = 110 Top = 114
Width = 335 Width = 227
Height = 221 Height = 139
ElementID = 'pnl_units' ElementID = 'pnl_units'
ChildOrder = 3 ChildOrder = 3
TabOrder = 7 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 end
object pnlComplaints: TWebPanel object pnlComplaints: TWebPanel
Left = 660 Left = 752
Top = 574 Top = 268
Width = 335 Width = 227
Height = 221 Height = 145
ElementID = 'pnl_complaints' ElementID = 'pnl_complaints'
ChildOrder = 3 ChildOrder = 3
TabOrder = 8 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 end
object xdwcBadgeCounts: TXDataWebClient object xdwcBadgeCounts: TXDataWebClient
Connection = DMConnection.ApiConnection Connection = DMConnection.ApiConnection
......
...@@ -13,17 +13,60 @@ ...@@ -13,17 +13,60 @@
<!-- Right: Connection label --> <!-- Right: Connection label -->
<span id="view.main.lblconnection" class="navbar-text text-light ms-auto"></span> <span id="view.main.lblconnection" class="navbar-text text-light ms-auto"></span>
</div> </div>
</nav> </nav>
<!-- Main content: fills space between navbars --> <!-- 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_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_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 --> <!-- 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="container-fluid">
<div class="d-flex justify-content-center gap-3 w-100"> <div class="d-flex justify-content-center gap-3 w-100">
<button id="view.main.btnmap" type="button" class="btn btn-primary"> <button id="view.main.btnmap" type="button" class="btn btn-primary">
...@@ -87,4 +130,3 @@ ...@@ -87,4 +130,3 @@
</div> </div>
</div> </div>
</div> </div>
...@@ -28,6 +28,10 @@ type ...@@ -28,6 +28,10 @@ type
pnlUnits: TWebPanel; pnlUnits: TWebPanel;
pnlComplaints: TWebPanel; pnlComplaints: TWebPanel;
tmrGlobalRefresh: TWebTimer; tmrGlobalRefresh: TWebTimer;
pnlDetails: TWebPanel;
btnUnitsModalClose: TWebButton;
btnComplaintsModalClose: TWebButton;
WebButton1: TWebButton;
procedure WebFormCreate(Sender: TObject); procedure WebFormCreate(Sender: TObject);
procedure mnuLogoutClick(Sender: TObject); procedure mnuLogoutClick(Sender: TObject);
procedure wllblLogoutClick(Sender: TObject); procedure wllblLogoutClick(Sender: TObject);
...@@ -43,10 +47,16 @@ type ...@@ -43,10 +47,16 @@ type
FMapForm: TFViewMap; FMapForm: TFViewMap;
FUnitsForm: TFViewUnits; FUnitsForm: TFViewUnits;
FComplaintsForm: TFViewComplaints; FComplaintsForm: TFViewComplaints;
FDetailsForm: TWebForm;
FLogoutProc: TLogoutProc; FLogoutProc: TLogoutProc;
[async] procedure RefreshBadgesAsync; [async] procedure RefreshBadgesAsync;
procedure ShowUnitDetails(UnitId: string); procedure ShowUnitDetails(UnitId: string);
procedure SetHeaderTitle(const title: 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); type TActivePanel = (apNone, apMap, apUnits, apComplaints);
var var
...@@ -91,6 +101,11 @@ uses ...@@ -91,6 +101,11 @@ uses
{$R *.dfm} {$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); procedure TFViewMain.WebFormCreate(Sender: TObject);
var var
userName: string; userName: string;
...@@ -98,6 +113,7 @@ begin ...@@ -98,6 +113,7 @@ begin
userName := JS.toString(AuthService.TokenPayload.Properties['user_name']); userName := JS.toString(AuthService.TokenPayload.Properties['user_name']);
lblUsername.Caption := ' ' + userName.ToLower + ' '; lblUsername.Caption := ' ' + userName.ToLower + ' ';
FChildForm := nil; FChildForm := nil;
FDetailsForm := nil;
FActivePanel := apNone; FActivePanel := apNone;
FGlobalRefreshTick := 0; FGlobalRefreshTick := 0;
...@@ -105,10 +121,28 @@ begin ...@@ -105,10 +121,28 @@ begin
FUnitsRefreshTick := 0; FUnitsRefreshTick := 0;
FComplaintsRefreshTick := 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; lblUsers.Visible := false;
Utils.HideSpinner('spinner'); 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; RefreshBadgesAsync;
end; end;
...@@ -148,15 +182,17 @@ begin ...@@ -148,15 +182,17 @@ begin
Console.Log('GlobalRefresh: refreshing panel=' + IntToStr(Ord(panel)) + ' at tick=' + IntToStr(FGlobalRefreshTick)); Console.Log('GlobalRefresh: refreshing panel=' + IntToStr(Ord(panel)) + ' at tick=' + IntToStr(FGlobalRefreshTick));
case panel of case panel of
apMap:
if Assigned(FMapForm) then
FMapForm.RefreshData; // ADD THIS DELETE BEFORE DEPLOY
apUnits: apUnits:
if Assigned(FUnitsForm) then if Assigned(FUnitsForm) then
FUnitsForm.RefreshData; FUnitsForm.RefreshData;
apComplaints: apComplaints:
if Assigned(FComplaintsForm) then if Assigned(FComplaintsForm) then
FComplaintsForm.RefreshData; FComplaintsForm.RefreshData;
apMap:
if Assigned(FMapForm) then
FMapForm.RefreshData;
end; end;
case panel of case panel of
...@@ -197,19 +233,21 @@ end; ...@@ -197,19 +233,21 @@ end;
procedure TFViewMain.btnComplaintsClick(Sender: TObject); procedure TFViewMain.btnComplaintsClick(Sender: TObject);
begin begin
ShowForm(TFViewComplaints); ShowComplaintsModal;
end; end;
procedure TFViewMain.btnMapClick(Sender: TObject); procedure TFViewMain.btnMapClick(Sender: TObject);
begin begin
ShowForm(TFViewMap); HideListModals;
SetHeaderTitle('Map');
SetActiveNavButton('view.main.btnmap');
end; end;
procedure TFViewMain.btnUnitsClick(Sender: TObject); procedure TFViewMain.btnUnitsClick(Sender: TObject);
begin begin
ShowForm(TFViewUnits); ShowUnitsModal;
end; end;
...@@ -224,84 +262,31 @@ end; ...@@ -224,84 +262,31 @@ end;
procedure TFViewMain.ShowForm(AFormClass: TWebFormClass); procedure TFViewMain.ShowForm(AFormClass: TWebFormClass);
begin begin
// Map Panel
if AFormClass = TFViewMap then if AFormClass = TFViewMap then
begin begin
HidePanel(pnlMain); HideListModals;
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;
Exit; Exit;
end; end;
// Units Panel
if AFormClass = TFViewUnits then if AFormClass = TFViewUnits then
begin begin
HidePanel(pnlMain); ShowUnitsModal;
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;
Exit; Exit;
end; end;
// Complaints Panel
if AFormClass = TFViewComplaints then if AFormClass = TFViewComplaints then
begin begin
HidePanel(pnlMain); ShowComplaintsModal;
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;
Exit; Exit;
end; end;
// Everything else: use pnlMain // everything else (admin/users/etc) can still use pnlMain
SetActivePanel(apNone); SetActivePanel(apNone);
HidePanel(pnlMap);
HidePanel(pnlUnits); HidePanel(pnlUnits);
HidePanel(pnlComplaints); HidePanel(pnlComplaints);
HidePanel(pnlDetails);
ShowPanel(pnlMain); ShowPanel(pnlMain);
if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then
...@@ -334,34 +319,27 @@ end; ...@@ -334,34 +319,27 @@ end;
procedure TFViewMain.ShowComplaintDetails(ComplaintId: string); procedure TFViewMain.ShowComplaintDetails(ComplaintId: string);
begin begin
SetActivePanel(apNone); // ensure complaints list is visible underneath
SetHeaderTitle('Complaint Details'); ShowComplaintsModal;
HidePanel(pnlMap); ShowDetailsModal('Complaint Details');
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
ShowPanel(pnlMain);
if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then if Assigned(FDetailsForm) then
FChildForm.Free; FDetailsForm.Free;
FChildForm := TFViewComplaintDetails.CreateForm(pnlMain.ElementID, ComplaintId); FDetailsForm := TFViewComplaintDetails.CreateForm(DETAILS_HOST_ID, ComplaintId);
end; end;
procedure TFViewMain.ShowUnitDetails(UnitId: string); procedure TFViewMain.ShowUnitDetails(UnitId: string);
begin begin
SetActivePanel(apNone); ShowUnitsModal;
SetHeaderTitle('Unit Details');
HidePanel(pnlMap); ShowDetailsModal('Unit Details');
HidePanel(pnlUnits);
HidePanel(pnlComplaints);
ShowPanel(pnlMain);
if Assigned(FChildForm) and (FChildForm <> FMapForm) and (FChildForm <> FUnitsForm) and (FChildForm <> FComplaintsForm) then if Assigned(FDetailsForm) then
FChildForm.Free; FDetailsForm.Free;
FChildForm := TFViewUnitDetails.CreateForm(pnlMain.ElementID, UnitId); FDetailsForm := TFViewUnitDetails.CreateForm(DETAILS_HOST_ID, UnitId);
end; end;
...@@ -434,15 +412,15 @@ procedure TFViewMain.ShowMapFocusUnit(const unitId: string); ...@@ -434,15 +412,15 @@ procedure TFViewMain.ShowMapFocusUnit(const unitId: string);
var var
pendingUnitId: string; pendingUnitId: string;
begin begin
ShowForm(TFViewMap); HideListModals;
pendingUnitId := unitId; pendingUnitId := unitId;
window.setTimeout( window.setTimeout(
procedure procedure
begin begin
if (FChildForm <> nil) and (FChildForm is TFViewMap) then if Assigned(FMapForm) then
TFViewMap(FChildForm).FocusUnit(pendingUnitId); FMapForm.FocusUnit(pendingUnitId);
end, 50); end, 50);
end; end;
...@@ -450,17 +428,90 @@ procedure TFViewMain.ShowMapFocusComplaint(const complaintId: string); ...@@ -450,17 +428,90 @@ procedure TFViewMain.ShowMapFocusComplaint(const complaintId: string);
var var
pendingComplaintId: string; pendingComplaintId: string;
begin begin
ShowForm(TFViewMap); HideListModals;
pendingComplaintId := complaintId; pendingComplaintId := complaintId;
window.setTimeout( window.setTimeout(
procedure procedure
begin begin
if (FChildForm <> nil) and (FChildForm is TFViewMap) then if Assigned(FMapForm) then
TFViewMap(FChildForm).FocusComplaint(pendingComplaintId); FMapForm.FocusComplaint(pendingComplaintId);
end, 50); end, 50);
end; 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. end.
...@@ -4,6 +4,10 @@ span.card { ...@@ -4,6 +4,10 @@ span.card {
border: none; border: none;
} }
:root {
--bottom-nav-h: 54px;
}
/* --- Login Screen Styling --- */ /* --- Login Screen Styling --- */
.login-card { .login-card {
display: inline-block; /* Or use d-flex on the parent to center it */ display: inline-block; /* Or use d-flex on the parent to center it */
...@@ -85,3 +89,5 @@ html, body { ...@@ -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