Commit 80ed6f36 by emsys

Merge branch 'master' into websockets

parents 376416dd 63541f7e
...@@ -9,17 +9,19 @@ emiMobileServer/doc/ ...@@ -9,17 +9,19 @@ emiMobileServer/doc/
emiMobileServer/Win32/ emiMobileServer/Win32/
emiMobileServer/*.log emiMobileServer/*.log
emiMobileServer/*.txt emiMobileServer/*.txt
emiMobileServer/bin/logs/
emiMobileServer/bin/static/
emiMobileServer/Source/__history emiMobileServer/Source/__history
emiMobileServer/Source/__recovery/ emiMobileServer/Source/__recovery/
emiMobileServer/logs/*
*.local *.local
*.exe *.exe
*.identcache *.identcache
*.res *.res
*.tvsconfig *.tvsconfig
*.dxsettings *.dxsettings
*.zip *.zip
*.log
*.dll
...@@ -590,17 +590,66 @@ object ApiDatabaseModule: TApiDatabaseModule ...@@ -590,17 +590,66 @@ object ApiDatabaseModule: TApiDatabaseModule
' a.STRPREFIX,' ' a.STRPREFIX,'
' a.STRNAME,' ' a.STRNAME,'
' a.STRSUFFIX,' ' a.STRSUFFIX,'
' a.CITY' ' a.CITY,'
' 0 as status'
'FROM COMPLAINT_ACTIVE ca' 'FROM COMPLAINT_ACTIVE ca'
'JOIN COMPLAINT_TIMES ct' 'JOIN COMPLAINT_TIMES ct'
' ON ca.COMPLAINTID = ct.COMPLAINTID' ' ON ca.COMPLAINTID = ct.COMPLAINTID'
'LEFT JOIN CD_DISPATCHCODES cdc' 'LEFT JOIN CD_DISPATCHCODES cdc'
' ON ca.DISPATCHCODE = cdc.CODE' ' ON ca.DISPATCHCODE = cdc.CODE'
'JOIN CD_DISTRICT cd' 'LEFT JOIN CD_DISTRICT cd'
' ON cd.AGENCYCODE = ca.DISPATCHDISTRICT'
'LEFT JOIN ADDRESS a'
' ON ca.ADDRESSID = a.ADDRESSID'
'WHERE ca.COMPLAINTID = :COMPLAINTID'
''
'union'
''
'SELECT'
' ca.COMPLAINTID,'
' ca.CFSID,'
' ca.COMPLAINT,'
' ca.PRIORITY,'
' ca.DISPATCHCODE,'
' cdc.CODE_DESC AS DISPATCH_CODE_DESC,'
' cd.CODE_DESC AS DISPATCHDISTRICT,'
' ca.ADDRESS,'
' ca.BUSINESS,'
' ct.DATEREPORTED,'
' ct.DATERECEIVED,'
' ct.DATEDISPATCHED,'
' ct.DATERESPONDED,'
' ct.DATEARRIVED,'
' ct.DATECLEARED,'
''
' -- For enabling/disabling buttons (disable when = '#39'-1'#39')'
' ca.HISTORY,'
' ca.CONTACTS,'
' ca.WARNINGS,'
''
' -- For Contacts + Warnings lookups'
' ca.ADDRESSID,'
' ca.AGENCY,'
''
' -- For History matching (address parts)'
' a.STRNUMBER,'
' a.STRHNUMBER,'
' a.STRPREFIX,'
' a.STRNAME,'
' a.STRSUFFIX,'
' a.CITY,'
' 1 as status'
'FROM COMPLAINT_ARCHIVE ca'
'JOIN COMPLAINT_TIMES ct'
' ON ca.COMPLAINTID = ct.COMPLAINTID'
'LEFT JOIN CD_DISPATCHCODES cdc'
' ON ca.DISPATCHCODE = cdc.CODE'
'LEFT JOIN CD_DISTRICT cd'
' ON cd.AGENCYCODE = ca.DISPATCHDISTRICT' ' ON cd.AGENCYCODE = ca.DISPATCHDISTRICT'
'LEFT JOIN ADDRESS a' 'LEFT JOIN ADDRESS a'
' ON ca.ADDRESSID = a.ADDRESSID' ' ON ca.ADDRESSID = a.ADDRESSID'
'WHERE ca.COMPLAINTID = :COMPLAINTID;') 'WHERE ca.COMPLAINTID = :COMPLAINTID;'
'')
ReadOnly = True ReadOnly = True
Left = 80 Left = 80
Top = 302 Top = 302
...@@ -713,6 +762,10 @@ object ApiDatabaseModule: TApiDatabaseModule ...@@ -713,6 +762,10 @@ object ApiDatabaseModule: TApiDatabaseModule
FieldName = 'BUSINESS' FieldName = 'BUSINESS'
Size = 35 Size = 35
end end
object uqComplaintDetailsSTATUS: TFloatField
FieldName = 'STATUS'
ReadOnly = True
end
end end
object ucENTCAD: TUniConnection object ucENTCAD: TUniConnection
ProviderName = 'Oracle' ProviderName = 'Oracle'
...@@ -807,8 +860,10 @@ object ApiDatabaseModule: TApiDatabaseModule ...@@ -807,8 +860,10 @@ object ApiDatabaseModule: TApiDatabaseModule
Calculated = True Calculated = True
end end
object uqMapComplaintspngName: TStringField object uqMapComplaintspngName: TStringField
DisplayWidth = 100
FieldKind = fkCalculated FieldKind = fkCalculated
FieldName = 'pngName' FieldName = 'pngName'
Size = 100
Calculated = True Calculated = True
end end
object uqMapComplaintsBUSINESS: TStringField object uqMapComplaintsBUSINESS: TStringField
...@@ -908,6 +963,7 @@ object ApiDatabaseModule: TApiDatabaseModule ...@@ -908,6 +963,7 @@ object ApiDatabaseModule: TApiDatabaseModule
' where ca.complaintid = :COMPLAINTID' ' where ca.complaintid = :COMPLAINTID'
')' ')'
'select' 'select'
' c.complaintid,'
' c.complaint,' ' c.complaint,'
' c.apartment,' ' c.apartment,'
' c.datereported,' ' c.datereported,'
...@@ -929,14 +985,39 @@ object ApiDatabaseModule: TApiDatabaseModule ...@@ -929,14 +985,39 @@ object ApiDatabaseModule: TApiDatabaseModule
'and (ctx.city is null or c.city = ctx.city)' 'and (ctx.city is null or c.city = ctx.city)'
'order by c.datereported desc') 'order by c.datereported desc')
ReadOnly = True ReadOnly = True
Left = 328 Left = 330
Top = 72 Top = 72
ParamData = < ParamData = <
item item
DataType = ftUnknown DataType = ftUnknown
Name = 'COMPLAINTID' Name = 'COMPLAINTID'
Value = nil Value = Null
end> end>
object uqComplaintHistoryCOMPLAINTID: TFloatField
FieldName = 'COMPLAINTID'
Required = True
end
object uqComplaintHistoryCOMPLAINT: TStringField
FieldName = 'COMPLAINT'
Size = 10
end
object uqComplaintHistoryAPARTMENT: TStringField
FieldName = 'APARTMENT'
Size = 6
end
object uqComplaintHistoryDATEREPORTED: TDateTimeField
FieldName = 'DATEREPORTED'
end
object uqComplaintHistoryDPRIORITY: TStringField
FieldName = 'DPRIORITY'
ReadOnly = True
Size = 120
end
object uqComplaintHistoryDCALLTYPE: TStringField
FieldName = 'DCALLTYPE'
ReadOnly = True
Size = 60
end
end end
object uqComplaintContacts: TUniQuery object uqComplaintContacts: TUniQuery
Connection = ucENTCAD Connection = ucENTCAD
......
...@@ -172,6 +172,13 @@ type ...@@ -172,6 +172,13 @@ type
uqMapUnitsDIS_UNITID: TFloatField; uqMapUnitsDIS_UNITID: TFloatField;
uqMapComplaintsBUSINESS: TStringField; uqMapComplaintsBUSINESS: TStringField;
uqComplaintDetailsBUSINESS: TStringField; uqComplaintDetailsBUSINESS: TStringField;
uqComplaintDetailsSTATUS: TFloatField;
uqComplaintHistoryCOMPLAINTID: TFloatField;
uqComplaintHistoryCOMPLAINT: TStringField;
uqComplaintHistoryAPARTMENT: TStringField;
uqComplaintHistoryDATEREPORTED: TDateTimeField;
uqComplaintHistoryDPRIORITY: TStringField;
uqComplaintHistoryDCALLTYPE: TStringField;
procedure uqComplaintListCalcFields(DataSet: TDataSet); procedure uqComplaintListCalcFields(DataSet: TDataSet);
procedure uqMapComplaintsCalcFields(DataSet: TDataSet); procedure uqMapComplaintsCalcFields(DataSet: TDataSet);
private private
......
...@@ -22,6 +22,7 @@ type ...@@ -22,6 +22,7 @@ type
[HttpGet] function GetComplaintMap: TJSONObject; [HttpGet] function GetComplaintMap: TJSONObject;
[HttpGet] function GetUnitMap: TJSONObject; [HttpGet] function GetUnitMap: TJSONObject;
[HttpGet] function GetComplaintDetails(const ComplaintId: string): TJSONObject; [HttpGet] function GetComplaintDetails(const ComplaintId: string): TJSONObject;
[HttpGet] function GetComplaintArchiveDetails(const ComplaintId: string): TJSONObject;
[HttpGet] function GetComplaintMemos(const CfsId: string): TJSONObject; [HttpGet] function GetComplaintMemos(const CfsId: string): TJSONObject;
[HttpGet] function GetComplaintHistory(const ComplaintId: string): TJSONObject; [HttpGet] function GetComplaintHistory(const ComplaintId: string): TJSONObject;
[HttpGet] function GetComplaintContacts(const ComplaintId: string): TJSONObject; [HttpGet] function GetComplaintContacts(const ComplaintId: string): TJSONObject;
......
...@@ -24,6 +24,7 @@ type ...@@ -24,6 +24,7 @@ type
function GetComplaintMap: TJSONObject; function GetComplaintMap: TJSONObject;
function GetUnitMap: TJSONObject; function GetUnitMap: TJSONObject;
function GetComplaintDetails(const ComplaintId: string): TJSONObject; function GetComplaintDetails(const ComplaintId: string): TJSONObject;
function GetComplaintArchiveDetails(const ComplaintId: string): TJSONObject;
function GetComplaintHistory(const ComplaintId: string): TJSONObject; function GetComplaintHistory(const ComplaintId: string): TJSONObject;
function GetComplaintContacts(const ComplaintId: string): TJSONObject; function GetComplaintContacts(const ComplaintId: string): TJSONObject;
function GetComplaintWarnings(const ComplaintId: string): TJSONObject; function GetComplaintWarnings(const ComplaintId: string): TJSONObject;
...@@ -443,7 +444,6 @@ begin ...@@ -443,7 +444,6 @@ begin
end; end;
function TApiService.GetComplaintDetails(const ComplaintId: string): TJSONObject; function TApiService.GetComplaintDetails(const ComplaintId: string): TJSONObject;
var var
obj: TJSONObject; obj: TJSONObject;
...@@ -525,6 +525,91 @@ begin ...@@ -525,6 +525,91 @@ begin
end; end;
function TApiService.GetComplaintArchiveDetails(const ComplaintId: string): TJSONObject;
var
obj: TJSONObject;
begin
Logger.Log(3,'---TApiService.GetComplaintArchiveDetails initiated: '+ComplaintId);
Result := TJSONObject.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
try
with ApiDB.uqComplaintDetails do
begin
ParamByName('COMPLAINTID').AsString := ComplaintId;
Open;
try
if Eof then raise EXDataHttpException.Create(404,'Complaint not found');
if not Locate('STATUS', 1, []) then
raise EXDataHttpException.Create(404,'Complaint archive not found');
obj := TJSONObject.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(obj);
obj.AddPair('ComplaintId', ApiDB.uqComplaintDetailsCOMPLAINTID.AsString);
obj.AddPair('CFSId', ApiDB.uqComplaintDetailsCFSID.AsString);
obj.AddPair('Complaint', ApiDB.uqComplaintDetailsCOMPLAINT.AsString);
obj.AddPair('Priority', ApiDB.uqComplaintDetailsPRIORITY.AsString);
obj.AddPair('DispatchCode', ApiDB.uqComplaintDetailsDISPATCHCODE.AsString);
obj.AddPair('DispatchCodeDesc', ApiDB.uqComplaintDetailsDISPATCH_CODE_DESC.AsString);
obj.AddPair('DispatchDistrict', ApiDB.uqComplaintDetailsDISPATCHDISTRICT.AsString);
obj.AddPair('Address', ApiDB.uqComplaintDetailsADDRESS.AsString);
obj.AddPair('Business', ApiDB.uqComplaintDetailsBUSINESS.AsString);
obj.AddPair('History', ApiDB.uqComplaintDetailsHISTORY.AsString);
obj.AddPair('Contacts', ApiDB.uqComplaintDetailsCONTACTS.AsString);
obj.AddPair('Warnings', ApiDB.uqComplaintDetailsWARNINGS.AsString);
if ApiDB.uqComplaintDetailsDATEREPORTED.IsNull then
obj.AddPair('DateReported', '')
else
obj.AddPair('DateReported', FormatDateTime('yyyy-mm-dd hh:nn:ss', ApiDB.uqComplaintDetailsDATEREPORTED.AsDateTime));
if ApiDB.uqComplaintDetailsDATERECEIVED.IsNull then
obj.AddPair('DateReceived', '')
else
obj.AddPair('DateReceived', FormatDateTime('yyyy-mm-dd hh:nn:ss', ApiDB.uqComplaintDetailsDATERECEIVED.AsDateTime));
if ApiDB.uqComplaintDetailsDATEDISPATCHED.IsNull then
obj.AddPair('DateDispatched', '')
else
obj.AddPair('DateDispatched', FormatDateTime('yyyy-mm-dd hh:nn:ss', ApiDB.uqComplaintDetailsDATEDISPATCHED.AsDateTime));
if ApiDB.uqComplaintDetailsDATERESPONDED.IsNull then
obj.AddPair('DateResponded', '')
else
obj.AddPair('DateResponded', FormatDateTime('yyyy-mm-dd hh:nn:ss', ApiDB.uqComplaintDetailsDATERESPONDED.AsDateTime));
if ApiDB.uqComplaintDetailsDATEARRIVED.IsNull then
obj.AddPair('DateArrived', '')
else
obj.AddPair('DateArrived', FormatDateTime('yyyy-mm-dd hh:nn:ss', ApiDB.uqComplaintDetailsDATEARRIVED.AsDateTime));
if ApiDB.uqComplaintDetailsDATECLEARED.IsNull then
obj.AddPair('DateCleared', '')
else
obj.AddPair('DateCleared', FormatDateTime('yyyy-mm-dd hh:nn:ss', ApiDB.uqComplaintDetailsDATECLEARED.AsDateTime));
Result.AddPair('data', obj);
finally
Close;
end;
end;
except
on E: EXDataHttpException do
begin
Logger.Log(3,'---TApiService.GetComplaintArchiveDetails not found');
raise;
end;
on E: Exception do
begin
Logger.Log(3,'---TApiService.GetComplaintArchiveDetails error: '+E.Message);
raise EXDataHttpException.Create(500,'Failed to load complaint archive details');
end;
end;
Logger.Log(3,'---TApiService.GetComplaintArchiveDetails End');
end;
function TApiService.GetComplaintMemos(const CfsId: string): TJSONObject; function TApiService.GetComplaintMemos(const CfsId: string): TJSONObject;
var var
data: TJSONArray; data: TJSONArray;
...@@ -612,16 +697,17 @@ begin ...@@ -612,16 +697,17 @@ begin
rowObj := TJSONObject.Create; rowObj := TJSONObject.Create;
dataArr.AddElement(rowObj); dataArr.AddElement(rowObj);
rowObj.AddPair('Complaint', FieldByName('COMPLAINT').AsString); rowObj.AddPair('ComplaintId', ApiDB.uqComplaintHistoryCOMPLAINTID.AsString);
rowObj.AddPair('Apartment', FieldByName('APARTMENT').AsString); rowObj.AddPair('Complaint', ApiDB.uqComplaintHistoryCOMPLAINT.AsString);
rowObj.AddPair('Apartment', ApiDB.uqComplaintHistoryAPARTMENT.AsString);
if FieldByName('DATEREPORTED').IsNull then if ApiDB.uqComplaintHistoryDATEREPORTED.IsNull then
rowObj.AddPair('DateReported', '') rowObj.AddPair('DateReported', '')
else else
rowObj.AddPair('DateReported', FormatDateTime('yyyy-mm-dd', FieldByName('DATEREPORTED').AsDateTime)); rowObj.AddPair('DateReported', FormatDateTime('yyyy-mm-dd', ApiDB.uqComplaintHistoryDATEREPORTED.AsDateTime));
rowObj.AddPair('DPriority', FieldByName('DPRIORITY').AsString); rowObj.AddPair('DPriority', ApiDB.uqComplaintHistoryDPRIORITY.AsString);
rowObj.AddPair('DCallType', FieldByName('DCALLTYPE').AsString); rowObj.AddPair('DCallType', ApiDB.uqComplaintHistoryDCALLTYPE.AsString);
Inc(returnedCount); Inc(returnedCount);
Next; Next;
......
...@@ -3,7 +3,7 @@ unit Common.Config; ...@@ -3,7 +3,7 @@ unit Common.Config;
interface interface
const const
defaultServerUrl = 'http://localhost:2009/emiMobile/'; defaultServerUrl = 'http://0.0.0.0:2009/emiMobile/';
type type
TServerConfig = class TServerConfig = class
......
[Settings] [Settings]
LogFileNum=610 LogFileNum=652
webClientVersion=0.1.0 webClientVersion=0.1.0
...@@ -186,6 +186,6 @@ begin ...@@ -186,6 +186,6 @@ begin
iniFile.Free; iniFile.Free;
end; end;
Logger.AddAppender(TMemoLogAppender.Create( memoLogLevel, FMain.memoinfo )); Logger.AddAppender(TMemoLogAppender.Create( memoLogLevel, FMain.memoinfo ));
Logger.AddAppender(TFileLogAppender.Create( fileLogLevel, 'webPoliceReports' )); Logger.AddAppender(TFileLogAppender.Create( fileLogLevel, 'emiMobileServer' ));
Application.Run; Application.Run;
end. end.
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode> <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale> <VerInfo_Locale>1033</VerInfo_Locale>
<DCC_ExeOutput>.</DCC_ExeOutput> <DCC_ExeOutput>.\bin</DCC_ExeOutput>
<VerInfo_MajorVer>0</VerInfo_MajorVer> <VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer> <VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>3</VerInfo_Release> <VerInfo_Release>3</VerInfo_Release>
...@@ -196,12 +196,7 @@ ...@@ -196,12 +196,7 @@
<Source> <Source>
<Source Name="MainSource">emiMobileServer.dpr</Source> <Source Name="MainSource">emiMobileServer.dpr</Source>
</Source> </Source>
<Excluded_Packages> <Excluded_Packages/>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k290.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality> </Delphi.Personality>
<Deployment Version="5"> <Deployment Version="5">
<DeployFile LocalName="emiMobileServer.exe" Configuration="Debug" Class="ProjectOutput"> <DeployFile LocalName="emiMobileServer.exe" Configuration="Debug" Class="ProjectOutput">
......
{
"AuthUrl" : "http://localhost:2009/emimobile/auth/",
"ApiUrl" : "http://localhost:2009/emimobile/api/",
"AppUrl" : "http://localhost:2009/emimobile/app/"
}
\ No newline at end of file
.login-card {
display: inline-block;
width: 300px; /* Adjust width as needed */
padding: 0;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
background-color: #fff;
}
.card-header {
width: 100%;
text-align: left; /* Align text to the left */
background-color: #f8f9fa; /* Match the card background */
padding: 0.75rem 1.25rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
margin: 0; /* Remove any margin */
box-sizing: border-box; /* Ensure padding is included in the element's total width and height */
}
.mr-2 {
margin-right: 0.5rem;
}
.card-title {
margin: 0;
font-size: 1.25rem; /* Adjust font size as needed */
}
.card-body {
padding: 2rem;
}
.table tbody tr:hover {
background-color: #d1e7fd; /* Light blue color for hover effect */
cursor: pointer;
}
.form-input{
display: table;
}
.form-cells{
display: table-cell
}
.table tbody tr {
transition: background-color 0.3s ease;
}
.table {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
@media (max-width: 1200px) {
.table-responsive {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.table thead {
display: none;
}
.table tbody, .table tr, .table td {
display: block;
width: 100%;
}
.table tr {
margin-bottom: 1rem;
}
.table td {
text-align: right;
padding-left: 50%; /* Adjust padding to accommodate the data-label */
position: relative;
}
.table td::before {
content: attr(data-label);
position: absolute;
left: 0;
width: 50%;
padding-left: 15px; /* Adjust as necessary */
font-weight: bold;
text-align: left;
}
.table td .transcript {
margin-top: 20px; /* Set top margin to 20px */
text-align: left; /* Ensure text alignment is left */
margin-left: 8px;
white-space: normal; /* Prevent text from being cut off */
}
}
.login-navbar {
max-width: 1200px; /* Set the max-width to match a medium screen */
margin: auto;
border-bottom-left-radius: 10px; /* Round the bottom left corner */
border-bottom-right-radius: 10px; /* Round the bottom right corner */
border: 1px solid #d3d3d3;
}
.navbar-toggler {
display: none;
}
.dropdown-menu a {
display: flex; /* Use flexbox for alignment */
align-items: center; /* Vertically center the content */
width: 100%; /* Ensure they take up the full width */
padding: 0.5rem 1rem; /* Add padding to make them clickable */
color: #000; /* Adjust the text color if necessary */
text-decoration: none; /* Remove underlines */
}
.dropdown-menu a:hover {
background-color: #204d74;
color: #fff;
}
.dropdown-menu a span {
flex-grow: 1; /* Make the span take up the remaining space */
}
/* Style for the selected number */
.selected-number .page-link {
background-color: #204d74;
color: #fff !important;
}
/* Style for the unselected numbers and text (previous/next) */
.pagination .page-item a,
.pagination .page-item span {
color: #204d74;
}
.pagination .page-item.active .page-link,
.pagination .page-item.active .page-link:hover,
.pagination .page-item.active .page-link:focus {
background-color: #204d74;
border-color: #204d74;
color: #fff !important;
}
/* This is needed to get rid of the line that was appearing. */
span.card {
border: none;
}
.modal-backdrop {
z-index: 1040 !important;
}
.modal {
z-index: 1055 !important;
}
object FViewComplaintArchive: TFViewComplaintArchive
Width = 640
Height = 480
object tblRemarksArc: TWebDBTableControl
Left = 102
Top = 128
Width = 191
Height = 147
ElementId = 'tbl_remarks_arc'
BorderColor = clSilver
ChildOrder = 8
ElementFont = efCSS
ElementHeaderClassName = 'table-light'
ElementTableClassName =
'table table-sm table-striped table-hover table-bordered mb-0 ali' +
'gn-middle'
Footer.ButtonActiveElementClassName = 'btn btn-primary'
Footer.ButtonElementClassName = 'btn btn-light'
Footer.DropDownElementClassName = 'form-control'
Footer.InputElementClassName = 'form-control'
Footer.LinkActiveElementClassName = 'link-primary'
Footer.LinkElementClassName = 'link-secondary'
Footer.ListElementClassName = 'pagination'
Footer.ListItemElementClassName = 'page-item'
Footer.ListLinkElementClassName = 'page-link'
Header.ButtonActiveElementClassName = 'btn btn-primary'
Header.ButtonElementClassName = 'btn btn-light'
Header.DropDownElementClassName = 'form-control'
Header.InputElementClassName = 'form-control'
Header.LinkActiveElementClassName = 'link-primary'
Header.LinkElementClassName = 'link-secondary'
Header.ListElementClassName = 'pagination'
Header.ListItemElementClassName = 'page-item'
Header.ListLinkElementClassName = 'page-link'
WordWrap = True
Columns = <
item
ElementClassName = 'd-none'
DataField = 'MemoType'
Title = 'Type'
TitleElementClassName = 'd-none'
end
item
DataField = 'Timestamp'
Title = 'Timestamp'
end
item
DataField = 'Remarks'
Title = 'Remarks'
end>
DataSource = wdsRemarksArc
end
object btnUntArc: TWebButton
Left = 378
Top = 85
Width = 96
Height = 25
Caption = 'UNT'
ChildOrder = 1
ElementID = 'btn_unt_arc'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
TabStop = False
WidthPercent = 100.000000000000000000
OnClick = btnUntArcClick
end
object btnREMArc: TWebButton
Left = 276
Top = 85
Width = 96
Height = 25
Caption = 'REM'
ChildOrder = 1
ElementID = 'btn_rem_arc'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
TabStop = False
WidthPercent = 100.000000000000000000
OnClick = btnREMArcClick
end
object btnE911Arc: TWebButton
Left = 166
Top = 85
Width = 96
Height = 25
Caption = 'E-911'
ChildOrder = 1
ElementID = 'btn_e911_arc'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
TabStop = False
WidthPercent = 100.000000000000000000
OnClick = btnE911ArcClick
end
object btnCmpArc: TWebButton
Left = 64
Top = 85
Width = 96
Height = 25
Caption = 'CMP'
ChildOrder = 1
ElementID = 'btn_cmp_arc'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
TabStop = False
WidthPercent = 100.000000000000000000
OnClick = btnCmpArcClick
end
object btnComplaintViewOnMapArc: TWebButton
Left = 342
Top = 259
Width = 96
Height = 25
Caption = 'Map'
ChildOrder = 1
ElementID = 'btn_complaint_view_on_map_arc'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnComplaintViewOnMapArcClick
end
object xdwcComplaintArchive: TXDataWebClient
Connection = DMConnection.ApiConnection
Left = 292
Top = 310
end
object xdwdsRemarksArc: TXDataWebDataSet
Left = 68
Top = 316
object xdwdsRemarksArcMemoId: TStringField
FieldName = 'MemoId'
end
object xdwdsRemarksArcCFSId: TStringField
FieldName = 'CFSId'
end
object xdwdsRemarksArcMemoType: TStringField
FieldName = 'MemoType'
end
object xdwdsRemarksArcTimestamp: TStringField
FieldName = 'Timestamp'
end
object xdwdsRemarksArcBadgeNumber: TStringField
FieldName = 'BadgeNumber'
end
object xdwdsRemarksArcRemarks: TStringField
FieldName = 'Remarks'
end
end
object wdsRemarksArc: TWebDataSource
DataSet = xdwdsRemarksArc
Left = 156
Top = 314
end
end
<div class="d-flex flex-column h-100 w-100 overflow-hidden">
<div class="flex-grow-1 d-flex flex-column overflow-auto bg-light p-2 p-md-3" style="min-height:0;">
<!-- Sticky block: Summary header + summary body -->
<div class="sticky-top bg-light" style="z-index:20;">
<!-- Summary header -->
<div class="card border-0 shadow-sm mb-2">
<div class="card-header bg-white py-2">
<button
class="btn btn-link text-decoration-none p-0 w-100 d-flex align-items-center justify-content-between summary-toggle"
type="button"
data-bs-toggle="collapse"
data-bs-target="#cdetails_summary_arc"
aria-expanded="true"
aria-controls="cdetails_summary_arc">
<span class="fw-semibold text-dark" id="lbl_summary_title_arc">Summary</span>
<span class="summary-chevron" aria-hidden="true">
<svg class="summary-chevron-icon" viewBox="0 0 16 16" focusable="false">
<path fill="currentColor" d="M7.646 5.354a.5.5 0 0 1 .708 0l5 5a.5.5 0 0 1-.708.708L8 6.414 3.354 11.06a.5.5 0 1 1-.708-.708l5-5z"/>
</svg>
</span>
</button>
</div>
</div>
<!-- Summary body -->
<div id="cdetails_summary_arc" class="collapse show">
<div class="card border-0 shadow-sm mb-2">
<div class="card-body py-2">
<table class="table table-sm mb-0 w-100">
<tbody>
<tr>
<th scope="row" class="fw-semibold text-nowrap pe-2 w-auto">Priority:</th>
<td class="w-100" id="lbl_priority_arc"></td>
</tr>
<tr>
<th scope="row" class="fw-semibold text-nowrap pe-2 w-auto">Status:</th>
<td class="w-100" id="lbl_status_arc"></td>
</tr>
<tr>
<th scope="row" class="fw-semibold text-nowrap pe-2 w-auto">Dispatch Code:</th>
<td class="w-100" id="lbl_dispatch_code_arc"></td>
</tr>
<tr>
<th scope="row" class="fw-semibold text-nowrap pe-2 w-auto">Dispatch District:</th>
<td class="w-100" id="lbl_dispatch_district_arc"></td>
</tr>
<tr>
<th scope="row" class="fw-semibold text-nowrap pe-2 w-auto">Address:</th>
<td class="w-100" id="lbl_address_arc"></td>
</tr>
<tr id="row_business_arc" class="d-none">
<th scope="row" class="fw-semibold text-nowrap pe-2 w-auto">Business:</th>
<td class="w-100" id="lbl_business_arc"></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Remarks toggle filters -->
<div class="pb-2">
<div class="d-flex flex-wrap gap-2 justify-content-center mt-2" id="row_remarks_toggles_arc">
<button type="button" class="btn btn-success btn-sm px-3 active" id="btn_cmp_arc" aria-pressed="true">CMP</button>
<button type="button" class="btn btn-success btn-sm px-3 active" id="btn_e911_arc" aria-pressed="true">E-911</button>
<button type="button" class="btn btn-success btn-sm px-3 active" id="btn_rem_arc" aria-pressed="true">REM</button>
<button type="button" class="btn btn-success btn-sm px-3 active" id="btn_unt_arc" aria-pressed="true">UNT</button>
</div>
</div>
</div>
</div>
<!-- Remarks table (scrolls with page) -->
<div class="card border-0 shadow-sm">
<div class="card-body p-0">
<div id="tbl_remarks_arc"></div>
</div>
</div>
</div>
<button id="btn_complaint_view_on_map_arc"
type="button"
class="btn btn-primary btn-sm shadow position-fixed"
style="right: 15px; bottom: 25px; z-index: 1040;">
Map
</button>
</div>
unit View.ComplaintArchive;
interface
uses
System.SysUtils, System.Classes, JS, Web,
WEBLib.Graphics, WEBLib.Controls, WEBLib.Forms, WEBLib.Dialogs,
Vcl.Controls, Vcl.StdCtrls, Data.DB,
WEBLib.StdCtrls, WEBLib.Grids, WEBLib.DBCtrls, WEBLib.DB,
XData.Web.Client, XData.Web.JsonDataset, XData.Web.Dataset,
ConnectionModule;
type
TFViewComplaintArchive = class(TWebForm)
tblRemarksArc: TWebDBTableControl;
xdwcComplaintArchive: TXDataWebClient;
xdwdsRemarksArc: TXDataWebDataSet;
xdwdsRemarksArcMemoId: TStringField;
xdwdsRemarksArcCFSId: TStringField;
xdwdsRemarksArcMemoType: TStringField;
xdwdsRemarksArcTimestamp: TStringField;
xdwdsRemarksArcBadgeNumber: TStringField;
xdwdsRemarksArcRemarks: TStringField;
wdsRemarksArc: TWebDataSource;
btnUntArc: TWebButton;
btnREMArc: TWebButton;
btnE911Arc: TWebButton;
btnCmpArc: TWebButton;
btnComplaintViewOnMapArc: TWebButton;
procedure WebFormCreate(Sender: TObject);
procedure btnCmpArcClick(Sender: TObject);
procedure btnE911ArcClick(Sender: TObject);
procedure btnREMArcClick(Sender: TObject);
procedure btnUntArcClick(Sender: TObject);
procedure btnComplaintViewOnMapArcClick(Sender: TObject);
private
FComplaintId: string;
FCfsId: string;
FAllMemos: TJSArray;
FShowCMP: Boolean;
FShowE911: Boolean;
FShowREM: Boolean;
FShowUNT: Boolean;
procedure WireUi;
procedure SetTextById(const Id, Value: string);
procedure SetHiddenById(const Id: string; Hidden: Boolean);
procedure SetButtonActive(aButton: TWebButton; Active: Boolean);
[async] procedure LoadArchiveAsync;
[async] procedure LoadMemosAsync;
procedure ApplyMemoFilters;
function GetMemoTypeCode(const MemoType: string): string;
function MemoTypeLabel(const MemoType: string): string;
public
class function CreateForm(const AHostId, AComplaintId: string): TFViewComplaintArchive;
end;
implementation
uses
View.Main;
{$R *.dfm}
class function TFViewComplaintArchive.CreateForm(const AHostId, AComplaintId: string): TFViewComplaintArchive;
begin
Result := TFViewComplaintArchive(inherited CreateNew(AHostId));
Result.FComplaintId := AComplaintId;
end;
procedure TFViewComplaintArchive.WebFormCreate(Sender: TObject);
begin
FAllMemos := nil;
FShowCMP := True;
FShowE911 := True;
FShowREM := True;
FShowUNT := True;
WireUi;
LoadArchiveAsync;
end;
procedure TFViewComplaintArchive.WireUi;
begin
// Nothing required here beyond component OnClick handlers;
// all element IDs are bound via the DFM.
end;
procedure TFViewComplaintArchive.SetTextById(const Id, Value: string);
var
el: TJSElement;
begin
el := Document.getElementById(Id);
if el <> nil then
el.innerHTML := Value;
end;
procedure TFViewComplaintArchive.SetHiddenById(const Id: string; Hidden: Boolean);
var
el: TJSHTMLElement;
begin
el := TJSHTMLElement(Document.getElementById(Id));
if el = nil then
Exit;
if Hidden then
el.classList.add('d-none')
else
el.classList.remove('d-none');
end;
procedure TFViewComplaintArchive.SetButtonActive(aButton: TWebButton; Active: Boolean);
var
el: TJSHTMLElement;
begin
if (aButton = nil) or (aButton.ElementHandle = nil) then
Exit;
el := TJSHTMLElement(aButton.ElementHandle);
if Active then
begin
el.classList.add('active');
el.setAttribute('aria-pressed', 'true');
end
else
begin
el.classList.remove('active');
el.setAttribute('aria-pressed', 'false');
end;
end;
[async] procedure TFViewComplaintArchive.LoadArchiveAsync;
var
resp: TXDataClientResponse;
rootObj: TJSObject;
dataObj: TJSObject;
business: string;
begin
resp := await(xdwcComplaintArchive.RawInvokeAsync('IApiService.GetComplaintArchiveDetails', [FComplaintId]));
rootObj := TJSObject(resp.Result);
dataObj := TJSObject(rootObj['data']);
// Summary title (optional)
SetTextById('lbl_summary_title_arc', 'Summary');
SetTextById('lbl_priority_arc', string(dataObj['Priority']));
SetTextById('lbl_dispatch_code_arc', string(dataObj['DispatchCodeDesc']));
SetTextById('lbl_dispatch_district_arc', string(dataObj['DispatchDistrict']));
SetTextById('lbl_address_arc', string(dataObj['Address']));
business := string(dataObj['Business']);
if business <> '' then
begin
SetTextById('lbl_business_arc', business);
SetHiddenById('row_business_arc', False);
end
else
SetHiddenById('row_business_arc', True);
// Status: same logic style as details; simplest is derive from timestamps if you want,
// but archive view can just show blank unless you prefer the full logic.
// If your archive endpoint includes a computed Status, you can display it directly.
if dataObj.hasOwnProperty('Status') then
SetTextById('lbl_status_arc', string(dataObj['Status']))
else
SetTextById('lbl_status_arc', '');
// CFSId is needed for memos
FCfsId := string(dataObj['CFSId']);
await(LoadMemosAsync);
end;
function TFViewComplaintArchive.MemoTypeLabel(const MemoType: string): string;
var
c: string;
begin
c := GetMemoTypeCode(MemoType);
if c = 'CMP' then Exit('CMP');
if c = 'E911' then Exit('E-911');
if c = 'REM' then Exit('REM');
if c = 'UNT' then Exit('UNT');
Result := MemoType;
end;
function TFViewComplaintArchive.GetMemoTypeCode(const MemoType: string): string;
var
mt: string;
begin
mt := LowerCase(Trim(MemoType));
// Match whatever your server returns in GetComplaintMemos:
// Keep these mappings aligned with ComplaintDetails.
if (mt = 'cmp') or (mt = 'complaint') then Exit('CMP');
if (mt = 'e-911') or (mt = 'e911') then Exit('E911');
if (mt = 'rem') or (mt = 'remarks') then Exit('REM');
if (mt = 'unt') or (mt = 'unit') then Exit('UNT');
Result := UpperCase(mt);
end;
[async] procedure TFViewComplaintArchive.LoadMemosAsync;
var
resp: TXDataClientResponse;
rootObj: TJSObject;
dataArr: TJSArray;
i: Integer;
memoObj: TJSObject;
memoType: string;
begin
// Reset dataset
xdwdsRemarksArc.Close;
resp := await(xdwcComplaintArchive.RawInvokeAsync('IApiService.GetComplaintMemos', [FCfsId]));
rootObj := TJSObject(resp.Result);
dataArr := TJSArray(rootObj['data']);
// Save master array for filtering
FAllMemos := dataArr;
// Add/normalize memo type label/code (client-side)
for i := 0 to dataArr.length - 1 do
begin
memoObj := TJSObject(dataArr[i]);
memoType := string(memoObj['MemoType']);
memoObj['MemoTypeCode'] := GetMemoTypeCode(memoType);
memoObj['MemoType'] := MemoTypeLabel(memoType);
end;
ApplyMemoFilters;
end;
procedure TFViewComplaintArchive.ApplyMemoFilters;
var
filtered: TJSArray;
i: Integer;
memoObj: TJSObject;
code: string;
ok: Boolean;
begin
if FAllMemos = nil then
Exit;
filtered := TJSArray.new;
for i := 0 to FAllMemos.length - 1 do
begin
memoObj := TJSObject(FAllMemos[i]);
code := string(memoObj['MemoTypeCode']);
ok := False;
if (code = 'CMP') and FShowCMP then ok := True;
if (code = 'E911') and FShowE911 then ok := True;
if (code = 'REM') and FShowREM then ok := True;
if (code = 'UNT') and FShowUNT then ok := True;
if ok then
filtered.push(memoObj);
end;
xdwdsRemarksArc.SetJsonData(filtered);
xdwdsRemarksArc.Open;
end;
procedure TFViewComplaintArchive.btnCmpArcClick(Sender: TObject);
begin
FShowCMP := not FShowCMP;
SetButtonActive(btnCmpArc, FShowCMP);
ApplyMemoFilters;
end;
procedure TFViewComplaintArchive.btnE911ArcClick(Sender: TObject);
begin
FShowE911 := not FShowE911;
SetButtonActive(btnE911Arc, FShowE911);
ApplyMemoFilters;
end;
procedure TFViewComplaintArchive.btnREMArcClick(Sender: TObject);
begin
FShowREM := not FShowREM;
SetButtonActive(btnREMArc, FShowREM);
ApplyMemoFilters;
end;
procedure TFViewComplaintArchive.btnUntArcClick(Sender: TObject);
begin
FShowUNT := not FShowUNT;
SetButtonActive(btnUntArc, FShowUNT);
ApplyMemoFilters;
end;
procedure TFViewComplaintArchive.btnComplaintViewOnMapArcClick(Sender: TObject);
begin
if Assigned(FViewMain) then
FViewMain.ShowMapFocusComplaint(FComplaintId);
end;
end.
object FViewComplaintDetails: TFViewComplaintDetails object FViewComplaintDetails: TFViewComplaintDetails
Width = 800 Width = 800
Height = 672 Height = 672
Caption = 'tbl_logs'
CSSLibrary = cssBootstrap CSSLibrary = cssBootstrap
ElementFont = efCSS ElementFont = efCSS
object btnHistory: TWebButton object btnHistory: TWebButton
...@@ -361,8 +360,8 @@ object FViewComplaintDetails: TFViewComplaintDetails ...@@ -361,8 +360,8 @@ object FViewComplaintDetails: TFViewComplaintDetails
ListSource = wdsWarnings ListSource = wdsWarnings
end end
object btnComplaintViewOnMap: TWebButton object btnComplaintViewOnMap: TWebButton
Left = 510 Left = 687
Top = 430 Top = 496
Width = 96 Width = 96
Height = 25 Height = 25
Caption = 'Map' Caption = 'Map'
...@@ -376,12 +375,12 @@ object FViewComplaintDetails: TFViewComplaintDetails ...@@ -376,12 +375,12 @@ object FViewComplaintDetails: TFViewComplaintDetails
end end
object xdwcComplaintDetails: TXDataWebClient object xdwcComplaintDetails: TXDataWebClient
Connection = DMConnection.ApiConnection Connection = DMConnection.ApiConnection
Left = 378 Left = 384
Top = 424 Top = 422
end end
object xdwdsRemarks: TXDataWebDataSet object xdwdsRemarks: TXDataWebDataSet
Left = 40 Left = 40
Top = 350 Top = 348
object xdwdsRemarksMemoId: TStringField object xdwdsRemarksMemoId: TStringField
FieldName = 'MemoId' FieldName = 'MemoId'
end end
...@@ -403,12 +402,15 @@ object FViewComplaintDetails: TFViewComplaintDetails ...@@ -403,12 +402,15 @@ object FViewComplaintDetails: TFViewComplaintDetails
end end
object wdsRemarks: TWebDataSource object wdsRemarks: TWebDataSource
DataSet = xdwdsRemarks DataSet = xdwdsRemarks
Left = 126 Left = 128
Top = 350 Top = 348
end end
object xdwdsHistory: TXDataWebDataSet object xdwdsHistory: TXDataWebDataSet
Left = 238 Left = 238
Top = 348 Top = 348
object xdwdsHistoryComplaintId: TStringField
FieldName = 'ComplaintId'
end
object xdwdsHistoryComplaint: TStringField object xdwdsHistoryComplaint: TStringField
FieldName = 'Complaint' FieldName = 'Complaint'
end end
...@@ -428,11 +430,11 @@ object FViewComplaintDetails: TFViewComplaintDetails ...@@ -428,11 +430,11 @@ object FViewComplaintDetails: TFViewComplaintDetails
object wdsHistory: TWebDataSource object wdsHistory: TWebDataSource
DataSet = xdwdsHistory DataSet = xdwdsHistory
Left = 328 Left = 328
Top = 350 Top = 348
end end
object xdwdsContacts: TXDataWebDataSet object xdwdsContacts: TXDataWebDataSet
Left = 436 Left = 438
Top = 352 Top = 348
object xdwdsContactsName: TStringField object xdwdsContactsName: TStringField
FieldName = 'Name' FieldName = 'Name'
end end
...@@ -448,12 +450,12 @@ object FViewComplaintDetails: TFViewComplaintDetails ...@@ -448,12 +450,12 @@ object FViewComplaintDetails: TFViewComplaintDetails
end end
object wdsContacts: TWebDataSource object wdsContacts: TWebDataSource
DataSet = xdwdsContacts DataSet = xdwdsContacts
Left = 530 Left = 532
Top = 352 Top = 348
end end
object xdwdsWarnings: TXDataWebDataSet object xdwdsWarnings: TXDataWebDataSet
Left = 634 Left = 612
Top = 492 Top = 422
object xdwdsWarningsCodeDesc: TStringField object xdwdsWarningsCodeDesc: TStringField
FieldName = 'CodeDesc' FieldName = 'CodeDesc'
end end
...@@ -466,7 +468,7 @@ object FViewComplaintDetails: TFViewComplaintDetails ...@@ -466,7 +468,7 @@ object FViewComplaintDetails: TFViewComplaintDetails
end end
object wdsWarnings: TWebDataSource object wdsWarnings: TWebDataSource
DataSet = xdwdsWarnings DataSet = xdwdsWarnings
Left = 728 Left = 712
Top = 492 Top = 422
end end
end end
...@@ -97,8 +97,8 @@ ...@@ -97,8 +97,8 @@
<button id="btn_complaint_view_on_map" <button id="btn_complaint_view_on_map"
type="button" type="button"
class="btn btn-primary btn-sm shadow position-fixed" class="btn btn-primary btn-sm shadow position-fixed"
style="right: 12px; bottom: 72px; z-index: 1040;"> style="right: 15px; bottom: 25px; z-index: 1040;">
View On Map Map
</button> </button>
</div> </div>
...@@ -54,6 +54,7 @@ type ...@@ -54,6 +54,7 @@ type
btnUnt: TWebButton; btnUnt: TWebButton;
lstWarnings: TWebDBListControl; lstWarnings: TWebDBListControl;
btnComplaintViewOnMap: TWebButton; btnComplaintViewOnMap: TWebButton;
xdwdsHistoryComplaintId: TStringField;
procedure btnRemarksClick(Sender: TObject); procedure btnRemarksClick(Sender: TObject);
procedure btnHistoryClick(Sender: TObject); procedure btnHistoryClick(Sender: TObject);
...@@ -560,6 +561,7 @@ begin ...@@ -560,6 +561,7 @@ begin
rootObj := TJSObject(resp.Result); rootObj := TJSObject(resp.Result);
dataObj := TJSObject(rootObj['data']); dataObj := TJSObject(rootObj['data']);
complaintText := string(dataObj['Complaint']); complaintText := string(dataObj['Complaint']);
priorityText := string(dataObj['Priority']); priorityText := string(dataObj['Priority']);
dispatchDescText := string(dataObj['DispatchCodeDesc']); dispatchDescText := string(dataObj['DispatchCodeDesc']);
......
...@@ -56,8 +56,8 @@ object FViewComplaints: TFViewComplaints ...@@ -56,8 +56,8 @@ object FViewComplaints: TFViewComplaints
'ustify-content-center gap-1"><button type="button" class="btn bt' + 'ustify-content-center gap-1"><button type="button" class="btn bt' +
'n-primary btn-sm complaint-details-btn" data-id="(%ComplaintId%)' + 'n-primary btn-sm complaint-details-btn" data-id="(%ComplaintId%)' +
'">Details</button><button type="button" class="btn btn-primary b' + '">Details</button><button type="button" class="btn btn-primary b' +
'tn-sm btn-complaint-map" data-id="(%ComplaintId%)">View On Map</' + 'tn-sm btn-complaint-map" data-id="(%ComplaintId%)">Map</button><' +
'button></div></div></div>' '/div></div></div>'
ListSource = wdsComplaints ListSource = wdsComplaints
end end
object xdwcComplaints: TXDataWebClient object xdwcComplaints: TXDataWebClient
...@@ -121,10 +121,4 @@ object FViewComplaints: TFViewComplaints ...@@ -121,10 +121,4 @@ object FViewComplaints: TFViewComplaints
Left = 156 Left = 156
Top = 410 Top = 410
end end
object tmrRefresh: TWebTimer
Interval = 30000
OnTimer = tmrRefreshTimer
Left = 164
Top = 44
end
end end
...@@ -31,20 +31,19 @@ type ...@@ -31,20 +31,19 @@ type
xdwdsComplaintsPriorityColor: TStringField; xdwdsComplaintsPriorityColor: TStringField;
xdwdsComplaintsPriorityTextColor: TStringField; xdwdsComplaintsPriorityTextColor: TStringField;
xdwdsComplaintsDistrictSector: TStringField; xdwdsComplaintsDistrictSector: TStringField;
tmrRefresh: TWebTimer;
xdwdsComplaintsBusiness: TStringField; xdwdsComplaintsBusiness: TStringField;
procedure WebFormCreate(Sender: TObject); procedure WebFormCreate(Sender: TObject);
procedure btnRefreshClick(Sender: TObject);
procedure tmrRefreshTimer(Sender: TObject);
procedure WebFormDestroy(Sender: TObject); procedure WebFormDestroy(Sender: TObject);
private private
FSelectProc: TSelectProc; FSelectProc: TSelectProc;
FLoading: Boolean; FLoading: Boolean;
FFirstLoad: Boolean;
[async] procedure GetComplaints; [async] procedure GetComplaints;
procedure HandleListClick(e: TJSMouseEvent); procedure HandleListClick(e: TJSMouseEvent);
procedure ShowHideBusinessRows; procedure ShowHideBusinessRows;
public public
property OnShowDetails: TSelectProc read FSelectProc write FSelectProc; property OnShowDetails: TSelectProc read FSelectProc write FSelectProc;
procedure RefreshData;
end; end;
var var
...@@ -57,19 +56,12 @@ implementation ...@@ -57,19 +56,12 @@ implementation
procedure TFViewComplaints.WebFormCreate(Sender: TObject); procedure TFViewComplaints.WebFormCreate(Sender: TObject);
begin begin
Document.addEventListener('click', @HandleListClick); Document.addEventListener('click', @HandleListClick);
ShowSpinner('spinner'); FFirstLoad := True;
tmrRefresh.Enabled := False;
GetComplaints; GetComplaints;
tmrRefresh.Enabled := True;
asm asm
if (!window.showComplaintDetails) { if (!window.showComplaintDetails) {
window.showComplaintDetails = function (id) { window.showComplaintDetails = function (id) {
console.log('JS bridge showComplaintDetails called, id=', id);
try {
pas['View.Main'].FViewMain.ShowComplaintDetails(id); pas['View.Main'].FViewMain.ShowComplaintDetails(id);
} catch (e) {
console.log('Error in TFViewMain.ShowComplaintDetails', e);
}
}; };
} }
end; end;
...@@ -139,18 +131,12 @@ begin ...@@ -139,18 +131,12 @@ begin
end; end;
end; end;
procedure TFViewComplaints.WebFormDestroy(Sender: TObject); procedure TFViewComplaints.WebFormDestroy(Sender: TObject);
begin begin
Document.removeEventListener('click', @HandleListClick); Document.removeEventListener('click', @HandleListClick);
end; end;
//Note: HTML for individual complaint cards can be found in the twebdblistcontrol HTMLString property //Note: HTML for individual complaint cards can be found in the twebdblistcontrol HTMLString property
procedure TFViewComplaints.btnRefreshClick(Sender: TObject);
begin
GetComplaints;
end;
[async] procedure TFViewComplaints.GetComplaints; [async] procedure TFViewComplaints.GetComplaints;
var var
xdcResponse: TXDataClientResponse; xdcResponse: TXDataClientResponse;
...@@ -161,6 +147,8 @@ begin ...@@ -161,6 +147,8 @@ begin
Exit; Exit;
FLoading := True; FLoading := True;
if FFirstLoad then
ShowSpinner('spinner'); ShowSpinner('spinner');
try try
try try
...@@ -182,13 +170,18 @@ begin ...@@ -182,13 +170,18 @@ begin
Utils.ShowErrorModal(E.Message); Utils.ShowErrorModal(E.Message);
end; end;
finally finally
HideSpinner('spinner');
FLoading := False; FLoading := False;
if FFirstLoad then
begin
HideSpinner('spinner');
FFirstLoad := False;
end;
end; end;
end; end;
procedure TFViewComplaints.tmrRefreshTimer(Sender: TObject); procedure TFViewComplaints.RefreshData;
begin begin
Console.Log('Complaints.RefreshData');
GetComplaints; GetComplaints;
end; end;
......
...@@ -76,7 +76,6 @@ procedure TFViewEditUser.btnCancelClick(Sender: TObject); ...@@ -76,7 +76,6 @@ procedure TFViewEditUser.btnCancelClick(Sender: TObject);
// Cancels the edit or addition // Cancels the edit or addition
begin begin
Info := 'Failure:Changes discarded!'; Info := 'Failure:Changes discarded!';
FViewMain.ShowUserForm(Info);
end; end;
procedure TFViewEditUser.btnCloseNotificationClick(Sender: TObject); procedure TFViewEditUser.btnCloseNotificationClick(Sender: TObject);
...@@ -222,7 +221,6 @@ begin ...@@ -222,7 +221,6 @@ begin
if (not Info.Contains('Failure')) then if (not Info.Contains('Failure')) then
begin begin
console.log('Navigating back to user list...'); console.log('Navigating back to user list...');
FViewMain.ShowUserForm(Info);
end end
else else
begin begin
......
object FViewMain: TFViewMain object FViewMain: TFViewMain
Width = 640 Width = 1208
Height = 586 Height = 810
CSSLibrary = cssBootstrap CSSLibrary = cssBootstrap
ElementFont = efCSS ElementFont = efCSS
OnCreate = WebFormCreate OnCreate = WebFormCreate
...@@ -16,18 +16,6 @@ object FViewMain: TFViewMain ...@@ -16,18 +16,6 @@ object FViewMain: TFViewMain
Visible = False Visible = False
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
end end
object wllblUserProfile: TWebLinkLabel
Left = 529
Top = 21
Width = 63
Height = 15
ElementID = 'dropdown.menu.userprofile'
Visible = False
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = wllblUserProfileClick
Caption = ' User Profile'
end
object wllblLogout: TWebLinkLabel object wllblLogout: TWebLinkLabel
Left = 551 Left = 551
Top = 85 Top = 85
...@@ -61,7 +49,6 @@ object FViewMain: TFViewMain ...@@ -61,7 +49,6 @@ object FViewMain: TFViewMain
Visible = False Visible = False
HeightPercent = 100.000000000000000000 HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
OnClick = lblCallsListClick
Caption = 'Calls' Caption = 'Calls'
end end
object lblUsers: TWebLinkLabel object lblUsers: TWebLinkLabel
...@@ -74,7 +61,6 @@ object FViewMain: TFViewMain ...@@ -74,7 +61,6 @@ object FViewMain: TFViewMain
Visible = False Visible = False
HeightPercent = 100.000000000000000000 HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
OnClick = lblUsersClick
Caption = 'Users' Caption = 'Users'
end end
object lblMainTitle: TWebLabel object lblMainTitle: TWebLabel
...@@ -88,12 +74,12 @@ object FViewMain: TFViewMain ...@@ -88,12 +74,12 @@ object FViewMain: TFViewMain
HeightPercent = 100.000000000000000000 HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
end end
object WebPanel1: TWebPanel object pnlMain: TWebPanel
Left = 136 Left = 136
Top = 110 Top = 110
Width = 471 Width = 471
Height = 369 Height = 369
ElementID = 'main.webpanel' ElementID = 'pnl_main'
ChildOrder = 3 ChildOrder = 3
TabOrder = 0 TabOrder = 0
end end
...@@ -108,7 +94,7 @@ object FViewMain: TFViewMain ...@@ -108,7 +94,7 @@ object FViewMain: TFViewMain
end end
object WebMemo1: TWebMemo object WebMemo1: TWebMemo
Left = 136 Left = 136
Top = 467 Top = 469
Width = 471 Width = 471
Height = 83 Height = 83
ElementID = 'main.debugmemo' ElementID = 'main.debugmemo'
...@@ -121,8 +107,8 @@ object FViewMain: TFViewMain ...@@ -121,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'
...@@ -135,8 +121,8 @@ object FViewMain: TFViewMain ...@@ -135,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'
...@@ -149,8 +135,8 @@ object FViewMain: TFViewMain ...@@ -149,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'
...@@ -162,6 +148,55 @@ object FViewMain: TFViewMain ...@@ -162,6 +148,55 @@ object FViewMain: TFViewMain
WidthPercent = 100.000000000000000000 WidthPercent = 100.000000000000000000
OnClick = btnUnitsClick OnClick = btnUnitsClick
end end
object pnlMap: TWebPanel
Left = 708
Top = 99
Width = 237
Height = 436
ElementID = 'pnl_map'
ChildOrder = 3
TabOrder = 6
end
object pnlUnits: TWebPanel
Left = 740
Top = 180
Width = 227
Height = 139
ElementID = 'pnl_units'
ChildOrder = 3
TabOrder = 7
end
object pnlComplaints: TWebPanel
Left = 740
Top = 346
Width = 227
Height = 145
ElementID = 'pnl_complaints'
ChildOrder = 3
TabOrder = 8
end
object pnlDetails: TWebPanel
Left = 992
Top = 277
Width = 163
Height = 114
ElementID = 'pnl_details'
ChildOrder = 15
ElementFont = efCSS
TabOrder = 9
object btnDetailsModalClose: TWebButton
Left = 127
Top = 8
Width = 28
Height = 23
ElementID = 'btn_details_modal_close'
ElementFont = efCSS
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnDetailsModalCloseClick
end
end
object xdwcBadgeCounts: TXDataWebClient object xdwcBadgeCounts: TXDataWebClient
Connection = DMConnection.ApiConnection Connection = DMConnection.ApiConnection
Left = 44 Left = 44
...@@ -173,4 +208,10 @@ object FViewMain: TFViewMain ...@@ -173,4 +208,10 @@ object FViewMain: TFViewMain
Left = 42 Left = 42
Top = 360 Top = 360
end end
object tmrGlobalRefresh: TWebTimer
Interval = 30000
OnTimer = tmrGlobalRefreshTimer
Left = 42
Top = 434
end
end end
...@@ -13,16 +13,33 @@ ...@@ -13,16 +13,33 @@
<!-- 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 -->
<main id="main.webpanel" class="flex-grow-1 position-relative p-0 overflow-hidden" style="min-height:0;"> <div id="pnl_main" class="flex-grow-1 position-relative p-0 overflow-hidden d-none" style="min-height:0;"></div>
<!-- TWebPanel content gets injected here --> <div id="pnl_map" class="flex-grow-1 position-relative p-0 overflow-hidden" style="min-height:0;"></div>
</main> <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>
<!-- Details modal (new panel pnl_details) -->
<div id="pnl_details"
class="position-fixed top-0 start-0 w-100 h-100 d-none d-flex justify-content-center align-items-center"
style="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">
...@@ -86,4 +103,3 @@ ...@@ -86,4 +103,3 @@
</div> </div>
</div> </div>
</div> </div>
...@@ -72,17 +72,11 @@ object FViewMap: TFViewMap ...@@ -72,17 +72,11 @@ object FViewMap: TFViewMap
Left = 232 Left = 232
Top = 696 Top = 696
end end
object tmrRefresh: TWebTimer
Interval = 30000
OnTimer = tmrRefreshTimer
Left = 358
Top = 696
end
object tmrLocate: TWebTimer object tmrLocate: TWebTimer
Enabled = False Enabled = False
Interval = 100 Interval = 100
OnTimer = tmrLocateTimer OnTimer = tmrLocateTimer
Left = 174 Left = 222
Top = 74 Top = 52
end end
end end
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="map_filter_location"> <input class="form-check-input" type="checkbox" id="map_filter_location">
<label class="form-check-label" for="map_filter_location">Show Location</label> <label class="form-check-label" for="map_filter_location">Show My Location</label>
</div> </div>
</div> </div>
<div class="d-grid gap-2 mt-4"> <div class="d-grid gap-2 mt-4">
...@@ -50,7 +50,6 @@ ...@@ -50,7 +50,6 @@
class="btn btn-primary border shadow position-absolute bottom-0 end-0 me-2 mb-4" class="btn btn-primary border shadow position-absolute bottom-0 end-0 me-2 mb-4"
style="z-index:1000;"> style="z-index:1000;">
<i class="fa fa-crosshairs"></i> <i class="fa fa-crosshairs"></i>
<span class="d-none d-sm-inline">Locate</span>
</button> </button>
<!-- Filters (top-right) --> <!-- Filters (top-right) -->
......
...@@ -16,7 +16,6 @@ type ...@@ -16,7 +16,6 @@ type
lfMap: TTMSFNCLeaflet; lfMap: TTMSFNCLeaflet;
httpReqGeoJson: TWebHttpRequest; httpReqGeoJson: TWebHttpRequest;
xdwcMap: TXDataWebClient; xdwcMap: TXDataWebClient;
tmrRefresh: TWebTimer;
btnFindLocation: TWebButton; btnFindLocation: TWebButton;
tmrLocate: TWebTimer; tmrLocate: TWebTimer;
...@@ -25,7 +24,6 @@ type ...@@ -25,7 +24,6 @@ type
procedure lfMapCustomizeMarker(Sender: TObject; procedure lfMapCustomizeMarker(Sender: TObject;
var ACustomizeMarker: string); var ACustomizeMarker: string);
procedure lfMapCustomizeCSS(Sender: TObject; var ACustomizeCSS: string); procedure lfMapCustomizeCSS(Sender: TObject; var ACustomizeCSS: string);
procedure tmrRefreshTimer(Sender: TObject);
procedure btnFindLocationClick(Sender: TObject); procedure btnFindLocationClick(Sender: TObject);
procedure tmrLocateTimer(Sender: TObject); procedure tmrLocateTimer(Sender: TObject);
private private
...@@ -50,6 +48,7 @@ type ...@@ -50,6 +48,7 @@ type
public public
procedure FocusUnit(const unitId: string); procedure FocusUnit(const unitId: string);
procedure FocusComplaint(const complaintId: string); procedure FocusComplaint(const complaintId: string);
procedure RefreshData;
end; end;
var var
...@@ -70,20 +69,16 @@ begin ...@@ -70,20 +69,16 @@ begin
httpReqGeoJson.Execute; httpReqGeoJson.Execute;
asm asm
window.showComplaintDetails = function (id) { window.showComplaintDetails = function (id) {
console.log('JS bridge showComplaintDetails called, id=', id);
try { try {
pas['View.Main'].FViewMain.ShowComplaintDetails(id); pas['View.Main'].FViewMain.ShowComplaintDetails(id);
} catch (e) { } catch (e) {
console.log('Error in TFViewMain.ShowComplaintDetails', e);
} }
}; };
window.showUnitDetails = function (id) { window.showUnitDetails = function (id) {
console.log('JS bridge showUnitDetails called, id=', id);
try { try {
pas['View.Main'].FViewMain.ShowUnitDetails(id); pas['View.Main'].FViewMain.ShowUnitDetails(id);
} catch (e) { } catch (e) {
console.log('Error in TFViewMain.ShowUnitDetails', e);
} }
}; };
end; end;
...@@ -155,9 +150,7 @@ begin ...@@ -155,9 +150,7 @@ begin
try try
lfMap.Polygons.Clear; lfMap.Polygons.Clear;
Console.Log('GeoJSON len=' + AResponse.Length.ToString);
lfMap.LoadGeoJSONFromText(AResponse, True, Trim(FPendingUnitId) = ''); lfMap.LoadGeoJSONFromText(AResponse, True, Trim(FPendingUnitId) = '');
Console.Log('Loaded polygons count=' + lfMap.Polygons.Count.ToString);
for i := 0 to lfMap.Polygons.Count - 1 do for i := 0 to lfMap.Polygons.Count - 1 do
begin begin
...@@ -290,7 +283,6 @@ begin ...@@ -290,7 +283,6 @@ begin
// --- Swap Markers (no blank map while loading) --------------------------- // --- Swap Markers (no blank map while loading) ---------------------------
lfMap.BeginUpdate; lfMap.BeginUpdate;
try try
// Delete old unit/complaint markers right before adding new ones
for i := lfMap.Markers.Count - 1 downto 0 do for i := lfMap.Markers.Count - 1 downto 0 do
begin begin
m := lfMap.Markers[i]; m := lfMap.Markers[i];
...@@ -299,7 +291,7 @@ begin ...@@ -299,7 +291,7 @@ begin
lfMap.Markers.Delete(i); lfMap.Markers.Delete(i);
end; end;
// Add unit markers // Unit markers
if unitsData <> nil then if unitsData <> nil then
begin begin
for i := 0 to unitsData.Length - 1 do for i := 0 to unitsData.Length - 1 do
...@@ -404,12 +396,11 @@ begin ...@@ -404,12 +396,11 @@ begin
'</div>'; '</div>';
m.DataString := 'unit|' + unitId; m.DataString := 'unit|' + unitId;
console.log('Unit marker ds=' + m.DataString);
m.IconURL := CarIconForDistrict(dist); m.IconURL := CarIconForDistrict(dist);
end; end;
end; end;
// Add complaint markers // Complaint markers
if complaintsData <> nil then if complaintsData <> nil then
begin begin
for i := 0 to complaintsData.Length - 1 do for i := 0 to complaintsData.Length - 1 do
...@@ -645,14 +636,6 @@ begin ...@@ -645,14 +636,6 @@ begin
FDoFocusZoom := False; FDoFocusZoom := False;
end; end;
procedure TFViewMap.tmrRefreshTimer(Sender: TObject);
begin
if FLoadingPoints then
Exit;
LoadPointsAsync(False);
end;
procedure TFViewMap.btnFindLocationClick(Sender: TObject); procedure TFViewMap.btnFindLocationClick(Sender: TObject);
var var
coord: TTMSFNCMapsCoordinateRec; coord: TTMSFNCMapsCoordinateRec;
...@@ -662,6 +645,13 @@ begin ...@@ -662,6 +645,13 @@ begin
coord := CreateCoordinate(userLocationMarker.Latitude, userLocationMarker.Longitude); coord := CreateCoordinate(userLocationMarker.Latitude, userLocationMarker.Longitude);
lfMap.SetCenterCoordinate(coord); lfMap.SetCenterCoordinate(coord);
FPendingFocusCoord := coord;
FPendingFocusZoom := 17;
FDoFocusZoom := True;
tmrLocate.Interval := 250;
tmrLocate.Enabled := True;
end; end;
...@@ -758,6 +748,12 @@ begin ...@@ -758,6 +748,12 @@ begin
end; end;
procedure TFViewMap.RefreshData;
begin
Console.Log('Map.RefreshData');
LoadPointsAsync(False);
end;
end. end.
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
<button id="btn_unit_view_on_map" <button id="btn_unit_view_on_map"
type="button" type="button"
class="btn btn-primary btn-sm shadow position-fixed" class="btn btn-primary btn-sm shadow position-fixed"
style="right: 12px; bottom: 72px; z-index: 1040;"> style="right: 15px; bottom: 25px; z-index: 1040;">
Map Map
</button> </button>
</div> </div>
......
...@@ -53,7 +53,7 @@ object FViewUnits: TFViewUnits ...@@ -53,7 +53,7 @@ object FViewUnits: TFViewUnits
'pe="button" class="btn btn-primary btn-sm btn-unit-details" data' + 'pe="button" class="btn btn-primary btn-sm btn-unit-details" data' +
'-unitid="(%UnitId%)">Details</button> <button type="button"' + '-unitid="(%UnitId%)">Details</button> <button type="button"' +
' class="btn btn-primary btn-sm btn-unit-map" data-unitid="(%Unit' + ' class="btn btn-primary btn-sm btn-unit-map" data-unitid="(%Unit' +
'Id%)">View On Map</button> </div> </div></div>' 'Id%)">Map</button> </div> </div></div>'
ListSource = wdsUnits ListSource = wdsUnits
end end
object wdsUnits: TWebDataSource object wdsUnits: TWebDataSource
...@@ -96,10 +96,4 @@ object FViewUnits: TFViewUnits ...@@ -96,10 +96,4 @@ object FViewUnits: TFViewUnits
Left = 58 Left = 58
Top = 410 Top = 410
end end
object tmrRefresh: TWebTimer
Interval = 30000
OnTimer = tmrRefreshTimer
Left = 172
Top = 22
end
end end
...@@ -25,16 +25,14 @@ type ...@@ -25,16 +25,14 @@ type
xdwdsUnitsOfficer1: TStringField; xdwdsUnitsOfficer1: TStringField;
xdwdsUnitsOfficer2: TStringField; xdwdsUnitsOfficer2: TStringField;
xdwdsUnitsCallType: TStringField; xdwdsUnitsCallType: TStringField;
tmrRefresh: TWebTimer;
procedure WebFormCreate(Sender: TObject); procedure WebFormCreate(Sender: TObject);
procedure btnRefreshClick(Sender: TObject);
procedure tmrRefreshTimer(Sender: TObject);
private private
FLoading: Boolean; FLoading: Boolean;
FFirstLoad: Boolean;
[async] procedure GetUnits; [async] procedure GetUnits;
procedure HandleListClick(e: TJSMouseEvent); procedure HandleListClick(e: TJSMouseEvent);
public public
procedure RefreshData;
end; end;
var var
...@@ -49,19 +47,13 @@ procedure TFViewUnits.WebFormCreate(Sender: TObject); ...@@ -49,19 +47,13 @@ procedure TFViewUnits.WebFormCreate(Sender: TObject);
begin begin
DMConnection.ApiConnection.Connected := True; DMConnection.ApiConnection.Connected := True;
Document.addEventListener('click', @HandleListClick); Document.addEventListener('click', @HandleListClick);
tmrRefresh.Enabled := False; FFirstLoad := True;
GetUnits; GetUnits;
tmrRefresh.Enabled := True;
asm asm
if (!window.showUnitDetails) { if (!window.showUnitDetails) {
window.showUnitDetails = function (id) { window.showUnitDetails = function (id) {
console.log('JS bridge showUnitDetails called, id=', id);
try {
pas['View.Main'].FViewMain.ShowUnitDetails(id); pas['View.Main'].FViewMain.ShowUnitDetails(id);
} catch (e) {
console.log('Error in TFViewMain.ShowUnitDetails', e);
}
}; };
} }
end; end;
...@@ -106,68 +98,56 @@ begin ...@@ -106,68 +98,56 @@ begin
e.stopPropagation; e.stopPropagation;
asm asm
try {
pas['View.Main'].FViewMain.ShowMapFocusUnit(unitId); pas['View.Main'].FViewMain.ShowMapFocusUnit(unitId);
} catch (e) {
console.log('ShowMapFocusUnit failed', e);
}
end; end;
end; end;
end; end;
end; end;
procedure TFViewUnits.btnRefreshClick(Sender: TObject); [async] procedure TFViewUnits.GetUnits;
begin
GetUnits;
end;
procedure TFViewUnits.GetUnits;
var var
xdcResponse: TXDataClientResponse; xdcResponse: TXDataClientResponse;
respObj: TJSObject; respObj: TJSObject;
unitCount: Integer; unitCount: Integer;
begin begin
if FLoading then Exit; if FLoading then
Exit;
FLoading := True; FLoading := True;
console.log('GetUnits: Invoking API...'); if FFirstLoad then
Utils.ShowSpinner('spinner'); Utils.ShowSpinner('spinner');
try try
try try
xdcResponse := await(xdwcUnits.RawInvokeAsync('IApiService.GetUnitList', [])); xdcResponse := await(xdwcUnits.RawInvokeAsync('IApiService.GetUnitList', []));
console.log('RawInvoke returned:', xdcResponse.Result);
respObj := TJSObject(xdcResponse.Result); respObj := TJSObject(xdcResponse.Result);
xdwdsUnits.Close; xdwdsUnits.Close;
console.log('Units dataset closed');
xdwdsUnits.SetJsonData(respObj['data']); xdwdsUnits.SetJsonData(respObj['data']);
console.log('JsonData set on units dataset:', respObj['data']);
xdwdsUnits.Open; xdwdsUnits.Open;
console.log('Units dataset opened. Record count:', xdwdsUnits.RecordCount);
unitCount := Integer(respObj['count']); unitCount := Integer(respObj['count']);
lblEntries.Caption := Format('%d units', [unitCount]); lblEntries.Caption := Format('%d units', [unitCount]);
console.log('Units label updated:', lblEntries.Caption);
except except
on E: EXDataClientRequestException do on E: EXDataClientRequestException do
begin
console.log('XData exception (units):', E.ErrorResult.ErrorMessage);
Utils.ShowErrorModal(E.ErrorResult.ErrorMessage); Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
end; on E: Exception do
Utils.ShowErrorModal(E.Message);
end; end;
finally finally
FLoading := False; if FFirstLoad then
Utils.HideSpinner('spinner'); Utils.HideSpinner('spinner');
console.log('GetUnits complete'); FFirstLoad := False;
FLoading := False;
end; end;
end; end;
procedure TFViewUnits.tmrRefreshTimer(Sender: TObject); procedure TFViewUnits.RefreshData;
begin begin
Console.Log('Units.RefreshData');
GetUnits; GetUnits;
end; end;
......
...@@ -150,7 +150,6 @@ begin ...@@ -150,7 +150,6 @@ begin
isActive := false isActive := false
else else
isActive := true; isActive := true;
FViewMain.EditUser('Edit', Username.innerText, FullName.innerText, PhoneNum.innerText, Email.innerText, isAdmin, isActive);
end; end;
...@@ -483,8 +482,7 @@ end; ...@@ -483,8 +482,7 @@ end;
procedure TFViewUsers.btnAddUserClick(Sender: TObject); procedure TFViewUsers.btnAddUserClick(Sender: TObject);
begin begin
//Info := ''; //Info := '';mm
FViewMain.EditUser('Add', '', '', '', '', false, true);
end; end;
procedure TFViewUsers.btnCloseNotificationClick(Sender: TObject); procedure TFViewUsers.btnCloseNotificationClick(Sender: TObject);
......
...@@ -4,6 +4,7 @@ span.card { ...@@ -4,6 +4,7 @@ span.card {
border: none; border: none;
} }
/* --- 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 +86,5 @@ html, body { ...@@ -85,3 +86,5 @@ html, body {
} }
...@@ -23,7 +23,8 @@ uses ...@@ -23,7 +23,8 @@ uses
View.ErrorPage in 'View.ErrorPage.pas' {FViewErrorPage: TWebForm} {*.html}, View.ErrorPage in 'View.ErrorPage.pas' {FViewErrorPage: TWebForm} {*.html},
View.ComplaintDetails in 'View.ComplaintDetails.pas' {FViewComplaintDetails: TWebForm} {*.html}, View.ComplaintDetails in 'View.ComplaintDetails.pas' {FViewComplaintDetails: TWebForm} {*.html},
View.UnitDetails in 'View.UnitDetails.pas' {FViewUnitDetails: TWebForm} {*.html}, View.UnitDetails in 'View.UnitDetails.pas' {FViewUnitDetails: TWebForm} {*.html},
uMapFilters in 'uMapFilters.pas'; uMapFilters in 'uMapFilters.pas',
View.ComplaintArchive in 'View.ComplaintArchive.pas' {FViewComplaintArchive: TWebForm} {*.html};
{$R *.res} {$R *.res}
......
...@@ -97,8 +97,9 @@ ...@@ -97,8 +97,9 @@
<VerInfo_MajorVer>0</VerInfo_MajorVer> <VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_Release>3</VerInfo_Release> <VerInfo_Release>3</VerInfo_Release>
<TMSWebBrowser>1</TMSWebBrowser> <TMSWebBrowser>1</TMSWebBrowser>
<TMSWebSingleInstance>1</TMSWebSingleInstance>
<TMSUseJSDebugger>2</TMSUseJSDebugger> <TMSUseJSDebugger>2</TMSUseJSDebugger>
<TMSWebOutputPath>..\emiMobileServer\bin\static</TMSWebOutputPath>
<TMSWebSingleInstance>1</TMSWebSingleInstance>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''"> <PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
...@@ -188,6 +189,11 @@ ...@@ -188,6 +189,11 @@
<DesignClass>TWebForm</DesignClass> <DesignClass>TWebForm</DesignClass>
</DCCReference> </DCCReference>
<DCCReference Include="uMapFilters.pas"/> <DCCReference Include="uMapFilters.pas"/>
<DCCReference Include="View.ComplaintArchive.pas">
<Form>FViewComplaintArchive</Form>
<FormType>dfm</FormType>
<DesignClass>TWebForm</DesignClass>
</DCCReference>
<None Include="index.html"/> <None Include="index.html"/>
<None Include="css\app.css"/> <None Include="css\app.css"/>
<None Include="css\spinner.css"/> <None Include="css\spinner.css"/>
...@@ -506,12 +512,7 @@ ...@@ -506,12 +512,7 @@
<Source> <Source>
<Source Name="MainSource">webEmiMobile.dpr</Source> <Source Name="MainSource">webEmiMobile.dpr</Source>
</Source> </Source>
<Excluded_Packages> <Excluded_Packages/>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k290.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality> </Delphi.Personality>
<Deployment Version="5"> <Deployment Version="5">
<DeployFile Condition="'$(SKIADIR)'==''" Required="true" LocalName="$(BDS)\bin64\sk4d.dll" Configuration="Debug" Class="Skia"> <DeployFile Condition="'$(SKIADIR)'==''" Required="true" LocalName="$(BDS)\bin64\sk4d.dll" Configuration="Debug" Class="Skia">
......
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