Commit 61959006 by emsys

Merge branch 'mac3' into cam3

parents df22fc95 74a2acc1
......@@ -200,44 +200,6 @@ object FViewAddCustomer: TFViewAddCustomer
WidthPercent = 100.000000000000000000
OnClick = btnEditClick
end
object pnlMessage: TWebPanel
Left = 324
Top = 19
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 5
ElementPosition = epRelative
Role = 'null'
TabOrder = 16
object lblMessage: TWebLabel
Left = 28
Top = 9
Width = 46
Height = 15
Caption = 'Message'
ElementID = 'view.login.message.label'
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
ElementFont = efCSS
ElementPosition = epRelative
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
Role = 'null'
WidthStyle = ssAuto
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object edtCustomerID: TWebDBEdit
Left = 151
Top = 12
......@@ -393,7 +355,6 @@ object FViewAddCustomer: TFViewAddCustomer
SelLength = 0
SelStart = 0
WidthPercent = 100.000000000000000000
OnChange = memoAddressBlockChange
end
object btnAdd: TWebButton
Left = 19
......
<nav class="navbar navbar-expand navbar-light bg-light sticky-top" style="z-index: 100;">
<div class="container-fluid ps-0">
<div id="view.login.message" class="alert alert-danger"
style="padding: 0.25rem 0.5rem; font-size: 0.875rem; line-height: 1.5; display: flex; align-items: center; margin: 0 0 0 60px; height: 32px; width: 400px;">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
<ul class="navbar-nav me-auto ps-2">
<li class="nav-item pe-2">
<button id="btnadd" class="btn btn-primary btn-sm">Add</button>
......
......@@ -9,7 +9,7 @@ uses
WEBLib.Forms, WEBLib.Dialogs, WEBLib.Menus, WEBLib.ExtCtrls, WEBLib.StdCtrls,
WEBLib.JSON, Auth.Service, XData.Web.Client, WebLib.Storage,
ConnectionModule, App.Types, Vcl.StdCtrls, Vcl.Controls, WEBLib.DBCtrls,
Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, WEBLib.Grids;
Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, WEBLib.Grids, VCL.Forms;
type
TFViewAddCustomer = class(TWebForm)
......@@ -29,9 +29,6 @@ type
btnDelete: TWebButton;
btnClose: TWebButton;
btnEdit: TWebButton;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
XDataWebClient1: TXDataWebClient;
WebDataSource1: TWebDataSource;
XDataWebDataSet1: TXDataWebDataSet;
......@@ -83,7 +80,6 @@ type
XDataWebDataSet1REP_USER_ID: TStringField;
xdwdsUsersfull_name: TStringField;
procedure WebFormShow(Sender: TObject);
procedure btnCloseNotificationClick(Sender: TObject);
procedure btnSaveClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure xdwdsShipToAfterEdit(DataSet: TDataSet);
......@@ -92,7 +88,6 @@ type
procedure btnEditClick(Sender: TObject);
procedure wdbtcAddressesDblClickCell(Sender: TObject; ACol, ARow: Integer);
procedure btnClearClick(Sender: TObject);
procedure memoAddressBlockChange(Sender: TObject);
procedure AddressEditMode();
procedure edtShippingAddressChange(Sender: TObject);
procedure btnAddClick(Sender: TObject);
......@@ -105,9 +100,6 @@ type
procedure btnShipDeleteClick(Sender: TObject);
private
{ Private declarations }
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure ViewMode();
procedure EditMode();
[async] procedure GetCustomer();
......@@ -159,6 +151,7 @@ begin
newform.Caption := 'Select Customer and Order Type';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.Position := poScreenCenter;
// used to manage Back button handling to close subform
window.location.hash := 'subform';
......@@ -180,7 +173,7 @@ begin
Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.DelShippingAddress',
[xdwdsShipTo.FieldByName('ship_id').AsString, customerID]));
notification := TJSObject(Response.Result);
ShowNotification(string(notification['status']));
ShowToast(string(notification['status']));
xdwdsShipTo.Close;
xdwdsShipTo.SetJSONData(notification['ADDRESS']);
xdwdsShipTo.Open;
......@@ -222,7 +215,7 @@ begin
[AddressJSON.ToString]));
notification := TJSObject(Response.Result);
ShowNotification(string(notification['status']));
ShowToast(string(notification['status']));
xdwdsShipTo.Close;
xdwdsShipTo.SetJSONData(notification['ADDRESS']);
xdwdsShipTo.Open;
......@@ -241,8 +234,16 @@ begin
document.getElementById('btn_confirm_cancel').innerText := 'No';
document.getElementById('btn_confirm_delete').innerText := 'Yes';
asm
var confirmationModal = new bootstrap.Modal(document.getElementById('confirmation_modal'), {
keyboard: false });
var modal = document.getElementById('confirmation_modal');
// Ensure modal is a direct child of <body> to avoid z-index/backdrop issues
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
var confirmationModal = new bootstrap.Modal(modal, {
keyboard: false
});
confirmationModal.show();
end;
end;
......@@ -259,17 +260,12 @@ begin
FViewMain.ShowForm(TFViewCustomers)
end;
procedure TFViewAddCustomer.btnCloseNotificationClick(Sender: TObject);
// Closes a Notification.
begin
HideNotification();
end;
procedure TFViewAddCustomer.btnDeleteClick(Sender: TObject);
// Eventually will delete customers after a confirmation
// TODO implement deleting customers
begin
ShowMessage('Deleting Customers Is Not Yet Available');
ShowErrorModal('Deleting Customers Is Not Yet Available');
end;
procedure TFViewAddCustomer.btnEditClick(Sender: TObject);
......@@ -460,7 +456,7 @@ begin
edtCustomerID.Text := CustomerID;
ShowNotification(msg);
ShowToast(msg);
//TODO update the BILL_ADDRESS_BLOCK memo after saving.
......@@ -646,10 +642,10 @@ begin
else
mode := 'EDIT';
if notification = '' then
hideNotification()
else
showNotification(notification);
if notification <> '' then
begin
showToast(notification);
end;
EditMode();
......@@ -669,43 +665,6 @@ begin
EditMode();
end;
procedure TFViewAddCustomer.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFViewAddCustomer.memoAddressBlockChange(Sender: TObject);
begin
EditMode();
end;
procedure TFViewAddCustomer.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
begin
if Notification <> '' then
begin
splitNotification := Notification.Split([':']);
if(splitNotification[0] = 'Success') then
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
end
else
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
end;
end;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
end;
end;
procedure TFViewAddCustomer.tmrReturnTimer(Sender: TObject);
// Timer to returnto the customer page because it takes slightly too long to
......
......@@ -175,10 +175,10 @@ begin
Exit('');
Result := '';
asm
var Token = AToken.split('.');
if (Token.length = 3) {
Result = Token[1];
Result = atob(Result);
const parts = AToken.split('.');
if (parts.length === 3) { // <- strict compare
// JWTs use url-safe base64; convert before atob
Result = atob(parts[1].replace(/-/g,'+').replace(/_/g,'/'));
}
end;
end;
......
......@@ -19,7 +19,7 @@ type
FUnauthorizedAccessProc: TUnauthorizedAccessProc;
public
const clientVersion = '0.9.4';
const clientVersion = '0.9.6';
procedure InitApp(SuccessProc: TSuccessProc;
UnauthorizedAccessProc: TUnauthorizedAccessProc);
procedure SetClientConfig(Callback: TVersionCheckCallback);
......
......@@ -9,10 +9,11 @@ procedure ShowStatusMessage(const AMessage, AClass: string; const AElementId: st
procedure HideStatusMessage(const AElementId: string);
procedure ShowSpinner(SpinnerID: string);
procedure HideSpinner(SpinnerID: string);
procedure ShowErrorModal(const msg: string);
procedure ShowErrorModal(msg: string);
function CalculateAge(DateOfBirth: TDateTime): Integer;
function FormatPhoneNumber(PhoneNumber: string): string;
procedure ApplyReportTitle(CurrentReportType: string);
procedure ShowToast(const MessageText: string; const ToastType: string = 'success');
// function FormatDollarValue(ValueStr: string): string;
......@@ -84,9 +85,8 @@ begin
end;
// The $IFNDEF WIN32 was recommended by Holger to deal with any modal issues
procedure ShowErrorModal(const msg: string);
procedure ShowErrorModal(msg: string);
begin
{$IFNDEF WIN32}
asm
var modal = document.getElementById('main_errormodal');
var label = document.getElementById('main_lblmodal_body');
......@@ -110,13 +110,9 @@ begin
var bsModal = new bootstrap.Modal(modal, { keyboard: false });
bsModal.show();
end;
{$ENDIF}
end;
function CalculateAge(DateOfBirth: TDateTime): Integer;
var
Today, BirthDate: TJSDate;
......@@ -160,6 +156,71 @@ begin
end;
procedure ShowToast(const MessageText: string; const ToastType: string = 'success');
var
ParsedText, ToastKind, MsgPrefix: string;
Parts: TArray<string>;
begin
ParsedText := MessageText.Trim;
ToastKind := ToastType.ToLower;
// Check for "Success:" or "Failure:" at the start of message
if ParsedText.Contains(':') then
begin
Parts := ParsedText.Split([':'], 2);
MsgPrefix := Parts[0].Trim.ToLower;
if (MsgPrefix = 'success') or (MsgPrefix = 'failure') then
begin
ParsedText := Parts[1].Trim;
if MsgPrefix = 'success' then
ToastKind := 'success'
else
ToastKind := 'danger';
end;
end;
asm
var toastEl = document.getElementById('bootstrapToast');
var toastBody = document.getElementById('bootstrapToastBody');
if (!toastEl || !toastBody) return;
toastBody.innerText = ParsedText;
toastEl.classList.remove('bg-success', 'bg-danger', 'bg-warning', 'bg-info');
toastEl.classList.remove('slide-in');
switch (ToastKind) {
case 'danger':
toastEl.classList.add('bg-danger');
break;
case 'warning':
toastEl.classList.add('bg-warning');
break;
case 'info':
toastEl.classList.add('bg-info');
break;
default:
toastEl.classList.add('bg-success');
}
// Add slide-in animation
toastEl.classList.add('slide-in');
var toast = new bootstrap.Toast(toastEl, { delay: 2500 });
toast.show();
// Remove animation class after it's done (so it can be reapplied)
setTimeout(function() {
toastEl.classList.remove('slide-in');
}, 500);
end;
end;
procedure ApplyReportTitle(CurrentReportType: string);
var
CrimeTitleElement: TJSHTMLElement;
......
object FAddOrder: TFAddOrder
Width = 871
Height = 477
Height = 428
OnShow = WebFormShow
object WebLabel1: TWebLabel
Left = 4
Top = 81
Top = 49
Width = 95
Height = 15
Caption = 'Search Customers'
......@@ -13,7 +13,7 @@ object FAddOrder: TFAddOrder
end
object WebLabel2: TWebLabel
Left = 135
Top = 81
Top = 49
Width = 113
Height = 15
Caption = 'Selected Customer ID'
......@@ -22,7 +22,7 @@ object FAddOrder: TFAddOrder
end
object WebLabel3: TWebLabel
Left = 283
Top = 81
Top = 49
Width = 134
Height = 15
Caption = 'Selected Customer Name'
......@@ -31,7 +31,7 @@ object FAddOrder: TFAddOrder
end
object edtSearch: TWebEdit
Left = 4
Top = 102
Top = 70
Width = 121
Height = 22
HeightPercent = 100.000000000000000000
......@@ -40,7 +40,7 @@ object FAddOrder: TFAddOrder
end
object edtID: TWebEdit
Left = 135
Top = 102
Top = 70
Width = 142
Height = 22
ChildOrder = 1
......@@ -50,7 +50,7 @@ object FAddOrder: TFAddOrder
end
object TMSFNCGrid1: TTMSFNCGrid
Left = 0
Top = 160
Top = 111
Width = 871
Height = 317
Align = alBottom
......@@ -204,10 +204,11 @@ object FAddOrder: TFAddOrder
ScrollMode = scmItemScrolling
DesignTimeSampleData = True
OnCellClick = TMSFNCGrid1CellClick
ExplicitTop = 112
end
object cbCorrugatedPlate: TWebCheckBox
Left = 4
Top = 49
Top = 17
Width = 113
Height = 22
Caption = 'Corrugated Plate'
......@@ -219,7 +220,7 @@ object FAddOrder: TFAddOrder
end
object cbWebPlate: TWebCheckBox
Left = 134
Top = 49
Top = 17
Width = 83
Height = 22
Caption = 'Web Plate'
......@@ -230,7 +231,7 @@ object FAddOrder: TFAddOrder
end
object btnCancel: TWebButton
Left = 542
Top = 101
Top = 69
Width = 96
Height = 25
Caption = 'Cancel'
......@@ -241,7 +242,7 @@ object FAddOrder: TFAddOrder
end
object btnConfirm: TWebButton
Left = 436
Top = 101
Top = 69
Width = 96
Height = 25
Caption = 'Select'
......@@ -252,7 +253,7 @@ object FAddOrder: TFAddOrder
end
object cbCuttingDie: TWebCheckBox
Left = 239
Top = 49
Top = 17
Width = 83
Height = 22
Caption = 'Cutting Die'
......@@ -261,30 +262,9 @@ object FAddOrder: TFAddOrder
WidthPercent = 100.000000000000000000
OnClick = cbCuttingDieClick
end
object edtNotification: TWebEdit
Left = 4
Top = 16
Width = 510
Height = 22
HelpType = htKeyword
TabStop = False
ChildOrder = 8
ElementFont = efCSS
Enabled = False
Font.Charset = ANSI_CHARSET
Font.Color = clRed
Font.Height = -13
Font.Name = 'Arial'
Font.Style = []
HeightPercent = 100.000000000000000000
HideSelection = False
ParentFont = False
TabOrder = 1
WidthPercent = 100.000000000000000000
end
object edtName: TWebEdit
Left = 283
Top = 102
Top = 70
Width = 142
Height = 22
ChildOrder = 1
......
......@@ -11,7 +11,7 @@ uses
VCL.TMSFNCGridOptions, Vcl.Controls, VCL.TMSFNCCustomControl,
VCL.TMSFNCCustomScrollControl, VCL.TMSFNCGridData, VCL.TMSFNCCustomGrid,
VCL.TMSFNCGrid, Vcl.StdCtrls, WEBLib.StdCtrls, XData.Web.Client, Data.DB,
XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, ConnectionModule;
XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, ConnectionModule, Utils;
type
TFAddOrder = class(TWebForm)
......@@ -30,7 +30,6 @@ type
xdwdsCustomersSHORT_NAME: TStringField;
wdsCustomers: TWebDataSource;
cbCuttingDie: TWebCheckBox;
edtNotification: TWebEdit;
xdwdsCustomersstaff_fields_invoice_to: TStringField;
xdwdsCustomersCUSTOMER_ID: TIntegerField;
WebLabel3: TWebLabel;
......@@ -67,25 +66,25 @@ begin
Close;
end;
procedure TFAddOrder.btnConfirmClick(Sender: TObject);
begin
confirm := true;
edtNotification.ElementHandle.style.setProperty('color', '#8B0000', 'important');
if ( ( not cbCorrugatedPlate.Checked ) and ( not cbWebPlate.Checked ) and ( not cbCuttingDie.Checked ) ) then
begin
edtNotification.Text := 'Please Select an Order Type';
ShowToast('Please Select an Order Type', 'danger');
confirm := false;
end;
if edtID.Text = '' then
begin
edtNotification.Text := 'Please Select a Customer';
ShowToast('Please Select a Customer', 'danger');
confirm := false;
end;
if ( ( not cbCorrugatedPlate.Checked ) and ( not cbWebPlate.Checked ) and ( not cbCuttingDie.Checked ) and (edtID.Text = '' )) then
begin
edtNotification.Text := 'Please Select an Order Type and a Customer';
ShowToast('Please Select an Order Type and a Customer', 'danger');
confirm := false;
end;
......@@ -95,6 +94,7 @@ begin
end;
end;
procedure TFAddOrder.WebFormShow(Sender: TObject);
begin
confirm := false;
......@@ -108,23 +108,27 @@ begin
cbCuttingDie.Checked := False;
end;
procedure TFAddOrder.cbCuttingDieClick(Sender: TObject);
begin
cbCorrugatedPlate.Checked := False;
cbWebPlate.Checked := False;
end;
procedure TFAddOrder.cbWebPlateClick(Sender: TObject);
begin
cbCorrugatedPlate.Checked := False;
cbCuttingDie.Checked := False;
end;
procedure TFAddOrder.edtSearchChange(Sender: TObject);
begin
ApplyFilter;
end;
[async] procedure TFAddOrder.getCustomers();
// retrieves customer list from server
var
......@@ -144,6 +148,7 @@ begin
PopulateGridManually;
end;
procedure TFAddOrder.PopulateGridManually;
// populates the grid with customers manually.
var
......@@ -191,6 +196,7 @@ begin
DBID := TMSFNCGrid1.Cells[0, ARow];
end;
procedure TFAddOrder.ApplyFilter;
// filters the grid based on search textbox contents.
var
......
......@@ -42,6 +42,7 @@ object FViewCustomers: TFViewCustomers
HeightPercent = 100.000000000000000000
Text = '500'
WidthPercent = 100.000000000000000000
OnChange = wcbPageSizeChange
ItemIndex = -1
Items.Strings = (
'100'
......
<div class="container h-100 d-flex flex-column mt-0" style="max-width: 100%; padding-bottom: 0;">
<!-- Alert Section -->
<div class="row">
<div class=col-sm>
<div id="view.login.message" class="alert alert-danger">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
</div>
</div>
<!-- Actions Row -->
<div class="row mt-3 justify-content-center align-items-end">
<div class="col-auto">
......
......@@ -13,7 +13,7 @@ uses
WEBLib.Grids, VCL.TMSFNCTypes, VCL.TMSFNCUtils, VCL.TMSFNCGraphics,
VCL.TMSFNCGraphicsTypes, VCL.TMSFNCGridCell, VCL.TMSFNCGridOptions,
VCL.TMSFNCCustomControl, VCL.TMSFNCCustomScrollControl, VCL.TMSFNCGridData,
VCL.TMSFNCCustomGrid, VCL.TMSFNCGrid;
VCL.TMSFNCCustomGrid, VCL.TMSFNCGrid, VCL.Forms;
type
TFViewCustomers = class(TWebForm)
......@@ -36,13 +36,13 @@ type
procedure btnAddCustomerClick(Sender: TObject);
procedure wdbtcCustomersDblClickCell(Sender: TObject; ACol, ARow: Integer);
procedure edtFilterChange(Sender: TObject);
procedure wcbPageSizeChange(Sender: TObject);
private
{ Private declarations }
procedure GeneratePagination(TotalPages: Integer);
[async] procedure GetCustomers(searchOptions: string);
function GenerateSearchOptions(): string;
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure ShowSelectCustomerForm();
var
......@@ -75,6 +75,7 @@ begin
newform.Caption := 'Select Customer and Order Type';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.Position := poScreenCenter;
// used to manage Back button handling to close subform
window.location.hash := 'subform';
......@@ -173,34 +174,13 @@ begin
end;
procedure TFViewCustomers.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
procedure TFViewCustomers.wcbPageSizeChange(Sender: TObject);
begin
if Notification <> '' then
begin
splitNotification := Notification.Split([':']);
if(splitNotification[0] = 'Success') then
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
end
else
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
end;
end;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
end;
PageSize := StrToInt(wcbPageSize.Text);
getCustomers(GenerateSearchOptions());
end;
procedure TFViewCustomers.wdbtcCustomersDblClickCell(Sender: TObject; ACol,
ARow: Integer);
begin
......
......@@ -108,6 +108,7 @@ object FViewEditUser: TFViewEditUser
ElementID = 'edtconfirmpassword'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnChange = edtConfirmPasswordChange
end
object edtEmail: TWebEdit
Left = 96
......@@ -128,6 +129,7 @@ object FViewEditUser: TFViewEditUser
ElementID = 'edtpassword'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnChange = edtPasswordChange
end
object btnConfirm: TWebButton
Left = 96
......@@ -187,48 +189,6 @@ object FViewEditUser: TFViewEditUser
WidthPercent = 100.000000000000000000
OnClick = btnCancelClick
end
object btnConfirmChanges: TWebButton
Left = 100
Top = 330
Width = 96
Height = 25
Caption = 'Confirm'
ChildOrder = 16
ElementID = 'btn_confirm_changes'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnConfirmChangesClick
end
object pnlMessage: TWebPanel
Left = 482
Top = 4
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 17
TabOrder = 8
object lblMessage: TWebLabel
Left = 16
Top = 11
Width = 46
Height = 15
Caption = 'Message'
ElementID = 'view.login.message.label'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object cbStatus: TWebCheckBox
Left = 96
Top = 162
......
<div class="row">
<div class="col-12">
<div class="container mt-4">
<div class="row justify-content-center">
<div class="col-12 col-md-8">
<div class="container">
<!-- Edit-User form -->
<div class="row">
<div class=col-sm>
<div id="view.login.message" class="alert alert-danger">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
</div>
</div>
<form class="form-inline">
<div class="row">
<div class="col-sm">
<label class= 'pe-2' style="font-weight: 700;font-size: 15px;"id="lblfullname">Full Name:</label>
<input id="edtfullname" class= "form-control input-sm" width='50%'/>
</div>
<div class="col-sm">
<label class= 'pe-2' style="font-weight: 700;font-size: 15px"id="lblusername">Username:</label>
<input id="edtusername" class="form-control input-sm" width='50%'>
</div>
</div>
</form>
<form class="form-inline">
<div class="row">
<div class="col-sm">
<label class='pe-2' style="font-weight: 700;font-size: 15px;"id="lblpassword">Password:</label>
<input id="edtpassword" class= "form-control input-sm" width='50%'/>
</div>
<div class="col-sm">
<label class= 'pe-2' style="font-weight: 700;font-size: 15px"id="lblconfirm">Confirm Password:</label>
<input class="form-control input-sm" id="edtconfirmpassword">
</div>
</div>
<div class="col-lg-10 col-xl-8 mx-auto">
<form id="edituserform" class="row g-3 needs-validation" novalidate>
<div class="col-md-6">
<label id="lblfullname" for="edtfullname" class="form-label">Full&nbsp;Name</label>
<input id="edtfullname" class="form-control" required>
<div class="invalid-feedback">Full Name is required.</div>
</div>
<div class="col-md-6">
<label id="lblusername" for="edtusername" class="form-label">Username</label>
<input id="edtusername" class="form-control" required>
<div class="invalid-feedback">Username is required.</div>
</div>
<div class="col-md-6">
<label id="lblpassword" for="edtpassword" class="form-label">Password</label>
<input id="edtpassword" type="password" class="form-control" required>
<div class="invalid-feedback">Passwords must match.</div>
</div>
<div class="col-md-6">
<label id="lblconfirm" for="edtconfirmpassword" class="form-label">Confirm&nbsp;Password</label>
<input id="edtconfirmpassword" type="password" class="form-control" required disabled>
<div class="invalid-feedback">Passwords must match.</div>
</div>
<div class="col-md-6">
<label id="lblemail" for="edtemail" class="form-label">Email&nbsp;Address</label>
<input id="edtemail" type="email" class="form-control" required>
<div class="invalid-feedback">Valid email is required.</div>
</div>
<div class="col-md-6">
<label id="lblQB" for="edtQB" class="form-label">QuickBooks&nbsp;ID</label>
<input id="edtQB" class="form-control">
</div>
<div class="col-md-6">
<label id="lblrights" for="edtrights" class="form-label">System&nbsp;Rights</label>
<input id="edtrights" class="form-control">
</div>
<div class="col-md-6">
<label id="lblaccess" for="cbaccess" class="form-label">Access&nbsp;Type</label>
<select id="cbaccess" class="form-select" required>
<option selected disabled value="">Choose...</option>
<option value="ALL">All</option>
<option value="LIMITED">Limited</option>
</select>
<div class="invalid-feedback">Please select an access type.</div>
</div>
<div class="col-md-6">
<div class="form-check pt-2">
<input id="cbstatus" class="form-check-input" type="checkbox">
<label id="lblactive" for="cbstatus" class="form-check-label">Active</label>
</div>
</div>
<div class="d-flex gap-2 mt-4">
<button id="btnconfirm" type="button" class="btn btn-primary flex-grow-1">
Confirm
</button>
<button id="btncancel" type="button" class="btn btn-outline-secondary flex-grow-1">
Cancel
</button>
</div>
</form>
<form class="form-inline">
<div class="row">
<div class="col-sm">
<label class='pe-2' style="font-weight: 700;font-size: 15px;" id="lblemail">Email Address:</label>
<input id="edtemail" class= "form-control input-sm" width='50%'/>
</div>
<div class="col-sm">
<label class= 'pe-2' style="font-weight: 700;font-size: 15px"id="lblQB">Quickbook ID:</label>
<input class="form-control input-sm" id="edtQB">
</div>
</div>
</form>
<div class="row">
<div class="col-6">
<label class='pe-2' style="font-weight: 700;font-size: 15px;" id="lblrights">System Rights:</label>
<input id="edtrights" class= "form-control input-sm" width='50%'/>
</div>
</div>
<div class="row">
<div class="col-sm py-3">
<label class= 'pe-2' style="font-weight: 700;font-size: 15px"id="lblaccess">Access Type:</label>
<select class="custom-select-large" id="cbaccess" style="font-size: 1.00rem;"></select>
</div>
</div>
<div class="row">
<div class="col-sm">
<form class='form-inline'>
<div class="col-sm">
<div class="form-cells"><input type="checkbox" id="cbstatus"></div>
<div class="form-cells ps-1 py-2"><label style="font-weight: 700;font-size: 15px" id="lblactive">Active></label></div>
</div>
</form>
</div>
<div class="col-sm-12 py-2">
<button class="py-2" id="btnconfirm" style="font-weight: 700;font-size: 15px";>Confirm</button>
<button class="py-2" id="btncancel" style="font-weight: 700;font-size: 15px";>Cancel</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Confirmation modal -->
<div class="modal fade" id="confirmation_modal" tabindex="-1" aria-labelledby="confirmation_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
......@@ -95,3 +94,4 @@
</div>
</div>
</div>
......@@ -26,10 +26,6 @@ type
XDataWebClient1: TXDataWebClient;
btnCancel: TWebButton;
WebTimer1: TWebTimer;
btnConfirmChanges: TWebButton;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
lblactive: TWebLabel;
cbStatus: TWebCheckBox;
lblRights: TWebLabel;
......@@ -42,8 +38,8 @@ type
procedure btnConfirmClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure WebTimer1Timer(Sender: TObject);
procedure btnConfirmChangesClick(Sender: TObject);
procedure btnCloseNotificationClick(Sender: TObject);
procedure edtPasswordChange(Sender: TObject);
procedure edtConfirmPasswordChange(Sender: TObject);
private
{ Private declarations }
FMessage: string;
......@@ -59,8 +55,7 @@ type
QB: string;
[async] procedure EditUser();
[async] function AddUser(): string;
procedure HideNotification();
procedure ShowNotification(notification: string);
procedure ValidatePasswords;
public
{ Public declarations }
Info: string;
......@@ -84,24 +79,10 @@ Utils;
procedure TFViewEditUser.btnCancelClick(Sender: TObject);
// Cancels the edit or addition
begin
Info := 'Failure:Changes discarded!';
Info := 'Failure: Changes discarded!';
FViewMain.ShowUserForm(Info);
end;
procedure TFViewEditUser.btnCloseNotificationClick(Sender: TObject);
begin
HideNotification;
end;
procedure TFViewEditUSer.btnConfirmChangesClick(Sender: TObject);
begin
if Mode = 'Edit' then
EditUser()
else
AddUser();
WebTimer1.Enabled := true;
Utils.ShowSpinner('spinner');
end;
function TFViewEditUser.AddUser: string;
// Sends UserInfo over to the server so it can be added to the database
......@@ -131,20 +112,6 @@ begin
end;
procedure TFViewEditUser.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFViewEditUser.ShowNotification(Notification: string);
begin
if Notification <> '' then
begin
lblMessage.Caption := Notification;
pnlMessage.ElementHandle.hidden := False;
end;
end;
procedure TFViewEditUser.EditUser();
// Sends EditOptions over to the server so the given user can be editted
var
......@@ -172,6 +139,16 @@ begin
end;
procedure TFViewEditUser.edtConfirmPasswordChange(Sender: TObject);
begin
ValidatePasswords;
end;
procedure TFViewEditUser.edtPasswordChange(Sender: TObject);
begin
ValidatePasswords;
end;
class function TFViewEditUser.CreateForm(AElementID, Mode, Username, Password, Name, Status, Email,
Access, Rights, Perspective, QB: string): TWebForm;
// Autofills known information about a user on create
......@@ -199,9 +176,7 @@ procedure TFViewEditUser.WebFormCreate(Sender: TObject);
// Autofills known information about a user on create
begin
if FMessage <> '' then
ShowNotification(FMessage)
else
HideNotification;
ShowToast(FMessage);
edtUsername.Text := Username;
edtFullName.Text := FullName;
if Mode = 'Edit' then
......@@ -226,132 +201,79 @@ begin
FViewMain.ShowUserForm(Info);
end
else
showNotification(Info);
showToast(Info);
console.log('Info at Timer:' + Info);
end;
procedure TFViewEditUser.btnConfirmClick(Sender: TObject);
// Confirms the edit or addition
var
checkString: string;
charIndex: integer;
phoneNum: string;
FormEl: TJSHTMLFormElement;
begin
{ checkString := edtFullName.Text + edtUsername.Text + edtPassword.Text
+ edtConfirmPassword.Text + edtPhoneNumber.Text + edtEmail.Text;
if string(edtFullName.Text).IsEmpty then
begin
ShowNotification('Full Name field is blank!');
exit;
end;
FormEl := TJSHTMLFormElement(document.getElementById('edituserform'));
if string(edtUsername.Text).IsEmpty then
if not FormEl.checkValidity then
begin
ShowNotification('Username field is blank!');
exit;
FormEl.classList.add('was-validated');
Exit;
end;
if string(edtPassword.Text).IsEmpty then
begin
ShowNotification('Password field is blank!');
exit;
end;
if string(edtConfirmPassword.Text).IsEmpty then
begin
ShowNotification('Please confirm your password!');
exit;
end;
if string(edtPhoneNumber.Text).IsEmpty then
begin
ShowNotification('Phone Number field is blank!');
exit;
end;
if string(edtEmail.Text).IsEmpty then
begin
ShowNotification('Email field is blank!');
exit;
end;
Utils.ShowSpinner('spinner');
if checkString.Contains('&') then
begin
ShowNotification('No fields may contain "&&"!');
exit;
end;
if Mode = 'Edit' then
EditUser
else
AddUser;
if string(edtEmail.Text).Contains('@') = false then
begin
ShowNotification('Please enter a valid email address');
exit;
end;
WebTimer1.Enabled := True;
end;
if (length(string(edtEmail.Text).Split(['@'])) <> 2) or (string(edtEmail.text).CountChar('@') > 1) then
begin
ShowNotification('Please enter a valid email address');
exit;
end;
phoneNum := edtPhoneNumber.Text;
procedure TFViewEditUser.ValidatePasswords;
var
Pwd, Confirm: string;
PwdInput, ConfirmInput: TJSHTMLInputElement;
begin
PwdInput := TJSHTMLInputElement(edtPassword.ElementHandle);
ConfirmInput := TJSHTMLInputElement(edtConfirmPassword.ElementHandle);
if (not phoneNum.Contains('(')) or (not phoneNum.Contains(')')) or (not phoneNum.Contains('-')) then
begin
ShowNotification('Please enter a valid phone number');
exit;
end;
Pwd := PwdInput.value.Trim;
Confirm := ConfirmInput.value.Trim;
if (phoneNum.CountChar('(') <> 1) or (phoneNum.CountChar(')') <> 1) or (phoneNum.CountChar('-') <> 1) or (phoneNum.CountChar(' ') > 1) then
// Disable confirm until password exists
if Pwd = '' then
begin
ShowNotification('Please enter a valid phone number');
exit;
end;
phoneNum := phoneNum.Replace('(', '');
phoneNum := phoneNum.Replace(')', '');
phoneNum := phoneNum.Replace('-', '');
phoneNum := phoneNum.Replace(' ', '');
if(length(phoneNum) <> 10) then
ConfirmInput.disabled := True;
ConfirmInput.value := '';
ConfirmInput.setCustomValidity('');
ConfirmInput.classList.remove('is-invalid');
ConfirmInput.classList.remove('is-valid');
end
else
begin
ShowNotification('Please enter a valid phone number');
exit;
end;
ConfirmInput.disabled := False;
for CharIndex := 1 to Length(phoneNum) do
// Live match check
if Confirm = '' then
begin
if not (phoneNum[CharIndex] in ['0' .. '9']) then
begin
console.log('here');
ShowNotification('Please enter a valid phone number');
exit;
end;
end;
if edtPassword.Text <> edtConfirmPassword.Text then
ConfirmInput.setCustomValidity('');
ConfirmInput.classList.remove('is-invalid');
ConfirmInput.classList.remove('is-valid');
end
else if Confirm = Pwd then
begin
ShowNotification('Passwords must match!');
exit;
end;
if (length(edtPassword.Text) > 20) or (length(edtPassword.Text) < 6) then
ConfirmInput.setCustomValidity('');
ConfirmInput.classList.add('is-valid');
ConfirmInput.classList.remove('is-invalid');
end
else
begin
ShowNotification('Passwords must be between 6-20 characters!');
exit;
ConfirmInput.setCustomValidity('Passwords must match');
ConfirmInput.classList.add('is-invalid');
ConfirmInput.classList.remove('is-valid');
end;
}
asm
var modal = document.getElementById('confirmation_modal');
// ensure the modal is directly under <body>
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
var bsModal = new bootstrap.Modal(modal, {
keyboard: false
});
bsModal.show();
end;
end;
end.
......@@ -50,7 +50,6 @@ object FViewItems: TFViewItems
ChildOrder = 7
ElementID = 'btnadd'
ElementFont = efCSS
Enabled = False
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
......@@ -97,51 +96,6 @@ object FViewItems: TFViewItems
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object pnlMessage: TWebPanel
Left = 0
Top = 27
Width = 121
Height = 33
ElementClassName = 'card'
ElementID = 'view.login.message'
ChildOrder = 5
ElementBodyClassName = 'card-body'
ElementFont = efCSS
ElementPosition = epRelative
Role = 'null'
TabOrder = 5
Visible = False
object lblMessage: TWebLabel
Left = 28
Top = 9
Width = 42
Height = 13
Caption = 'Message'
ElementID = 'view.login.message.label'
ElementFont = efCSS
ElementPosition = epRelative
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementClassName = 'btn btn-light'
ElementID = 'view.login.message.button'
ElementFont = efCSS
ElementPosition = epRelative
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
Role = 'null'
WidthStyle = ssAuto
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object btnSave: TWebButton
Left = 565
Top = 228
......
<nav class="navbar navbar-expand navbar-light bg-light sticky-top" style="z-index: 100;">
<div class="container-fluid ps-0">
<div id="view.login.message" class="alert alert-danger"
style="padding: 0.25rem 0.5rem; font-size: 0.875rem; line-height: 1.5; display: flex; align-items: center; margin: 0 0 0 60px; height: 32px; width: 400px;">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
<ul class="navbar-nav me-auto ps-2">
<li class="nav-item pe-2">
<button id="btnadd" class="btn btn-primary btn-sm">Add</button>
......
......@@ -24,9 +24,6 @@ type
edtName: TWebEdit;
edtDescription: TWebEdit;
cbStatus: TWebCheckBox;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
btnSave: TWebButton;
btnCancel: TWebButton;
btnDelete: TWebButton;
......@@ -34,7 +31,6 @@ type
procedure WebFormCreate(Sender: TObject);
procedure btnAddClick(Sender: TObject);
procedure wcbPageSizeChange(Sender: TObject);
procedure btnCloseNotificationClick(Sender: TObject);
procedure btnEditClick(Sender: TObject);
procedure btnSaveClick(Sender: TObject);
procedure btnDeleteClick(Sender: TObject);
......@@ -45,8 +41,6 @@ type
procedure ClearTable();
procedure GeneratePagination(TotalPages: Integer);
function GenerateSearchOptions(): string;
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure ViewMode();
procedure EditMode();
[async] procedure GetItems(searchOptions: string);
......@@ -412,6 +406,7 @@ begin
newform.Caption := 'Select Customer and Order Type';
newForm.Popup := True;
newForm.position:= poScreenCenter;
newForm.Border := fbDialog;
// used to manage Back button handling to close subform
......@@ -427,64 +422,28 @@ end;
procedure TFViewItems.btnCancelClick(Sender: TObject);
begin
ShowMessage('Editting Items is not yet implemented');
ShowToast('Editing items is not yet implemented.', 'info');
end;
procedure TFViewItems.btnCloseNotificationClick(Sender: TObject);
begin
HideNotification();
end;
procedure TFViewItems.btnDeleteClick(Sender: TObject);
begin
ShowMessage('Deleting Items is no yet implemented');
ShowToast('Deleting items is no yet implemented.', 'info');
end;
procedure TFViewItems.btnEditClick(Sender: TObject);
begin
ShowMessage('Editting Items is not yet implemented');
ShowToast('Editing items is not yet implemented.', 'info');
//EditMode();
end;
procedure TFViewItems.btnSaveClick(Sender: TObject);
//TODO implement editting items
begin
ShowMessage('Editting Items is not yet implemented');
ShowToast('Editing items is not yet implemented.', 'info');
//ViewMode();
end;
procedure TFViewItems.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
begin
if Notification <> '' then
begin
splitNotification := Notification.Split([':']);
if(splitNotification[0] = 'Success') then
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
end
else
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
end;
end;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
end;
end;
procedure TFViewItems.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFViewItems.AddItem(itemOptions: string);
// adds an item to the database.
......
......@@ -57,7 +57,7 @@ object FViewMain: TFViewMain
end
object lblAppTitle: TWebLabel
Left = 57
Top = 31
Top = 33
Width = 75
Height = 14
Caption = 'Koehler-Gibson'
......
......@@ -47,7 +47,22 @@
</div>
</div>
</nav>
<!-- Toast wrapper directly under navbar -->
<div id="toast-wrapper"
class="position-fixed top-0 start-0 mt-5 ms-4"
style="z-index: 1080; min-width: 300px; max-width: 500px;">
<div id="bootstrapToast"
class="toast align-items-center text-white bg-success border-0 shadow"
role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body" id="bootstrapToastBody">
Success message
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto"
data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div id="main.webpanel" class="col-12"></div>
......@@ -86,6 +101,25 @@
</div>
</div>
<div class="modal fade" id="confirmation_modal" tabindex="-1" aria-labelledby="confirmation_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="confirmation_modal_label">Confirm</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 fw-bold" id="modal_body">
Are you sure you want to delete this order?
</div>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-secondary me-3" data-bs-dismiss="modal" id="btn_confirm_cancel">Cancel</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="btn_confirm_delete">Delete</button>
</div>
</div>
</div>
</div>
......
......@@ -6,7 +6,7 @@ uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, WEBLib.ExtCtrls, Vcl.Controls, Vcl.StdCtrls,
WEBLib.StdCtrls, Data.DB, XData.Web.JsonDataset, XData.Web.Dataset,
App.Types, ConnectionModule, XData.Web.Client, WEBLib.Menus;
App.Types, ConnectionModule, XData.Web.Client, WEBLib.Menus, Utils;
type
TFViewMain = class(TWebForm)
......@@ -46,6 +46,8 @@ type
//procedure EditUser( AParam, BParam, CParam, DParam, EParam: string);
function GetUserInfo: string;
procedure setActive(page: string);
procedure ConfirmLogout;
procedure OnConfirmLogout(Event: TJSEvent);
public
{ Public declarations }
class procedure Display(LogoutProc: TLogoutProc);
......@@ -101,7 +103,6 @@ begin
ShowForm(TFViewOrders);
lblAppTitle.Caption := 'Koehler-Gibson Orders';
lblVersion.Caption := 'v' + DMConnection.clientVersion;
setActive('Orders');
end;
......@@ -117,7 +118,7 @@ begin
setActive('Customers');
end
else
ShowMessage('Please Save or Cancel your changes');
ShowErrorModal('Please Save or Cancel your changes');
end;
procedure TFViewMain.lblHomeClick(Sender: TObject);
......@@ -129,7 +130,7 @@ begin
//setActive('Home');
end
else
ShowMessage('Please Save or Cancel your changes');
ShowErrorModal('Please Save or Cancel your changes');
end;
procedure TFViewMain.lblordersClick(Sender: TObject);
......@@ -142,7 +143,7 @@ begin
setActive('Orders');
end
else
ShowMessage('Please Save or Cancel your changes');
ShowErrorModal('Please Save or Cancel your changes');
end;
procedure TFViewMain.lblQuickbooksClick(Sender: TObject);
......@@ -154,7 +155,7 @@ begin
setActive('QuickBooks');
end
else
ShowMessage('Please Save or Cancel your changes');
ShowErrorModal('Please Save or Cancel your changes');
end;
procedure TFViewMain.lblUsersClick(Sender: TObject);
......@@ -165,7 +166,7 @@ begin
lblAppTitle.Caption := 'Koehler-Gibson Users';
end
else
ShowMessage('Please Save or Cancel your changes');
ShowErrorModal('Please Save or Cancel your changes');
end;
procedure TFViewMain.lblItemsListClick(Sender: TObject);
......@@ -177,7 +178,7 @@ begin
setActive('Items');
end
else
ShowMessage('Please Save or Cancel your changes');
ShowErrorModal('Please Save or Cancel your changes');
end;
procedure TFViewMain.setActive(page: string);
......@@ -200,15 +201,55 @@ end;
procedure TFViewMain.mnuLogoutClick(Sender: TObject);
begin
FLogoutProc;
ConfirmLogout;
end;
procedure TFViewMain.wllblLogoutClick(Sender: TObject);
begin
FLogoutProc;
ConfirmLogout;
end;
procedure TFViewMain.ConfirmLogout;
var
yesBtn: TJSElement;
begin
document.getElementById('modal_body').innerHTML := 'Are you sure you want to log out?';
document.getElementById('btn_confirm_cancel').innerText := 'No';
document.getElementById('btn_confirm_delete').innerText := 'Yes';
asm
var modal = document.getElementById('confirmation_modal');
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
end;
// Detach any existing click handler (optional cleanup if reused often)
yesBtn := document.getElementById('btn_confirm_delete');
if Assigned(yesBtn) then
begin
TJSElement(yesBtn).removeEventListener('click', @OnConfirmLogout);
TJSElement(yesBtn).addEventListener('click', @OnConfirmLogout);
end;
asm
var confirmationModal = new bootstrap.Modal(document.getElementById('confirmation_modal'), {
keyboard: false
});
confirmationModal.show();
end;
end;
procedure TFViewMain.OnConfirmLogout(Event: TJSEvent);
begin
if Assigned(FLogoutProc) then
FLogoutProc('');
end;
procedure TFViewMain.wllblUserProfileClick(Sender: TObject);
begin
......
......@@ -99,41 +99,6 @@ object FOrderEntryCorrugated: TFOrderEntryCorrugated
Visible = False
WidthPercent = 100.000000000000000000
end
object pnlMessage: TWebPanel
Left = 324
Top = 19
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 5
ElementPosition = epRelative
Role = 'null'
TabOrder = 0
object lblMessage: TWebLabel
Left = 28
Top = 9
Width = 44
Height = 14
Caption = 'Message'
ElementID = 'view.login.message.label'
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
Role = 'null'
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object dtpOrderDate: TWebDateTimePicker
Left = 22
Top = 218
......@@ -385,6 +350,7 @@ object FOrderEntryCorrugated: TFOrderEntryCorrugated
HeightPercent = 100.000000000000000000
HideSelection = False
WidthPercent = 100.000000000000000000
OnChange = edtJobNameChange
DataField = 'staff_fields_job_name'
DataSource = WebDataSource1
end
......@@ -1190,7 +1156,7 @@ object FOrderEntryCorrugated: TFOrderEntryCorrugated
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btn_confirm_delete: TWebButton
object btn_modal_confirm: TWebButton
Left = 1094
Top = 414
Width = 96
......@@ -1200,7 +1166,7 @@ object FOrderEntryCorrugated: TFOrderEntryCorrugated
ElementID = 'btn_confirm_delete'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btn_confirm_deleteClick
OnClick = btn_modal_confirmClick
end
object btnEdit: TWebButton
Left = 1202
......
<nav class="navbar navbar-expand navbar-light bg-light border-light sticky-top" style="z-index: 100;">
<div class="container-fluid ps-0">
<div id="view.login.message" class="alert alert-danger"
style="padding: 0.25rem 0.5rem; font-size: 0.875rem; line-height: 1.5; display: flex; align-items: center; margin: 0 0 0 60px; height: 32px; width: 400px;">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
<ul class="navbar-nav me-auto ps-2">
<li class="nav-item pe-2">
<button id="btnadd" class="btn btn-primary btn-sm">Add</button>
......@@ -220,7 +215,7 @@
<hr class="custom-hr">
<div class="row">
<div class="col-auto">
<label for="wdbe_first_name" class="form-label mt-2">Loose:</label>
<label for="wdbe_first_name" style="font-weight: 700; font-size: 15px;" class="form-label mt-2">Loose:</label>
<input type="checkbox" id="cbloose">
<input id="edtloose" class="form-control input-sm" style="width: 150px"/>
</div>
......@@ -367,23 +362,18 @@
<div class="modal fade" id="confirmation_modal" tabindex="-1" aria-labelledby="confirmation_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="confirmation_modal_label">Confirm</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="modal_body">
<div class="modal-body fs-6 fw-bold" id="modal_body">
Are you sure you want to delete this order?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id= 'btn_confirm_cancel'>Cancel</button>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-secondary me-3" data-bs-dismiss="modal" id="btn_confirm_cancel">Cancel</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="btn_confirm_delete">Delete</button>
</div>
</div>
</div>
</div>
<style>
.modal-backdrop {
opacity: 0 !important;
}
</style>
......@@ -228,43 +228,6 @@ object FOrderEntryCuttingDie: TFOrderEntryCuttingDie
WidthPercent = 100.000000000000000000
OnClick = btnCancelClick
end
object pnlMessage: TWebPanel
Left = 324
Top = 19
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 5
ElementPosition = epRelative
Role = 'alert'
TabOrder = 15
object lblMessage: TWebLabel
Left = 28
Top = 9
Width = 46
Height = 15
Caption = 'Message'
ElementID = 'view.login.message.label'
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
ElementFont = efCSS
ElementPosition = epRelative
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
Role = 'button'
WidthStyle = ssAuto
WidthPercent = 100.000000000000000000
end
end
object edtCompanyName: TWebDBEdit
Left = 26
Top = 92
......@@ -400,14 +363,15 @@ object FOrderEntryCuttingDie: TFOrderEntryCuttingDie
end
object WebDataSource1: TWebDataSource
DataSet = XDataWebDataSet1
Left = 22
Top = 10
OnDataChange = WebDataSource1DataChange
Left = 318
Top = 262
end
object XDataWebDataSet1: TXDataWebDataSet
AfterEdit = XDataWebDataSet1AfterEdit
Connection = DMConnection.ApiConnection
Left = 90
Top = 20
Left = 318
Top = 208
object XDataWebDataSet1COMPANY_ID: TIntegerField
FieldName = 'COMPANY_ID'
end
......@@ -471,8 +435,8 @@ object FOrderEntryCuttingDie: TFOrderEntryCuttingDie
end
object XDataWebClient1: TXDataWebClient
Connection = DMConnection.ApiConnection
Left = 192
Top = 92
Left = 218
Top = 76
end
object tmrScrollTop: TWebTimer
Interval = 100
......@@ -487,21 +451,21 @@ object FOrderEntryCuttingDie: TFOrderEntryCuttingDie
end
object xdwdsShipTo: TXDataWebDataSet
AfterEdit = xdwdsShipToAfterEdit
Left = 288
Top = 370
Left = 438
Top = 208
object xdwdsShipToADDRESS: TStringField
FieldName = 'ADDRESS'
end
end
object wdsQBItem: TWebDataSource
DataSet = xdwdsQBItem
Left = 230
Top = 554
Left = 272
Top = 548
end
object xdwdsQBItem: TXDataWebDataSet
AfterEdit = xdwdsQBItemAfterEdit
Left = 190
Top = 548
Left = 568
Top = 216
object xdwdsQBItemname: TStringField
FieldName = 'name'
end
......
<nav class="navbar navbar-expand navbar-light bg-light sticky-top" style="z-index: 100;">
<div class="container-fluid ps-0">
<div id="view.login.message" class="alert alert-danger"
style="padding: 0.25rem 0.5rem; font-size: 0.875rem; line-height: 1.5; display: flex; align-items: center; margin: 0 0 0 60px; height: 32px; width: 400px;">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
<ul class="navbar-nav me-auto ps-2">
<li class="nav-item pe-2">
<button id="btnadd" class="btn btn-primary btn-sm">Add</button>
......@@ -131,24 +126,18 @@
</div>
<div class="modal fade" id="confirmation_modal" tabindex="-1" aria-labelledby="confirmation_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="confirmation_modal_label">Confirm</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="modal_body">
<div class="modal-body fs-6 fw-bold" id="modal_body">
Are you sure you want to delete this order?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id=btn_confirm_cancel>Cancel</button>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-secondary me-3" data-bs-dismiss="modal" id="btn_confirm_cancel">Cancel</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="btn_confirm_delete">Delete</button>
</div>
</div>
</div>
</div>
</div>
<style>
.modal-backdrop {
opacity: 0 !important;
}
</style>
......@@ -112,44 +112,6 @@ object FOrderEntryWeb: TFOrderEntryWeb
Visible = False
WidthPercent = 100.000000000000000000
end
object pnlMessage: TWebPanel
Left = 324
Top = 19
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 5
ElementPosition = epRelative
Role = 'alert'
TabOrder = 0
object lblMessage: TWebLabel
Left = 28
Top = 9
Width = 46
Height = 15
Caption = 'Message'
ElementID = 'view.login.message.label'
ElementPosition = epRelative
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
ElementFont = efCSS
ElementPosition = epRelative
HeightStyle = ssAuto
HeightPercent = 100.000000000000000000
Role = 'button'
WidthStyle = ssAuto
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object edtCompanyName: TWebDBEdit
Left = 24
Top = 92
......@@ -743,7 +705,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
Top = 87
Width = 96
Height = 25
Caption = '+'
Caption = 'Add Color'
ChildOrder = 59
ElementID = 'btnaddcolor'
HeightPercent = 100.000000000000000000
......@@ -863,6 +825,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtaround'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_around'
DataSource = WebDataSource1
......@@ -876,6 +839,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtaccross'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_accross'
DataSource = WebDataSource1
......@@ -889,6 +853,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtreverseprint'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_reverse_print'
DataSource = WebDataSource1
......@@ -902,6 +867,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtsurfaceprint'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_surface_print'
DataSource = WebDataSource1
......@@ -915,6 +881,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtcutoffdimension'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_cutoff_dimension'
DataSource = WebDataSource1
......@@ -928,6 +895,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtcylinderrepeat'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_cylinder_repeat'
DataSource = WebDataSource1
......@@ -941,6 +909,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtpitch'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_pitch'
DataSource = WebDataSource1
......@@ -954,6 +923,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtbleed'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_bleed'
DataSource = WebDataSource1
......@@ -967,6 +937,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtteeth'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_teeth'
DataSource = WebDataSource1
......@@ -980,6 +951,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtcutback'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_cutback'
DataSource = WebDataSource1
......@@ -993,6 +965,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtminimumtrapdimension'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_minimum_trap_dim'
DataSource = WebDataSource1
......@@ -1006,6 +979,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtmaximumtrapdimension'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'layout_maximum_trap_dim'
DataSource = WebDataSource1
......@@ -1019,6 +993,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
ChildOrder = 79
ElementID = 'edtsize'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'upc_size'
DataSource = WebDataSource1
......@@ -1028,10 +1003,12 @@ object FOrderEntryWeb: TFOrderEntryWeb
Top = 452
Width = 121
Height = 23
TabStop = False
AutoSize = True
ChildOrder = 79
ElementID = 'edtbarwidthreduction'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'upc_bar_width_reduction'
DataSource = WebDataSource1
......@@ -1041,10 +1018,12 @@ object FOrderEntryWeb: TFOrderEntryWeb
Top = 523
Width = 121
Height = 23
TabStop = False
AutoSize = True
ChildOrder = 79
ElementID = 'edtdistortionamount'
HeightPercent = 100.000000000000000000
ShowFocus = False
WidthPercent = 100.000000000000000000
DataField = 'upc_distortion_amount'
DataSource = WebDataSource1
......@@ -1054,6 +1033,7 @@ object FOrderEntryWeb: TFOrderEntryWeb
Top = 490
Width = 121
Height = 23
TabStop = False
AutoSize = True
ChildOrder = 79
ElementID = 'edtdistortionpercent'
......
<nav class="navbar navbar-expand navbar-light bg-light sticky-top" style="z-index: 100;">
<div class="container-fluid ps-0">
<div id="view.login.message" class="alert alert-danger"
style="padding: 0.25rem 0.5rem; font-size: 0.875rem; line-height: 1.5; display: flex; align-items: center; margin: 0 0 0 60px; height: 32px; width: 400px;">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
<ul class="navbar-nav me-auto ps-2">
<li class="nav-item pe-2">
<button id="btnadd" class="btn btn-primary btn-sm">Add</button>
......@@ -248,25 +243,43 @@
<input class="form-control input-sm" id="dtpdigitalcolordate" type="date">
</div>
</div>
<h4 class="custom-h4 mt-3">Quantity and Colors</h4>
<h4 class="custom-h4 mt-3">Quantity</h4>
<hr class="custom-hr">
<div class="row">
<div class="col-auto">
<label style="font-weight: 700; font-size: 15px;" class="form-label mt-2">Press Name:</label>
<input id="edtpressname" class="form-control input-sm" width='50%'/>
<input id="edtpressname" class="form-control input-sm" width="50%" />
</div>
<div class="col-auto">
<label style="font-weight: 700; font-size: 15px;" class="form-label mt-2">Anilax Info:</label>
<input id="edtanilaxinfo" class="form-control input-sm" width='50%'/>
</div>
<div class="col-auto">
<label for="wdbe_first_name" style="font-weight: 700; font-size: 15px;" class="form-label mt-2">Colors:</label>
<button id="btnaddcolor" class="btn btn-primary btn-sm float-end">+</button>
<div id="additionalFields" class="row mt-3"></div>
<input id="edtanilaxinfo" class="form-control input-sm" width="50%" />
</div>
</div>
<h4 class="custom-h4 mt-3">Colors</h4>
<hr class="custom-hr">
<div class="row align-items-center">
<!-- placeholders for the 4 dynamic input columns to center the Add Color button -->
<div class="col-sm"></div>
<div class="col-sm"></div>
<div class="col-sm"></div>
<div class="col-sm"></div>
<div class="col-auto d-flex justify-content-center">
<!-- Delphi-generated TWebButton stays here -->
<button id="btnaddcolor" class="btn btn-primary btn-sm me-3">
Add Color
</button>
</div>
</div>
<!-- Dynamically injected color rows go here -->
<div id="additionalFields" class="row mt-3"></div>
<h4 class="custom-h4 mt-3">Plate Marks</h4>
<hr class="custom-hr">
<div class="row">
<div class="col-auto">
<label label style="font-weight: 700; font-size: 15px;" class="form-label mt-2">Microdots:</label>
......@@ -407,24 +420,18 @@
</div>
<div class="modal fade" id="confirmation_modal" tabindex="-1" aria-labelledby="confirmation_modal_label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-content shadow-lg">
<div class="modal-header">
<h5 class="modal-title" id="confirmation_modal_label">Confirm</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="modal_body">
<div class="modal-body fs-6 fw-bold" id="modal_body">
Are you sure you want to delete this order?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id=btn_confirm_cancel>Cancel</button>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-secondary me-3" data-bs-dismiss="modal" id="btn_confirm_cancel">Cancel</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="btn_confirm_delete">Delete</button>
</div>
</div>
</div>
</div>
</div>
<style>
.modal-backdrop {
opacity: 0 !important;
}
</style>
object FViewOrders: TFViewOrders
Width = 676
Height = 480
Caption = 'main.errorpanel'
CSSLibrary = cssBootstrap
ElementFont = efCSS
Font.Charset = DEFAULT_CHARSET
......@@ -310,36 +309,6 @@ object FViewOrders: TFViewOrders
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object pnlMessage: TWebPanel
Left = 12
Top = 16
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 17
TabOrder = 8
object lblMessage: TWebLabel
Left = 16
Top = 11
Width = 42
Height = 13
Caption = 'Message'
ElementID = 'view.login.message.label'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object XDataWebClient1: TXDataWebClient
Connection = DMConnection.ApiConnection
Left = 28
......
<div class="container h-100 d-flex flex-column mt-0 py-0" style="max-width: 100%;">
<!-- Alert Section -->
<div class="row">
<div class=col-sm>
<div id="view.login.message" class="alert alert-danger">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
</div>
</div>
<!-- Actions Row -->
<div class="row mt-2 justify-content-center">
<div class="col-auto d-flex align-items-center">
......
......@@ -14,7 +14,7 @@ uses
WEBLib.JSON, Auth.Service, XData.Web.Client, WebLib.Storage,
ConnectionModule, App.Types, Vcl.StdCtrls, Vcl.Controls, WEBLib.DBCtrls,
XData.Web.JsonDataset, WEBLib.DB, Data.DB, XData.Web.Dataset, XData.Web.DatasetCommon,
WEBLib.Grids;
WEBLib.Grids, VCL.Forms;
type
TFViewOrders = class(TWebForm)
......@@ -56,15 +56,11 @@ type
wcbPageSize: TWebComboBox;
wlcbOrderBy: TWebLookupComboBox;
edtSearch: TWebEdit;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
xdwdsOrdersDBID: TStringField;
tmrReturn: TWebTimer;
procedure WebFormCreate(Sender: TObject);
procedure btnAddOrderClick(Sender: TObject);
procedure btnSearchClick(Sender: TObject);
procedure btnCloseNotificationClick(Sender: TObject);
procedure WebFormShow(Sender: TObject);
procedure btnPDFClick(Sender: TObject);
procedure wcbPageSizeChange(Sender: TObject);
......@@ -73,20 +69,20 @@ type
procedure wdbtcOrdersClickCell(Sender: TObject; ACol, ARow: Integer);
procedure WebButton1Click(Sender: TObject);
procedure tmrReturnTimer(Sender: TObject);
[async] procedure GenerateReportPDFAsync(APdfTab: TJSWindow);
private
FChildForm: TWebForm;
FPendingPdfTab: TJSWindow;
procedure ClearTable();
procedure GeneratePagination(TotalPages: Integer);
function GenerateSearchOptions(): string;
procedure orderEntry(orderInfo, customerInfo, mode, orderType: string);
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure ShowAddOrderForm();
procedure ShowSearchForm();
procedure ShowSetStatusForm();
[async] procedure GetOrders(searchOptions: string);
[async] procedure GenerateReportPDF;
[async] procedure SetStatus(statusInfo: string);
procedure HandlePDFConfirmation;
var
PageNumber: integer;
PageSize: integer;
......@@ -146,43 +142,128 @@ begin
end;
procedure TFViewOrders.btnPDFClick(Sender: TObject);
var
confirmBtn: TJSHTMLElement;
begin
if xdwdsOrders.RecordCount >= 100 then
begin
FPendingPdfTab := nil;
document.getElementById('modal_body').innerHTML :=
'You are about to generate a PDF for over 100 orders. This may take some time. Continue?';
document.getElementById('btn_confirm_cancel').innerText := 'Cancel';
document.getElementById('btn_confirm_delete').innerText := 'Yes';
confirmBtn := TJSHTMLElement(document.getElementById('btn_confirm_delete'));
confirmBtn.addEventListener('click',
TJSEventHandler(
procedure(Event: TJSEvent)
begin
asm bootstrap.Modal.getInstance(document.getElementById('confirmation_modal')).hide(); end;
HandlePDFConfirmation;
end
)
);
asm
var modal = document.getElementById('confirmation_modal');
if (modal && modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
var confirmationModal = new bootstrap.Modal(modal, { keyboard: false });
confirmationModal.show();
end;
end
else
begin
FPendingPdfTab := window.open('', '_blank');
if Assigned(FPendingPdfTab) then
FPendingPdfTab.document.write(
'<!DOCTYPE html>' +
'<html lang="en">' +
'<head>' +
'<meta charset="UTF-8">' +
'<meta name="viewport" content="width=device-width, initial-scale=1.0">' +
'<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">' +
'</head>' +
'<body class="d-flex flex-column justify-content-center align-items-center vh-100 bg-light">' +
'<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"></div>' +
'<div class="mt-3 fs-5 text-muted">Generating PDF, please wait�</div>' +
'</body>' +
'</html>'
);
Utils.ShowSpinner('spinner');
GenerateReportPDFAsync(FPendingPdfTab);
end;
end;
procedure TFViewOrders.HandlePDFConfirmation;
begin
// Open tab only now
FPendingPdfTab := window.open('', '_blank');
if Assigned(FPendingPdfTab) then
FPendingPdfTab.document.write(
'<!DOCTYPE html>' +
'<html lang="en">' +
'<head>' +
'<meta charset="UTF-8">' +
'<meta name="viewport" content="width=device-width, initial-scale=1.0">' +
'<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">' +
'</head>' +
'<body class="d-flex flex-column justify-content-center align-items-center vh-100 bg-light">' +
'<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"></div>' +
'<div class="mt-3 fs-5 text-muted">Generating PDF, please wait�</div>' +
'</body>' +
'</html>'
);
Utils.ShowSpinner('spinner');
GenerateReportPDF;
GenerateReportPDFAsync(FPendingPdfTab);
FPendingPdfTab := nil;
end;
[async] procedure TFViewOrders.GenerateReportPDF;
// sends the search to the server which then sends back a pdf of the results
[async] procedure TFViewOrders.GenerateReportPDFAsync(APdfTab: TJSWindow);
var
xdcResponse: TXDataClientResponse;
searchOptions, pdfURL: string;
jsObject: TJSObject;
begin
Utils.ShowSpinner('spinner');
try
searchOptions := edtSearch.Text;
searchOptions := edtSearch.Text + '&forPDF=true';
// Call the server method to generate the PDF
xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GenerateOrderListPDF', [searchOptions]));
jsObject := JS.TJSObject(xdcResponse.Result);
pdfURL := JS.toString(jsObject.Properties['value']);
xdcResponse := await(
XDataWebClient1.RawInvokeAsync('ILookupService.GenerateOrderListPDF',
[searchOptions]));
jsObject := TJSObject(xdcResponse.Result);
pdfURL := String(jsObject.Properties['value']);
// Open the PDF in a new browser tab
window.open(pdfURL, '_blank');
if Assigned(APdfTab) then
APdfTab.location.href := pdfURL;
except
on E: EXDataClientRequestException do
Utils.ShowErrorModal('Could not generate report PDF: ' + E.ErrorResult.ErrorMessage);
begin
Utils.ShowErrorModal('Could not generate report PDF: ' +
E.ErrorResult.ErrorMessage);
if Assigned(APdfTab) then
APdfTab.close; // close the blank tab on failure
end;
end;
Utils.HideSpinner('spinner');
end;
procedure TFViewOrders.WebButton1Click(Sender: TObject);
begin
if statusOrderID <> '' then
ShowSetStatusForm()
else
ShowNotification('Failure:Please select an order');
ShowToast('Failure: Please select an order');
end;
procedure TFViewOrders.WebFormCreate(Sender: TObject);
......@@ -265,9 +346,7 @@ end;
procedure TFViewOrders.WebFormShow(Sender: TObject);
begin
if info <> '' then
ShowNotification(info)
else
HideNotification();
ShowToast(info)
end;
......@@ -288,6 +367,7 @@ begin
newform.Caption := 'Select Customer and Order Type';
newForm.Popup := True;
newForm.position:= poScreenCenter;
newForm.Border := fbDialog;
// used to manage Back button handling to close subform
......@@ -320,6 +400,7 @@ begin
newform.Caption := 'Input Search Options';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.position:= poScreenCenter;
newForm.searchOptions := FViewMain.search;
// used to manage Back button handling to close subform
......@@ -370,6 +451,7 @@ begin
newform.Caption := 'Input Search Options';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.Position := poScreenCenter;
newForm.OrderID := statusOrderID;
newForm.JobName := wdbtcOrders.Cells[3, row];
if wdbtcOrders.Cells[14, row] <> '' then
......@@ -722,10 +804,6 @@ begin
FViewMain.ViewOrderEntryCuttingDie(orderInfo, customerInfo, mode, '');
end;
procedure TFViewOrders.btnCloseNotificationClick(Sender: TObject);
begin
HideNotification();
end;
procedure TFViewOrders.btnSearchClick(Sender: TObject);
var
......@@ -798,39 +876,5 @@ begin
end;
procedure TFViewOrders.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
info := '';
end;
procedure TFViewOrders.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
begin
if Notification <> '' then
begin
splitNotification := Notification.Split([':']);
if(splitNotification[0] = 'Success') then
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
end
else
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
end;
end;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
end;
end;
end.
......@@ -216,6 +216,7 @@ object FSelectCustomer: TFSelectCustomer
ChildOrder = 5
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnCancelClick
end
object btnConfirm: TWebButton
Left = 440
......
......@@ -47,6 +47,7 @@ type
procedure btnConfirmClick(Sender: TObject);
procedure TMSFNCGrid1CellClick(Sender: TObject; ACol, ARow: Integer);
procedure edtSearchChange(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
private
{ Private declarations }
[Async] procedure GetCustomers();
......@@ -84,6 +85,11 @@ begin
getCustomers();
end;
procedure TFSelectCustomer.btnCancelClick(Sender: TObject);
begin
Close();
end;
procedure TFSelectCustomer.btnConfirmClick(Sender: TObject);
begin
if edtID.Text = '' then
......
......@@ -5,7 +5,7 @@ interface
uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, Vcl.Controls, Vcl.StdCtrls, WEBLib.ExtCtrls,
WEBLib.StdCtrls;
WEBLib.StdCtrls, Utils;
type
TFSetStatus = class(TWebForm)
......@@ -41,8 +41,6 @@ type
procedure btnCancelClick(Sender: TObject);
private
{ Private declarations }
procedure HideNotification;
procedure ShowNotification(Notification: string);
public
{ Public declarations }
confirm: boolean;
......@@ -65,14 +63,15 @@ end;
procedure TFSetStatus.btnConfirmClick(Sender: TObject);
begin
if ( (dtpDate.Date = 0 ) or ( wlcbStatus.value = '' ) ) then
ShowNotification('Failure:Please fill in all information')
ShowToast('Failure: Please fill in all information')
else if ( ( OrderType = 'web plate' ) and ( wlcbStatus.Value = 'MOUNT' ) ) then
ShowNotification('Failure:Web Plate Orders do not have Mount Due/Done dates')
ShowToast('Failure: Web Plate Orders do not have Mount Due/Done dates')
else if ( ( OrderType = 'cutting die' ) and ( ( wlcbStatus.Value = 'MOUNT' ) or ( wlcbStatus.Value = 'ART' ) or (wlcbStatus.Value = 'PLATE') ) ) then
ShowNotification('Failure:Cutting Die Orders do not have Art/Plate/Mount Due or Done Dates')
ShowToast('Failure: Cutting Die Orders do not have Art/Plate/Mount Due or Done Dates')
else
begin
confirm := true;
ShowToast('Success: Status updated!');
Close;
end;
end;
......@@ -83,7 +82,6 @@ var
i: integer;
filteredItems: TJSArray;
begin
HideNotification();
edtOrderID.Text := OrderID;
dtpDate.Date := 0;
edtJobName.Text := JobName;
......@@ -138,17 +136,5 @@ begin
end;
end;
procedure TFSetStatus.HideNotification;
begin
//pnlMessage.ElementHandle.hidden := True;
end;
procedure TFSetStatus.ShowNotification(Notification: string);
begin
if Notification <> '' then
begin
edtNotification.Text := Notification;
end;
end;
end.
\ No newline at end of file
<div class="row">
<div class="col-lg-12">
<div class="container">
<!-- Profile form -->
<div class="row">
<div class=col-sm>
<div id="view.login.message" class="alert alert-danger">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
</div>
<div role="form">
<div class="form-group">
<label id="view.userprofile.form.lblUserID">User ID:</label>
<input id="view.userprofile.form.edtUserID" class="form-control">
</div>
<div class="form-group">
<label id="view.userprofile.form.lblUserName">Username:</label>
<input id="view.userprofile.form.edtUsername" class="form-control">
</div>
<div class="form-group">
<label id="view.userprofile.form.lblFullName">Full Name:</label>
<input id="view.userprofile.form.edtFullName" class="form-control">
</div>
<div class="form-group">
<label id="view.userprofile.form.lblPhone">Phone Number:</label>
<input id="view.userprofile.form.edtPhone" class="form-control">
<div class="col-lg-8 col-xl-6 mx-auto">
<form id="userprofileform" class="needs-validation" role="form" autocomplete="off" novalidate>
<div class="mb-3">
<label id="view.userprofile.form.lblUserID"
for="view.userprofile.form.edtUserID"
class="form-label">User&nbsp;ID</label>
<input id="view.userprofile.form.edtUserID"
class="form-control"
readonly>
</div>
<div class="form-group">
<label id="view.userprofile.form.lblEmail">Email Address:</label>
<input id="view.userprofile.form.edtEmail" class="form-control">
<div class="mb-3">
<label id="view.userprofile.form.lblUserName"
for="view.userprofile.form.edtUsername"
class="form-label">Username</label>
<input id="view.userprofile.form.edtUsername"
class="form-control"
required>
<div class="invalid-feedback">Username is required.</div>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="view.userprofile.form.chkAdminUser">
<label class="custom-control-label" for="view.userprofile.form.chkAdminUser">Admin User</label>
<div class="mb-3">
<label id="view.userprofile.form.lblFullName"
for="view.userprofile.form.edtFullName"
class="form-label">Full&nbsp;Name</label>
<input id="view.userprofile.form.edtFullName"
class="form-control"
required>
<div class="invalid-feedback">Full Name is required.</div>
</div>
<div class="form-group">
<button class="btn btn-primary" id="view.userprofile.form.btnconfirm">Confirm Changes</button>
<button class="btn btn-primary" id="view.userprofile.form.btncancel">Xancel Changes</button>
<div class="mb-3">
<label id="view.userprofile.form.lblEmail"
for="view.userprofile.form.edtEmail"
class="form-label">Email&nbsp;Address</label>
<input id="view.userprofile.form.edtEmail"
type="email"
class="form-control"
required>
<div class="invalid-feedback">Valid email is required.</div>
</div>
<div class="form-group">
<label id="view.userprofile.form.lblresult"></label>
<div class="form-check mb-4">
<input type="checkbox"
id="view.userprofile.form.chkAdminUser"
class="form-check-input">
<label for="view.userprofile.form.chkAdminUser"
class="form-check-label">
Admin&nbsp;User
</label>
</div>
<div class="d-flex gap-2 mb-4">
<button id="view.userprofile.form.btnconfirm"
class="btn btn-primary flex-grow-1"
type="button">
Confirm&nbsp;Changes
</button>
<button id="view.userprofile.form.btncancel"
class="btn btn-outline-secondary flex-grow-1"
type="button">
Cancel&nbsp;Changes
</button>
</div>
<label id="view.userprofile.form.lblresult" class="form-text"></label>
</form>
</div>
</div>
</div>
......@@ -6,7 +6,8 @@ uses
System.SysUtils, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
WEBLib.Forms, WEBLib.Dialogs, Vcl.Controls, Vcl.StdCtrls, WEBLib.StdCtrls,
XData.Web.Client, WEBLib.ExtCtrls, DB, XData.Web.JsonDataset,
XData.Web.Dataset, XData.Web.Connection, Vcl.Forms, ConnectionModule;
XData.Web.Dataset, XData.Web.Connection, Vcl.Forms, ConnectionModule,
WEBLib.Toast;
type
TFViewUserProfile = class(TWebForm)
......@@ -17,27 +18,18 @@ type
edtUserId: TWebEdit;
edtFullName: TWebEdit;
WebLabel4: TWebLabel;
edtPhone: TWebEdit;
WebLabel5: TWebLabel;
chkAdminUser: TWebCheckBox;
edtEmail: TWebEdit;
WebLabel6: TWebLabel;
btnConfirm: TWebButton;
lblResult: TWebLabel;
XDataWebClient1: TXDataWebClient;
WebButton1: TWebButton;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
btnCancel: TWebButton;
procedure WebFormShow(Sender: TObject);
procedure btnConfirmClick(Sender: TObject);
[async] procedure EditUser();
[async] procedure GetUser();
procedure WebButton1Click(Sender: TObject);
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure btnCloseNotificationClick(Sender: TObject);
function CheckInputs(): boolean;
procedure btnCancelClick(Sender: TObject);
end;
var
......@@ -47,57 +39,83 @@ implementation
uses
Auth.Service,
XData.Model.Classes;
XData.Model.Classes,
Utils,
View.Main;
{$R *.dfm}
procedure TFViewUserProfile.btnCloseNotificationClick(Sender: TObject);
begin
HideNotification;
end;
procedure TFViewUserProfile.btnConfirmClick(Sender: TObject);
var
resultString: string;
FormEl: TJSHTMLFormElement;
begin
FormEl := TJSHTMLFormElement(document.querySelector('form'));
if not FormEl.checkValidity then
begin
FormEl.classList.add('was-validated');
Exit;
end;
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
var modal = document.getElementById('confirmation_modal');
var btnCancel = document.getElementById('btn_confirm_cancel');
var btnConfirm = document.getElementById('btn_confirm_delete');
var modalBody = document.getElementById('modal_body');
var self = this;
if (modal && btnCancel && btnConfirm && modalBody) {
modalBody.innerText = 'Are you sure you want to save changes to your profile?';
btnCancel.innerText = 'Cancel';
btnConfirm.innerText = 'Save';
if (modal.parentNode !== document.body) {
document.body.appendChild(modal);
}
var bsModal = new bootstrap.Modal(modal, { keyboard: false });
bsModal.show();
btnConfirm.onclick = function () {
self.EditUser();
bsModal.hide();
};
}
end;
if CheckInputs() then
begin
EditUser();
end
end;
procedure TFViewUserProfile.EditUser();
[async] procedure TFViewUserProfile.EditUser;
var
xdcResponse: TXDataClientResponse;
responseString: TJSObject;
editOptions: string;
editOptions, resultMsg: string;
begin
if(checkInputs()) then
begin
console.log(edtFullName.Text);
try
editOptions := '&username=' + edtUsername.Text +
'&fullname=' + edtFullName.Text +
'&phonenumber=' + edtPhone.Text +
'&email=' + edtEmail.Text;
xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.EditUser',
[editOptions]));
xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.EditUser', [editOptions]));
responseString := TJSObject(xdcResponse.Result);
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
ShowNotification(string(responseString['value']));
resultMsg := string(responseString['value']);
Utils.ShowToast(resultMsg);
if resultMsg.ToLower.StartsWith('success:') then
FViewMain.ViewOrders('');
except
on E: EXDataClientRequestException do
Utils.ShowErrorModal('Error editing user: ' + E.ErrorResult.ErrorMessage);
on E: Exception do
Utils.ShowErrorModal('Unexpected error: ' + E.Message);
end;
end;
procedure TFViewUserProfile.WebButton1Click(Sender: TObject);
procedure TFViewUserProfile.btnCancelClick(Sender: TObject);
var
xdcResponse: TXDataClientResponse;
userList: TJSObject;
......@@ -105,21 +123,17 @@ var
user: TJSObject;
begin
GetUser();
showNotification('Failure:Changes discarded');
showToast('Failure: Changes discarded');
end;
procedure TFViewUserProfile.WebFormShow(Sender: TObject);
var
xdcResponse: TXDataClientResponse;
userList: TJSObject;
data: TJSArray;
user: TJSObject;
begin
HideNotification;
GetUser();
//edtJwt.Text := TJSJSON.stringify(AuthService.TokenPayload);
chkAdminUser.Checked := JS.toBoolean(AuthService.TokenPayload.Properties['user_admin']);
// View.UserProfile.WebFormShow
chkAdminUser.Checked := SameText(string(AuthService.TokenPayload.Properties['user_admin']), 'true');
end;
procedure TFViewUserProfile.GetUser;
......@@ -129,6 +143,7 @@ var
data: TJSArray;
user: TJSObject;
begin
try
xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetUsers',
[JS.toString(AuthService.TokenPayload.Properties['user_name'])]));
userList := TJSObject(xdcResponse.Result);
......@@ -136,132 +151,14 @@ begin
user := TJSObject(data[0]);
edtUsername.Text := string(user['username']);
edtFullName.Text := string(user['full_name']);
edtPhone.Text := string(user['phone_number']);
edtEmail.Text := string(user['email_address']);
edtUserId.Text := string(user['userID']);
chkAdminUser.Checked := boolean(user['admin']);
end;
procedure TFViewUserProfile.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFViewUserProfile.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
begin
if Notification <> '' then
begin
splitNotification := Notification.Split([':']);
if(splitNotification[0] = 'Success') then
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
end
else
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
end;
end;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
except
on E: EXDataClientRequestException do
Utils.ShowErrorModal('Could not retrieve users: ' + E.ErrorResult.ErrorMessage);
end;
end;
function TFViewUserProfile.CheckInputs(): boolean;
var
checkString: string;
charIndex: integer;
phoneNum: string;
begin
Result := false;
checkString := edtFullName.Text + edtUsername.Text + edtPhone.Text + edtEmail.Text;
if string(edtFullName.Text).IsEmpty then
begin
ShowNotification('Failure:Full Name field is blank!');
exit;
end;
if string(edtUsername.Text).IsEmpty then
begin
ShowNotification('Failure:Username field is blank!');
exit;
end;
if string(edtPhone.Text).IsEmpty then
begin
ShowNotification('Failure:Phone Number field is blank!');
exit;
end;
if string(edtEmail.Text).IsEmpty then
begin
ShowNotification('Failure:Email field is blank!');
exit;
end;
if checkString.Contains('&') then
begin
ShowNotification('Failure:No fields may contain "&&"!');
exit;
end;
if string(edtEmail.Text).Contains('@') = false then
begin
ShowNotification('Failure:Please enter a valid email address');
exit;
end;
if (length(string(edtEmail.Text).Split(['@'])) <> 2) or (string(edtEmail.text).CountChar('@') > 1) then
begin
ShowNotification('Failure:Please enter a valid email address');
exit;
end;
phoneNum := edtPhone.Text;
if (not phoneNum.Contains('(')) or (not phoneNum.Contains(')')) or (not phoneNum.Contains('-')) then
begin
ShowNotification('Failure:Please enter a valid phone number');
exit;
end;
if (phoneNum.CountChar('(') <> 1) or (phoneNum.CountChar(')') <> 1) or (phoneNum.CountChar('-') <> 1) or (phoneNum.CountChar(' ') > 1) then
begin
ShowNotification('Failure:Please enter a valid phone number');
exit;
end;
phoneNum := phoneNum.Replace('(', '');
phoneNum := phoneNum.Replace(')', '');
phoneNum := phoneNum.Replace('-', '');
phoneNum := phoneNum.Replace(' ', '');
console.log(phoneNum);
console.log(length(phoneNum));
if(length(phoneNum) <> 10) then
begin
ShowNotification('Failure:Please enter a valid phone number');
exit;
end;
for CharIndex := 1 to Length(phoneNum) do
begin
if not (phoneNum[CharIndex] in ['0' .. '9']) then
begin
console.log('here');
ShowNotification('Failure:Please enter a valid phone number');
exit;
end;
end;
result := true;
end;
end.
......@@ -45,36 +45,6 @@ object FViewUsers: TFViewUsers
WidthPercent = 100.000000000000000000
OnClick = btnConfirmDeleteClick
end
object pnlMessage: TWebPanel
Left = 12
Top = 16
Width = 121
Height = 33
ElementID = 'view.login.message'
ChildOrder = 17
TabOrder = 2
object lblMessage: TWebLabel
Left = 16
Top = 11
Width = 46
Height = 15
Caption = 'Message'
ElementID = 'view.login.message.label'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
end
object btnCloseNotification: TWebButton
Left = 96
Top = 3
Width = 22
Height = 25
ChildOrder = 1
ElementID = 'view.login.message.button'
HeightPercent = 100.000000000000000000
WidthPercent = 100.000000000000000000
OnClick = btnCloseNotificationClick
end
end
object XDataWebClient1: TXDataWebClient
Connection = DMConnection.ApiConnection
Left = 462
......
......@@ -5,10 +5,6 @@
<div class="col-12 col-md-8">
<div class="row">
<div class=col-sm>
<div id="view.login.message" class="alert alert-danger">
<button id="view.login.message.button" type="button" class="btn-close" aria-label="Close"></button>
<span id="view.login.message.label"></span>
</div>
</div>
</div>
</div>
......
......@@ -16,9 +16,6 @@ type
btnAddUser: TWebButton;
WebDataSource1: TWebDataSource;
btnConfirmDelete: TWebButton;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
XDataWebDataSet1userID: TStringField;
XDataWebDataSet1username: TStringField;
XDataWebDataSet1full_name: TStringField;
......@@ -34,7 +31,6 @@ type
//AField: TField; AValue: string; AElement: TJSHTMLElementRecord);
procedure btnConfirmDeleteClick(Sender: TObject);
procedure btnAddUserClick(Sender: TObject);
procedure btnCloseNotificationClick(Sender: TObject);
//procedure btnApplyClick(Sender: TObject);
//procedure btnSearchClick(Sender: TObject);
private
......@@ -46,8 +42,6 @@ type
[async] procedure DelUser(username: string);
[async] procedure EditUser(row: TJSHTMLElement);
[async] procedure GetUsers(searchOptions: string);
procedure HideNotification;
procedure ShowNotification(Notification: string);
procedure AddRowToTable(UserID, Username, Password, Full_Name, Status,
Email, AType, PID, QBID: string; Rights: integer);
//[async] procedure addUser();
......@@ -98,10 +92,7 @@ begin
PageSize := 10;
GetUsers('');
if Info <> '' then
ShowNotification(Info)
else
HideNotification();
ShowToast(Info)
end;
procedure TFViewUsers.DelUser(username: string);
......@@ -112,7 +103,7 @@ begin
xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.DelUser',
[username]));
responseString := TJSObject(xdcResponse.Result);
ShowNotification(string(responseString['value']));
ShowToast(string(responseString['value']));
getUsers('');
end;
......@@ -449,7 +440,7 @@ begin
Cell := TJSHTMLElement(document.createElement('td'));
Cell.setAttribute('data-label', 'Edit');
Button := TJSHTMLElement(document.createElement('a'));
Button.className := 'btn btn-primary';
Button.className := 'btn btn-sm btn-primary';
Button.innerHTML := '<i class="far fa-edit fa-fw"></i><span>Edit</span>';
Button.addEventListener('click', procedure(Event: TJSMouseEvent)
begin
......@@ -468,43 +459,6 @@ begin
FViewMain.EditUser('Add', '', '', '', '', '', '', '', '', '');
end;
procedure TFViewUsers.btnCloseNotificationClick(Sender: TObject);
begin
HideNotification;
end;
procedure TFViewUsers.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFViewUsers.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
begin
if Notification <> '' then
begin
splitNotification := Notification.Split([':']);
if(splitNotification[0] = 'Success') then
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-danger');
messageDiv.classList.add('alert-success');
end;
end
else
begin
asm
var messageDiv = document.getElementById('view.login.message');
messageDiv.classList.remove('alert-success');
messageDiv.classList.add('alert-danger');
end;
end;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
end;
end;
procedure TFViewUsers.btnConfirmDeleteClick(Sender: TObject);
begin
......
......@@ -367,6 +367,21 @@ is-invalid .form-check-input {
}
@keyframes slideInLeft {
from {
transform: translateX(-120%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.toast.slide-in {
animation: slideInLeft 0.4s ease-out forwards;
}
......
<html><head>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<noscript>Your browser does not support JavaScript!</noscript>
<link href="data:;base64,=" rel="icon"/>
<title>Web KG Orders</title>
<title>EM Systems webKGOrders App</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/2.3.1/css/flag-icon.min.css" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.0/css/all.min.css" rel="stylesheet"/>
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<script crossorigin="anonymous" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" src="https://code.jquery.com/jquery-3.7.1.js"></script>
<script src="$(ProjectName).js" type="text/javascript"></script>
<title>EM Systems webKGOrders App</title>
<link href="css/app.css" rel="stylesheet" type="text/css"/>
<link href="css/spinner.css" rel="stylesheet" type="text/css">
<link href="css/spinner.css" rel="stylesheet" type="text/css"/>
<script crossorigin="anonymous" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" src="https://code.jquery.com/jquery-3.7.1.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="$(ProjectName).js" type="text/javascript"></script>
</head>
<body>
</body>
<script type="text/javascript">rtl.run();</script>
</html>
......@@ -69,9 +69,13 @@
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.5.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.5.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>5</VerInfo_Release>
<AppDPIAwarenessMode>none</AppDPIAwarenessMode>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXSqliteDriver;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;DataSnapConnectors;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;DataSnapClient;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;emshosting;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
......@@ -90,13 +94,14 @@
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.2.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.2.0;Comments=;LastCompiledTime=2018/08/27 15:18:29</VerInfo_Keys>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.5.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.5.0;Comments=;LastCompiledTime=2018/08/27 15:18:29</VerInfo_Keys>
<AppDPIAwarenessMode>PerMonitor</AppDPIAwarenessMode>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<TMSWebSingleInstance>1</TMSWebSingleInstance>
<TMSUseJSDebugger>2</TMSUseJSDebugger>
<VerInfo_Release>2</VerInfo_Release>
<VerInfo_Release>5</VerInfo_Release>
<TMSWebBrowser>3</TMSWebBrowser>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
......@@ -107,11 +112,13 @@
<TMSWebDefines>RELEASE</TMSWebDefines>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<VerInfo_Build>8</VerInfo_Build>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.8;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;LastCompiledTime=2018/08/22 16:25:56</VerInfo_Keys>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.9.6.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.6.0;Comments=;LastCompiledTime=2018/08/22 16:25:56</VerInfo_Keys>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<AppDPIAwarenessMode>PerMonitor</AppDPIAwarenessMode>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>6</VerInfo_Release>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
......
......@@ -132,6 +132,7 @@ begin
JWT.Claims.SetClaimOfType<string>('user_email', userEmail);
JWT.Claims.SetClaimOfType<string>('user_qb_id', userQBID);
JWT.Claims.SetClaimOfType<string>('user_access_type', userAccessType);
JWT.Claims.SetClaimOfType<string>('user_admin', LowerCase(BoolToStr(SameText(userAccessType, 'ALL'), True)));
Result := TJOSE.SHA256CompactToken(serverConfig.jwtTokenSecret, JWT);
finally
......
......@@ -116,8 +116,8 @@
<DCC_UnitSearchPath>C:\RADTOOLS\FastMM4;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<VerInfo_MajorVer>0</VerInfo_MajorVer>
<VerInfo_MinorVer>9</VerInfo_MinorVer>
<VerInfo_Release>4</VerInfo_Release>
<VerInfo_Keys>CompanyName=EM Systems;FileDescription=$(MSBuildProjectName);FileVersion=0.9.4.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.4.0;Comments=</VerInfo_Keys>
<VerInfo_Release>6</VerInfo_Release>
<VerInfo_Keys>CompanyName=EM Systems;FileDescription=$(MSBuildProjectName);FileVersion=0.9.6.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=0.9.6.0;Comments=</VerInfo_Keys>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
......
[Settings]
MemoLogLevel=3
FileLogLevel=5
webClientVersion=0.9.4
LogFileNum=735
webClientVersion=0.9.6
LogFileNum=756
[Database]
Server=192.168.159.131
Server=192.168.159.151
--Server=192.168.102.130
--Server=192.168.75.133
Database=kg_order_entry
......@@ -17,6 +17,9 @@ Password=emsys01
CompanyID=9341454272655710
ClientID=ABgO14uvjh8XqLud7spQ8lkb98AUpcdA7HbyMJfCAtl65sQ5yy
ClientSecret=bQ06TRemHeAGFzVHRaTUvUoBU9jpU9itK6MOMgqN
RefreshToken=RT1-251-H0-1759499151mghzkhn74tjkqi2vg5c0
AccessToken=eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwieC5vcmciOiJIMCJ9..BPFIXN1xTjdWuZGjkh1jUQ.IghcYUEoPWx47KnmuIbgZBNm1EhInMZjAXUi68M-l6zZkuKnlQYmbYq6gC3gIyTd66cx85t7pMmdBAH_q-v3qkUKx2ZqVSRZyYVKSrxYWFl0Vafzbj_BY-4kjrGEqZRFtR4dfQfbFmmlDW215Vjn8MO9v3tvgAVbWO9kafJ3Frv4KtNRgJQPmC01nz4ixF5RD91EnCSo-q4DuuRtCERkjjIiEW9D8ODt1GexshbHxam7dWCDGM2yHX_V0trWi37X5jBBrWgTYRogXhTPfpvlfkCQKTrNmKWhVDuVUxJB3aPREI43IMlW6h3hf445quAjINvgK5wokDCnmVPW3XvIDvnckgAaa9qOLzpl5UktpjqDRRiI4zVNs6BXP7kCsZs9ez0Ai5oeWgj0_j0NKbuVW1exkLcrinmYrMny-s8XpADNDslW8XCmJnHPsOWqZZL5bEXFJXPcYfPkGkV7rt-ln84gRD9413Ji05cmOzO1X5ClhrRhFRwjT3dbrgh88Dro-vMNs3weRdYOVpYFvA5aDXs9xkmHx8auphCdZo5a3sB8n9iKiM618HR-mSeYwCIU3aF2xE8kx0ljH8qVgX1bI2w9ByfM-mNBkasu3uKDH3HcpfqJBKWNOkG692JjzBoy.6H4UaInosVyqlMSCqGMAaA
LastRefresh=6/24/2025 10:51:36 AM
RefreshToken=RT1-251-H0-1759499151mghzkhn74tjkqi2vg5c0
AccessToken=eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwieC5vcmciOiJIMCJ9..swWerhSONJsQ3kK2n0Z6Mw.hKhH99-B-e1no4mO69AheB1JQi9AVo_2uT_e9Urpto2s_JM_hGuytHiCYkSAt6f8KVoej5YXyB2JRjteqO0FbxLa6UwEx2zYfgKV2bdVDlHWjU1f3nVtJw7RNXc3kOUL8xHDo7a-wAdAl7u3f7HWHxyptZac49L4iZCQ-wTVKHGATp6GIhmS8Al4ICPDV0BGLOLVsc69xIi2vqJwQgfazilPfJAB_9p3hHlpv0xafuAUNpBUATTDSVO8C65cuPQ_pGNZIR4MPjTZIH0vgmOruFsyOynqO1JyZd_bqOCGhO0bS0pfDdoLai1XERlnQsb_2UXE2arFvEqygEq1oqSglj0vW_uy8F6XWoR1mmwr68MXMRE_IbauNV4LuXnYBm_qh2vztX6fk7r-Cja51508Z-YjjBi4uwEpnKf7dBBNpI6J-z7bfKffuVRdVBxuQo1ZUePwz6Df41nkjPqv1cw3NLp4IyyCToqX_wzGhnkx19zzMbjkK5ZaHRxpsms29qpHxpikR8QOtXni0o2DBK9xNGhRuCRTPxuEDZzaf26_c258rz0bd2xFl0IfMsfid9iki8O_u6KLfDcQJPPR50UI150HqvNlzPZQuYBRKzXDnwv7h75igYH0NH2rwellgU_k.Y_Nxh6SpCFATsEzsAUs26g
......
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