Commit 9546b45b by Mac Stephens

added showtoast, replacing shownotification on all but login, updated users to…

added showtoast, replacing shownotification on all but login, updated users to work correctly and populate correct, lots of other changes, fixed pdf popup block situation
parent 94cbacc0
......@@ -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,11 +260,6 @@ 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
......@@ -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;
if mode = 'ADD' then
EditMode()
......@@ -672,43 +668,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;
......
......@@ -13,6 +13,7 @@ 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;
......@@ -155,6 +156,64 @@ 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');
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');
}
var toast = new bootstrap.Toast(toastEl, { delay: 2500 });
toast.show();
end;
end;
procedure ApplyReportTitle(CurrentReportType: string);
var
CrimeTitleElement: TJSHTMLElement;
......
<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)
......@@ -42,7 +42,6 @@ type
[async] procedure GetCustomers(searchOptions: string);
function GenerateSearchOptions(): string;
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure ShowSelectCustomerForm();
var
......@@ -75,6 +74,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 +173,6 @@ begin
end;
procedure TFViewCustomers.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 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="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>
</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 class="container">
<!-- Edit-User form -->
<div class="row">
<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>
</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;
if string(edtUsername.Text).IsEmpty then
begin
ShowNotification('Username field is blank!');
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;
FormEl := TJSHTMLFormElement(document.getElementById('edituserform'));
if string(edtPhoneNumber.Text).IsEmpty then
if not FormEl.checkValidity then
begin
ShowNotification('Phone Number field is blank!');
exit;
FormEl.classList.add('was-validated');
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
begin
if not (phoneNum[CharIndex] in ['0' .. '9']) then
// Live match check
if Confirm = '' then
begin
ConfirmInput.setCustomValidity('');
ConfirmInput.classList.remove('is-invalid');
ConfirmInput.classList.remove('is-valid');
end
else if Confirm = Pwd then
begin
ConfirmInput.setCustomValidity('');
ConfirmInput.classList.add('is-valid');
ConfirmInput.classList.remove('is-invalid');
end
else
begin
console.log('here');
ShowNotification('Please enter a valid phone number');
exit;
ConfirmInput.setCustomValidity('Passwords must match');
ConfirmInput.classList.add('is-invalid');
ConfirmInput.classList.remove('is-valid');
end;
end;
if edtPassword.Text <> edtConfirmPassword.Text then
begin
ShowNotification('Passwords must match!');
exit;
end;
if (length(edtPassword.Text) > 20) or (length(edtPassword.Text) < 6) then
begin
ShowNotification('Passwords must be between 6-20 characters!');
exit;
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,23 @@
</div>
</div>
</nav>
<!-- Toast wrapper directly under navbar -->
<div id="toast-wrapper"
class="position-fixed start-50 translate-middle-x mt-2"
style="z-index: 1080; top: 60px; 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 +102,28 @@
</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>
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1100">
</div>
......
......@@ -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);
......@@ -199,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
......
<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>
......
......@@ -9,13 +9,10 @@ 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;
Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, VCL.Forms;
type
TFOrderEntryCorrugated = class(TWebForm)
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
dtpOrderDate: TWebDateTimePicker;
dtpProofDate: TWebDateTimePicker;
dtpShipDate: TWebDateTimePicker;
......@@ -204,8 +201,6 @@ type
btnAdd: TWebButton;
WebButton2: TWebButton;
procedure WebFormCreate(Sender: TObject);
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure WebFormShow(Sender: TObject);
[async] procedure getOrder(Order_ID: string);
[async] procedure getCustomer(customerID: string);
......@@ -221,7 +216,6 @@ type
procedure btnCopyClick(Sender: TObject);
procedure sendOrderToServer();
procedure btnCloseClick(Sender: TObject);
procedure btnCloseNotificationClick(Sender: TObject);
procedure btnDeleteClick(Sender: TObject);
procedure btn_confirm_deleteClick(Sender: TObject);
procedure tmrReturnTimer(Sender: TObject);
......@@ -486,7 +480,7 @@ begin
dtpApprovedDate.Date := 0;
edtOrderNum.Text := '';
EditMode();
ShowNotification('Success: Order Successfully Copied');
ShowToast('Success: Order Successfully Copied');
window.scrollTo(0, 0);
end;
......@@ -520,7 +514,7 @@ begin
if mode = 'EDIT' then
GenerateReportPDF
else
showNotification('Failure: Cannot Generate PDF when Adding an Order');
ShowToast('Failure: Cannot Generate PDF when Adding an Order');
end;
procedure TFOrderEntryCorrugated.btn_confirm_deleteClick(Sender: TObject);
......@@ -592,7 +586,7 @@ begin
edtOrderNum.Text := OrderID;
mode := 'EDIT';
console.log(jsObj);
ShowNotification(string(jsObj.Properties['status']));
ShowToast(string(jsObj.Properties['status']));
end;
procedure TFOrderEntryCorrugated.DelOrder();
......@@ -722,7 +716,7 @@ begin
[AddressJSON.ToString]));
notification := TJSObject(Response.Result);
ShowNotification(string(notification['status']));
ShowToast(string(notification['status']));
xdwdsShipTo.Close;
xdwdsShipTo.SetJSONData(notification['ADDRESS']);
xdwdsShipTo.Open;
......@@ -739,6 +733,7 @@ begin
newform.Caption := 'Input Shipping Information';
newForm.Popup := True;
newForm.Position := poScreenCenter;
newForm.Border := fbDialog;
// used to manage Back button handling to close subform
......@@ -784,6 +779,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
......@@ -840,10 +836,6 @@ begin
FViewMain.ViewOrders('');
end;
procedure TFOrderEntryCorrugated.btnCloseNotificationClick(Sender: TObject);
begin
hideNotification();
end;
procedure TFOrderEntryCorrugated.WebFormCreate(Sender: TObject);
begin
......@@ -1062,13 +1054,9 @@ begin
EditMode();
end;
edtOrderNum.Text := OrderID;
if notification = '' then
begin
HideNotification;
end
else
if notification <> '' then
begin
ShowNotification(notification);
ShowToast(notification);
end;
end;
......@@ -1087,41 +1075,6 @@ begin
EditMode();
end;
procedure TFOrderEntryCorrugated.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFOrderEntryCorrugated.ShowNotification(Notification: string);
var
splitNotification: TArray<string>;
begin
console.log(notification);
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;
console.log(splitNotification[1]) ;
lblMessage.Caption := splitNotification[1];
pnlMessage.ElementHandle.hidden := False;
end;
end;
procedure TFOrderEntryCorrugated.tmrReturnTimer(Sender: TObject);
begin
......
......@@ -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
......
<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>
......
......@@ -7,7 +7,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;
Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, VCL.Forms;
type
TFOrderEntryCuttingDie = class(TWebForm)
......@@ -52,9 +52,6 @@ type
edtSpecialInstructions: TWebDBEdit;
btnSave: TWebButton;
btnCancel: TWebButton;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
edtCompanyName: TWebDBEdit;
XDataWebDataSet1NAME: TStringField;
XDataWebDataSet1staff_fields_quickbooks_item: TStringField;
......@@ -76,9 +73,7 @@ type
WebButton2: TWebButton;
procedure btnSaveClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure WebFormCreate(Sender: TObject);
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure WebFormCreate(Sender: TObject);
procedure WebFormShow(Sender: TObject);
[async] procedure GetCuttingDieOrder(Order_ID: string);
[async] procedure GetCustomer(customerID: string);
......@@ -141,7 +136,7 @@ begin
[AddressJSON.ToString]));
notification := TJSObject(Response.Result);
ShowNotification(string(notification['status']));
ShowToast(string(notification['status']));
xdwdsShipTo.Close;
xdwdsShipTo.SetJSONData(notification['ADDRESS']);
xdwdsShipTo.Open;
......@@ -159,6 +154,7 @@ begin
newform.Caption := 'Shipping Information';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.Position := poScreenCenter;
// used to manage Back button handling to close subform
window.location.hash := 'subform';
......@@ -296,9 +292,9 @@ begin
orderJSON.AddPair('ORDER_ID', orderID);
if mode = 'ADD' then
ShowNotification('Success:Order Added Successfully!')
ShowToast('Success: Order Added Successfully!')
else
ShowNotification('Success:Order Edited Successfully');
ShowToast('Success: Order Edited Successfully');
AddCuttingDieOrder(orderJSON);
......@@ -321,7 +317,7 @@ begin
dtpOrderDate.Date := 0;
dtpProofDate.Date := 0;
edtOrderNum.Text := '';
ShowNotification('Success:Order Successfully Copied');
ShowToast('Success: Order Successfully Copied');
EditMode();
window.scrollTo(0, 0);
end;
......@@ -370,7 +366,7 @@ begin
FViewMain.change := false;
if OrderID <> '' then
begin
FViewMain.ViewOrderEntryCuttingDie(OrderID, '', 'EDIT', 'Failure:Changes Discarded');
FViewMain.ViewOrderEntryCuttingDie(OrderID, '', 'EDIT', 'Failure: Changes Discarded');
end
else
FViewMain.ViewOrders('');
......@@ -450,7 +446,6 @@ begin
begin
with TFOrderEntryCuttingDie(AForm) do
begin
HideNotification;
TFOrderEntryCuttingDie(AForm).customerID := customerInfo;
TFOrderEntryCuttingDie(AForm).orderID := orderInfo;
TFOrderEntryCuttingDie(AForm).mode := localMode;
......@@ -470,6 +465,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';
......@@ -637,46 +633,9 @@ begin
EditMode();
end;
edtOrderNum.Text := OrderID;
if notification = '' then
if notification <> '' then
begin
HideNotification;
end
else
begin
ShowNotification(notification);
end;
end;
procedure TFOrderEntryCuttingDie.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFOrderEntryCuttingDie.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;
ShowToast(notification);
end;
end;
......
......@@ -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
......
<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>
......
......@@ -7,14 +7,11 @@ 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;
Data.DB, XData.Web.JsonDataset, XData.Web.Dataset, WEBLib.DB, VCL.Forms;
type
TFOrderEntryWeb = class(TWebForm)
WebLabel2: TWebLabel;
pnlMessage: TWebPanel;
lblMessage: TWebLabel;
btnCloseNotification: TWebButton;
edtCompanyName: TWebDBEdit;
edtCompanyAccountName: TWebDBEdit;
edtInQuickBooks: TWebDBEdit;
......@@ -208,8 +205,6 @@ type
btnAdd: TWebButton;
WebButton2: TWebButton;
procedure WebFormCreate(Sender: TObject);
procedure HideNotification();
procedure ShowNotification(Notification: string);
procedure WebFormShow(Sender: TObject);
[async] procedure getOrder(Order_ID: string);
[async] procedure getCustomer(customerID: string);
......@@ -226,7 +221,6 @@ type
procedure btnCloseClick(Sender: TObject);
procedure btnDeleteClick(Sender: TObject);
[async] procedure DelOrder;
procedure btnCloseNotificationClick(Sender: TObject);
procedure tmrReturnTimer(Sender: TObject);
procedure btn_confirm_deleteClick(Sender: TObject);
function VerifyOrder(): boolean;
......@@ -277,7 +271,7 @@ begin
[AddressJSON.ToString]));
notification := TJSObject(Response.Result);
ShowNotification(string(notification['status']));
ShowToast(string(notification['status']));
xdwdsShipTo.Close;
xdwdsShipTo.SetJSONData(notification['ADDRESS']);
xdwdsShipTo.Open;
......@@ -295,6 +289,7 @@ begin
newform.Caption := 'Input Shipping Information';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.Position := poScreenCenter;
// used to manage Back button handling to close subform
window.location.hash := 'subform';
......@@ -413,7 +408,7 @@ begin
dtpDigitalColorDate.Date := 0;
edtOrderNum.Text := '';
EditMode();
ShowNotification('Success:Order Successfully Copied');
ShowToast('Success: Order Successfully Copied');
window.scrollTo(0, 0);
end;
......@@ -555,7 +550,7 @@ begin
else
info := 'Success:Order Successfully Added';
AddWebOrder(orderJSON);
ShowNotification(info);
ShowToast(info);
end;
procedure TFOrderEntryWeb.btnPDFClick(Sender: TObject);
......@@ -648,7 +643,6 @@ begin
begin
with TFOrderEntryWeb(AForm) do
begin
HideNotification;
TFOrderEntryWeb(AForm).customerID := customerInfo;
TFOrderEntryWeb(AForm).orderID := orderInfo;
TFOrderEntryWeb(AForm).mode := localMode;
......@@ -747,6 +741,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';
......@@ -801,10 +796,6 @@ begin
FViewMain.ViewOrders('');
end;
procedure TFOrderEntryWeb.btnCloseNotificationClick(Sender: TObject);
begin
hideNotification();
end;
procedure TFOrderEntryWeb.WebFormCreate(Sender: TObject);
begin
......@@ -992,13 +983,9 @@ begin
EditMode();
end;
edtOrderNum.Text := OrderID;
if notification = '' then
begin
HideNotification;
end
else
if notification <> '' then
begin
ShowNotification(notification);
ShowToast(notification);
end;
end;
......@@ -1007,39 +994,6 @@ begin
EditMode();
end;
procedure TFOrderEntryWeb.HideNotification;
begin
pnlMessage.ElementHandle.hidden := True;
end;
procedure TFOrderEntryWeb.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 TFOrderEntryWeb.tmrReturnTimer(Sender: TObject);
begin
......
......@@ -309,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,19 +69,17 @@ type
procedure wdbtcOrdersClickCell(Sender: TObject; ACol, ARow: Integer);
procedure WebButton1Click(Sender: TObject);
procedure tmrReturnTimer(Sender: TObject);
[async] procedure GenerateReportPDFAsync(APdfTab: TJSWindow);
private
FChildForm: TWebForm;
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);
var
PageNumber: integer;
......@@ -144,43 +138,57 @@ begin
end;
procedure TFViewOrders.btnPDFClick(Sender: TObject);
var
pdfTab: TJSWindow; // handle for the new tab
begin
pdfTab := window.open('', '_blank');
if Assigned(pdfTab) then
pdfTab.document.write('<html><body style="font-family:Arial;padding:2rem;">'
+'Generating PDF</body></html>');
Utils.ShowSpinner('spinner');
GenerateReportPDF;
GenerateReportPDFAsync(pdfTab); // pass the handle along
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;
// 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 OrderID <> '' then
ShowSetStatusForm()
else
ShowNotification('Failure:Please select an order');
ShowToast('Failure: Please select an order');
end;
procedure TFViewOrders.WebFormCreate(Sender: TObject);
......@@ -263,9 +271,7 @@ end;
procedure TFViewOrders.WebFormShow(Sender: TObject);
begin
if info <> '' then
ShowNotification(info)
else
HideNotification();
ShowToast(info)
end;
......@@ -286,6 +292,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
......@@ -318,6 +325,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
......@@ -368,6 +376,7 @@ begin
newform.Caption := 'Input Search Options';
newForm.Popup := True;
newForm.Border := fbDialog;
newForm.Position := poScreenCenter;
newForm.OrderID := OrderID;
newForm.JobName := wdbtcOrders.Cells[3, row];
if wdbtcOrders.Cells[14, row] <> '' then
......@@ -720,10 +729,6 @@ begin
FViewMain.ViewOrderEntryCuttingDie(orderInfo, customerInfo, mode, '');
end;
procedure TFViewOrders.btnCloseNotificationClick(Sender: TObject);
begin
HideNotification();
end;
procedure TFViewOrders.btnSearchClick(Sender: TObject);
var
......@@ -796,39 +801,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();
......@@ -81,6 +82,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,11 +63,11 @@ 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;
......@@ -83,7 +81,6 @@ var
i: integer;
filteredItems: TJSArray;
begin
HideNotification();
edtOrderID.Text := OrderID;
dtpDate.Date := 0;
edtJobName.Text := JobName;
......@@ -137,17 +134,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="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 class="container">
<!-- Profile form -->
<div class="row">
<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="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="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="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-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 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>
<div class="form-group">
<label id="view.userprofile.form.lblEmail">Email Address:</label>
<input id="view.userprofile.form.edtEmail" class="form-control">
</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>
<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>
<div class="form-group">
<label id="view.userprofile.form.lblresult"></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>
......@@ -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
......
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<noscript>Your browser does not support JavaScript!</noscript>
<link href="data:;base64,=" rel="icon"/>
......@@ -11,22 +11,22 @@
<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"/>
<link href="css/app.css" rel="stylesheet" type="text/css"/>
<link href="css/spinner.css" rel="stylesheet" type="text/css"/>
<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="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>
<script type="text/javascript">rtl.run();</script>
</html>
......@@ -5,7 +5,7 @@
<FrameworkType>VCL</FrameworkType>
<MainSource>webKGOrders.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Release</Config>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
......
......@@ -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
......
......@@ -132,6 +132,7 @@ begin
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result);
end;
function TLookupService.GetCustomers: TCustomerList;
// Retrieves a list of customers and sends it to the client in object form.
// The object contains the ID, Name, Short Name, and the shipping address.
......@@ -1426,22 +1427,32 @@ begin
end;
function TLookupService.GetUsers(searchOptions: string): TUserList;
// Gets a list of all users for the user edit page.
// searchOptions: username of a specific user otherwise empty.
// TODO: change SQL to hide passwords instead of storing them in plain text.
// Returns all users, or one specific user when searchOptions <> ''.
// Uses parameterised SQL and the real column name USER_NAME.
var
SQL: string;
user: TUserItem;
begin
try
// Prepare and open the query
ordersDB.UniQuery1.Close;
if searchOptions = '' then
SQL := 'select * from users order by NAME ASC'
begin
ordersDB.UniQuery1.SQL.Text :=
'SELECT * FROM users ORDER BY NAME ASC';
end
else
SQL := 'select * from users where username=' + quotedStr(searchOptions);
doQuery(ordersDB.UniQuery1, SQL);
begin
ordersDB.UniQuery1.SQL.Text :=
'SELECT * FROM users WHERE USER_NAME = :uname';
ordersDB.UniQuery1.ParamByName('uname').AsString := searchOptions;
end;
ordersDB.UniQuery1.Open;
Result := TUserList.Create;
Result.data := TList<TUserItem>.Create;
// Build result list
Result := TUserList.Create;
Result.data := TList<TUserItem>.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(Result.data);
while not ordersDB.UniQuery1.Eof do
......@@ -1449,32 +1460,42 @@ begin
user := TUserItem.Create;
TXDataOperationContext.Current.Handler.ManagedObjects.Add(user);
Result.data.Add(user);
user.userID := ordersDB.UniQuery1.FieldByName('USER_ID').AsString;
user.username := ordersDB.UniQuery1.FieldByName('USER_NAME').AsString;
user.password := ordersDB.UniQuery1.FieldByName('PASSWORD').AsString;
user.full_name := ordersDB.UniQuery1.FieldByName('NAME').AsString;
user.status := ordersDB.UniQuery1.FieldByName('STATUS').AsString;
user.userID := ordersDB.UniQuery1.FieldByName('USER_ID').AsString;
user.username := ordersDB.UniQuery1.FieldByName('USER_NAME').AsString;
user.password := ordersDB.UniQuery1.FieldByName('PASSWORD').AsString;
user.full_name := ordersDB.UniQuery1.FieldByName('NAME').AsString;
user.status := ordersDB.UniQuery1.FieldByName('STATUS').AsString;
user.email_address := ordersDB.UniQuery1.FieldByName('EMAIL').AsString;
user.AType := ordersDB.UniQuery1.FieldByName('ACCESS_TYPE').AsString;
user.rights := ordersDB.UniQuery1.FieldByName('SYSTEM_RIGHTS').AsInteger;
user.AType := ordersDB.UniQuery1.FieldByName('ACCESS_TYPE').AsString;
user.rights := ordersDB.UniQuery1.FieldByName('SYSTEM_RIGHTS').AsInteger;
user.perspectiveID := ordersDB.UniQuery1.FieldByName('PERSPECTIVE_ID').AsString;
user.QBID := ordersDB.UniQuery1.FieldByName('QB_ID').AsString;
user.QBID := ordersDB.UniQuery1.FieldByName('QB_ID').AsString;
ordersDB.UniQuery1.Next;
end;
ordersDB.UniQuery1.Close;
SQL := 'select count(*) as total_count from users';
doQuery(ordersDB.UniQuery1, SQL);
// Get total-row count (keeps old behaviour)
ordersDB.UniQuery1.SQL.Text :=
'SELECT COUNT(*) AS total_count FROM users';
ordersDB.UniQuery1.Open;
Result.count := ordersDB.UniQuery1.FieldByName('total_count').AsInteger;
ordersDB.UniQuery1.Close;
except
on E: Exception do
begin
raise EXDataHttpException.Create(500, 'Unable to retrieve users: ' + E.Message);
ordersDB.UniQuery1.Close;
raise EXDataHttpException.Create(
500,
'Unable to retrieve users: ' + E.Message
);
end;
end;
end;
function TLookupService.EditUser(const editOptions: string): string;
// Edits the user.
// editOptions: all user information that will be changed.
......@@ -1703,7 +1724,6 @@ begin
end;
function TLookupService.AddStatusSchedule(StatusType: string; order: TJSONObject; ORDER_ID: integer): string;
// Adds/edits orders_status_schedule table.
// StatusType: name of the status getting added to the schedule.
......@@ -1893,9 +1913,9 @@ begin
end;
function TLookupService.AddUser(userInfo: string): string;
// Adds a user to the database
// userInfo - user information being added
var
user: string;
password: string;
......@@ -1908,53 +1928,54 @@ var
QB: string;
SQL: string;
dateCreated: TDateTime;
hashString: string;
hashPW: string;
rightsInt: Integer;
params: TStringList;
begin
try
params := TStringList.Create;
params.StrictDelimiter := true;
// parse the searchOptions
params.StrictDelimiter := True;
params.Delimiter := '&';
params.DelimitedText := userInfo;
dateCreated := now;
user := params.Values['username'];
password := params.Values['password'];
full_name := params.Values['fullname'];
status := params.Values['status'];
email := params.Values['email'];
access := params.Values['access'];
rights := params.Values['rights'];
dateCreated := Now;
user := params.Values['username'];
password := params.Values['password'];
full_name := params.Values['fullname'];
status := params.Values['status'];
email := params.Values['email'];
access := params.Values['access'];
rights := params.Values['rights'];
perspective := params.Values['perspective'];
QB := params.Values['QB'];
//newUser := params.Values['newuser'];
//hashString := DateTimeToStr(dateCreated) + params.Values['password'];
//hashPW := THashSHA2.GetHashString(hashString, THashSHA2.TSHA2Version.SHA512).ToUpper;
SQL := 'select * from users where USER_NAME = ' + QuotedStr(params.Values['username'].toLower);
QB := params.Values['QB'];
SQL := 'SELECT * FROM users WHERE USER_NAME = ' + QuotedStr(user.ToLower);
ordersDB.UniQuery1.Close;
ordersDB.UniQuery1.SQL.Text := SQL;
ordersDB.UniQuery1.Open;
if ordersDB.UniQuery1.IsEmpty then
begin
ordersDB.UniQuery1.Insert;
ordersDB.UniQuery1.FieldByName('USER_NAME').AsString := user;
ordersDB.UniQuery1.FieldByName('PASSWORD').AsString := password;
//THashSHA2.GetHashString(hashString, THashSHA2.TSHA2Version.SHA512).ToUpper;
//ordersDB.UniQuery1.FieldByName('date_created').AsString := DateTimeToStr(dateCreated);
ordersDB.UniQuery1.FieldByName('NAME').AsString := full_name;
ordersDB.UniQuery1.FieldByName('PASSWORD').AsString := password;
ordersDB.UniQuery1.FieldByName('NAME').AsString := full_name;
if( StrToBool(status) ) then
if StrToBoolDef(status, False) then
ordersDB.UniQuery1.FieldByName('STATUS').AsString := 'ACTIVE'
else
ordersDB.UniQuery1.FieldByName('STATUS').AsString := 'INACTIVE';
ordersDB.UniQuery1.FieldByName('EMAIL').AsString := email;
ordersDB.UniQuery1.FieldByName('ACCESS_TYPE').AsString := Access;
ordersDB.UniQuery1.FieldByName('SYSTEM_RIGHTS').AsInteger := StrToInt(rights);
ordersDB.UniQuery1.FieldByName('EMAIL').AsString := email;
ordersDB.UniQuery1.FieldByName('ACCESS_TYPE').AsString := access;
if not TryStrToInt(rights, rightsInt) then
rightsInt := 0;
ordersDB.UniQuery1.FieldByName('SYSTEM_RIGHTS').AsInteger := rightsInt;
ordersDB.UniQuery1.FieldByName('PERSPECTIVE_ID').AsString := perspective;
ordersDB.UniQuery1.FieldByName('QB_ID').AsString := QB;
ordersDB.UniQuery1.FieldByName('QB_ID').AsString := QB;
ordersDB.UniQuery1.Post;
Result := 'Success: User successfully added';
......@@ -1967,6 +1988,8 @@ begin
end;
end;
function TLookupService.AddItem(itemInfo: string): TJSONObject;
// Adds an item to the database
// itemInfo: item info to add to database
......@@ -2424,6 +2447,7 @@ begin
ordersDB.UniQuery1.Post;
end;
function TLookupService.getQBCustomers: TJSONArray;
var
iniFile: TIniFile;
......@@ -2563,6 +2587,7 @@ begin
end;
end;
function TLookupService.GetQBItems: TJSONArray;
var
restClient: TRESTClient;
......@@ -2749,6 +2774,7 @@ begin
end;
end;
procedure TLookupService.SaveTokens(AccessToken, RefreshToken: string);
var
f: TStringList;
......
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