// Add Customer page for KGOrders. Handles Adding and Editting Customers and
// Their shipping addresses.
unit AddCustomer;

interface

uses
  System.SysUtils, System.Generics.Collections, System.Classes, JS, Web, WEBLib.Graphics, WEBLib.Controls,
  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, VCL.Forms;

type
  TFViewAddCustomer = class(TWebForm)
    dtpStartDate: TWebDateTimePicker;
    dtpEndDate: TWebDateTimePicker;
    edtShortName: TWebDBEdit;
    edtName: TWebDBEdit;
    edtBillAddress: TWebDBEdit;
    edtBillCity: TWebDBEdit;
    edtBillState: TWebDBEdit;
    edtBillZip: TWebDBEdit;
    edtBillContact: TWebDBEdit;
    edtPhone: TWebDBEdit;
    edtFax: TWebDBEdit;
    btnSave: TWebButton;
    btnCancel: TWebButton;
    btnDelete: TWebButton;
    btnClose: TWebButton;
    btnEdit: TWebButton;
    XDataWebClient1: TXDataWebClient;
    WebDataSource1: TWebDataSource;
    XDataWebDataSet1: TXDataWebDataSet;
    XDataWebDataSet1SHORT_NAME: TStringField;
    XDataWebDataSet1NAME: TStringField;
    XDataWebDataSet1BILL_ADDRESS: TStringField;
    XDataWebDataSet1BILL_CITY: TStringField;
    edtCustomerID: TWebDBEdit;
    edtQBID: TWebDBEdit;
    wdbtcAddresses: TWebDBTableControl;
    wdsShipTo: TWebDataSource;
    xdwdsShipTo: TXDataWebDataSet;
    XDataWebDataSet1BILL_STATE: TStringField;
    XDataWebDataSet1BILL_CONTACT: TStringField;
    XDataWebDataSet1BILL_ZIP: TStringField;
    XDataWebDataSet1START_DATE: TStringField;
    XDataWebDataSet1END_DATE: TStringField;
    XDataWebDataSet1QB_LIST_ID: TStringField;
    XDataWebDataSet1FAX: TStringField;
    XDataWebDataSet1PHONE: TStringField;
    XDataWebDataSet1CUSTOMER_ID: TIntegerField;
    edtShippingAddress: TWebEdit;
    edtShippingState: TWebEdit;
    edtShippingContact: TWebEdit;
    edtShippingZip: TWebEdit;
    edtShippingCity: TWebEdit;
    xdwdsShipToADDRESS: TStringField;
    xdwdsShipToship_id: TStringField;
    xdwdsShipToshipping_address: TStringField;
    xdwdsShipTocity: TStringField;
    xdwdsShipTostate: TStringField;
    xdwdsShipTozip: TStringField;
    xdwdsShipTocontact: TStringField;
    memoShipBlock: TWebMemo;
    memoAddressBlock: TWebMemo;
    btnAdd: TWebButton;
    btnShipSave: TWebButton;
    btnShipCancel: TWebButton;
    btnShipDelete: TWebButton;
    btnShipEdit: TWebButton;
    btnShipAdd: TWebButton;
    btn_confirm_delete: TWebButton;
    tmrReturn: TWebTimer;
    edtFirstLine: TWebEdit;
    wdsUsers: TWebDataSource;
    xdwdsUsers: TXDataWebDataSet;
    wdblcbRep: TWebDBLookupComboBox;
    xdwdsUsersuserID: TStringField;
    XDataWebDataSet1REP_USER_ID: TStringField;
    xdwdsUsersfull_name: TStringField;
    procedure WebFormShow(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
    procedure xdwdsShipToAfterEdit(DataSet: TDataSet);
    procedure XDataWebDataSet1AfterEdit(DataSet: TDataSet);
    procedure btnCloseClick(Sender: TObject);
    procedure btnEditClick(Sender: TObject);
    procedure wdbtcAddressesDblClickCell(Sender: TObject; ACol, ARow: Integer);
    procedure btnClearClick(Sender: TObject);
    procedure AddressEditMode();
    procedure edtShippingAddressChange(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure btn_confirm_deleteClick(Sender: TObject);
    procedure tmrReturnTimer(Sender: TObject);
    procedure btnDeleteClick(Sender: TObject);
    procedure btnShipAddClick(Sender: TObject);
    procedure btnShipEditClick(Sender: TObject);
    procedure btnShipSaveClick(Sender: TObject);
    procedure btnShipDeleteClick(Sender: TObject);
  private
    { Private declarations }
    procedure ViewMode();
    procedure EditMode();
    [async] procedure GetCustomer();
    [async] procedure SendCustomerToServer();
    [async] procedure SendAddressToServer();
    [async] procedure DelAddress();
    function VerifyCustomer(): boolean;
    function VerifyAddress(): boolean;
    procedure Clear();
    procedure ShowSelectCustomerForm();
  var
    customerID: string;
    notification: string;
    mode: string;
    shipmode: string;
  public
    { Public declarations }
     class function CreateForm(AElementID, customerInfo, info: string): TWebForm;
  end;

var
  FViewAddCustomer: TFViewAddCustomer;

implementation

{$R *.dfm}

uses View.Main, View.Customers, View.SelectCustomer, Utils;

procedure TFViewAddCustomer.Clear();
// Clears the shipping address fields.
begin
  edtShippingAddress.Text := '';
  edtShippingCity.Text := '';
  edtShippingState.Text := '';
  edtShippingZip.Text := '';
  edtShippingContact.Text := '';
  memoShipBlock.Text := '';
  edtFirstLine.Text := '';
end;

procedure TFViewAddCustomer.ShowSelectCustomerForm();
// displays the add order pop-up so the user can choose a customer
var
  newform: TFSelectCustomer;
begin
  newform := TFSelectCustomer.CreateNew;

  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';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    begin

    end
  );
end;

procedure TFViewAddCustomer.DelAddress;
// Deletes a shipping address.
var
  Response: TXDataClientResponse;
  notification: TJSObject;
begin
  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.DelShippingAddress',
              [xdwdsShipTo.FieldByName('ship_id').AsString, customerID]));
  notification := TJSObject(Response.Result);
  ShowToast(string(notification['status']));
  xdwdsShipTo.Close;
  xdwdsShipTo.SetJSONData(notification['ADDRESS']);
  xdwdsShipTo.Open;
  Utils.HideSpinner('spinner');
