Files
2026-10-16 01:25:50 +05:30

202 lines
4.9 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'api/support_api.dart';
import 'models/api_exception.dart';
import 'models/support_message.dart';
import 'models/support_ticket.dart';
enum TicketStatusFilter { open, closed, all }
class InboxController extends ChangeNotifier {
InboxController({required this.api});
final SupportApi api;
TicketStatusFilter statusFilter = TicketStatusFilter.open;
String? category;
List<SupportTicket> tickets = [];
bool loading = false;
String? error;
String? activeTicketId;
SupportTicket? threadTicket;
List<SupportMessage> messages = [];
bool threadLoading = false;
String? threadError;
int _listGeneration = 0;
int _threadGeneration = 0;
String? get statusQuery {
switch (statusFilter) {
case TicketStatusFilter.open:
return 'open';
case TicketStatusFilter.closed:
return 'closed';
case TicketStatusFilter.all:
return null;
}
}
Future<void> refreshList({bool showLoading = false}) async {
final generation = ++_listGeneration;
if (showLoading) {
loading = true;
error = null;
notifyListeners();
}
try {
final next = await api.listTickets(
status: statusQuery,
category: category,
);
if (generation != _listGeneration) {
return;
}
tickets = next;
error = null;
} on ApiException catch (caught) {
if (generation != _listGeneration || caught.isUnauthorized) {
return;
}
error = caught.message;
} finally {
if (generation == _listGeneration) {
loading = false;
notifyListeners();
}
}
}
Future<void> refreshThread({bool showLoading = false}) async {
final ticketId = activeTicketId;
if (ticketId == null) {
return;
}
final generation = ++_threadGeneration;
if (showLoading) {
threadLoading = true;
threadError = null;
notifyListeners();
}
try {
final thread = await api.getThread(ticketId);
if (generation != _threadGeneration || activeTicketId != ticketId) {
return;
}
_applyThread(thread);
threadError = null;
} on ApiException catch (caught) {
if (generation != _threadGeneration || caught.isUnauthorized) {
return;
}
threadError = caught.message;
} finally {
if (generation == _threadGeneration) {
threadLoading = false;
notifyListeners();
}
}
}
Future<String?> sendReply(String raw) async {
final ticketId = activeTicketId;
if (ticketId == null) {
return 'No ticket is open.';
}
final validation = validateReplyBody(raw);
if (validation != null) {
return validation;
}
final generation = ++_threadGeneration;
try {
final thread = await api.reply(ticketId, raw.trim());
if (generation != _threadGeneration || activeTicketId != ticketId) {
return null;
}
_applyThread(thread);
threadError = null;
notifyListeners();
return null;
} on ApiException catch (caught) {
if (caught.isUnauthorized) {
return null;
}
return caught.message;
}
}
Future<String?> setStatus(String status) async {
final ticketId = activeTicketId;
if (ticketId == null) {
return 'No ticket is open.';
}
final generation = ++_threadGeneration;
try {
final thread = await api.setStatus(ticketId, status);
if (generation != _threadGeneration || activeTicketId != ticketId) {
return null;
}
_applyThread(thread);
threadError = null;
notifyListeners();
return null;
} on ApiException catch (caught) {
if (caught.isUnauthorized) {
return null;
}
return caught.message;
}
}
void setStatusFilter(TicketStatusFilter value) {
if (statusFilter == value) {
return;
}
statusFilter = value;
tickets = [];
unawaited(refreshList(showLoading: true));
}
void setCategory(String? value) {
final next = (value == null || value.isEmpty) ? null : value;
if (category == next) {
return;
}
category = next;
tickets = [];
unawaited(refreshList(showLoading: true));
}
void reset() {
_listGeneration++;
_threadGeneration++;
statusFilter = TicketStatusFilter.open;
category = null;
tickets = [];
loading = false;
error = null;
activeTicketId = null;
threadTicket = null;
messages = [];
threadLoading = false;
threadError = null;
notifyListeners();
}
void _applyThread(SupportThread thread) {
threadTicket = thread.ticket;
messages = thread.messages;
final index = tickets.indexWhere((ticket) => ticket.id == thread.ticket.id);
if (index >= 0) {
tickets = [
for (var i = 0; i < tickets.length; i++)
if (i == index) thread.ticket else tickets[i],
];
}
}
}