Email CC Expriment
Support Request Modify
@page "/supportrequestmodify/{id}"
@inject ISupportRequestService _ISupportRequestService
<MudText Typo="Typo.h4">Modify Support Request</MudText>
<EditForm Model="@_SupportRequest" OnValidSubmit="SupportRequestModifyPage">
<DataAnnotationsValidator />
<MudGrid>
<MudItem xs="12" sm="7">
<MudCard>
<MudCardContent>
<MudTextField Label="Request No" @bind-Value="_SupportRequest.RequestNo"
For="@(() => _SupportRequest.RequestNo)" ReadOnly="true" Variant="Variant.Filled" />
<MudTextField Label="User Name" @bind-Value="_SupportRequest.UserName"
For="@(() => _SupportRequest.UserName)" ReadOnly="true" Variant="Variant.Filled" />
<MudSelect T="string" Dense="true" Label="Select Type" Placeholder="Select Type"
@bind-Value="_SupportRequest.TypeCode" For="@(() => _SupportRequest.TypeCode)"
Validation="@(_SupportRequest.TypeCode)">
@foreach (var listdata2 in supportcombolists.Item1)
{
<MudSelectItem Value="listdata2.TypeCode">@listdata2.TypeName</MudSelectItem>
}
</MudSelect>
<MudSelect T="string" Dense="true" Label="Select Status" Placeholder="Select Status"
@bind-Value="_SupportRequest.StatusCode" For="@(() => _SupportRequest.StatusCode)"
Validation="@(_SupportRequest.StatusCode)">
@foreach (var listdata3 in supportcombolists.Item2)
{
<MudSelectItem Value="listdata3.StatusCode">@listdata3.StatusName</MudSelectItem>
}
</MudSelect>
<MudTextField Label="Subject" Class="mt-3" Lines="2" @bind-Value="_SupportRequest.Subject"
For="@(() => _SupportRequest.Subject)" />
<MudTextField Label="Description" Class="mt-3" Lines="3" @bind-Value="_SupportRequest.Notes"
For="@(() => _SupportRequest.Notes)" />
<MudTextField Label="User Mobile No" @bind-Value="_SupportRequest.MobileNo"
For="@(() => _SupportRequest.MobileNo)" HelperText="In case we want to contact you..." />
@if (userType == "S")
{
<MudTextField Label="Suggestions"
Lines="5" @bind-Value="_SupportRequest.SystemNotes"
For="@(() => _SupportRequest.SystemNotes)" AutoGrow />
@* <MudTextField Label="CC Email" Placeholder="Enter CC Emails separated by semicolon (;)"
Lines="5" @bind-Value="_SupportRequest.EmailCc"
For="@(() => _SupportRequest.EmailCc)" AutoGrow /> *@
<div style="position: relative;">
<MudTextField T="string"
Label="CC Email"
Immediate="true"
Placeholder="Enter CC Emails separated by semicolon (;)"
Value="_SupportRequest.EmailCc"
ValueChanged="HandleCcInput"
OnKeyDown="HandleCcKeyPress"
Lines="3"
style="width: 100%; padding: 12px; font-size: 1rem; font-family: inherit;" />
<div class="ghost-suggestion">@GetCcSuggestionOverlay()</div>
</div>
}
</MudCardContent>
<MudCardActions>
<MudStack Row="true">
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary"
Class="ml-auto" StartIcon="@Icons.Material.Filled.Save">Save</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Default" OnClick="Cancel"
StartIcon="@Icons.Material.Filled.Cancel">Cancel</MudButton>
</MudStack>
</MudCardActions>
</MudCard>
</MudItem>
</MudGrid>
</EditForm>
@code
{
SupportRequest _SupportRequest = new ();
[Parameter]
public string id { get; set; } = string.Empty;
Tuple<List<SupportRequest>, List<SupportRequest>> supportcombolists =
new Tuple<List<SupportRequest>, List<SupportRequest>>
(new List<SupportRequest>(), new List<SupportRequest>());
PostLogin _PostLogin = new ();
public string userType { get; set; } = string.Empty;
public string lastEmailCc = "";
public string? ccPrediction;
List<string> knownEmails = new(); // already loaded in OnInit
protected override async Task OnInitializedAsync()
{
_PostLogin = await _LocalSession.GetItemAsync<PostLogin>("userinfo");
var rolecnt = _IPostLoginService.GetUserRolesCnt(_PostLogin.userdb, "SupportRequest", _PostLogin.dbname);
var usersessionid = _IPostLoginService.GetUserSessionId(_PostLogin.userdb);
usersessionid = usersessionid.Replace("\"", "");
if (_PostLogin.BrowserSessionId != usersessionid)
{
NavManager.NavigateTo("/invaliduser/5");
}
else if (rolecnt > 0)
{
userType = _IPostLoginService.GetUserType(_PostLogin.userdb).Replace("\"", "");
supportcombolists = await _ISupportRequestService.SupportRequestCombo();
_SupportRequest = await _ISupportRequestService.SupportRequestDetails(Convert.ToInt32(id));
knownEmails = await _ISupportRequestService.GetDistinctEmails();
}
else
{
NavManager.NavigateTo("/accessdenied/1");
}
}
public async Task SupportRequestModifyPage()
{
await _ISupportRequestService.SupportRequestModify(_SupportRequest);
NavManager.NavigateTo($"/supportrequestdetails/{Convert.ToInt32(id)}");
}
public void Cancel() => NavManager.NavigateTo($"/supportrequestdetails/{Convert.ToInt32(id)}");
private void HandleCcInput(string value)
{
if (value == lastEmailCc) return;
lastEmailCc = value;
_SupportRequest.EmailCc = value;
ccPrediction = null;
var tokens = value.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
var lastEmail = tokens.LastOrDefault()?.Trim() ?? "";
if (!string.IsNullOrWhiteSpace(lastEmail))
{
var match = knownEmails
.FirstOrDefault(email =>
email.StartsWith(lastEmail, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(email, lastEmail, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(match))
{
ccPrediction = match;
}
}
}
private void HandleCcKeyPress(KeyboardEventArgs e)
{
if (e.Key == "ArrowRight" && !string.IsNullOrWhiteSpace(ccPrediction))
{
var parts = _SupportRequest.EmailCc.Split(';', StringSplitOptions.TrimEntries).ToList();
if (parts.Count > 0)
{
// Replace the last incomplete email with prediction
parts[^1] = ccPrediction!;
_SupportRequest.EmailCc = string.Join(";", parts) + ";";
StateHasChanged();
lastEmailCc = _SupportRequest.EmailCc;
}
ccPrediction = null;
}
}
private string GetCcSuggestionOverlay()
{
if (_SupportRequest.EmailCc == null || ccPrediction == null)
return string.Empty;
var tokens = _SupportRequest.EmailCc.Split(';', StringSplitOptions.None);
var lastEmail = tokens.LastOrDefault() ?? "";
if (!string.IsNullOrWhiteSpace(lastEmail) &&
ccPrediction.StartsWith(lastEmail, StringComparison.OrdinalIgnoreCase))
{
var suffix = ccPrediction.Substring(lastEmail.Length);
return _SupportRequest.EmailCc + suffix;
}
return string.Empty;
}
}
<style>
.ghost-suggestion {
position: absolute;
top: 31px; /* Adjust based on padding of input */
left: 12px;
font-size: 1rem; /* Match input font */
font-family: inherit;
color: gray;
opacity: 0.5;
white-space: pre;
pointer-events: none;
z-index: 1;
}
</style>Support Request Services
Task<List<string>> GetDistinctEmails();
public async Task<List<string>> GetDistinctEmails()
{
return await _HttpClient.GetFromJsonAsync<List<string>>($"api/supportrequest/getdistinctemails")?? new List<string>();
}Support Request Controller
[HttpGet]
public async Task<ActionResult> GetDistinctEmails()
{
return Ok(await _ISupportRequestRepository.GetDistinctEmails());
}Support Request Repository
Task<List<string>> GetDistinctEmails();
public async Task<List<string>> GetDistinctEmails()
{
var query = @"SELECT DISTINCT UserEmail FROM SupportRequest
WHERE Project ='MFG' AND UserEmail IS NOT NULL";
using var connection = _DapperContext.SetCommonConnection();
var data = await connection.QueryAsync<string>(query);
return data.ToList();
}