end;

procedure TFViewAddCustomer.SendAddressToServer;
// Creates an Address JSON and then sends it to the server for the address to be
// Added or edited.
var
  Field: TField;
  AddressJSON: TJSONObject;
  Response: TXDataClientResponse;
  notification: TJSObject;
  ship_block: string;
begin
  AddressJSON := TJSONObject.Create;

  AddressJSON.AddPair('address', edtShippingAddress.Text);
  AddressJSON.AddPair('city', edtShippingcity.Text);
  AddressJSON.AddPair('state', edtShippingstate.Text);
  AddressJSON.AddPair('zip', edtShippingzip.Text);
  AddressJSON.AddPair('contact', edtShippingContact.Text);
  AddressJSON.AddPair('customer_id', customerID);

  ship_block := edtFirstLine.Text + slinebreak +
                edtName.Text + slinebreak +
                edtShippingContact.Text + slinebreak +
                edtShippingAddress.Text + slinebreak +
                edtShippingCity.Text + ', ' + edtShippingState.Text + ' ' + edtShippingZip.Text;
  AddressJSON.AddPair('ship_block', ship_block);

  if shipmode = 'EDIT' then
    AddressJSON.AddPair('customer_ship_id', xdwdsShipTo.FieldByName('ship_id').AsString);

  AddressJSON.AddPair('mode', shipmode);

  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddShippingAddress',
              [AddressJSON.ToString]));

  notification := TJSObject(Response.Result);
  ShowToast(string(notification['status']));
  xdwdsShipTo.Close;
  xdwdsShipTo.SetJSONData(notification['ADDRESS']);
  xdwdsShipTo.Open;
end;

