forked from eatvio/eatvio_app
Merge pull request 'build 22' (#480) from main into test-flight
Reviewed-on: eatvio/eatvio_app#480
This commit is contained in:
@@ -388,7 +388,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 21;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -538,7 +538,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 21;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -576,7 +576,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
CURRENT_PROJECT_VERSION = 21;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20</string>
|
||||
<string>21</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
||||
@@ -32,7 +32,7 @@ import 'package:eatvio_app/features/glossary/presentation/pages/glossary_screen.
|
||||
import 'package:eatvio_app/features/menu/presentation/pages/menu_screen.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/my_diets_screen.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/card_settings.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/consultant_finance_screen.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/presentation/consultations_archive_screen.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/pages/user_finance_screen.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart';
|
||||
import 'package:eatvio_app/features/notifications/presentation/notifications_screen.dart';
|
||||
@@ -177,7 +177,7 @@ class AppRouter {
|
||||
GoRoute(
|
||||
path: '/consultant-finance-screen',
|
||||
name: 'consultantFinanceScreen',
|
||||
builder: (context, state) => const ConsultantFinanceScreen(),
|
||||
builder: (context, state) => const ConsultationsArchiveScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/user-finance-screen',
|
||||
|
||||
13
lib/core/enums/filters_comparison_enum.dart
Normal file
13
lib/core/enums/filters_comparison_enum.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
enum FiltersComparisonEnum {
|
||||
equal('\$eq'),
|
||||
notEqual('\$ne'),
|
||||
greaterThan('\$gt'),
|
||||
lessThan('\$lt'),
|
||||
greaterThanOrEqual('\$gte'),
|
||||
lessThanOrEqual('\$lte'),
|
||||
inArray('\$in'),
|
||||
notInArray('\$notIn');
|
||||
|
||||
final String value;
|
||||
const FiltersComparisonEnum(this.value);
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import 'package:eatvio_app/features/complaining/services/complaining_service.dar
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations/services/consultation_service.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
||||
import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart';
|
||||
@@ -121,7 +122,8 @@ Future<void> init() async {
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
sl.registerFactory<DiaryCubit>(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl(), dietRepository: sl()));
|
||||
sl.registerFactory<DiaryCubit>(
|
||||
() => DiaryCubit(chatRepository: sl(), diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl(), dietRepository: sl()));
|
||||
sl.registerFactory<AboutDietCubit>(() => AboutDietCubit(dietsRepository: sl(), profileRepository: sl()));
|
||||
sl.registerFactory<BlogPostCreateCubit>(() => BlogPostCreateCubit(blogPostRepository: sl()));
|
||||
sl.registerFactory<SubCubit>(() => SubCubit(profileRepository: sl()));
|
||||
@@ -144,6 +146,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<CancelPlanCubit>(() => CancelPlanCubit(cancelPlanRepository: sl()));
|
||||
sl.registerFactory<VerifyEmailCubit>(() => VerifyEmailCubit(profileRepository: sl()));
|
||||
sl.registerFactory<MyRecipesCubit>(() => MyRecipesCubit(myRecipesRepository: sl(), aboutRecipeRepository: sl()));
|
||||
sl.registerFactory<ConsultationsArchiveCubit>(() => ConsultationsArchiveCubit(consultationsRepository: sl()));
|
||||
|
||||
// Repository
|
||||
sl.registerLazySingleton<ChatRepository>(() => ChatRepository(chatService: sl()));
|
||||
|
||||
@@ -101,8 +101,7 @@ class PrimaryColors {
|
||||
// Blue
|
||||
Color get blue400 => const Color(0XFF43A6F2);
|
||||
|
||||
Color get blueA400 => const Color(0XFF2F80ED);
|
||||
|
||||
Color get blueA400 => const Color(0XFF2F80ED);
|
||||
// BlueGray
|
||||
Color get blueGray400 => const Color(0XFF7B8794);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:eatvio_app/core/enums/base_state.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
|
||||
@@ -7,6 +8,7 @@ import 'package:eatvio_app/features/consultations/presentation/cubit/consultatio
|
||||
import 'package:eatvio_app/features/consultations/presentation/widgets/consultation_card_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class ConsultationsScreen extends StatelessWidget {
|
||||
static const path = '/consultations-screen';
|
||||
@@ -46,15 +48,49 @@ class ConsultationsContent extends StatelessWidget {
|
||||
context.read<ConsultationsCubit>().loadConsultations();
|
||||
}),
|
||||
BaseState.initial => const Loader(),
|
||||
BaseState.success => ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
itemBuilder: (context, index) => ConsultationCardWidget(
|
||||
consultationsModel: state.consultations[index],
|
||||
BaseState.success => SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => ConsultationCardWidget(
|
||||
consultationsModel: state.consultations[index],
|
||||
),
|
||||
separatorBuilder: (context, index) => const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
shrinkWrap: true,
|
||||
itemCount: state.consultations.length,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed('consultantFinanceScreen');
|
||||
},
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Архив консультаций',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
separatorBuilder: (context, index) => const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
itemCount: state.consultations.length,
|
||||
),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
@@ -73,7 +74,7 @@ class _ConsultationCardWidgetState extends State<ConsultationCardWidget> {
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundImage: NetworkImage(widget.consultationsModel.userProfilePhotoUrl),
|
||||
backgroundImage: NetworkImage(baseUrl + widget.consultationsModel.userProfilePhotoUrl),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Column(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'package:eatvio_app/core/enums/filters_comparison_enum.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations/services/consultation_service.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/statistic_model.dart';
|
||||
|
||||
class ConsultationsRepository {
|
||||
final ConsultationService consultationService;
|
||||
@@ -13,4 +15,31 @@ class ConsultationsRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<ConsultationModel>> getFilteredConsultations({
|
||||
String? state,
|
||||
String? date,
|
||||
FiltersComparisonEnum? stateComparison,
|
||||
FiltersComparisonEnum? dateComparison,
|
||||
}) async {
|
||||
try {
|
||||
final model = await consultationService.getFilteredConsultations(
|
||||
state: state,
|
||||
date: date,
|
||||
stateComparison: stateComparison,
|
||||
dateComparison: dateComparison,
|
||||
);
|
||||
return model.data;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<StatisticModel> getStatistic() async {
|
||||
try {
|
||||
return await consultationService.getStatistics();
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,69 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/enums/filters_comparison_enum.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/statistic_model.dart';
|
||||
|
||||
part 'consultation_service.g.dart';
|
||||
class ConsultationService {
|
||||
final Dio dio;
|
||||
ConsultationService(this.dio);
|
||||
|
||||
@RestApi()
|
||||
abstract class ConsultationService {
|
||||
factory ConsultationService(Dio dio, {String baseUrl}) = _ConsultationService;
|
||||
Future<ConsultationPaginationModel> getConsultations() async {
|
||||
try {
|
||||
final response = await dio.get('/api/consultations', queryParameters: {
|
||||
'filters[last_state][\$notIn][]': const [
|
||||
'initied',
|
||||
'in_coordination',
|
||||
'start_date_has_been_set',
|
||||
'pending_payment',
|
||||
'canceled_by_the_initiator',
|
||||
'charge_was_collected',
|
||||
],
|
||||
'sort[]': 'created_at:desc'
|
||||
});
|
||||
return ConsultationPaginationModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@GET('/api/consultations')
|
||||
Future<ConsultationPaginationModel> getConsultations({
|
||||
@Query('filters[last_state][\$notIn][]') String query = 'canceled_by_the_initiator',
|
||||
@Query('filters[last_state][\$notIn][]') String query2 = 'charge_was_collected',
|
||||
@Query('sort[]') String sort = 'created_at:desc',
|
||||
});
|
||||
Future<ConsultationPaginationModel> getFilteredConsultations({
|
||||
String? state,
|
||||
String? date,
|
||||
FiltersComparisonEnum? stateComparison,
|
||||
FiltersComparisonEnum? dateComparison,
|
||||
}) async {
|
||||
try {
|
||||
final response = await dio.get(
|
||||
'/api/consultations',
|
||||
queryParameters: {
|
||||
if (stateComparison == FiltersComparisonEnum.notInArray)
|
||||
'filters[last_state][\$notIn][]': const [
|
||||
'initied',
|
||||
'in_coordination',
|
||||
'start_date_has_been_set',
|
||||
'pending_payment',
|
||||
'canceled_by_the_initiator',
|
||||
'charge_was_collected',
|
||||
]
|
||||
else if (state != null && stateComparison != null)
|
||||
'filters[last_state][${stateComparison.value}]': state,
|
||||
if (dateComparison != null && date != null) 'filters[start_date][${dateComparison.value}]': date,
|
||||
},
|
||||
);
|
||||
return ConsultationPaginationModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<StatisticModel> getStatistics() async {
|
||||
try {
|
||||
final response = await dio.get(
|
||||
'/api/consultations/statistics',
|
||||
);
|
||||
return StatisticModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/diary/models/consultant_review_model.dart';
|
||||
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
||||
@@ -23,8 +24,14 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
final GlossaryRepository glossaryRepository;
|
||||
final ProfileRepository profileRepository;
|
||||
final DietRepository dietRepository;
|
||||
final ChatRepository chatRepository;
|
||||
int? diaryId;
|
||||
DiaryCubit({required this.diaryRepository, required this.glossaryRepository, required this.profileRepository, required this.dietRepository})
|
||||
DiaryCubit(
|
||||
{required this.chatRepository,
|
||||
required this.diaryRepository,
|
||||
required this.glossaryRepository,
|
||||
required this.profileRepository,
|
||||
required this.dietRepository})
|
||||
: super(const DiaryState.loading()) {
|
||||
today = DateTime.now();
|
||||
selectedDay = today;
|
||||
@@ -146,6 +153,7 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
|
||||
fetchDiary([bool needLoading = false, int? diaryId]) async {
|
||||
this.diaryId ??= diaryId;
|
||||
|
||||
if (needLoading) {
|
||||
emit(const DiaryState.loading());
|
||||
selectedMeal = 1;
|
||||
@@ -159,8 +167,15 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
diaryDay = await diaryRepository.getDiaryByDate(stringDate);
|
||||
}
|
||||
ConsultantReviewModel? consultantReview;
|
||||
int? planDuration;
|
||||
int? currentPlanDay;
|
||||
String? planName;
|
||||
if (diaryDay.chosenPlanId != null) {
|
||||
consultantReview = await diaryRepository.getDiaryComments(planId: diaryDay.chosenPlanId!, diaryId: diaryDay.id);
|
||||
final chosenPlanModel = await chatRepository.getChosenPlan(id: diaryDay.chosenPlanId!);
|
||||
planDuration = chosenPlanModel.plan.duration;
|
||||
planName = chosenPlanModel.plan.name;
|
||||
currentPlanDay = DateTime.now().difference(chosenPlanModel.startDate).inDays + 1;
|
||||
}
|
||||
final nutrition = await getNutrition(diaryDay.id);
|
||||
|
||||
@@ -179,6 +194,9 @@ class DiaryCubit extends Cubit<DiaryState> {
|
||||
consultantReview: consultantReview,
|
||||
isDiaryFinished: isDiaryFinished,
|
||||
isDiaryCommented: isDiaryCommented,
|
||||
chosenPlanCurrentDay: currentPlanDay,
|
||||
chosenPlanDuration: planDuration,
|
||||
chosenPlanName: planName,
|
||||
),
|
||||
);
|
||||
} catch (e, st) {
|
||||
|
||||
@@ -20,8 +20,11 @@ abstract class DiaryState with _$DiaryState {
|
||||
required NutritionDataModel nutrition,
|
||||
required DateTime selectedDay,
|
||||
required int selectedMeal,
|
||||
@Default(false) bool isConsultantView,
|
||||
int? chosenPlanCurrentDay,
|
||||
String? chosenPlanName,
|
||||
int? chosenPlanDuration,
|
||||
ConsultantReviewModel? consultantReview,
|
||||
@Default(false) bool isConsultantView,
|
||||
@Default(false) bool isDiaryFinished,
|
||||
@Default(false) bool isDiaryCommented,
|
||||
}) = DiaryStateLoaded;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ChosenPlanWidget extends StatelessWidget {
|
||||
const ChosenPlanWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DiaryCubit, DiaryState>(builder: (context, state) {
|
||||
if (state is DiaryStateLoaded) {
|
||||
if (state.diary.typeOfDiary.hasChosenPlan) {
|
||||
return ChosenPlanWidgetContent(
|
||||
currentPlanDay: state.chosenPlanCurrentDay ?? 0,
|
||||
planName: state.chosenPlanName ?? '',
|
||||
planDuration: state.chosenPlanDuration ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ChosenPlanWidgetContent extends StatelessWidget {
|
||||
const ChosenPlanWidgetContent({
|
||||
super.key,
|
||||
required this.currentPlanDay,
|
||||
required this.planName,
|
||||
required this.planDuration,
|
||||
});
|
||||
final int currentPlanDay;
|
||||
final String planName;
|
||||
final int planDuration;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
final s = S.of(context);
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size.width * 0.4,
|
||||
child: Text(planName, style: TextStyles.textLMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
const Spacer(),
|
||||
Container(
|
||||
decoration: BoxDecoration(color: appTheme.dividerColor, borderRadius: BorderRadius.circular(12)),
|
||||
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
|
||||
child: Text('${s.day} $currentPlanDay из $planDuration', style: TextStyles.textMSemibold.copyWith(color: appTheme.gray)),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/add_product_button_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/chosen_diet_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/chosen_plan_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/comment_container.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/meal_button_widget.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/meal_comment_widget.dart';
|
||||
@@ -60,6 +61,7 @@ class _MealWidgetState extends State<MealWidget> {
|
||||
const TimeOfMealPickerWidget(),
|
||||
|
||||
const ChosenDietWidget(),
|
||||
const ChosenPlanWidget(),
|
||||
const ProductsListWidget(),
|
||||
if (widget.showAddButton) ...[
|
||||
const SizedBox(height: 12),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
@@ -77,7 +79,13 @@ class FeedCubit extends Cubit<FeedState> {
|
||||
}
|
||||
}
|
||||
|
||||
likePost(int id) async => await feedRepository.likeBlogPost(id: id);
|
||||
likePost(int id) async {
|
||||
try {
|
||||
await feedRepository.likeBlogPost(id: id);
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
}
|
||||
}
|
||||
|
||||
unlikedPost(int id) async => await feedRepository.unlikedBlogPost(id: id);
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/core/enums/filters_comparison_enum.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_state.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/statistic_model.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/period_enum.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ConsultationsArchiveCubit extends Cubit<ConsultationsArchiveState> {
|
||||
final ConsultationsRepository consultationsRepository;
|
||||
ConsultationsArchiveCubit({
|
||||
required this.consultationsRepository,
|
||||
}) : super(
|
||||
ConsultationsArchiveState(
|
||||
statisticModel: StatisticModel(
|
||||
total: 0,
|
||||
canceled: 0,
|
||||
inProgress: 0,
|
||||
finished: 0,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> getConsultations() async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final consultations = await consultationsRepository.getFilteredConsultations(
|
||||
date: state.periodFilterStatus?.value,
|
||||
state: state.consultationFilterStatus?.value,
|
||||
dateComparison: state.periodFilterStatus == PeriodFilterStatus.all ? null : FiltersComparisonEnum.greaterThanOrEqual,
|
||||
stateComparison: state.consultationFilterStatus == ConsultationFilterStatus.all
|
||||
? null
|
||||
: state.consultationFilterStatus == ConsultationFilterStatus.inProgress
|
||||
? FiltersComparisonEnum.notInArray
|
||||
: FiltersComparisonEnum.equal,
|
||||
);
|
||||
emit(state.copyWith(consultations: consultations, isLoading: false));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setConsultationsPeriod(PeriodFilterStatus period) async {
|
||||
emit(state.copyWith(periodFilterStatus: period));
|
||||
await getConsultations();
|
||||
}
|
||||
|
||||
Future<void> setConsultationsStatus(ConsultationFilterStatus status) async {
|
||||
emit(state.copyWith(consultationFilterStatus: status));
|
||||
await getConsultations();
|
||||
}
|
||||
|
||||
Future<void> getStatistic() async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final statistic = await consultationsRepository.getStatistic();
|
||||
emit(state.copyWith(statisticModel: statistic, isLoading: false));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ConsultationFilterStatus {
|
||||
all,
|
||||
canceled,
|
||||
finished,
|
||||
inProgress;
|
||||
|
||||
String get name => switch (this) {
|
||||
ConsultationFilterStatus.all => 'Все консультации',
|
||||
ConsultationFilterStatus.canceled => 'Отменён',
|
||||
ConsultationFilterStatus.finished => 'Завершён',
|
||||
ConsultationFilterStatus.inProgress => 'В процессе',
|
||||
};
|
||||
|
||||
String? get value => switch (this) {
|
||||
ConsultationFilterStatus.all => null,
|
||||
ConsultationFilterStatus.canceled => 'canceled_by_the_initiator',
|
||||
ConsultationFilterStatus.finished => 'charge_was_collected',
|
||||
ConsultationFilterStatus.inProgress => 'active',
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_cubit.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/statistic_model.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/period_enum.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'consultations_archive_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ConsultationsArchiveState with _$ConsultationsArchiveState {
|
||||
|
||||
factory ConsultationsArchiveState({
|
||||
@Default([]) List<ConsultationModel> consultations,
|
||||
@Default(false) isLoading,
|
||||
@Default(null) String? error,
|
||||
@Default(null) PeriodFilterStatus? periodFilterStatus,
|
||||
@Default(null) ConsultationFilterStatus? consultationFilterStatus,
|
||||
required StatisticModel statisticModel,
|
||||
}) = _ConsultationsArchiveState;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/consultant_finances/consultant_finances_state.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/period_enum.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ConsultantFinancesCubit extends Cubit<ConsultantFinancesState> {
|
||||
final ConsultationsRepository consultationsRepository;
|
||||
ConsultantFinancesCubit({
|
||||
required this.consultationsRepository,
|
||||
}) : super(
|
||||
ConsultantFinancesState(),
|
||||
);
|
||||
|
||||
Future<void> getConsultations() async {
|
||||
try {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setConsultationsPeriod(PeriodFilterStatus period) async {
|
||||
emit(state.copyWith(periodFilterStatus: period));
|
||||
await getConsultations();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/period_enum.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'consultant_finances_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ConsultantFinancesState with _$ConsultantFinancesState {
|
||||
factory ConsultantFinancesState({
|
||||
@Default([]) List<String> financesModels,
|
||||
@Default(false) isLoading,
|
||||
@Default(null) String? error,
|
||||
@Default(null) PeriodFilterStatus? periodFilterStatus,
|
||||
}) = _ConsultantFinancesState;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'statistic_model.freezed.dart';
|
||||
part 'statistic_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class StatisticModel with _$StatisticModel {
|
||||
factory StatisticModel({
|
||||
required int total,
|
||||
@JsonKey(name: 'in_progress') required int inProgress,
|
||||
required int finished,
|
||||
required int canceled,
|
||||
}) = _StatisticModel;
|
||||
|
||||
factory StatisticModel.fromJson(Map<String, dynamic> json) => _$StatisticModelFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
|
||||
enum PeriodFilterStatus {
|
||||
all,
|
||||
month,
|
||||
week;
|
||||
|
||||
String get name => switch (this) {
|
||||
PeriodFilterStatus.all => 'Все периоды',
|
||||
PeriodFilterStatus.month => 'За месяц',
|
||||
PeriodFilterStatus.week => 'За неделю',
|
||||
};
|
||||
|
||||
String? get value => switch (this) {
|
||||
PeriodFilterStatus.all => null,
|
||||
PeriodFilterStatus.month => DateTime.now().subtract(const Duration(days: 30)).format('yyyy-MM-dd'),
|
||||
PeriodFilterStatus.week => DateTime.now().subtract(const Duration(days: 7)).format('yyyy-MM-dd'),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
// import 'package:eatvio_app/core/locator_service.dart';
|
||||
// import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
// import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
// import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
// import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
// import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
|
||||
// import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
// import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_cubit.dart';
|
||||
// import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_state.dart';
|
||||
// import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/consultant_finances/consultant_finances_cubit.dart';
|
||||
// import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/consultant_finances/consultant_finances_state.dart';
|
||||
// import 'package:eatvio_app/features/finances_and_consultations_archive/period_enum.dart';
|
||||
// import 'package:eatvio_app/features/finances_and_consultations_archive/presentation/widgets/status_widget.dart';
|
||||
// import 'package:eatvio_app/generated/l10n.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
// class ConsultantFinancesScreen extends StatefulWidget {
|
||||
// const ConsultantFinancesScreen({super.key});
|
||||
|
||||
// @override
|
||||
// State<ConsultantFinancesScreen> createState() => _ConsultantFinancesScreenState();
|
||||
// }
|
||||
|
||||
// class _ConsultantFinancesScreenState extends State<ConsultantFinancesScreen> {
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// final s = S.of(context);
|
||||
// return BlocProvider<ConsultantFinancesCubit>(
|
||||
// create: (context) => sl<ConsultantFinancesCubit>(),
|
||||
// child: BlocBuilder<ConsultantFinancesCubit, ConsultantFinancesState>(
|
||||
// builder: (context, state) {
|
||||
// return Scaffold(
|
||||
// backgroundColor: const Color(0xFFF0F2F5),
|
||||
// appBar: AppBar(
|
||||
// shape: const RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadiusDirectional.vertical(
|
||||
// bottom: Radius.circular(12),
|
||||
// ),
|
||||
// ),
|
||||
// title: const Text('Архив консультаций'),
|
||||
// centerTitle: true,
|
||||
// ),
|
||||
// body: state.isLoading
|
||||
// ? const Center(
|
||||
// child: Loader(),
|
||||
// )
|
||||
// : SingleChildScrollView(
|
||||
// padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Material(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(12),
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// const SizedBox(height: 16),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
// child: Text(
|
||||
// 'Всего консультаций: ${state.statisticModel.total}',
|
||||
// style: const TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// color: Color(0xFF6D6F71),
|
||||
// height: 1,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 12),
|
||||
// Row(
|
||||
// children: [
|
||||
// const SizedBox(width: 16),
|
||||
// Material(
|
||||
// color: const Color(0xFF0BB450).withAlpha(11),
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
// child: Text(
|
||||
// 'Завершено: ${state.statisticModel.finished}',
|
||||
// style: const TextStyle(
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w400,
|
||||
// color: Color(0xFF0BB450),
|
||||
// height: 1,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 8),
|
||||
// Material(
|
||||
// color: const Color(0xFFD01717).withAlpha(11),
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
// child: Text(
|
||||
// 'Отменено: ${state.statisticModel.canceled}',
|
||||
// style: const TextStyle(
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w400,
|
||||
// color: Color(0xFFD01717),
|
||||
// height: 1,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 16),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// Material(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(12),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||
// child: SingleChildScrollView(
|
||||
// physics: const NeverScrollableScrollPhysics(),
|
||||
// child: Column(
|
||||
// children: [
|
||||
// CustomDropDownButton<PeriodFilterStatus>(
|
||||
// items: PeriodFilterStatus.values
|
||||
// .map(
|
||||
// (value) => DropdownMenuItem(
|
||||
// value: value,
|
||||
// child: Text(
|
||||
// value.name,
|
||||
// style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// .toList(),
|
||||
// onChanged: (value) {
|
||||
// if (value == null) return;
|
||||
// context.read<ConsultationsArchiveCubit>().setConsultationsPeriod(value);
|
||||
// },
|
||||
// value: state.periodFilterStatus ?? PeriodFilterStatus.values.first,
|
||||
// ),
|
||||
// const SizedBox(height: 12),
|
||||
// CustomDropDownButton<ConsultationFilterStatus>(
|
||||
// items: ConsultationFilterStatus.values
|
||||
// .map(
|
||||
// (value) => DropdownMenuItem(
|
||||
// value: value,
|
||||
// child: Text(
|
||||
// value.name,
|
||||
// style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// .toList(),
|
||||
// onChanged: (value) {
|
||||
// if (value == null) return;
|
||||
// context.read<ConsultationsArchiveCubit>().setConsultationsStatus(value);
|
||||
// },
|
||||
// value: state.consultationFilterStatus,
|
||||
// ),
|
||||
// const SizedBox(height: 12),
|
||||
// if (state.consultations.isNotEmpty)
|
||||
// ListView.separated(
|
||||
// shrinkWrap: true,
|
||||
// physics: const NeverScrollableScrollPhysics(),
|
||||
// itemBuilder: (context, index) {
|
||||
// return Material(
|
||||
// color: const Color(0xFFF6F6F6),
|
||||
// borderRadius: BorderRadius.circular(20),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(12),
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// state.consultations[index].id.toString(),
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF323F4B),
|
||||
// height: 1,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// Text(
|
||||
// state.consultations[index].startDate.format('yyyy.MM.dd'),
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF6D6F71),
|
||||
// height: 1,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// Text(
|
||||
// state.consultations[index].planTitle,
|
||||
// style: TextStyle(
|
||||
// color: appTheme.blueA400,
|
||||
// height: 1,
|
||||
// fontSize: 18,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// Text(
|
||||
// 'Покупатель: ${state.consultations[index].userName}',
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF323F4B),
|
||||
// height: 1,
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// Text(
|
||||
// '${state.consultations[index].duration} ${getDayForm(state.consultations[index].duration, s)}',
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF323F4B),
|
||||
// height: 1,
|
||||
// fontSize: 14,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// Container(
|
||||
// height: 1,
|
||||
// width: double.infinity,
|
||||
// decoration: const BoxDecoration(
|
||||
// color: Color(0xFFDEDEDF),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// '${state.consultations[index].consultantPayment.toStringAsFixed(2)} ₽',
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF323F4B),
|
||||
// height: 1,
|
||||
// fontSize: 18,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// ),
|
||||
// ),
|
||||
// StatusWidget(
|
||||
// status: state.consultations[index].chosenPlanState,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
// itemCount: state.financesModels.length,
|
||||
// )
|
||||
// else
|
||||
// const Padding(
|
||||
// padding: EdgeInsets.symmetric(vertical: 40.0),
|
||||
// child: Text(
|
||||
// 'У вас нет таких консультаций',
|
||||
// style: TextStyles.textMMedium,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,281 @@
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_cubit.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/cubit/archive/consultations_archive_state.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/period_enum.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/presentation/widgets/status_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ConsultationsArchiveScreen extends StatefulWidget {
|
||||
const ConsultationsArchiveScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ConsultationsArchiveScreen> createState() => _ConsultationsArchiveScreenState();
|
||||
}
|
||||
|
||||
class _ConsultationsArchiveScreenState extends State<ConsultationsArchiveScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return BlocProvider<ConsultationsArchiveCubit>(
|
||||
create: (context) => sl<ConsultationsArchiveCubit>()
|
||||
..getConsultations()
|
||||
..getStatistic(),
|
||||
child: BlocBuilder<ConsultationsArchiveCubit, ConsultationsArchiveState>(
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF0F2F5),
|
||||
appBar: AppBar(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadiusDirectional.vertical(
|
||||
bottom: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
title: const Text('Архив консультаций'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: state.isLoading
|
||||
? const Center(
|
||||
child: Loader(),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
'Всего консультаций: ${state.statisticModel.total}',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF6D6F71),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(width: 16),
|
||||
Material(
|
||||
color: const Color(0xFF0BB450).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'Завершено: ${state.statisticModel.finished}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF0BB450),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Material(
|
||||
color: const Color(0xFFD01717).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'Отменено: ${state.statisticModel.canceled}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFFD01717),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||
child: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomDropDownButton<PeriodFilterStatus>(
|
||||
items: PeriodFilterStatus.values
|
||||
.map(
|
||||
(value) => DropdownMenuItem(
|
||||
value: value,
|
||||
child: Text(
|
||||
value.name,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
context.read<ConsultationsArchiveCubit>().setConsultationsPeriod(value);
|
||||
},
|
||||
value: state.periodFilterStatus ?? PeriodFilterStatus.values.first,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CustomDropDownButton<ConsultationFilterStatus>(
|
||||
items: ConsultationFilterStatus.values
|
||||
.map(
|
||||
(value) => DropdownMenuItem(
|
||||
value: value,
|
||||
child: Text(
|
||||
value.name,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
context.read<ConsultationsArchiveCubit>().setConsultationsStatus(value);
|
||||
},
|
||||
value: state.consultationFilterStatus ?? ConsultationFilterStatus.values.first,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (state.consultations.isNotEmpty)
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return Material(
|
||||
color: const Color(0xFFF6F6F6),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
state.consultations[index].id.toString(),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
state.consultations[index].startDate.format('yyyy.MM.dd'),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
state.consultations[index].planTitle,
|
||||
style: TextStyle(
|
||||
color: appTheme.blueA400,
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Покупатель: ${state.consultations[index].userName}',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${state.consultations[index].duration} ${getDayForm(state.consultations[index].duration, s)}',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDEDEDF),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${state.consultations[index].consultantPayment.toStringAsFixed(2)} ₽',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
StatusWidget(
|
||||
status: state.consultations[index].chosenPlanState,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemCount: state.consultations.length,
|
||||
)
|
||||
else
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 40.0),
|
||||
child: Text(
|
||||
'У вас нет таких консультаций',
|
||||
style: TextStyles.textMMedium,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StatusWidget extends StatelessWidget {
|
||||
const StatusWidget({super.key, required this.status});
|
||||
final ChosenPlanStateEnum status;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (status == ChosenPlanStateEnum.stateCanceledByTheInitiator) {
|
||||
return Material(
|
||||
color: appTheme.lightRed,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'Отменён',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: appTheme.strongRed,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (status == ChosenPlanStateEnum.stateChargeWasCollected) {
|
||||
return Material(
|
||||
color: const Color(0xFF0BB450).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'Успешно',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF0BB450),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Material(
|
||||
color: appTheme.transparentBlue,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'В процессе',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: appTheme.blueA400,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
|
||||
import 'package:eatvio_app/features/my_finance/entities/consultant_finance_entity.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ConsultantFinanceScreen extends StatefulWidget {
|
||||
const ConsultantFinanceScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ConsultantFinanceScreen> createState() => _ConsultantFinanceScreenState();
|
||||
}
|
||||
|
||||
class _ConsultantFinanceScreenState extends State<ConsultantFinanceScreen> {
|
||||
final List<String> periods = ['За всё время', 'За месяц', 'За неделю'];
|
||||
final List<String> statuses = ['Все консультации', 'Отменён', 'Завершён', 'В процессе'];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF0F2F5),
|
||||
appBar: AppBar(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadiusDirectional.vertical(
|
||||
bottom: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
title: const Text('Архив консультаций'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
'Всего консультаций: ${testFinanceEntity.totalConsultationsCount}',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF6D6F71),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(width: 16),
|
||||
Material(
|
||||
color: const Color(0xFF0BB450).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'Завершено: ${testFinanceEntity.completedCount}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF0BB450),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Material(
|
||||
color: const Color(0xFFD01717).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
'Отменено: ${testFinanceEntity.canceledCount}',
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFFD01717),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||
child: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomDropDownButton(
|
||||
items: periods
|
||||
.mapIndexed(
|
||||
(index, value) => DropdownMenuItem(
|
||||
value: periods[index],
|
||||
child: Text(
|
||||
periods[index],
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {},
|
||||
value: periods.first,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
CustomDropDownButton(
|
||||
items: statuses
|
||||
.mapIndexed(
|
||||
(index, value) => DropdownMenuItem(
|
||||
value: statuses[index],
|
||||
child: Text(
|
||||
statuses[index],
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {},
|
||||
value: statuses.first,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => Material(
|
||||
color: const Color(0xFFF6F6F6),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].id,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].date.format('dd.MM.yyy', 'RU'),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6D6F71),
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
testFinanceEntity.consultationsList[index].title,
|
||||
style: TextStyle(
|
||||
color: appTheme.blueA400,
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Покупатель: ${testFinanceEntity.consultationsList[index].clientName}',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${testFinanceEntity.consultationsList[index].planDuration} дней',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDEDEDF),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${testFinanceEntity.consultationsList[index].price} ₽',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Material(
|
||||
color: const Color(0xFF0BB450).withAlpha(11),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: Text(
|
||||
testFinanceEntity.consultationsList[index].status.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xFF0BB450),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
itemCount: testFinanceEntity.consultationsList.length,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -55,4 +55,16 @@ enum ChosenPlanStateEnum {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static List<ChosenPlanStateEnum> getActiveStates() {
|
||||
return [
|
||||
ChosenPlanStateEnum.statePaid,
|
||||
ChosenPlanStateEnum.stateStarted,
|
||||
ChosenPlanStateEnum.stateInProgress,
|
||||
ChosenPlanStateEnum.stateLastDayStarted,
|
||||
ChosenPlanStateEnum.stateLastDayFinished,
|
||||
ChosenPlanStateEnum.stateComplained,
|
||||
ChosenPlanStateEnum.stateDone
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,7 +562,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, top: 20),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
ListView.separated(
|
||||
@@ -964,7 +964,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
context.pushTransparentRoute(
|
||||
rootNavigator: true,
|
||||
PhotoViewScreen(
|
||||
imageUrls: [state.profile.profilePhotoUrl],
|
||||
imageUrls: [baseUrl + state.profile.profilePhotoUrl],
|
||||
index: 0,
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user