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.example.mycrib.ui.screens.AddResidenceScreen import com.example.mycrib.ui.screens.EditResidenceScreen import com.example.mycrib.ui.screens.EditTaskScreen import com.example.mycrib.ui.screens.ForgotPasswordScreen import com.example.mycrib.ui.screens.HomeScreen import com.example.mycrib.ui.screens.LoginScreen import com.example.mycrib.ui.screens.RegisterScreen import com.example.mycrib.ui.screens.ResetPasswordScreen import com.example.mycrib.ui.screens.ResidenceDetailScreen import com.example.mycrib.ui.screens.ResidencesScreen import com.example.mycrib.ui.screens.TasksScreen import com.example.mycrib.ui.screens.VerifyEmailScreen import com.example.mycrib.ui.screens.VerifyResetCodeScreen import com.example.mycrib.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.example.mycrib.ui.screens.MainScreen import com.example.mycrib.ui.screens.ProfileScreen import com.example.mycrib.ui.theme.MyCribTheme import com.example.mycrib.ui.theme.ThemeManager import com.example.mycrib.navigation.* import com.example.mycrib.repository.LookupsRepository import com.example.mycrib.models.Residence import com.example.mycrib.models.TaskCategory import com.example.mycrib.models.TaskDetail import com.example.mycrib.models.TaskFrequency import com.example.mycrib.models.TaskPriority import com.example.mycrib.models.TaskStatus import com.example.mycrib.network.ApiResult import com.example.mycrib.network.AuthApi import com.example.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 } val currentTheme by remember { derivedStateOf { ThemeManager.currentTheme } } MyCribTheme(themeColors = currentTheme) { 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.propertyTypeId, streetAddress = residence.streetAddress, apartmentUnit = residence.apartmentUnit, city = residence.city, stateProvince = residence.stateProvince, postalCode = residence.postalCode, country = residence.country, bedrooms = residence.bedrooms, bathrooms = residence.bathrooms?.toFloat(), squareFootage = residence.squareFootage, lotSize = residence.lotSize?.toFloat(), yearBuilt = residence.yearBuilt, description = residence.description, isPrimary = residence.isPrimary, ownerUserName = residence.ownerUsername, createdAt = residence.createdAt, updatedAt = residence.updatedAt, owner = residence.ownerId ) ) }, onNavigateToEditTask = { task -> navController.navigate( EditTaskRoute( taskId = task.id, residenceId = task.residenceId, title = task.title, description = task.description, categoryId = task.category?.id ?: 0, categoryName = task.category?.name ?: "", frequencyId = task.frequency?.id ?: 0, frequencyName = task.frequency?.name ?: "", priorityId = task.priority?.id ?: 0, 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, ownerId = route.owner ?: 0, name = route.name, propertyTypeId = route.propertyType, streetAddress = route.streetAddress ?: "", apartmentUnit = route.apartmentUnit ?: "", city = route.city ?: "", stateProvince = route.stateProvince ?: "", postalCode = route.postalCode ?: "", country = route.country ?: "", bedrooms = route.bedrooms, bathrooms = route.bathrooms?.toDouble(), squareFootage = route.squareFootage, lotSize = route.lotSize?.toDouble(), yearBuilt = route.yearBuilt, description = route.description ?: "", purchaseDate = null, purchasePrice = null, isPrimary = route.isPrimary, 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.propertyTypeId, streetAddress = residence.streetAddress, apartmentUnit = residence.apartmentUnit, city = residence.city, stateProvince = residence.stateProvince, postalCode = residence.postalCode, country = residence.country, bedrooms = residence.bedrooms, bathrooms = residence.bathrooms?.toFloat(), squareFootage = residence.squareFootage, lotSize = residence.lotSize?.toFloat(), yearBuilt = residence.yearBuilt, description = residence.description, isPrimary = residence.isPrimary, ownerUserName = residence.ownerUsername, createdAt = residence.createdAt, updatedAt = residence.updatedAt, owner = residence.ownerId ) ) }, onNavigateToEditTask = { task -> navController.navigate( EditTaskRoute( taskId = task.id, residenceId = task.residenceId, title = task.title, description = task.description, categoryId = task.category?.id ?: 0, categoryName = task.category?.name ?: "", frequencyId = task.frequency?.id ?: 0, frequencyName = task.frequency?.name ?: "", priorityId = task.priority?.id ?: 0, 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, residenceId = route.residenceId, createdById = 0, title = route.title, description = route.description ?: "", category = TaskCategory(id = route.categoryId, name = route.categoryName), frequency = TaskFrequency( id = route.frequencyId, name = route.frequencyName, days = null ), priority = TaskPriority(id = route.priorityId, name = route.priorityName), status = route.statusId?.let { TaskStatus(id = it, name = route.statusName ?: "") }, dueDate = route.dueDate, estimatedCost = route.estimatedCost?.toDoubleOrNull(), createdAt = route.createdAt, updatedAt = route.updatedAt, 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") } } } } */ }