diff --git a/app/lib/features/authentication/register/presentation/pages/v2/_pages.dart b/app/lib/features/authentication/register/presentation/pages/v2/_pages.dart new file mode 100644 index 0000000..c3c60e1 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/v2/_pages.dart @@ -0,0 +1,19 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; + +import '../../../../../../core/bases/widgets/atoms/button.dart'; +import '../../../../../../core/bases/widgets/layout/bebras_scaffold.dart'; +import '../../../../../../core/constants/assets.dart'; +import '../../../../../../../services/di.dart'; +import '../../../../../main/presentation/bloc/home_cubit.dart'; +import '../../../bloc/user_register_bloc.dart'; +import '../../../model/form_item.dart'; +import 'widgets/biro_bebras_dropdownV2.dart'; +import 'widgets/custom_date_pickerV2.dart'; +import 'widgets/custom_text_fieldV2.dart'; +import 'widgets/province_dropdownV2.dart'; + +part 'register_page.dart'; diff --git a/app/lib/features/authentication/register/presentation/pages/v2/register_page.dart b/app/lib/features/authentication/register/presentation/pages/v2/register_page.dart new file mode 100644 index 0000000..508461a --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/v2/register_page.dart @@ -0,0 +1,363 @@ +// ignore_for_file: lines_longer_than_80_chars + +part of '_pages.dart'; + +class RegisterPageV2 extends StatefulWidget { + const RegisterPageV2({super.key, this.isUpdateProfile}); + + final String? isUpdateProfile; + + @override + State createState() => _RegisterPageStateV2(); +} + +class _RegisterPageStateV2 extends State { + Future showModal() { + return showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Container( + height: 206, + width: double.infinity, + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox( + height: 30, + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: const Text( + 'Anda akan meninggalkan halaman ini. Data formulir tidak akan disimpan. Lanjutkan?', + textAlign: TextAlign.left, + style: + TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + const SizedBox( + height: 15, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + customButtonColor: Color.fromARGB(255, 243, 238, 238), + customTextColor: Colors.blue, + text: 'Ya'), + ), + const SizedBox( + height: 5, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + customButtonColor: Color(0xFF1BB8E1), + customTextColor: Colors.white, + text: 'Tidak'), + ), + ], + ), + ); + }); + }); + } + + late final UserRegisterBloc _userRegisterBloc; + String? selectedValue; + + @override + void initState() { + _userRegisterBloc = get(); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + return BlocProvider( + create: (_) => get() + ..add( + const InitialValueEvent(), + ), + child: BlocListener( + listener: (context, state) { + if (state is UserRegisterSuccessState) { + if (widget.isUpdateProfile == 'true') { + // refresh page + Navigator.pop(context); + Navigator.push( + context, + // ignore: inference_failure_on_instance_creation + MaterialPageRoute( + builder: (context) => + const RegisterPageV2(isUpdateProfile: 'true'), + ), + ); + + context.read().fetchUser(); + + // add notification + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Pembaruan data profil berhasil'), + behavior: SnackBarBehavior.floating, + ), + ); + } else { + context.go('/main'); + } + } + }, + child: BlocBuilder( + builder: (context, state) { + return BebrasScaffold( + avoidBottomInset: false, + body: Padding( + padding: const EdgeInsets.only( + left: 16, + top: 20, + right: 16, + ), + child: Form( + key: state.formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + GestureDetector( + onTap: () { + showModal(); + }, + child: Container( + child: Icon( + Icons.arrow_back, + // color: Colors.blue, + ), + ), + ), + Flexible( + child: GestureDetector( + onTap: () async { + await context.push( + Uri( + path: '/register', + queryParameters: { + 'isUpdateProfile': 'true', + }, + ).toString(), + ); + }, + child: Container( + // width: double.infinity, + child: Center( + child: const Text( + 'Edit Profile', + textAlign: TextAlign.start, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + ), + ), + ), + ], + ), + const SizedBox( + height: 10, + ), + Column(children: [ + CircleAvatar( + maxRadius: 50, + backgroundImage: NetworkImage( + Assets.bLogo, + ), + ), + const SizedBox( + height: 15, + ), + Text('Putri Nabila', + textAlign: TextAlign.center, + style: TextStyle(fontWeight: FontWeight.w600)), + ]), + const SizedBox( + height: 10, + ), + CustomTextFieldV2( + 'Email', + (value) { + BlocProvider.of(context).add( + EmailEvent(email: BlocFormItem(value: value)), + ); + }, + (val) { + return state.email.error; + }, + state.email.value, + ), + CustomTextFieldV2( + 'Nama', + (value) { + BlocProvider.of(context) + .add(NameEvent(name: BlocFormItem(value: value))); + }, + (val) { + return state.name.error; + }, + state.name.value, + ), + CustomTextFieldV2( + 'Tempat Lahir', + (value) { + // BlocProvider.of(context).add( + // NameEvent(name: BlocFormItem(value: value)), + // ); + }, + (val) { + // return state.name.error; + null; + }, + null, + ), + CustomDatePickerV2( + 'Date', + (value) { + BlocProvider.of(context).add( + BirthDateEvent( + birthDate: BlocFormItem( + value: value, + ), + ), + ); + }, + (val) { + return state.birthDate.error; + }, + state.birthDate.value, + ), + CustomTextFieldV2( + 'Asal Sekolah', + (value) { + BlocProvider.of(context).add( + SchoolEvent( + school: BlocFormItem( + value: value, + ), + ), + ); + }, + (val) { + return state.school.error; + }, + state.school.value, + ), + ProvinceDropdownV2( + 'Provinsi', + (value) { + BlocProvider.of(context).add( + ProvinceEvent( + province: BlocFormItem( + value: value, + ), + ), + ); + }, + (val) { + return state.province.error; + }, + state.province.value.isNotEmpty + ? state.province.value + : 'Provinsi', + ), + BiroBebrasDropdownV2( + 'Bebras Biro', + (value) { + BlocProvider.of(context).add( + BebrasBiroEvent( + bebrasBiro: BlocFormItem( + value: value, + ), + ), + ); + }, + (val) { + return state.bebrasBiro.error; + }, + state.bebrasBiro.value.isNotEmpty + ? state.bebrasBiro.value + : 'Bebras Biro', + ), + BlocConsumer( + bloc: _userRegisterBloc, + listener: (context, state) { + if (state is UserRegisterSuccessState) { + if (widget.isUpdateProfile == 'true') { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text( + 'Profile data successfully updated', + ), + action: SnackBarAction( + label: 'OK', + onPressed: () { + // Some code to undo the change. + }, + ), + ), + ); + } else { + context.go('/main'); + } + } + }, + builder: (context, state) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + fixedSize: Size(size.width, 45), + backgroundColor: Colors.lightBlue, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onPressed: () { + if (state is! UserRegisterLoadingState) { + if (widget.isUpdateProfile == 'true') { + BlocProvider.of(context) + .add(const FormSubmitUpdateEvent()); + } else { + BlocProvider.of(context) + .add(const FormSubmitEvent()); + } + } + }, + child: Text( + widget.isUpdateProfile == 'true' + ? 'Perbarui' + : 'Daftar', + style: + const TextStyle(fontWeight: FontWeight.w600), + ), + ); + }, + ), + ], + ), + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/app/lib/features/authentication/register/presentation/pages/v2/widgets/biro_bebras_dropdownV2.dart b/app/lib/features/authentication/register/presentation/pages/v2/widgets/biro_bebras_dropdownV2.dart new file mode 100644 index 0000000..2e3ceb9 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/v2/widgets/biro_bebras_dropdownV2.dart @@ -0,0 +1,59 @@ +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../../core/constants/bebras_biro_dropdown.dart'; + +class BiroBebrasDropdownV2 extends StatelessWidget { + const BiroBebrasDropdownV2( + this.labelText, + this.handleTextInput, + this.validator, + this.initValue, { + super.key, + }); + + final String labelText; + final void Function(String value)? handleTextInput; + final String? Function(String?)? validator; + final String? initValue; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 70, + child: DropdownSearch( + selectedItem: initValue, + validator: validator, + popupProps: const PopupProps.menu( + showSearchBox: true, + ), + items: bebrasBiroList, + dropdownDecoratorProps: DropDownDecoratorProps( + textAlignVertical: TextAlignVertical.center, + baseStyle: const TextStyle(fontSize: 12), + dropdownSearchDecoration: InputDecoration( + helperText: '', + helperStyle: const TextStyle( + fontSize: 10, + ), + hintText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(5), + ), + enabledBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + onChanged: (String? item) => handleTextInput!(item!), + ), + ); + } +} diff --git a/app/lib/features/authentication/register/presentation/pages/v2/widgets/custom_date_pickerV2.dart b/app/lib/features/authentication/register/presentation/pages/v2/widgets/custom_date_pickerV2.dart new file mode 100644 index 0000000..946ea19 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/v2/widgets/custom_date_pickerV2.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class CustomDatePickerV2 extends StatefulWidget { + const CustomDatePickerV2( + this.labelText, + this.handleTextInput, + this.validator, + this.initValue, { + Key? key, + }) : super(key: key); + + final String labelText; + final void Function(String value)? handleTextInput; + final String? Function(String?)? validator; + final String? initValue; + + @override + State createState() => _CustomDatePickerState(); +} + +class _CustomDatePickerState extends State { + final TextEditingController dateinput = TextEditingController(); + + @override + void initState() { + setState(() { + dateinput.text = widget.initValue!; + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 70, + child: Padding( + padding: const EdgeInsets.symmetric(), + child: TextFormField( + controller: dateinput, + validator: widget.validator, + style: const TextStyle(fontSize: 12, color: Colors.black), + decoration: InputDecoration( + helperText: '', + helperStyle: const TextStyle(fontSize: 10), + labelText: widget.labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + suffixIcon: GestureDetector( + onTap: () async { + final pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1900), + lastDate: DateTime(2101), + ); + + if (pickedDate != null) { + final formattedDate = + DateFormat('yyyy-MM-dd').format(pickedDate); + widget.handleTextInput!(formattedDate); + setState(() { + dateinput.text = formattedDate; + }); + } else { + print('Date is not selected'); + } + }, + child: const Icon(Icons.calendar_today), + ), + ), + readOnly: true, + onTap: () async { + final pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1900), + lastDate: DateTime(2101), + ); + + if (pickedDate != null) { + final formattedDate = DateFormat('yyyy-MM-dd').format(pickedDate); + widget.handleTextInput!(formattedDate); + setState(() { + dateinput.text = formattedDate; + }); + } else { + print('Date is not selected'); + } + }, + onChanged: (value) => widget.handleTextInput!(value), + ), + ), + ); + } +} diff --git a/app/lib/features/authentication/register/presentation/pages/v2/widgets/custom_text_fieldV2.dart b/app/lib/features/authentication/register/presentation/pages/v2/widgets/custom_text_fieldV2.dart new file mode 100644 index 0000000..9edecb8 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/v2/widgets/custom_text_fieldV2.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class CustomTextFieldV2 extends StatelessWidget { + const CustomTextFieldV2( + this.labelText, + this.handleTextInput, + this.validator, + this.initValue, { + super.key, + }); + + final String labelText; + final void Function(String value)? handleTextInput; + final String? Function(String?)? validator; + final String? initValue; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 70, + child: TextFormField( + onChanged: (value) => handleTextInput!(value), + validator: validator, + initialValue: initValue, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + helperText: '', + helperStyle: const TextStyle(fontSize: 10), + labelText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + ); + } +} diff --git a/app/lib/features/authentication/register/presentation/pages/v2/widgets/province_dropdownV2.dart b/app/lib/features/authentication/register/presentation/pages/v2/widgets/province_dropdownV2.dart new file mode 100644 index 0000000..ff519ca --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/v2/widgets/province_dropdownV2.dart @@ -0,0 +1,57 @@ +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; + +import '../../../../../../../core/constants/indonesia_province.dart'; + +class ProvinceDropdownV2 extends StatelessWidget { + const ProvinceDropdownV2( + this.labelText, + this.handleTextInput, + this.validator, + this.initValue, { + super.key, + }); + + final String labelText; + final void Function(String value)? handleTextInput; + final String? Function(String?)? validator; + final String? initValue; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 70, + child: DropdownSearch( + selectedItem: initValue, + validator: validator, + popupProps: const PopupProps.menu( + showSearchBox: true, + ), + items: provinceList, + dropdownDecoratorProps: DropDownDecoratorProps( + textAlignVertical: TextAlignVertical.center, + baseStyle: const TextStyle(fontSize: 12), + dropdownSearchDecoration: InputDecoration( + helperText: '', + helperStyle: const TextStyle(fontSize: 10), + hintText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + onChanged: (String? item) => handleTextInput!(item!), + ), + ); + } +} diff --git a/app/lib/features/main/presentation/pages/v2/delete_page.dart b/app/lib/features/main/presentation/pages/v2/delete_page.dart new file mode 100644 index 0000000..fd1825f --- /dev/null +++ b/app/lib/features/main/presentation/pages/v2/delete_page.dart @@ -0,0 +1,272 @@ +// part of '_pages.dart'; + +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../../../../../core/bases/widgets/layout/bebras_scaffold.dart'; + +class DeleteAccountPage extends StatefulWidget { + const DeleteAccountPage({super.key}); + + @override + State createState() => _DeleteAccountPageState(); +} + +class _DeleteAccountPageState extends State { + @override + Widget build(BuildContext context) { + return BebrasScaffold( + avoidBottomInset: false, + body: Padding( + padding: const EdgeInsets.only( + left: 15, + top: 20, + right: 16, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + child: Container( + child: Icon( + Icons.arrow_back, + )), + )), + Flexible( + child: Center( + child: Text('Hapus Akun', + textAlign: TextAlign.center, + style: + TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), + )), + ], + ), + const SizedBox( + height: 50, + ), + Column( + children: [ + Container( + child: const Text( + 'Kami sangat menyesal mendengar bahwa Anda mempertimbangkan untuk menghapus akun Anda di Bebras Pandai. ' + 'Sebelum Anda melangkah lebih jauh, kami ingin memastikan Anda memahami konsekuensi dari penghapusan akun. Mohon perhatikan informasi berikut:', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + )), + ) + ], + ), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: Row( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '1', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Kehilangan Akses', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ], + )), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Menghapus akun berarti Anda akan kehilangan akses ke semua data, prestasi, dan konten yang terkait dengan akun Anda, ' + 'termasuk riwayat latihan yang pernah Anda kerjakan.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]), + ]), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: Row(children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '2', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Tidak Dapat Dipulihkan', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ])), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Penghapusan akun bersifat permanen dan tidak dapat dipulihkan. ' + 'Pastikan untuk mempertimbangkan keputusan ini secara hati-hati sebelum melanjutkan.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ]), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: Row(children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '3', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Pertanyaan dan Bantuan', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ])), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Jika Anda memiliki pertanyaan atau memerlukan bantuan, tim dukungan kami siap membantu. ' + 'Hubungi kami di support@bebraspandai.com.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ]), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: Row(children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '4', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Peringatan Akhir', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ])), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Sebelum menekan tombol "Hapus Akun," pastikan Anda telah mempertimbangkan keputusan ini dengan matang.' + 'Kami berharap Anda mempertimbangkan untuk tetap menjadi tetap mengikuti perjalanan pendidikan bersama kami.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ]), + const SizedBox( + height: 30, + ), + Text( + 'Terima kasih atas partisipasi Anda di Bebras Pandai. Kami berharap Anda mempertimbangkan pilihan Anda dengan cermat sebelum mengambil langkah ini.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + )), + const SizedBox( + height: 30, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.lightBlue, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onPressed: () async { + final url = Uri.parse( + 'https://docs.google.com/forms/d/1mUpZXTLvNU93C_bD-HeUTSTBVK1tRDE69t117dkE7ks/edit', + ); + if (!await launchUrl(url)) { + throw Exception('Could not launch $url'); + } + }, + child: Text('Hapus Akun')), + ], + ), + ), + ); + } +} diff --git a/app/lib/features/main/presentation/pages/v2/policy_page.dart b/app/lib/features/main/presentation/pages/v2/policy_page.dart new file mode 100644 index 0000000..78ddee2 --- /dev/null +++ b/app/lib/features/main/presentation/pages/v2/policy_page.dart @@ -0,0 +1,304 @@ +// part of '_pages.dart'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../../../../core/bases/widgets/layout/bebras_scaffold.dart'; + +class PrivacyPolicyPage extends StatefulWidget { + const PrivacyPolicyPage({super.key}); + + @override + State createState() => _PrivacyPolicyPageState(); +} + +class _PrivacyPolicyPageState extends State { + @override + Widget build(BuildContext context) { + return BebrasScaffold( + avoidBottomInset: false, + body: Padding( + padding: const EdgeInsets.only( + left: 15, + top: 20, + right: 16, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + child: Container( + child: Icon( + Icons.arrow_back, + )), + )), + Flexible( + child: Center( + child: Text('Kebijakan Privasi', + textAlign: TextAlign.center, + style: + TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), + )), + ], + ), + const SizedBox( + height: 10, + ), + Column( + children: [ + Container( + child: const Text( + 'Selamat datang di Kebijakan Privasi Bebras Pandai! ' + 'Kami sangat menghargai kepercayaan dan privasi Anda ' + 'Sebagai pengguna Bebras Pandai, Anda memiliki hak untuk mengetahui bagaimana data Anda diambil, digunakan, dan dijaga.' + 'Mohon luangkan waktu sejenak untuk membaca kebijakan privasi kami:', + textAlign: TextAlign.justify, + style: + TextStyle(fontSize: 12,)), + ) + ], + ), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: Row( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '1', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Informasi yang kami kumpulkan', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ], + )), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Bebras Pandai mengumpulkan informasi yang diperlukan untuk pengaturan akun dan meningkatkan pengalaman pengguna. ' + 'Ini mungkin mencakup nama, alamat email, dan informasi profil tambahan yang Anda pilih untuk dibagikan.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]), + ]), + const SizedBox( + height: 5, + ), + Column( + children: [ + Container( + child: Row( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '2', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Penggunaan Informasi', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ] + ) + ), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Informasi yang kami kumpulkan digunakan untuk menyajikan konten yang sesuai dengan minat Anda, memantau kinerja aplikasi, dan memastikan keamanan akun Anda. ' + 'Kami tidak pernah menyediakan informasi pribadi Anda kepada pihak ketiga tanpa izin Anda.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ] + ), + const SizedBox( + height: 5, + ), + Column( + children: [ + Container( + child: Row( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '3', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Keamanan Data', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ] + ) + ), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Keamanan data Anda adalah prioritas kami.' + 'Kami menggunakan langkah-langkah keamanan yang ketat untuk melindungi informasi pribadi Anda dari akses yang tidak sah atau penggunaan yang tidak sah.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ] + ), + const SizedBox( + height: 5, + ), + Column( + children: [ + Container( + child: Row( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '4', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Perubahan Kebijakan Privasi', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ] + ) + ), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Kebijakan Privasi kami dapat diperbarui dari waktu ke waktu.' + 'Pemberitahuan perubahan akan disajikan melalui aplikasi atau situs web kami. Pastikan untuk memeriksa kebijakan ini secara berkala.', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ] + ), + const SizedBox( + height: 5, + ), + Column( + children: [ + Container( + child: Row( + children: [ + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + height: 30, + width: 30, + child: Center( + child: const Text( + '5', + style: TextStyle( + fontWeight: FontWeight.w600, color: Colors.white), + ), + ), + decoration: BoxDecoration( + color: Colors.blue[300], + shape: BoxShape.circle, + )), + Flexible( + child: Text('Kontak Kami', + style: TextStyle( + fontWeight: FontWeight.w600, + ))) + ] + ) + ), + const SizedBox( + height: 5, + ), + Column(children: [ + Container( + child: const Text( + 'Jika Anda memiliki pertanyaan atau kekhawatiran tentang kebijakan privasi kami, jangan ragu untuk menghubungi tim dukungan kami di support@bebraspandai.com.' + 'Dengan menggunakan Bebras Pandai, Anda menyetujui Kebijakan Privasi kami. Terima kasih atas kepercayaan dan partisipasi Anda dalam Aplikasi Bebras Pandai!', + textAlign: TextAlign.justify, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + ))) + ]) + ] + ), + ], + ), + ), + ); + } +} diff --git a/app/lib/features/main/presentation/pages/v2/register_page.dart b/app/lib/features/main/presentation/pages/v2/register_page.dart new file mode 100644 index 0000000..ea5f363 --- /dev/null +++ b/app/lib/features/main/presentation/pages/v2/register_page.dart @@ -0,0 +1,242 @@ +// // ignore_for_file: lines_longer_than_80_chars + +// part of '_pages.dart'; + +// class RegisterPage extends StatefulWidget { +// const RegisterPage({super.key, this.isUpdateProfile}); + +// final String? isUpdateProfile; + +// @override +// State createState() => _RegisterPageState(); +// } + +// class _RegisterPageState extends State { +// late final UserRegisterBloc _userRegisterBloc; +// String? selectedValue; + +// @override +// void initState() { +// _userRegisterBloc = get(); + +// super.initState(); +// } + +// @override +// Widget build(BuildContext context) { +// final size = MediaQuery.of(context).size; +// return BlocProvider( +// create: (_) => get() +// ..add( +// const InitialValueEvent(), +// ), +// child: BlocListener( +// listener: (context, state) { +// if (state is UserRegisterSuccessState) { +// if (widget.isUpdateProfile == 'true') { +// // refresh page +// Navigator.pop(context); +// Navigator.push( +// context, +// // ignore: inference_failure_on_instance_creation +// MaterialPageRoute( +// builder: (context) => +// const RegisterPage(isUpdateProfile: 'true'), +// ), +// ); + +// context.read().fetchUser(); + +// // add notification +// ScaffoldMessenger.of(context).showSnackBar( +// const SnackBar( +// content: Text('Pembaruan data profil berhasil'), +// behavior: SnackBarBehavior.floating, +// ), +// ); +// } else { +// context.go('/main'); +// } +// } +// }, +// child: BlocBuilder( +// builder: (context, state) { +// return BebrasScaffold( +// avoidBottomInset: false, +// body: Padding( +// padding: const EdgeInsets.only( +// left: 16, +// top: 30, +// right: 16, +// ), +// child: Form( +// key: state.formKey, +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.stretch, +// children: [ +// CircleAvatar( +// maxRadius: 60, +// backgroundImage: NetworkImage( +// Assets.bLogo, +// ), +// ), +// const SizedBox( +// height: 40, +// ), +// CustomTextField( +// 'Email', +// (value) { +// BlocProvider.of(context).add( +// EmailEvent(email: BlocFormItem(value: value)), +// ); +// }, +// (val) { +// return state.email.error; +// }, +// state.email.value, +// ), +// CustomTextField( +// 'Nama', +// (value) { +// BlocProvider.of(context) +// .add(NameEvent(name: BlocFormItem(value: value))); +// }, +// (val) { +// return state.name.error; +// }, +// state.name.value, +// ), +// CustomDatePicker( +// 'Date', +// (value) { +// BlocProvider.of(context).add( +// BirthDateEvent( +// birthDate: BlocFormItem( +// value: value, +// ), +// ), +// ); +// }, +// (val) { +// return state.birthDate.error; +// }, +// state.birthDate.value, +// ), +// CustomTextField( +// 'Sekolah', +// (value) { +// BlocProvider.of(context).add( +// SchoolEvent( +// school: BlocFormItem( +// value: value, +// ), +// ), +// ); +// }, +// (val) { +// return state.school.error; +// }, +// state.school.value, +// ), +// ProvinceDropdown( +// 'Provinsi', +// (value) { +// BlocProvider.of(context).add( +// ProvinceEvent( +// province: BlocFormItem( +// value: value, +// ), +// ), +// ); +// }, +// (val) { +// return state.province.error; +// }, +// state.province.value.isNotEmpty +// ? state.province.value +// : 'Provinsi', +// ), +// BiroBebrasDropdown( +// 'Bebras Biro', +// (value) { +// BlocProvider.of(context).add( +// BebrasBiroEvent( +// bebrasBiro: BlocFormItem( +// value: value, +// ), +// ), +// ); +// }, +// (val) { +// return state.bebrasBiro.error; +// }, +// state.bebrasBiro.value.isNotEmpty +// ? state.bebrasBiro.value +// : 'Bebras Biro', +// ), +// const SizedBox(height: 20), +// BlocConsumer( +// bloc: _userRegisterBloc, +// listener: (context, state) { +// if (state is UserRegisterSuccessState) { +// if (widget.isUpdateProfile == 'true') { +// ScaffoldMessenger.of(context).showSnackBar( +// SnackBar( +// content: const Text( +// 'Profile data successfully updated', +// ), +// action: SnackBarAction( +// label: 'OK', +// onPressed: () { +// // Some code to undo the change. +// }, +// ), +// ), +// ); +// } else { +// context.go('/main'); +// } +// } +// }, +// builder: (context, state) { +// return ElevatedButton( +// style: ElevatedButton.styleFrom( +// fixedSize: Size(size.width, 45), +// backgroundColor: Colors.black, +// foregroundColor: Colors.white, +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(10), +// ), +// ), +// onPressed: () { +// if (state is! UserRegisterLoadingState) { +// if (widget.isUpdateProfile == 'true') { +// BlocProvider.of(context) +// .add(const FormSubmitUpdateEvent()); +// } else { +// BlocProvider.of(context) +// .add(const FormSubmitEvent()); +// } +// } +// }, +// child: Text( +// widget.isUpdateProfile == 'true' +// ? 'Perbarui' +// : 'Daftar', +// style: +// const TextStyle(fontWeight: FontWeight.w600), +// ), +// ); +// }, +// ), +// ], +// ), +// ), +// ), +// ); +// }, +// ), +// ), +// ); +// } +// } diff --git a/app/lib/services/router_service.dart b/app/lib/services/router_service.dart index 28fa1fa..c58a41b 100644 --- a/app/lib/services/router_service.dart +++ b/app/lib/services/router_service.dart @@ -6,6 +6,9 @@ import '../features/authentication/signin/presentation/pages/_pages.dart'; import '../features/authentication/signin/presentation/pages/v2/_pages.dart'; import '../features/error/presentation/pages/_pages.dart'; import '../features/main/presentation/pages/_pages.dart'; +import '../features/main/presentation/pages/v2/_pages.dart'; +import '../features/main/presentation/pages/v2/delete_page.dart'; +import '../features/main/presentation/pages/v2/policy_page.dart'; import '../features/material/menu/presentation/pages/_pages.dart'; import '../features/material/viewer/presentation/pages/_pages.dart'; import '../features/onboarding/presentation/pages/_pages.dart'; @@ -17,7 +20,6 @@ import '../features/quiz_result/presentation/pages/_pages.dart'; import '../features/quiz_start/presentation/pages/_pages.dart'; import '../features/task_detail/presentation/pages/_pages.dart'; import '../features/task_list/presentation/pages/_pages.dart'; -import '../features/main/presentation/pages/v2/_pages.dart'; GoRouter router = GoRouter( routes: [ @@ -54,9 +56,9 @@ GoRouter router = GoRouter( isUpdateProfile: state.queryParameters['isUpdateProfile'], ); } else if (dotenv.env['APP_VERSION'] == 'V2') { - return RegisterPageV2( - isUpdateProfile: state.queryParameters['isUpdateProfile'], - ); + // return RegisterPageV2( + // isUpdateProfile: state.queryParameters['isUpdateProfile'], + // ); } return RegisterPage( isUpdateProfile: state.queryParameters['isUpdateProfile'], @@ -221,5 +223,27 @@ GoRouter router = GoRouter( id: state.queryParameters['id'], ); }), + GoRoute( + path: '/policy', + builder: (context, state) { + if (dotenv.env['APP_VERSION'] == 'V1') { + return const PrivacyPolicyPage(); + } else if (dotenv.env['APP_VERSION'] == 'V2') { + // return const V2SettingPage(); + } + return const PrivacyPolicyPage(); + }, + ), + GoRoute( + path: '/delete', + builder: (context, state) { + if (dotenv.env['APP_VERSION'] == 'V1') { + return const DeleteAccountPage(); + } else if (dotenv.env['APP_VERSION'] == 'V2') { + // return const V2SettingPage(); + } + return const DeleteAccountPage(); + }, + ), ], );