FlagFacade

Updated FlagModel Structure

@freezed
class FlagModel with _$FlagModel {
  const factory FlagModel({
    @JsonKey(includeFromJson: false, includeToJson: false) String? id,
    @TimestampConverter() required FieldValue createdAt,
    @TimestampConverter() required FieldValue updatedAt,
    @Default(IssueStatus.pending) IssueStatus status,
    @Default(false) bool danger,
    @Default(false) bool acknowledged,
    required FlagType flagType,
    required String fromUid,
    required String toUid,
    required String objId,
    required ModelObjType objType,
    required String message,
    CommentModel? resolution,
    @TimestampConverter() FieldValue? resolvedAt,
    @Default(0) int commentCount, // ✅ ADDED: Track comment count for UI
    @TimestampMapConverter() Map<String, FieldValue>? activity,
    @TimestampMapConverter() Map<String, FieldValue>? updates,
  }) = _FlagModel;
}

Firestore Structure

/flag/{flagId}                          <- Main flag document
  ├── flagType: "spam"
  ├── message: "Inappropriate content"
  ├── commentCount: 3                   <- Cached count for UI
  ├── createdAt: timestamp
  └── updatedAt: timestamp

  /comments/{commentId}                 <- Sub-collection
    ├── fromUid: "user123"
    ├── toUid: "admin456"
    ├── comment: "This is suspicious"
    ├── isAdmin: false
    ├── createdAt: timestamp
    └── updatedAt: timestamp

  /comments/{commentId2}                <- Another comment
    ├── fromUid: "moderator_001"
    ├── comment: "We're investigating"
    ├── isAdmin: true
    └── ...

Usage Examples

Adding Comments

// Create a comment
final comment = CommentModel.withTimestamp(
  fromUid: 'user123',
  toUid: 'admin456',
  comment: 'This looks suspicious',
  isAdmin: false,
);

// Add to flag sub-collection
final result = await FlagCommentsService.addComment(
  flagId: 'flag_abc123',
  comment: comment,
);

print('Comment added: ${result?.comment}');

Real-time Comment Stream

// Listen to all comments for a flag
final stream = FlagCommentsService.getCommentsStream(
  flagId: 'flag_abc123',
  limit: 50,
);

stream.listen((comments) {
  print('Flag has ${comments.length} comments');
  for (final comment in comments) {
    print('- ${comment.comment} (${comment.isAdmin ? 'Admin' : 'User'})');
  }
});

Flag Updates Stream

// Listen to flag changes (including comment count updates)
final flagStream = FlagCommentsService.getFlagWithCommentsStream(
  flagId: 'flag_abc123',
);

flagStream.listen((flag) {
  if (flag != null) {
    print('Flag comment count: ${flag.commentCount}');
    print('Flag status: ${flag.status}');
  }
});

Getting Comments

// Get all comments (paginated)
final comments = await FlagCommentsService.getComments(
  flagId: 'flag_abc123',
  limit: 20,
);

print('Retrieved ${comments.length} comments');

Updating Comments

final updatedComment = existingComment.copyWith(
  comment: 'Updated comment text',
  updatedAt: kServerTimestamp,
);

final result = await FlagCommentsService.updateComment(
  flagId: 'flag_abc123',
  comment: updatedComment,
);

Deleting Comments

await FlagCommentsService.deleteComment(
  flagId: 'flag_abc123',
  commentId: 'comment_xyz789',
);