procedure TFViewAddCustomer.btnAddClick(Sender: TObject);
// Takes the user to the Add Customer Page.
begin
  ShowSelectCustomerForm();
end;

procedure TFViewAddCustomer.btnCancelClick(Sender: TObject);
// Shows a pop-up to confirm the user would like to cancel their changes.
begin
  document.getElementById('modal_body').innerHTML := 'Are you sure you want to cancel all changes to the customer?';
  document.getElementById('btn_confirm_cancel').innerText := 'No';
  document.getElementById('btn_confirm_delete').innerText := 'Yes';
  asm
    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;

procedure TFViewAddCustomer.btnClearClick(Sender: TObject);
// Clears the shipping address fields.
begin
  Clear();
end;

procedure TFViewAddCustomer.btnCloseClick(Sender: TObject);
// closes the Add Customer page.
begin
  FViewMain.ShowForm(TFViewCustomers)
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');
end;

procedure TFViewAddCustomer.btnEditClick(Sender: TObject);
// Puts the form into edit mode
begin
  EditMode();
end;

procedure TFViewAddCustomer.edtShippingAddressChange(Sender: TObject);
// Puts the form into Address Edit Mode
begin
  AddressEditMode();
end;

procedure TFViewAddCustomer.EditMode;
// Enables Customer Fields while disabling shipping address fields.
begin
  FViewMain.change := true;
  btnAdd.Enabled := false;
  btnDelete.Enabled := false;
  btnClose.Enabled := false;
  btnSave.Enabled := true;
  btnCancel.Enabled := True;
  btnEdit.Enabled := false;

  // Disable Shipping Address Editting
  edtShippingAddress.Enabled := false;
  edtShippingCity.Enabled := false;
  edtShippingState.Enabled := false;
  edtShippingZip.Enabled := false;
  edtShippingContact.Enabled := false;
  edtFirstLine.Enabled := false;

  btnShipDelete.Enabled := false;
  btnShipSave.Enabled := false;
  btnShipCancel.Enabled := false;
  btnShipEdit.Enabled := false;
  btnShipAdd.Enabled := false;

end;

procedure TFViewAddCustomer.AddressEditMode;
// Enables Shipping Address fields while disabling customer fields.
begin
  FViewMain.change := true;
  btnDelete.Enabled := false;
  btnClose.Enabled := false;
  btnSave.Enabled := false;
  btnCancel.Enabled := false;
  btnEdit.Enabled := false;
  btnAdd.Enabled := false;

  btnShipDelete.Enabled := false;
  btnShipSave.Enabled := true;
  btnShipCancel.Enabled := true;
  btnShipEdit.Enabled := false;
  btnShipAdd.Enabled := false;

  edtShippingAddress.Enabled := true;
  edtShippingCity.Enabled := true;
  edtShippingState.Enabled := true;
  edtShippingZip.Enabled := true;
  edtShippingContact.Enabled := true;
  edtFirstLine.Enabled := true;

  edtName.Enabled := false;
  edtShortName.Enabled := false;
  edtBillAddress.Enabled := false;
  edtBillCity.Enabled := false;
  edtBillState.Enabled := false;
  edtBillZip.Enabled := false;
  edtBillContact.Enabled := false;
  dtpStartDate.Enabled := false;
  dtpEndDate.Enabled := false;
  edtFax.Enabled := false;
  edtPhone.enabled := false;
  wdblcbRep.Enabled := false;
end;

procedure TFViewAddCustomer.ViewMode;
// Enables Customer Fields while disabling shipping address fields.
begin
  btnAdd.Enabled := true;
  btnDelete.Enabled := true;
  btnClose.Enabled := true;
  btnSave.Enabled := false;
  btnCancel.Enabled := false;
  btnEdit.Enabled := true;
  FViewMain.change := false;

  btnShipAdd.Enabled := true;
  if ( not xdwdsShipTo.IsEmpty ) then
    btnShipDelete.Enabled := true;
  btnShipSave.Enabled := false;
  btnShipCancel.Enabled := false;
  btnShipEdit.Enabled := true;
  FViewMain.change := false;

  edtName.Enabled := true;
  edtShortName.Enabled := true;
  edtBillAddress.Enabled := true;
  edtBillCity.Enabled := true;
  edtBillState.Enabled := true;
  edtBillZip.Enabled := true;
  edtBillContact.Enabled := true;
  dtpStartDate.Enabled := true;
  dtpEndDate.Enabled := true;
  edtFax.Enabled := true;
  edtPhone.enabled := true;
  wdblcbRep.Enabled := true;

