From 2c98b348d5e1ddb89bf3b811e252dc1982eca1d4 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 3 Jul 2025 20:53:30 +0800 Subject: [PATCH] :sparkles: Abuse reports --- assets/i18n/en-US.json | 1 + lib/models/abuse_report.dart | 25 +++ lib/models/abuse_report.freezed.dart | 202 ++++++++++++++++++ lib/models/abuse_report.g.dart | 46 ++++ lib/route.dart | 17 +- lib/screens/account.dart | 10 +- lib/screens/account/profile.g.dart | 4 +- .../article_detail.dart} | 0 lib/screens/realm/realm_detail.dart | 1 + lib/screens/reports/report_detail.dart | 66 ++++++ lib/screens/reports/report_list.dart | 59 +++++ lib/services/abuse_report_service.dart | 25 +++ 12 files changed, 452 insertions(+), 4 deletions(-) create mode 100644 lib/models/abuse_report.dart create mode 100644 lib/models/abuse_report.freezed.dart create mode 100644 lib/models/abuse_report.g.dart rename lib/screens/{article_detail_screen.dart => discovery/article_detail.dart} (100%) create mode 100644 lib/screens/reports/report_detail.dart create mode 100644 lib/screens/reports/report_list.dart create mode 100644 lib/services/abuse_report_service.dart diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 1f5c07d..d26cc9a 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -590,6 +590,7 @@ "yes": "Yes", "navigateToChat": "Navigate to Chat", "wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?", + "abuseReports": "Abuse Reports", "abuseReport": "Report", "abuseReportTitle": "Report Content", "abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.", diff --git a/lib/models/abuse_report.dart b/lib/models/abuse_report.dart new file mode 100644 index 0000000..630320a --- /dev/null +++ b/lib/models/abuse_report.dart @@ -0,0 +1,25 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:island/models/user.dart'; + +part 'abuse_report.freezed.dart'; +part 'abuse_report.g.dart'; + +@freezed +sealed class SnAbuseReport with _$SnAbuseReport { + const factory SnAbuseReport({ + required String id, + required String resourceIdentifier, + required int type, + required String reason, + required DateTime? resolvedAt, + required String? resolution, + required String accountId, + required SnAccount? account, + required DateTime createdAt, + required DateTime updatedAt, + required DateTime? deletedAt, + }) = _SnAbuseReport; + + factory SnAbuseReport.fromJson(Map json) => + _$SnAbuseReportFromJson(json); +} diff --git a/lib/models/abuse_report.freezed.dart b/lib/models/abuse_report.freezed.dart new file mode 100644 index 0000000..ba3cffb --- /dev/null +++ b/lib/models/abuse_report.freezed.dart @@ -0,0 +1,202 @@ +// dart format width=80 +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'abuse_report.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$SnAbuseReport { + + String get id; String get resourceIdentifier; int get type; String get reason; DateTime? get resolvedAt; String? get resolution; String get accountId; SnAccount? get account; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; +/// Create a copy of SnAbuseReport +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SnAbuseReportCopyWith get copyWith => _$SnAbuseReportCopyWithImpl(this as SnAbuseReport, _$identity); + + /// Serializes this SnAbuseReport to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAbuseReport&&(identical(other.id, id) || other.id == id)&&(identical(other.resourceIdentifier, resourceIdentifier) || other.resourceIdentifier == resourceIdentifier)&&(identical(other.type, type) || other.type == type)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.resolvedAt, resolvedAt) || other.resolvedAt == resolvedAt)&&(identical(other.resolution, resolution) || other.resolution == resolution)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,resourceIdentifier,type,reason,resolvedAt,resolution,accountId,account,createdAt,updatedAt,deletedAt); + +@override +String toString() { + return 'SnAbuseReport(id: $id, resourceIdentifier: $resourceIdentifier, type: $type, reason: $reason, resolvedAt: $resolvedAt, resolution: $resolution, accountId: $accountId, account: $account, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; +} + + +} + +/// @nodoc +abstract mixin class $SnAbuseReportCopyWith<$Res> { + factory $SnAbuseReportCopyWith(SnAbuseReport value, $Res Function(SnAbuseReport) _then) = _$SnAbuseReportCopyWithImpl; +@useResult +$Res call({ + String id, String resourceIdentifier, int type, String reason, DateTime? resolvedAt, String? resolution, String accountId, SnAccount? account, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt +}); + + +$SnAccountCopyWith<$Res>? get account; + +} +/// @nodoc +class _$SnAbuseReportCopyWithImpl<$Res> + implements $SnAbuseReportCopyWith<$Res> { + _$SnAbuseReportCopyWithImpl(this._self, this._then); + + final SnAbuseReport _self; + final $Res Function(SnAbuseReport) _then; + +/// Create a copy of SnAbuseReport +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? resourceIdentifier = null,Object? type = null,Object? reason = null,Object? resolvedAt = freezed,Object? resolution = freezed,Object? accountId = null,Object? account = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,resourceIdentifier: null == resourceIdentifier ? _self.resourceIdentifier : resourceIdentifier // ignore: cast_nullable_to_non_nullable +as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as int,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable +as String,resolvedAt: freezed == resolvedAt ? _self.resolvedAt : resolvedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,resolution: freezed == resolution ? _self.resolution : resolution // ignore: cast_nullable_to_non_nullable +as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable +as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable +as SnAccount?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} +/// Create a copy of SnAbuseReport +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnAccountCopyWith<$Res>? get account { + if (_self.account == null) { + return null; + } + + return $SnAccountCopyWith<$Res>(_self.account!, (value) { + return _then(_self.copyWith(account: value)); + }); +} +} + + +/// @nodoc +@JsonSerializable() + +class _SnAbuseReport implements SnAbuseReport { + const _SnAbuseReport({required this.id, required this.resourceIdentifier, required this.type, required this.reason, required this.resolvedAt, required this.resolution, required this.accountId, required this.account, required this.createdAt, required this.updatedAt, required this.deletedAt}); + factory _SnAbuseReport.fromJson(Map json) => _$SnAbuseReportFromJson(json); + +@override final String id; +@override final String resourceIdentifier; +@override final int type; +@override final String reason; +@override final DateTime? resolvedAt; +@override final String? resolution; +@override final String accountId; +@override final SnAccount? account; +@override final DateTime createdAt; +@override final DateTime updatedAt; +@override final DateTime? deletedAt; + +/// Create a copy of SnAbuseReport +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SnAbuseReportCopyWith<_SnAbuseReport> get copyWith => __$SnAbuseReportCopyWithImpl<_SnAbuseReport>(this, _$identity); + +@override +Map toJson() { + return _$SnAbuseReportToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAbuseReport&&(identical(other.id, id) || other.id == id)&&(identical(other.resourceIdentifier, resourceIdentifier) || other.resourceIdentifier == resourceIdentifier)&&(identical(other.type, type) || other.type == type)&&(identical(other.reason, reason) || other.reason == reason)&&(identical(other.resolvedAt, resolvedAt) || other.resolvedAt == resolvedAt)&&(identical(other.resolution, resolution) || other.resolution == resolution)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,resourceIdentifier,type,reason,resolvedAt,resolution,accountId,account,createdAt,updatedAt,deletedAt); + +@override +String toString() { + return 'SnAbuseReport(id: $id, resourceIdentifier: $resourceIdentifier, type: $type, reason: $reason, resolvedAt: $resolvedAt, resolution: $resolution, accountId: $accountId, account: $account, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; +} + + +} + +/// @nodoc +abstract mixin class _$SnAbuseReportCopyWith<$Res> implements $SnAbuseReportCopyWith<$Res> { + factory _$SnAbuseReportCopyWith(_SnAbuseReport value, $Res Function(_SnAbuseReport) _then) = __$SnAbuseReportCopyWithImpl; +@override @useResult +$Res call({ + String id, String resourceIdentifier, int type, String reason, DateTime? resolvedAt, String? resolution, String accountId, SnAccount? account, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt +}); + + +@override $SnAccountCopyWith<$Res>? get account; + +} +/// @nodoc +class __$SnAbuseReportCopyWithImpl<$Res> + implements _$SnAbuseReportCopyWith<$Res> { + __$SnAbuseReportCopyWithImpl(this._self, this._then); + + final _SnAbuseReport _self; + final $Res Function(_SnAbuseReport) _then; + +/// Create a copy of SnAbuseReport +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? resourceIdentifier = null,Object? type = null,Object? reason = null,Object? resolvedAt = freezed,Object? resolution = freezed,Object? accountId = null,Object? account = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { + return _then(_SnAbuseReport( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,resourceIdentifier: null == resourceIdentifier ? _self.resourceIdentifier : resourceIdentifier // ignore: cast_nullable_to_non_nullable +as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as int,reason: null == reason ? _self.reason : reason // ignore: cast_nullable_to_non_nullable +as String,resolvedAt: freezed == resolvedAt ? _self.resolvedAt : resolvedAt // ignore: cast_nullable_to_non_nullable +as DateTime?,resolution: freezed == resolution ? _self.resolution : resolution // ignore: cast_nullable_to_non_nullable +as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable +as String,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable +as SnAccount?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} + +/// Create a copy of SnAbuseReport +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnAccountCopyWith<$Res>? get account { + if (_self.account == null) { + return null; + } + + return $SnAccountCopyWith<$Res>(_self.account!, (value) { + return _then(_self.copyWith(account: value)); + }); +} +} + +// dart format on diff --git a/lib/models/abuse_report.g.dart b/lib/models/abuse_report.g.dart new file mode 100644 index 0000000..d78ad15 --- /dev/null +++ b/lib/models/abuse_report.g.dart @@ -0,0 +1,46 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'abuse_report.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_SnAbuseReport _$SnAbuseReportFromJson(Map json) => + _SnAbuseReport( + id: json['id'] as String, + resourceIdentifier: json['resource_identifier'] as String, + type: (json['type'] as num).toInt(), + reason: json['reason'] as String, + resolvedAt: + json['resolved_at'] == null + ? null + : DateTime.parse(json['resolved_at'] as String), + resolution: json['resolution'] as String?, + accountId: json['account_id'] as String, + account: + json['account'] == null + ? null + : SnAccount.fromJson(json['account'] as Map), + createdAt: DateTime.parse(json['created_at'] as String), + updatedAt: DateTime.parse(json['updated_at'] as String), + deletedAt: + json['deleted_at'] == null + ? null + : DateTime.parse(json['deleted_at'] as String), + ); + +Map _$SnAbuseReportToJson(_SnAbuseReport instance) => + { + 'id': instance.id, + 'resource_identifier': instance.resourceIdentifier, + 'type': instance.type, + 'reason': instance.reason, + 'resolved_at': instance.resolvedAt?.toIso8601String(), + 'resolution': instance.resolution, + 'account_id': instance.accountId, + 'account': instance.account?.toJson(), + 'created_at': instance.createdAt.toIso8601String(), + 'updated_at': instance.updatedAt.toIso8601String(), + 'deleted_at': instance.deletedAt?.toIso8601String(), + }; diff --git a/lib/route.dart b/lib/route.dart index 78b97e8..d9266e0 100644 --- a/lib/route.dart +++ b/lib/route.dart @@ -11,7 +11,7 @@ import 'package:island/screens/posts/post_search.dart'; import 'package:island/widgets/app_wrapper.dart'; import 'package:island/screens/tabs.dart'; import 'package:island/screens/explore.dart'; -import 'package:island/screens/article_detail_screen.dart'; +import 'package:island/screens/discovery/article_detail.dart'; import 'package:island/screens/account.dart'; import 'package:island/screens/notification.dart'; import 'package:island/screens/wallet.dart'; @@ -41,6 +41,8 @@ import 'package:island/screens/realm/realms.dart'; import 'package:island/screens/realm/realm_detail.dart'; import 'package:island/screens/account/event_calendar.dart'; import 'package:island/screens/discovery/realms.dart'; +import 'package:island/screens/reports/report_detail.dart'; +import 'package:island/screens/reports/report_list.dart'; // Shell route keys for nested navigation final rootNavigatorKey = GlobalKey(); @@ -258,6 +260,19 @@ final routerProvider = Provider((ref) { builder: (context, state) => const AboutScreen(), ), + GoRoute( + path: '/safety/reports/me', + builder: (context, state) => const AbuseReportListScreen(), + ), + + GoRoute( + path: '/safety/reports/me/:id', + builder: (context, state) { + final id = state.pathParameters['id']!; + return AbuseReportDetailScreen(reportId: id); + }, + ), + // Main tabs with TabsScreen shell ShellRoute( navigatorKey: _tabsShellKey, diff --git a/lib/screens/account.dart b/lib/screens/account.dart index 87de77c..bf5ae8b 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -222,9 +222,17 @@ class AccountScreen extends HookConsumerWidget { contentPadding: EdgeInsets.symmetric(horizontal: 24), title: Text('relationships').tr(), onTap: () { - context.push('/account/relationship'); + context.push('/account/relationships'); }, ), + ListTile( + minTileHeight: 48, + title: Text('abuseReports').tr(), + contentPadding: const EdgeInsets.only(left: 24, right: 17), + leading: const Icon(Symbols.gavel), + trailing: const Icon(Symbols.chevron_right), + onTap: () => context.push('/safety/reports/me'), + ), const Divider(height: 1).padding(vertical: 8), ListTile( minTileHeight: 48, diff --git a/lib/screens/account/profile.g.dart b/lib/screens/account/profile.g.dart index 5817caa..1fd7db1 100644 --- a/lib/screens/account/profile.g.dart +++ b/lib/screens/account/profile.g.dart @@ -395,7 +395,7 @@ class _AccountAppbarForcegroundColorProviderElement String get uname => (origin as AccountAppbarForcegroundColorProvider).uname; } -String _$accountDirectChatHash() => r'60d0015fc2a3c8fc2190bb41d6818cf3027d9d0a'; +String _$accountDirectChatHash() => r'3d28c8ba8079159f724fe3cd47bbe00db55cedcc'; /// See also [accountDirectChat]. @ProviderFor(accountDirectChat) @@ -517,7 +517,7 @@ class _AccountDirectChatProviderElement } String _$accountRelationshipHash() => - r'cb7d0d3f8cd4f23ad9d2d529872c540dac483d4f'; + r'0be2420e1f6a65b8dcead9617191471924aaf232'; /// See also [accountRelationship]. @ProviderFor(accountRelationship) diff --git a/lib/screens/article_detail_screen.dart b/lib/screens/discovery/article_detail.dart similarity index 100% rename from lib/screens/article_detail_screen.dart rename to lib/screens/discovery/article_detail.dart diff --git a/lib/screens/realm/realm_detail.dart b/lib/screens/realm/realm_detail.dart index 948c4db..48145cf 100644 --- a/lib/screens/realm/realm_detail.dart +++ b/lib/screens/realm/realm_detail.dart @@ -77,6 +77,7 @@ class RealmDetailScreen extends HookConsumerWidget { ); return AppScaffold( + noBackground: false, body: realmState.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => Center(child: Text('Error: $error')), diff --git a/lib/screens/reports/report_detail.dart b/lib/screens/reports/report_detail.dart new file mode 100644 index 0000000..8d78586 --- /dev/null +++ b/lib/screens/reports/report_detail.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:island/models/abuse_report.dart'; +import 'package:island/services/abuse_report_service.dart'; + +class AbuseReportDetailScreen extends ConsumerStatefulWidget { + final String reportId; + + const AbuseReportDetailScreen({super.key, required this.reportId}); + + @override + ConsumerState createState() => + _AbuseReportDetailScreenState(); +} + +class _AbuseReportDetailScreenState + extends ConsumerState { + Future? _reportFuture; + + @override + void initState() { + super.initState(); + _reportFuture = + ref.read(abuseReportServiceProvider).getReport(widget.reportId); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Abuse Report Details'), + ), + body: FutureBuilder( + future: _reportFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else if (snapshot.hasData) { + final report = snapshot.data!; + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Report ID: ${report.id}'), + Text('Resource Identifier: ${report.resourceIdentifier}'), + Text('Type: ${report.type}'), + Text('Reason: ${report.reason}'), + Text('Resolved At: ${report.resolvedAt}'), + Text('Resolution: ${report.resolution}'), + Text('Account ID: ${report.accountId}'), + Text('Created At: ${report.createdAt}'), + Text('Updated At: ${report.updatedAt}'), + ], + ), + ); + } else { + return const Center(child: Text('No data')); + } + }, + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/reports/report_list.dart b/lib/screens/reports/report_list.dart new file mode 100644 index 0000000..9bfa8c7 --- /dev/null +++ b/lib/screens/reports/report_list.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:island/models/abuse_report.dart'; +import 'package:island/services/abuse_report_service.dart'; + +class AbuseReportListScreen extends ConsumerStatefulWidget { + const AbuseReportListScreen({super.key}); + + @override + ConsumerState createState() => + _AbuseReportListScreenState(); +} + +class _AbuseReportListScreenState extends ConsumerState { + Future>? _reportsFuture; + + @override + void initState() { + super.initState(); + _reportsFuture = ref.read(abuseReportServiceProvider).getReports(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('My Abuse Reports'), + ), + body: FutureBuilder>( + future: _reportsFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else if (snapshot.hasData) { + final reports = snapshot.data!; + return ListView.builder( + itemCount: reports.length, + itemBuilder: (context, index) { + final report = reports[index]; + return ListTile( + title: Text(report.reason), + subtitle: Text(report.id), + onTap: () { + context.push('/safety/reports/me/${report.id}'); + }, + ); + }, + ); + } else { + return const Center(child: Text('No data')); + } + }, + ), + ); + } +} diff --git a/lib/services/abuse_report_service.dart b/lib/services/abuse_report_service.dart new file mode 100644 index 0000000..9ee7778 --- /dev/null +++ b/lib/services/abuse_report_service.dart @@ -0,0 +1,25 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:island/models/abuse_report.dart'; +import 'package:island/pods/network.dart'; + +final abuseReportServiceProvider = Provider((ref) { + return AbuseReportService(ref); +}); + +class AbuseReportService { + final Ref ref; + AbuseReportService(this.ref); + + Future getReport(String id) async { + final response = + await ref.read(apiClientProvider).get('/safety/reports/me/$id'); + return SnAbuseReport.fromJson(response.data); + } + + Future> getReports() async { + final response = await ref.read(apiClientProvider).get('/safety/reports/me'); + return (response.data as List) + .map((json) => SnAbuseReport.fromJson(json)) + .toList(); + } +}