import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart'; import 'package:brick_sqlite/brick_sqlite.dart'; import 'package:brick_supabase/brick_supabase.dart'; import '../utils/app_time.dart'; /// Work categories for a programmer task. Values are the TitleCase display /// strings stored directly in the `programmer_task_category` Postgres enum /// (same convention as the IT-support request_type / request_category enums). class ProgrammerTaskCategory { static const softwareSupport = 'Software Support'; static const softwareDevelopment = 'Software Development'; static const softwareEnhancement = 'Software Enhancement'; static const bugFix = 'Bug Fix'; static const meeting = 'Meeting'; static const facilitateEvent = 'Facilitate Event'; static const others = 'Others'; static const all = [ softwareSupport, softwareDevelopment, softwareEnhancement, bugFix, meeting, facilitateEvent, others, ]; /// Enum values already read as display labels, but this keeps the call site /// symmetric with other models and guards unknown values. static String label(String category) => all.contains(category) ? category : category; } /// Status lifecycle for a programmer task. /// /// `queued -> in_progress -> completed | cancelled`. Pause/resume are recorded /// as activity-log events (not statuses): a paused task keeps `inProgress`. class ProgrammerTaskStatus { static const queued = 'queued'; static const inProgress = 'in_progress'; static const completed = 'completed'; static const cancelled = 'cancelled'; static const all = [queued, inProgress, completed, cancelled]; static const terminal = [completed, cancelled]; static String label(String status) { switch (status) { case queued: return 'Queued'; case inProgress: return 'In Progress'; case completed: return 'Completed'; case cancelled: return 'Cancelled'; default: return status; } } } @ConnectOfflineFirstWithSupabase( supabaseConfig: SupabaseSerializable(tableName: 'programmer_tasks'), ) class ProgrammerTask extends OfflineFirstWithSupabaseModel { final String id; final String title; final String? description; final String category; final String status; final int priority; final String? assigneeId; final String? creatorId; final String? projectId; final DateTime createdAt; final DateTime? startedAt; final DateTime? completedAt; final DateTime? cancelledAt; final String? cancellationReason; final DateTime updatedAt; ProgrammerTask({ required this.id, required this.title, this.description, required this.category, required this.status, this.priority = 1, this.assigneeId, this.creatorId, this.projectId, required this.createdAt, this.startedAt, this.completedAt, this.cancelledAt, this.cancellationReason, required this.updatedAt, }); bool get isTerminal => ProgrammerTaskStatus.terminal.contains(status); @Supabase(ignore: true) @Sqlite(ignore: true) @override bool operator ==(Object other) => identical(this, other) || other is ProgrammerTask && runtimeType == other.runtimeType && id == other.id && status == other.status && updatedAt == other.updatedAt; @Supabase(ignore: true) @Sqlite(ignore: true) @override int get hashCode => Object.hash(id, status, updatedAt); factory ProgrammerTask.fromMap(Map map) { return ProgrammerTask( id: map['id'].toString(), title: map['title'] as String? ?? '', description: map['description'] as String?, category: map['category'] as String? ?? ProgrammerTaskCategory.others, status: map['status'] as String? ?? ProgrammerTaskStatus.queued, priority: (map['priority'] as num?)?.toInt() ?? 1, assigneeId: map['assignee_id']?.toString(), creatorId: map['creator_id']?.toString(), projectId: map['project_id']?.toString(), createdAt: AppTime.parse(map['created_at'] as String), startedAt: map['started_at'] == null ? null : AppTime.parse(map['started_at'] as String), completedAt: map['completed_at'] == null ? null : AppTime.parse(map['completed_at'] as String), cancelledAt: map['cancelled_at'] == null ? null : AppTime.parse(map['cancelled_at'] as String), cancellationReason: map['cancellation_reason'] as String?, updatedAt: map['updated_at'] == null ? AppTime.parse(map['created_at'] as String) : AppTime.parse(map['updated_at'] as String), ); } }