// Customer Form accessed from the ccustomer header in the main form.

unit View.Customers;

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,
  XData.Web.JsonDataset, WEBLib.DB, Data.DB, XData.Web.Dataset,
  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.Forms;

type
  TFViewCustomers = class(TWebForm)
    btnAddCustomer: TWebButton;
    wcbPageSize: TWebComboBox;
    pnlMessage: TWebPanel;
    lblMessage: TWebLabel;
    btnCloseNotification: TWebButton;
    XDataWebClient1: TXDataWebClient;
    wdsCustomers: TWebDataSource;
    xdwdsCustomers: TXDataWebDataSet;
    xdwdsCustomersNAME: TStringField;
    xdwdsCustomersSTART_DATE: TStringField;
    xdwdsCustomersSHORT_NAME: TStringField;
    xdwdsCustomersCUSTOMER_ID: TIntegerField;
    wdbtcCustomers: TWebDBTableControl;
    edtFilter: TWebEdit;
    lblEntries: TWebLabel;
    xdwdsCustomersQB_LIST_ID: TStringField;
    procedure WebFormCreate(Sender: TObject);
    procedure btnAddCustomerClick(Sender: TObject);
    procedure wdbtcCustomersDblClickCell(Sender: TObject; ACol, ARow: Integer);
    procedure edtFilterChange(Sender: TObject);
    procedure wcbPageSizeChange(Sender: TObject);
  private
    { Private declarations }
    procedure GeneratePagination(TotalPages: Integer);
    [async] procedure GetCustomers(searchOptions: string);
    function GenerateSearchOptions(): string;
    procedure HideNotification();
    procedure ShowSelectCustomerForm();

    var
      PageNumber: integer;
      PageSize: integer;
      TotalPages: integer;
  public
    { Public declarations }
  end;

var
  FViewCustomers: TFViewCustomers;

implementation

uses
  XData.Model.Classes, View.Main, View.Customer.Select, Utils;

{$R *.dfm}

procedure TFViewCustomers.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 to Add';
  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 TFViewCustomers.WebFormCreate(Sender: TObject);
// Initializes important values:
// PageNumber: What page number the user is on IE 1: 1-10, 2: 11-20 etc
// TotalPages: Total number of pages returned from the search.
// PageSize: Number of entries per page.
begin
  DMConnection.ApiConnection.Connected := True;
  PageNumber := 1;
  TotalPages := 1; // Initial total pages
  wcbPageSize.Text := '50';
  PageSize := 50;
  HideNotification();
  getCustomers(GenerateSearchOptions());
end;

procedure TFViewCustomers.GetCustomers(searchOptions: string);
// retrieves a list of Customers that fit a given search criteria
// searchOptions: search info to be sent to the server
var
  xdcResponse: TXDataClientResponse;
  customerList: TJSObject;
  customerListLength: integer;
  TotalPages: integer;
begin
  if PageNumber > 0 then
  begin
    Utils.ShowSpinner('spinner');
    try
      xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.GetCustomers', [searchOptions]));
      customerList := TJSObject(xdcResponse.Result);

      xdwdsCustomers.Close;
      xdwdsCustomers.SetJsonData(customerList['data']);
      xdwdsCustomers.Open;

      customerListLength := integer(customerList['count']);
      TotalPages := (customerListLength + PageSize - 1) div PageSize;
      generatePagination(TotalPages);

      if customerListLength = 0 then
        begin
          lblEntries.Caption := 'No entries found';
          ShowToast('No entries found', 'danger');
        end
        else if (PageNumber * PageSize) < customerListLength then
          lblEntries.Caption := Format('Showing entries %d - %d of %d',
            [(PageNumber - 1) * PageSize + 1, PageNumber * PageSize, customerListLength])
        else
          lblEntries.Caption := Format('Showing entries %d - %d of %d',
            [(PageNumber - 1) * PageSize + 1, customerListLength, customerListLength]);
    except
      on E: EXDataClientRequestException do
        Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
    end;
    Utils.HideSpinner('spinner');
  end;
end;

function TFViewCustomers.GenerateSearchOptions(): string;
// Generates searchOptions for GetOrders.
var
  searchOptions: string;
begin
  searchOptions :=  '&pagenumber=' + IntToStr(PageNumber) +
                    '&pagesize=' + IntToStr(PageSize);

  Result := searchOptions;
end;


procedure TFViewCustomers.HideNotification;
begin
  pnlMessage.ElementHandle.hidden := True;
end;


procedure TFViewCustomers.wcbPageSizeChange(Sender: TObject);
begin
  PageSize := StrToInt(wcbPageSize.Text);
  getCustomers(GenerateSearchOptions());
end;

procedure TFViewCustomers.wdbtcCustomersDblClickCell(Sender: TObject; ACol,
  ARow: Integer);
begin
  FViewMain.ViewAddCustomer(wdbtcCustomers.Cells[0, ARow], '') ;
end;

procedure TFViewCustomers.btnAddCustomerClick(Sender: TObject);
begin
  if AuthService.TokenPayload.Properties['qb_enabled'] then
    ShowSelectCustomerForm()
  else
    ShowNotificationModal('QuickBooks interface is not currently active');
end;

procedure TFViewCustomers.edtFilterChange(Sender: TObject);
begin
  xdwdsCustomers.Filter := 'SHORT_NAME LIKE ' + quotedStr('%' + edtFilter.Text + '%');
  xdwdsCustomers.Filtered := true;
end;

