// Displays orders in the grid. Allows the user
// to sort the entries, filter their search, and search for a specific person.
// Authors:
// Cameron Hayes
// Mac Stephens

unit View.Orders;

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, XData.Web.DatasetCommon,
  WEBLib.Grids, VCL.Forms;

type
  TFViewOrders = class(TWebForm)
    XDataWebClient1: TXDataWebClient;
    xdwdsOrders: TXDataWebDataSet;
    lblEntries: TWebLabel;
    wdsOrders: TWebDataSource;
    xdwdsOrderscompanyName: TStringField;
    xdwdsOrdersjobName: TStringField;
    xdwdsOrdersorderDate: TStringField;
    xdwdsOrdersproofDue: TStringField;
    xdwdsOrdersproofDone: TStringField;
    xdwdsOrdersartDue: TStringField;
    xdwdsOrdersartDone: TStringField;
    xdwdsOrdersmountDue: TStringField;
    xdwdsOrdersmountDone: TStringField;
    xdwdsOrdersshipDue: TStringField;
    xdwdsOrdersshipDone: TStringField;
    xdwdsOrdersprice: TStringField;
    xdwdsOrdersID: TStringField;
    xdwdsOrderscolors: TStringField;
    btnAddOrder: TWebButton;
    btnSearch: TWebButton;
    xdwdsOrdersplateDue: TStringField;
    xdwdsOrdersplateDone: TStringField;
    xdwdsOrdersorderType: TStringField;
    WebButton1: TWebButton;
    btnPDF: TWebButton;
    wdsCustomers: TWebDataSource;
    xdwdsCustomers: TXDataWebDataSet;
    xdwdsCustomersNAME: TStringField;
    xdwdsCustomersID: TIntegerField;
    xdwdsCustomersCURR_ID: TIntegerField;
    xdwdsSave: TXDataWebDataSet;
    wdsSave: TWebDataSource;
    xdwdsSaveCURR_ID: TIntegerField;
    wdbtcOrders: TWebDBTableControl;
    wcbPageSize: TWebComboBox;
    wlcbOrderBy: TWebLookupComboBox;
    edtSearch: TWebEdit;
    xdwdsOrdersDBID: TStringField;
    tmrReturn: TWebTimer;
    xdwdsOrdersIN_QB: TStringField;
    xdwdsOrdersqbRefNum: TStringField;
    btnOrderBy: TWebButton;
    xdwdsOrderscadFile: TStringField;
    procedure WebFormCreate(Sender: TObject);
    procedure btnAddOrderClick(Sender: TObject);
    procedure btnSearchClick(Sender: TObject);
    procedure WebFormShow(Sender: TObject);
    procedure btnPDFClick(Sender: TObject);
    procedure wcbPageSizeChange(Sender: TObject);
    procedure wlcbOrderByChange(Sender: TObject);
    procedure wdbtcOrdersDblClickCell(Sender: TObject; ACol, ARow: Integer);
    procedure wdbtcOrdersClickCell(Sender: TObject; ACol, ARow: Integer);
    procedure WebButton1Click(Sender: TObject);
    procedure tmrReturnTimer(Sender: TObject);
    [async] procedure GenerateReportPDFAsync(APdfTab: TJSWindow);
    procedure btnOrderByClick(Sender: TObject);
  private
    FChildForm: TWebForm;
    FPendingPdfTab: TJSWindow;
    procedure ClearTable();
    procedure GeneratePagination(TotalPages: Integer);
    function GenerateSearchOptions(): string;
    procedure OrderEntry(orderInfo, customerInfo, mode, orderType: string);
    procedure ShowAddOrderForm();
    procedure ShowSearchForm();
    procedure ShowSetStatusForm();
    [async] procedure GetOrders(searchOptions: string);
    [async] procedure SetStatus(statusInfo: string);
    procedure HandlePDFConfirmation;
    var
      PageNumber: integer;
      PageSize: integer;
      TotalPages: integer;
      statusOrderID: string; // used strictly for setting status.
      OrderID: string; // used strictly for search string.
      CompanyID: string;
      JobName: string;
      statusOrderType: string; // used strictly for setting status.
      orderType: string; // used strictly for search string.on

      //Status 1
      StartDate1: string;
      EndDate1: string;
      filterType1: string;
      null1: boolean;

      //Status 2
      StartDate2: string;
      EndDate2: string;
      filterType2: string;
      null2: boolean;

      OrderBy: string;
      direction: string;
      cadFile: string;
      filters: boolean;
      info: string;
      row: integer;
  public
    class function CreateForm(AElementID, Info: string): TWebForm;

  end;