end;

procedure TFViewAddCustomer.wdbtcAddressesDblClickCell(Sender: TObject; ACol,
  ARow: Integer);
// Retrieves the shipping address allowing it to be edited.
begin
  xdwdsShipTo.Locate('ship_id', wdbtcAddresses.Cells[0, ARow], []);
  edtShippingAddress.Text := xdwdsShipTo.FieldByName('shipping_address').AsString;
  edtShippingCity.Text := xdwdsShipTo.FieldByName('city').AsString;
  edtShippingState.Text := xdwdsShipTo.FieldByName('state').AsString;
  edtShippingZip.Text := xdwdsShipTo.FieldByName('zip').AsString;
  edtShippingContact.Text := xdwdsShipTo.FieldByName('contact').AsString;
  memoShipBlock.Text := xdwdsShipTo.FieldByName('ADDRESS').AsString;
  edtFirstLine.Text := memoShipBlock.Lines[0];
end;

procedure TFViewAddCustomer.SendCustomerToServer();
// Creates the customer JSON and then sends it to the server.
var
  customerJSON: TJSONObject;
  Field: TField;
  Response: TXDataClientResponse;
  notification: TJSObject;
  input: TJSHTMLElement;
  msg: string;
  BILL_ADDRESS_BLOCK: string;
begin

  customerJSON := TJSONObject.Create;

  if dtpStartDate.Date <> 0 then
    XDataWebDataSet1START_DATE.Value := DateTimeToStr(dtpStartDate.Date);

  if dtpEndDate.Date <> 0 then
    XDataWebDataSet1END_DATE.Value := DateTimeToStr(dtpEndDate.Date);

  XDataWebDataSet1.First;

  while not XDataWebDataSet1.Eof do
  begin
    for Field in XDataWebDataSet1.Fields do
    begin
      if Field is TStringField then
      begin
        if Field.AsString = '' then
          customerJSON.AddPair(Field.FieldName, '')
        else
          customerJSON.AddPair(Field.FieldName, Field.AsString);  // Add all other fields
      end
      else if Field is TIntegerField then
      begin
        customerJSON.AddPair(Field.FieldName, Field.AsString);
      end;
    end;
    XDataWebDataSet1.Next;
  end;

  BILL_ADDRESS_BLOCK := edtName.Text + slinebreak +
                        edtBillContact.Text + slinebreak +
                        edtBillAddress.Text + slinebreak +
                        edtBillCity.Text + ', ' + edtBillState.Text + ' ' + edtBillZip.Text;

  CustomerJSON.AddPair('BILL_ADDRESS_BLOCK', BILL_ADDRESS_BLOCK);

  customerJSON.AddPair('mode', mode);
  if mode = 'EDIT' then
    customerJSON.AddPair('CUSTOMER_ID', customerID);


  Response := await(XDataWebClient1.RawInvokeAsync('ILookupService.AddCustomer',
              [customerJSON.ToString]));

  notification := TJSObject(Response.Result);
  msg := string(notification['status']);
  if CustomerID = '' then
    CustomerID := string(notification['CustomerID']);

  edtCustomerID.Text := CustomerID;

  ShowToast(msg);

  //TODO update the BILL_ADDRESS_BLOCK memo after saving.

  if msg.Contains('Failure') then
  begin
    input := TJSHTMLInputElement(document.getElementById('edtcompanyaccountname'));
    input.classList.add('is-invalid');
    input := TJSHTMLInputElement(document.getElementById('shortnamefeedback'));
    input.innerHTML := 'Company Account Name must be Unique.' ;
  end;

