Issue-483: WIP* moderation consultant request status and message

This commit is contained in:
mso7nueh
2025-06-03 18:17:03 +03:00
parent 7c354cc0a3
commit c361e12d35
15 changed files with 151 additions and 44 deletions

View File

@@ -6,7 +6,6 @@ import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
@@ -98,12 +97,10 @@ class CustomPopup extends StatelessWidget {
),
);
});
if (complainedContentType == ComplainedContent.posts || complainedContentType == ComplainedContent.recipe) {
if (complainedContentType == ComplainedContent.posts) {
addItem('assets/icons/edit_paint.svg', 'Редактировать', () async {
if (complainedContentType == ComplainedContent.posts) {
GoRouter.of(context).pushNamed('blogPostCreateScreen', extra: feedBlogPostModel);
} else if (complainedContentType == ComplainedContent.recipe) {
GoRouter.of(context).pushNamed(RecipeCreateScreen.name, extra: recipe);
}
});
}

View File

@@ -11,6 +11,7 @@ abstract class ConsultationRequestModel with _$ConsultationRequestModel {
@JsonKey(name: 'rating_place') int? ratingPlace,
@JsonKey(name: 'education_resource') required EducationModel educationModel,
@JsonKey(name: 'cert_photos') required List<CertPhotosModel> photos,
@JsonKey(name: 'canceled_moderation') required CanceledModerationModel canceledModeration,
}) = _ConsultationRequestModel;
factory ConsultationRequestModel.fromJson(Map<String, dynamic> json) => _$ConsultationRequestModelFromJson(json);
@@ -24,3 +25,20 @@ abstract class CertPhotosModel with _$CertPhotosModel {
factory CertPhotosModel.fromJson(Map<String, dynamic> json) => _$CertPhotosModelFromJson(json);
}
enum ModerationStatus {
approved,
created,
canceled
}
@freezed
abstract class CanceledModerationModel with _$CanceledModerationModel {
const factory CanceledModerationModel({
required String title,
required ModerationStatus status,
required List<String>? additional,
}) = _CanceledModerationModel;
factory CanceledModerationModel.fromJson(Map<String, dynamic> json) => _$CanceledModerationModelFromJson(json);
}

View File

@@ -76,6 +76,7 @@ class RegisterConsultantCubit extends Cubit<RegisterConsultantState> {
),
acceptOffer: false,
loading: false,
requestModel: myRequestStatus,
),
);
}

View File

@@ -1,4 +1,5 @@
import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart';
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'register_consultant_state.freezed.dart';
@@ -9,5 +10,6 @@ abstract class RegisterConsultantState with _$RegisterConsultantState {
required ConsultantProfileModel consultant,
required bool acceptOffer,
required bool loading,
ConsultationRequestModel? requestModel,
}) = _RegisterConsultantState;
}

View File

@@ -1,5 +1,6 @@
import 'package:eatvio_app/core/utils/image_constant.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart';
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart';
import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart';
@@ -80,9 +81,57 @@ class _StepperBecomeConsultantScreenState extends State<StepperBecomeConsultantS
),
),
),
if (state.requestModel?.canceledModeration.status == ModerationStatus.canceled)
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(state.requestModel!.canceledModeration.title),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
for (int i = 0; i < state.requestModel!.canceledModeration.additional!.length; i++) ...[
Text('• ${state.requestModel!.canceledModeration.additional![i]}'),
]
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
},
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 48,
width: MediaQuery.of(context).size.width * 0.6,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0x33FFCC00),
),
child: const Center(
child: Text(
'Комментарий',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF323F4B),
height: 1,
),
),
),
),
),
Container(
height: 48,
width: MediaQuery.of(context).size.width * 0.8,
width: state.requestModel?.canceledModeration.status == ModerationStatus.canceled
? MediaQuery.of(context).size.width * 0.2
: MediaQuery.of(context).size.width * 0.8,
padding: const EdgeInsets.only(left: 4, right: 16),
child: FloatingActionButton.extended(
heroTag: 'nextButtonRegistration',
@@ -92,7 +141,11 @@ class _StepperBecomeConsultantScreenState extends State<StepperBecomeConsultantS
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
backgroundColor: isLoading ? Colors.grey : appTheme.blueA400,
backgroundColor: isLoading
? Colors.grey
: state.requestModel?.canceledModeration.status == ModerationStatus.canceled
? const Color(0xFFEAF2FD)
: appTheme.blueA400,
onPressed: isLoading
? null
: () async {
@@ -219,10 +272,15 @@ class _StepperBecomeConsultantScreenState extends State<StepperBecomeConsultantS
},
label: isLoading
? const CircularProgressIndicator()
: Text(
'Продолжить',
style: theme.textTheme.titleSmall!.copyWith(color: Colors.white),
),
: state.requestModel?.canceledModeration.status == ModerationStatus.canceled
? Icon(
Icons.arrow_forward_ios_outlined,
color: appTheme.blueA400,
)
: Text(
'Продолжить',
style: theme.textTheme.titleSmall!.copyWith(color: Colors.white),
),
),
),
],

View File