var
  FViewOrders: TFViewOrders;

implementation

uses
  XData.Model.Classes, View.Main, View.Order.Add, View.Search, View.SetStatus, Utils;

{$R *.dfm}

class function TFViewOrders.CreateForm(AElementID, Info: string): TWebForm;
var
  localInfo: string;
begin
  localInfo := info;
  Application.CreateForm(TFViewOrders, AElementID, Result,
    procedure(AForm: TObject)
    begin
      with TFViewOrders(AForm) do
      begin
        TFViewOrders(AForm).info := LocalInfo;
      end;
    end
  );
end;


procedure TFViewOrders.btnOrderByClick(Sender: TObject);
var
  btn: TJSHTMLElement;
begin
  btn := document.getElementById('btnorderby') as TJSHTMLElement;
  if btnOrderBy.Caption = 'Ascending' then
  begin
    btnOrderBy.Caption := 'Descending';
    btn.innerHTML := 'Descending <i class="fa fa-arrow-down"></i>';
    direction := 'DESC';
  end
  else
  begin
    btnOrderBy.Caption := 'Ascending';
    btn.innerHTML := 'Ascending <i class="fa fa-arrow-up"></i>';
    direction := 'ASC';
  end;
  getOrders(generateSearchOptions());
end;

procedure TFViewOrders.btnPDFClick(Sender: TObject);
begin
  if xdwdsOrders.RecordCount >= 100 then
  begin
    FPendingPdfTab := nil;

    ShowConfirmationModal(
      'You are about to generate a PDF for over 100 orders. This may take some time. Continue?',
      'Yes',
      'No',
      procedure(confirmed: Boolean)
      begin
        if confirmed then
        begin
          HandlePDFConfirmation;
        end;
      end
    );
  end
  else
  begin

    if Assigned(FPendingPdfTab) then
      FPendingPdfTab.document.write(
        '<!DOCTYPE html>' +
        '<html lang="en">' +
        '<head>' +
          '<meta charset="UTF-8">' +
          '<meta name="viewport" content="width=device-width, initial-scale=1.0">' +
          '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">' +
        '</head>' +
        '<body class="d-flex flex-column justify-content-center align-items-center vh-100 bg-light">' +
          '<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"></div>' +
          '<div class="mt-3 fs-5 text-muted">Generating PDF, please wait�</div>' +
        '</body>' +
        '</html>'
      );

    Utils.ShowSpinner('spinner');
    GenerateReportPDFAsync(FPendingPdfTab);
  end;
end;



procedure TFViewOrders.HandlePDFConfirmation;
begin
  // Open tab only now
  FPendingPdfTab := window.open('', '_blank');

  if Assigned(FPendingPdfTab) then
    FPendingPdfTab.document.write(
      '<!DOCTYPE html>' +
      '<html lang="en">' +
      '<head>' +
        '<meta charset="UTF-8">' +
        '<meta name="viewport" content="width=device-width, initial-scale=1.0">' +
        '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">' +
      '</head>' +
      '<body class="d-flex flex-column justify-content-center align-items-center vh-100 bg-light">' +
        '<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"></div>' +
        '<div class="mt-3 fs-5 text-muted">Generating PDF, please wait�</div>' +
      '</body>' +
      '</html>'
    );

  Utils.ShowSpinner('spinner');
  GenerateReportPDFAsync(FPendingPdfTab);
  FPendingPdfTab := nil;
