left-icon

Blazor WebAssembly Succinctly®
by Michael Washington

Previous
Chapter

of
A
A
A

CHAPTER 8

Help Desk Ticket Administration

Help Desk Ticket Administration


In this chapter, we will detail the steps to create the screens that allow the administrators to manage the help desk tickets. In the ticket administration that we will construct, help desk tickets can be updated and deleted, but ticket details that are part of a help desk ticket can only be added and deleted.

Create the Administration page

New Item

Figure 64: New Item

Add the Administration page to the Client project by right-clicking the Pages folder and selecting Add > New Item.

 Add New Item

Figure 65: Add New Item

Select the Razor Component template, name the control Administration.razor, and click Add.

Use the following code for the razor control.

Code Listing 49: Administration.razor

@page "/administration"

@using SyncfusionHelpDeskClient.Shared

@inject HttpClient Http

@inject IHttpClientFactory ClientFactory

@*AuthorizeView control ensures that *@

@*Only users in the Administrators role can view this content*@

<AuthorizeView Roles="Administrators">

</AuthorizeView>

@code {

    #nullable disable

    [CascadingParameter]

    private Task<AuthenticationState> authenticationStateTask { get; set; }

}

Add Link in NavMenu.razor

We will now add a link to the Administration control in the navigation menu.

Open the NavMenu.razor control in the Shared folder of the Client project and remove the following code (for the links to the counter and fetchdata pages).

Code Listing 50: Remove NavMenu Code

    <div class="nav-item px-3">

        <NavLink class="nav-link" href="counter">

            <span class="oi oi-plus" aria-hidden="true"></span> Counter

        </NavLink>

    </div>

    <div class="nav-item px-3">

        <NavLink class="nav-link" href="fetchdata">

            <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data

        </NavLink>

    </div>

Add the following code in its place.

Code Listing 51: Add NavMenu Code

    <AuthorizeView Roles="Administrators">

        <div class="nav-item px-3">

            <NavLink class="nav-link" href="administration">

                <span class="oi oi-plus" aria-hidden="true"></span> Administration

            </NavLink>

        </div>

    </AuthorizeView>

This will display a link to the Administration.razor page, but this link will only display for administrators because it is wrapped in an AuthorizeView control with the Roles property set to Administrators.

Administration Link

Figure 66: Administration Link

When we run the application and log in as the administrator, we see the Administration link. When we click on the link, we are navigated to the Administration page (currently blank).

Using Syncfusion DataGrid

The Syncfusion DataGrid control (programmatically called SfGrid) allows you to display tabular data. We will use it to display the help desk tickets. This control will allow us to page, sort, and trigger editing of the records.

It has a DataSource property that we will bind to a collection of the help desk tickets. It also has properties to allow for paging and sorting.

The control also allows us to define the columns that will contain the tabular data, as well as Edit and Delete buttons.

Enter the following inside the AuthorizeView control tag.

Code Listing 52: DataGrid

<div>

