diff --git a/AppShell.xaml b/AppShell.xaml
index 8b97a0d..edeea18 100644
--- a/AppShell.xaml
+++ b/AppShell.xaml
@@ -12,6 +12,11 @@
+
+
();
+ builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
diff --git a/Models/User.cs b/Models/User.cs
new file mode 100644
index 0000000..1cf7ac9
--- /dev/null
+++ b/Models/User.cs
@@ -0,0 +1,58 @@
+using SQLite;
+using System.ComponentModel;
+
+namespace UndacApp.Models
+{
+ public class User : AModel
+ {
+ private string _name;
+ public string Name
+ {
+ get => _name;
+ set => SetField(ref _name, value);
+ }
+
+ private string _email;
+ public string Email
+ {
+ get => _email;
+ set => SetField(ref _email, value);
+ }
+
+ private string _accessLevel;
+ public string AccessLevel
+ {
+ get => _accessLevel;
+ set => SetField(ref _accessLevel, value);
+ }
+
+ private bool _employed = true;
+ public bool Employed
+ {
+ get => _employed;
+ set => SetField(ref _employed, value);
+ }
+
+ private string _role;
+ public string Role
+ {
+ get => _role;
+ set => SetField(ref _role, value);
+ }
+
+ private string _team;
+ public string Team
+ {
+ get => _team;
+ set => SetField(ref _team, value);
+ }
+
+ private string _password;
+ public string Password
+ {
+ get => _password;
+ set => SetField(ref _password, value);
+ }
+ }
+}
+
diff --git a/Services/IUsersService.cs b/Services/IUsersService.cs
new file mode 100644
index 0000000..4e2a15a
--- /dev/null
+++ b/Services/IUsersService.cs
@@ -0,0 +1,11 @@
+using UndacApp.Models;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace UndacApp.Services
+{
+ public interface IUsersService : IService
+ {
+ // Define additional methods specific to user management if needed
+ }
+}
diff --git a/Services/UserService.cs b/Services/UserService.cs
new file mode 100644
index 0000000..1853597
--- /dev/null
+++ b/Services/UserService.cs
@@ -0,0 +1,16 @@
+using UndacApp.Models;
+using System.Threading.Tasks;
+
+namespace UndacApp.Services
+{
+ public class UsersService : AService, IUsersService
+ {
+ public UsersService() : base()
+ {
+ // Additional initialization if required
+ }
+
+ // Implement any additional methods specific to the User entity
+ // For now, all basic CRUD operations are inherited from AService
+ }
+}
diff --git a/Utils/PasswordHasher.cs b/Utils/PasswordHasher.cs
new file mode 100644
index 0000000..b5cd4ee
--- /dev/null
+++ b/Utils/PasswordHasher.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+
+public static class PasswordHasher
+{
+ public static string HashPassword(string password)
+ {
+ using (var sha256 = SHA256.Create())
+ {
+ var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
+ return Convert.ToBase64String(hashedBytes);
+ }
+ }
+
+ public static bool VerifyPassword(string enteredPassword, string storedHash)
+ {
+ string enteredHash = HashPassword(enteredPassword);
+ return enteredHash == storedHash;
+ }
+}
diff --git a/Views/UsersPage.xaml b/Views/UsersPage.xaml
new file mode 100644
index 0000000..4bb375a
--- /dev/null
+++ b/Views/UsersPage.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/UsersPage.xaml.cs b/Views/UsersPage.xaml.cs
new file mode 100644
index 0000000..9679cf6
--- /dev/null
+++ b/Views/UsersPage.xaml.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Threading.Tasks;
+using UndacApp.Models;
+using UndacApp.Services;
+using Microsoft.Maui.Controls;
+
+namespace UndacApp.Views
+{
+ public partial class UsersPage : ContentPage
+ {
+ IUsersService userService;
+ ObservableCollection users = new ObservableCollection();
+ private User selectedUser;
+
+ public UsersPage()
+ {
+ InitializeComponent();
+ userService = new UsersService();
+ InitializePickers();
+ LoadUsers();
+ }
+
+ private void InitializePickers()
+ {
+ pickerRole.ItemsSource = new List { "User", "System Administrator" };
+ pickerAccessLevel.ItemsSource = new List { "Low", "Medium", "High" };
+ }
+
+ private async Task LoadUsers()
+ {
+ var userList = await userService.GetAll();
+ users = new ObservableCollection(userList);
+ listViewUsers.ItemsSource = users;
+ }
+
+ private async void LoginButton_Clicked(object sender, EventArgs e)
+ {
+ string email = txtLoginEmail.Text; string password = txtLoginPassword.Text;
+ var user = users.FirstOrDefault(u => u.Email == email && PasswordHasher.VerifyPassword(password, u.Password));
+
+ if (user != null)
+ {
+ if (user.Role == "User")
+ {
+ await DisplayAlert("Notice", "Contact manager", "OK");
+ }
+ else
+ {
+ if (user.Role != "Admin")
+ {
+ userManagementSection.IsVisible = true;
+ }
+ else
+ {
+ if (email == "admin@example.com")
+ {
+ userManagementSection.IsVisible = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (email == "1" && password == "1")
+ {
+ userManagementSection.IsVisible = true;
+ }
+ else
+ {
+ await DisplayAlert("Login Failed", "Invalid credentials", "OK");
+ }
+ }
+ }
+
+
+ private void HideLoginSection()
+ {
+ // Assuming the login section is within a named StackLayout
+ txtLoginEmail.IsVisible = false;
+ txtLoginPassword.IsVisible = false;
+ // Hide the login button or the entire login section container if necessary
+ // For example: loginSection.IsVisible = false;
+ }
+
+
+ private async void AddUserButton_Clicked(object sender, EventArgs e)
+ {
+ if (txtName.Text != null)
+ {
+ if (txtEmail.Text != null)
+ {
+ if (txtPassword.Text != null)
+ {
+ if (txtTeam.Text != null)
+ {
+ if (IsValidEmail(txtEmail.Text))
+ {
+ var newUser = new User
+ {
+ Name = txtName.Text,
+ Email = txtEmail.Text,
+ Password = PasswordHasher.HashPassword(txtPassword.Text),
+ Team = txtTeam.Text
+ };
+ if (pickerRole.SelectedItem != null)
+ {
+ newUser.Role = (string)pickerRole.SelectedItem;
+ if (pickerAccessLevel.SelectedItem != null)
+ {
+ newUser.AccessLevel = (string)pickerAccessLevel.SelectedItem;
+ await userService.Add(newUser);
+ users.Add(newUser);
+ ClearUserInputFields();
+ await DisplayAlert("Success", $"{newUser.Name} added!", "OK");
+ }
+ else await DisplayAlert("Error", "Access Level not selected", "OK");
+ }
+ else await DisplayAlert("Error", "Role not selected", "OK");
+ }
+ else await DisplayAlert("Error", "Invalid Email", "OK");
+ }
+ else await DisplayAlert("Error", "Team is empty", "OK");
+ }
+ else await DisplayAlert("Error", "Password is empty", "OK");
+ }
+ else await DisplayAlert("Error", "Email is empty", "OK");
+ }
+ else await DisplayAlert("Error", "Name is empty", "OK");
+ }
+
+
+ private void OnUserSelected(object sender, SelectedItemChangedEventArgs e)
+ {
+ selectedUser = e.SelectedItem as User;
+ btnEdit.IsEnabled = btnDelete.IsEnabled = selectedUser != null;
+ }
+
+ private async void EditUserButton_Clicked(object sender, EventArgs e)
+ {
+ if (selectedUser == null) return;
+
+ txtName.Text = selectedUser.Name;
+ txtEmail.Text = selectedUser.Email;
+ txtPassword.Text = selectedUser.Password; // Keep in mind this is hashed
+ txtTeam.Text = selectedUser.Team;
+ pickerRole.SelectedItem = selectedUser.Role;
+ pickerAccessLevel.SelectedItem = selectedUser.AccessLevel;
+
+ AddUserButton.Text = "Save Changes";
+ AddUserButton.Clicked -= AddUserButton_Clicked;
+ AddUserButton.Clicked += SaveUserChangesButton_Clicked;
+ }
+
+ private async void SaveUserChangesButton_Clicked(object sender, EventArgs e)
+ {
+ if (!ValidateUserInput()) return;
+
+ selectedUser.Name = txtName.Text;
+ selectedUser.Email = txtEmail.Text;
+ selectedUser.Password = PasswordHasher.HashPassword(txtPassword.Text); // Hashing new password
+ selectedUser.Team = txtTeam.Text;
+ selectedUser.Role = (string)pickerRole.SelectedItem;
+ selectedUser.AccessLevel = (string)pickerAccessLevel.SelectedItem;
+
+ await userService.Update(selectedUser);
+
+ RefreshListView();
+ ClearUserInputFields();
+
+ AddUserButton.Text = "Add User";
+ AddUserButton.Clicked -= SaveUserChangesButton_Clicked;
+ AddUserButton.Clicked += AddUserButton_Clicked;
+
+ await DisplayAlert("Success", "User updated successfully!", "OK");
+ }
+
+ private async void DeleteUserButton_Clicked(object sender, EventArgs e)
+ {
+ if (selectedUser == null) return;
+
+ var confirm = await DisplayAlert("Confirm Delete", $"Are you sure you want to delete {selectedUser.Name}?", "Yes", "No");
+ if (confirm)
+ {
+ await userService.Remove(selectedUser);
+ users.Remove(selectedUser);
+ RefreshListView();
+ ClearUserInputFields();
+
+ await DisplayAlert("User Deleted", $"Access privileges removed, {selectedUser.Name} deleted!", "OK");
+ }
+ }
+
+ private void ClearUserInputFields()
+ {
+ txtName.Text = "";
+ txtEmail.Text = "";
+ txtPassword.Text = "";
+ txtTeam.Text = "";
+ pickerRole.SelectedIndex = -1;
+ pickerAccessLevel.SelectedIndex = -1;
+ selectedUser = null;
+ btnEdit.IsEnabled = false;
+ btnDelete.IsEnabled = false;
+ }
+
+ private void RefreshListView()
+ {
+ listViewUsers.ItemsSource = null;
+ listViewUsers.ItemsSource = users;
+ }
+
+ private bool IsValidEmail(string email)
+ {
+ try
+ {
+ var addr = new System.Net.Mail.MailAddress(email);
+ return addr.Address == email;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ private bool ValidateUserInput()
+ {
+ if (string.IsNullOrWhiteSpace(txtName.Text) ||
+ string.IsNullOrWhiteSpace(txtEmail.Text) ||
+ string.IsNullOrWhiteSpace(txtPassword.Text) ||
+ string.IsNullOrWhiteSpace(txtTeam.Text) ||
+ pickerRole.SelectedIndex == -1 ||
+ pickerAccessLevel.SelectedIndex == -1)
+ {
+ DisplayAlert("Validation Error", "All fields are required.", "OK");
+ return false;
+ }
+
+ if (!IsValidEmail(txtEmail.Text))
+ {
+ DisplayAlert("Validation Error", "Enter a valid email address.", "OK");
+ return false;
+ }
+
+ return true;
+ }
+ }
+}