feat: add notifications_enabled toggle for users (web + Android)

This commit is contained in:
2026-06-13 17:28:59 -04:00
parent 81f61ff96e
commit ec38afe3e9
11 changed files with 352 additions and 8 deletions

View File

@@ -21,7 +21,8 @@ data class ProfileUpdateRequest(
val email: String,
val current_password: String? = null,
val new_password: String? = null,
val confirm_password: String? = null
val confirm_password: String? = null,
val notifications_enabled: Boolean? = null
)
@Serializable
@@ -51,5 +52,6 @@ data class UserProfile(
val username: String = "",
val email: String = "",
val role: String = "",
val created_at: String? = null
val created_at: String? = null,
val notifications_enabled: Boolean = true
)

View File

@@ -24,14 +24,16 @@ class ProfileRepository {
email: String,
currentPassword: String?,
newPassword: String?,
confirmPassword: String?
confirmPassword: String?,
notificationsEnabled: Boolean = true
): Result<String> {
return try {
val request = ProfileUpdateRequest(
email = email,
current_password = currentPassword?.takeIf { it.isNotBlank() },
new_password = newPassword?.takeIf { it.isNotBlank() },
confirm_password = confirmPassword?.takeIf { it.isNotBlank() }
confirm_password = confirmPassword?.takeIf { it.isNotBlank() },
notifications_enabled = notificationsEnabled
)
val response = api.updateProfile(request)
if (response.success) {

View File

@@ -249,6 +249,49 @@ fun ProfileScreen(
}
}
Spacer(modifier = Modifier.height(16.dp))
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Notifications",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.height(12.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = "Push Notifications",
style = MaterialTheme.typography.bodyLarge
)
Text(
text = "Receive alerts for threshold breaches and app updates",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Switch(
checked = state.notificationsEnabled,
onCheckedChange = viewModel::updateNotificationsEnabled,
enabled = !state.isSaving
)
}
}
}
if (state.error != null) {
Spacer(modifier = Modifier.height(16.dp))
Card(

View File

@@ -23,7 +23,8 @@ data class ProfileUiState(
val successMessage: String? = null,
val emailError: String? = null,
val newPasswordError: String? = null,
val confirmPasswordError: String? = null
val confirmPasswordError: String? = null,
val notificationsEnabled: Boolean = true
)
class ProfileViewModel : ViewModel() {
@@ -44,7 +45,8 @@ class ProfileViewModel : ViewModel() {
isLoading = false,
username = profile.username,
email = profile.email,
role = profile.role
role = profile.role,
notificationsEnabled = profile.notifications_enabled
)
},
onFailure = { e ->
@@ -61,6 +63,10 @@ class ProfileViewModel : ViewModel() {
_uiState.value = _uiState.value.copy(email = value, error = null, successMessage = null, emailError = null)
}
fun updateNotificationsEnabled(value: Boolean) {
_uiState.value = _uiState.value.copy(notificationsEnabled = value)
}
fun updateCurrentPassword(value: String) {
_uiState.value = _uiState.value.copy(currentPassword = value, error = null, successMessage = null)
}
@@ -103,7 +109,8 @@ class ProfileViewModel : ViewModel() {
state.email,
state.currentPassword.takeIf { it.isNotBlank() },
state.newPassword.takeIf { it.isNotBlank() },
state.confirmPassword.takeIf { it.isNotBlank() }
state.confirmPassword.takeIf { it.isNotBlank() },
state.notificationsEnabled
)
result.fold(
onSuccess = { message ->