forked from eatvio/eatvio_app
Merge remote-tracking branch 'upstream/main'
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 = 21;
|
||||
CURRENT_PROJECT_VERSION = 24;
|
||||
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 = 21;
|
||||
CURRENT_PROJECT_VERSION = 24;
|
||||
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 = 21;
|
||||
CURRENT_PROJECT_VERSION = 24;
|
||||
DEVELOPMENT_TEAM = VL68C36HYS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>21</string>
|
||||
<string>24</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
||||
@@ -100,9 +100,6 @@ class AppRouter {
|
||||
GoRoute(
|
||||
path: '/my-profile-screen',
|
||||
name: 'myProfileScreen',
|
||||
redirect: (context, state) async {
|
||||
return null;
|
||||
},
|
||||
pageBuilder: (context, state) {
|
||||
return const NoTransitionPage(child: ProfileScreen());
|
||||
},
|
||||
@@ -112,15 +109,21 @@ class AppRouter {
|
||||
name: 'feedScreen',
|
||||
pageBuilder: (context, state) => const NoTransitionPage(child: FeedScreen()),
|
||||
redirect: (context, state) async {
|
||||
final data = state.extra as Map<String, dynamic>?;
|
||||
if (data?['needToInitializeWebSocket'] == false) {
|
||||
return null;
|
||||
try {
|
||||
await sl<WsManager>().initialize();
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
await sl<WsManager>().initialize();
|
||||
return null;
|
||||
return '/feed-screen';
|
||||
},
|
||||
),
|
||||
GoRoute(path: '/diary-screen', name: 'diaryScreen', pageBuilder: (context, state) => const NoTransitionPage(child: DiaryScreen())),
|
||||
GoRoute(
|
||||
path: '/diary-screen',
|
||||
name: 'diaryScreen',
|
||||
pageBuilder: (context, state) => const NoTransitionPage(
|
||||
child: DiaryScreen(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: ConsultationsScreen.path,
|
||||
name: ConsultationsScreen.name,
|
||||
@@ -296,7 +299,12 @@ class AppRouter {
|
||||
),
|
||||
GoRoute(path: '/become-consultant-screen', name: 'becomeConsultantScreen', builder: (context, state) => const BecomeConsultantScreen()),
|
||||
GoRoute(
|
||||
path: '/stepper-become-consultant-screen', name: 'stepperBecomeConsultantScreen', builder: (context, state) => const StepperBecomeConsultantScreen()),
|
||||
path: '/stepper-become-consultant-screen',
|
||||
name: 'stepperBecomeConsultantScreen',
|
||||
builder: (context, state) => StepperBecomeConsultantScreen(
|
||||
slug: state.extra == null ? null : state.extra as String,
|
||||
),
|
||||
),
|
||||
GoRoute(path: '/calendar-screen', name: 'calendarScreen', builder: (context, state) => const CalendarScreen()),
|
||||
GoRoute(path: '/support-screen', name: 'supportScreen', builder: (context, state) => const SupportScreen()),
|
||||
GoRoute(
|
||||
|
||||
@@ -120,7 +120,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl(), consultantRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
sl.registerFactory<DiaryCubit>(
|
||||
() => DiaryCubit(chatRepository: sl(), diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl(), dietRepository: sl()));
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
|
||||
@@ -98,12 +97,10 @@ class CustomPopup extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
});
|
||||
if (complainedContentType == ComplainedContent.posts || complainedContentType == ComplainedContent.recipe) {
|
||||
if (complainedContentType == ComplainedContent.posts) {
|
||||
addItem('assets/icons/edit_paint.svg', 'Редактировать', () async {
|
||||
if (complainedContentType == ComplainedContent.posts) {
|
||||
GoRouter.of(context).pushNamed('blogPostCreateScreen', extra: feedBlogPostModel);
|
||||
} else if (complainedContentType == ComplainedContent.recipe) {
|
||||
GoRouter.of(context).pushNamed(RecipeCreateScreen.name, extra: recipe);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ part 'consultation_request_model.g.dart';
|
||||
@freezed
|
||||
abstract class ConsultationRequestModel with _$ConsultationRequestModel {
|
||||
const factory ConsultationRequestModel({
|
||||
@JsonKey(name: 'rating_place') required int ratingPlace,
|
||||
@JsonKey(name: 'rating_place') int? ratingPlace,
|
||||
@JsonKey(name: 'education_resource') required EducationModel educationModel,
|
||||
@JsonKey(name: 'cert_photos') required List<CertPhotosModel> photos,
|
||||
@JsonKey(name: 'canceled_moderation') CanceledModerationModel? canceledModeration,
|
||||
}) = _ConsultationRequestModel;
|
||||
|
||||
factory ConsultationRequestModel.fromJson(Map<String, dynamic> json) => _$ConsultationRequestModelFromJson(json);
|
||||
@@ -24,3 +25,20 @@ abstract class CertPhotosModel with _$CertPhotosModel {
|
||||
|
||||
factory CertPhotosModel.fromJson(Map<String, dynamic> json) => _$CertPhotosModelFromJson(json);
|
||||
}
|
||||
|
||||
enum ModerationStatus {
|
||||
approved,
|
||||
created,
|
||||
canceled
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class CanceledModerationModel with _$CanceledModerationModel {
|
||||
const factory CanceledModerationModel({
|
||||
required String title,
|
||||
required ModerationStatus status,
|
||||
required List<String>? additional,
|
||||
}) = _CanceledModerationModel;
|
||||
|
||||
factory CanceledModerationModel.fromJson(Map<String, dynamic> json) => _$CanceledModerationModelFromJson(json);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class RegisterConsultantCubit extends Cubit<RegisterConsultantState> {
|
||||
final ConsultantRepository consultantRepository;
|
||||
bool _update = false;
|
||||
|
||||
RegisterConsultantCubit({
|
||||
required this.consultantRepository,
|
||||
@@ -17,12 +19,80 @@ class RegisterConsultantCubit extends Cubit<RegisterConsultantState> {
|
||||
socialLinks: SocialLinksModel(),
|
||||
hasMedicalEducation: true,
|
||||
),
|
||||
loading: true,
|
||||
acceptOffer: false,
|
||||
),
|
||||
);
|
||||
|
||||
Future<File> downloadImageAsFile(String imageUrl) async {
|
||||
final response = await http.get(Uri.parse(imageUrl));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
final filePath = '${tempDir.path}/${imageUrl.split('/').last}';
|
||||
final file = File(filePath);
|
||||
return await file.writeAsBytes(response.bodyBytes);
|
||||
} else {
|
||||
throw Exception('Не удалось загрузить изображение');
|
||||
}
|
||||
}
|
||||
|
||||
getMyRequestStatus(String slug) async {
|
||||
_update = true;
|
||||
final myRequestStatus = await consultantRepository.getMyRequestStatus(slug);
|
||||
|
||||
final List<String> photos = await Future.wait(
|
||||
myRequestStatus.photos.map(
|
||||
(e) async => (await downloadImageAsFile(e.url)).path,
|
||||
),
|
||||
);
|
||||
|
||||
List<CertificatesModel>? certificates = myRequestStatus.educationModel.completedCourses?.map((courseMap) {
|
||||
final course = courseMap.values.first;
|
||||
|
||||
return CertificatesModel(
|
||||
title: course.title,
|
||||
date: course.date,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
String? sanitizeLink(String? link) {
|
||||
return (link != null && link.isNotEmpty) ? link : null;
|
||||
}
|
||||
|
||||
emit(
|
||||
RegisterConsultantState(
|
||||
consultant: ConsultantProfileModel(
|
||||
photos: photos,
|
||||
certificates: certificates,
|
||||
socialLinks: SocialLinksModel(
|
||||
vkLink: sanitizeLink(myRequestStatus.educationModel.vkLink),
|
||||
tgLink: sanitizeLink(myRequestStatus.educationModel.tgLink),
|
||||
fbLink: sanitizeLink(myRequestStatus.educationModel.fbLink),
|
||||
instaLink: sanitizeLink(myRequestStatus.educationModel.instaLink),
|
||||
personalSiteLink: sanitizeLink(myRequestStatus.educationModel.personalSiteLink),
|
||||
),
|
||||
hasMedicalEducation: myRequestStatus.educationModel.hasMedicalEducation == 1,
|
||||
),
|
||||
acceptOffer: false,
|
||||
loading: false,
|
||||
requestModel: myRequestStatus,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
disableLoading() {
|
||||
emit(state.copyWith(loading: false));
|
||||
}
|
||||
|
||||
updateConsultantProfileModel(ConsultantProfileModel consultant, [bool acceptOffer = false]) {
|
||||
emit(RegisterConsultantState(consultant: consultant, acceptOffer: acceptOffer));
|
||||
emit(
|
||||
state.copyWith(
|
||||
consultant: consultant,
|
||||
acceptOffer: acceptOffer,
|
||||
loading: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
registerConsultant() async {
|
||||
@@ -35,7 +105,7 @@ class RegisterConsultantCubit extends Cubit<RegisterConsultantState> {
|
||||
),
|
||||
);
|
||||
}
|
||||
await consultantRepository.registerConsultant(consultant: state.consultant);
|
||||
await consultantRepository.registerConsultant(consultant: state.consultant, update: _update);
|
||||
}
|
||||
|
||||
Future<List<String>> uploadPhotos(List<File> files) async {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'register_consultant_state.freezed.dart';
|
||||
@@ -8,5 +9,7 @@ abstract class RegisterConsultantState with _$RegisterConsultantState {
|
||||
const factory RegisterConsultantState({
|
||||
required ConsultantProfileModel consultant,
|
||||
required bool acceptOffer,
|
||||
required bool loading,
|
||||
ConsultationRequestModel? requestModel,
|
||||
}) = _RegisterConsultantState;
|
||||
}
|
||||
|
||||
@@ -30,19 +30,20 @@ class _CertificatesAndDiplomasScreenState extends State<CertificatesAndDiplomasS
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (context.read<RegisterConsultantCubit>().state.consultant.certificates != null) {
|
||||
diplomasList = context
|
||||
.read<RegisterConsultantCubit>()
|
||||
.state
|
||||
.consultant
|
||||
.certificates!
|
||||
.map(
|
||||
(e) => DiplomaEntity(
|
||||
date: DateTime.tryParse(e.date),
|
||||
textEditingController: TextEditingController(text: e.title),
|
||||
enableDeleteButton: true,
|
||||
diplomasList = [
|
||||
...context.read<RegisterConsultantCubit>().state.consultant.certificates!.map(
|
||||
(e) => DiplomaEntity(
|
||||
date: DateTime.tryParse(e.date),
|
||||
textEditingController: TextEditingController(text: e.title),
|
||||
enableDeleteButton: true,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
DiplomaEntity(
|
||||
textEditingController: TextEditingController(),
|
||||
enableDeleteButton: false,
|
||||
date: null,
|
||||
),
|
||||
];
|
||||
diplomasList.last.enableDeleteButton = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:eatvio_app/core/utils/image_constant.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/last_step_screen.dart';
|
||||
@@ -15,7 +18,9 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
|
||||
class StepperBecomeConsultantScreen extends StatefulWidget {
|
||||
const StepperBecomeConsultantScreen({super.key});
|
||||
final String? slug;
|
||||
|
||||
const StepperBecomeConsultantScreen({super.key, this.slug});
|
||||
|
||||
@override
|
||||
State<StepperBecomeConsultantScreen> createState() => _StepperBecomeConsultantScreenState();
|
||||
@@ -25,249 +30,328 @@ class _StepperBecomeConsultantScreenState extends State<StepperBecomeConsultantS
|
||||
double progressValue = 1 / 6;
|
||||
int step = 1;
|
||||
final pageController = PageController();
|
||||
final registrationConsultantCubit = sl<RegisterConsultantCubit>();
|
||||
late final RegisterConsultantCubit registrationConsultantCubit;
|
||||
bool isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.slug == null) {
|
||||
registrationConsultantCubit = sl<RegisterConsultantCubit>()..disableLoading();
|
||||
} else {
|
||||
registrationConsultantCubit = sl<RegisterConsultantCubit>()..getMyRequestStatus(widget.slug!);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<RegisterConsultantCubit>(
|
||||
create: (context) => registrationConsultantCubit,
|
||||
child: Scaffold(
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||
floatingActionButton: Row(
|
||||
children: [
|
||||
Container(
|
||||
height: 48,
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
padding: const EdgeInsets.only(left: 16, right: 4),
|
||||
child: FloatingActionButton.extended(
|
||||
heroTag: 'backButtonRegistration',
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: const Color(0xFFEAF2FD),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
pageController.previousPage(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
});
|
||||
},
|
||||
label: Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 48,
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
padding: const EdgeInsets.only(left: 4, right: 16),
|
||||
child: FloatingActionButton.extended(
|
||||
heroTag: 'nextButtonRegistration',
|
||||
highlightElevation: 0,
|
||||
elevation: 0,
|
||||
focusElevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: isLoading ? Colors.grey : appTheme.blueA400,
|
||||
onPressed: isLoading
|
||||
? null
|
||||
: () async {
|
||||
if (step == 6) {
|
||||
if (registrationConsultantCubit.state.acceptOffer) {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
try {
|
||||
await registrationConsultantCubit.registerConsultant();
|
||||
if (!context.mounted) return;
|
||||
await showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
showDragHandle: true,
|
||||
context: context,
|
||||
builder: (context) => Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'Спасибо!\nВаши данные отправлены на модерацию',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Lottie.asset(
|
||||
'assets/lottie_animations/success.json',
|
||||
width: 160,
|
||||
height: 160,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'В течении трех рабочих дней Вам придет уведомление о смене статуса',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
GoRouter.of(context).pop();
|
||||
},
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Закрыть',
|
||||
child: BlocBuilder<RegisterConsultantCubit, RegisterConsultantState>(
|
||||
builder: (context, state) {
|
||||
if (state.loading == false) {
|
||||
return Scaffold(
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||
floatingActionButton: Row(
|
||||
children: [
|
||||
Container(
|
||||
height: 48,
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
padding: const EdgeInsets.only(left: 16, right: 4),
|
||||
child: FloatingActionButton.extended(
|
||||
heroTag: 'backButtonRegistration',
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: const Color(0xFFEAF2FD),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
pageController.previousPage(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
});
|
||||
},
|
||||
label: Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (state.requestModel?.educationModel.requestState == ModerationStatus.canceled)
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(state.requestModel!.canceledModeration!.title),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (int i = 0; i < state.requestModel!.canceledModeration!.additional!.length; i++) ...[
|
||||
Text('• ${state.requestModel!.canceledModeration!.additional![i]}'),
|
||||
]
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
height: 48,
|
||||
width: MediaQuery.of(context).size.width * 0.6,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: const Color(0x33FFCC00),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Комментарий',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF323F4B),
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 48,
|
||||
width: state.requestModel?.educationModel.requestState == ModerationStatus.canceled
|
||||
? MediaQuery.of(context).size.width * 0.2
|
||||
: MediaQuery.of(context).size.width * 0.8,
|
||||
padding: const EdgeInsets.only(left: 4, right: 16),
|
||||
child: FloatingActionButton.extended(
|
||||
heroTag: 'nextButtonRegistration',
|
||||
highlightElevation: 0,
|
||||
elevation: 0,
|
||||
focusElevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: isLoading
|
||||
? Colors.grey
|
||||
: state.requestModel?.educationModel.requestState == ModerationStatus.canceled
|
||||
? const Color(0xFFEAF2FD)
|
||||
: appTheme.blueA400,
|
||||
onPressed: isLoading
|
||||
? null
|
||||
: () async {
|
||||
if (step == 6) {
|
||||
if (registrationConsultantCubit.state.acceptOffer) {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
try {
|
||||
await registrationConsultantCubit.registerConsultant();
|
||||
if (!context.mounted) return;
|
||||
await showModalBottomSheet(
|
||||
useRootNavigator: true,
|
||||
showDragHandle: true,
|
||||
context: context,
|
||||
builder: (context) => Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'Спасибо!\nВаши данные отправлены на модерацию',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontSize: 20,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Lottie.asset(
|
||||
'assets/lottie_animations/success.json',
|
||||
width: 160,
|
||||
height: 160,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'В течении трех рабочих дней Вам придет уведомление о смене статуса',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
GoRouter.of(context).pop();
|
||||
},
|
||||
child: Ink(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
height: 52,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Закрыть',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
if (!context.mounted) return;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
actionsPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
content: Text(e.toString()),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('Ок'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
if (!context.mounted) return;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
actionsPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
content: Text(e.toString()),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('Ок'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
actionsPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
content: const Text('Примите договор публичной офёрты'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('Ок'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
setState(() {
|
||||
pageController.nextPage(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
label: isLoading
|
||||
? const CircularProgressIndicator()
|
||||
: state.requestModel?.educationModel.requestState == ModerationStatus.canceled
|
||||
? Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: appTheme.blueA400,
|
||||
)
|
||||
: Text(
|
||||
'Продолжить',
|
||||
style: theme.textTheme.titleSmall!.copyWith(color: Colors.white),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
actionsPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
content: const Text('Примите договор публичной офёрты'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('Ок'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
setState(() {
|
||||
pageController.nextPage(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
label: isLoading ? const CircularProgressIndicator() : Text(
|
||||
'Продолжить',
|
||||
style: theme.textTheme.titleSmall!.copyWith(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
leading: Builder(
|
||||
builder: (context) => IconButton(
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
onPressed: () => GoRouter.of(context).pop(),
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
title: SvgPicture.asset(
|
||||
ImageConstant.imgLogoEatvio,
|
||||
height: 48,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: Text('шаг $step из 6'),
|
||||
),
|
||||
],
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(MediaQuery.of(context).size.width, 32),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TweenAnimationBuilder<double>(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOut,
|
||||
tween: Tween<double>(
|
||||
begin: 1 / 6,
|
||||
end: progressValue,
|
||||
),
|
||||
builder: (context, value, _) => LinearProgressIndicator(
|
||||
value: value,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
minHeight: 8,
|
||||
backgroundColor: Colors.grey.shade100,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
leading: Builder(
|
||||
builder: (context) => IconButton(
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
onPressed: () => GoRouter.of(context).pop(),
|
||||
),
|
||||
),
|
||||
centerTitle: true,
|
||||
title: SvgPicture.asset(
|
||||
ImageConstant.imgLogoEatvio,
|
||||
height: 48,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: Text('шаг $step из 6'),
|
||||
),
|
||||
],
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(MediaQuery.of(context).size.width, 32),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TweenAnimationBuilder<double>(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOut,
|
||||
tween: Tween<double>(
|
||||
begin: 1 / 6,
|
||||
end: progressValue,
|
||||
),
|
||||
builder: (context, value, _) => LinearProgressIndicator(
|
||||
value: value,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
minHeight: 8,
|
||||
backgroundColor: Colors.grey.shade100,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(appTheme.blueA400),
|
||||
),
|
||||
body: PageView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
controller: pageController,
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
step = index + 1;
|
||||
progressValue = step / 6;
|
||||
});
|
||||
},
|
||||
children: const [
|
||||
CertificatesAndDiplomasScreen(),
|
||||
PhotoOrScansScreen(),
|
||||
AdditionalSettingsScreen(),
|
||||
SocialNetworksScreen(),
|
||||
RegistrationAsScreen(),
|
||||
LastStepScreen(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: PageView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
controller: pageController,
|
||||
onPageChanged: (index) {
|
||||
setState(() {
|
||||
step = index + 1;
|
||||
progressValue = step / 6;
|
||||
});
|
||||
},
|
||||
children: const [
|
||||
CertificatesAndDiplomasScreen(),
|
||||
PhotoOrScansScreen(),
|
||||
AdditionalSettingsScreen(),
|
||||
SocialNetworksScreen(),
|
||||
RegistrationAsScreen(),
|
||||
LastStepScreen(),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Scaffold(
|
||||
body: Loader(),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,11 +14,18 @@ class ConsultantRepository {
|
||||
|
||||
Future<void> registerConsultant({
|
||||
required ConsultantProfileModel consultant,
|
||||
bool update = false,
|
||||
}) async {
|
||||
try {
|
||||
return await consultantService.consultantRegistration(
|
||||
consultantModel: consultant,
|
||||
);
|
||||
if (update) {
|
||||
return await consultantService.consultantUpdate(
|
||||
consultantModel: consultant,
|
||||
);
|
||||
} else {
|
||||
return await consultantService.consultantRegistration(
|
||||
consultantModel: consultant,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
@@ -57,4 +64,12 @@ class ConsultantRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<ConsultationRequestModel> getMyRequestStatus(String slug) async {
|
||||
try {
|
||||
return await consultantService.getMyRequestStatus(slug: slug);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,14 @@ abstract class ConsultantService {
|
||||
Future<ConsultationRequestModel> getConsultantRequestStatus({
|
||||
@Path() required String slug,
|
||||
});
|
||||
|
||||
@GET('/api/consultant_request/{slug}/status')
|
||||
Future<ConsultationRequestModel> getMyRequestStatus({
|
||||
@Path() required String slug,
|
||||
});
|
||||
|
||||
@PUT('/api/consultant_request/update')
|
||||
Future<void> consultantUpdate({
|
||||
@Body() required ConsultantProfileModel consultantModel,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -293,6 +293,7 @@ class CreateDietCubit extends Cubit<CreateDietState> {
|
||||
final diet = Diet(
|
||||
id: 0,
|
||||
name: state.dietData.name ?? '',
|
||||
slug: '',
|
||||
image: imageInBase64,
|
||||
duration: state.dietData.duration ?? 0,
|
||||
state: state.dietData.state ?? DietState.active,
|
||||
|
||||
@@ -192,7 +192,7 @@ class _DietPreviewScreenState extends State<DietPreviewScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
path: 'diet/${widget.diet.slug}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
|
||||
@@ -16,6 +16,7 @@ import 'package:path_provider/path_provider.dart';
|
||||
class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
final RecipeRepository recipeRepository;
|
||||
final GlossaryRepository glossaryRepository;
|
||||
|
||||
CreateRecipeCubit({
|
||||
required this.recipeRepository,
|
||||
required this.glossaryRepository,
|
||||
@@ -192,7 +193,7 @@ class CreateRecipeCubit extends Cubit<CreateRecipeState> {
|
||||
recipe.steps!.map(
|
||||
(e) async => StepEntity(
|
||||
description: e.description,
|
||||
image: await downloadImageAsFile('$baseUrl/storage/${e.image}'),
|
||||
image: e.image.isEmpty ? null : await downloadImageAsFile('$baseUrl/storage/${e.image}'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -318,7 +318,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
path: 'diet/${widget.diet.slug}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
diet: widget.diet,
|
||||
@@ -499,7 +499,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
path: 'diet/${widget.diet.slug}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
diet: widget.diet,
|
||||
@@ -526,7 +526,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
path: 'diet/${widget.diet.slug}',
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: widget.diet.id,
|
||||
diet: widget.diet,
|
||||
|
||||
@@ -20,6 +20,7 @@ abstract class DietsPagination with _$DietsPagination {
|
||||
abstract class Diet with _$Diet {
|
||||
const factory Diet({
|
||||
@JsonKey(name: "id") required int id,
|
||||
@JsonKey(name: "slug") String? slug,
|
||||
@JsonKey(name: "name") required String name,
|
||||
@JsonKey(name: "image") required String image,
|
||||
@JsonKey(name: "duration") required int duration,
|
||||
|
||||
@@ -90,7 +90,7 @@ class _DietsWidgetState extends State<DietsWidget> {
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: CustomPopup(
|
||||
isAuthor: widget.diet.author.authorIsMe,
|
||||
path: 'diet/${widget.diet.id}',
|
||||
path: 'diet/${widget.diet.slug}',
|
||||
id: widget.diet.id,
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
diet: widget.diet,
|
||||
|
||||
@@ -62,8 +62,9 @@ class _PlanWidgetState extends State<PlanWidget> {
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: '$baseUrl/storage/${widget.plan.image}',
|
||||
fit: BoxFit.fitWidth,
|
||||
fit: BoxFit.cover,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 426,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
@@ -95,7 +96,7 @@ class _PlanWidgetState extends State<PlanWidget> {
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
path: 'plan/${widget.plan.slug}',
|
||||
id: widget.plan.id,
|
||||
slug: widget.plan.slug,
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
|
||||
@@ -113,7 +113,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
path: 'plan/${widget.plan.slug}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
@@ -143,7 +143,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
path: 'plan/${widget.plan.slug}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
@@ -362,7 +362,7 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
actions: [
|
||||
CustomPopup(
|
||||
isAuthor: widget.plan.author.authorIsMe,
|
||||
path: 'plan/${widget.plan.id}',
|
||||
path: 'plan/${widget.plan.slug}',
|
||||
complainedContentType: ComplainedContent.plan,
|
||||
slug: widget.plan.slug,
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:eatvio_app/features/my_finance/models/card_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/badge_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@@ -50,7 +51,7 @@ abstract class EducationModel with _$EducationModel {
|
||||
@JsonKey(name: "fb_link") String? fbLink,
|
||||
@JsonKey(name: "tg_link") String? tgLink,
|
||||
@JsonKey(name: "personal_site_link") String? personalSiteLink,
|
||||
@JsonKey(name: "request_state") String? requestState,
|
||||
@JsonKey(name: "request_state") required ModerationStatus requestState,
|
||||
}) = _EducationModel;
|
||||
|
||||
factory EducationModel.fromJson(Map<String, dynamic> json) => _$EducationModelFromJson(json);
|
||||
|
||||
@@ -33,6 +33,7 @@ class ProfileCubit extends Cubit<ProfileState> {
|
||||
);
|
||||
} catch (e) {
|
||||
emit(ProfileState.error(errorMessage: e.toString()));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@@ -92,12 +93,15 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
}
|
||||
return widget.author == null || widget.author!.authorIsMe ? _myProfileScreen(state) : _profileScreen(state);
|
||||
} else if (state is ProfileStateError) {
|
||||
return DataErrorWidget(
|
||||
onReload: () async {
|
||||
widget.author == null || widget.author!.authorIsMe
|
||||
? await profileCubit.getMyProfile()
|
||||
: await profileCubit.getProfileBySlug(widget.author!.authorSlug);
|
||||
},
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: DataErrorWidget(
|
||||
onReload: () async {
|
||||
widget.author == null || widget.author!.authorIsMe
|
||||
? await profileCubit.getMyProfile()
|
||||
: await profileCubit.getProfileBySlug(widget.author!.authorSlug);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
@@ -329,7 +333,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: 378,
|
||||
height: 781,
|
||||
child: PageView.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return PlanWidget(
|
||||
@@ -347,6 +351,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_bullets(_currentBullet, state.plansList.length),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -435,12 +440,12 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'Дипломы\nи сертификаты',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
@@ -449,14 +454,19 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF2F80ED),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug);
|
||||
// },
|
||||
// child: Text(
|
||||
// widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '',
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF2F80ED),
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -531,12 +541,12 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'Образование',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF323F4B),
|
||||
@@ -544,14 +554,19 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF2F80ED),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug);
|
||||
// },
|
||||
// child: Text(
|
||||
// widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '',
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xFF2F80ED),
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -584,6 +599,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
}
|
||||
|
||||
_educationBlock(String title, String date) {
|
||||
final parsedDate = DateTime.tryParse(date);
|
||||
final formattedDate = parsedDate != null
|
||||
? DateFormat('d MMMM y', 'ru_RU').format(parsedDate)
|
||||
: date;
|
||||
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Material(
|
||||
@@ -605,7 +625,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
date,
|
||||
formattedDate,
|
||||
style: const TextStyle(
|
||||
height: 1,
|
||||
color: Color(0xFF6D6F71),
|
||||
@@ -620,6 +640,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
_socialLinks(ProfileStateLoaded state) {
|
||||
if (!state.profile.roles.contains('consultant')) {
|
||||
return const SizedBox.shrink();
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/features/recipe/models/my_recipe_model.dart';
|
||||
import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recieps_cubit.dart';
|
||||
@@ -131,29 +130,6 @@ class _MyRecipeWidgetState extends State<MyRecipeWidget> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
GoRouter.of(context).pushNamed(
|
||||
RecipeCreateScreen.name,
|
||||
extra: await context.read<MyRecipesCubit>().getRecipeById(widget.recipe.slug),
|
||||
);
|
||||
},
|
||||
text: s.edit,
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
side: const WidgetStatePropertyAll(BorderSide.none),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
|
||||
@@ -58,7 +58,6 @@ class RegistrationCubit extends Cubit<RegistrationState> {
|
||||
),
|
||||
);
|
||||
await TokenStorage.saveTokenInStorage(token);
|
||||
AppRouter.navigatorKey.currentContext?.go('/feed-screen');
|
||||
AppRouter.navigatorKey.currentContext?.pushNamed('verifyEmailScreen');
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
|
||||
@@ -17,6 +17,13 @@ class _VerifyEmailScreenState extends State<VerifyEmailScreen> {
|
||||
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
|
||||
final List<TextEditingController> _controllers = List.generate(4, (_) => TextEditingController());
|
||||
String email = '';
|
||||
late final GoRouter goRouter;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
goRouter = GoRouter.of(context);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -48,7 +55,7 @@ class _VerifyEmailScreenState extends State<VerifyEmailScreen> {
|
||||
});
|
||||
} else if (state is VerifyEmailStateVerifySuccess) {
|
||||
showSuccessToast('Почта успешно подтверждена');
|
||||
GoRouter.of(context).pop();
|
||||
goRouter.pushNamed('feedScreen');
|
||||
} else if (state is VerifyEmailStateVerifyError) {
|
||||
showErrorToast("Неверный код. Попробуйте снова.");
|
||||
for (var controller in _controllers) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
|
||||
@@ -8,19 +10,31 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
class SettingsCubit extends Cubit<SettingsState> {
|
||||
final ProfileRepository profileRepository;
|
||||
final SettingsRepository settingsRepository;
|
||||
final ConsultantRepository consultantRepository;
|
||||
|
||||
SettingsCubit({
|
||||
required this.profileRepository,
|
||||
required this.settingsRepository,
|
||||
required this.consultantRepository,
|
||||
}) : super(const SettingsState.loading());
|
||||
|
||||
Future<void> init() async {
|
||||
final profile = await profileRepository.getMyProfile();
|
||||
late final ConsultationRequestModel? consultantInfo;
|
||||
try {
|
||||
emit(SettingsState.loaded(
|
||||
profileSettings: await settingsRepository.getProfileSettings(),
|
||||
profileDetails: await profileRepository.getMyProfileDetails(),
|
||||
profile: await profileRepository.getMyProfile(),
|
||||
),);
|
||||
consultantInfo = await consultantRepository.getMyRequestStatus(profile.slug);
|
||||
} catch (e) {
|
||||
consultantInfo = null;
|
||||
}
|
||||
try {
|
||||
emit(
|
||||
SettingsState.loaded(
|
||||
profileSettings: await settingsRepository.getProfileSettings(),
|
||||
profileDetails: await profileRepository.getMyProfileDetails(),
|
||||
profile: profile,
|
||||
consultationRequestModel: consultantInfo,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(SettingsState.error(errorMessage: e.toString()));
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@@ -14,6 +15,7 @@ abstract class SettingsState with _$SettingsState {
|
||||
required ProfileSettingsModel profileSettings,
|
||||
required ProfileDetailsModel profileDetails,
|
||||
required ProfileModel profile,
|
||||
ConsultationRequestModel? consultationRequestModel,
|
||||
}) = SettingsStateLoaded;
|
||||
|
||||
const factory SettingsState.error({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart';
|
||||
import 'package:eatvio_app/features/settings/entities/settings_entity.dart';
|
||||
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart';
|
||||
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_state.dart';
|
||||
@@ -58,11 +59,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
const SizedBox(height: 12),
|
||||
_aboutEatvio(state),
|
||||
const SizedBox(height: 12),
|
||||
if (!state.profile.roles.contains('consultant'))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _becomeConsultantButton(state),
|
||||
),
|
||||
_becomeConsultantButton(state),
|
||||
_deleteAccountButton(state),
|
||||
],
|
||||
),
|
||||
@@ -355,31 +352,84 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
}
|
||||
|
||||
_becomeConsultantButton(SettingsStateLoaded state) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: InkWell(
|
||||
onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
height: 52,
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Стать консультантом',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
if (state.consultationRequestModel == null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
|
||||
child: InkWell(
|
||||
onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
height: 52,
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Стать консультантом',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
if (state.consultationRequestModel!.educationModel.requestState == ModerationStatus.created) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
|
||||
child: Ink(
|
||||
height: 52,
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: const Color(0xFFEAEAEA),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Данные на проверке',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (state.consultationRequestModel!.educationModel.requestState == ModerationStatus.canceled) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16) + const EdgeInsets.only(bottom: 8),
|
||||
child: InkWell(
|
||||
onTap: () => GoRouter.of(context).pushNamed('stepperBecomeConsultantScreen', extra: state.profile.slug),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Ink(
|
||||
height: 52,
|
||||
width: MediaQuery.of(context).size.width - 16,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: const Color(0x33FFCC00),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Заявка обработана',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
height: 1,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
_deleteAccountButton(SettingsStateLoaded state) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: eatvio_app
|
||||
description: A new Flutter project.
|
||||
version: 1.1.1+30
|
||||
version: 1.1.2+32
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
|
||||
Reference in New Issue
Block a user