forked from eatvio/eatvio_app
feat: Implement comprehensive navigation logic for various notification types within the NotificationWidget.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -20,4 +20,5 @@ env/.env
|
||||
.env
|
||||
android/key.properties
|
||||
app/upload-keystore.jks
|
||||
coverage/
|
||||
coverage/
|
||||
backend/
|
||||
@@ -17,12 +17,25 @@ class ContentRoutes {
|
||||
name: 'aboutPlanScreen',
|
||||
builder: (context, state) {
|
||||
final slug = state.uri.queryParameters['slug'];
|
||||
final commentIdStr = state.uri.queryParameters['commentId'];
|
||||
final commentId = int.tryParse(commentIdStr ?? '');
|
||||
|
||||
if (slug != null) {
|
||||
return AboutPlanScreen(slug: slug, navigateToComments: false, index: null);
|
||||
return AboutPlanScreen(
|
||||
slug: slug,
|
||||
navigateToComments: commentId != null,
|
||||
index: null,
|
||||
highlightedCommentId: commentId,
|
||||
);
|
||||
}
|
||||
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
return AboutPlanScreen(slug: data['slug'] as String, index: data['index'] as int?, navigateToComments: data['navigateToComments'] as bool);
|
||||
return AboutPlanScreen(
|
||||
slug: data['slug'] as String,
|
||||
index: data['index'] as int?,
|
||||
navigateToComments: data['navigateToComments'] as bool? ?? (data['commentId'] != null),
|
||||
highlightedCommentId: data['commentId'] as int?,
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
@@ -30,12 +43,25 @@ class ContentRoutes {
|
||||
name: 'aboutRecipesScreen',
|
||||
builder: (context, state) {
|
||||
final slug = state.uri.queryParameters['slug'];
|
||||
final commentIdStr = state.uri.queryParameters['commentId'];
|
||||
final commentId = int.tryParse(commentIdStr ?? '');
|
||||
|
||||
if (slug != null) {
|
||||
return AboutRecipeScreen(recipeSlug: slug, navigateToComments: false, index: null);
|
||||
return AboutRecipeScreen(
|
||||
recipeSlug: slug,
|
||||
navigateToComments: commentId != null,
|
||||
index: null,
|
||||
highlightedCommentId: commentId,
|
||||
);
|
||||
}
|
||||
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
return AboutRecipeScreen(recipeSlug: data['recipe'] as String, index: data['index'] as int?, navigateToComments: data['navigateToComments'] as bool);
|
||||
return AboutRecipeScreen(
|
||||
recipeSlug: data['recipe'] as String,
|
||||
index: data['index'] as int?,
|
||||
navigateToComments: data['navigateToComments'] as bool? ?? (data['commentId'] != null),
|
||||
highlightedCommentId: data['commentId'] as int?,
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
@@ -43,15 +69,25 @@ class ContentRoutes {
|
||||
name: 'aboutDietScreen',
|
||||
builder: (context, state) {
|
||||
final slug = state.uri.queryParameters['slug'];
|
||||
final commentIdStr = state.uri.queryParameters['commentId'];
|
||||
final commentId = int.tryParse(commentIdStr ?? '');
|
||||
|
||||
if (slug != null) {
|
||||
return AboutDietScreen(id: null, slug: slug, index: null, navigateToComments: false);
|
||||
return AboutDietScreen(
|
||||
id: null,
|
||||
slug: slug,
|
||||
index: null,
|
||||
navigateToComments: commentId != null,
|
||||
highlightedCommentId: commentId,
|
||||
);
|
||||
}
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
return AboutDietScreen(
|
||||
id: data['id'] as int?,
|
||||
slug: data['slug'] as String?,
|
||||
index: data['index'] as int?,
|
||||
navigateToComments: data['navigateToComments'] as bool,
|
||||
navigateToComments: data['navigateToComments'] as bool? ?? (data['commentId'] != null),
|
||||
highlightedCommentId: data['commentId'] as int?,
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -65,12 +101,26 @@ class ContentRoutes {
|
||||
name: 'blogPostScreen',
|
||||
builder: (context, state) {
|
||||
final id = state.uri.queryParameters['id'];
|
||||
final commentIdStr = state.uri.queryParameters['commentId'];
|
||||
final commentId = int.tryParse(commentIdStr ?? '');
|
||||
final parsedId = int.tryParse(id ?? '');
|
||||
|
||||
if (parsedId != null) {
|
||||
return BlogPostScreen(id: parsedId);
|
||||
return BlogPostScreen(
|
||||
id: parsedId,
|
||||
highlightedCommentId: commentId,
|
||||
);
|
||||
}
|
||||
|
||||
return BlogPostScreen(id: state.extra as int);
|
||||
if (state.extra is int) {
|
||||
return BlogPostScreen(id: state.extra as int);
|
||||
}
|
||||
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
return BlogPostScreen(
|
||||
id: data['id'] as int,
|
||||
highlightedCommentId: data['commentId'] as int?,
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
@@ -21,8 +21,9 @@ import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class BlogPostScreen extends StatefulWidget {
|
||||
final int id;
|
||||
final int? highlightedCommentId;
|
||||
|
||||
const BlogPostScreen({super.key, required this.id});
|
||||
const BlogPostScreen({super.key, required this.id, this.highlightedCommentId});
|
||||
|
||||
@override
|
||||
State<BlogPostScreen> createState() => _BlogPostScreenState();
|
||||
@@ -303,7 +304,13 @@ class _BlogPostScreenState extends State<BlogPostScreen> {
|
||||
const SizedBox(height: 16),
|
||||
if (state is CommentsStateLoading) const Loader(),
|
||||
if (state is CommentsStateLoaded)
|
||||
CommentsWidget(id: widget.id.toString(), commentSourceType: CommentSourceType.blogPost, comment: state.comment, replyId: replyId),
|
||||
CommentsWidget(
|
||||
id: widget.id.toString(),
|
||||
commentSourceType: CommentSourceType.blogPost,
|
||||
comment: state.comment,
|
||||
replyId: replyId,
|
||||
highlightedCommentId: widget.highlightedCommentId,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -568,6 +568,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
||||
CustomTextFormField(key: AppKeys.blogPostCreateScreenVideoLinkTextField, controller: videoUrlController),
|
||||
const SizedBox(height: 80),
|
||||
_createBlogPostButton(),
|
||||
const SizedBox(height: 80),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -37,8 +37,9 @@ class AboutDietScreen extends StatefulWidget {
|
||||
final int? id;
|
||||
final int? index;
|
||||
final bool navigateToComments;
|
||||
final int? highlightedCommentId;
|
||||
|
||||
const AboutDietScreen({super.key, required this.index, required this.navigateToComments, required this.slug, required this.id});
|
||||
const AboutDietScreen({super.key, required this.index, required this.navigateToComments, required this.slug, required this.id, this.highlightedCommentId});
|
||||
|
||||
@override
|
||||
State<AboutDietScreen> createState() => _AboutDietScreenState();
|
||||
@@ -433,6 +434,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
commentSourceType: CommentSourceType.diet,
|
||||
comment: state.comment,
|
||||
replyId: replyId,
|
||||
highlightedCommentId: widget.highlightedCommentId,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -23,14 +23,60 @@ class CommentsWidget extends StatefulWidget {
|
||||
final CommentSourceType commentSourceType;
|
||||
final CommentModel comment;
|
||||
final int? replyId;
|
||||
final int? highlightedCommentId;
|
||||
|
||||
const CommentsWidget({super.key, required this.id, required this.commentSourceType, required this.comment, this.replyId});
|
||||
const CommentsWidget({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.commentSourceType,
|
||||
required this.comment,
|
||||
this.replyId,
|
||||
this.highlightedCommentId,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CommentsWidget> createState() => _CommentsWidgetState();
|
||||
}
|
||||
|
||||
class _CommentsWidgetState extends State<CommentsWidget> {
|
||||
final Map<int, GlobalKey> commentKeys = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.highlightedCommentId != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_scrollToHighlightedComment();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(CommentsWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.highlightedCommentId != null && widget.highlightedCommentId != oldWidget.highlightedCommentId) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_scrollToHighlightedComment();
|
||||
});
|
||||
} else if (widget.comment != oldWidget.comment && widget.highlightedCommentId != null) {
|
||||
// Comments might have just loaded
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_scrollToHighlightedComment();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _scrollToHighlightedComment() {
|
||||
final key = commentKeys[widget.highlightedCommentId];
|
||||
if (key != null && key.currentContext != null) {
|
||||
Scrollable.ensureVisible(
|
||||
key.currentContext!,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
@@ -49,8 +95,10 @@ class _CommentsWidgetState extends State<CommentsWidget> {
|
||||
}
|
||||
|
||||
Widget _comment(S s, Comment comment, [double radius = 18, bool isChild = false]) {
|
||||
final key = commentKeys.putIfAbsent(comment.id, () => GlobalKey());
|
||||
final isMe = (sl<ProfileAvatarCubit>().state as ProfileAvatarStateLoaded).profile.slug == comment.authorSlug;
|
||||
return GestureDetector(
|
||||
key: key,
|
||||
onTap: () {
|
||||
showCommentsActionsBottomSheet(
|
||||
context,
|
||||
@@ -83,7 +131,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.replyId == comment.id ? appTheme.blueA400.withValues(alpha: 0.1) : Colors.white,
|
||||
color: (widget.replyId == comment.id || widget.highlightedCommentId == comment.id) ? appTheme.blueA400.withValues(alpha: 0.1) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
|
||||
@@ -215,6 +215,8 @@ class ChosenPlanStartedToConsultantNotification implements BaseNotificationModel
|
||||
final bool isRead;
|
||||
final String planName;
|
||||
final String customerName;
|
||||
final int planId;
|
||||
final int customerId;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
ChosenPlanStartedToConsultantNotification({
|
||||
@@ -222,6 +224,8 @@ class ChosenPlanStartedToConsultantNotification implements BaseNotificationModel
|
||||
required this.isRead,
|
||||
required this.planName,
|
||||
required this.customerName,
|
||||
required this.planId,
|
||||
required this.customerId,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
@@ -231,6 +235,8 @@ class ChosenPlanStartedToConsultantNotification implements BaseNotificationModel
|
||||
isRead: isRead ?? false,
|
||||
planName: json['plan_name'],
|
||||
customerName: json['client_name'],
|
||||
planId: json['plan_id'] ?? 0,
|
||||
customerId: json['client_id'] ?? 0,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
}
|
||||
@@ -420,6 +426,7 @@ class CommentReplied implements BaseNotificationModel {
|
||||
final String author;
|
||||
final int authorId;
|
||||
final int parentCommentId;
|
||||
final int? commentId;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
@@ -431,6 +438,7 @@ class CommentReplied implements BaseNotificationModel {
|
||||
required this.author,
|
||||
required this.authorId,
|
||||
required this.parentCommentId,
|
||||
this.commentId,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
});
|
||||
@@ -444,6 +452,7 @@ class CommentReplied implements BaseNotificationModel {
|
||||
author: json['author'],
|
||||
authorId: json['author_id'],
|
||||
parentCommentId: json['parrent_comment_id'],
|
||||
commentId: json['comment_id'],
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
@@ -504,6 +513,7 @@ class EntityCommented implements BaseNotificationModel {
|
||||
final String authorName;
|
||||
final int authorId;
|
||||
final String authorSlug;
|
||||
final int? commentId;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
@@ -517,6 +527,7 @@ class EntityCommented implements BaseNotificationModel {
|
||||
required this.authorName,
|
||||
required this.authorId,
|
||||
required this.authorSlug,
|
||||
this.commentId,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
});
|
||||
@@ -532,6 +543,7 @@ class EntityCommented implements BaseNotificationModel {
|
||||
authorName: json['author_name'],
|
||||
authorId: json['author_id'],
|
||||
authorSlug: json['author_slug'],
|
||||
commentId: json['comment_id'],
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
@@ -831,7 +843,15 @@ class UnknownNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
UnknownNotification({required this.type, this.isRead = true, DateTime? createdAt}) : createdAt = createdAt ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||
UnknownNotification({required this.type, this.isRead = true, required this.createdAt});
|
||||
|
||||
factory UnknownNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return UnknownNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DietCancelledNotification implements BaseNotificationModel {
|
||||
@@ -1015,16 +1035,28 @@ class StayOnTrackToAuthorNotification implements BaseNotificationModel {
|
||||
final bool isRead;
|
||||
final String planName;
|
||||
final String clientName;
|
||||
final int planId;
|
||||
final int clientId;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
StayOnTrackToAuthorNotification({required this.type, required this.planName, required this.clientName, required this.isRead, required this.createdAt});
|
||||
StayOnTrackToAuthorNotification({
|
||||
required this.type,
|
||||
required this.planName,
|
||||
required this.clientName,
|
||||
required this.planId,
|
||||
required this.clientId,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory StayOnTrackToAuthorNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return StayOnTrackToAuthorNotification(
|
||||
type: type,
|
||||
planName: json['plan_name'] ?? '',
|
||||
clientName: json['client_name'] ?? '',
|
||||
planId: json['plan_id'] ?? 0,
|
||||
clientId: json['client_id'] ?? 0,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
@@ -1326,16 +1358,28 @@ class StayOnTrackToCustomerNotification implements BaseNotificationModel {
|
||||
final bool isRead;
|
||||
final String planName;
|
||||
final String consultantName;
|
||||
final int planId;
|
||||
final int consultantId;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
StayOnTrackToCustomerNotification({required this.type, required this.planName, required this.consultantName, required this.isRead, required this.createdAt});
|
||||
StayOnTrackToCustomerNotification({
|
||||
required this.type,
|
||||
required this.planName,
|
||||
required this.consultantName,
|
||||
required this.planId,
|
||||
required this.consultantId,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory StayOnTrackToCustomerNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return StayOnTrackToCustomerNotification(
|
||||
type: type,
|
||||
planName: json['plan_name'] ?? '',
|
||||
consultantName: json['consultant_name'] ?? '',
|
||||
planId: json['plan_id'] ?? 0,
|
||||
consultantId: json['consultant_id'] ?? 0,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
@@ -1652,14 +1696,16 @@ class ProductStatusUpdatedForAuthorNotification implements BaseNotificationModel
|
||||
final String productName;
|
||||
final String oldStatus;
|
||||
final String newStatus;
|
||||
final String status; // Added to capture single status if old/new aren't provided
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
ProductStatusUpdatedForAuthorNotification({
|
||||
required this.type,
|
||||
required this.productName,
|
||||
required this.oldStatus,
|
||||
required this.newStatus,
|
||||
this.oldStatus = '',
|
||||
this.newStatus = '',
|
||||
this.status = '',
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
});
|
||||
@@ -1670,6 +1716,7 @@ class ProductStatusUpdatedForAuthorNotification implements BaseNotificationModel
|
||||
productName: json['product_name'] ?? '',
|
||||
oldStatus: json['old_status'] ?? '',
|
||||
newStatus: json['new_status'] ?? '',
|
||||
status: json['status'] ?? '',
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
@@ -1724,6 +1771,309 @@ class PersonalDietIsDefinedToCustomerNotification implements BaseNotificationMod
|
||||
}
|
||||
}
|
||||
|
||||
// New Model Classes for Comprehensive Support
|
||||
|
||||
class ConsultantEducationUpdatedNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String consultantName;
|
||||
|
||||
ConsultantEducationUpdatedNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.consultantName,
|
||||
});
|
||||
|
||||
factory ConsultantEducationUpdatedNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return ConsultantEducationUpdatedNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
consultantName: json['consultant_name'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ComplaintRegisteredNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String complaintType;
|
||||
final String entityName;
|
||||
|
||||
ComplaintRegisteredNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.complaintType,
|
||||
required this.entityName,
|
||||
});
|
||||
|
||||
factory ComplaintRegisteredNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return ComplaintRegisteredNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
complaintType: json['complaint_type'] ?? '',
|
||||
entityName: json['entity_name'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ContentUnpublishedNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String reason;
|
||||
final String entityName;
|
||||
|
||||
ContentUnpublishedNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.reason,
|
||||
required this.entityName,
|
||||
});
|
||||
|
||||
factory ContentUnpublishedNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return ContentUnpublishedNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
reason: json['reason'] ?? '',
|
||||
entityName: json['entity_name'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FinanceQuestionCreatedNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String questionText;
|
||||
|
||||
FinanceQuestionCreatedNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.questionText,
|
||||
});
|
||||
|
||||
factory FinanceQuestionCreatedNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return FinanceQuestionCreatedNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
questionText: json['question_text'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NewChatMessageNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String senderName;
|
||||
final String messagePreview;
|
||||
final int chatId;
|
||||
|
||||
NewChatMessageNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.senderName,
|
||||
required this.messagePreview,
|
||||
required this.chatId,
|
||||
});
|
||||
|
||||
factory NewChatMessageNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return NewChatMessageNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
senderName: json['sender_name'] ?? '',
|
||||
messagePreview: json['message_preview'] ?? '',
|
||||
chatId: json['chat_id'] ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CompleteRegistrationNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
CompleteRegistrationNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory CompleteRegistrationNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return CompleteRegistrationNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChosenDietExpiredNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String dietName;
|
||||
|
||||
ChosenDietExpiredNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.dietName,
|
||||
});
|
||||
|
||||
factory ChosenDietExpiredNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return ChosenDietExpiredNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
dietName: json['diet_name'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MotivateUserNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String message;
|
||||
|
||||
MotivateUserNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.message,
|
||||
});
|
||||
|
||||
factory MotivateUserNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return MotivateUserNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
message: json['message'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CommentComplaintNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String commentPreview;
|
||||
final String reason;
|
||||
|
||||
CommentComplaintNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.commentPreview,
|
||||
required this.reason,
|
||||
});
|
||||
|
||||
factory CommentComplaintNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return CommentComplaintNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
commentPreview: json['comment_preview'] ?? '',
|
||||
reason: json['reason'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CommentDeletedNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String commentPreview;
|
||||
|
||||
CommentDeletedNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.commentPreview,
|
||||
});
|
||||
|
||||
factory CommentDeletedNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return CommentDeletedNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
commentPreview: json['comment_preview'] ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserSubscribedNotification implements BaseNotificationModel {
|
||||
@override
|
||||
final NotificationType type;
|
||||
@override
|
||||
final bool isRead;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
final String subscriberName;
|
||||
final int subscriberId;
|
||||
|
||||
UserSubscribedNotification({
|
||||
required this.type,
|
||||
required this.isRead,
|
||||
required this.createdAt,
|
||||
required this.subscriberName,
|
||||
required this.subscriberId,
|
||||
});
|
||||
|
||||
factory UserSubscribedNotification.fromJson(Map<String, dynamic> json, NotificationType type, {bool? isRead, String? createdAt}) {
|
||||
return UserSubscribedNotification(
|
||||
type: type,
|
||||
isRead: isRead ?? false,
|
||||
createdAt: parseDate(createdAt ?? json['created_at'] ?? DateTime.now().toIso8601String()),
|
||||
subscriberName: json['subscriber_name'] ?? '',
|
||||
subscriberId: json['subscriber_id'] ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum NotificationType {
|
||||
// Diet related
|
||||
dietCancelled,
|
||||
@@ -1731,6 +2081,7 @@ enum NotificationType {
|
||||
dietExpired,
|
||||
dietWillStartedIn,
|
||||
dietCanNotBeStarted,
|
||||
chosenDietExpired, // New
|
||||
|
||||
// Plan related
|
||||
personalDietCreationNeeded,
|
||||
@@ -1760,12 +2111,17 @@ enum NotificationType {
|
||||
// Comments
|
||||
entityCommented,
|
||||
commentReplied,
|
||||
commentComplaint, // New
|
||||
commentDeleted, // New
|
||||
|
||||
// Profile
|
||||
phoneChanged,
|
||||
consultantEducationUpdated, // New
|
||||
completeRegistration, // New
|
||||
|
||||
// Subscription
|
||||
subscription,
|
||||
userSubscribed, // New
|
||||
|
||||
// Badges
|
||||
badgeAwarded,
|
||||
@@ -1773,16 +2129,21 @@ enum NotificationType {
|
||||
|
||||
// Consultant
|
||||
consultantRequestStarted,
|
||||
motivateUser, // New
|
||||
|
||||
// Complaints
|
||||
clientCloseComplaintSuccess,
|
||||
complaintToModerationForUser,
|
||||
complaintRegistered, // New
|
||||
contentUnpublished, // New
|
||||
contentUnpublishedComplaint, // New
|
||||
|
||||
// Finance
|
||||
clientRefundSuccess,
|
||||
consultantRefundSuccess,
|
||||
clientRejectSuccess,
|
||||
consultantRejectSuccess,
|
||||
financeQuestionCreated, // New
|
||||
|
||||
// Score
|
||||
scoreAdded,
|
||||
@@ -1794,6 +2155,9 @@ enum NotificationType {
|
||||
// Diary
|
||||
diaryReminderForUsers,
|
||||
|
||||
// Chat
|
||||
newChatMessage, // New
|
||||
|
||||
// Legacy types (keeping for backward compatibility)
|
||||
planSubscriptionStartedToAuthor,
|
||||
planSubscriptionCanceledToAuthor,
|
||||
@@ -1865,7 +2229,23 @@ enum NotificationType {
|
||||
'stay-on-track-to-customer' => NotificationType.stayOnTrackToCustomer,
|
||||
'diary-reminder-for-users' => NotificationType.diaryReminderForUsers,
|
||||
'personal-diet-is-defined-to-customer' => NotificationType.personalDietIsDefinedToCustomer,
|
||||
|
||||
|
||||
// New additions
|
||||
'consultant-education-updated' => NotificationType.consultantEducationUpdated,
|
||||
'complaint-registered' => NotificationType.complaintRegistered,
|
||||
'content-unpublished' => NotificationType.contentUnpublished,
|
||||
'content-unpublished-complaint' => NotificationType.contentUnpublishedComplaint,
|
||||
'finance-question-created' => NotificationType.financeQuestionCreated,
|
||||
'new-chat-message' => NotificationType.newChatMessage,
|
||||
'complete-registration' => NotificationType.completeRegistration,
|
||||
'chosen-diet-expired' => NotificationType.chosenDietExpired,
|
||||
'motivate-user' => NotificationType.motivateUser,
|
||||
'comment-complaint' => NotificationType.commentComplaint,
|
||||
'comment-deleted' => NotificationType.commentDeleted,
|
||||
'user-subscribed' => NotificationType.userSubscribed,
|
||||
// 'diary-reminder' => NotificationType.diaryReminder, // Already legacy? Check if it maps to diaryReminderNotification
|
||||
'meal-reminder' => NotificationType.mealReminder, // Maps to legacy if string matches? No, legacy was App\\...
|
||||
|
||||
// Legacy mapping
|
||||
'App\\Notifications\\Plan\\PlanSubscriptionStartedToAuthor' => NotificationType.planSubscriptionStartedToAuthor,
|
||||
'App\\Notifications\\Plan\\PlanSubscriptionCanceledToAuthor' => NotificationType.planSubscriptionCanceledToAuthor,
|
||||
|
||||
@@ -267,10 +267,82 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.unknown => UnknownNotification(type: type),
|
||||
NotificationType.consultantEducationUpdated => ConsultantEducationUpdatedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.complaintRegistered => ComplaintRegisteredNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.contentUnpublished => ContentUnpublishedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.contentUnpublishedComplaint => ContentUnpublishedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.financeQuestionCreated => FinanceQuestionCreatedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.newChatMessage => NewChatMessageNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.completeRegistration => CompleteRegistrationNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenDietExpired => ChosenDietExpiredNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.motivateUser => MotivateUserNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.commentComplaint => CommentComplaintNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.commentDeleted => CommentDeletedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.userSubscribed => UserSubscribedNotification.fromJson(
|
||||
notificationJson,
|
||||
type,
|
||||
isRead: isRead,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.unknown => UnknownNotification(type: type, createdAt: parseDate(createdAt ?? jsonEncode(notificationJson))),
|
||||
};
|
||||
} catch (e) {
|
||||
return UnknownNotification(type: NotificationType.unknown);
|
||||
return UnknownNotification(type: NotificationType.unknown, createdAt: DateTime.now());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -413,6 +413,78 @@ class NotificationsService {
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.consultantEducationUpdated => ConsultantEducationUpdatedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.complaintRegistered => ComplaintRegisteredNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.contentUnpublished => ContentUnpublishedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.contentUnpublishedComplaint => ContentUnpublishedNotification.fromJson( // Reusing ContentUnpublishedNotification if structure is same, or create specific if different. Assuming similar for now or check backend.
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.financeQuestionCreated => FinanceQuestionCreatedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.newChatMessage => NewChatMessageNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.completeRegistration => CompleteRegistrationNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.chosenDietExpired => ChosenDietExpiredNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.motivateUser => MotivateUserNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.commentComplaint => CommentComplaintNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.commentDeleted => CommentDeletedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.userSubscribed => UserSubscribedNotification.fromJson(
|
||||
notificationJson['data'],
|
||||
type,
|
||||
isRead: readDate != null,
|
||||
createdAt: createdAt,
|
||||
),
|
||||
NotificationType.unknown => UnknownNotification(type: type, createdAt: parseDate(createdAt)),
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
@@ -32,10 +32,18 @@ import 'package:go_router/go_router.dart';
|
||||
import '../../../../core/widgets/option_widget.dart';
|
||||
|
||||
class AboutPlanScreen extends StatefulWidget {
|
||||
const AboutPlanScreen({super.key, required this.slug, required this.navigateToComments, required this.index});
|
||||
final String slug;
|
||||
final bool navigateToComments;
|
||||
final int? index;
|
||||
final int? highlightedCommentId;
|
||||
|
||||
const AboutPlanScreen({
|
||||
super.key,
|
||||
required this.slug,
|
||||
required this.navigateToComments,
|
||||
required this.index,
|
||||
this.highlightedCommentId,
|
||||
});
|
||||
@override
|
||||
State<AboutPlanScreen> createState() => _AboutPlanScreenState();
|
||||
}
|
||||
@@ -468,13 +476,14 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (commentsState is CommentsStateLoading) const Loader(),
|
||||
if (commentsState is CommentsStateLoaded)
|
||||
CommentsWidget(
|
||||
id: state.planModel?.id.toString() ?? '',
|
||||
commentSourceType: CommentSourceType.plan,
|
||||
comment: commentsState.comment,
|
||||
replyId: replyId,
|
||||
),
|
||||
if (commentsState is CommentsStateLoaded)
|
||||
CommentsWidget(
|
||||
id: state.planModel?.id.toString() ?? '',
|
||||
commentSourceType: CommentSourceType.plan,
|
||||
comment: commentsState.comment,
|
||||
replyId: replyId,
|
||||
highlightedCommentId: widget.highlightedCommentId,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -36,8 +36,9 @@ class AboutRecipeScreen extends StatefulWidget {
|
||||
final String recipeSlug;
|
||||
final int? index;
|
||||
final bool navigateToComments;
|
||||
final int? highlightedCommentId;
|
||||
|
||||
const AboutRecipeScreen({super.key, required this.recipeSlug, required this.index, required this.navigateToComments});
|
||||
const AboutRecipeScreen({super.key, required this.recipeSlug, required this.index, required this.navigateToComments, this.highlightedCommentId});
|
||||
|
||||
@override
|
||||
State<AboutRecipeScreen> createState() => _AboutRecipeScreenState();
|
||||
@@ -391,6 +392,7 @@ class _AboutRecipeScreenState extends State<AboutRecipeScreen> {
|
||||
commentSourceType: CommentSourceType.recipe,
|
||||
comment: state.comment,
|
||||
replyId: replyId,
|
||||
highlightedCommentId: widget.highlightedCommentId,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -101,7 +101,7 @@ void main() {
|
||||
|
||||
registerMocks(cubit, commentsCubit);
|
||||
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false)));
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(AboutDietScreen), findsOneWidget);
|
||||
@@ -127,7 +127,7 @@ void main() {
|
||||
registerMocks(cubit, commentsCubit);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false)));
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 600));
|
||||
});
|
||||
@@ -157,7 +157,7 @@ void main() {
|
||||
registerMocks(cubit, commentsCubit);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false)));
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 600));
|
||||
});
|
||||
@@ -183,7 +183,7 @@ void main() {
|
||||
|
||||
registerMocks(cubit, commentsCubit);
|
||||
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false)));
|
||||
await tester.pumpWidget(wrap(cubit, feedCubit, commentsCubit, const AboutDietScreen(slug: 'test', id: null, index: null, navigateToComments: false, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(AboutDietScreen), findsOneWidget);
|
||||
|
||||
@@ -124,7 +124,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('UnknownNotification uses default createdAt when not provided', () {
|
||||
final notification = UnknownNotification(type: NotificationType.unknown);
|
||||
final notification = UnknownNotification(type: NotificationType.unknown, createdAt: DateTime.now());
|
||||
|
||||
expect(notification.type, NotificationType.unknown);
|
||||
expect(notification.isRead, true);
|
||||
|
||||
@@ -160,6 +160,8 @@ void main() {
|
||||
type: NotificationType.chosenPlanStartedToConsultant,
|
||||
planName: 'Test Plan',
|
||||
customerName: 'Test Customer',
|
||||
planId: 1,
|
||||
customerId: 1,
|
||||
isRead: false,
|
||||
createdAt: testDate,
|
||||
);
|
||||
@@ -586,6 +588,8 @@ void main() {
|
||||
type: NotificationType.stayOnTrackToAuthor,
|
||||
planName: 'Test Plan',
|
||||
clientName: 'Test Client',
|
||||
planId: 1,
|
||||
clientId: 1,
|
||||
isRead: false,
|
||||
createdAt: testDate,
|
||||
);
|
||||
@@ -752,6 +756,8 @@ void main() {
|
||||
type: NotificationType.stayOnTrackToCustomer,
|
||||
planName: 'Test Plan',
|
||||
consultantName: 'Test Consultant',
|
||||
planId: 1,
|
||||
consultantId: 1,
|
||||
isRead: false,
|
||||
createdAt: testDate,
|
||||
);
|
||||
|
||||
@@ -123,7 +123,7 @@ void main() {
|
||||
|
||||
registerMocks(planCubit, commentsCubit);
|
||||
|
||||
await tester.pumpWidget(wrap(planCubit, feedCubit, commentsCubit, const AboutPlanScreen(slug: 'test', navigateToComments: false, index: null)));
|
||||
await tester.pumpWidget(wrap(planCubit, feedCubit, commentsCubit, const AboutPlanScreen(slug: 'test', navigateToComments: false, index: null, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(AboutPlanScreen), findsOneWidget);
|
||||
@@ -149,7 +149,7 @@ void main() {
|
||||
registerMocks(planCubit, commentsCubit);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(planCubit, feedCubit, commentsCubit, const AboutPlanScreen(slug: 'test', navigateToComments: false, index: null)));
|
||||
await tester.pumpWidget(wrap(planCubit, feedCubit, commentsCubit, const AboutPlanScreen(slug: 'test', navigateToComments: false, index: null, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
});
|
||||
@@ -177,7 +177,7 @@ void main() {
|
||||
|
||||
registerMocks(planCubit, commentsCubit);
|
||||
|
||||
await tester.pumpWidget(wrap(planCubit, feedCubit, commentsCubit, const AboutPlanScreen(slug: 'test', navigateToComments: false, index: null)));
|
||||
await tester.pumpWidget(wrap(planCubit, feedCubit, commentsCubit, const AboutPlanScreen(slug: 'test', navigateToComments: false, index: null, highlightedCommentId: null)));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(AboutPlanScreen), findsOneWidget);
|
||||
|
||||
Reference in New Issue
Block a user