end;


[async] procedure TFViewOrders.GenerateReportPDFAsync(APdfTab: TJSWindow);
var
  xdcResponse: TXDataClientResponse;
  searchOptions, pdfURL: string;
  jsObject: TJSObject;
begin
  try
    searchOptions := edtSearch.Text + '&forPDF=true';

    xdcResponse := await(
      XDataWebClient1.RawInvokeAsync('ILookupService.GenerateOrderListPDF',
                                     [searchOptions]));
    jsObject := TJSObject(xdcResponse.Result);
    pdfURL   := String(jsObject.Properties['value']);
    if Assigned(APdfTab) then
      APdfTab.location.href := pdfURL;
  except
    on E: EXDataClientRequestException do
    begin
      Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
      if Assigned(APdfTab) then
        APdfTab.close;   // close the blank tab on failure
    end;
  end;
  Utils.HideSpinner('spinner');
end;



procedure TFViewOrders.WebButton1Click(Sender: TObject);
begin
  if statusOrderID <> '' then
    ShowSetStatusForm()
  else
    ShowToast('Failure: Please select an order');
end;


procedure TFViewOrders.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.
var
  today: TDateTime;
  params: TStringList;
  btn: TJSHTMLElement;
begin
  Utils.ShowSpinner('spinner');
  DMConnection.ApiConnection.Connected := True;
  PageNumber := 1;
  TotalPages := 1; // Initial total pages
  if FViewMain.search = '' then
  begin
    //Status 1
    startDate1 := FormatDateTime('yyyy/mm/dd', 0);
    endDate1 := FormatDateTime('yyyy/mm/dd', 0);
    filterType1 := '';
    null1 := false;

    //Status 2
    startDate2 := FormatDateTime('yyyy/mm/dd', 0);
    endDate2 := FormatDateTime('yyyy/mm/dd', 0);
    filterType2 := '';
    null2 := false;

    orderType := '';

    //today := TDateTime.Today;
    wcbPageSize.Text := '500';
    PageSize := 500;
    wlcbOrderBy.DisplayText := 'Order Date';
    OrderBy := 'COALESCE(cpo.staff_fields_order_date, wpo.staff_fields_order_date, cdo.staff_fields_order_date)';
    direction := 'DESC';
  end
  else
  begin
    params := TStringList.Create;
    params.StrictDelimiter := true;
    // parse the searchOptions
    params.Delimiter := '&';
    params.DelimitedText := FViewMain.search;

    PageNumber := StrToInt(params.Values['pagenumber']);
    PageSize := StrToInt(params.Values['pagesize']);
    wcbPageSize.Text := IntToStr(PageSize);
    OrderBy := params.Values['orderby'];
    direction := params.Values['direction'];
    wlcbOrderBy.DisplayText := OrderBy;
    statusOrderType := params.Values['orderType'].ToLower();
    statusOrderID := params.Values['orderID'];
    companyID := params.Values['companyID'];
    jobName := params.Values['jobName'];
    wlcbOrderBy.Value := OrderBy;

    btn := document.getElementById('btnorderby') as TJSHTMLElement;
    if direction = 'DESC' then
    begin
      btnOrderBy.Caption := 'Descending';
      btn.innerHTML := 'Descending <i class="fa fa-arrow-down"></i>';
      direction := 'DESC';
    end
    else
    begin
      btnOrderBy.Caption := 'Ascending';
      btn.innerHTML := 'Ascending <i class="fa fa-arrow-up"></i>';
      direction := 'ASC';
    end;


    // Status1
    startDate1 := params.Values['startDate1'];
    endDate1 := params.Values['endDate1'];
    filterType1 := params.Values['filterType1'];
    if params.Values['null1'] = '' then
      null1 := false
    else
      null1 := StrToBool(params.Values['null1']);

    // Status 2
    startDate2 := params.Values['startDate2'];
    endDate2 := params.Values['endDate2'];
    filterType2 := params.Values['filterType2'];
    if params.Values['null2'] = '' then
      null2 := false
    else
      null2 := StrToBool(params.Values['null2']);
  end;
  GenerateSearchOptions();
  getOrders(FViewMain.search);
