Open Closed

Linked Accounts Return to Previous Page #6852


User avatar
0
dhill created
  • ABP Framework version: v8.0.4
  • UI Type: Blazor Server
  • Database System: EF Core (SQL Server)

Is it possible to bypass the "My Account" page with the linked account module and instead return directly to the previously opened page?


9 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    We considered this issue, but it would cause problems if the linked account did not have permissions, so we gave up

  • User Avatar
    0
    dhill created

    Is there any way we can streamline it or reduce the number of clicks? Any suggestions on how we can improve the user experience?

    Basically can you think of any recommendations that we could apply in a reasonable fashion?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Sorry, maybe I misunderstand.

    Do you mean to open the linked account modal directly instead of redirecting to my account first? Right?

  • User Avatar
    0
    dhill created

    Yes that would be helpful.

    Basically the goal is to reduce the number of clicks that a user has to do to change accounts across tenants.

    So imagine a scenario where the user is on an invoices page and they want to enter invoices for one tenant and then quickly switch to another tenant and add invoices there as well.

    The current navigation is kind of clicky and involves multiple steps to switch tenants.

    The goal would be something that is a little bit more like say Gmail for example where you can switch back and forth with ease and few clicks.

    And I understand that there are some technical challenges and limitations from what I initially asked.

    Therefore with the goals that we have in mind are there any easy wins that we can implement as an alternative?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    You can make it yourself

    You can add a user menu:

    https://docs.abp.io/en/abp/latest/UI/Blazor/Navigation-Menu#standard-menus

    The user menu can be a Blazor component, for example:

    context.Menu.Items.Add(
      new ApplicationMenuItem("LinkedAccounts", "Linked Accounts", "#")
        .UseComponent(typeof(LinkedAccountComponent)));
    

    Then you can inject the IIdentityLinkUserAppService service to get the account list.

  • User Avatar
    0
    Sturla created

    I implemented this as I understood you guys. I think it would be rather easy to add the users into the dropdown so you would only need one click to switch.

    This modal has a button to switch

    @using Volo.Abp.Account
    @using Volo.Abp.Data
    @using Volo.Abp.Domain.Repositories
    @using Volo.Abp.Identity
    @using Volo.Abp.MultiTenancy
    @using Volo.Abp.Users
    @inject ICurrentTenant CurrentTenant
    @inject ICurrentUser CurrentUser
    @inject NavigationManager NavigationManager
    @inject IIdentityLinkUserAppService IdentityLinkUserAppService
    @inject IJSRuntime JsRuntime
    
    <form method="post" action="Account/LinkLogin" id="LinkLoginForm" hidden>
        <input type="hidden" name="SourceLinkUserId" value="@CurrentUser.Id">
        <input type="hidden" name="SourceLinkTenantId" value="@CurrentTenant.Id">
        <input type="hidden" id="SourceLinkToken" name="SourceLinkToken">
        <input type="hidden" id="TargetLinkUserId" name="TargetLinkUserId">
        <input type="hidden" id="TargetLinkTenantId" name="TargetLinkTenantId">
        <input type="hidden" name="ReturnUrl">
    </form>
    
    @if (linkedAccounts != null)
    {
        <li class="outer-menu-item" id="MenuItem_LinkedAccounts" @onclick="@ShowModal" style="cursor:pointer;">
            <a class="lpx-menu-item-link">
                <span class="lpx-menu-item-icon">
                    <i class="lpx-icon fa fa-exchange-alt" aria-hidden="true"></i>
                </span>
                <span class="lpx-menu-item-text">Switch Account</span>
            </a>
        </li>
    }
    
    <Modal @ref="modalRef">
        <ModalContent>
            <ModalHeader>
                <ModalTitle>Switch Account</ModalTitle>
                <CloseButton Clicked="@HideModal" />
            </ModalHeader>
            <ModalBody>
                @if (linkedAccounts == null)
                {
                    <Text> Loading... </Text>
                }
                else
                {
                    foreach (var account in linkedAccounts)
                    {
                        <Button Color="Color.Light" Size="Size.ExtraSmall" Clicked="() => SwitchToAccount(account)">
                            Switch to Tenant: @account.TargetTenantName (user: @account.TargetUserName)
                        </Button>
                    }
                }
            </ModalBody>
            <ModalFooter>
                <Button Color="Color.Secondary" Clicked="@HideModal">Close</Button>
            </ModalFooter>
        </ModalContent>
    </Modal>
    
    @code {
        private List<LinkUserDto> linkedAccounts = new();
    
        public LinkedAccountComponent(IRepository<IdentityUser, Guid> userRepository)
        {
            this.userRepository = userRepository;
        }
    
        private readonly IRepository<IdentityUser, Guid> userRepository;
        private Modal modalRef = new();
    
        protected override async Task OnInitializedAsync()
        {
            linkedAccounts = (await IdentityLinkUserAppService.GetAllListAsync()).Items.ToList();
        }
    
        public async Task SwitchToAccount(LinkUserDto linkedAccount)
        {
            // Generating SourceLinkToken
            var sourceLinkToken = await IdentityLinkUserAppService.GenerateLinkLoginTokenAsync();
    
            await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('SourceLinkToken').value = '" + sourceLinkToken + "'");
            await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('TargetLinkUserId').value = '" + linkedAccount.TargetUserId + "'");
            await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('TargetLinkTenantId').value = '" + linkedAccount.TargetTenantId + "'");
            await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('LinkLoginForm').submit()");
    
            await HideModal();
        }
    
        private Task ShowModal()
        {
            return modalRef.Show();
        }
    
        private Task HideModal()
        {
            return modalRef.Hide();
        }
    }
    

    and ConfigureMenuAsync in the IMenuContributor

        public async Task ConfigureMenuAsync(MenuConfigurationContext context)
       {
           if (context.Menu.Name == StandardMenus.Main)
           {
               await ConfigureMainMenuAsync(context);
           }
           else if (context.Menu.Name == StandardMenus.User)
           {
               await ConfigureUserMenuAsync(context);
           }
       }
       
       private async Task ConfigureUserMenuAsync(MenuConfigurationContext context)
       {
           context.Menu.Items.Add(
             new ApplicationMenuItem("LinkedAccounts", "Linked Accounts", "#")
               .UseComponent(typeof(LinkedAccountComponent)));
               
           await Task.CompletedTask.ConfigureAwait(false);
       }
    

    Is this code valid @liangshiwei AND how should you do the actual switching?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    You can try:

    
    <form method="post" action="Account/LinkLogin" id="LinkLoginForm" hidden>
        <input type="hidden" name="SourceLinkUserId" value="@CurrentUser.Id">
        <input type="hidden" name="SourceLinkTenantId" value="@CurrentTenant.Id">
        <input type="hidden" id="SourceLinkToken" name="SourceLinkToken">
        <input type="hidden" id="TargetLinkUserId" name="TargetLinkUserId">
        <input type="hidden" id="TargetLinkTenantId" name="TargetLinkTenantId">
        <input type="hidden" name="ReturnUrl">
    </form>
    
    
    .......................
    
    public async Task SwitchToAccount(LinkedAccount linkedAccount)
    {
        // Generating SourceLinkToken
        var sourceLinkToken = await IdentityLinkUserAppService.GenerateLinkLoginTokenAsync();
    
        // HERE TENANTID AND TARGETENANTID ARE NULL
        
        await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('SourceLinkToken').value = '" + sourceLinkToken + "'");
        await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('TargetLinkUserId').value = '" + linkedAccount.TargetUserId + "'");
        await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('TargetLinkTenantId').value = '" + linkedAccount.TargetTenantId + "'");
        await JsRuntime.InvokeVoidAsync("eval", "document.getElementById('LinkLoginForm').submit()");
    }
    
  • User Avatar
    0
    Sturla created

    It is almost working but something is off..

    I updated my code example with yours.

    Am I pulling the correct values? I have connected gg and ss..

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    should be await IdentityLinkUserAppService.GenerateLinkLoginTokenAsync();

    not

    await IdentityLinkUserAppService.GenerateLinkTokenAsync()

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11