Finishing touches (Angular)

In this final part of the CRM tutorial we will add a few final features that will make the CRM application more polished.

  • Customize the navigation.
  • Show the current user picture.
  • Allow the current user to update his personal details - first name, last name and picture.
  • Create custom design for the login page.

Customize the navigation

We will rearrange the navigation, create a hierarchy, and add icons.

The application navigation typically lives in the Main layout. Layouts are special pages that define common UI components that are shared between multiple pages.

  1. Open the Main layout in Radzen.
  2. Select the PanelMenu component. Click the button to open the Navigation item editor.
  3. By default it doesn’t display any items because it shows all pages that are marked as “include in navigation” (add and edit pages are excluded by default).
  4. Click the refresh button to create items for all pages in the application.
  5. Remove the Opportunity statuses, Task Statuses and Task Types pages. We will add them later under a common parent.
  6. Move the Home page to the top so it appears first. Set Text to Dashboard and Icon to home.
  7. Move the Contacts page so it appears second. Set the Icon to perm_contact_calendar.
  8. Make the Tasks page third and set the Icon to work.
  9. Make Opportunities fourth and set the Icon to shopping_cart.
  10. Add a new item with Text Settings and Icon: settings. Set the Visible property to ${security.user.isInRole("Sales Manager")}. This makes this item visible only to members of the Sales Manager role.
  11. Add a child item with Text Opportunity Statuses and pick the Opportunity Statuses page from the Path dropdown.
  12. Then add another child with Text Task Types and pick the Task Types page from the Path dropdown.
  13. Finally add one last child for the Task Statuses page.

Now when a member of the Sales Manager role logs in she would see this navigation. Members of the Sales Representative role will see this (not that the Settings menu item is not present).

Show the current user picture

By default the Main layout has a ProfileMenu component which allows users to logout or update their profile. Let’s customize the ProfileMenu to show the current user name and profile picture.

Get the user details

First we have to retrieve the current user details - FirstName, LastName and Picture from the database. The easiest and most secure way to do that is via custom method.

  1. Open server\project.csproj with Vusual Studio (or the server directory with Visual Studio Code).
  2. Open server\Controllers\ServerMethodsController.cs.
  3. Decorate the ServerMethodsController class with the Authorize attribute. It is mandatory for getting the currently logged user via the ASP.NET Core Identity framework.
    [Authorize(AuthenticationSchemes = "Bearer")]
    public class ServerMethodsController : Controller
    {
       /* snip */
    }
    
  4. Inject an instance of the UserManager ASP.NET Core Identity class.
    private readonly UserManager<ApplicationUser> userManager;
    
    public ServerMethodsController(CrmContext context, UserManager<ApplicationUser> userManager)
    {
        this.context = context;
        this.userManager = userManager;
    }
    
  5. Create a method that returns the current user data.
    public IActionResult UserPersonalData()
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;
        var user = userManager.FindByIdAsync(userId).GetAwaiter().GetResult();
    
        return Json(new
        {
            FirstName = user.FirstName,
            LastName = user.LastName,
            Picture = user.Picture
        }, new JsonSerializerSettings()
        {
            ContractResolver = new DefaultContractResolver()
        });
    }
    

Now that we a custom method we can invoke it and store the user details in a page property.

  1. Open the Main layout.
  2. Add a new handler for the page Load event.
  3. Invoke the UserPersonalData custom method.
  4. Handle the Then event and create a page property called userData with the ${result}.

Time to update the ProfileMenu.

  1. Select the ProfileMenu component.
  2. Click the Edit template button.
  3. Delete the Gravatar component.
  4. Drag and drop a Label and an Image.
  5. Set the Text of the Label to ${userData.FirstName} ${userData.LastName}.
  6. Set the Path of the Image to ${userData.Picture}. Set Width and Height to 32px and BorderRadius to 16px.
  7. End template editing.

If you run the application from Radzen you will see the current user picture and name in the top right corner.

Update user details

When you enable security for a Radzen application one of the scaffolded pages is Profile (also accessible from the ProfileMenu component in the top right corner). By default it allows the current user to change their password. In the CRM application we have extended the AspNetUsers table with three new columns - FirstName, LastName, Picture and we want the user to be able to change them.

Update the user details