<div id="target" style="height: 500px;">

    <SfGrid ID="Grid"

            DataSource="@colHelpDeskTickets"

            AllowPaging="true"

            AllowSorting="true"

            AllowResizing="true"

            AllowReordering="true">

        <SfDataManager Url="SyncfusionHelpDesk" Adaptor="Adaptors.WebApiAdaptor">

        </SfDataManager>

        <GridPageSettings PageSize="5"></GridPageSettings>

        <GridEvents CommandClicked="OnCommandClicked"

                    TValue="HelpDeskTicket">

        </GridEvents>

        <GridColumns>

            <GridColumn HeaderText="" TextAlign="TextAlign.Left" Width="150">

                <GridCommandColumns>

                    <GridCommandColumn Type=CommandButtonType.Edit

                        ButtonOption="@(new CommandButtonOptions()

                        { Content = "Edit" })">

                    </GridCommandColumn>

                    <GridCommandColumn Type=CommandButtonType.Delete

                        ButtonOption="@(new CommandButtonOptions()

                        { Content = "Delete" })">

                    </GridCommandColumn>

                </GridCommandColumns>

            </GridColumn>

            <GridColumn IsPrimaryKey="true" Field=@nameof(HelpDeskTicket.Id)

                        HeaderText="ID #" TextAlign="@TextAlign.Left"

                        Width="70">

            </GridColumn>

            <GridColumn Field=@nameof(HelpDeskTicket.TicketStatus)

                        HeaderText="Status" TextAlign="@TextAlign.Left"

                        Width="80">

            </GridColumn>

            <GridColumn Field=@nameof(HelpDeskTicket.TicketDate)

                        HeaderText="Date" TextAlign="@TextAlign.Left"

                        Width="80">

            </GridColumn>

            <GridColumn Field=@nameof(HelpDeskTicket.TicketDescription)

                        HeaderText="Description" TextAlign="@TextAlign.Left"

                        Width="150">

            </GridColumn>

            <GridColumn Field=@nameof(HelpDeskTicket.TicketRequesterEmail)

                        HeaderText="Requester" TextAlign="@TextAlign.Left"

                        Width="150">

            </GridColumn>

        </GridColumns>

    </SfGrid>

</div>

</div>

Enter the following in the @code section.

Code Listing 53: DataGrid Code

    // SfDataManager calls the Get method in the SyncfusionHelpDesk

    // controller in the server project that the

    // SfGrid will use to only pull records for the

    // page that is currently selected.

    public IQueryable<HelpDeskTicket> colHelpDeskTickets { get; set; }

    public async void OnCommandClicked(

               CommandClickEventArgs<HelpDeskTicket> args)

    {

        // Code to be added later.

    }    // SfDataManager calls the Get method in the SyncfusionHelpDesk

    // controller in the server project that the

    // SfGrid will use to only pull records for the

    // page that is currently selected.

    public IQueryable<HelpDeskTicket> colHelpDeskTickets { get; set; }

    public async void OnCommandClicked(

               CommandClickEventArgs<HelpDeskTicket> args)

    {

        // Code to be added later.

    }

The SfDataManager control populates the colHelpDeskTickets collection that is bound to the DataSource property of the DataGrid.

DataGrid Control

Figure 67: DataGrid Control

When running the application, log in as an administrator and navigate to the Administration page. We will see the help desk ticket records displayed in the data grid.

Sorting

Figure 68: Sorting

We can sort by clicking the column headers.

Paging

Figure 69: Paging

The grid also enables paging.

Deleting a record

We will implement the functionality to delete a help desk ticket record.

To enable this, the DataGrid control allows us to create custom command buttons using the CommandClicked property that we currently have wired to the OnCommandClicked method.

We will use the OnCommandClicked method to display a dialog box, using the Syncfusion Dialog control, which will require the user to confirm that they want to delete the record.

Syncfusion Dialog

The Dialog control is used to display information and accept user input. It can display as a modal control that requires the user to interact with it before continuing to use any other part of the application.

Enter the following inside the AuthorizeView control tag.

Code Listing 54: Confirm Delete Dialog

<SfDialog Target="#target"

            Width="100px"

            Height="130px"

            IsModal="true"

            ShowCloseIcon="false"

            @bind-Visible="DeleteRecordConfirmVisibility">

    <DialogTemplates>

        <Header> DELETE RECORD ? </Header>

        <Content>

            <div class="button-container">

                <button type="submit"

                        class="e-btn e-normal e-primary"

                        @onclick="ConfirmDeleteYes">

                    Yes

                </button>

                <button type="submit"

                        class="e-btn e-normal"

                        @onclick="ConfirmDeleteNo">

                    No

                </button>

            </div>

        </Content>

    </DialogTemplates>

</SfDialog>

Enter the following in the @code section.