end;


procedure TFViewOrders.WebFormShow(Sender: TObject);
begin
  if info <> '' then
    ShowToast(info)
end;


procedure TFViewOrders.wlcbOrderByChange(Sender: TObject);
begin
  OrderBy := wlcbOrderBy.Value;
  getOrders(generateSearchOptions());
end;


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

  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
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    begin
      if newform.confirm then
      begin
        if newform.cbCorrugatedPlate.Checked then
          orderType := 'corrugated'
        else if newform.cbWebPlate.Checked then
          orderType := 'web'
        else
          orderType := 'cutting';
        orderEntry('', newForm.DBID, 'ADD', orderType);
      end;
    end
  );
end;

procedure TFViewOrders.ShowSearchForm();
// displays the search pop-up that allows the user to filter the order list
var
  newform: TFSearch;
begin
  newform := TFSearch.CreateNew;

  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
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    var
      searchOptions: string;
    begin
      if newform.confirm then
      begin
        pageNumber := 1;

        // Status 1
        startDate1 := FormatDateTime('yyyy/mm/dd', newform.dtpStartDate1.Date);
        endDate1 := FormatDateTime('yyyy/mm/dd', newform.dtpEndDate1.Date);
        filterType1 := newform.wcbFilterType1.Text;
        null1 := newform.cbNull1.Checked;

        // Status 2
        startDate2 := FormatDateTime('yyyy/mm/dd', newform.dtpStartDate2.Date);
        endDate2 := FormatDateTime('yyyy/mm/dd', newform.dtpEndDate2.Date);
        filterType2 := newform.wcbFilterType2.Text;
        null2 := newform.cbNull2.Checked;

        jobName := newform.edtJobName.Text;
        orderID := newform.edtOrderID.Text;
        companyID := newform.DBID;
        orderType := newform.wcbOrderType.Text;
        cadFile := newform.edtCadFile.Text;

        generateSearchOptions();
        //searchOptions := generateSearchOptions();
        edtSearch.Text := FViewMain.search;
        getOrders(FViewMain.search);
      end;
    end
  );
end;

procedure TFViewOrders.ShowSetStatusForm();
// displays the search pop-up that allows the user to filter the order list
var
  newform: TFSetStatus;
begin
  newform := TFSetStatus.CreateNew;

  newform.Caption := 'Set Status';
  newForm.Popup := True;
  newForm.Border := fbDialog;
  newForm.Position := poScreenCenter;
  newForm.OrderID := statusOrderID;
  newForm.JobName := wdbtcOrders.Cells[4, row];
   if wdbtcOrders.Cells[15, row] <> '' then
    newForm.ShipDue := StrToDateTime(wdbtcOrders.Cells[15, row])
  else
    newForm.MountDue := 0;
  if wdbtcOrders.Cells[13, row] <> '' then
    newForm.MountDue := StrToDateTime(wdbtcOrders.Cells[13, row])
  else
    newForm.MountDue := 0;
   if wdbtcOrders.Cells[11, row] <> '' then
    newForm.PlateDue := StrToDateTime(wdbtcOrders.Cells[11, row])
  else
    newForm.PlateDue := 0;
   if wdbtcOrders.Cells[9, row] <> '' then
    newForm.ArtDue := StrToDateTime(wdbtcOrders.Cells[9, row])
  else
    newForm.ArtDue := 0 ;
  newForm.OrderType := statusOrderType;

  // used to manage Back button handling to close subform
  window.location.hash := 'subform';

  newform.ShowModal(
    procedure(AValue: TModalResult)
    var
      searchOptions: string;
      StatusJSON: TJSONObject;
    begin
      if newform.confirm then
      begin
        Utils.ShowSpinner('spinner');
        StatusJSON := TJSONObject.Create;
        StatusJSON.AddPair('ORDER_ID', StatusOrderID);
        StatusJSON.AddPair('date', DateTimeToStr(newform.dtpDate.Date));
        StatusJSON.AddPair('status', newform.wlcbStatus.Value);
        StatusJSON.AddPair('USER_ID', JS.toString(AuthService.TokenPayload.Properties['user_id']));
        StatusJSON.AddPair('mode', 'EDIT');
        StatusJSON.AddPair('staff_fields_ship_date', DateToStr(newForm.dtpShipDue.Date));
        StatusJSON.AddPair('staff_fields_mount_due', DateToStr(newForm.dtpMountDue.Date));
        StatusJSON.AddPair('staff_fields_plate_due', DateToStr(newForm.dtpPlateDue.Date));
        StatusJSON.AddPair('staff_fields_art_due', DateToStr(newForm.dtpArtDue.Date));
        StatusJSON.AddPair('OrderType', NewForm.OrderType);


        SetStatus(StatusJSON.ToString);
        OrderID := '';
        tmrReturn.Enabled := true;
      end;
    end
  );