@@ -293,6 +293,7 @@ class CreateDietCubit extends Cubit<CreateDietState> {
final diet = Diet(
id: 0,
name: state.dietData.name ?? '',
slug: '',
image: imageInBase64,
duration: state.dietData.duration ?? 0,
state: state.dietData.state ?? DietState.active,

View File

@@ -192,7 +192,7 @@ class _DietPreviewScreenState extends State<DietPreviewScreen> {
actions: [
CustomPopup(
isAuthor: widget.diet.author.authorIsMe,
path: 'diet/${widget.diet.id}',
path: 'diet/${widget.diet.slug}',
complainedContentType: ComplainedContent.diet,
),
const SizedBox(width: 16),

View File

@@ -318,7 +318,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
actions: [
CustomPopup(
isAuthor: widget.diet.author.authorIsMe,
path: 'diet/${widget.diet.id}',
path: 'diet/${widget.diet.slug}',
complainedContentType: ComplainedContent.diet,
id: widget.diet.id,
diet: widget.diet,
@@ -499,7 +499,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
actions: [
CustomPopup(
isAuthor: widget.diet.author.authorIsMe,
path: 'diet/${widget.diet.id}',
path: 'diet/${widget.diet.slug}',
complainedContentType: ComplainedContent.diet,
id: widget.diet.id,
diet: widget.diet,
@@ -526,7 +526,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
actions: [
CustomPopup(
isAuthor: widget.diet.author.authorIsMe,
path: 'diet/${widget.diet.id}',
path: 'diet/${widget.diet.slug}',
complainedContentType: ComplainedContent.diet,
id: widget.diet.id,
diet: widget.diet,

View File

@@ -20,6 +20,7 @@ abstract class DietsPagination with _$DietsPagination {
abstract class Diet with _$Diet {
const factory Diet({
@JsonKey(name: "id") required int id,
@JsonKey(name: "slug") required String slug,
@JsonKey(name: "name") required String name,
@JsonKey(name: "image") required String image,
@JsonKey(name: "duration") required int duration,

View File

@@ -90,7 +90,7 @@ class _DietsWidgetState extends State<DietsWidget> {
borderRadius: BorderRadius.circular(4),
child: CustomPopup(
isAuthor: widget.diet.author.authorIsMe,
path: 'diet/${widget.diet.id}',
path: 'diet/${widget.diet.slug}',
id: widget.diet.id,
complainedContentType: ComplainedContent.diet,
diet: widget.diet,

View File

@@ -96,7 +96,7 @@ class _PlanWidgetState extends State<PlanWidget> {
borderRadius: BorderRadius.circular(4),
child: CustomPopup(
isAuthor: widget.plan.author.authorIsMe,
path: 'plan/${widget.plan.id}',
path: 'plan/${widget.plan.slug}',
id: widget.plan.id,
slug: widget.plan.slug,
complainedContentType: ComplainedContent.plan,

View File

@@ -113,7 +113,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
actions: [
CustomPopup(
isAuthor: widget.plan.author.authorIsMe,
path: 'plan/${widget.plan.id}',
path: 'plan/${widget.plan.slug}',
complainedContentType: ComplainedContent.plan,
slug: widget.plan.slug,
),
@@ -143,7 +143,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
actions: [
CustomPopup(
isAuthor: widget.plan.author.authorIsMe,
path: 'plan/${widget.plan.id}',
path: 'plan/${widget.plan.slug}',
complainedContentType: ComplainedContent.plan,
slug: widget.plan.slug,
),
@@ -362,7 +362,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
actions: [
CustomPopup(
isAuthor: widget.plan.author.authorIsMe,
path: 'plan/${widget.plan.id}',
path: 'plan/${widget.plan.slug}',
complainedContentType: ComplainedContent.plan,
slug: widget.plan.slug,
),

View File

@@ -330,7 +330,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
const SizedBox(height: 8),
SizedBox(
height: 759,
height: 781,
child: PageView.builder(
itemBuilder: (BuildContext context, int index) {
return PlanWidget(
@@ -348,6 +348,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
const SizedBox(height: 8),
_bullets(_currentBullet, state.plansList.length),
const SizedBox(height: 8),
],
);
}

View File

@@ -6,7 +6,6 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/utils/localization_utils.dart';
import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
import 'package:eatvio_app/features/recipe/models/my_recipe_model.dart';
import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recieps_cubit.dart';
@@ -131,29 +130,6 @@ class _MyRecipeWidgetState extends State<MyRecipeWidget> {
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: [
Row(
children: [
Expanded(
child: CustomOutlinedButton(
onPressed: () async {
GoRouter.of(context).pushNamed(
RecipeCreateScreen.name,
extra: await context.read<MyRecipesCubit>().getRecipeById(widget.recipe.slug),
);
},
text: s.edit,
height: 52,
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
buttonStyle: ButtonStyle(
shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))),
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
side: const WidgetStatePropertyAll(BorderSide.none),
),
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
Expanded(

View File

@@ -1,6 +1,7 @@
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
import 'package:eatvio_app/features/settings/entities/settings_entity.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_state.dart';
@@ -377,7 +378,58 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
),
);
} else {
if (state.consultationRequestModel!.canceledModeration.status == ModerationStatus.created) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0xFFEAEAEA),
),
child: const Center(
child: Text(
'Данные на проверке...',
style: TextStyle(
color: Colors.black,
height: 1,
fontSize: 18,
),
),
),
),
);
} else if (state.consultationRequestModel!.canceledModeration.status == ModerationStatus.canceled) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
child: InkWell(
onTap: () => GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug),
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,
width: MediaQuery.of(context).size.width - 16,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0x33FFCC00),
),
child: const Center(
child: Text(
'Заявка обработана',
style: TextStyle(
color: Colors.black,
height: 1,
fontSize: 18,
),
),
),
),
),
);
}
}
return const SizedBox.shrink();
}
_deleteAccountButton(SettingsStateLoaded state) {