procedure TFViewCustomers.GeneratePagination(TotalPages: Integer);
// Generates pagination for the table.
// TotalPages: Total amount of pages generated by the search
// This could definitely be improved.
var
  PaginationElement, PageItem, PageLink: TJSHTMLElement;
  I, Start, Finish: Integer;
begin
  PaginationElement := TJSHTMLElement(document.getElementById('pagination'));
  PaginationElement.innerHTML := ''; // Clear existing pagination

  // Previous Button
  PageItem := TJSHTMLElement(document.createElement('li'));
  PageItem.className := 'page-item';
  if PageNumber = 1 then
    PageItem.classList.add('disabled');
  PageLink := TJSHTMLElement(document.createElement('a'));
  PageLink.className := 'page-link';
  PageLink.innerText := 'Previous';
  PageLink.setAttribute('href', 'javascript:void(0)');
  PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
  begin
    if PageNumber > 1 then
    begin
      Dec(PageNumber);
      GetCustomers(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

  // Page Numbers

  if TotalPages <= 7 then
  begin
    for I := 1  to 7 do
    begin
      if I <= TotalPages then
      begin
        PageItem := TJSHTMLElement(document.createElement('li'));
        PageItem.className := 'page-item';
        if I = PageNumber then
          PageItem.classList.add('selected-number'); // Add the selected-number class
        PageLink := TJSHTMLElement(document.createElement('a'));
        PageLink.className := 'page-link';
        PageLink.innerText := IntToStr(I);
        PageLink.setAttribute('href', 'javascript:void(0)');
        PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
        var
          PageNum: Integer;
        begin
          PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
          PageNumber := PageNum;
          GetCustomers(GenerateSearchOptions());
        end);
        PageItem.appendChild(PageLink);
        PaginationElement.appendChild(PageItem);
      end;
    end;
  end
  else
  begin
    if PageNumber <= 4 then
    // If page number is low enough no early elipsis needed
    Begin
      Start := 2;
      Finish := 5;
    End
    else if (PageNumber >= (TotalPages - 3)) then
    // If page number is high enough no late elipsis needed
    begin
      Start := TotalPages - 3;
      Finish := TotalPages - 1;
    end
    else
    begin
      Start := PageNumber - 1;
      Finish := PageNumber + 1;
    end;

    PageItem := TJSHTMLElement(document.createElement('li'));
    PageItem.className := 'page-item';
    if 1 = PageNumber then
      PageItem.classList.add('selected-number'); // Add the selected-number class
    PageLink := TJSHTMLElement(document.createElement('a'));
    PageLink.className := 'page-link';
    PageLink.innerText := '1';
    PageLink.setAttribute('href', 'javascript:void(0)');
    PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
    var
      PageNum: Integer;
    begin
      PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
      PageNumber := PageNum;
      GetCustomers(GenerateSearchOptions());
    end);
    PageItem.appendChild(PageLink);
    PaginationElement.appendChild(PageItem);

    // Adds Elipse to pagination if page number is too big
    if PageNumber > 4 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      PageItem.classList.add('disabled');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := '...';
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageItem.appendChild(PageLink);
      PaginationElement.appendChild(PageItem);
    end;


    // Adds Page, page - 1, and page + 1 to pagination
    for I := Start  to Finish do
    begin
      if ( I > 1) and (I < TotalPages) then
      begin
        PageItem := TJSHTMLElement(document.createElement('li'));
        PageItem.className := 'page-item';
        if I = PageNumber then
          PageItem.classList.add('selected-number'); // Add the selected-number class
        PageLink := TJSHTMLElement(document.createElement('a'));
        PageLink.className := 'page-link';
        PageLink.innerText := IntToStr(I);
        PageLink.setAttribute('href', 'javascript:void(0)');
        PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
        var
          PageNum: Integer;
        begin
          PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
          PageNumber := PageNum;
          GetCustomers(GenerateSearchOptions());
        end);
        PageItem.appendChild(PageLink);
        PaginationElement.appendChild(PageItem);
      end;
    end;

    // adds ellipse if number is too small
    if PageNumber < TotalPages - 4 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      PageItem.classList.add('disabled');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := '...';
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageItem.appendChild(PageLink);
      PaginationElement.appendChild(PageItem);
    end;

    if TotalPages <> 1 then
    begin
      PageItem := TJSHTMLElement(document.createElement('li'));
      PageItem.className := 'page-item';
      if TotalPages = PageNumber then
            PageItem.classList.add('selected-number');
      PageLink := TJSHTMLElement(document.createElement('a'));
      PageLink.className := 'page-link';
      PageLink.innerText := IntToStr(TotalPages);
      PageLink.setAttribute('href', 'javascript:void(0)');
      PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
      var
        PageNum: Integer;
      begin
        PageNum := StrToInt((Event.currentTarget as TJSHTMLElement).innerText);
        PageNumber := PageNum;
        GetCustomers(generateSearchOptions());
      end);
    end;
    PageItem.appendChild(PageLink);
    PaginationElement.appendChild(PageItem);
  end;

  // Next Button
  PageItem := TJSHTMLElement(document.createElement('li'));
  PageItem.className := 'page-item';
  if PageNumber = TotalPages then
    PageItem.classList.add('disabled');
  PageLink := TJSHTMLElement(document.createElement('a'));
  PageLink.className := 'page-link';
  PageLink.innerText := 'Next';
  PageLink.setAttribute('href', 'javascript:void(0)');
  PageLink.addEventListener('click', procedure(Event: TJSMouseEvent)
  begin
    if PageNumber < TotalPages then
    begin
      Inc(PageNumber);
      GetCustomers(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);

end;


end.