end;

procedure TFViewOrders.tmrReturnTimer(Sender: TObject);
begin
  Utils.HideSpinner('spinner');
  tmrReturn.Enabled := false;
  getOrders(fViewMain.search);
end;

procedure TFViewOrders.SetStatus(statusInfo: string);
var
  xdcResponse: TXDataClientResponse;
  statusOptions: string;
begin
  xdcResponse := await(XDataWebClient1.RawInvokeAsync('ILookupService.SetStatus', [statusInfo]));
end;


procedure TFViewOrders.wcbPageSizeChange(Sender: TObject);
begin
  PageSize := StrToInt(wcbPageSize.Text);
  getOrders(generateSearchOptions());
end;

procedure TFViewOrders.wdbtcOrdersClickCell(Sender: TObject; ACol,
  ARow: Integer);
begin
  statusOrderID := wdbtcOrders.Cells[0, ARow];
  statusOrderType := wdbtcOrders.Cells[5, ARow];
  row := ARow;
end;

procedure TFViewOrders.wdbtcOrdersDblClickCell(Sender: TObject; ACol,
  ARow: Integer);
begin
  OrderID := wdbtcOrders.Cells[0, ARow];
  orderType :=  wdbtcOrders.Cells[5, ARow].Split([' '])[0];


  // Parameter 1: OrderID: The ID of the order, used when editting an existing order.
  // Parameter 2: CustomerID: The ID of the customer, used when adding a new order. Blank when editting an existing order because the customer id is already attached to the order.
  // Parameter 3: Mode: EDIT if editting an existing order, ADD if adding a new order.
  // Parameter 4: orderType: Type of order so we go to the correct order entry page.
  orderEntry(OrderID, '', 'EDIT', orderType);
end;

