Upload via GUI (4909 Dateien)
This commit is contained in:
@@ -227,9 +227,11 @@ class TicketRepository(
|
||||
status: String?,
|
||||
assignedStaffId: Int?,
|
||||
updateAssignment: Boolean,
|
||||
resolutionCode: String? = null,
|
||||
): TicketSummary {
|
||||
val request = linkedMapOf<String, Any?>("number" to number)
|
||||
status?.let { request["status"] = it }
|
||||
resolutionCode?.let { request["resolutionCode"] = it }
|
||||
if (updateAssignment) request["assignedStaffId"] = assignedStaffId
|
||||
return requireApi().updateTicket(request).ticket.toDomain()
|
||||
}
|
||||
@@ -264,8 +266,8 @@ class TicketRepository(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun addMessage(number: String, type: String, message: String, setStatus: String?, signature: String? = null) {
|
||||
requireApi().addMessage(MessageRequest(number, type, message, setStatus, signature))
|
||||
suspend fun addMessage(number: String, type: String, message: String, setStatus: String?, signature: String? = null, resolutionCode: String? = null) {
|
||||
requireApi().addMessage(MessageRequest(number, type, message, setStatus, signature, resolutionCode))
|
||||
}
|
||||
|
||||
suspend fun cannedResponses(): List<CannedResponse> =
|
||||
|
||||
@@ -5365,8 +5365,8 @@ private fun TicketDetailScreen(
|
||||
state: DeskHubState,
|
||||
onBack: () -> Unit,
|
||||
onRetry: () -> Unit,
|
||||
onUpdate: (String, Int?) -> Unit,
|
||||
onMessage: (String, String, String?, String?, () -> Unit) -> Unit,
|
||||
onUpdate: (String, Int?, String?) -> Unit,
|
||||
onMessage: (String, String, String?, String?, String?, () -> Unit) -> Unit,
|
||||
onSpamAction: (Boolean) -> Unit,
|
||||
onSnooze: (String?) -> Unit = {},
|
||||
onFollow: (Boolean) -> Unit = {},
|
||||
@@ -5421,8 +5421,8 @@ private fun TicketDetailContent(
|
||||
cannedResponses: List<de.deskhub.staff.domain.model.CannedResponse>,
|
||||
mutationLoading: Boolean,
|
||||
mutationError: String?,
|
||||
onUpdate: (String, Int?) -> Unit,
|
||||
onMessage: (String, String, String?, String?, () -> Unit) -> Unit,
|
||||
onUpdate: (String, Int?, String?) -> Unit,
|
||||
onMessage: (String, String, String?, String?, String?, () -> Unit) -> Unit,
|
||||
onSpamAction: (Boolean) -> Unit,
|
||||
onSnooze: (String?) -> Unit = {},
|
||||
onFollow: (Boolean) -> Unit = {},
|
||||
@@ -5437,6 +5437,8 @@ private fun TicketDetailContent(
|
||||
var messageType by rememberSaveable(ticket.summary.number) { mutableStateOf("reply") }
|
||||
var message by rememberSaveable(ticket.summary.number) { mutableStateOf("") }
|
||||
var replyStatus by rememberSaveable(ticket.summary.number) { mutableStateOf("answered") }
|
||||
var resolutionCode by rememberSaveable(ticket.summary.number) { mutableStateOf("") }
|
||||
val resolutionChoices = listOf("fixed" to "Fehler behoben", "guidance" to "Anleitung", "duplicate" to "Doppelt", "not_reproducible" to "Nicht reproduzierbar", "no_action" to "Keine Maßnahme", "spam" to "Spam", "automated" to "Automatisch", "other" to "Sonstiges")
|
||||
// Signatur beim Antworten: "own", "dept" oder "none" (Voreinstellung vom Server)
|
||||
var signatureChoice by rememberSaveable(ticket.summary.number) { mutableStateOf(ticket.replySignatures?.default ?: "none") }
|
||||
// Textbausteine: nur die der Abteilung dieses Tickets und die für alle Abteilungen (ältere Server liefern alle)
|
||||
@@ -5726,14 +5728,21 @@ private fun TicketDetailContent(
|
||||
}
|
||||
}
|
||||
Button(
|
||||
onClick = { onUpdate(selectedStatus, selectedAgent) },
|
||||
onClick = { onUpdate(selectedStatus, selectedAgent, resolutionCode.takeIf { selectedStatus in setOf("resolved", "closed") }) },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
enabled = !mutationLoading &&
|
||||
(selectedStatus != ticket.summary.status || selectedAgent != ticket.summary.assignedStaff?.id),
|
||||
(selectedStatus != ticket.summary.status || selectedAgent != ticket.summary.assignedStaff?.id) &&
|
||||
(selectedStatus !in setOf("resolved", "closed") || selectedStatus == ticket.summary.status || resolutionCode.isNotBlank()),
|
||||
) {
|
||||
Text(if (mutationLoading) "Speichert …" else "Änderungen speichern")
|
||||
}
|
||||
if (selectedStatus in setOf("resolved", "closed")) {
|
||||
var reasonExpanded by remember { mutableStateOf(false) }
|
||||
SelectionField(label = "Abschlussgrund", value = resolutionChoices.firstOrNull { it.first == resolutionCode }?.second ?: "Bitte auswählen", expanded = reasonExpanded, onExpand = { reasonExpanded = true }, onDismiss = { reasonExpanded = false }) {
|
||||
resolutionChoices.forEach { (code, label) -> DropdownMenuItem(text = { Text(label) }, onClick = { resolutionCode = code; reasonExpanded = false }) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5886,6 +5895,12 @@ private fun TicketDetailContent(
|
||||
)
|
||||
}
|
||||
}
|
||||
if (replyStatus in setOf("resolved", "closed")) {
|
||||
var reasonExpanded by remember { mutableStateOf(false) }
|
||||
SelectionField(label = "Abschlussgrund", value = resolutionChoices.firstOrNull { it.first == resolutionCode }?.second ?: "Bitte auswählen", expanded = reasonExpanded, onExpand = { reasonExpanded = true }, onDismiss = { reasonExpanded = false }) {
|
||||
resolutionChoices.forEach { (code, label) -> DropdownMenuItem(text = { Text(label) }, onClick = { resolutionCode = code; reasonExpanded = false }) }
|
||||
}
|
||||
}
|
||||
}
|
||||
mutationError?.let { ErrorText(it) }
|
||||
Button(
|
||||
@@ -5895,13 +5910,14 @@ private fun TicketDetailContent(
|
||||
message,
|
||||
replyStatus.takeIf { messageType == "reply" },
|
||||
signatureChoice.takeIf { messageType == "reply" && ticket.replySignatures != null },
|
||||
resolutionCode.takeIf { messageType == "reply" && replyStatus in setOf("resolved", "closed") },
|
||||
) { message = "" }
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
enabled = !mutationLoading && message.isNotBlank() &&
|
||||
enabled = !mutationLoading && message.isNotBlank() && (messageType != "reply" || replyStatus !in setOf("resolved", "closed") || resolutionCode.isNotBlank()) &&
|
||||
((messageType == "reply" && canReply && !chatLockedByOther) || (messageType == "note" && canNote)),
|
||||
) {
|
||||
if (!mutationLoading) {
|
||||
|
||||
@@ -530,7 +530,7 @@ class DeskHubViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTicket(status: String, assignedStaffId: Int?) {
|
||||
fun updateTicket(status: String, assignedStaffId: Int?, resolutionCode: String?) {
|
||||
val ticket = state.value.selectedTicket ?: return
|
||||
viewModelScope.launch {
|
||||
mutableState.update { it.copy(mutationLoading = true, mutationError = null) }
|
||||
@@ -541,6 +541,7 @@ class DeskHubViewModel(
|
||||
status = status.takeIf { it != ticket.summary.status },
|
||||
assignedStaffId = assignedStaffId,
|
||||
updateAssignment = updateAssignment,
|
||||
resolutionCode = resolutionCode,
|
||||
)
|
||||
}.onSuccess {
|
||||
mutableState.update { it.copy(mutationLoading = false) }
|
||||
@@ -720,11 +721,11 @@ class DeskHubViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun addMessage(type: String, message: String, setStatus: String?, signature: String?, onSuccess: () -> Unit) {
|
||||
fun addMessage(type: String, message: String, setStatus: String?, signature: String?, resolutionCode: String?, onSuccess: () -> Unit) {
|
||||
val number = state.value.selectedTicket?.summary?.number ?: return
|
||||
viewModelScope.launch {
|
||||
mutableState.update { it.copy(mutationLoading = true, mutationError = null) }
|
||||
runCatching { repository.addMessage(number, type, message, setStatus, signature) }
|
||||
runCatching { repository.addMessage(number, type, message, setStatus, signature, resolutionCode) }
|
||||
.onSuccess {
|
||||
mutableState.update { it.copy(mutationLoading = false) }
|
||||
onSuccess()
|
||||
|
||||
Reference in New Issue
Block a user