mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-10 15:17:21 +00:00
add delete account UI and logic
This commit is contained in:
3
assets/icons/delete_account_icon.svg
Normal file
3
assets/icons/delete_account_icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 14 KiB |
@ -20,6 +20,7 @@ class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
|||||||
on<UpdateTimerEvent>(_onUpdateTimer);
|
on<UpdateTimerEvent>(_onUpdateTimer);
|
||||||
on<VerifyPassCodeEvent>(verifyCode);
|
on<VerifyPassCodeEvent>(verifyCode);
|
||||||
on<ChangePasswordEvent>(changePassword);
|
on<ChangePasswordEvent>(changePassword);
|
||||||
|
on<DeleteAccountEvent>(onDeleteAccountEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSetPassword(SetPassword event, Emitter<SecurityState> emit) {
|
void _onSetPassword(SetPassword event, Emitter<SecurityState> emit) {
|
||||||
@ -180,7 +181,6 @@ class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
|||||||
ChangePasswordEvent event, Emitter<SecurityState> emit) async {
|
ChangePasswordEvent event, Emitter<SecurityState> emit) async {
|
||||||
emit(LoadingForgetState());
|
emit(LoadingForgetState());
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final response = await AuthenticationAPI.forgetPassword(
|
final response = await AuthenticationAPI.forgetPassword(
|
||||||
email: HomeCubit.user!.email!,
|
email: HomeCubit.user!.email!,
|
||||||
otpCode: event.otpCode,
|
otpCode: event.otpCode,
|
||||||
@ -196,4 +196,17 @@ class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> onDeleteAccountEvent(
|
||||||
|
DeleteAccountEvent event, Emitter<SecurityState> emit) async {
|
||||||
|
try {
|
||||||
|
await AuthenticationAPI.deleteAccount();
|
||||||
|
emit(ChangedPassState());
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorData = e.response!.data;
|
||||||
|
String errorMessage =
|
||||||
|
errorData['error']['message'] ?? 'something went wrong';
|
||||||
|
validate = errorMessage;
|
||||||
|
emit(AuthInitialState());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,5 @@ class ChangePasswordEvent extends SecurityEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class VerifyPassCodeEvent extends SecurityEvent {}
|
class VerifyPassCodeEvent extends SecurityEvent {}
|
||||||
|
|
||||||
|
class DeleteAccountEvent extends SecurityEvent {}
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
|
|
||||||
|
import '../../../../../../generated/assets.dart';
|
||||||
|
import '../../../../../../utils/resource_manager/color_manager.dart';
|
||||||
|
import '../../../../../shared_widgets/default_scaffold.dart';
|
||||||
|
|
||||||
|
class DeleteAccountPage extends StatelessWidget {
|
||||||
|
const DeleteAccountPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocListener<SecurityBloc, SecurityState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state is ChangedPassState) {
|
||||||
|
AuthCubit.get(context).logout();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: DefaultScaffold(
|
||||||
|
title: 'Delete Account',
|
||||||
|
bottomNavBar: SizedBox(
|
||||||
|
height: 150,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
context.read<SecurityBloc>().add(DeleteAccountEvent());
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 50,
|
||||||
|
margin: const EdgeInsets.only(right: 20, left: 20),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: ColorsManager.blueColor,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
|
child: const Center(
|
||||||
|
child: Text(
|
||||||
|
'Delete Account',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorsManager.onPrimaryColor),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 80, bottom: 30),
|
||||||
|
child: SvgPicture.asset(Assets.deleteAccountIcon),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: BodyMedium(
|
||||||
|
text: 'Account Verification',
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const BodyMedium(
|
||||||
|
text: 'if you confirm to "delete account",',
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 4,
|
||||||
|
),
|
||||||
|
const BodyMedium(
|
||||||
|
text: 'the account will be deleted',
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,10 @@ class ChangePasswordPage extends StatelessWidget {
|
|||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => BlocProvider(
|
builder: (context) => BlocProvider(
|
||||||
create: (_) => SecurityBloc(), // Provide the Bloc
|
create: (_) => SecurityBloc(), // Provide the Bloc
|
||||||
child: const VerificationCodePage(),
|
child: const VerificationCodePage(
|
||||||
|
title: 'Change Password',
|
||||||
|
isDeleteAccountMode: false,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/securty/view/change_password_page.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/securty/view/change_password_page.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/securty/view/verification_code_page.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
|
||||||
|
import '../bloc/security_event.dart';
|
||||||
|
|
||||||
class SecurtyView extends StatelessWidget {
|
class SecurtyView extends StatelessWidget {
|
||||||
const SecurtyView({super.key});
|
const SecurtyView({super.key});
|
||||||
|
|
||||||
@ -108,33 +113,44 @@ class SecurtyView extends StatelessWidget {
|
|||||||
// ],
|
// ],
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// InkWell(
|
Container(
|
||||||
// onTap: () {},
|
margin: const EdgeInsets.symmetric(vertical: 15),
|
||||||
// child: Column(
|
height: 1,
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
color: ColorsManager.greyColor,
|
||||||
// mainAxisSize: MainAxisSize.min,
|
),
|
||||||
// children: [
|
InkWell(
|
||||||
// const Row(
|
onTap: () {
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
// children: [
|
builder: (context) => BlocProvider(
|
||||||
// BodyMedium(
|
create: (_) => SecurityBloc()..add(StartTimerEvent()),
|
||||||
// text: 'Delete Account',
|
child: VerificationCodePage(
|
||||||
// ),
|
title: 'Delete Account',
|
||||||
// Icon(
|
isDeleteAccountMode: true,
|
||||||
// Icons.arrow_forward_ios,
|
),
|
||||||
// color: ColorsManager.greyColor,
|
),
|
||||||
// size: 15,
|
));
|
||||||
// )
|
},
|
||||||
// ],
|
child: Column(
|
||||||
// ),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
// Container(
|
mainAxisSize: MainAxisSize.min,
|
||||||
// margin: const EdgeInsets.symmetric(vertical: 15),
|
children: [
|
||||||
// height: 1,
|
Row(
|
||||||
// color: ColorsManager.greyColor,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
// ),
|
children: [
|
||||||
// ],
|
BodyMedium(
|
||||||
// ),
|
text: 'Delete Account',
|
||||||
// ),
|
fontColor: ColorsManager.red,
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
size: 15,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
// InkWell(
|
// InkWell(
|
||||||
// onTap: () {},
|
// onTap: () {},
|
||||||
// child: const Row(
|
// child: const Row(
|
||||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
|||||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_bloc.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.dart';
|
||||||
|
import 'package:syncrow_app/features/menu/view/widgets/securty/delete_account/delete_account_page.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/securty/view/set_password_page.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/securty/view/set_password_page.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
@ -11,7 +12,13 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
|||||||
import 'package:pin_code_fields/pin_code_fields.dart';
|
import 'package:pin_code_fields/pin_code_fields.dart';
|
||||||
|
|
||||||
class VerificationCodePage extends StatelessWidget {
|
class VerificationCodePage extends StatelessWidget {
|
||||||
const VerificationCodePage({super.key});
|
final String title;
|
||||||
|
final bool isDeleteAccountMode;
|
||||||
|
const VerificationCodePage({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.isDeleteAccountMode,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -20,19 +27,29 @@ class VerificationCodePage extends StatelessWidget {
|
|||||||
create: (context) => SecurityBloc()..add(StartTimerEvent()),
|
create: (context) => SecurityBloc()..add(StartTimerEvent()),
|
||||||
child: BlocConsumer<SecurityBloc, SecurityState>(
|
child: BlocConsumer<SecurityBloc, SecurityState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
|
final securityBloc = context.read<SecurityBloc>();
|
||||||
if (state is SuccessForgetState) {
|
if (state is SuccessForgetState) {
|
||||||
|
if (isDeleteAccountMode) {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
|
builder: (context) => BlocProvider.value(
|
||||||
|
value: securityBloc,
|
||||||
|
child: DeleteAccountPage(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
builder: (context) => SetPasswordPage(
|
builder: (context) => SetPasswordPage(
|
||||||
otpCode: otp,
|
otpCode: otp,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final _bloc = BlocProvider.of<SecurityBloc>(context);
|
final _bloc = BlocProvider.of<SecurityBloc>(context);
|
||||||
|
|
||||||
return DefaultScaffold(
|
return DefaultScaffold(
|
||||||
title: 'Change Password',
|
title: title,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 55),
|
const SizedBox(height: 55),
|
||||||
@ -109,27 +126,35 @@ class VerificationCodePage extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap:
|
onTap: state is TimerState &&
|
||||||
state is TimerState && !state.isButtonEnabled && state.remainingTime != 1
|
!state.isButtonEnabled &&
|
||||||
|
state.remainingTime != 1
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
_bloc.add(StartTimerEvent());
|
_bloc.add(StartTimerEvent());
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(right: 20, left: 20, top: 15, bottom: 15),
|
padding: const EdgeInsets.only(
|
||||||
|
right: 20, left: 20, top: 15, bottom: 15),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: state is TimerState && !state.isButtonEnabled
|
color: state is TimerState && !state.isButtonEnabled
|
||||||
? ColorsManager.blueButton
|
? ColorsManager.blueButton
|
||||||
: ColorsManager.blueColor,
|
: ColorsManager.blueColor,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(20))),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "${_bloc.formattedTime(state.remainingTime)} " : "Resend"}',
|
state is TimerState &&
|
||||||
|
!state.isButtonEnabled &&
|
||||||
|
state.remainingTime != 1
|
||||||
|
? "${_bloc.formattedTime(state.remainingTime)} "
|
||||||
|
: "Resend",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: state is TimerState && !state.isButtonEnabled
|
color: state is TimerState &&
|
||||||
|
!state.isButtonEnabled
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: ColorsManager.onPrimaryColor,
|
: ColorsManager.onPrimaryColor,
|
||||||
),
|
),
|
||||||
@ -142,18 +167,24 @@ class VerificationCodePage extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<SecurityBloc>().add(VerifyPassCodeEvent());
|
context
|
||||||
|
.read<SecurityBloc>()
|
||||||
|
.add(VerifyPassCodeEvent());
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(right: 20, left: 20, top: 15, bottom: 15),
|
padding: const EdgeInsets.only(
|
||||||
|
right: 20, left: 20, top: 15, bottom: 15),
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: ColorsManager.blueColor,
|
color: ColorsManager.blueColor,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(20))),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Verify",
|
"Verify",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16, color: Colors.white, fontWeight: FontWeight.w700),
|
fontSize: 16,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w700),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1128,7 +1128,7 @@ class Assets {
|
|||||||
static const String editNameSetting = "assets/icons/edit_name_setting.svg";
|
static const String editNameSetting = "assets/icons/edit_name_setting.svg";
|
||||||
|
|
||||||
static const String verificationIcon = "assets/icons/verification_icon.svg";
|
static const String verificationIcon = "assets/icons/verification_icon.svg";
|
||||||
|
static const String deleteAccountIcon='assets/icons/delete_account_icon.svg';
|
||||||
static const String passwordUnvisibility =
|
static const String passwordUnvisibility =
|
||||||
"assets/icons/password_unvisibility.svg";
|
"assets/icons/password_unvisibility.svg";
|
||||||
static const String passwordVisibility =
|
static const String passwordVisibility =
|
||||||
|
@ -195,6 +195,7 @@ abstract class ApiEndpoints {
|
|||||||
static const String sendPicture = '/user/profile-picture/{userUuid}';
|
static const String sendPicture = '/user/profile-picture/{userUuid}';
|
||||||
static const String getRegion = '/region';
|
static const String getRegion = '/region';
|
||||||
static const String getTimezone = '/timezone';
|
static const String getTimezone = '/timezone';
|
||||||
|
static const String deleteProfile = '/user';
|
||||||
|
|
||||||
//multiple-time offline
|
//multiple-time offline
|
||||||
static const String addMultipleTimeTemporaryPassword =
|
static const String addMultipleTimeTemporaryPassword =
|
||||||
|
@ -83,4 +83,11 @@ class AuthenticationAPI {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<void> deleteAccount() async {
|
||||||
|
await HTTPService().delete(
|
||||||
|
path: ApiEndpoints.deleteProfile,
|
||||||
|
expectedResponseModel: (p0) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user