diff --git a/.gitignore b/.gitignore
index a4228d2..d1429a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,9 +17,9 @@ captures
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
-# Google Service
-composeApp/google-service.json
-**/google-service.json
-google-service.json
+# Google Services
+#composeApp/google-services.json
+#**/google-services.json
+#google-services.json
# Project exclude paths
\ No newline at end of file
diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
index e69e0f7..7ee770b 100644
--- a/composeApp/build.gradle.kts
+++ b/composeApp/build.gradle.kts
@@ -78,6 +78,7 @@ kotlin {
implementation(compose.components.uiToolingPreview)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
+
//adaptive
implementation(libs.adaptive)
implementation(libs.adaptive.layout)
@@ -90,24 +91,24 @@ kotlin {
implementation(libs.koin.compose.viewmodel.navigation)
api(libs.koin.annotations)
+ //ktor
implementation(libs.ktor.client.core)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.client.logging)
implementation(libs.bundles.coil)
-
implementation(libs.kotlinx.datetime)
-
implementation(libs.androidx.datastore.preferences)
-
implementation(libs.calf.file.picker)
+ //navigation
+ implementation(libs.navigation.compose)
+ implementation(libs.kotlinx.serialization.json)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
-
implementation(libs.kotlinx.coroutines.test)
implementation(libs.ktor.client.mock)
implementation(libs.koin.test)
diff --git a/composeApp/src/commonMain/composeResources/values-ar/string.xml b/composeApp/src/commonMain/composeResources/values-ar/string.xml
index 0dc7e89..fe30da7 100644
--- a/composeApp/src/commonMain/composeResources/values-ar/string.xml
+++ b/composeApp/src/commonMain/composeResources/values-ar/string.xml
@@ -6,7 +6,7 @@
الفريق يحاول حلها حاليا, جرب مرة اخرى.
حسناً
- مرحبًا بك في صنعة 👋
+ مرحبًا بك في كرافتو 👋
أدخل رقم هاتفك للمتابعة
+٢٠ ٠٠٠ - ٠٠٠ - ٠٠٠٠
الشروط والأحكام
diff --git a/composeApp/src/commonMain/composeResources/values/string.xml b/composeApp/src/commonMain/composeResources/values/string.xml
index a8033d4..5756f83 100644
--- a/composeApp/src/commonMain/composeResources/values/string.xml
+++ b/composeApp/src/commonMain/composeResources/values/string.xml
@@ -7,7 +7,7 @@
Ok
- Welcome to San3a 👋
+ Welcome to Crafto 👋
Enter your phone number to\n continue
+20 000 - 000 - 0000
Terms and Conditions
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/App.kt b/composeApp/src/commonMain/kotlin/org/example/project/App.kt
index e767ad8..50a0f78 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/App.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/App.kt
@@ -1,17 +1,25 @@
package org.example.project
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.navigation.compose.rememberNavController
import org.example.project.presentation.designsystem.textstyle.AppTheme
-import org.example.project.presentation.screens.setup.craftsmansetup.CraftsmanSetupScreen
-import org.example.project.presentation.screens.splash.SplashScreen
+import org.example.project.presentation.navigation.CraftoNavGraph
import org.jetbrains.compose.ui.tooling.preview.Preview
@Composable
@Preview
fun App() {
AppTheme {
- //OnboardingScreen()
- SplashScreen { }
- CraftsmanSetupScreen()
+ val navController = rememberNavController()
+ CraftoNavGraph(
+ navController = navController,
+ modifier = Modifier
+ .fillMaxSize()
+ .background(AppTheme.craftoColors.background.screen)
+ .navigationBarsPadding())
}
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/data/repository/OnboardingRepositoryImp.kt b/composeApp/src/commonMain/kotlin/org/example/project/data/repository/OnboardingRepositoryImp.kt
index b4ec49b..d0cbbb2 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/data/repository/OnboardingRepositoryImp.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/data/repository/OnboardingRepositoryImp.kt
@@ -8,13 +8,11 @@ import org.example.project.data.remote.network.ApiConstants.Endpoints.ONBOARDING
import org.example.project.data.remote.network.wrapApiCall
import org.example.project.domain.entity.OnboardingItem
import org.example.project.domain.repository.OnboardingRepository
-import org.koin.core.annotation.Provided
-import org.koin.core.annotation.Single
-@Single(binds = [OnboardingRepository::class])
+
class OnboardingRepositoryImp(
- @Provided private val httpClient: HttpClient
+ private val httpClient: HttpClient
) : OnboardingRepository {
override suspend fun getOnboardingData(): List {
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/data/repository/UserPreferencesImpl.kt b/composeApp/src/commonMain/kotlin/org/example/project/data/repository/UserPreferencesImpl.kt
index aec8671..5649de8 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/data/repository/UserPreferencesImpl.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/data/repository/UserPreferencesImpl.kt
@@ -1,6 +1,7 @@
package org.example.project.data.repository
import org.example.project.data.local.datasource.StorageLocalDataSource
+import org.example.project.domain.entity.UserType
import org.example.project.domain.repository.UserPreferences
class UserPreferencesImpl(
@@ -9,6 +10,8 @@ class UserPreferencesImpl(
companion object {
private const val KEY_USER_ID = "user_id"
+ private const val KEY_USER_TYPE = "user_type"
+ private const val KEY_IS_FIRST_TIME = "is_first_time"
}
override suspend fun getUserId(): String? {
@@ -22,4 +25,30 @@ class UserPreferencesImpl(
override suspend fun clearUserId() {
storage.remove(KEY_USER_ID)
}
+
+ override suspend fun getUserType(): UserType? {
+ return storage.getString(KEY_USER_TYPE)?.let {
+ try {
+ UserType.valueOf(it)
+ } catch (e: IllegalArgumentException) {
+ null
+ }
+ }
+ }
+
+ override suspend fun setUserType(userType: UserType) {
+ storage.saveString(KEY_USER_TYPE, userType.name)
+ }
+
+ override suspend fun clearUserType() {
+ storage.remove(KEY_USER_TYPE)
+ }
+
+ override suspend fun isFirstTime(): Boolean {
+ return storage.getBoolean(KEY_IS_FIRST_TIME) ?: true
+ }
+
+ override suspend fun setFirstTime(isFirstTime: Boolean) {
+ storage.saveBoolean(KEY_IS_FIRST_TIME, isFirstTime)
+ }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/di/DataModule.kt b/composeApp/src/commonMain/kotlin/org/example/project/di/DataModule.kt
index 4ab09b4..a948c51 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/di/DataModule.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/di/DataModule.kt
@@ -11,10 +11,12 @@ import org.example.project.data.remote.datasource.CraftsmanRemoteDataSourceImpl
import org.example.project.data.repository.CategoryRepositoryImpl
import org.example.project.data.repository.CraftsmanRepositoryImpl
import org.example.project.data.repository.LocationRepositoryImpl
+import org.example.project.data.repository.OnboardingRepositoryImp
import org.example.project.data.service.ValidationServiceImpl
import org.example.project.domain.repository.CategoryRepository
import org.example.project.domain.repository.CraftsmanRepository
import org.example.project.domain.repository.LocationRepository
+import org.example.project.domain.repository.OnboardingRepository
import org.example.project.domain.service.ValidationService
import org.koin.dsl.module
@@ -27,6 +29,9 @@ val dataModule = module {
userPreferences = get()
)
}
+ single {
+ OnboardingRepositoryImp(get())
+ }
single { categorySeed }
single { CategoryMemoryDataSource(get()) }
single { CategoryRepositoryImpl(get()) }
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/di/DomainModule.kt b/composeApp/src/commonMain/kotlin/org/example/project/di/DomainModule.kt
index 70c9a8c..74abecb 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/di/DomainModule.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/di/DomainModule.kt
@@ -8,6 +8,10 @@ import org.example.project.domain.usecase.craftsman.GetCraftsmanStatusUseCase
import org.example.project.domain.usecase.craftsman.UploadIdCardsUseCase
import org.example.project.domain.usecase.craftsman.UploadProfilePictureUseCase
import org.example.project.domain.usecase.craftsman.UploadWorkPortfolioUseCase
+import org.example.project.domain.usecase.session.ClearUserSessionUseCase
+import org.example.project.domain.usecase.session.GetUserSessionUseCase
+import org.example.project.domain.usecase.session.MarkOnboardingCompleteUseCase
+import org.example.project.domain.usecase.session.SaveUserTypeUseCase
import org.koin.dsl.module
val domainModule = module {
@@ -19,4 +23,9 @@ val domainModule = module {
factory { DeleteCraftsmanAccountUseCase(get()) }
factory { GetCategoriesUseCase(get())}
factory { UploadProfilePictureUseCase(get(),get()) }
+
+ factory { GetUserSessionUseCase(get()) }
+ factory { SaveUserTypeUseCase(get()) }
+ factory { MarkOnboardingCompleteUseCase(get()) }
+ factory { ClearUserSessionUseCase(get()) }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/di/PresentationModule.kt b/composeApp/src/commonMain/kotlin/org/example/project/di/PresentationModule.kt
index 9a1adec..e5d40cb 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/di/PresentationModule.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/di/PresentationModule.kt
@@ -1,5 +1,7 @@
package org.example.project.di
+import org.example.project.presentation.screens.auth.UserTypeSelectionViewModel
+import org.example.project.presentation.screens.onboarding.OnboardingViewModel
import org.example.project.presentation.screens.setup.craftsmansetup.CraftsmanSetupViewModel
import org.example.project.presentation.screens.setup.location.LocationViewModel
import org.koin.core.module.dsl.viewModel
@@ -15,5 +17,7 @@ val presentationModule = module {
uploadProfilePictureUseCase = get(),
)
}
- viewModel {LocationViewModel(get())}
+ viewModel { LocationViewModel(get()) }
+ viewModel { OnboardingViewModel(get(), get()) }
+ viewModel { UserTypeSelectionViewModel(get()) }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/di/initKoin.kt b/composeApp/src/commonMain/kotlin/org/example/project/di/initKoin.kt
index e38cf21..f2bec9c 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/di/initKoin.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/di/initKoin.kt
@@ -8,7 +8,6 @@ fun initKoin(config: KoinAppDeclaration? = null) {
startKoin {
config?.invoke(this)
modules(
- //CraftoModule().module,
networkModule,
dataModule,
domainModule,
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/entity/UserSession.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/entity/UserSession.kt
new file mode 100644
index 0000000..a697ae4
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/entity/UserSession.kt
@@ -0,0 +1,7 @@
+package org.example.project.domain.entity
+
+data class UserSession(
+ val userId: String?,
+ val userType: UserType?,
+ val isFirstTime: Boolean
+)
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/entity/UserType.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/entity/UserType.kt
new file mode 100644
index 0000000..8897a23
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/entity/UserType.kt
@@ -0,0 +1,6 @@
+package org.example.project.domain.entity
+
+enum class UserType {
+ CUSTOMER,
+ CRAFTSMAN
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/repository/UserPreferences.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/repository/UserPreferences.kt
index 7564fd0..17a04b6 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/domain/repository/UserPreferences.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/repository/UserPreferences.kt
@@ -1,7 +1,18 @@
package org.example.project.domain.repository
+import org.example.project.domain.entity.UserType
+
interface UserPreferences {
suspend fun getUserId(): String?
suspend fun setUserId(userId: String)
suspend fun clearUserId()
+
+ //TODO: Separate UserType to its own Repository
+ suspend fun getUserType(): UserType?
+ suspend fun setUserType(userType: UserType)
+ suspend fun clearUserType()
+
+ // Add these
+ suspend fun isFirstTime(): Boolean
+ suspend fun setFirstTime(isFirstTime: Boolean)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/ClearUserSessionUseCase.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/ClearUserSessionUseCase.kt
new file mode 100644
index 0000000..69cd850
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/ClearUserSessionUseCase.kt
@@ -0,0 +1,12 @@
+package org.example.project.domain.usecase.session
+
+import org.example.project.domain.repository.UserPreferences
+
+class ClearUserSessionUseCase(
+ private val userPreferences: UserPreferences
+) {
+ suspend operator fun invoke() {
+ userPreferences.clearUserId()
+ userPreferences.clearUserType()
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/GetUserSessionUseCase.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/GetUserSessionUseCase.kt
new file mode 100644
index 0000000..e367f19
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/GetUserSessionUseCase.kt
@@ -0,0 +1,16 @@
+package org.example.project.domain.usecase.session
+
+import org.example.project.domain.entity.UserSession
+import org.example.project.domain.repository.UserPreferences
+
+class GetUserSessionUseCase(
+ private val userPreferences: UserPreferences
+) {
+ suspend operator fun invoke(): UserSession {
+ return UserSession(
+ userId = userPreferences.getUserId(),
+ userType = userPreferences.getUserType(),
+ isFirstTime = userPreferences.isFirstTime()
+ )
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/MarkOnboardingCompleteUseCase.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/MarkOnboardingCompleteUseCase.kt
new file mode 100644
index 0000000..44f490b
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/MarkOnboardingCompleteUseCase.kt
@@ -0,0 +1,11 @@
+package org.example.project.domain.usecase.session
+
+import org.example.project.domain.repository.UserPreferences
+
+class MarkOnboardingCompleteUseCase(
+ private val userPreferences: UserPreferences
+) {
+ suspend operator fun invoke() {
+ userPreferences.setFirstTime(false)
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/SaveUserTypeUseCase.kt b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/SaveUserTypeUseCase.kt
new file mode 100644
index 0000000..e0f0565
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/domain/usecase/session/SaveUserTypeUseCase.kt
@@ -0,0 +1,12 @@
+package org.example.project.domain.usecase.session
+
+import org.example.project.domain.entity.UserType
+import org.example.project.domain.repository.UserPreferences
+
+class SaveUserTypeUseCase(
+ private val userPreferences: UserPreferences
+) {
+ suspend operator fun invoke(userType: UserType) {
+ userPreferences.setUserType(userType)
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/BottomNavigation.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/BottomNavigation.kt
new file mode 100644
index 0000000..b540d6b
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/BottomNavigation.kt
@@ -0,0 +1,107 @@
+package org.example.project.presentation.navigation
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.navigation.NavController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import crafto.composeapp.generated.resources.Res
+import crafto.composeapp.generated.resources.*
+import org.example.project.domain.entity.UserType
+import org.example.project.presentation.designsystem.components.CraftoBottomNavBar
+import org.example.project.presentation.designsystem.components.CraftoNavItem
+import org.jetbrains.compose.resources.DrawableResource
+import org.jetbrains.compose.resources.painterResource
+
+
+enum class BottomNavigationItem(
+ val icon: DrawableResource,
+ val selectedIcon: DrawableResource,
+ val label: String,
+ val route: NavigationBarDestinations,
+) {
+ Home(
+ icon = Res.drawable.home_angle,
+ selectedIcon = Res.drawable.home_angle_1,
+ label = "Home",
+ route = NavigationBarDestinations.HomeScreen
+ ),
+ MyRequests( // Customer
+ icon = Res.drawable.clipboard_text,
+ selectedIcon = Res.drawable.clipboard_text_1,
+ label = "My Requests",
+ route = NavigationBarDestinations.MyRequestsScreen
+ ),
+ MyJobs( // Craftsman
+ icon = Res.drawable.clipboard_text,
+ selectedIcon = Res.drawable.clipboard_text_1,
+ label = "My Jobs",
+ route = NavigationBarDestinations.MyJobsScreen
+ ),
+ Messages(
+ icon = Res.drawable.dialog,
+ selectedIcon = Res.drawable.dialog_1,
+ label = "Messages",
+ route = NavigationBarDestinations.MessagesScreen
+ ),
+ More(
+ icon = Res.drawable.user_circle,
+ selectedIcon = Res.drawable.user_circle_1,
+ label = "More",
+ route = NavigationBarDestinations.MoreScreen
+ )
+}
+
+fun getBottomNavItems(userType: UserType): List {
+ return when (userType) {
+ UserType.CUSTOMER -> listOf(
+ BottomNavigationItem.Home,
+ BottomNavigationItem.MyRequests,
+ BottomNavigationItem.Messages,
+ BottomNavigationItem.More
+ )
+ UserType.CRAFTSMAN -> listOf(
+ BottomNavigationItem.Home,
+ BottomNavigationItem.MyJobs,
+ BottomNavigationItem.Messages,
+ BottomNavigationItem.More
+ )
+ }
+}
+
+@Composable
+fun CraftoNavBar(
+ currentRoute: NavigationBarDestinations,
+ onNavDestinationClicked: (NavigationBarDestinations) -> Unit,
+ userType: UserType
+) {
+ val items = getBottomNavItems(userType)
+ val selectedIndex = items.indexOfFirst { it.route == currentRoute }
+
+ CraftoBottomNavBar(
+ items = items.map { item ->
+ CraftoNavItem(
+ label = item.label,
+ icon = painterResource(item.icon),
+ selectedIcon = painterResource(item.selectedIcon)
+ )
+ },
+ selectedIndex = selectedIndex.coerceAtLeast(0),
+ onItemSelected = { index ->
+ val selectedItem = items[index]
+ if (selectedItem.route != currentRoute) {
+ onNavDestinationClicked(selectedItem.route)
+ }
+ }
+ )
+}
+
+@Composable
+fun getCurrentNavBarScreen(navController: NavController): NavigationBarDestinations? {
+ val backStackEntry by navController.currentBackStackEntryAsState()
+ val currentRoute: String? = backStackEntry?.destination?.route
+ val matchedEntry: Map.Entry? =
+ bottomNavBarDestinationsMap.entries.firstOrNull { (route, _) ->
+ currentRoute != null && route != null && currentRoute.startsWith(route)
+ }
+ return matchedEntry?.value
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/CraftoNavGraph.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/CraftoNavGraph.kt
new file mode 100644
index 0000000..948110d
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/CraftoNavGraph.kt
@@ -0,0 +1,150 @@
+package org.example.project.presentation.navigation
+
+import androidx.compose.animation.EnterTransition
+import androidx.compose.animation.ExitTransition
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.rememberNavController
+import kotlinx.coroutines.launch
+import org.example.project.domain.entity.UserType
+import org.example.project.domain.usecase.session.GetUserSessionUseCase
+import org.example.project.presentation.navigation.routes.*
+import org.koin.compose.koinInject
+
+@Composable
+fun CraftoNavGraph(
+ modifier: Modifier = Modifier,
+ navController: NavHostController = rememberNavController(),
+ getUserSessionUseCase: GetUserSessionUseCase = koinInject()
+) {
+ var userType by remember { mutableStateOf(null) }
+ var startDestination by remember { mutableStateOf(OnboardingDestination) }
+ var isLoading by remember { mutableStateOf(true) }
+
+ val coroutineScope = rememberCoroutineScope()
+
+ LaunchedEffect(Unit) {
+ coroutineScope.launch {
+ try {
+ val session = getUserSessionUseCase()
+ userType = session.userType
+
+ startDestination = when {
+ session.isFirstTime -> {
+ OnboardingDestination
+ }
+ session.userId != null && session.userType != null -> {
+ NavigationBarDestinations.HomeScreen
+ }
+ session.userId != null && session.userType == null -> {
+ UserTypeSelectionDestination
+ }
+ else -> {
+ OtpRegistrationDestination
+ }
+ }
+ } catch (e: Exception) {
+ println("Error loading session: ${e.message}")
+ startDestination = OnboardingDestination
+ } finally {
+ isLoading = false
+ }
+ }
+ }
+
+// if (isLoading || startDestination == null) {
+// Box(
+// modifier = Modifier.fillMaxSize(),
+// contentAlignment = Alignment.Center
+// ) {
+// CraftoCircularProgressIndicator()
+// }
+// return
+// }
+
+ Scaffold(
+ modifier = modifier,
+ bottomBar = {
+ getCurrentNavBarScreen(navController)?.let { selectedRoute ->
+ userType?.let { type ->
+ ShowNavigationBar(
+ selectedRoute = selectedRoute,
+ navController = navController,
+ userType = type
+ )
+ }
+ }
+ }
+ ) { innerPadding ->
+ NavHost(
+ navController = navController,
+ startDestination = startDestination,
+ enterTransition = { EnterTransition.None },
+ exitTransition = { ExitTransition.None }
+ ) {
+ authNavigationGraph(navController, onUserTypeUpdated = { type -> userType = type })
+ setupNavigationGraph(navController, onUserTypeUpdated = { type -> userType = type })
+ bottomNavigationBarGraph(navController)
+ //detailsNavigationGraph(navController)
+ }
+ }
+}
+
+@Composable
+private fun ShowNavigationBar(
+ selectedRoute: NavigationBarDestinations,
+ navController: NavHostController,
+ userType: UserType
+) {
+ CraftoNavBar(
+ currentRoute = selectedRoute,
+ onNavDestinationClicked = { route ->
+ navController.navigate(route) {
+ popUpTo(NavigationBarDestinations.HomeScreen) {
+ saveState = true
+ }
+ launchSingleTop = true
+ restoreState = true
+ }
+ },
+ userType = userType
+ )
+}
+
+// ===== Navigation Graph Functions =====
+
+fun NavGraphBuilder.authNavigationGraph(
+ navController: NavHostController,
+ onUserTypeUpdated: (UserType) -> Unit
+) {
+ onboardingRoute(navController)
+ otpRegistrationRoute(navController)
+ userTypeSelectionRoute(navController, onUserTypeUpdated)
+}
+
+fun NavGraphBuilder.setupNavigationGraph(
+ navController: NavHostController,
+ onUserTypeUpdated: (UserType) -> Unit
+) {
+ craftsmanSetupRoute(navController, onUserTypeUpdated)
+ customerSetupRoute(navController, onUserTypeUpdated)
+}
+
+fun NavGraphBuilder.bottomNavigationBarGraph(navController: NavHostController) {
+ homeRoute(navController)
+ myRequestsRoute(navController)
+ myJobsRoute(navController)
+ messagesRoute(navController)
+ moreRoute(navController)
+}
+
+//fun NavGraphBuilder.detailsNavigationGraph(navController: NavHostController) {
+// requestDetailsRoute(navController)
+// jobDetailsRoute(navController)
+// messageThreadRoute(navController)
+// settingsDetailRoute(navController)
+//}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/Destination.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/Destination.kt
new file mode 100644
index 0000000..7cdfaa8
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/Destination.kt
@@ -0,0 +1,49 @@
+package org.example.project.presentation.navigation
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+sealed interface NavigationBarDestinations {
+ @Serializable
+ data object HomeScreen : NavigationBarDestinations
+
+ @Serializable
+ data object MyRequestsScreen : NavigationBarDestinations // Customer
+
+ @Serializable
+ data object MyJobsScreen : NavigationBarDestinations // Craftsman
+
+ @Serializable
+ data object MessagesScreen : NavigationBarDestinations
+
+ @Serializable
+ data object MoreScreen : NavigationBarDestinations
+}
+
+val bottomNavBarDestinationsMap: Map = mapOf(
+ NavigationBarDestinations.HomeScreen::class.qualifiedName to NavigationBarDestinations.HomeScreen,
+ NavigationBarDestinations.MyRequestsScreen::class.qualifiedName to NavigationBarDestinations.MyRequestsScreen,
+ NavigationBarDestinations.MyJobsScreen::class.qualifiedName to NavigationBarDestinations.MyJobsScreen,
+ NavigationBarDestinations.MessagesScreen::class.qualifiedName to NavigationBarDestinations.MessagesScreen,
+ NavigationBarDestinations.MoreScreen::class.qualifiedName to NavigationBarDestinations.MoreScreen,
+ //SettingsDetailDestination::class.qualifiedName to NavigationBarDestinations.MoreScreen // Keep bottom nav selected
+)
+
+
+@Serializable
+data object OnboardingDestination
+
+@Serializable
+data object OtpRegistrationDestination
+
+@Serializable
+data object UserTypeSelectionDestination
+
+@Serializable
+data object CraftsmanSetupDestination
+
+@Serializable
+data object CustomerSetupDestination
+
+//@Serializable
+//data class SettingsDetailDestination(val settingType: String)
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/AuthRoutes.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/AuthRoutes.kt
new file mode 100644
index 0000000..ce3e31a
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/AuthRoutes.kt
@@ -0,0 +1,67 @@
+package org.example.project.presentation.navigation.routes
+
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.composable
+import org.example.project.domain.entity.UserType
+import org.example.project.presentation.navigation.CraftsmanSetupDestination
+import org.example.project.presentation.navigation.CustomerSetupDestination
+import org.example.project.presentation.navigation.OnboardingDestination
+import org.example.project.presentation.navigation.OtpRegistrationDestination
+import org.example.project.presentation.navigation.UserTypeSelectionDestination
+import org.example.project.presentation.screens.auth.UserTypeSelectionScreen
+import org.example.project.presentation.screens.onboarding.OnboardingScreen
+import org.example.project.presentation.screens.register.RegisterScreen
+
+
+fun NavGraphBuilder.onboardingRoute(navController: NavHostController) {
+ composable {
+ OnboardingScreen(
+ onNavigateToOtp = {
+ navController.navigate(OtpRegistrationDestination) {
+ popUpTo(OnboardingDestination) { inclusive = true }
+ }
+ }
+ )
+ }
+}
+
+fun NavGraphBuilder.otpRegistrationRoute(navController: NavHostController) {
+ composable {
+ RegisterScreen(
+ onRegistrationComplete = {
+ navController.navigate(UserTypeSelectionDestination) {
+ popUpTo(OtpRegistrationDestination) { inclusive = true }
+ }
+ },
+ )
+ }
+}
+
+fun NavGraphBuilder.userTypeSelectionRoute(
+ navController: NavHostController,
+ onUserTypeUpdated: (UserType) -> Unit
+) {
+ composable {
+ UserTypeSelectionScreen(
+ onNavigateToSetup = { userType ->
+ onUserTypeUpdated(userType)
+
+ when (userType) {
+ UserType.CRAFTSMAN -> {
+ navController.navigate(CraftsmanSetupDestination) {
+ //popUpTo(UserTypeSelectionDestination) { inclusive = true }
+ launchSingleTop = true
+ }
+ }
+ UserType.CUSTOMER -> {
+ navController.navigate(CustomerSetupDestination) {
+ //popUpTo(UserTypeSelectionDestination) { inclusive = true }
+ launchSingleTop = true
+ }
+ }
+ }
+ },
+ )
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/BottomNavRoutes.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/BottomNavRoutes.kt
new file mode 100644
index 0000000..b00c228
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/BottomNavRoutes.kt
@@ -0,0 +1,41 @@
+package org.example.project.presentation.navigation.routes
+
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.composable
+import org.example.project.presentation.navigation.NavigationBarDestinations
+import org.example.project.presentation.screens.home.HomeScreen
+import org.example.project.presentation.screens.messages.MessagesScreen
+import org.example.project.presentation.screens.more.MoreScreen
+import org.example.project.presentation.screens.myjobs.MyJobsScreen
+import org.example.project.presentation.screens.myrequests.MyRequestsScreen
+
+fun NavGraphBuilder.homeRoute(navController: NavHostController) {
+ composable {
+ HomeScreen()
+ }
+}
+
+fun NavGraphBuilder.myRequestsRoute(navController: NavHostController) {
+ composable {
+ MyRequestsScreen()
+ }
+}
+
+fun NavGraphBuilder.myJobsRoute(navController: NavHostController) {
+ composable {
+ MyJobsScreen()
+ }
+}
+
+fun NavGraphBuilder.messagesRoute(navController: NavHostController) {
+ composable {
+ MessagesScreen()
+ }
+}
+
+fun NavGraphBuilder.moreRoute(navController: NavHostController) {
+ composable {
+ MoreScreen()
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/SetupRoutes.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/SetupRoutes.kt
new file mode 100644
index 0000000..4b8ab53
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/navigation/routes/SetupRoutes.kt
@@ -0,0 +1,49 @@
+package org.example.project.presentation.navigation.routes
+
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.composable
+import org.example.project.domain.entity.UserType
+import org.example.project.presentation.navigation.CraftsmanSetupDestination
+import org.example.project.presentation.navigation.CustomerSetupDestination
+import org.example.project.presentation.navigation.NavigationBarDestinations
+import org.example.project.presentation.screens.setup.craftsmansetup.CraftsmanSetupScreen
+import org.example.project.presentation.screens.setup.customersetup.CustomerSetupScreen
+
+fun NavGraphBuilder.craftsmanSetupRoute(
+ navController: NavHostController,
+ onUserTypeUpdated: (UserType) -> Unit
+) {
+ composable {
+ CraftsmanSetupScreen(
+ onComplete = {
+ onUserTypeUpdated(UserType.CRAFTSMAN)
+ navController.navigate(NavigationBarDestinations.HomeScreen) {
+ popUpTo(0) { inclusive = true }
+ }
+ },
+ onClose = {
+ navController.popBackStack()
+ }
+ )
+ }
+}
+
+fun NavGraphBuilder.customerSetupRoute(
+ navController: NavHostController,
+ onUserTypeUpdated: (UserType) -> Unit
+) {
+ composable {
+ CustomerSetupScreen(
+ onComplete = {
+ onUserTypeUpdated(UserType.CUSTOMER)
+ navController.navigate(NavigationBarDestinations.HomeScreen) {
+ popUpTo(0) { inclusive = true }
+ }
+ },
+ onClose = {
+ navController.popBackStack()
+ }
+ )
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionEffect.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionEffect.kt
new file mode 100644
index 0000000..5f3938d
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionEffect.kt
@@ -0,0 +1,7 @@
+package org.example.project.presentation.screens.auth
+
+import org.example.project.domain.entity.UserType
+
+sealed interface UserTypeSelectionEffect {
+ data class NavigateToSetup(val userType: UserType) : UserTypeSelectionEffect
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionInteractionListener.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionInteractionListener.kt
new file mode 100644
index 0000000..c702bb0
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionInteractionListener.kt
@@ -0,0 +1,8 @@
+package org.example.project.presentation.screens.auth
+
+import org.example.project.domain.entity.UserType
+
+interface UserTypeSelectionInteractionListener {
+ fun onUserTypeSelected(userType: UserType)
+ fun onContinueClick()
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionScreen.kt
new file mode 100644
index 0000000..c8093d6
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionScreen.kt
@@ -0,0 +1,129 @@
+package org.example.project.presentation.screens.auth
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Snackbar
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import crafto.composeapp.generated.resources.Res
+import crafto.composeapp.generated.resources.continue_button
+import crafto.composeapp.generated.resources.registration_step_1_description
+import crafto.composeapp.generated.resources.user_type
+import org.example.project.domain.entity.UserType
+import org.example.project.presentation.designsystem.components.ButtonState
+import org.example.project.presentation.designsystem.components.TextButton
+import org.example.project.presentation.designsystem.textstyle.AppTheme
+import org.example.project.presentation.screens.setup.composable.SetupScreenScaffold
+import org.example.project.presentation.screens.setup.composable.page.UserTypeSelectionPage
+import org.example.project.presentation.shared.base.ErrorUiState
+import org.jetbrains.compose.resources.stringResource
+import org.koin.compose.viewmodel.koinViewModel
+
+@Composable
+fun UserTypeSelectionScreen(
+ viewModel: UserTypeSelectionViewModel = koinViewModel(),
+ onNavigateToSetup: (UserType) -> Unit,
+) {
+ val state by viewModel.state.collectAsStateWithLifecycle()
+
+ LaunchedEffect(Unit) {
+ viewModel.effect.collect { effect ->
+ when (effect) {
+ is UserTypeSelectionEffect.NavigateToSetup -> {
+ onNavigateToSetup(effect.userType)
+ }
+ }
+ }
+ }
+
+ Box(modifier = Modifier.fillMaxSize()) {
+ UserTypeSelectionContent(
+ state = state,
+ viewModel = viewModel,
+ )
+
+ AnimatedVisibility(
+ visible = state.error != null,
+ enter = slideInVertically { it } + fadeIn(),
+ exit = slideOutVertically { it } + fadeOut(),
+ modifier = Modifier.align(Alignment.BottomCenter)
+ ) {
+ state.error?.let { error ->
+ ErrorSnackbar(
+ error = error,
+ onDismiss = viewModel::clearError,
+ modifier = Modifier.padding(16.dp)
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun UserTypeSelectionContent(
+ state: UserTypeSelectionUiState,
+ viewModel: UserTypeSelectionInteractionListener,
+) {
+ SetupScreenScaffold(
+ currentPageNumber = 1,
+ totalPages = 1,
+ title = stringResource(Res.string.user_type),
+ description = stringResource(Res.string.registration_step_1_description),
+ nextButtonText = stringResource(Res.string.continue_button),
+ nextButtonEnabled = state.selectedType != null && !state.isLoading,
+ nextButtonState = when {
+ state.isLoading -> ButtonState.LOADING
+ state.selectedType != null -> ButtonState.Enable
+ else -> ButtonState.DISABLED
+ },
+ showBackButton = false,
+ onNextButtonClick = viewModel::onContinueClick
+ ) {
+ UserTypeSelectionPage(
+ selectedType = state.selectedType,
+ onTypeSelected = viewModel::onUserTypeSelected,
+ modifier = Modifier.fillMaxSize()
+ )
+ }
+}
+
+@Composable
+private fun ErrorSnackbar(
+ error: ErrorUiState,
+ onDismiss: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Snackbar(
+ modifier = modifier,
+ shape = RoundedCornerShape(8.dp),
+ containerColor = AppTheme.craftoColors.additional.primaryRed.copy(alpha = 0.95f),
+ contentColor = AppTheme.craftoColors.button.onPrimary,
+ action = {
+ TextButton(
+ onClick = onDismiss,
+ text = "Dismiss",
+ enabled = true,
+ buttonState = ButtonState.Enable
+ )
+ }
+ ) {
+ Text(
+ text = error.message,
+ style = AppTheme.textStyle.body.medium,
+ color = AppTheme.craftoColors.button.onPrimary
+ )
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionUiState.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionUiState.kt
new file mode 100644
index 0000000..8434970
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionUiState.kt
@@ -0,0 +1,11 @@
+package org.example.project.presentation.screens.auth
+
+import org.example.project.domain.entity.UserType
+import org.example.project.presentation.shared.base.BaseScreenState
+import org.example.project.presentation.shared.base.ErrorUiState
+
+data class UserTypeSelectionUiState(
+ override val isLoading: Boolean = false,
+ override val error: ErrorUiState? = null,
+ val selectedType: UserType? = null
+) : BaseScreenState
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionViewModel.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionViewModel.kt
new file mode 100644
index 0000000..0b5b09d
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/auth/UserTypeSelectionViewModel.kt
@@ -0,0 +1,57 @@
+package org.example.project.presentation.screens.auth
+
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
+import org.example.project.domain.entity.UserType
+import org.example.project.domain.usecase.session.SaveUserTypeUseCase
+import org.example.project.presentation.shared.base.BaseViewModel
+import org.example.project.presentation.shared.base.ErrorUiState
+
+class UserTypeSelectionViewModel(
+ private val saveUserTypeUseCase: SaveUserTypeUseCase
+) : BaseViewModel(
+ UserTypeSelectionUiState()
+), UserTypeSelectionInteractionListener {
+
+ init {
+ viewModelScope.launch {
+ isLoading.collect { loading ->
+ updateState { it.copy(isLoading = loading) }
+ }
+ }
+ }
+
+
+ override fun onUserTypeSelected(userType: UserType) {
+ updateState { it.copy(selectedType = userType) }
+ }
+
+ override fun onContinueClick() {
+ val selectedType = state.value.selectedType
+
+ if (selectedType == null) {
+ updateState {
+ it.copy(error = ErrorUiState("Please select a user type"))
+ }
+ return
+ }
+
+ tryToCall(
+ call = {
+ saveUserTypeUseCase(selectedType)
+ selectedType
+ },
+ onSuccess = { type ->
+ sendNewEffect(UserTypeSelectionEffect.NavigateToSetup(type))
+ },
+ onError = { error ->
+ updateState { it.copy(error = error) }
+ },
+ showLoading = true
+ )
+ }
+
+ fun clearError() {
+ updateState { it.copy(error = null) }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/home/HomeScreen.kt
new file mode 100644
index 0000000..10a11fa
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/home/HomeScreen.kt
@@ -0,0 +1,31 @@
+package org.example.project.presentation.screens.home
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import org.example.project.presentation.designsystem.textstyle.AppTheme
+
+@Composable
+fun HomeScreen(
+
+) {
+ Box(
+ modifier = Modifier.fillMaxSize().background(AppTheme.craftoColors.brand.primary)
+ ) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text("Home Screen", style = AppTheme.textStyle.title.large,
+ textAlign = androidx.compose.ui.text.style.TextAlign.Center
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/messages/MessagesScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/messages/MessagesScreen.kt
new file mode 100644
index 0000000..2c00987
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/messages/MessagesScreen.kt
@@ -0,0 +1,31 @@
+package org.example.project.presentation.screens.messages
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import org.example.project.presentation.designsystem.textstyle.AppTheme
+
+@Composable
+fun MessagesScreen(
+
+) {
+ Box(
+ modifier = Modifier.fillMaxSize().background(AppTheme.craftoColors.brand.primary)
+ ) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text("Messages Screen", style = AppTheme.textStyle.title.large,
+ textAlign = androidx.compose.ui.text.style.TextAlign.Center
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/more/MoreScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/more/MoreScreen.kt
new file mode 100644
index 0000000..c8ffeae
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/more/MoreScreen.kt
@@ -0,0 +1,31 @@
+package org.example.project.presentation.screens.more
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import org.example.project.presentation.designsystem.textstyle.AppTheme
+
+@Composable
+fun MoreScreen(
+
+) {
+ Box(
+ modifier = Modifier.fillMaxSize().background(AppTheme.craftoColors.brand.primary)
+ ) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text("More Screen", style = AppTheme.textStyle.title.large,
+ textAlign = androidx.compose.ui.text.style.TextAlign.Center
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/myjobs/MyJobsScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/myjobs/MyJobsScreen.kt
new file mode 100644
index 0000000..7419a98
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/myjobs/MyJobsScreen.kt
@@ -0,0 +1,31 @@
+package org.example.project.presentation.screens.myjobs
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import org.example.project.presentation.designsystem.textstyle.AppTheme
+
+@Composable
+fun MyJobsScreen(
+
+) {
+ Box(
+ modifier = Modifier.fillMaxSize().background(AppTheme.craftoColors.brand.primary)
+ ) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text("My Jobs Screen", style = AppTheme.textStyle.title.large,
+ textAlign = androidx.compose.ui.text.style.TextAlign.Center
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/myrequests/MyRequestsScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/myrequests/MyRequestsScreen.kt
new file mode 100644
index 0000000..0d54bfb
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/myrequests/MyRequestsScreen.kt
@@ -0,0 +1,31 @@
+package org.example.project.presentation.screens.myrequests
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import org.example.project.presentation.designsystem.textstyle.AppTheme
+
+@Composable
+fun MyRequestsScreen(
+
+) {
+ Box(
+ modifier = Modifier.fillMaxSize().background(AppTheme.craftoColors.brand.primary)
+ ) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text("My Requests Screen", style = AppTheme.textStyle.title.large,
+ textAlign = androidx.compose.ui.text.style.TextAlign.Center
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingScreen.kt
index 957729d..d96c4c5 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingScreen.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingScreen.kt
@@ -20,6 +20,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
@@ -38,7 +39,6 @@ import org.example.project.presentation.designsystem.components.SecondaryButton
import org.example.project.presentation.designsystem.textstyle.AppTheme
import org.example.project.presentation.screens.onboarding.composable.OnboardingIndicator
import org.example.project.presentation.screens.onboarding.composable.OnboardingItem
-import org.example.project.presentation.screens.onboarding.OnboardingViewModel
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
import org.jetbrains.compose.ui.tooling.preview.Preview
@@ -46,10 +46,23 @@ import org.koin.compose.viewmodel.koinViewModel
@Composable
fun OnboardingScreen(
- viewModel: OnboardingViewModel = koinViewModel()
-
+ viewModel: OnboardingViewModel = koinViewModel(),
+ onNavigateToOtp: () -> Unit
) {
val state by viewModel.state.collectAsState()
+ LaunchedEffect(Unit) {
+ viewModel.effect.collect { effect ->
+ when (effect) {
+ OnboardingScreenEffect.NavigateToGetStartedScreen,
+ OnboardingScreenEffect.NavigateToRegisterScreen -> {
+ onNavigateToOtp()
+ }
+ OnboardingScreenEffect.NavigateToNext -> {
+ // Internal navigation handled by pager
+ }
+ }
+ }
+ }
OnboardingContent(
state = state,
interactions = viewModel
@@ -98,7 +111,8 @@ private fun OnboardingContent(
)
)
}
- interactions::onSkipClick
+// interactions::onSkipClick
+ interactions.onSkipClick()
},
buttonState = ButtonState.Enable,
containerColor = AppTheme.craftoColors.button.secondary,
@@ -165,7 +179,8 @@ private fun OnboardingActionsRow(
)
}
} else {
- interactions::onGetStartedClick
+ //interactions::onGetStartedClick
+ interactions.onGetStartedClick()
}
},
buttonState = ButtonState.Enable,
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingViewModel.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingViewModel.kt
index f22d328..e76292a 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/onboarding/OnboardingViewModel.kt
@@ -5,14 +5,14 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import org.example.project.domain.entity.OnboardingItem
import org.example.project.domain.repository.OnboardingRepository
+import org.example.project.domain.usecase.session.MarkOnboardingCompleteUseCase
import org.example.project.presentation.screens.onboarding.model.toUiState
import org.example.project.presentation.shared.base.BaseViewModel
-import org.koin.android.annotation.KoinViewModel
-import org.koin.core.annotation.Provided
-@KoinViewModel
+
class OnboardingViewModel(
- @Provided private val repository: OnboardingRepository,
+ private val repository: OnboardingRepository,
+ private val markOnboardingCompleteUseCase: MarkOnboardingCompleteUseCase,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) :
BaseViewModel(initialState = OnboardingScreenState()),
@@ -22,16 +22,17 @@ class OnboardingViewModel(
loadData()
}
-
private fun loadData() {
tryToCall(
call = {
updateState { it.copy(loading = true) }
repository.getOnboardingData()
},
- onSuccess = ::onLoadDataSuccess ,
- onError = { errorState -> updateState { it.copy(errorMessage = errorState) } },
- dispatcher = ioDispatcher
+ onSuccess = ::onLoadDataSuccess,
+ onError = { errorState ->
+ updateState { it.copy(errorMessage = errorState, loading = false) }
+ },
+ dispatcher = ioDispatcher,
)
}
@@ -45,6 +46,7 @@ class OnboardingViewModel(
}
override fun onSkipClick() {
+ markOnboardingComplete()
sendNewEffect(OnboardingScreenEffect.NavigateToGetStartedScreen)
}
@@ -53,6 +55,22 @@ class OnboardingViewModel(
}
override fun onGetStartedClick() {
+ markOnboardingComplete()
sendNewEffect(OnboardingScreenEffect.NavigateToRegisterScreen)
}
+
+ private fun markOnboardingComplete() {
+ tryToCall(
+ call = {
+ markOnboardingCompleteUseCase()
+ },
+ onSuccess = {
+ // Do nothing, just continue navigation
+ },
+ onError = { error ->
+ updateState { it.copy(loading = false) }
+ println("⚠️ Failed to mark onboarding complete: ${error.message}")
+ },
+ )
+ }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/register/RegisterScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/register/RegisterScreen.kt
index d319231..7d229e1 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/register/RegisterScreen.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/register/RegisterScreen.kt
@@ -39,17 +39,17 @@ import org.example.project.presentation.designsystem.components.TextField
import org.example.project.presentation.designsystem.textstyle.AppTheme
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
-import org.jetbrains.compose.ui.tooling.preview.Preview
@Composable
fun RegisterScreen(
modifier: Modifier = Modifier,
+ onRegistrationComplete: () -> Unit
) {
RegisterContent(
modifier = modifier,
onPrivacyPolicyClick = {},
onTermsClick = {},
- onButtonClick = {}
+ onButtonClick = { onRegistrationComplete() }
)
}
@@ -176,10 +176,10 @@ private fun PrivacyAndTextSection(
}
}
-@Preview
-@Composable
-private fun RegisterScreenPreview() {
- AppTheme {
- RegisterScreen()
- }
-}
\ No newline at end of file
+//@Preview
+//@Composable
+//private fun RegisterScreenPreview() {
+// AppTheme {
+// RegisterScreen()
+// }
+//}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/SetupScreenScaffold.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/SetupScreenScaffold.kt
index 04994fa..dfadc50 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/SetupScreenScaffold.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/SetupScreenScaffold.kt
@@ -31,10 +31,11 @@ fun SetupScreenScaffold(
totalPages: Int = 4,
nextButtonText: String = stringResource(Res.string.next),
nextButtonEnabled: Boolean = true,
+ showBackButton: Boolean= true,
nextButtonState: ButtonState = ButtonState.Enable,
title: String,
description: String,
- onBackButtonClick: () -> Unit,
+ onBackButtonClick: () -> Unit = {},
onNextButtonClick: () -> Unit,
content: @Composable (() -> Unit)
) {
@@ -52,6 +53,7 @@ fun SetupScreenScaffold(
totalPages = totalPages,
nextButtonText = nextButtonText,
nextButtonEnabled = nextButtonEnabled,
+ showBackButton = showBackButton,
nextButtonState = nextButtonState,
description = description,
onBackButtonClick = onBackButtonClick,
@@ -68,6 +70,7 @@ fun SetupScreenScaffold(
totalPages = totalPages,
nextButtonText = nextButtonText,
nextButtonEnabled = nextButtonEnabled,
+ showBackButton = showBackButton,
nextButtonState = nextButtonState,
title = title,
description = description,
@@ -90,6 +93,7 @@ private fun PortraitLayout(
nextButtonText: String,
nextButtonEnabled: Boolean,
nextButtonState: ButtonState,
+ showBackButton: Boolean = true,
description: String,
onBackButtonClick: () -> Unit,
onNextButtonClick: () -> Unit,
@@ -107,7 +111,8 @@ private fun PortraitLayout(
AccountSetupTopBar(
onBackButtonClick = onBackButtonClick,
currentPage = currentPageNumber,
- totalPages = totalPages )
+ totalPages = totalPages,
+ showBackButton = showBackButton)
TitleDescriptionBox(
modifier = Modifier.weight(1f),
@@ -141,6 +146,7 @@ private fun LandscapeLayout(
nextButtonText: String,
nextButtonEnabled: Boolean,
nextButtonState: ButtonState,
+ showBackButton: Boolean,
title: String,
description: String,
onBackButtonClick: () -> Unit,
@@ -159,7 +165,8 @@ private fun LandscapeLayout(
AccountSetupTopBar(
onBackButtonClick = onBackButtonClick,
currentPage = currentPageNumber,
- totalPages = totalPages)
+ totalPages = totalPages,
+ showBackButton = showBackButton)
Row(
modifier = Modifier
.fillMaxWidth()
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/page/UserTypeSelectionPage.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/page/UserTypeSelectionPage.kt
index 62a8677..a2f01e4 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/page/UserTypeSelectionPage.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/composable/page/UserTypeSelectionPage.kt
@@ -13,18 +13,19 @@ import crafto.composeapp.generated.resources.customer
import crafto.composeapp.generated.resources.customer_description
import crafto.composeapp.generated.resources.selection_craftsman
import crafto.composeapp.generated.resources.selection_customer
+import org.example.project.domain.entity.UserType
import org.example.project.presentation.designsystem.components.SelectionCard
-import org.example.project.presentation.screens.setup.craftsmansetup.UserType
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
@Composable
fun UserTypeSelectionPage(
selectedType: UserType?,
- onTypeSelected: (UserType) -> Unit
+ onTypeSelected: (UserType) -> Unit,
+ modifier: Modifier=Modifier
) {
Row(
- modifier = Modifier
+ modifier = modifier
.fillMaxSize(),
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupInteractionListener.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupInteractionListener.kt
index bc33d78..20eebc5 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupInteractionListener.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupInteractionListener.kt
@@ -5,8 +5,6 @@ import org.example.project.presentation.model.PersonalInfoUiModel
import org.example.project.presentation.shared.base.ErrorUiState
interface CraftsmanSetupInteractionListener {
- fun onUserTypeSelected(userType: UserType)
-
fun onCategoryToggled(categoryId: Int)
fun onPersonalInfoChanged(personalInfo: PersonalInfoUiModel)
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupScreen.kt
index d9d4369..2faa672 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupScreen.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupScreen.kt
@@ -28,16 +28,13 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import crafto.composeapp.generated.resources.Res
import crafto.composeapp.generated.resources.identity_verification
-import crafto.composeapp.generated.resources.location_hint
import crafto.composeapp.generated.resources.personal_info
import crafto.composeapp.generated.resources.portfolio_upload
-import crafto.composeapp.generated.resources.registration_step_1_description
import crafto.composeapp.generated.resources.registration_step_2_description
import crafto.composeapp.generated.resources.registration_step_3_description
import crafto.composeapp.generated.resources.registration_step_4_description
import crafto.composeapp.generated.resources.registration_step_5_description
import crafto.composeapp.generated.resources.service_selection
-import crafto.composeapp.generated.resources.user_type
import org.example.project.presentation.designsystem.components.ButtonState
import org.example.project.presentation.designsystem.components.TextButton
import org.example.project.presentation.designsystem.textstyle.AppTheme
@@ -46,7 +43,6 @@ import org.example.project.presentation.screens.setup.composable.page.IdentityVe
import org.example.project.presentation.screens.setup.composable.page.PersonalInfoPage
import org.example.project.presentation.screens.setup.composable.page.PortfolioUploadPage
import org.example.project.presentation.screens.setup.composable.page.ServiceSelectionPage
-import org.example.project.presentation.screens.setup.composable.page.UserTypeSelectionPage
import org.example.project.presentation.shared.base.ErrorUiState
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
@@ -134,18 +130,16 @@ fun CraftsmanSetupContent(
onNextButtonClick = {
when (state.currentStep) {
RegistrationStep.IDENTITY_VERIFICATION -> {
- if (state.idCardFront != null && state.idCardBack != null) {
+ if (state.hasUploadedIdCards)
viewModel.onUploadIdCards()
- } else {
- viewModel.onSkipIdentityVerification()
- }
+// } else {
+// viewModel.onSkipIdentityVerification()
+// }
}
else -> viewModel.navigateNext()
}
},
title = when (state.currentStep) {
- RegistrationStep.USER_TYPE -> {
- stringResource(Res.string.user_type) }
RegistrationStep.SERVICE_SELECTION -> {
stringResource(Res.string.service_selection)
}
@@ -160,9 +154,6 @@ fun CraftsmanSetupContent(
}
},
description =when (state.currentStep) {
- RegistrationStep.USER_TYPE -> {
- stringResource(Res.string.registration_step_1_description)
- }
RegistrationStep.SERVICE_SELECTION -> {
stringResource(Res.string.registration_step_2_description)
}
@@ -187,12 +178,6 @@ fun CraftsmanSetupContent(
userScrollEnabled = state.isSwipeEnabled && state.canNavigateNext
) { page ->
when (RegistrationStep.fromIndex(page)) {
- RegistrationStep.USER_TYPE -> {
- UserTypeSelectionPage(
- selectedType = state.userType,
- onTypeSelected = viewModel::onUserTypeSelected,
- )
- }
RegistrationStep.SERVICE_SELECTION -> {
ServiceSelectionPage(
availableCategories = state.availableCategories,
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupUiState.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupUiState.kt
index ac71fa9..83af7a4 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupUiState.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupUiState.kt
@@ -12,7 +12,7 @@ data class CraftsmanSetupUiState(
override val error: ErrorUiState? = null,
val currentPageIndex: Int = 0,
- val totalPages: Int = 5,
+ val totalPages: Int = 4,
val canNavigateNext: Boolean = false,
val canNavigateBack: Boolean = false,
val isSwipeEnabled: Boolean = true,
@@ -23,8 +23,6 @@ data class CraftsmanSetupUiState(
val uploadedPortfolioUrls: List = emptyList(),
val verificationDocuments: VerificationDocuments? = null,
- val userType: UserType? = null,
-
val availableCategories: List = emptyList(),
val selectedCategoryIds: Set = emptySet(),
@@ -48,12 +46,11 @@ data class CraftsmanSetupUiState(
val currentStep: RegistrationStep
get() = RegistrationStep.fromIndex(currentPageIndex)
- val progress: Float
- get() = (currentPageIndex + 1) / totalPages.toFloat()
+ val hasUploadedIdCards: Boolean
+ get() = idCardFront != null && idCardBack != null
val nextButtonText: String
get() = when (currentStep) {
- RegistrationStep.USER_TYPE -> "Next"
RegistrationStep.SERVICE_SELECTION -> "Next"
RegistrationStep.PERSONAL_INFO -> if (isLoading) "Creating Profile..." else "Next"
RegistrationStep.PORTFOLIO_UPLOAD -> "Next"
@@ -62,19 +59,13 @@ data class CraftsmanSetupUiState(
}
enum class RegistrationStep(val index: Int) {
- USER_TYPE(0),
- SERVICE_SELECTION(1),
- PERSONAL_INFO(2),
- PORTFOLIO_UPLOAD(3),
- IDENTITY_VERIFICATION(4);
+ SERVICE_SELECTION(0),
+ PERSONAL_INFO(1),
+ PORTFOLIO_UPLOAD(2),
+ IDENTITY_VERIFICATION(3);
companion object {
fun fromIndex(index: Int): RegistrationStep =
- entries.firstOrNull { it.index == index } ?: USER_TYPE
+ entries.firstOrNull { it.index == index } ?: SERVICE_SELECTION
}
-}
-
-enum class UserType {
- CUSTOMER,
- CRAFTSMAN
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupViewModel.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupViewModel.kt
index 35e6f2b..6c62473 100644
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/craftsmansetup/CraftsmanSetupViewModel.kt
@@ -27,22 +27,6 @@ class CraftsmanSetupViewModel(
CraftsmanSetupUiState()
), CraftsmanSetupInteractionListener {
- override fun onUserTypeSelected(userType: UserType) {
- when (userType) {
- UserType.CRAFTSMAN -> {
- updateState {
- it.copy(
- userType = userType,
- canNavigateNext = true
- )
- }
- }
- UserType.CUSTOMER -> {
- TODO("Implement Customer setup flow – redirect to CustomerSetupScreen when ready")
- }
- }
- }
-
init {
validateCurrentPage()
fetchCategories()
@@ -106,7 +90,7 @@ class CraftsmanSetupViewModel(
updateState { it.copy(error = ErrorUiState("Please upload both ID card images")) }
return
}
- updateState { it.copy(isSwipeEnabled = false) }
+ updateState { it.copy(isSwipeEnabled = false, isUploadingIdCards = true) }
tryToCall(
call = {
@@ -119,14 +103,18 @@ class CraftsmanSetupViewModel(
)
},
onSuccess = { verificationDocs ->
- updateState { it.copy(isSwipeEnabled = true) }
+ updateState { it.copy(
+ isSwipeEnabled = true,
+ isUploadingIdCards = false,
+ verificationDocuments = verificationDocs) }
sendNewEffect(CraftsmanRegistrationEffect.RegistrationComplete)
},
onError = { error ->
updateState {
it.copy(
error = error,
- isSwipeEnabled = true
+ isSwipeEnabled = true,
+ isUploadingIdCards = false
)
}
},
@@ -135,8 +123,8 @@ class CraftsmanSetupViewModel(
}
override fun onSkipIdentityVerification() {
- //sendNewEffect(CraftsmanRegistrationEffect.RegistrationComplete)
- navigateNext()
+ sendNewEffect(CraftsmanRegistrationEffect.RegistrationComplete)
+ //navigateNext()
}
override fun onPortfolioImagesAdded(images: List) {
@@ -349,7 +337,6 @@ class CraftsmanSetupViewModel(
}
if (currentIndex < state.value.totalPages - 1 && state.value.canNavigateNext) {
- AppLogger.d("Navigation", "Navigating from page $currentIndex to ${currentIndex + 1}")
updateState { it.copy(currentPageIndex = currentIndex + 1) }
}
}
@@ -392,11 +379,10 @@ class CraftsmanSetupViewModel(
private fun validateCurrentPage() {
val canProceed = when (state.value.currentStep) {
- RegistrationStep.USER_TYPE -> state.value.userType != null
RegistrationStep.SERVICE_SELECTION -> state.value.selectedCategoryIds.isNotEmpty()
RegistrationStep.PERSONAL_INFO -> validatePersonalInfo(state.value.personalInfo)
RegistrationStep.PORTFOLIO_UPLOAD -> state.value.portfolioImages.isNotEmpty()
- RegistrationStep.IDENTITY_VERIFICATION -> true // Optional step
+ RegistrationStep.IDENTITY_VERIFICATION -> true
}
updateState { it.copy(canNavigateNext = canProceed) }
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/customersetup/CustomerSetupScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/customersetup/CustomerSetupScreen.kt
new file mode 100644
index 0000000..a3e9134
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/customersetup/CustomerSetupScreen.kt
@@ -0,0 +1,12 @@
+package org.example.project.presentation.screens.setup.customersetup
+
+import androidx.compose.runtime.Composable
+
+
+@Composable
+fun CustomerSetupScreen(
+ onComplete: () -> Unit={},
+ onClose: () -> Unit={}
+) {
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/customersetup/init b/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/customersetup/init
deleted file mode 100644
index 6a8de1b..0000000
--- a/composeApp/src/commonMain/kotlin/org/example/project/presentation/screens/setup/customersetup/init
+++ /dev/null
@@ -1 +0,0 @@
-TODO()
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index eee6826..11934f6 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
[versions]
-adaptive = "1.2.0-alpha07"
+adaptive = "1.2.0"
agp = "8.13.0"
android-compileSdk = "36"
android-minSdk = "24"
@@ -8,19 +8,19 @@ androidx-activity = "1.11.0"
androidx-appcompat = "1.7.1"
androidx-core = "1.17.0"
androidx-espresso = "3.7.0"
-androidx-lifecycle = "2.9.4"
+androidx-lifecycle = "2.9.6"
androidx-testExt = "1.3.0"
-calfFilePicker = "0.8.0"
+calfFilePicker = "0.9.0"
coilComposeVersion = "3.3.0"
-composeMultiplatform = "1.9.0"
+composeMultiplatform = "1.9.3"
datastorePreferences = "1.1.7"
junit = "4.13.2"
-kotlin = "2.2.20"
+kotlin = "2.2.21"
ksp = "2.2.20-2.0.4"
koinTest = "4.1.1"
koin = "4.1.1"
-koinAnnotations = "2.2.0"
-ktor = "3.3.1"
+koinAnnotations = "2.3.1"
+ktor = "3.3.2"
coil = "3.3.0"
koinComposeMultiplatform = "4.1.1"
kotlinxCoroutinesTest = "1.10.2"
@@ -31,8 +31,9 @@ google-services = "4.4.4"
#newer version of firebase-bom causes gradle errors
firebase-bom = "33.16.0"
firebaseCrashlytics = "3.0.6"
-ktorClientCio = "3.3.1"
-ktorClientMock = "3.3.1"
+ktorClientCio = "3.3.2"
+ktorClientMock = "3.3.2"
+navigationCompose = "2.9.1"
[libraries]
@@ -85,6 +86,7 @@ coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
coil-compose-core = { module = "io.coil-kt.coil3:coil-compose-core", version.ref = "coil" }
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-network-ktor3 = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }
+navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigationCompose" }