Code Listing 55: Help Desk Ticket Object and Property

    // Global property for the Help Desk Ticket.

    private HelpDeskTicket SelectedTicket = new HelpDeskTicket();

    // Property to control the delete dialog.

    public bool DeleteRecordConfirmVisibility { get; set; } = false;

Change the OnCommandClicked method to the following to respond to the Delete button being clicked for a help desk record.

This method will open the confirmation dialog.

Code Listing 56: Open Confirmation Dialog

    public async void OnCommandClicked(

               CommandClickEventArgs<HelpDeskTicket> args)

    {

        if (args.CommandColumn.ButtonOption.Content == "Delete")

        {

            // We only need the TicketGuid

            // of the selected Help Desk Ticket.

            SelectedTicket = new HelpDeskTicket();

            SelectedTicket.TicketGuid = args.RowData.TicketGuid;

            // Open Delete confirmation dialog.

            this.DeleteRecordConfirmVisibility = true;

            StateHasChanged();

        }

    }

Note: StateHasChanged, used in the preceding code, notifies a component (the Administration page) that its state has changed and causes that component to rerender. This is usually only required when that state was changed by a JavaScript interop call. The Syncfusion Dialog control uses JavaScript interop in the underlying code to open the dialog, so StateHasChanged is required in this case.

Add the following method, which will simply close the dialog if the user clicks the No button on the dialog.

Code Listing 57: Confirmation Close Dialog

    public void ConfirmDeleteNo()

    {

        // Open the dialog

        // to give the user a chance

        // to confirm they want to delete the record.

        this.DeleteRecordConfirmVisibility = false;

    }

Using @ref (capture references to components)

Adding an @ref attribute to a component allows you to programmatically access and manipulate a control or component. To implement it, you add the @ref attribute to a component, then define a field with the same type as the component.

Add the following property to the SfGrid control.

Code Listing 58: DataGrid @ref

@ref="gridObj"

Now, add the following corresponding field to the @code section.

Code Listing 58b: DataGrid Field

    SfGrid<HelpDeskTicket> gridObj;

Now, we can add the following method to delete the record if the user clicks the Yes button in the dialog.

This method will refresh the data grid by calling gridObj.Refresh(), which uses the gridObj object defined with the @ref attribute.

Code Listing 59: Delete Record

    public async void ConfirmDeleteYes()

    {

        // The user selected Yes to delete the

        // selected Help Desk Ticket.

        // Delete the record.

        await Http.DeleteAsync(

            "SyncfusionHelpDesk?HelpDeskTicketGuid=" +

            SelectedTicket.TicketGuid);

        // Close the dialog.

        this.DeleteRecordConfirmVisibility = false;

        StateHasChanged();

        // Refresh the SfGrid

        // so the deleted record will not show.

        await gridObj.Refresh();

    }

When we run the application, we can click Delete to open the dialog.

Figure 70: Delete Confirmation

Clicking the No button will simply close the dialog. Clicking the Yes button will delete the selected record and refresh the data grid.

Edit ticket control

Edit Ticket Control

Figure 71: Edit Ticket Control

We will construct an EditTicket control that will be placed inside a dialog in the Administration page and displayed when an administrator wants to edit a help desk ticket. We do this to allow this control to be reused in the EmailTicketEdit.razor page (covered in the following chapter).

In the Pages folder of the Client project, create a new control called EditTicket.razor using the following code.

Code Listing 60: EditTicket.razor

@using System.Security.Claims;

@using Syncfusion.Blazor.DropDowns

@using SyncfusionHelpDeskClient.Shared

@inject HttpClient Http

@inject IHttpClientFactory ClientFactory

<div>

    <SfDropDownList TItem="HelpDeskStatus" Enabled="!isReadOnly"

                    TValue="string" PopupHeight="230px"

                    Placeholder="Ticket Status"

                    DataSource="@HelpDeskStatus.Statuses"

                    FloatLabelType="@FloatLabelType.Always"

                    @bind-Value="@SelectedTicket.TicketStatus">

        <DropDownListFieldSettings Text="Text"

                                   Value="ID">

        </DropDownListFieldSettings>

    </SfDropDownList>

