Login flow with shell
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.