end;

procedure TFViewAddCustomer.btnSaveClick(Sender: TObject);
// Sends the customer JSON to the server
begin
  if VerifyCustomer() then
  begin
    sendCustomerToServer();
    GetCustomer();
    ViewMode();
  end;
end;

procedure TFViewAddCustomer.btnShipAddClick(Sender: TObject);
// Sets the form to address edit mode and allows the user to add a shipping address.
begin
  shipmode := 'ADD';
  Clear();
  AddressEditMode();
end;

procedure TFViewAddCustomer.btnShipDeleteClick(Sender: TObject);
// Allows the user to delete a Shipping Address.
begin
  document.getElementById('modal_body').innerHTML := 'Are you sure you want to delete this address?';
  document.getElementById('btn_confirm_cancel').innerText := 'Cancel';
  document.getElementById('btn_confirm_delete').innerText := 'Delete';
  asm
    var confirmationModal = new bootstrap.Modal(document.getElementById('confirmation_modal'), {
    keyboard: false });
    confirmationModal.show();
  end;
end;

procedure TFViewAddCustomer.btnShipEditClick(Sender: TObject);
// Sets the form into AddressEdit mode.
begin
  shipmode := 'EDIT';
  AddressEditMode();
end;

procedure TFViewAddCustomer.btnShipSaveClick(Sender: TObject);
// After Verifying the Address it sends the address down to the server.
begin
  if VerifyAddress() then
  begin
    SendAddressToServer();
    Clear();
    ViewMode();
  end;
end;

procedure TFViewAddCustomer.btn_confirm_deleteClick(Sender: TObject);
// Modal Confirmation button. Checks if the user is cancelling changes, or
// Deleting a shipping address/ customer
begin
  FViewMain.change := false;
  if  document.getElementById('btn_confirm_delete').innerText = 'Yes' then
  // checks if the user is canceling or deleting
  begin
    if CustomerID <> '' then
    begin
      FViewMain.ViewAddCustomer(CustomerID, 'Failure:Changes Discarded');
    end
    else
      FViewMain.ShowForm(TFViewCustomers);
  end
  else if document.getElementById('modal_body').innerHTML.Contains('customer') then
  // checks if the user is deleting a customer or a shipping address
  begin
    asm
      var confirmationModal = new bootstrap.Modal(document.getElementById('confirmation_modal'), {
      keyboard: false });
      confirmationModal.hide();
    end;
    Utils.ShowSpinner('spinner');
    //delCustomer();
    tmrReturn.Enabled := true;
  end
  else
  begin
    asm
      var confirmationModal = new bootstrap.Modal(document.getElementById('confirmation_modal'), {
      keyboard: false });
      confirmationModal.hide();
    end;
    Utils.ShowSpinner('spinner');
    delAddress();
  end;
end;

class function TFViewAddCustomer.CreateForm(AElementID: string; customerInfo: string; info: string): TWebForm;
// Creates the Add Customer form. Setting the customer id so the customer can be
// Retrieved and the notification to be shown.
begin
  Application.CreateForm(TFViewAddCustomer, AElementID, Result,
    procedure(AForm: TObject)
    begin
      with TFViewAddCustomer(AForm) do
      begin
        TFViewAddCustomer(AForm).customerID := customerInfo;
        TFViewAddCustomer(AForm).notification := info;
      end;
    end
  );

end;

procedure TFViewAddCustomer.GetCustomer;
// Retrieves a customer for a given CustomerID.
var
  xdcResponse: TXDataClientResponse;
  customer : TJSObject;
  address: string;
  items: TJSObject;
  ship_block: TStringList;