</div>

<div>

    <SfDatePicker ID="TicketDate" Enabled="!isReadOnly"

                  Placeholder="Ticket Date"

                  FloatLabelType="@FloatLabelType.Always"

                  @bind-Value="@SelectedTicket.TicketDate"

                  Max="DateTime.Now"

                  ShowClearButton="false">

    </SfDatePicker>

</div>

<div>

    <SfTextBox Enabled="!isReadOnly" Placeholder="Ticket Description"

               FloatLabelType="@FloatLabelType.Always"

               @bind-Value="@SelectedTicket.TicketDescription">

    </SfTextBox>

</div>

<div>

    <SfTextBox Enabled="!isReadOnly" Placeholder="Requester Email"

               FloatLabelType="@FloatLabelType.Always"

               @bind-Value="@SelectedTicket.TicketRequesterEmail">

    </SfTextBox>

</div>

@if (SelectedTicket.HelpDeskTicketDetails != null)

{

    @if (SelectedTicket.HelpDeskTicketDetails.Count() > 0)

    {

        <table class="table">

            <thead>

                <tr>

                    <th>Date</th>

                    <th>Description</th>

                </tr>

            </thead>

            <tbody>

                @foreach (var TicketDetail in

               SelectedTicket.HelpDeskTicketDetails)

                {

                    <tr>

                        <td>

                            @TicketDetail.TicketDetailDate.ToShortDateString()

                        </td>

                        <td>

                            @TicketDetail.TicketDescription

                        </td>

                    </tr>

                }

            </tbody>

        </table>

    }

    <SfTextBox Placeholder="NewHelp Desk Ticket Detail"

           @bind-Value="@NewHelpDeskTicketDetailText">

    </SfTextBox>

    <SfButton CssClass="e-small e-success"

          @onclick="AddHelpDeskTicketDetail">

        Add

    </SfButton>

}

<br />

@code {

    #nullable disable

    [CascadingParameter]

    private Task<AuthenticationState> authenticationStateTask { get; set; }

    [Parameter]

    public HelpDeskTicket SelectedTicket { get; set; }

    public bool isReadOnly = true;

    ClaimsPrincipal CurrentUser = new ClaimsPrincipal();

    string NewHelpDeskTicketDetailText = "";

    protected override async Task OnInitializedAsync()

    {

        // Get the current user.

        CurrentUser = (await authenticationStateTask).User;

        // If there is a logged in user

        // they are an Administrator.

        // Enable editing.

        isReadOnly = !CurrentUser.Identity.IsAuthenticated;

    }

    private void AddHelpDeskTicketDetail()

    {

        // Create New HelpDeskTicketDetails record.

        HelpDeskTicketDetail NewHelpDeskTicketDetail =

            new HelpDeskTicketDetail();

        NewHelpDeskTicketDetail.HelpDeskTicketId =

        SelectedTicket.Id;

        NewHelpDeskTicketDetail.TicketDetailDate =

        DateTime.Now;

        NewHelpDeskTicketDetail.TicketDescription =

        NewHelpDeskTicketDetailText;

        // Add to collection.

        SelectedTicket.HelpDeskTicketDetails

            .Add(NewHelpDeskTicketDetail);

        // Clear the Text Box.

        NewHelpDeskTicketDetailText = "";

    }

}

Notice that this exposes a SelectedTicket parameter (of type HelpDeskTicket) that will accept a reference of a help desk ticket record.

In the Administration.razor control, add the following markup to display the EditTicket.razor page in a Dialog control.

Code Listing 61: EditTicket Dialog