procedure TFViewOrders.GeneratePagination(TotalPages: Integer);
// Generates pagination for the table.
// TotalPages: Total amount of pages generated by the search
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);
      GetOrders(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;
          GetOrders(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;
      GetOrders(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;
          GetOrders(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;
        GetOrders(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);
      GetOrders(GenerateSearchOptions());
    end;
  end);
  PageItem.appendChild(PageLink);
  PaginationElement.appendChild(PageItem);
end;



procedure TFViewOrders.GetOrders(searchOptions: string);
var
  xdcResponse: TXDataClientResponse;
  orderList: TJSObject;
  orderListLength, TotalPages: Integer;
begin
  Utils.ShowSpinner('spinner');
  try
    try
      xdcResponse := await(XDataWebClient1.RawInvokeAsync(
        'ILookupService.GetOrders', [searchOptions]));

      if Assigned(xdcResponse.Result) then
      begin
        orderList := TJSObject(xdcResponse.Result);
        xdwdsOrders.Close;
        xdwdsOrders.SetJsonData(orderList['data']);
        xdwdsOrders.Open;

        orderListLength := Integer(orderList['count']);
        TotalPages := (orderListLength + PageSize - 1) div PageSize;
        GeneratePagination(TotalPages);

        // Update label
        if orderListLength = 0 then
        begin
          lblEntries.Caption := 'No entries found';
          ShowToast('No entries found', 'danger');
        end
        else if (PageNumber * PageSize) < orderListLength then
          lblEntries.Caption := Format('Showing entries %d - %d of %d',
            [(PageNumber - 1) * PageSize + 1, PageNumber * PageSize, orderListLength])
        else
          lblEntries.Caption := Format('Showing entries %d - %d of %d',
            [(PageNumber - 1) * PageSize + 1, orderListLength, orderListLength]);
      end;

    except
      on E: EXDataClientRequestException do
        Utils.ShowErrorModal(E.ErrorResult.ErrorMessage);
    end;
  finally
    Utils.HideSpinner('spinner');
  end;
end;


procedure TFViewOrders.btnAddOrderClick(Sender: TObject);
begin
  ShowAddOrderForm();
end;


procedure TFViewOrders.OrderEntry(orderInfo, customerInfo, mode, orderType: string);
begin
  if orderType = 'corrugated' then
    FViewMain.ViewOrderEntryCorrugated(orderInfo, customerInfo, mode, '')
  else if orderType = 'web' then
    FViewMain.ViewOrderEntryWeb(orderInfo, customerInfo, mode, '')
  else
    FViewMain.ViewOrderEntryCuttingDie(orderInfo, customerInfo, mode, '');
end;


procedure TFViewOrders.btnSearchClick(Sender: TObject);
var
  filterSection: TJSHTMLElement;
begin
  ShowSearchForm();
end;

procedure TFViewOrders.ClearTable();
// clears the table
var
  tbody: TJSHTMLElement;
begin
  tbody := TJSHTMLElement(document.getElementById('tblPhoneGrid').getElementsByTagName('tbody')[0]);
  tbody.innerHTML := '';
end;


function TFViewOrders.GenerateSearchOptions(): string;
// Generates searchOptions for GetOrders.
var
searchOptions: string;
begin
  searchOptions :=  '&pagenumber=' + IntToStr(PageNumber) +
                    '&pagesize=' + IntToStr(PageSize) +
                    '&orderby=' + OrderBy +
                    '&direction=' + direction +
                    '&accessRights=' + JS.toString(AuthService.TokenPayload.Properties['user_access_type']) +
                    '&userID=' +  JS.toString(AuthService.TokenPayload.Properties['user_id']);

                    //Status 1
                    if ( (filterType1 <> '') and (filterType1 <> 'NONE') ) then
                    begin
                      searchOptions := searchOptions +
                      '&filterType1=' + filterType1 +
                      '&null1=' + BoolToStr(null1);
                      if (not (null1)) then
                      begin
                        searchOptions := searchOptions +
                        '&startDate1=' + startDate1 +
                        '&endDate1=' + endDate1;
                      end;
                    end;


                    // Status2
                    if ( (filterType2 <> '') and (filterType2 <> 'NONE') ) then
                    begin
                      searchOptions := searchOptions +
                      '&filterType2=' + filterType2 +
                      '&null2=' + BoolToStr(null2);
                      if (not (null2)) then
                      begin
                        searchOptions := searchOptions +
                        '&startDate2=' + startDate2 +
                        '&endDate2=' + endDate2;
                      end;
                    end;

                    if ( ( orderType <> '' ) AND ( orderType <> 'Any' ) ) then
                      searchOptions := searchOptions + '&orderType=' + orderType;

                    if jobName <> '' then
                      searchOptions := searchOptions + '&jobName=' + jobName;

                    if companyID <> '' then
                      searchOptions := searchOptions + '&companyID=' + companyID;

                    if orderID <> '' then
                      searchOptions := searchOptions + '&orderID=' + orderID;

                    if cadFile <>  '' then
                      searchOptions := searchOptions + '&cadFile=' + cadFile;

  edtSearch.text := searchOptions;
  FViewMain.search := searchOptions;
  Result := searchOptions;
end;



end.