begin
  if CustomerID = '' then
  begin
    mode := 'ADD';
  end
  else
    mode := 'EDIT';
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCustomer',
        [customerID]));
  customer :=  TJSObject(xdcResponse.Result);
  console.log(customer);

  xdwdsUsers.Close;
  xdwdsUsers.SetJSONData(customer['USERS']);
  xdwdsUsers.Open;

  XDataWebDataSet1.Close;
  XDataWebDataSet1.SetJsonData(customer);
  XDataWebDataSet1.Open;


  edtCustomerID.Text := CustomerID;

  if XDataWebDataSet1.FieldByName('START_DATE').AsString <> '' then
    dtpStartDate.Date := XDataWebDataSet1.FieldByName('START_DATE').AsDateTime;

  if XDataWebDataSet1.FieldByName('END_DATE').AsString <> '' then
    dtpEndDate.Date := XDataWebDataSet1.FieldByName('End_DATE').AsDateTime;

  xdwdsShipTo.Close;
  xdwdsShipTo.SetJSONData(customer['ADDRESS_LIST']);
  xdwdsShipTo.Open;

  memoAddressBlock.Text :=  string(customer['staff_fields_invoice_to']);

  edtShippingAddress.Text := xdwdsShipTo.FieldByName('shipping_address').AsString;
  edtShippingCity.Text := xdwdsShipTo.FieldByName('city').AsString;
  edtShippingState.Text := xdwdsShipTo.FieldByName('state').AsString;
  edtShippingZip.Text := xdwdsShipTo.FieldByName('zip').AsString;
  edtShippingContact.Text := xdwdsShipTo.FieldByName('contact').AsString;
  memoShipBlock.Text := xdwdsShipTo.FieldByName('ADDRESS').AsString;
  if memoShipBlock.Lines.Count > 0 then
    edtFirstLine.Text := memoShipBlock.Lines[0]
  else
    edtFirstLine.Text := '';

end;

procedure TFViewAddCustomer.WebFormShow(Sender: TObject);
// Sets the form up whenever it is shown.
var
  SQL: string;
begin
  if customerID = '' then
    mode := 'ADD'
  else
    mode := 'EDIT';

  if notification <> '' then
  begin
    showToast(notification);
  end;

  if mode = 'ADD' then
    EditMode()
  else
    ViewMode();

  getCustomer();

  dtpStartDate.Date := 0;
  dtpEndDate.Date := 0;
end;

procedure TFViewAddCustomer.XDataWebDataSet1AfterEdit(DataSet: TDataSet);
begin
  EditMode();
end;

procedure TFViewAddCustomer.xdwdsShipToAfterEdit(DataSet: TDataSet);
begin
  EditMode();
end;


procedure TFViewAddCustomer.tmrReturnTimer(Sender: TObject);
// Timer to returnto the customer page  because it takes slightly too long to
// Delete customers causing ghost customers to show up.
begin
  Utils.HideSpinner('spinner');
  tmrReturn.Enabled := false;
  FViewMain.ViewCustomerList('Success:Customer Successfully Deleted');
end;

function TFViewAddCustomer.VerifyCustomer(): boolean;
var
  input: TJSHTMLElement;
begin
  result := true;

  // Company Verification
  input := TJSHTMLInputElement(document.getElementById('edtcompanyname'));
  if edtName.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');


  input := TJSHTMLInputElement(document.getElementById('edtcompanyaccountname'));
  if edtShortName.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');


  // Billing Information Verification
  input := TJSHTMLInputElement(document.getElementById('edtbillingaddress'));
  if edtBillAddress.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtbillingcity'));
  if edtBillCity.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtbillingstate'));
  if edtBillState.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtbillingzip'));
  if edtBillZip.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtbillingcontact'));
  if edtBillContact.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');
end;

function TFViewAddCustomer.VerifyAddress: Boolean;
// Verifies all the shipping information is filled in.
var
  input: TJSHTMLElement;
begin
  result := true;
  input := TJSHTMLInputElement(document.getElementById('edtshippingaddress'));
  if edtShippingAddress.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtshippingcity'));
  if edtShippingCity.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtshippingstate'));
  if edtShippingState.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtshippingzip'));
  if edtShippingZip.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtshippingcontact'));
  if edtShippingContact.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

  input := TJSHTMLInputElement(document.getElementById('edtfirstline'));
  if edtFirstLine.Text = '' then
  begin
    input.classList.add('is-invalid');
    result := false;
  end
  else
    input.classList.remove('is-invalid');

end;

end.