forked from eatvio/eatvio_app
feat(consultations): updated consultations archive screen, and added buisines logic
This commit is contained in:
@@ -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,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/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,13 +1,51 @@
|
||||
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/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',
|
||||
);
|
||||
return ConsultationPaginationModel.fromJson(response.data);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@GET('/api/consultations')
|
||||
Future<ConsultationPaginationModel> getConsultations();
|
||||
Future<ConsultationPaginationModel> getFilteredConsultations({
|
||||
String? state,
|
||||
String? date,
|
||||
FiltersComparisonEnum? stateComparison,
|
||||
FiltersComparisonEnum? dateComparison,
|
||||
}) async {
|
||||
try {
|
||||
final response = await dio.get(
|
||||
'/api/consultations',
|
||||
queryParameters: {
|
||||
if (state != null) 'filters[last_state][${stateComparison?.value ?? '\$chosen_plan_status'}]': 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/core/enums/filters_comparison_enum.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations_archive/cubit/consultations_archive_state.dart';
|
||||
import 'package:eatvio_app/features/consultations_archive/models/statistic_model.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.inProgress && state.consultationFilterStatus == ConsultationFilterStatus.all
|
||||
? null
|
||||
: 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 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'),
|
||||
};
|
||||
}
|
||||
|
||||
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,21 @@
|
||||
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations_archive/cubit/consultations_archive_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultations_archive/models/statistic_model.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,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,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/consultations_archive/cubit/consultations_archive_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultations_archive/cubit/consultations_archive_state.dart';
|
||||
import 'package:eatvio_app/features/consultations_archive/presentation/status_widget.dart';
|
||||
import 'package:eatvio_app/features/my_finance/entities/consultant_finance_entity.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ConsultationsArchive extends StatefulWidget {
|
||||
const ConsultationsArchive({super.key});
|
||||
|
||||
@override
|
||||
State<ConsultationsArchive> createState() => _ConsultationsArchiveState();
|
||||
}
|
||||
|
||||
class _ConsultationsArchiveState extends State<ConsultationsArchive> {
|
||||
@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,
|
||||
),
|
||||
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,64 @@
|
||||
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) {
|
||||
final activeStates = ChosenPlanStateEnum.getActiveStates();
|
||||
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
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user