<SfDialog Target="#target"

            Width="500px"

            Height="500px"

            IsModal="true"

            ShowCloseIcon="true"

            @bind-Visible="EditDialogVisibility">

    <DialogTemplates>

        <Header> EDIT TICKET # @SelectedTicket.Id</Header>

        <Content>

            <EditTicket SelectedTicket="@SelectedTicket" />

        </Content>

        <FooterTemplate>

            <div class="button-container">

                <button type="submit"

                        class="e-btn e-normal e-primary"

                        @onclick="SaveTicket">

                    Save

                </button>

            </div>

        </FooterTemplate>

    </DialogTemplates>

</SfDialog>

Note that this instantiates the EditTicket control (the EditTicket.razor code page) and passes a reference to the currently selected help desk ticket record (@SelectedTicket) through the SelectedTicket attribute.

Add the following to the @code section to implement the functionality for the Save button on the dialog.

Code Listing 62: SaveTicket Method

    public bool EditDialogVisibility { get; set; } = false;

    public async Task SaveTicket()

    {

        // Update the selected Help Desk Ticket.

        await Http.PutAsJsonAsync(

        "SyncfusionHelpDesk", SelectedTicket);

        // Close the Edit dialog.

        this.EditDialogVisibility = false;

        // Refresh the SfGrid

        // so the changes to the selected

        // Help Desk Ticket are reflected.

        await gridObj.Refresh();

    }

Next, add the following code to the OnCommandClicked method to open the dialog when the Edit button is clicked on a row in the data grid.

Code Listing 63: Open Dialog

        if (args.CommandColumn.ButtonOption.Content == "Edit")

        {

            // Get the selected Help Desk Ticket.

            SelectedTicket =

                await Http.GetFromJsonAsync<HelpDeskTicket>(

                    "Email?HelpDeskTicketGuid=" +

                    args.RowData.TicketGuid);

            // Open the Edit dialog.

            this.EditDialogVisibility = true;

            StateHasChanged();

        }

Finally, in the Server project, create a new class in the Controllers folder called EmailController.cs using the following code.

Code Listing 64: EmailController.cs

#nullable disable

using System;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Mvc;

using Microsoft.EntityFrameworkCore;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.Primitives;

using SyncfusionHelpDeskClient.Shared;

namespace SyncfusionHelpDesk.Data

{

    [ApiController]

    [Route("[controller]")]

    public class EmailController : ControllerBase

    {

        private readonly IConfiguration configuration;

        private readonly IHttpContextAccessor httpContextAccessor;

        private readonly SyncfusionHelpDeskContext _context;

        public EmailController(

            IConfiguration Configuration,

            IHttpContextAccessor HttpContextAccessor,

            SyncfusionHelpDeskContext context)

        {

            configuration = Configuration;

            httpContextAccessor = HttpContextAccessor;

            _context = context;

        }

        [HttpGet]

        [AllowAnonymous]

        public object Get()

        {

            // Return only one ticket.

            StringValues HelpDeskTicketGuidProperty;

            string HelpDeskTicketGuid =

                (Request.Query.TryGetValue("HelpDeskTicketGuid",

                out HelpDeskTicketGuidProperty))

                ? HelpDeskTicketGuidProperty.ToString() : "";

            var ExistingTicket = _context.HelpDeskTickets

                .Include(x => x.HelpDeskTicketDetails)

                .Where(x => x.TicketGuid == HelpDeskTicketGuid)

                .FirstOrDefault();

            return ExistingTicket;

        }  

    }

}

This EmailController class is called by the OnCommandClicked method in the Administration.razor control to get the details of the currently selected record so that it can be displayed in the dialog and updated.

This class will later be expanded when we add email functionally, in the next chapter.

Edit Ticket Dialog

Figure 72: Edit Ticket Dialog

When we run the application, we can click Edit next to a record to open it up in the dialog.

Any of the help desk ticket values at the top of the form can be edited and saved by clicking Save at the bottom of the dialog.

Near the bottom of the form, help desk ticket detail records can be added by entering text in the text box and clicking Add.

Edit Ticket

Figure 73: Edit Ticket

The help desk detail record will be added, but it will not be saved until the Save button is clicked.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.