Implemented complete password reset flow with email verification and deep linking: iOS (SwiftUI): - PasswordResetViewModel: Manages 3-step flow (request, verify, reset) with deep link support - ForgotPasswordView: Email entry screen with success/error states - VerifyResetCodeView: 6-digit code verification with resend option - ResetPasswordView: Password reset with live validation and strength indicators - PasswordResetFlow: Container managing navigation between screens - Deep link handling in iOSApp.swift for mycrib://reset-password?token=xxx - Info.plist: Added CFBundleURLTypes for deep link scheme Android (Compose): - PasswordResetViewModel: StateFlow-based state management with coroutines - ForgotPasswordScreen: Material3 email entry with auto-navigation - VerifyResetCodeScreen: Code verification with Material3 design - ResetPasswordScreen: Password reset with live validation checklist - Deep link handling in MainActivity.kt and AndroidManifest.xml - Token cleanup callback to prevent reusing expired deep link tokens - Shared ViewModel scoping across all password reset screens - Improved error handling for Django validation errors Shared: - Routes: Added ForgotPasswordRoute, VerifyResetCodeRoute, ResetPasswordRoute - AuthApi: Enhanced resetPassword with Django validation error parsing - User models: Added password reset request/response models Security features: - Deep link tokens expire after use - Proper token validation on backend - Session invalidation after password change - Password strength requirements enforced 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
107 lines
2.4 KiB
Kotlin
107 lines
2.4 KiB
Kotlin
package com.mycrib.shared.models
|
|
|
|
import kotlinx.serialization.SerialName
|
|
import kotlinx.serialization.Serializable
|
|
|
|
@Serializable
|
|
data class User(
|
|
val id: Int,
|
|
val username: String,
|
|
val email: String,
|
|
@SerialName("first_name") val firstName: String?,
|
|
@SerialName("last_name") val lastName: String?,
|
|
@SerialName("is_staff") val isStaff: Boolean = false,
|
|
@SerialName("is_active") val isActive: Boolean = true,
|
|
@SerialName("date_joined") val dateJoined: String,
|
|
val verified: Boolean = false
|
|
)
|
|
|
|
@Serializable
|
|
data class UserProfile(
|
|
val id: Int,
|
|
val user: Int,
|
|
@SerialName("phone_number") val phoneNumber: String?,
|
|
val address: String?,
|
|
val city: String?,
|
|
@SerialName("state_province") val stateProvince: String?,
|
|
@SerialName("postal_code") val postalCode: String?,
|
|
val country: String?,
|
|
@SerialName("profile_picture") val profilePicture: String?,
|
|
val bio: String?
|
|
)
|
|
|
|
@Serializable
|
|
data class RegisterRequest(
|
|
val username: String,
|
|
val email: String,
|
|
val password: String,
|
|
@SerialName("first_name") val firstName: String? = null,
|
|
@SerialName("last_name") val lastName: String? = null
|
|
)
|
|
|
|
@Serializable
|
|
data class LoginRequest(
|
|
val username: String,
|
|
val password: String
|
|
)
|
|
|
|
@Serializable
|
|
data class AuthResponse(
|
|
val token: String,
|
|
val user: User,
|
|
val verified: Boolean = false
|
|
)
|
|
|
|
@Serializable
|
|
data class VerifyEmailRequest(
|
|
val code: String
|
|
)
|
|
|
|
@Serializable
|
|
data class VerifyEmailResponse(
|
|
val message: String,
|
|
val verified: Boolean
|
|
)
|
|
|
|
@Serializable
|
|
data class UpdateProfileRequest(
|
|
@SerialName("first_name") val firstName: String? = null,
|
|
@SerialName("last_name") val lastName: String? = null,
|
|
val email: String? = null
|
|
)
|
|
|
|
// Password Reset Models
|
|
@Serializable
|
|
data class ForgotPasswordRequest(
|
|
val email: String
|
|
)
|
|
|
|
@Serializable
|
|
data class ForgotPasswordResponse(
|
|
val message: String
|
|
)
|
|
|
|
@Serializable
|
|
data class VerifyResetCodeRequest(
|
|
val email: String,
|
|
val code: String
|
|
)
|
|
|
|
@Serializable
|
|
data class VerifyResetCodeResponse(
|
|
val message: String,
|
|
@SerialName("reset_token") val resetToken: String
|
|
)
|
|
|
|
@Serializable
|
|
data class ResetPasswordRequest(
|
|
@SerialName("reset_token") val resetToken: String,
|
|
@SerialName("new_password") val newPassword: String,
|
|
@SerialName("confirm_password") val confirmPassword: String
|
|
)
|
|
|
|
@Serializable
|
|
data class ResetPasswordResponse(
|
|
val message: String
|
|
)
|