Login flow with shell

Eduardo Gomez 3,426 Reputation points
2024-02-28T21:32:13.65+00:00

I have an App shell view model.

public partial class AppShellViewModel(IAppService appService) : BaseViewModel {
    [ObservableProperty]
    User? user;
    [ObservableProperty]
    bool isCoordinator;
    [ObservableProperty]
    bool isStudent;
    [ObservableProperty]
    bool isTeacher;
    [ObservableProperty]
    bool isRegisterOpen;
    [RelayCommand]
    async Task SignOut() {
        SecureStorage.Default.RemoveAll();
        await appService.NavigateBack();
    }


that receives a user, to give me the options that I have available.

   <FlyoutItem
       Title="Notifications"
       IsVisible="{Binding IsTeacher}">
       <ShellContent
           ContentTemplate="{DataTemplate view:NotificationsPage}"
           Route="NotificationsPage" />
   </FlyoutItem>
   <ShellContent
       ContentTemplate="{DataTemplate view:LoginPage}"
       Route="LoginPage"
       Shell.FlyoutBehavior="Disabled"
       Shell.FlyoutItemIsVisible="False" />
   <ShellContent
       ContentTemplate="{DataTemplate view:WelcomePage}"
       Route="WelcomePage"
       Shell.FlyoutItemIsVisible="False" />
   <FlyoutItem
       Title="My courses"
       IsVisible="{Binding IsStudent}">
       <ShellContent
           ContentTemplate="{DataTemplate view:CoursesPage}"
           Route="CoursesPage" />
   </FlyoutItem>
   <FlyoutItem Title="Join Meeting">
       <ShellContent
           ContentTemplate="{DataTemplate view:JoinMeetingPage}"
           Route="JoinMeetingPage" />
   </FlyoutItem>
   <FlyoutItem
       Title="New lecture"
       IsVisible="{Binding IsTeacher}">
       <ShellContent
           ContentTemplate="{DataTemplate view:NewLecturePage}"
           Route="NewLecturePage" />
   </FlyoutItem>
   <FlyoutItem
       Title="New test"
       IsVisible="{Binding IsTeacher}">
       <ShellContent
           ContentTemplate="{DataTemplate view:NewTestPage}"
           Route="NewTestPage" />
   </FlyoutItem>
   <FlyoutItem
       Title="Schedule lecture"
       IsVisible="{Binding IsTeacher}">
       <ShellContent
           ContentTemplate="{DataTemplate view:ScheduleLecturePage}"
           Route="ScheduleLecturePage" />
   </FlyoutItem>
   <FlyoutItem
       Title="Schedule test"
       IsVisible="{Binding IsTeacher}">
       <ShellContent
           ContentTemplate="{DataTemplate view:ScheduleTestPage}"
           Route="ScheduleLecturePage" />
   </FlyoutItem>
   <FlyoutItem
       Title="Manage courses"
       IsVisible="{Binding IsCoordinator}">
       <ShellContent
           ContentTemplate="{DataTemplate view:ManageCoursePage}"
           Route="ManageCoursePage" />
   </FlyoutItem>


and then I have the app, and login view model.

public partial class App : Application {
    private readonly IAppService _appService;
    private readonly IAuthenticationService _authenticationService;
    private readonly IDataService<User> _dataService;
    private readonly AppShellViewModel _shellViewModel;
    public App(IAppService appService, IAuthenticationService authenticationService,
        IDataService<User> dataService, AppShellViewModel shellViewModel) {
        InitializeComponent();
        Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(Constants.LICENSE);
        _appService = appService;
        _authenticationService = authenticationService;
        _dataService = dataService;
        _shellViewModel = shellViewModel;
    }
    protected override async void OnStart() {
        base.OnStart();
        await InitializeApp();
    }
    private async Task InitializeApp() {
        MainPage = await DetermineInitialPage();
    }
    private async Task<Page> DetermineInitialPage() {
        var currentUserEmail = await SecureStorage.GetAsync("CurrentUser");
        if(string.IsNullOrEmpty(currentUserEmail)) {
            // No token found, navigate to the login page
            return new LoginPage(new LoginPageViewModel(_dataService, _appService, _authenticationService, _shellViewModel));
        } else {
            // Token found, navigate to the WelcomePage within the Shell
            return new AppShell(_shellViewModel, _appService);
        }
    }


and the method to manaage Visibility base on role

 public static async Task ManageFlyoutItemsVisibility(AppShellViewModel appShellViewModel,
        IDataService<User> dataService, string userUID, IAppService appService) {
        var UsersList = await dataService.GetAllAsync<User>("Users");
        var currentUser = UsersList.FirstOrDefault(user => user.Object.Email == userUID)?.Object;
        if(currentUser != null) {
            switch(currentUser.Role) {
                case nameof(Roles.Coordinator):
                    appShellViewModel.IsCoordinator = true;
                    break;
                case nameof(Roles.Teacher):
                    appShellViewModel.IsTeacher = true;
                    break;
                case nameof(Roles.Student):
                    appShellViewModel.IsStudent = true;
                    break;
            }
            appShellViewModel.User = currentUser;
            await appService.NavigateTo($"//{nameof(WelcomePage)}", true);
        } else {
            // Handle the case where currentUser is null (e.g., user not found)
            // You might want to show an error message or take appropriate action
        }
    }

and this is called from the login

public partial class LoginPageViewModel(IDataService<User> dataService, IAppService appService,
    IAuthenticationService authenticationService, AppShellViewModel appShellViewModel) : BaseViewModel {
    [ObservableProperty]
    bool isPopOpen;
    [ObservableProperty]
    User user = new();
    [RelayCommand]
    void OpenPopUp() {
        IsPopOpen = true;
    }
    [RelayCommand]
    async Task Login() {
        IsBusy = true;
        //var user = await authenticationService.LoginWithEmailAndPassword(User.Email!, User.Password!);
        var user = await authenticationService.LoginWithEmailAndPassword("admin@xxx.com", "123456");
        if(user != null) {
            await SecureStorage.SetAsync("CurrentUser", user.Info.Email);
            await RoleVisibility.ManageFlyoutItemsVisibility(appShellViewModel, dataService, "admin@xxxxx.com", appService);
            //await RoleVisibility.ManageFlyoutItemsVisibility(appShellViewModel, dataService, User.Email!, appService);
        }
        IsBusy = false;
    }


the problems the following On dependency container, I was registering every page and view Model as a singleton, and I was getting errors when navigating, I changed everything to transient, and no I don't see any options in the menu, just the join page that can be viewed by all roles. furthermore, if I put a breakpoint n App.xaml.cs and another one in the AppShellViewMode, it the breakpoint in the AppShell will activate firsts, and that why I cannot see any options.

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
3,409 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.