This commit is contained in:
Zeeshaun
2026-03-17 08:54:34 -05:00
parent 64856c640e
commit cdcba54aa4
330 changed files with 54110 additions and 0 deletions
@@ -0,0 +1,16 @@
@page "/error"
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@@ -0,0 +1,47 @@
@page "/History"
@using ReserveManagementSystemUI.Shared.Components.Table;
@attribute [Authorize(Policy = "IsRMSAssociate")]
<h1>Audit/Activity History</h1>
<TabControl>
<TabTextTemplate Context="TheTab">
@TheTab.Text <img src="images/rotating.gif" alt="Spinning globe" class="App-logo">
</TabTextTemplate>
<ChildContent>
<TabPage Text="Loan History">
<div id="" class="alert alert-primary">We found <b>@reserveHistory.Count</b> history record(s)</div>
<table class="table table-striped table-hover">
<thead>
<tr>
<TableHeader TableHeaderValue="Member Number" OnClick="OnSortClick" HeaderName="MemberNumber" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="Loan Number" OnClick="OnSortClick" HeaderName="LoanNumber" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="Activity Type" OnClick="OnSortClick" HeaderName="ActivityType" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="Old Value" OnClick="OnSortClick" HeaderName="OldValue" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="New Value" OnClick="OnSortClick" HeaderName="NewValue" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="Modified Date" OnClick="OnSortClick" HeaderName="ModifiedDate" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="Modified By" OnClick="OnSortClick" HeaderName="ModifiedBy" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
<TableHeader TableHeaderValue="Description" OnClick="OnSortClick" HeaderName="AuditDescription" SelectedHeader="@currentSortedHeader" Ascending="@ascending" />
</tr>
</thead>
<tbody>
@foreach (var history in reserveHistory)
{
<tr>
<TableData TableDataValue="@history.MemberNumber" />
<TableData TableDataValue="@history.LoanNumber" />
<TableData TableDataValue="@history.ActivityType" />
<TableData TableDataValue="@history.OldValue" />
<TableData TableDataValue="@history.NewValue" />
<TableData TableDataValue="@(history.ModifiedDate.ToString("M/d/yyyy h:mm:ss tt"))" />
<TableData TableDataValue="@history.ModifiedBy" />
<TableData TableDataValue="@history.AuditDescription" />
</tr>
}
</tbody>
</table>
</TabPage>
</ChildContent>
</TabControl>
@@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
using Blazored.Modal;
using Blazored.Toast.Services;
using Blazored.Modal.Services;
using Models = ReserveManagementSystemLib.Models;
using ReserveManagementSystemUI.Helpers;
using ReserveManagementSystemUI.Services;
using ReserveManagementSystemUI.Shared.Components;
namespace ReserveManagementSystemUI.Pages
{
public partial class History : ComponentBase
{
[Inject]
private ReserveService ReserveService { get; set; }
[Inject]
IToastService ToastService { get; set; }
[Inject]
IModalService Modal { get; set; }
[Inject]
GridHelpers GridHelpers { get; set; }
private List<Models.AuditHistory> reserveHistory = new List<Models.AuditHistory>();
private bool ascending;
private string currentSortedHeader;
private IModalReference openModal;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
openModal = Modal.Show<LoadingSpinner>();
await LoadHistoryData();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task<bool> LoadHistoryData()
{
var result = true;
reserveHistory = await ReserveService.GetHistory();
if (reserveHistory == null)
{
ToastService.ShowError("There was an issue retrieving history data.");
reserveHistory = new List<Models.AuditHistory>();
result = false;
}
StateHasChanged();
openModal.Close();
return result;
}
private void OnSortClick(string sortBy)
{
var sameClick = sortBy == currentSortedHeader;
if (sameClick)
{
ascending = !ascending;
}
if (ascending)
{
reserveHistory = GridHelpers.OrderByAscending(reserveHistory, sortBy);
}
else
{
reserveHistory = GridHelpers.OrderByDescending(reserveHistory, sortBy);
}
currentSortedHeader = sortBy;
StateHasChanged();
}
}
}
@@ -0,0 +1,9 @@
@page "/"
@using ReserveManagementSystemUI.Shared.Components;
@inject IConfiguration Configuration;
@using ReserveManagementSystemUI.Model.Configuration;
@attribute [Authorize(Policy = "IsRMSAssociate")]
<h1>Home</h1>
<ImportList ShowAllImports="false" NumberOfImportsToShow="5"></ImportList>
@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Components;
namespace ReserveManagementSystemUI.Pages
{
public partial class Index: ComponentBase
{
}
}
@@ -0,0 +1,255 @@
@page "/LoanView/{LoanId:int}"
@attribute [Authorize(Policy = "IsRMSAssociate")]
<EditForm Model="@loanDetails" EditContext="@EditContext" Context="FormContext">
<FluentValidationValidator />
<div class="p-1"></div>
<h4>Member Information</h4>
<div class="form-group row">
<div class="form-group col-md-3">
<label for="MemberNumber" class="col-form-label">Member Number</label>
<InputText class="form-control" id="MemberNumber" readonly="true" @bind-Value="@loanDetails.MemberNumber" />
</div>
<div class="form-group col-md-3">
<label for="MemberLastName" class="col-form-label">Last Name</label>
<InputText class="form-control" id="MemberLastName" readonly="true" @bind-Value="@loanDetails.MemberLastName" />
</div>
<div class="form-group col-md-3">
<label for="MemberFirstName" class="col-form-label">First Name</label>
<InputText class="form-control" id="MemberFirstName" readonly="true" @bind-Value="@loanDetails.MemberFirstName" />
</div>
<div class="form-group col-md-1">
<label for="MemberInitial" class="col-form-label">Initial</label>
<InputText class="form-control" id="MemberInitial" readonly="true" @bind-Value="@loanDetails.MemberInitial" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
@if (loanDetails.ValidationErrors != null)
{
@foreach (var error in loanDetails.ValidationErrors)
{
<p class="validation-message"> @error.ErrorMessage</p>
}
}
</div>
</div>
<TabControl>
<TabTextTemplate Context="TheTab">
@TheTab.Text
</TabTextTemplate>
<ChildContent>
<TabPage Text="Loan Information">
<div class="form-row">
<div class="form-group col-md-3">
<label for="LoanNumber" class="col-form-label">Loan Number</label>
<InputText class="form-control" id="LoanNumber" readonly="true" @bind-Value="@loanDetails.LoanNumber" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="LoanDate" class="col-form-label">Loan Date</label>
<input type="text" class="form-control" id="LoanDate" readonly value="@loanDetails.LoanDate.ToString("M/d/yyyy")" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="LoanAmount" class="col-form-label">Loan Amount</label>
<input type="text" class="form-control" id="LoanAmount" readonly value="@loanDetails.LoanAmount.ToString("C")" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label for="ApplicationId" class="col-form-label">Application Id</label>
<InputText class="form-control" id="ApplicationId" readonly="true" @bind-Value="@loanDetails.ApplicationId" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="PostedDate" class="col-form-label">Posted Date</label>
<input type="text" class="form-control" id="PostedDate" readonly value="@loanDetails.PostedDate.ToString("M/d/yyyy")" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="MonthlyPmt" class="col-form-label">Monthly Payment</label>
<input type="text" class="form-control" id="MonthlyPmt" readonly value="@loanDetails.MonthlyPmt.ToString("C")" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label for="LoanStatus" class="col-form-label">Loan Status</label>
<InputText class="form-control" id="LoanStatus" readonly="true" @bind-Value="@loanDetails.LoanStatus" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="FirstPmtDate" class="col-form-label">First Payment Date</label>
<input type="text" class="@GetFieldValidationClass("LoanDate")" id="FirstPmtDate" readonly value="@loanDetails.FirstPmtDate.ToString("M/d/yyyy")" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="Term" class="col-form-label">Term</label>
<input class="form-control" id="Term" readonly value="@loanDetails.Term.ToString()" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label for="LoanTypeDescription " class="col-form-label">Loan Type - Description</label>
<input type="text" class="@GetFieldValidationClass("LoanTypeId")" id="LoanTypeDescription" readonly value="@LoanTypeDetailString" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="FinalPmtDate" class="col-form-label">Final Payment Date</label>
<input class="form-control" id="FinalPmtDate" readonly value="@loanDetails.FinalPmtDate.ToString("M/d/yyyy")" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="BuyRate" class="col-form-label">Buy Rate</label>
<input type="text" class="form-control" id="BuyRate" readonly value="@loanDetails.BuyRate.ToString("#0.0##")%" />
</div>
</div>
<div class="form-row">
<div class="form-group col-xs-1">
<label for="Gap" class="col-form-label">GAP</label>
<input type="text" class="form-control fieldInsurance" id="Gap" readonly value="@GapString" />
</div>
<div class="col-xs-1"></div>
<div class="form-group col-xs-1">
<label for="CreditLife" class="col-form-label">CRL</label>
<input type="text" class="form-control fieldInsurance" id="CreditLife" readonly value="@CreditLifeString" />
</div>
<div class="col-xs-1"></div>
<div class="form-group col-xs-1">
<label for="CreditDisability" class="col-form-label">CRD</label>
<input type="text" class="form-control fieldInsurance" id="CreditDisability" readonly value="@CreditDisabilityString" />
</div>
<div class="col-xs-1"></div>
<div class="form-group col-xs-1">
<label for="Warranty" class="col-form-label">WTY</label>
<input type="text" class="form-control fieldInsurance" id="Warranty" readonly value="@WarrantyString" />
</div>
<div class="col-xs-1"></div>
<div class="form-group col-xs-1">
<label for="Mbp " class="col-form-label">MBP</label>
<input type="text" class="form-control fieldInsurance" id="Mbp" readonly value="@MbpString" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="PaidDate" class="col-form-label">Paid Date</label>
<input type="text" class="form-control" id="PaidDate" readonly value="@PaidLoanDateString" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-md-3">
<label for="ContractRate" class="col-form-label">Contract Rate</label>
<input type="text" class="form-control" id="ContractRate" readonly value="@loanDetails.ContractRate.ToString("#0.0##")%" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label for="ReserveAmount" class="col-form-label">Reserve Amount</label>
<input type="text" class="form-control" id="ReserveAmount" readonly value="@loanDetails.ReserveAmount.ToString("C")" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-lg-7">
<label for="ReserveMessage" class="col-form-label">Reserve Message</label>
<InputText class="form-control" id="ReserveMessage" readonly="true" @bind-Value="@loanDetails.ReserveMessage" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label for="Chargeback" class="col-form-label">Chargeback Amount</label>
<input type="text" class="form-control" id="Chargeback" readonly value="@ChargeBackString" />
</div>
<div class="col-sm-1"></div>
<div class="form-group col-lg-7">
<label for="ChargebackMessage" class="col-form-label">Chargeback Message</label>
<input type="text" class="form-control" id="ChargebackMessage" readonly value="@loanDetails.ChargebackMessage" />
</div>
</div>
</TabPage>
<TabPage Text="Dealer Information">
<div class="form-row">
<div class="form-group col-md-5">
<label for="DealerCode" class="col-form-label">Dealer Code</label>
<InputText class="form-control" id="DealerCode" readonly="true" @bind-Value="@loanDetails.Dealer.DealerCode" />
</div>
</div>
@if (loanDetails.Dealer != null)
{
<div class="form-row">
<div class="form-group col-md-5">
<label for="DealerName" class="col-form-label">Dealer Name</label>
<input type="text" class="@GetFieldValidationClass("Dealer.Name")" id="DealerOrg2" readonly value="@loanDetails.Dealer.Name" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-5">
<label for="DealerOrg" class="col-form-label">Dealer Organization</label>
<input type="text" class="@GetFieldValidationClass("DealerOrganizationNumber")" id="DealerOrg" readonly value="@loanDetails.Dealer.DealerOrganizationNumber" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-5">
<label for="DealerAccount" class="col-form-label">Dealer Account</label>
<InputText class="form-control" id="DealerAccount" readonly="true" @bind-Value="@loanDetails.Dealer.DealerAccountNumber" />
</div>
</div>
}
</TabPage>
<TabPage Text="Vehicle Information">
@if (loanDetails.Vehicle != null)
{
<div class="form-row">
<div class="form-group col-md-3">
<label for="VINNumber" class="col-form-label">VIN Number</label>
<InputText class="form-control" id="VINNumber" readonly="true" @bind-Value="@loanDetails.Vehicle.VINNumber" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-3">
<label for="Make" class="col-form-label">Make</label>
<InputText class="form-control" id="Make" readonly="true" @bind-Value="@loanDetails.Vehicle.Make" />
</div>
<div class="form-group col-md-3">
<label for="Model" class="col-form-label">Model</label>
<InputText class="form-control" id="Model" readonly="true" @bind-Value="@loanDetails.Vehicle.Model" />
</div>
</div>
<div class="form-row">
<div class="form-group col-md-1">
<label for="Year" class="col-form-label">Year</label>
<InputText class="form-control" id="Year" readonly="true" @bind-Value="@loanDetails.Vehicle.Year" />
</div>
<div class="form-group col-md-2">
<label for="Mileage" class="col-form-label">Mileage</label>
<input type="text" class="form-control" id="Mileage" readonly value="@VehicleMileageFormat" />
</div>
<div class="form-group col-md-3">
<label for="Color" class="col-form-label">Color</label>
<InputText class="form-control" id="Color" readonly="true" @bind-Value="@loanDetails.Vehicle.Color" />
</div>
</div>
}
@if (loanDetails.Vehicle == null)
{
<div>Sorry no vehicle detail information for this loan!</div>
}
</TabPage>
</ChildContent>
</TabControl>
</EditForm>
@@ -0,0 +1,93 @@
using Blazored.Modal;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using ReserveManagementSystemLib.Models;
using ReserveManagementSystemUI.Services;
using ReserveManagementSystemUI.Shared.Components;
using System.Threading.Tasks;
namespace ReserveManagementSystemUI.Pages
{
public partial class LoanView : ComponentBase
{
[Inject]
IToastService ToastService { get; set; }
[Inject]
IModalService Modal { get; set; }
[Inject]
ReserveService ReserveService { get; set; }
[Parameter]
public int LoanId { get; set; }
private Loan loanDetails = new Loan();
private IModalReference openModal;
private string LoanTypeDetailString => !string.IsNullOrEmpty(loanDetails.LoanType?.ToString()) ? loanDetails.LoanTypeId?.ToString() + " - " + @loanDetails.LoanType?.LoanComment : "";
private string PaidLoanDateString => loanDetails.PaidLoanDate?.ToString("M/d/yyyy");
private string ChargeBackString => loanDetails.ChargeBack?.ToString("C");
private string StatementDateString => loanDetails.StatementDate?.ToString("M/d/yyyy");
private string AdjustmentString => loanDetails.Adjustment?.ToString("C");
private string VehicleMileageFormat => loanDetails.Vehicle.Mileage.ToString("#,##0");
private string GapString => loanDetails.Gap == true ? "Y" : "N";
private string WarrantyString => loanDetails.Warranty == true ? "Y" : "N";
private string MbpString => loanDetails.Mbp == true ? "Y" : "N";
private string CreditLifeString => loanDetails.CreditLife == true ? "Y" : "N";
private string CreditDisabilityString => loanDetails.CreditDisability == true ? "Y" : "N";
[CascadingParameter] EditContext EditContext { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await LoadLoanDetails();
}
await base.OnAfterRenderAsync(firstRender);
}
private string GetFieldValidationClass(string fieldName)
{
string className = "form-control";
if (loanDetails.ValidationErrors != null) {
foreach(var error in loanDetails.ValidationErrors)
{
if (error.PropertyName == fieldName) {
return "form-control invalid";
}
}
}
return className;
}
private async Task LoadLoanDetails()
{
openModal = Modal.Show<LoadingSpinner>();
loanDetails = await ReserveService.GetLoanById(LoanId);
if (loanDetails == null)
{
ToastService.ShowError("There was an issue retrieving this loan.");
}
openModal.Close();
StateHasChanged();
}
}
}
@@ -0,0 +1,228 @@
@page "/Loans/{ImportId:int}"
@page "/Loans/"
@using ReserveManagementSystemUI.Shared.Components.Table;
@using ReserveManagementSystemUI.Model;
@using ReserveManagementSystemLib.Models;
@attribute [Authorize(Policy = "IsRMSAssociate")]
<h1>Loans</h1>
<TabControl>
<TabTextTemplate Context="TheTab">
@TheTab.Text
</TabTextTemplate>
<ChildContent>
<TabPage Text="Loan Summary">
<h5>This is a summary view list from the Loan table, please click Select to view loan details.</h5>
<div id="" class="alert alert-primary">We found <b>@pagedResponse.TotalItems</b> loan(s)</div>
<div class="row filterBuffer">
<div class="input-group">
<div class="col-lg-3 col-lg-offset-3">
<label for="@currentLoanFilter.MemberNumberText" class="col-form-label">Member Number</label>
<BlazoredTypeahead SearchMethod="GetMemberNumbersAsync"
TValue="string"
TItem="string"
Value="@currentLoanFilter.MemberNumberText"
ValueChanged="SelectedMemberNumberResultChangedAsync"
ValueExpression="@(() => currentLoanFilter.MemberNumberText)"
MaximumSuggestions="10"
placeholder="Search by member number...">
<SelectedTemplate>
@context
</SelectedTemplate>
<ResultTemplate>
@context
</ResultTemplate>
</BlazoredTypeahead>
</div>
<div class="col-lg-3 col-lg-offset-3">
<label for="MemberNameText" class="col-form-label">Member Name</label>
<input type="search" id="MemberNameText" class="form-control" placeholder="Search by member name..."
spellcheck="false" autocomplete="false"
@onchange="OnMemberNameTextChangeAsync" />
</div>
<div class="col-lg-3 col-lg-offset-3">
<label for="@currentLoanFilter.LoanNumberText" class="col-form-label">Loan Number</label>
<BlazoredTypeahead SearchMethod="GetLoanNumbersAsync"
TValue="string"
TItem="string"
Value="@currentLoanFilter.LoanNumberText"
ValueChanged="SelectedLoanNumberResultChangedAsync"
ValueExpression="@(() => currentLoanFilter.LoanNumberText)"
MaximumSuggestions="10"
placeholder="Search by loan number...">
<SelectedTemplate>
@context
</SelectedTemplate>
<ResultTemplate>
@context
</ResultTemplate>
</BlazoredTypeahead>
</div>
<div class="col-lg-3 col-lg-offset-3">
<label for="@currentLoanFilter.ApplicationIdText" class="col-form-label">Application Id</label>
<BlazoredTypeahead SearchMethod="GetApplicationIdsAsync"
TValue="string"
TItem="string"
Value="@currentLoanFilter.ApplicationIdText"
ValueChanged="SelectedApplicationIdResultChangedAsync"
ValueExpression="@(() => currentLoanFilter.ApplicationIdText)"
MaximumSuggestions="10"
placeholder="Search by application id...">
<SelectedTemplate>
@context
</SelectedTemplate>
<ResultTemplate>
@context
</ResultTemplate>
</BlazoredTypeahead>
</div>
</div>
</div>
<div class="row filterBuffer">
<div class="input-group">
<div class="col-lg-3 col-lg-offset-3">
<label for="@SelectedDealer" class="col-form-label">Dealer</label>
<BlazoredTypeahead SearchMethod="GetDealersAsync"
TValue="Dealer"
TItem="Dealer"
Value="SelectedDealer"
ValueChanged="SelectedDealerResultChangedAsync"
ValueExpression="@(() => SelectedDealer)"
MaximumSuggestions="10"
MinimumLength="1"
placeholder="Search by dealer code or name...">
<SelectedTemplate Context="dealer">
@dealer.DealerCode - @dealer.Name
</SelectedTemplate>
<ResultTemplate Context="dealer">
@dealer.DealerCode - @dealer.Name
</ResultTemplate>
</BlazoredTypeahead>
</div>
<div class="col-lg-2 col-lg-offset-2">
<label for="@currentLoanFilter.ActionRequired" class="col-form-label">Action Required</label>
<BlazoredTypeahead SearchMethod="GetActionRequiredLoansAsync"
TValue="bool?"
TItem="bool?"
Value="@currentLoanFilter.ActionRequired"
ValueChanged="SelectedActionResultChangedAsync"
ValueExpression="@(() => @currentLoanFilter.ActionRequired)"
EnableDropDown="true"
placeholder="Search by action required...">
<SelectedTemplate Context="action">
@action
</SelectedTemplate>
<ResultTemplate Context="action">
@action
</ResultTemplate>
</BlazoredTypeahead>
</div>
<div class="col-lg-2 col-lg-offset-2">
<label for="LoanDateStart" class="col-form-label">Origination Date Start</label>
<input type="search" id="LoanDateStart" class="form-control" placeholder="Enter date..."
spellcheck="false" autocomplete="false"
@onchange="OnLoanDateStartChangeAsync" />
</div>
<div class="col-lg-2 col-lg-offset-2">
<label for="LoanDateEnd" class="col-form-label">Origination Date End</label>
<input type="search" id="LoanDateEnd" class="form-control" placeholder="Enter date..."
spellcheck="false" autocomplete="false"
@onchange="OnLoanDateEndChangeAsync" />
</div>
<div class="col-lg-3 col-lg-offset-3">
<label for="@SelectedImport" class="col-form-label">Import</label>
<BlazoredTypeahead SearchMethod="GetImportsAsync"
TValue="Import"
TItem="Import"
Value="SelectedImport"
ValueChanged="SelectedImportResultChangedAsync"
ValueExpression="@(() => SelectedImport)"
EnableDropDown="true"
MaximumSuggestions="5"
MinimumLength="3"
placeholder="Search by import...">
<SelectedTemplate Context="import">
@import?.ImportType @import?.StartDate.ToString("M/d/yyyy h:mm:ss tt")
</SelectedTemplate>
<ResultTemplate Context="import">
@import?.ImportType @import?.StartDate.ToString("M/d/yyyy h:mm:ss tt")
</ResultTemplate>
</BlazoredTypeahead>
</div>
</div>
</div>
<h6 style="text-align: right">Page @(pagedResponse.TotalPages < pagedResponse.PageIndex ? 0 : pagedResponse.PageIndex) of @pagedResponse.TotalPages</h6>
<div style="text-align: right;">
<div id="allButtons" class="pagination2 margin">
<button type="button" class="btn btn-primary" disabled="@(!pagedResponse.HasPreviousPage)" @onclick="@(() => LoadLoanDataAsync(1))"><i class="fa fa-angle-double-left" aria-hidden="true"></i></button>
<button type="button" class="btn btn-primary" disabled="@(!pagedResponse.HasPreviousPage)" @onclick="@(() => LoadLoanDataAsync(pagedResponse.PageIndex - 1))"><i class="fa fa-angle-left" aria-hidden="true"></i></button>
@for (int i = pagedResponse.FirstPage; i <= pagedResponse.LastPage; i++)
{
var currentPage = i;
<button type="button" class="@GetPageButtonClass(currentPage)" @onclick="@(() => LoadLoanDataAsync(currentPage))">@i</button>
}
<button type="button" class="btn btn-primary" disabled="@(!pagedResponse.HasNextPage)" @onclick="@(() => LoadLoanDataAsync(pagedResponse.PageIndex + 1))"><i class="fa fa-angle-right" aria-hidden="true"></i></button>
<button type="button" class="btn btn-primary" disabled="@(!pagedResponse.HasNextPage)" @onclick="@(() => LoadLoanDataAsync(pagedResponse.TotalPages))"><i class="fa fa-angle-double-right" aria-hidden="true"></i></button>
</div>
</div>
<table class="table table-striped table-hover">
<thead>
<tr>
<TableHeader TableHeaderValue="Dealer Code" OnClick="OnSortClickAsync" HeaderName="Dealer.DealerCode" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Dealer Name" OnClick="OnSortClickAsync" HeaderName="Dealer.Name" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Member Number" OnClick="OnSortClickAsync" HeaderName="MemberNumber" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Loan Number" OnClick="OnSortClickAsync" HeaderName="LoanNumber" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Application Id" OnClick="OnSortClickAsync" HeaderName="ApplicationId" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Last Name" OnClick="OnSortClickAsync" HeaderName="MemberLastName" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="First Name" OnClick="OnSortClickAsync" HeaderName="MemberFirstName" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Origination Date" OnClick="OnSortClickAsync" HeaderName="LoanDate" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableHeader TableHeaderValue="Action Required" OnClick="OnSortClickAsync" HeaderName="ActionRequired" SelectedHeader="@currentLoanFilter.SortField" Ascending="@ascending" />
<TableData TableDataValue="" />
</tr>
</thead>
<tbody>
@foreach (var loan in pagedResponse.LoanList)
{
<tr>
<TableData TableDataValue="@loan.Dealer?.DealerCode" />
<TableData TableDataValue="@loan.Dealer?.Name" />
<TableData TableDataValue="@loan.MemberNumber" />
<TableData TableDataValue="@loan.LoanNumber" />
<TableData TableDataValue="@loan.ApplicationId" />
<TableData TableDataValue="@loan.MemberLastName" />
<TableData TableDataValue="@loan.MemberFirstName" />
<TableData TableDataValue="@(loan.LoanDate.ToString("M/d/yyyy"))" />
<td>
<div style="text-align: center;padding: 5px;">
@if (loan.ActionRequired)
{
<i class="fa fa-times-circle text-danger" aria-hidden="true" data-test="icon"></i>
}
</div>
</td>
<td>
<div style="text-align: center;padding: 5px;width: 115px;">
<button type="button" class="btn btn-primary" @onclick="@(() => GoToLoan(loan.LoanId))">Select</button>
</div>
</td>
</tr>
}
</tbody>
</table>
</TabPage>
</ChildContent>
</TabControl>
@@ -0,0 +1,266 @@
using Blazored.Modal;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ReserveManagementSystemLib.Models;
using ReserveManagementSystemUI.Services;
using ReserveManagementSystemUI.Shared.Components;
namespace ReserveManagementSystemUI.Pages
{
public partial class Loans : ComponentBase
{
[Inject]
private ReserveService ReserveService { get; set; }
[Inject]
IToastService ToastService { get; set; }
[Inject]
IModalService Modal { get; set; }
[Inject]
NavigationManager NavigationManager { get; set; }
[Inject]
IJSRuntime JSRuntime { get; set; }
[Parameter]
public int? ImportId { get; set; }
private LoanFilter currentLoanFilter = new LoanFilter();
private PaginatedListResponse pagedResponse = new PaginatedListResponse();
private const int TopImports = 5;
private List<Import> Imports = new List<Import>();
private List<bool?> Actions = new List<bool?>();
private Import SelectedImport;
private Dealer SelectedDealer;
private bool ascending = true;
private IModalReference openModal;
protected override async Task OnParametersSetAsync()
{
currentLoanFilter = new LoanFilter
{
PageIndex = 1,
MaxRecordsPerPage = 15,
MaxPagesPerRange = 7,
};
Imports = await ReserveService.GetRecentImports(TopImports);
AddActions();
if (ImportId.HasValue)
{
SelectedImport = Imports.Where(i => ImportId.Value == (i.ImportId)).FirstOrDefault();
}
else
{
SelectedImport = null;
}
currentLoanFilter.ImportId = SelectedImport?.ImportId;
await LoadLoanDataAsync(1);
await base.OnParametersSetAsync();
}
protected async Task BlazorFocusElement()
{
try
{
await JSRuntime.InvokeVoidAsync("BlazorFocusElement");
}
catch (Exception)
{
//do nothing
}
}
private async Task LoadLoanDataAsync(int pageIndex)
{
currentLoanFilter.PageIndex = pageIndex;
openModal = Modal.Show<LoadingSpinner>();
pagedResponse = await ReserveService.GetFilteredLoans(currentLoanFilter);
if (pagedResponse.LoanList == null)
{
ToastService.ShowError("There was an issue retrieving loan data.");
pagedResponse.LoanList = new List<Loan>();
}
StateHasChanged();
await BlazorFocusElement();
openModal.Close();
GetPageButtonClass(currentLoanFilter.PageIndex);
}
private async Task OnMemberNameTextChangeAsync(ChangeEventArgs args)
{
currentLoanFilter.MemberNameText = args.Value.ToString();
await LoadLoanDataAsync(1);
}
private async Task OnLoanDateStartChangeAsync(ChangeEventArgs args)
{
if (DateTime.TryParse(args.Value.ToString(), out DateTime startDate))
{
currentLoanFilter.LoanDateStart = startDate;
}
else
{
currentLoanFilter.LoanDateStart = null;
}
await LoadLoanDataAsync(1);
}
private async Task OnLoanDateEndChangeAsync(ChangeEventArgs args)
{
if (DateTime.TryParse(args.Value.ToString(), out DateTime endDate))
{
currentLoanFilter.LoanDateEnd = endDate;
}
else
{
currentLoanFilter.LoanDateEnd = null;
}
await LoadLoanDataAsync(1);
}
private async Task<IEnumerable<string>> GetMemberNumbersAsync(string searchText)
{
var result = await ReserveService.GetMemberNumbers(searchText);
return result;
}
private async Task SelectedMemberNumberResultChangedAsync(string result)
{
currentLoanFilter.MemberNumberText = result;
await LoadLoanDataAsync(1);
}
private async Task<IEnumerable<string>> GetLoanNumbersAsync(string searchText)
{
var result = await ReserveService.GetLoanNumbers(searchText);
return result;
}
private async Task SelectedLoanNumberResultChangedAsync(string result)
{
currentLoanFilter.LoanNumberText = result;
await LoadLoanDataAsync(1);
}
private async Task<IEnumerable<string>> GetApplicationIdsAsync(string searchText)
{
var result = await ReserveService.GetApplicationIds(searchText);
return result;
}
private async Task SelectedApplicationIdResultChangedAsync(string result)
{
currentLoanFilter.ApplicationIdText = result;
await LoadLoanDataAsync(1);
}
private async Task SelectedImportResultChangedAsync(Import result)
{
currentLoanFilter.ImportId = result?.ImportId;
SelectedImport = result;
await LoadLoanDataAsync(1);
}
private async Task<IEnumerable<Import>> GetImportsAsync(string searchText)
{
var search = await Task.FromResult(Imports);
return search;
}
private string GetPageButtonClass(int currentPage)
{
return currentPage == pagedResponse.PageIndex ? "btn btn-page-focus" : "btn btn-page";
}
private async Task<IEnumerable<Dealer>> GetDealersAsync(string searchText)
{
var dealers = new List<Dealer>();
if (!string.IsNullOrWhiteSpace(searchText))
{
dealers = await ReserveService.GetDealers(searchText);
}
return dealers;
}
private async Task SelectedDealerResultChangedAsync(Dealer selectedDealer)
{
SelectedDealer = selectedDealer;
currentLoanFilter.DealerCodeText = selectedDealer?.DealerCode;
await LoadLoanDataAsync(1);
}
private async Task<IEnumerable<bool?>> GetActionRequiredLoansAsync(string searchText)
{
bool action;
var results = new List<bool?>();
if (!string.IsNullOrWhiteSpace(searchText) && bool.TryParse(searchText, out action))
{
results = await Task.FromResult(Actions.Where(x => x.Value.ToString() == searchText || x == null).ToList());
}
else
{
results = await Task.FromResult(Actions.ToList());
}
return results;
}
private async Task SelectedActionResultChangedAsync(bool? result)
{
currentLoanFilter.ActionRequired = result;
await LoadLoanDataAsync(1);
}
private void AddActions()
{
if (Actions != null && Actions.Count == 0)
{
Actions.Add(true);
Actions.Add(false);
}
}
private async void OnSortClickAsync(string sortBy)
{
if (sortBy == currentLoanFilter.SortField)
{
ascending = !ascending;
}
currentLoanFilter.SortField = sortBy;
currentLoanFilter.SortDirection = ascending ? "ASC" : "DESC";
currentLoanFilter.PageIndex = 1;
pagedResponse = await ReserveService.GetFilteredLoans(currentLoanFilter);
StateHasChanged();
}
void GoToLoan(int loanId)
{
NavigationManager.NavigateTo($"LoanView/{loanId}");
}
}
}
@@ -0,0 +1,14 @@
@page "/Statements"
@inject IConfiguration Configuration;
@using ReserveManagementSystemUI.Model.Configuration;
@attribute [Authorize(Policy = "IsRMSAssociate")]
<h1 class="statementBuffer">Statements & Reports</h1>
<div class="statementContainer">
<a class="btn btn-primary btnStatement" target="_blank" href=@StatementLink>Dealer Statement</a>
<a class="btn btn-primary btnStatement" target="_blank" href=@ExceedMaxMarkupLink>Exceed Max Dealer Markup Report</a>
<a class="btn btn-primary btnStatement" target="_blank" href=@NoReserveLink>No Reserve Loans Report</a>
<a class="btn btn-primary btnStatement" target="_blank" href=@BuyDownLink>Buy Down Loans Report</a>
<a class="btn btn-primary btnStatement" target="_blank" href=@UpfrontDealerBalanceLink>Upfront Dealer Original Balance Report</a>
</div>
@@ -0,0 +1,31 @@
using Blazored.Modal;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using ReserveManagementSystemUI.Helpers;
using Serilog;
namespace ReserveManagementSystemUI.Pages
{
public partial class Statements : ComponentBase
{
[Inject]
IToastService ToastService { get; set; }
[Inject]
IModalService Modal { get; set; }
[Inject]
ServiceHelpers ServiceHelpers { get; set; }
string StatementLink => $"{ServiceHelpers.GetReportServerBaseUrl()}DealerReserveVehicleStatement";
string NoReserveLink => $"{ServiceHelpers.GetReportServerBaseUrl()}DealerReserveBuyDownNoReserveMarkups";
string ExceedMaxMarkupLink => $"{ServiceHelpers.GetReportServerBaseUrl()}DealerReserveExceedMaximumDealerMarkup";
string BuyDownLink => $"{ServiceHelpers.GetReportServerBaseUrl()}BuyDown";
string UpfrontDealerBalanceLink => $"{ServiceHelpers.GetReportServerBaseUrl()}UpfrontDealerBalance";
}
}
@@ -0,0 +1,21 @@
@page "/Test"
@inject IConfiguration Configuration;
@using ReserveManagementSystemUI.Model.Configuration;
@attribute [Authorize(Policy = "IsRMSAssociate")]
<h1>Hidden Page!</h1>
<div class="card card-block-addon">
<div class="card-body">
<h6 class="card-title">Test Logging</h6>
<div class="col-md-8">
<button type="button" class="btn btn-primary" @onclick="TestSeqInfo">Log Information</button>
</div>
<div class="col-md-8">
<button type="button" class="btn btn-primary" @onclick="TestSeqWarn">Log a Warning</button>
</div>
<div class="col-md-8">
<button type="button" class="btn btn-primary" @onclick="TestSeqError">Log an Error</button>
</div>
</div>
</div>
@@ -0,0 +1,32 @@
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Serilog;
namespace ReserveManagementSystemUI.Pages
{
public partial class Test
{
[Inject]
IToastService ToastService { get; set; }
private void TestSeqError()
{
Log.Error("Test error logging from RMS");
ToastService.ShowSuccess("Logged Error");
}
private void TestSeqInfo()
{
Log.Information("Test information logging from RMS");
ToastService.ShowSuccess("Logged Information");
}
private void TestSeqWarn()
{
Log.Warning("Test warning logging from RMS");
ToastService.ShowSuccess("Logged Warning");
}
}
}
@@ -0,0 +1,55 @@
@page "/"
@namespace ReserveManagementSystemUI.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ReserveManagementSystem</title>
<base href="~/" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="_content/Blazored.Toast/blazored-toast.min.css" rel="stylesheet" />
<link href="_content/Blazored.Typeahead/blazored-typeahead.css" rel="stylesheet" />
<link href="_content/Blazored.Modal/blazored-modal.css" rel="stylesheet" />
</head>
<body>
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
@* *******Required in order to use in IE 11.*******
https://docs.microsoft.com/en-us/aspnet/core/blazor/supported-platforms?view=aspnetcore-3.1
https://github.com/Daddoon/Blazor.Polyfill/tree/master/Publish/Blazor.Polyfill.Publish
*@
@if (Request.Headers.TryGetValue("User-Agent", out var userAgents) &&
(userAgents.FirstOrDefault() is string userAgent) &&
System.Text.RegularExpressions.Regex.IsMatch(userAgent, @"MSIE \d|Trident.*rv:"))
{
<script src="js/blazor.polyfill.min.js"></script>
}
<script src="_framework/blazor.server.js"></script>
<script src="_content/Blazored.Typeahead/blazored-typeahead.js"></script>
<script src="_content/Blazored.Modal/blazored.modal.js"></script>
<script src="js/loans.js"></script>
</body>
</html>