package com.example.ui.screens import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Campaign import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.DoneAll import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.Pause import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.filled.SmartDisplay import androidx.compose.material.icons.filled.Stop import androidx.compose.material.icons.filled.Verified import androidx.compose.material.icons.filled.Visibility import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChipDefaults import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.example.data.local.entity.CampaignEntity import com.example.data.local.entity.WhatsAppTemplateEntity import com.example.ui.components.StatusBadge import com.example.ui.theme.EmeraldContainer import com.example.ui.theme.EmeraldDark import com.example.ui.theme.EmeraldLight import com.example.ui.theme.EmeraldPrimary import com.example.ui.theme.TealSecondary import com.example.ui.viewmodel.MarketingViewModel @Composable fun CampaignsScreen( viewModel: MarketingViewModel, modifier: Modifier = Modifier ) { val campaigns by viewModel.campaigns.collectAsStateWithLifecycle() val categories by viewModel.categories.collectAsStateWithLifecycle() val templates by viewModel.templates.collectAsStateWithLifecycle() val eligibleContacts by viewModel.eligibleContacts.collectAsStateWithLifecycle() var showBuilderModal by remember { mutableStateOf(false) } var previewCampaign by remember { mutableStateOf(null) } Box(modifier = modifier.fillMaxSize()) { Column( modifier = Modifier .fillMaxSize() .padding(horizontal = 16.dp) ) { Spacer(modifier = Modifier.height(8.dp)) // Header Banner Card( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(14.dp), colors = CardDefaults.cardColors( containerColor = EmeraldPrimary.copy(alpha = 0.08f) ) ) { Row( modifier = Modifier.padding(14.dp), verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier .size(42.dp) .clip(CircleShape) .background(EmeraldPrimary), contentAlignment = Alignment.Center ) { Icon( imageVector = Icons.Default.Campaign, contentDescription = null, tint = Color.White, modifier = Modifier.size(24.dp) ) } Spacer(modifier = Modifier.width(12.dp)) Column(modifier = Modifier.weight(1f)) { Text( text = "Meta WhatsApp Cloud Campaigns", fontWeight = FontWeight.Bold, fontSize = 15.sp, color = MaterialTheme.colorScheme.onSurface ) Text( text = "Send approved marketing templates with images, videos, brochures, and dynamic tags to opted-in customer lists.", fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } } Spacer(modifier = Modifier.height(14.dp)) // Campaigns List Text( text = "All Campaigns (${campaigns.size})", fontWeight = FontWeight.Bold, fontSize = 16.sp, color = MaterialTheme.colorScheme.onSurface ) Spacer(modifier = Modifier.height(8.dp)) if (campaigns.isEmpty()) { Box( modifier = Modifier .fillMaxSize() .weight(1f), contentAlignment = Alignment.Center ) { Text( text = "No campaigns yet. Tap '+' to create your first broadcast.", fontSize = 14.sp, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } else { LazyColumn( modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(12.dp) ) { items(campaigns) { campaign -> CampaignCard( campaign = campaign, onPreview = { previewCampaign = campaign }, onPause = { viewModel.pauseCampaign(campaign.id) }, onResume = { viewModel.resumeCampaign(campaign.id) }, onCancel = { viewModel.cancelCampaign(campaign.id) } ) } item { Spacer(modifier = Modifier.height(72.dp)) } } } } // Floating Action Button to launch Campaign Builder FloatingActionButton( onClick = { showBuilderModal = true }, modifier = Modifier .align(Alignment.BottomEnd) .padding(20.dp) .testTag("create_campaign_fab"), containerColor = EmeraldPrimary, contentColor = Color.White ) { Icon(Icons.Default.Add, contentDescription = "Create Campaign") } // Modals if (showBuilderModal) { CampaignBuilderWizard( categories = categories, templates = templates, eligibleContactCount = eligibleContacts.size, onDismiss = { showBuilderModal = false }, onLaunch = { title, desc, templateId, templateName, catNames, mediaUrl, vars -> viewModel.createAndLaunchCampaign( title = title, description = desc, templateId = templateId, templateName = templateName, categoryNames = catNames, mediaUrl = mediaUrl, variableValues = vars ) showBuilderModal = false } ) } previewCampaign?.let { camp -> SimulatedWhatsAppPreviewModal( campaign = camp, onDismiss = { previewCampaign = null } ) } } } @Composable fun CampaignCard( campaign: CampaignEntity, onPreview: () -> Unit, onPause: () -> Unit, onResume: () -> Unit, onCancel: () -> Unit ) { Card( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(14.dp), colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) ) { Column(modifier = Modifier.padding(14.dp)) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Top ) { Column(modifier = Modifier.weight(1f)) { Text( text = campaign.title, fontWeight = FontWeight.Bold, fontSize = 16.sp, color = MaterialTheme.colorScheme.onSurface ) Text( text = "Template: ${campaign.templateName} • Target: ${campaign.categoryNames}", fontSize = 12.sp, color = MaterialTheme.colorScheme.onSurfaceVariant ) } StatusBadge(status = campaign.status) } Spacer(modifier = Modifier.height(10.dp)) // Progress bar val progress = if (campaign.targetCount > 0) { (campaign.deliveredCount.toFloat() / campaign.targetCount.toFloat()).coerceIn(0f, 1f) } else 0f LinearProgressIndicator( progress = { progress }, modifier = Modifier .fillMaxWidth() .height(8.dp) .clip(RoundedCornerShape(4.dp)), color = when (campaign.status) { "PAUSED" -> Color(0xFFD97706) "CANCELLED" -> Color(0xFFEF4444) else -> EmeraldPrimary }, trackColor = Color(0xFFE2E8F0) ) Spacer(modifier = Modifier.height(10.dp)) // Metrics Row Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { MetricItem(label = "Target", value = campaign.targetCount.toString()) MetricItem(label = "Sent", value = campaign.sentCount.toString()) MetricItem(label = "Delivered", value = campaign.deliveredCount.toString()) MetricItem(label = "Read", value = campaign.readCount.toString()) MetricItem(label = "Failed", value = campaign.failedCount.toString(), isError = campaign.failedCount > 0) } Spacer(modifier = Modifier.height(12.dp)) // Actions Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { OutlinedButton( onClick = onPreview, shape = RoundedCornerShape(8.dp) ) { Icon(Icons.Default.Visibility, contentDescription = null, modifier = Modifier.size(14.dp)) Spacer(modifier = Modifier.width(4.dp)) Text("WhatsApp Preview", fontSize = 11.sp) } Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) { if (campaign.status == "IN_PROGRESS" || campaign.status == "QUEUED") { IconButton(onClick = onPause) { Icon(Icons.Default.Pause, contentDescription = "Pause", tint = Color(0xFFD97706)) } } else if (campaign.status == "PAUSED") { IconButton(onClick = onResume) { Icon(Icons.Default.PlayArrow, contentDescription = "Resume", tint = EmeraldPrimary) } } if (campaign.status != "COMPLETED" && campaign.status != "CANCELLED") { IconButton(onClick = onCancel) { Icon(Icons.Default.Stop, contentDescription = "Cancel", tint = Color(0xFFEF4444)) } } } } } } } @Composable fun MetricItem(label: String, value: String, isError: Boolean = false) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(text = label, fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant) Text( text = value, fontSize = 13.sp, fontWeight = FontWeight.Bold, color = if (isError) Color(0xFFEF4444) else MaterialTheme.colorScheme.onSurface ) } } @Composable fun CampaignBuilderWizard( categories: List, templates: List, eligibleContactCount: Int, onDismiss: () -> Unit, onLaunch: ( title: String, description: String, templateId: String, templateName: String, categoryNames: String, mediaUrl: String, variableValues: String ) -> Unit ) { val context = LocalContext.current var title by remember { mutableStateOf("Festive Mega Solar Blast") } var description by remember { mutableStateOf("Diwali bulk promotion for authorized dealers") } var selectedCatNames by remember { mutableStateOf(setOf(categories.firstOrNull()?.name ?: "Solar Dealers and Distributors")) } var selectedTemplate by remember { mutableStateOf(templates.firstOrNull()) } var variableValues by remember { mutableStateOf("25% Festive Discount & Free Site Audit") } var mediaUrl by remember { mutableStateOf("https://images.unsplash.com/photo-1509391365360-2e959784a276?w=800") } var showMobileSimulatorInWizard by remember { mutableStateOf(false) } AlertDialog( onDismissRequest = onDismiss, title = { Text("Create WhatsApp Bulk Campaign") }, text = { Column( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(12.dp) ) { OutlinedTextField( value = title, onValueChange = { title = it }, label = { Text("Campaign Name *") }, singleLine = true, modifier = Modifier.fillMaxWidth() ) OutlinedTextField( value = description, onValueChange = { description = it }, label = { Text("Campaign Goal / Description") }, singleLine = true, modifier = Modifier.fillMaxWidth() ) // Audience Target: Exclusively Consumer Upload List Card( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(10.dp), colors = CardDefaults.cardColors(containerColor = EmeraldPrimary.copy(alpha = 0.08f)) ) { Column(modifier = Modifier.padding(10.dp)) { Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Default.Verified, contentDescription = null, tint = EmeraldPrimary, modifier = Modifier.size(16.dp)) Spacer(modifier = Modifier.width(6.dp)) Text( text = "Target Audience: Consumer CSV Upload List", fontWeight = FontWeight.Bold, fontSize = 12.sp, color = EmeraldDark ) } Spacer(modifier = Modifier.height(4.dp)) Text( text = "Messages are configured to send exclusively to Consumer contacts uploaded using CSV files. Delivery to Vendors and Retailers is restricted.", fontSize = 11.sp, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } // Eligible contacts shield Card( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(8.dp), colors = CardDefaults.cardColors(containerColor = Color(0xFFDCFCE7)) ) { Row( modifier = Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically ) { Icon(Icons.Default.Check, contentDescription = null, tint = Color(0xFF166534), modifier = Modifier.size(16.dp)) Spacer(modifier = Modifier.width(6.dp)) Text( text = "$eligibleContactCount Opted-in Consumers eligible from CSV upload", fontSize = 11.sp, fontWeight = FontWeight.SemiBold, color = Color(0xFF166534) ) } } // Template Selection Text("Select Approved Meta WhatsApp Template:", fontSize = 12.sp, fontWeight = FontWeight.Bold) templates.forEach { tmpl -> Surface( onClick = { selectedTemplate = tmpl }, shape = RoundedCornerShape(10.dp), color = if (selectedTemplate?.id == tmpl.id) EmeraldContainer else Color(0xFFF1F5F9), border = if (selectedTemplate?.id == tmpl.id) androidx.compose.foundation.BorderStroke(1.5.dp, EmeraldPrimary) else null, modifier = Modifier.fillMaxWidth() ) { Column(modifier = Modifier.padding(10.dp)) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Text(tmpl.templateName, fontWeight = FontWeight.Bold, fontSize = 13.sp) StatusBadge(status = tmpl.metaStatus) } Text("Header: ${tmpl.headerType} • Category: ${tmpl.category}", fontSize = 10.sp, color = Color.Gray) } } } // Dynamic Variables OutlinedTextField( value = variableValues, onValueChange = { variableValues = it }, label = { Text("Template Offer Variable {{2}}") }, singleLine = true, modifier = Modifier.fillMaxWidth() ) // Media URL OutlinedTextField( value = mediaUrl, onValueChange = { mediaUrl = it }, label = { Text("Header Media / Brochure URL") }, singleLine = true, modifier = Modifier.fillMaxWidth() ) // Test Message trigger Button( onClick = { Toast.makeText(context, "Test WhatsApp template dispatched to registered test mobile (+919876543210)", Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(8.dp), colors = ButtonDefaults.buttonColors(containerColor = TealSecondary) ) { Icon(Icons.Default.Send, contentDescription = null, modifier = Modifier.size(14.dp)) Spacer(modifier = Modifier.width(6.dp)) Text("Send Test Message", fontSize = 12.sp) } } }, confirmButton = { Button( onClick = { if (title.isNotBlank() && selectedTemplate != null) { onLaunch( title, description, selectedTemplate!!.id, selectedTemplate!!.templateName, selectedCatNames.joinToString(", "), mediaUrl, variableValues ) } }, colors = ButtonDefaults.buttonColors(containerColor = EmeraldPrimary) ) { Text("Schedule & Launch") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } } ) } @Composable fun SimulatedWhatsAppPreviewModal( campaign: CampaignEntity, onDismiss: () -> Unit ) { AlertDialog( onDismissRequest = onDismiss, title = { Row(verticalAlignment = Alignment.CenterVertically) { Box( modifier = Modifier .size(10.dp) .clip(CircleShape) .background(EmeraldLight) ) Spacer(modifier = Modifier.width(8.dp)) Text("WhatsApp Recipient Mobile View", fontSize = 16.sp) } }, text = { // Simulated Mobile Phone Screen Container Column( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)) .background(Color(0xFFEFEAE2)) // Classic WhatsApp chat background .border(2.dp, Color(0xFF075E54), RoundedCornerShape(16.dp)) ) { // WhatsApp Chat Header Row( modifier = Modifier .fillMaxWidth() .background(Color(0xFF075E54)) .padding(horizontal = 12.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier .size(32.dp) .clip(CircleShape) .background(Color.White), contentAlignment = Alignment.Center ) { Text("DG", fontWeight = FontWeight.Bold, color = Color(0xFF075E54), fontSize = 12.sp) } Spacer(modifier = Modifier.width(10.dp)) Column { Row(verticalAlignment = Alignment.CenterVertically) { Text( text = "DEWA Gram Udhyog Official", color = Color.White, fontWeight = FontWeight.Bold, fontSize = 13.sp ) Spacer(modifier = Modifier.width(4.dp)) Icon(Icons.Default.DoneAll, contentDescription = null, tint = Color(0xFF34B7F1), modifier = Modifier.size(14.dp)) } Text("Official WhatsApp Business Account", color = Color(0xFFD4E7E4), fontSize = 10.sp) } } // Chat bubble Column( modifier = Modifier .padding(12.dp) .clip(RoundedCornerShape(topStart = 0.dp, topEnd = 12.dp, bottomStart = 12.dp, bottomEnd = 12.dp)) .background(Color.White) .padding(10.dp) ) { // Header Image Placeholder banner Box( modifier = Modifier .fillMaxWidth() .height(110.dp) .clip(RoundedCornerShape(8.dp)) .background( androidx.compose.ui.graphics.Brush.linearGradient( listOf(Color(0xFF0F766E), Color(0xFF064E3B)) ) ), contentAlignment = Alignment.Center ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Icon(Icons.Default.Campaign, contentDescription = null, tint = Color.White, modifier = Modifier.size(28.dp)) Text("DEWA GRAM UDHYOG FESTIVE", color = Color.White, fontWeight = FontWeight.Bold, fontSize = 12.sp) Text("Certified Products & Solns", color = Color(0xFF99F6E4), fontSize = 10.sp) } } Spacer(modifier = Modifier.height(8.dp)) Text( text = "Dear Mrs Bimla,\n\nWelcome to DEWA Gram Udhyog Pvt Ltd! Get an exclusive ${campaign.variableValues} on all certified products this week.\n\nEnjoy quality assurance, fast delivery, and dedicated support from Bhiwani 127021 HR.", fontSize = 12.sp, color = Color(0xFF111B21), lineHeight = 16.sp ) Spacer(modifier = Modifier.height(6.dp)) Text( text = "Reply STOP to unsubscribe", fontSize = 10.sp, color = Color.Gray ) Spacer(modifier = Modifier.height(4.dp)) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically ) { Text("10:45 AM", fontSize = 9.sp, color = Color.Gray) Spacer(modifier = Modifier.width(4.dp)) Icon(Icons.Default.DoneAll, contentDescription = null, tint = Color(0xFF53BDEB), modifier = Modifier.size(12.dp)) } Spacer(modifier = Modifier.height(8.dp)) // Buttons Surface( color = Color(0xFFF0F2F5), shape = RoundedCornerShape(6.dp), modifier = Modifier.fillMaxWidth() ) { Row( modifier = Modifier.padding(8.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Icon(Icons.Default.Send, contentDescription = null, tint = Color(0xFF00A884), modifier = Modifier.size(14.dp)) Spacer(modifier = Modifier.width(6.dp)) Text("Chat with Sales", color = Color(0xFF00A884), fontWeight = FontWeight.Bold, fontSize = 12.sp) } } Spacer(modifier = Modifier.height(4.dp)) Surface( color = Color(0xFFF0F2F5), shape = RoundedCornerShape(6.dp), modifier = Modifier.fillMaxWidth() ) { Row( modifier = Modifier.padding(8.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Icon(Icons.Default.Link, contentDescription = null, tint = Color(0xFF00A884), modifier = Modifier.size(14.dp)) Spacer(modifier = Modifier.width(6.dp)) Text("Download Catalogue", color = Color(0xFF00A884), fontWeight = FontWeight.Bold, fontSize = 12.sp) } } } Spacer(modifier = Modifier.height(12.dp)) } }, confirmButton = { Button( onClick = onDismiss, colors = ButtonDefaults.buttonColors(containerColor = EmeraldPrimary) ) { Text("Close Preview") } } ) }