First we will create a custom method that updates the details of the current user.

  1. Open server\project.csproj with Vusual Studio (or the server directory with Visual Studio Code).
  2. Open server\Controllers\ServerMethodsController.cs.
  3. Add the following method which will update the current user details.
    [HttpPost]
    public IActionResult UpdatePersonalData(string firstName, string lastName, string picture)
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;
        var user = userManager.FindByIdAsync(userId).GetAwaiter().GetResult();
    
        user.FirstName = firstName;
        user.LastName = lastName;
        user.Picture = picture;
    
        var result = userManager.UpdateAsync(user).GetAwaiter().GetResult();
    
        if (result == IdentityResult.Success)
        {
            return Ok();
        }
        else
        {
            var message =  string.Join(", ", result.Errors.Select(error => error.Description));
    
            return BadRequest(new { error = new { message }});
        }
    }
    

Create the UI

Now let’s create the UI.

  1. Open the Profile page in Radzen.
  2. Drag and drop a Tabs component.
  3. Add two items: Personal and Password.
  4. Select the Password item and move the existing Form there.
  5. Delete the now empty Row.
  6. Select the Personal tab and drag and drop a new Form inside.
  7. Add the following form fields
    • Property: FirstName, Title: First Name, Required: Checked.
    • Property: LastName, Title: Last Name, Required: Checked
    • Property: Picture, Title: Picture, Type: file, Required: Checked
  8. Let’s now populate the form. Invoke the UserPersonalData custom method and create a property called personalData set to ${result}.
  9. Set the Data property of the form to ${personalData}. This will data-bind the form to the personalData property - the form fields will show the corresponding members of the personalData page property.

The final step is to use the UpdatePersonalData method when the user submits the form.

  1. Add a new handler for the form Submit event.
  2. Ivoke the UpdatePersonalData custom method.
    • Set the firstName parameter to ${event.FirstName}
    • Set the lastName parameter to ${event.LastName}
    • Set the picture parameter to ${event.Picture}
  3. Display a notification in the Then event to let the user know that their details have been updated.
  4. Display a notification in case of an error.

Custom login page

Finally let’s create a custom login page by editing both the Login layout and page.

Login layout

We will add a background image that will cover the whole page. Also we will add the CRM application logo.

Add the assets

Radzen allows you to use images seamlessly. For this demo we will use a background and logo. Download those files and add them as assets in the application.

Set the background image

  1. Open the Login layout.
  2. Drag an Image component and drop it before the existing row component.
  3. Set the Path of the image to login-background.png (click to use the asset picker).
  4. Set Width and Height to 100%. Set Position to absolute. Set Top and Left to 0. This will make the image cover the whole page.

Center the row

We now want to center the login form in the page (both horizontally and vertically).

  1. Select the Row component.
  2. Set Horizontal Alignment and Vertical Alignment to Center.
  3. Go to the Style tab. Set Position to absolute, Top, Right, Bottom and Left to 0. Set Margin to 0.

Specify column settings

  1. Select the Column component.
  2. Set the XL size to 3 units, LG to 4, MD to 5 and SM to 8.
  3. Set Vertical Alignment and Horizontal Alignment to None.
  4. Go to the Style tab and set Padding to 0px.
  1. Drag an Image component and drop it in the Card component.
  2. Set Path to logo.png.
  3. Set Width and Height to 128px. Set BorderRadius to 64px. This will make the logo a circle.
  4. Let’s center the image. Set Display to block. Set Right and Left Margin to auto.
  5. Now let’s make the image pop out of the card a bit. Set Top Margin to -72px.

Login page

Let’s now customize the Login page by using a TemplateForm instead of the Login component.

Create the login form

  1. Open the Login page.
  2. Delete the existing Login component and its parent row and column.
  3. Drag and drop a TemplateForm then delete its content.
  4. Drag and drop a TextBox inside the TemplateForm. Set its Name to Username and Width to 100%. Set top Margin to 16px.
  5. Drag a Label before the TextBox. Set its Text to Username and pick Username from the Component dropdown. Set Display to block so the TextBox starts on the next line.
  6. Drag and drop a Password. Set its Name to Password and Width to 100%.
  7. Duplicate the Label. Set Text and Component to Password.
  8. Drag and drop a Button. Set Text to Login, ButtonType to submit, Width to 100% and top Margin to 16px.

Perform the login

Now to actually perform the login.

  1. Handle the Submit event of the Template form.
  2. Invoke the login data source method. Set the username parameter to ${event.Username} and password to ${event.Password}.
  3. Handle the Error event and display a notification if the login fails for some reason.

That is all!

Complete source

The complete source of this application (with a few additional changes that are mostly cosmetic) is available in the Radzen github repository.