Merge pull request 'build 22' (#480) from main into test-flight

Reviewed-on: eatvio/eatvio_app#480
This commit is contained in:
mso7nueh
2025-05-30 13:10:02 +00:00
27 changed files with 1090 additions and 293 deletions

View File

@@ -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 = (

View File

@@ -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>

View File

@@ -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',

View 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);
}

View File

@@ -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()));

View File

@@ -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);

View File

@@ -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,
),
});
},

View File

@@ -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(

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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,
)
],
);
}
}

View File

@@ -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),

View File

@@ -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);

View File

@@ -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',
};
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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'),
};
}

View File

@@ -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,
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// );
// },
// ),
// );
// }
// }

View File

@@ -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,
),
),
],
),
),
),
),
],
),
),
);
},
),
);
}
}

View File

@@ -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,
),
),
),
);
}
}

View File

@@ -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,
),
],
),
),
),
),
],
),
),
);
}
}

View File

@@ -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
];
}
}

View File

@@ -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,
),
);