package com.example.mycrib import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.safeContentPadding import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.mycrib.android.ui.screens.AddResidenceScreen import com.mycrib.android.ui.screens.EditResidenceScreen import com.mycrib.android.ui.screens.EditTaskScreen import com.mycrib.android.ui.screens.ForgotPasswordScreen import com.mycrib.android.ui.screens.HomeScreen import com.mycrib.android.ui.screens.LoginScreen import com.mycrib.android.ui.screens.RegisterScreen import com.mycrib.android.ui.screens.ResetPasswordScreen import com.mycrib.android.ui.screens.ResidenceDetailScreen import com.mycrib.android.ui.screens.ResidencesScreen import com.mycrib.android.ui.screens.TasksScreen import com.mycrib.android.ui.screens.VerifyEmailScreen import com.mycrib.android.ui.screens.VerifyResetCodeScreen import com.mycrib.android.viewmodel.PasswordResetViewModel import androidx.lifecycle.viewmodel.compose.viewModel import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.composable import androidx.navigation.toRoute import com.mycrib.android.ui.screens.MainScreen import com.mycrib.android.ui.screens.ProfileScreen import com.mycrib.android.ui.theme.MyCribTheme import com.mycrib.navigation.* import com.mycrib.repository.LookupsRepository import com.mycrib.shared.models.Residence import com.mycrib.shared.models.TaskCategory import com.mycrib.shared.models.TaskDetail import com.mycrib.shared.models.TaskFrequency import com.mycrib.shared.models.TaskPriority import com.mycrib.shared.models.TaskStatus import com.mycrib.shared.network.ApiResult import com.mycrib.shared.network.AuthApi import com.mycrib.storage.TokenStorage import mycrib.composeapp.generated.resources.Res import mycrib.composeapp.generated.resources.compose_multiplatform @Composable @Preview fun App( deepLinkResetToken: String? = null, onClearDeepLinkToken: () -> Unit = {} ) { var isLoggedIn by remember { mutableStateOf(TokenStorage.hasToken()) } var isVerified by remember { mutableStateOf(false) } var isCheckingAuth by remember { mutableStateOf(true) } val navController = rememberNavController() // Check for stored token and verification status on app start LaunchedEffect(Unit) { val hasToken = TokenStorage.hasToken() isLoggedIn = hasToken if (hasToken) { // Fetch current user to check verification status val authApi = AuthApi() val token = TokenStorage.getToken() if (token != null) { when (val result = authApi.getCurrentUser(token)) { is ApiResult.Success -> { isVerified = result.data.verified LookupsRepository.initialize() } else -> { // If fetching user fails, clear token and logout TokenStorage.clearToken() isLoggedIn = false } } } } isCheckingAuth = false } MyCribTheme { if (isCheckingAuth) { // Show loading screen while checking auth Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { CircularProgressIndicator() } } return@MyCribTheme } val startDestination = when { deepLinkResetToken != null -> ForgotPasswordRoute !isLoggedIn -> LoginRoute !isVerified -> VerifyEmailRoute else -> MainRoute } Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { NavHost( navController = navController, startDestination = startDestination ) { composable { LoginScreen( onLoginSuccess = { user -> isLoggedIn = true isVerified = user.verified // Initialize lookups after successful login LookupsRepository.initialize() // Check if user is verified if (user.verified) { navController.navigate(MainRoute) { popUpTo { inclusive = true } } } else { navController.navigate(VerifyEmailRoute) { popUpTo { inclusive = true } } } }, onNavigateToRegister = { navController.navigate(RegisterRoute) }, onNavigateToForgotPassword = { navController.navigate(ForgotPasswordRoute) } ) } composable { RegisterScreen( onRegisterSuccess = { isLoggedIn = true isVerified = false // Initialize lookups after successful registration LookupsRepository.initialize() navController.navigate(VerifyEmailRoute) { popUpTo { inclusive = true } } }, onNavigateBack = { navController.popBackStack() } ) } composable { backStackEntry -> // Create shared ViewModel for all password reset screens val parentEntry = remember(backStackEntry) { navController.getBackStackEntry() } val passwordResetViewModel: PasswordResetViewModel = viewModel(parentEntry) { PasswordResetViewModel(deepLinkToken = deepLinkResetToken) } ForgotPasswordScreen( onNavigateBack = { // Clear deep link token when navigating back to login onClearDeepLinkToken() navController.popBackStack() }, onNavigateToVerify = { navController.navigate(VerifyResetCodeRoute) }, onNavigateToReset = { navController.navigate(ResetPasswordRoute) }, viewModel = passwordResetViewModel ) } composable { backStackEntry -> // Use shared ViewModel from ForgotPasswordRoute val parentEntry = remember(backStackEntry) { navController.getBackStackEntry() } val passwordResetViewModel: PasswordResetViewModel = viewModel(parentEntry) { PasswordResetViewModel() } VerifyResetCodeScreen( onNavigateBack = { navController.popBackStack() }, onNavigateToReset = { navController.navigate(ResetPasswordRoute) }, viewModel = passwordResetViewModel ) } composable { backStackEntry -> // Use shared ViewModel from ForgotPasswordRoute val parentEntry = remember(backStackEntry) { navController.getBackStackEntry() } val passwordResetViewModel: PasswordResetViewModel = viewModel(parentEntry) { PasswordResetViewModel() } ResetPasswordScreen( onPasswordResetSuccess = { // Clear deep link token and navigate back to login after successful password reset onClearDeepLinkToken() navController.navigate(LoginRoute) { popUpTo { inclusive = true } } }, onNavigateBack = { navController.popBackStack() }, viewModel = passwordResetViewModel ) } composable { VerifyEmailScreen( onVerifySuccess = { isVerified = true navController.navigate(MainRoute) { popUpTo { inclusive = true } } }, onLogout = { // Clear token and lookups on logout TokenStorage.clearToken() LookupsRepository.clear() isLoggedIn = false isVerified = false navController.navigate(LoginRoute) { popUpTo { inclusive = true } } } ) } composable { MainScreen( onLogout = { // Clear token and lookups on logout TokenStorage.clearToken() LookupsRepository.clear() isLoggedIn = false isVerified = false navController.navigate(LoginRoute) { popUpTo { inclusive = true } } }, onResidenceClick = { residenceId -> navController.navigate(ResidenceDetailRoute(residenceId)) }, onAddResidence = { navController.navigate(AddResidenceRoute) }, onAddTask = { // Tasks are added from within a residence // Navigate to first residence or show message if no residences exist // For now, this will be handled by the UI showing "add a property first" }, onNavigateToEditResidence = { residence -> navController.navigate( EditResidenceRoute( residenceId = residence.id, name = residence.name, propertyType = residence.propertyType?.toInt(), streetAddress = residence.streetAddress, apartmentUnit = residence.apartmentUnit, city = residence.city, stateProvince = residence.stateProvince, postalCode = residence.postalCode, country = residence.country, bedrooms = residence.bedrooms, bathrooms = residence.bathrooms, squareFootage = residence.squareFootage, lotSize = residence.lotSize, yearBuilt = residence.yearBuilt, description = residence.description, isPrimary = residence.isPrimary, ownerUserName = residence.ownerUsername, createdAt = residence.createdAt, updatedAt = residence.updatedAt, owner = residence.owner ) ) }, onNavigateToEditTask = { task -> navController.navigate( EditTaskRoute( taskId = task.id, residenceId = task.residence, title = task.title, description = task.description, categoryId = task.category.id, categoryName = task.category.name, frequencyId = task.frequency.id, frequencyName = task.frequency.name, priorityId = task.priority.id, priorityName = task.priority.name, statusId = task.status?.id, statusName = task.status?.name, dueDate = task.dueDate, estimatedCost = task.estimatedCost?.toString(), createdAt = task.createdAt, updatedAt = task.updatedAt ) ) } ) } composable { HomeScreen( onNavigateToResidences = { navController.navigate(MainRoute) }, onNavigateToTasks = { navController.navigate(TasksRoute) }, onLogout = { // Clear token and lookups on logout TokenStorage.clearToken() LookupsRepository.clear() isLoggedIn = false isVerified = false navController.navigate(LoginRoute) { popUpTo { inclusive = true } } } ) } composable { backStackEntry -> // Get refresh flag from saved state (set when returning from add/edit) val shouldRefresh = backStackEntry.savedStateHandle.get("refresh") ?: false ResidencesScreen( onResidenceClick = { residenceId -> navController.navigate(ResidenceDetailRoute(residenceId)) }, onAddResidence = { navController.navigate(AddResidenceRoute) }, onNavigateToProfile = { navController.navigate(ProfileRoute) }, shouldRefresh = shouldRefresh, onLogout = { // Clear token and lookups on logout TokenStorage.clearToken() LookupsRepository.clear() isLoggedIn = false isVerified = false navController.navigate(LoginRoute) { popUpTo { inclusive = true } } } ) } composable { AddResidenceScreen( onNavigateBack = { navController.popBackStack() }, onResidenceCreated = { // Set refresh flag before navigating back navController.previousBackStackEntry?.savedStateHandle?.set("refresh", true) navController.popBackStack() } ) } composable { backStackEntry -> val route = backStackEntry.toRoute() EditResidenceScreen( residence = Residence( id = route.residenceId, name = route.name, propertyType = route.propertyType.toString(), // Will be fetched from lookups streetAddress = route.streetAddress, apartmentUnit = route.apartmentUnit, city = route.city, stateProvince = route.stateProvince, postalCode = route.postalCode, country = route.country, bedrooms = route.bedrooms, bathrooms = route.bathrooms, squareFootage = route.squareFootage, lotSize = route.lotSize, yearBuilt = route.yearBuilt, description = route.description, purchaseDate = null, purchasePrice = null, isPrimary = route.isPrimary, ownerUsername = route.ownerUserName, owner = route.owner, createdAt = route.createdAt, updatedAt = route.updatedAt ), onNavigateBack = { navController.popBackStack() }, onResidenceUpdated = { // Set refresh flag before navigating back navController.previousBackStackEntry?.savedStateHandle?.set("refresh", true) navController.popBackStack() } ) } composable { TasksScreen( onNavigateBack = { navController.popBackStack() } ) } composable { backStackEntry -> val route = backStackEntry.toRoute() ResidenceDetailScreen( residenceId = route.residenceId, onNavigateBack = { navController.popBackStack() }, onNavigateToEditResidence = { residence -> navController.navigate( EditResidenceRoute( residenceId = residence.id, name = residence.name, propertyType = residence.propertyType?.toInt(), streetAddress = residence.streetAddress, apartmentUnit = residence.apartmentUnit, city = residence.city, stateProvince = residence.stateProvince, postalCode = residence.postalCode, country = residence.country, bedrooms = residence.bedrooms, bathrooms = residence.bathrooms, squareFootage = residence.squareFootage, lotSize = residence.lotSize, yearBuilt = residence.yearBuilt, description = residence.description, isPrimary = residence.isPrimary, ownerUserName = residence.ownerUsername, createdAt = residence.createdAt, updatedAt = residence.updatedAt, owner = residence.owner ) ) }, onNavigateToEditTask = { task -> navController.navigate( EditTaskRoute( taskId = task.id, residenceId = task.residence, title = task.title, description = task.description, categoryId = task.category.id, categoryName = task.category.name, frequencyId = task.frequency.id, frequencyName = task.frequency.name, priorityId = task.priority.id, priorityName = task.priority.name, statusId = task.status?.id, statusName = task.status?.name, dueDate = task.dueDate, estimatedCost = task.estimatedCost?.toString(), createdAt = task.createdAt, updatedAt = task.updatedAt ) ) } ) } composable { backStackEntry -> val route = backStackEntry.toRoute() EditTaskScreen( task = TaskDetail( id = route.taskId, residence = route.residenceId, title = route.title, description = route.description, category = TaskCategory(route.categoryId, route.categoryName), frequency = TaskFrequency( route.frequencyId, route.frequencyName, "", route.frequencyName, daySpan = 0, notifyDays = 0 ), priority = TaskPriority(route.priorityId, route.priorityName, displayName = route.statusName ?: ""), status = route.statusId?.let { TaskStatus(it, route.statusName ?: "", displayName = route.statusName ?: "") }, dueDate = route.dueDate, estimatedCost = route.estimatedCost?.toDoubleOrNull(), createdAt = route.createdAt, updatedAt = route.updatedAt, nextScheduledDate = null, showCompletedButton = false, completions = emptyList() ), onNavigateBack = { navController.popBackStack() }, onTaskUpdated = { navController.popBackStack() } ) } composable { ProfileScreen( onNavigateBack = { navController.popBackStack() }, onLogout = { // Clear token and lookups on logout TokenStorage.clearToken() LookupsRepository.clear() isLoggedIn = false isVerified = false navController.navigate(LoginRoute) { popUpTo { inclusive = true } } } ) } } } } /* MaterialTheme { var showContent by remember { mutableStateOf(false) } Column( modifier = Modifier .background(MaterialTheme.colorScheme.primaryContainer) .safeContentPadding() .fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { Button(onClick = { showContent = !showContent }) { Text("Click me!") } AnimatedVisibility(showContent) { val greeting = remember { Greeting().greet() } Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, ) { Image(painterResource(Res.drawable.compose_multiplatform), null) Text("Compose: $greeting") } } } } */ }