@using Indotalent.ConfigBackEnd.Extensions @using Indotalent.Features.Pipeline.Lead @using Indotalent.Features.Pipeline.Lead.Cqrs @using Microsoft.AspNetCore.Components.Web @using Microsoft.JSInterop @using MudBlazor @using Features.Root.Shared @using ClosedXML.Excel @using System.IO @inject LeadService LeadService @inject IDialogService DialogService @inject ISnackbar Snackbar @inject IJSRuntime JSRuntime
Lead Management Manage business opportunities and sales pipeline.
/ Pipeline / Lead
Search
@if (_isExporting) { } else { Excel } @if (_isRefreshing) { Refreshing... } else { Refresh } @if (_selectedLead != null) { View Edit Remove } else { Add New Lead }
Number Title Company Stage Closing Status @context.AutoNumber @context.Title @context.CompanyName @context.PipelineStage @context.ClosingStatus
Rows per page: Showing @(GetFilteredData().Count() == 0 ? 0 : _skip + 1)-@Math.Min(_skip + _top, GetFilteredData().Count()) of @GetFilteredData().Count()
Prev @{ var totalPages = _totalPage == 0 ? 1 : _totalPage; var maxVisible = 5; var startPage = Math.Max(1, _currentPage - maxVisible / 2); var endPage = Math.Min(totalPages, startPage + maxVisible - 1); if (endPage - startPage < maxVisible - 1) { startPage = Math.Max(1, endPage - maxVisible + 1); } } @for (int i = startPage; i <= endPage; i++) { var pageNum = i; var isActive = pageNum == _currentPage; @pageNum } Next
@code { [Parameter] public EventCallback OnAdd { get; set; } [Parameter] public EventCallback OnEdit { get; set; } [Parameter] public EventCallback OnView { get; set; } private List _leads = new(); private GetLeadListResponse? _selectedLead; private string _searchString = ""; private bool _isRefreshing = false; private bool _isExporting = false; private int _skip = 0; private int _top = 5; private int _totalPage => GetFilteredData().Count() == 0 ? 0 : (int)Math.Ceiling((double)GetFilteredData().Count() / (_top == 0 ? 1 : _top)); private int _currentPage => (_top >= GetFilteredData().Count() || _top == 0) ? 1 : (_skip / _top) + 1; protected override async Task OnInitializedAsync() => await LoadData(); private async Task LoadData() { _isRefreshing = true; _selectedLead = null; StateHasChanged(); var response = await LeadService.GetLeadListAsync(); await Task.Delay(500); if (response != null && response.IsSuccess) { _leads = response.Value ?? new List(); } _isRefreshing = false; StateHasChanged(); } private IEnumerable GetFilteredData() { if (string.IsNullOrWhiteSpace(_searchString)) return _leads; return _leads.Where(x => (x.Title?.Contains(_searchString, StringComparison.OrdinalIgnoreCase) ?? false) || (x.CompanyName?.Contains(_searchString, StringComparison.OrdinalIgnoreCase) ?? false) || (x.AutoNumber?.Contains(_searchString, StringComparison.OrdinalIgnoreCase) ?? false) ); } private IEnumerable GetPagedData() => GetFilteredData().Skip(_skip).Take(_top); private void OnSearchClick() { _skip = 0; _selectedLead = null; StateHasChanged(); } private void HandleSearchKeyDown(KeyboardEventArgs e) { if (e.Key == "Enter") OnSearchClick(); } private async Task ExportToExcel() { _isExporting = true; using var workbook = new XLWorkbook(); var worksheet = workbook.Worksheets.Add("Leads"); var currentRow = 1; worksheet.Cell(currentRow, 1).Value = "Number"; worksheet.Cell(currentRow, 2).Value = "Title"; worksheet.Cell(currentRow, 3).Value = "Company"; worksheet.Cell(currentRow, 4).Value = "Stage"; foreach (var item in GetFilteredData()) { currentRow++; worksheet.Cell(currentRow, 1).Value = item.AutoNumber; worksheet.Cell(currentRow, 2).Value = item.Title; worksheet.Cell(currentRow, 3).Value = item.CompanyName; worksheet.Cell(currentRow, 4).Value = item.PipelineStage.ToString(); } worksheet.Columns().AdjustToContents(); using var stream = new MemoryStream(); workbook.SaveAs(stream); var content = Convert.ToBase64String(stream.ToArray()); await JSRuntime.InvokeVoidAsync("downloadFile", "Lead_List.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", content); _isExporting = false; } private void OnPageChanged(int page) { if (page >= 1 && page <= _totalPage) { _skip = (page - 1) * _top; _selectedLead = null; } } private void OnPageSizeChanged(int size) { _top = size; _skip = 0; _selectedLead = null; } private async Task InvokeEdit() { if (_selectedLead != null) { var req = await MapToRequest(_selectedLead.Id!); if (req != null) await OnEdit.InvokeAsync(req); } } private async Task InvokeView() { if (_selectedLead != null) { var req = await MapToRequest(_selectedLead.Id!); if (req != null) await OnView.InvokeAsync(req); } } private async Task MapToRequest(string id) { var res = await LeadService.GetLeadByIdAsync(id); if (res != null && res.IsSuccess && res.Value != null) { var d = res.Value; return new UpdateLeadRequest { Id = d.Id, Title = d.Title, Description = d.Description, CompanyName = d.CompanyName, CompanyDescription = d.CompanyDescription, CompanyAddressStreet = d.CompanyAddressStreet, CompanyAddressCity = d.CompanyAddressCity, CompanyAddressState = d.CompanyAddressState, CompanyAddressZipCode = d.CompanyAddressZipCode, CompanyAddressCountry = d.CompanyAddressCountry, CompanyPhoneNumber = d.CompanyPhoneNumber, CompanyFaxNumber = d.CompanyFaxNumber, CompanyEmail = d.CompanyEmail, CompanyWebsite = d.CompanyWebsite, CompanyWhatsApp = d.CompanyWhatsApp, CompanyLinkedIn = d.CompanyLinkedIn, CompanyFacebook = d.CompanyFacebook, CompanyInstagram = d.CompanyInstagram, CompanyTwitter = d.CompanyTwitter, DateProspecting = d.DateProspecting, DateClosingEstimation = d.DateClosingEstimation, DateClosingActual = d.DateClosingActual, AmountTargeted = d.AmountTargeted, AmountClosed = d.AmountClosed, BudgetScore = d.BudgetScore, AuthorityScore = d.AuthorityScore, NeedScore = d.NeedScore, TimelineScore = d.TimelineScore, PipelineStage = d.PipelineStage, ClosingStatus = d.ClosingStatus, ClosingNote = d.ClosingNote, CampaignId = d.CampaignId, SalesTeamId = d.SalesTeamId, CreatedAt = d.CreatedAt, CreatedBy = d.CreatedBy, UpdatedAt = d.UpdatedAt, UpdatedBy = d.UpdatedBy }; } return null; } private async Task OnDelete() { if (_selectedLead == null) return; var parameters = new DialogParameters<_DeleteConfirmation> { { x => x.ContentText, _selectedLead.Title } }; var dialog = await DialogService.ShowAsync<_DeleteConfirmation>("", parameters, new DialogOptions { MaxWidth = MaxWidth.ExtraSmall, FullWidth = true }); var result = await dialog.Result; if (result != null && !result.Canceled) { if (await LeadService.DeleteLeadByIdAsync(_selectedLead.Id!)) { await LoadData(); Snackbar.Add("Deleted", Severity.Success); } } } }