Skip to content

Commit

Permalink
(chore): Add SignUpViewModel
Browse files Browse the repository at this point in the history
  • Loading branch information
N3v1 committed Oct 26, 2024
1 parent 00c7530 commit b07ae65
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 4 deletions.
5 changes: 4 additions & 1 deletion ScribbleLab/App/ScribbleLabApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ struct ScribbleLabApp: App {
init() {
/* SCRLog */
logger = SCRLog.shared
SCRLog.configureShared(subsystem: "com.nhsystems.scribblelab", category: .log)
SCRLog.configureShared(
subsystem: "com.nhsystems.scribblelab",
category: .log
)
logger.log("SCRLogStream successfully initialized")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class SignInViewModel: ObservableObject {
return !email.isEmpty && validateEmail(withEmail: email) && password.count >= 8
}

func validateEmail(withEmail email: String) -> Bool {
private func validateEmail(withEmail email: String) -> Bool {
return Validation.isValidEmail(email)
}

Expand Down
78 changes: 76 additions & 2 deletions ScribbleLab/Core/Authentication/Models/SignUpViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ import ScribbleFoundation

class SignUpViewModel: ObservableObject {

/// Published property holding the entered email.
@Published var email: String = ""

/// Published property holding the entered password.
@Published var password: String = ""

/// Published property holding the entered username.
@Published var username: String = ""

/// Published property determining if the sign-up button is enabled.
Expand All @@ -50,10 +55,79 @@ class SignUpViewModel: ObservableObject {

private var cancellables = Set<AnyCancellable>()

init() {
setUpValidation()
}

// That's the most ugliest code I've ever written - please don't blame me
// I'm just tired - Thank you for your understanding!
private func setUpValidation() {
Publishers.CombineLatest3($email, $password, $username)
.sink { [weak self] email, password, username in
guard let self = self else { return }

let isInputValid = self.validateInput(
email: email,
password: password,
username: username
)

if isInputValid {
Task {
if let isAvailable = try? await self.checkUsernameAvailability(for: username) {
DispatchQueue.main.async {
self.isSignUpButtonEnabled = isAvailable
}
}
}
} else {
self.isSignUpButtonEnabled = false
}
}
.store(in: &cancellables)
}

private func validateInput(
email: String,
password: String,
username: String
) -> Bool {
guard Validation.isValidEmail(email),
Validation.isStrongPassword(password),
!username.isEmpty
else {
return false
}

return true
}

init() {}
private func checkUsernameAvailability(for username: String) async throws -> Bool {
// swiftlint:disable:next identifier_name
let db = Firestore.firestore()

let usersRef = db.collection("users")
let query = usersRef.whereField("username", isEqualTo: username)

let snapshot = try await query.getDocuments()

return snapshot.isEmpty
}

func createScribbleID() async throws {
try await SCIDAuthService.shared.createUser(
email: email,
password: password,
username: username
)

// Resetting published properties after user creation
username = ""
password = ""
email = ""
}

deinit {}
deinit {
cancellables.removeAll()
}
}
121 changes: 121 additions & 0 deletions ScribbleLab/Misc/SCIDError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//
// SCIDError.swift
// ScribbleLab
//
// Copyright (c) 2024 ScribbleLabApp LLC. - All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import Foundation

/// A comprehensive list of errors that can occur within the ScribbleLabApp identity and user services.
///
/// The `SCIDError` enum categorizes errors into those related to Google authentication processes, such as
/// OAuth flows and user sign-ins, and errors encountered in user data retrieval and handling. Each error case
/// provides contextual information and a standardized error code to support debugging and enhance error
/// tracking throughout the app.
///
/// - Note: These error codes can be used in logging and alerting systems to quickly identify the
/// error source and cause.
internal enum SCIDError: Error {

/// The client ID required for Google Sign-In is missing.
///
/// This error occurs if the app is unable to retrieve the necessary client ID to initiate Google OAuth
/// authentication. The absence of this ID prevents the app from making the initial connection with
/// Google’s authentication services.
///
/// - Error Code: `GID-E115`
case missingClientID

/// Failed to present the OAuth consent sheet for Google Sign-In.
///
/// This error is encountered when the app cannot display the OAuth consent sheet, which is
/// required for users to grant permissions to their Google account. This may happen due to
/// UI-related constraints or network issues.
///
/// - Error Code: `GID-E110`
case failedOAuthSheet


/// The signed-in user or the ID token is unavailable after an attempt to sign in.
///
/// This error is returned if the app fails to retrieve the expected user profile or ID token
/// following a successful OAuth flow, potentially due to session timeouts or network interruptions.
///
/// - Error Code: `GID-E116`
case missingUserOrToken

/// Google Sign-In failed due to an unknown error.
///
/// This error generally occurs when the sign-in process does not complete successfully, either due
/// to connectivity issues or unhandled exceptions during authentication.
///
/// - Error Code: `GID-E118`
case signInFailed

/// The signed-in user object is unavailable after Google authentication completes.
///
/// This error occurs when the user object is not retrievable even after a successful Google Sign-In.
/// It is likely related to session handling or data parsing issues during the sign-in process.
///
/// - Error Code: `GID-E119`
case missingSignedInUser

/// The user’s login attempt failed.
///
/// This error represents a general failure in the login process. It may be caused by invalid credentials,
/// connectivity issues, or other authentication-related errors.
///
/// - Error Code: `AUT-E101`
case logInFailed

/// Failed to create a new user account.
///
/// This error occurs when the app fails to establish a new user account, potentially due to server-side
/// issues, invalid data inputs, or connectivity problems during account creation.
///
/// - Error Code: `AUT-E102`
case userCreationFailed

/// The requested user data could not be found or was invalid.
///
/// This error is encountered when attempting to fetch user data from the database, but the returned data
/// is either missing or improperly formatted. This may occur if the user’s record does not exist or if data
/// parsing fails.
///
/// - Error Code: `SLUSR-E201`
case userDataNotFound

/// Required user fields are missing or incomplete in the retrieved data.
///
/// This error is thrown when essential fields such as user ID, username, or email are missing in the
/// retrieved user data, leading to incomplete user profiles. This may happen due to improper data
/// entry or issues in database management.
///
/// - Error Code: `SLUSR-E202`
case missingRequiredUserFields
}

0 comments on commit b07ae65

Please sign in to comment.