1262 lines
49 KiB
Dart
1262 lines
49 KiB
Dart
// ignore_for_file: avoid_print, use_build_context_synchronously, unused_local_variable, deprecated_member_use
|
||
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_animate/flutter_animate.dart';
|
||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
import 'package:flutter_svg/flutter_svg.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:hoshan/core/gen/assets.gen.dart';
|
||
import 'package:hoshan/core/routes/route_generator.dart';
|
||
import 'package:hoshan/data/model/empty_states_enum.dart';
|
||
import 'package:hoshan/data/repository/auth_repository.dart';
|
||
import 'package:hoshan/ui/theme/colors.dart';
|
||
import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart';
|
||
import 'package:hoshan/ui/theme/responsive.dart';
|
||
import 'package:hoshan/ui/theme/text.dart';
|
||
import 'package:hoshan/ui/widgets/components/button/circle_icon_btn.dart';
|
||
import 'package:hoshan/ui/widgets/components/snackbar/snackbar_manager.dart';
|
||
import 'package:hoshan/ui/widgets/sections/empty/empty_states.dart';
|
||
import 'package:hoshan/ui/widgets/sections/header/primary_appbar.dart';
|
||
|
||
class AddFamily extends StatefulWidget {
|
||
const AddFamily({super.key});
|
||
|
||
@override
|
||
State<AddFamily> createState() => _AddFamilyState();
|
||
}
|
||
|
||
class _AddFamilyState extends State<AddFamily> {
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_fetchFamilyMembers();
|
||
}
|
||
|
||
bool _showInviteForm = false;
|
||
|
||
int? _selectedAgeIndex;
|
||
|
||
final TextEditingController _phoneController = TextEditingController();
|
||
|
||
final List<Map<String, dynamic>> _invitedMembers = [];
|
||
|
||
static const int _maxMembers = 5;
|
||
|
||
@override
|
||
void dispose() {
|
||
_phoneController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final theme = Theme.of(context);
|
||
final colorScheme = theme.colorScheme;
|
||
final isDark = theme.brightness == Brightness.dark;
|
||
final backgroundColor = colorScheme.background;
|
||
final surfaceColor = colorScheme.surface;
|
||
final onSurface = colorScheme.onSurface;
|
||
final borderColor = const Color.fromARGB(255, 207, 206, 205);
|
||
final accent = colorScheme.primary;
|
||
final success = colorScheme.secondary;
|
||
|
||
final int invitedMembersCount = _invitedMembers.length;
|
||
|
||
return Scaffold(
|
||
appBar: PrimaryAppbar(
|
||
context,
|
||
onBack: () => context.pop(),
|
||
actions: [
|
||
Center(
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: GestureDetector(
|
||
onTap: () => context.go(Routes.myAccount),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.end,
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
CircleIconBtn(
|
||
size: Responsive(context).isMobile() ? 32 : 46,
|
||
iconPadding: Responsive(context).isMobile()
|
||
? null
|
||
: const EdgeInsets.all(8),
|
||
icon: Assets.icon.outline.coin,
|
||
color: context.read<ThemeModeCubit>().isDark()
|
||
? AppColors.black[900]
|
||
: AppColors.secondryColor[50],
|
||
iconColor: Theme.of(context).colorScheme.secondary,
|
||
)
|
||
.animate(
|
||
autoPlay: true,
|
||
onPlay: (controller) =>
|
||
controller.repeat(reverse: true),
|
||
)
|
||
.moveY(
|
||
begin: 0,
|
||
end: -15,
|
||
duration: 800.ms,
|
||
curve: Curves.easeInBack,
|
||
delay: 30.seconds,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
body: Directionality(
|
||
textDirection: TextDirection.rtl,
|
||
child: SingleChildScrollView(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
_buildTopInfoCard(
|
||
context,
|
||
title: 'امکانات نامحدود',
|
||
icon: 'assets/icon/outline/ion_infinite.svg',
|
||
),
|
||
const SizedBox(width: 8),
|
||
_buildTopInfoCard(
|
||
context,
|
||
title: '5 عضو خانواده',
|
||
icon: 'assets/icon/outline/carbon_pedestrian-family.svg',
|
||
),
|
||
const SizedBox(width: 8),
|
||
_buildTopInfoCard(
|
||
context,
|
||
title: 'سکه باسا',
|
||
icon: 'assets/icon/outline/streamline_coins-stack.svg',
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 24),
|
||
Container(
|
||
padding: const EdgeInsets.all(12),
|
||
decoration: BoxDecoration(
|
||
color: isDark
|
||
? surfaceColor
|
||
: const Color.fromARGB(255, 233, 232, 231),
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: Text(
|
||
'در صورت اتمام شارژ، میتوانید با پرداخت هزینه مجددا سکه دریافت کنید یا تا تمدید بعدی اعتبار باساکارت منتظر بمانید.',
|
||
style: AppTextStyles.body5.copyWith(color: onSurface),
|
||
textAlign: TextAlign.justify,
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
Container(
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: surfaceColor,
|
||
border: Border.all(color: borderColor),
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
Column(
|
||
children: [
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
'مدیریت خانواده',
|
||
style: AppTextStyles.body3.copyWith(
|
||
color: accent,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
RichText(
|
||
text: TextSpan(
|
||
style: AppTextStyles.body3
|
||
.copyWith(fontFamily: 'Dana'),
|
||
children: [
|
||
TextSpan(
|
||
text: '$invitedMembersCount',
|
||
style: TextStyle(
|
||
color: accent,
|
||
fontWeight: FontWeight.bold,
|
||
fontSize: 25,
|
||
),
|
||
),
|
||
TextSpan(
|
||
text: '/$_maxMembers',
|
||
style: TextStyle(
|
||
color:
|
||
Color.fromARGB(255, 173, 173, 173),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 4),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Text(
|
||
'دعوت و مدیریت اعضای خانواده',
|
||
style: AppTextStyles.body6.copyWith(
|
||
color: Color.fromARGB(255, 173, 173, 173),
|
||
fontWeight: FontWeight.bold),
|
||
),
|
||
Text(
|
||
'اعضای خانواده',
|
||
style: AppTextStyles.body6.copyWith(
|
||
color: Color.fromARGB(255, 173, 173, 173),
|
||
fontWeight: FontWeight.bold),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 20),
|
||
ClipRRect(
|
||
borderRadius: BorderRadius.circular(4),
|
||
child: Directionality(
|
||
textDirection: TextDirection.ltr,
|
||
child: TweenAnimationBuilder<double>(
|
||
duration: const Duration(milliseconds: 1250),
|
||
curve: Curves.easeOutQuart,
|
||
tween: Tween<double>(
|
||
begin: 0,
|
||
end: invitedMembersCount / _maxMembers,
|
||
),
|
||
builder: (context, value, _) {
|
||
return LinearProgressIndicator(
|
||
value: value,
|
||
minHeight: 6,
|
||
backgroundColor: onSurface.withOpacity(0.1),
|
||
valueColor: AlwaysStoppedAnimation<Color>(
|
||
Color.fromARGB(255, 34, 197, 94)),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Column(
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
children: [
|
||
Align(
|
||
alignment: Alignment.centerRight,
|
||
child: Text(
|
||
'${_maxMembers - invitedMembersCount} جایگاه خالی',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: accent,
|
||
fontWeight: FontWeight.normal,
|
||
),
|
||
),
|
||
),
|
||
if (invitedMembersCount < _maxMembers) ...[
|
||
const SizedBox(height: 12),
|
||
ElevatedButton(
|
||
onPressed: () {
|
||
setState(() {
|
||
_showInviteForm = !_showInviteForm;
|
||
});
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: isDark
|
||
? success.withOpacity(0.15)
|
||
: const Color.fromARGB(255, 187, 247, 208),
|
||
foregroundColor: onSurface,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: 16, vertical: 8),
|
||
elevation: 0,
|
||
),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Icon(
|
||
_showInviteForm
|
||
? CupertinoIcons.minus
|
||
: CupertinoIcons.add,
|
||
size: 18,
|
||
),
|
||
const SizedBox(width: 4),
|
||
Text(
|
||
_showInviteForm
|
||
? 'بستن فرم'
|
||
: 'افزودن عضو جدید',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: onSurface,
|
||
fontWeight: FontWeight.bold),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
AnimatedSize(
|
||
duration: const Duration(milliseconds: 300),
|
||
curve: Curves.easeInOut,
|
||
child: _showInviteForm
|
||
? Padding(
|
||
padding: const EdgeInsets.only(top: 24),
|
||
child: _buildInviteCard(
|
||
invitedMembersCount + 1),
|
||
)
|
||
: const SizedBox.shrink(),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
if (_invitedMembers.isEmpty)
|
||
EmptyStates.getEmptyState(
|
||
status: EmptyStatesEnum.familyMembers,
|
||
title: 'هنوز عضوی اضافه نشده است.',
|
||
)
|
||
else
|
||
_buildInvitedMembersList(),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildInvitedMembersList() {
|
||
return Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.only(bottom: 12, top: 20),
|
||
child: Text(
|
||
'افراد دعوت شده',
|
||
style: AppTextStyles.body4.copyWith(
|
||
fontWeight: FontWeight.bold,
|
||
color: Theme.of(context).colorScheme.onSurface,
|
||
),
|
||
),
|
||
),
|
||
SizedBox(height: 10),
|
||
ListView.separated(
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
itemCount: _invitedMembers.length,
|
||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||
itemBuilder: (context, index) {
|
||
final member = _invitedMembers[index];
|
||
return _buildInvitedMemberCard(member, index);
|
||
},
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
Widget _buildInvitedMemberCard(Map<String, dynamic> member, int index) {
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
final onSurface = colorScheme.onSurface;
|
||
final surface = colorScheme.surface;
|
||
final outline = colorScheme.outlineVariant;
|
||
final warning = colorScheme.error;
|
||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||
|
||
return Container(
|
||
padding: const EdgeInsets.all(12),
|
||
decoration: BoxDecoration(
|
||
color: isDark
|
||
? Color.fromARGB(255, 80, 80, 80)
|
||
: Color.fromARGB(255, 252, 252, 252),
|
||
borderRadius: BorderRadius.circular(20),
|
||
border: Border.all(color: Color.fromARGB(255, 207, 206, 205)),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.03),
|
||
blurRadius: 8,
|
||
offset: const Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: Column(
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Container(
|
||
width: 48,
|
||
height: 48,
|
||
decoration: BoxDecoration(
|
||
color: AppColors.primaryColor[50],
|
||
shape: BoxShape.circle,
|
||
),
|
||
child: Icon(
|
||
CupertinoIcons.person_solid,
|
||
color: AppColors.primaryColor[500],
|
||
size: 28,
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
member['phone'] ?? '',
|
||
style: AppTextStyles.body4.copyWith(
|
||
fontWeight: FontWeight.normal,
|
||
fontFamily: 'Dana',
|
||
color: onSurface,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
member['time'],
|
||
style: AppTextStyles.body6.copyWith(
|
||
color: onSurface.withOpacity(0.6),
|
||
fontSize: 11,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.end,
|
||
children: [
|
||
// InkWell(
|
||
// onTap: () {
|
||
// _showEditDialog(index);
|
||
// },
|
||
// child:
|
||
// // Row(
|
||
// // children: [
|
||
// // Text(
|
||
// // 'ویرایش',
|
||
// // style: AppTextStyles.body6.copyWith(
|
||
// // color: AppColors.primaryColor[500],
|
||
// // ),
|
||
// // ),
|
||
// // const SizedBox(width: 4),
|
||
// // SvgPicture.asset(
|
||
// // 'assets/icon/outline/edit.svg',
|
||
// // ),
|
||
// // ],
|
||
// // ),
|
||
// ),
|
||
const SizedBox(width: 16),
|
||
InkWell(
|
||
onTap: () {
|
||
_showDeleteDialog(index);
|
||
},
|
||
child: SvgPicture.asset(
|
||
'assets/icon/outline/trash.svg',
|
||
color: warning,
|
||
height: 25,
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
// Container(
|
||
// padding:
|
||
// const EdgeInsets.symmetric(horizontal: 15, vertical: 9),
|
||
// decoration: BoxDecoration(
|
||
// color: Color.fromARGB(255, 224, 236, 255),
|
||
// borderRadius: BorderRadius.circular(6),
|
||
// ),
|
||
// child: Text(
|
||
// 'در انتظار تایید',
|
||
// style: AppTextStyles.body6.copyWith(
|
||
// color: colorScheme.primary,
|
||
// fontWeight: FontWeight.bold,
|
||
// fontSize: 10,
|
||
// ),
|
||
// ),
|
||
// ),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
void _showEditDialog(int index) {
|
||
final member = _invitedMembers[index];
|
||
final TextEditingController editPhoneController =
|
||
TextEditingController(text: member['phone']);
|
||
int? editAgeIndex = member['ageIndex'];
|
||
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) {
|
||
return StatefulBuilder(
|
||
builder: (context, setDialogState) {
|
||
return Dialog(
|
||
backgroundColor: Colors.transparent,
|
||
insetPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: const Color.fromARGB(255, 246, 246, 246),
|
||
borderRadius: BorderRadius.circular(16),
|
||
border: Border.all(color: AppColors.gray[300]),
|
||
),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Container(
|
||
width: double.infinity,
|
||
padding: const EdgeInsets.symmetric(
|
||
vertical: 12, horizontal: 16),
|
||
decoration: const BoxDecoration(
|
||
color: Color.fromARGB(255, 224, 236, 255),
|
||
borderRadius:
|
||
BorderRadius.vertical(top: Radius.circular(16)),
|
||
),
|
||
child: Directionality(
|
||
textDirection: TextDirection.rtl,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Text(
|
||
'ویرایش عضو ${_getOrdinal(index + 1)}',
|
||
textAlign: TextAlign.right,
|
||
style: AppTextStyles.body4.copyWith(
|
||
color: Colors.black,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
InkWell(
|
||
onTap: () => Navigator.pop(context),
|
||
child: const Icon(CupertinoIcons.clear, size: 20),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
Container(
|
||
height: 2,
|
||
color: const Color.fromARGB(255, 30, 29, 27),
|
||
),
|
||
Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Directionality(
|
||
textDirection: TextDirection.rtl,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'شماره همراه',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: AppColors.primaryColor[500],
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
TextFormField(
|
||
controller: editPhoneController,
|
||
keyboardType: TextInputType.phone,
|
||
textDirection: TextDirection.ltr,
|
||
decoration: InputDecoration(
|
||
suffixIcon: Icon(
|
||
CupertinoIcons.phone,
|
||
color: Theme.of(context).colorScheme.primary,
|
||
),
|
||
contentPadding: const EdgeInsets.symmetric(
|
||
horizontal: 16, vertical: 12),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
borderSide:
|
||
BorderSide(color: AppColors.gray[300]),
|
||
),
|
||
enabledBorder: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
borderSide:
|
||
BorderSide(color: AppColors.gray[300]),
|
||
),
|
||
focusedBorder: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
borderSide: BorderSide(
|
||
color: AppColors.primaryColor[500]),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Text(
|
||
'رده سنی',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: AppColors.primaryColor[500],
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: _buildDialogAgeOption(
|
||
title: 'زیر ۱۸ سال',
|
||
index: 0,
|
||
groupValue: editAgeIndex,
|
||
onChanged: (val) => setDialogState(
|
||
() => editAgeIndex = val),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: _buildDialogAgeOption(
|
||
title: '۱۸ تا ۳۰ سال',
|
||
index: 1,
|
||
groupValue: editAgeIndex,
|
||
onChanged: (val) => setDialogState(
|
||
() => editAgeIndex = val),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: _buildDialogAgeOption(
|
||
title: 'بالای ۳۰ سال',
|
||
index: 2,
|
||
groupValue: editAgeIndex,
|
||
onChanged: (val) => setDialogState(
|
||
() => editAgeIndex = val),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 24),
|
||
SizedBox(
|
||
width: double.infinity,
|
||
child: ElevatedButton(
|
||
onPressed: () {
|
||
if (editPhoneController.text.isNotEmpty) {
|
||
setState(() {
|
||
_invitedMembers[index] = {
|
||
'phone': editPhoneController.text,
|
||
'ageIndex': editAgeIndex,
|
||
'time': member['time'],
|
||
};
|
||
});
|
||
Navigator.pop(context);
|
||
SnackBarManager(context).show(
|
||
message: 'اطلاعات با موفقیت ویرایش شد',
|
||
status: SnackBarStatus.success,
|
||
isTop: true,
|
||
);
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor:
|
||
const Color.fromARGB(255, 34, 82, 160),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(20),
|
||
),
|
||
padding:
|
||
const EdgeInsets.symmetric(vertical: 12),
|
||
),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
'ثبت تغییرات',
|
||
style: AppTextStyles.body4.copyWith(
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
SvgPicture.asset(
|
||
'assets/icon/outline/edit.svg',
|
||
color: Colors.white)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
void _showDeleteDialog(int index) {
|
||
final member = _invitedMembers[index];
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) {
|
||
return Dialog(
|
||
backgroundColor: Colors.white,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: Directionality(
|
||
textDirection: TextDirection.rtl,
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.end,
|
||
children: [
|
||
InkWell(
|
||
onTap: () => Navigator.pop(context),
|
||
child: SvgPicture.asset(
|
||
'assets/icon/outline/close-circle.svg')),
|
||
],
|
||
),
|
||
SvgPicture.asset(
|
||
'assets/icon/outline/trashPopup.svg',
|
||
width: 55,
|
||
height: 55,
|
||
),
|
||
const SizedBox(height: 16),
|
||
Text(
|
||
'کاربر حذف شود؟',
|
||
style: AppTextStyles.body3.copyWith(
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.black,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'شماره همراه: ${member['phone']}',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: AppColors.black[700],
|
||
fontFamily: 'Dana',
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: ElevatedButton(
|
||
onPressed: () => Navigator.pop(context),
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Color.fromARGB(255, 190, 18, 60),
|
||
foregroundColor: Colors.white,
|
||
elevation: 0,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(100),
|
||
),
|
||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
),
|
||
child: const Text(
|
||
'خیر',
|
||
style: TextStyle(
|
||
fontFamily: 'Dana',
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
Expanded(
|
||
child: ElevatedButton(
|
||
onPressed: () async {
|
||
final dynamic rawId = member['id'];
|
||
print(
|
||
'Debug - Delete: rawId = $rawId (${rawId.runtimeType})');
|
||
print('Debug - Delete: member = $member');
|
||
|
||
String? id;
|
||
|
||
if (rawId is String) {
|
||
id = rawId;
|
||
} else if (rawId is int) {
|
||
id = rawId.toString();
|
||
}
|
||
|
||
if (id == null || id.isEmpty) {
|
||
Navigator.pop(context);
|
||
SnackBarManager(context).show(
|
||
message:
|
||
'شناسه کاربر نامعتبر است: rawId=$rawId (type: ${rawId.runtimeType})',
|
||
status: SnackBarStatus.error,
|
||
isTop: true,
|
||
);
|
||
return;
|
||
}
|
||
|
||
print('Debug - Delete: parsed id = $id');
|
||
|
||
try {
|
||
print('Debug - Deleting user with id: $id');
|
||
final isDeleted =
|
||
await AuthRepository.deleteSubUser(id);
|
||
|
||
if (!mounted) return;
|
||
|
||
if (isDeleted) {
|
||
setState(() {
|
||
_invitedMembers.removeAt(index);
|
||
});
|
||
Navigator.pop(context);
|
||
SnackBarManager(context).show(
|
||
message: 'کاربر با موفقیت حذف شد',
|
||
status: SnackBarStatus.success,
|
||
isTop: true,
|
||
);
|
||
} else {
|
||
Navigator.pop(context);
|
||
SnackBarManager(context).show(
|
||
message: 'خطا در حذف کاربر',
|
||
status: SnackBarStatus.error,
|
||
isTop: true,
|
||
);
|
||
}
|
||
} catch (e) {
|
||
print('Debug - Delete error: $e');
|
||
if (!mounted) return;
|
||
Navigator.pop(context);
|
||
SnackBarManager(context).show(
|
||
message: 'خطا در حذف کاربر: $e',
|
||
status: SnackBarStatus.error,
|
||
isTop: true,
|
||
);
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.grey[200],
|
||
foregroundColor: Colors.black,
|
||
elevation: 0,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(100),
|
||
side: const BorderSide(
|
||
color: Color.fromARGB(255, 190, 18, 60),
|
||
),
|
||
),
|
||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
),
|
||
child: const Text(
|
||
'بله',
|
||
style: TextStyle(
|
||
fontFamily: 'Dana',
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
Widget _buildDialogAgeOption({
|
||
required String title,
|
||
required int index,
|
||
required int? groupValue,
|
||
required ValueChanged<int> onChanged,
|
||
}) {
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
final isSelected = groupValue == index;
|
||
return InkWell(
|
||
onTap: () => onChanged(index),
|
||
borderRadius: BorderRadius.circular(8),
|
||
child: Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
decoration: BoxDecoration(
|
||
color: isSelected
|
||
? colorScheme.primaryContainer.withOpacity(0.35)
|
||
: colorScheme.surfaceVariant,
|
||
borderRadius: BorderRadius.circular(30),
|
||
),
|
||
child: Text(
|
||
title,
|
||
textAlign: TextAlign.center,
|
||
style: AppTextStyles.body6.copyWith(
|
||
color: isSelected
|
||
? colorScheme.onPrimaryContainer
|
||
: colorScheme.onSurface.withOpacity(0.7),
|
||
fontWeight: FontWeight.bold,
|
||
fontSize: 11,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
String _getOrdinal(int number) {
|
||
switch (number) {
|
||
case 1:
|
||
return 'اول';
|
||
case 2:
|
||
return 'دوم';
|
||
case 3:
|
||
return 'سوم';
|
||
case 4:
|
||
return 'چهارم';
|
||
case 5:
|
||
return 'پنجم';
|
||
default:
|
||
return '$numberام';
|
||
}
|
||
}
|
||
|
||
Widget _buildInviteCard(int memberNumber) {
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
return Container(
|
||
decoration: BoxDecoration(
|
||
color: Color.fromARGB(255, 246, 246, 246),
|
||
borderRadius: BorderRadius.circular(16),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.05),
|
||
blurRadius: 10,
|
||
offset: const Offset(0, 4),
|
||
)
|
||
],
|
||
),
|
||
child: Column(
|
||
children: [
|
||
Container(
|
||
width: double.infinity,
|
||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||
decoration: BoxDecoration(
|
||
color: Color.fromARGB(255, 224, 236, 255),
|
||
borderRadius:
|
||
const BorderRadius.vertical(top: Radius.circular(16)),
|
||
),
|
||
child: Text(
|
||
'دعوت از عضو ${_getOrdinal(memberNumber)}',
|
||
textAlign: TextAlign.right,
|
||
style: AppTextStyles.body4.copyWith(
|
||
color: Colors.black,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
),
|
||
Container(
|
||
height: 2,
|
||
color: colorScheme.outline,
|
||
),
|
||
Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'شماره همراه',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: colorScheme.primary,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
TextFormField(
|
||
controller: _phoneController,
|
||
keyboardType: TextInputType.phone,
|
||
textDirection: TextDirection.ltr,
|
||
decoration: InputDecoration(
|
||
suffixIcon: Icon(
|
||
CupertinoIcons.phone,
|
||
color: Theme.of(context).colorScheme.primary,
|
||
),
|
||
contentPadding: const EdgeInsets.symmetric(
|
||
horizontal: 16, vertical: 12),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
borderSide:
|
||
BorderSide(color: Color.fromARGB(255, 161, 160, 160)),
|
||
),
|
||
enabledBorder: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
borderSide: BorderSide(color: colorScheme.outlineVariant),
|
||
),
|
||
focusedBorder: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
borderSide: BorderSide(color: colorScheme.primary),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 20),
|
||
Text(
|
||
'رده سنی',
|
||
style: AppTextStyles.body5.copyWith(
|
||
color: colorScheme.primary,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: _buildAgeOption(
|
||
title: 'زیر ۱۸ سال',
|
||
index: 0,
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: _buildAgeOption(
|
||
title: '۱۸ تا ۳۰ سال',
|
||
index: 1,
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: _buildAgeOption(
|
||
title: 'بالای ۳۰ سال',
|
||
index: 2,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 24),
|
||
SizedBox(
|
||
width: double.infinity,
|
||
child: ElevatedButton(
|
||
onPressed: () async {
|
||
final phone = _phoneController.text;
|
||
|
||
if (phone.isEmpty) {
|
||
SnackBarManager(context).show(
|
||
message: 'لطفا شماره همراه را وارد کنید',
|
||
status: SnackBarStatus.error,
|
||
isTop: true,
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (_selectedAgeIndex == null) {
|
||
SnackBarManager(context).show(
|
||
message: 'لطفا رده سنی را انتخاب کنید',
|
||
status: SnackBarStatus.error,
|
||
isTop: true,
|
||
);
|
||
return;
|
||
}
|
||
|
||
int level;
|
||
switch (_selectedAgeIndex) {
|
||
case 0:
|
||
level = 3;
|
||
break;
|
||
case 1:
|
||
level = 2;
|
||
break;
|
||
case 2:
|
||
level = 1;
|
||
break;
|
||
default:
|
||
level = 3;
|
||
}
|
||
|
||
try {
|
||
final isSuccess =
|
||
await AuthRepository.addSubUser(phone, level);
|
||
|
||
if (isSuccess) {
|
||
if (!context.mounted) return;
|
||
|
||
SnackBarManager(context).show(
|
||
message: 'دعوتنامه برای $phone با موفقیت ارسال شد',
|
||
status: SnackBarStatus.success,
|
||
isTop: true,
|
||
);
|
||
|
||
setState(() {
|
||
_showInviteForm = false;
|
||
_phoneController.clear();
|
||
_selectedAgeIndex = null;
|
||
});
|
||
await _fetchFamilyMembers();
|
||
}
|
||
} catch (e) {
|
||
if (!context.mounted) return;
|
||
SnackBarManager(context).show(
|
||
message:
|
||
'خطا در ارسال دعوتنامه. لطفا مجدد تلاش کنید.',
|
||
status: SnackBarStatus.error,
|
||
isTop: true,
|
||
);
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: colorScheme.primary,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(20),
|
||
),
|
||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
'ارسال دعوتنامه',
|
||
style: AppTextStyles.body4.copyWith(
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
SvgPicture.asset('assets/icon/outline/send.svg')
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildAgeOption({required String title, required int index}) {
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
final isSelected = _selectedAgeIndex == index;
|
||
return InkWell(
|
||
onTap: () {
|
||
setState(() {
|
||
_selectedAgeIndex = index;
|
||
});
|
||
},
|
||
borderRadius: BorderRadius.circular(8),
|
||
child: Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||
decoration: BoxDecoration(
|
||
color: isSelected
|
||
? Color.fromARGB(255, 224, 236, 255)
|
||
: Color.fromARGB(255, 233, 232, 231),
|
||
borderRadius: BorderRadius.circular(30),
|
||
),
|
||
child: Text(
|
||
title,
|
||
textAlign: TextAlign.center,
|
||
style: AppTextStyles.body6.copyWith(
|
||
color: isSelected
|
||
? Colors.black
|
||
: colorScheme.onSurface.withOpacity(0.7),
|
||
fontWeight: FontWeight.bold,
|
||
fontSize: 11,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildTopInfoCard(BuildContext context,
|
||
{required String title, required String icon}) {
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
return Column(
|
||
children: [
|
||
Container(
|
||
height: 64,
|
||
width: 64,
|
||
padding: const EdgeInsets.all(5),
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(16),
|
||
color: Color.fromARGB(255, 248, 231, 241),
|
||
),
|
||
child: Center(
|
||
child: SvgPicture.asset(
|
||
icon,
|
||
width: 32,
|
||
height: 32,
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
title,
|
||
style: AppTextStyles.body6.copyWith(
|
||
fontSize: 11,
|
||
fontWeight: FontWeight.bold,
|
||
color: colorScheme.onSurface,
|
||
),
|
||
textAlign: TextAlign.center,
|
||
maxLines: 2,
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
Future<void> _fetchFamilyMembers() async {
|
||
try {
|
||
final subUsers = await AuthRepository.getSubUsers();
|
||
|
||
setState(() {
|
||
_invitedMembers.clear();
|
||
for (var user in subUsers) {
|
||
print('Debug - User data: $user');
|
||
print('Debug - User ID: ${user['id']} (${user['id'].runtimeType})');
|
||
|
||
_invitedMembers.add({
|
||
'id': user['id'],
|
||
'phone': user['mobile_number'],
|
||
'ageIndex': _getAgeIndexFromLevel(user['level']),
|
||
'time': _formatDate(user['created_at']),
|
||
});
|
||
}
|
||
});
|
||
print('Debug - Total members loaded: ${_invitedMembers.length}');
|
||
} catch (e) {
|
||
print('Debug - Error fetching family members: $e');
|
||
if (mounted) {
|
||
SnackBarManager(context).show(
|
||
message: 'خطا در دریافت اطلاعات خانواده: $e',
|
||
status: SnackBarStatus.error,
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
int _getAgeIndexFromLevel(int level) {
|
||
switch (level) {
|
||
case 3:
|
||
return 0;
|
||
case 2:
|
||
return 1;
|
||
case 1:
|
||
return 2;
|
||
default:
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
String _formatDate(String? isoDate) {
|
||
if (isoDate == null) return '';
|
||
try {
|
||
DateTime date = DateTime.parse(isoDate);
|
||
DateTime now = DateTime.now();
|
||
Duration difference = now.difference(date);
|
||
|
||
if (difference.inSeconds < 60) {
|
||
return 'دعوت شده در ${difference.inSeconds} ثانیه قبل';
|
||
} else if (difference.inMinutes < 60) {
|
||
return 'دعوت شده در ${difference.inMinutes} دقیقه قبل';
|
||
} else if (difference.inHours < 24) {
|
||
return 'دعوت شده در ${difference.inHours} ساعت قبل';
|
||
} else if (difference.inDays < 30) {
|
||
return 'دعوت شده در ${difference.inDays} روز قبل';
|
||
} else if (difference.inDays < 365) {
|
||
int months = (difference.inDays / 30).floor();
|
||
return 'دعوت شده در $months ماه قبل';
|
||
} else {
|
||
int years = (difference.inDays / 365).floor();
|
||
return 'دعوت شده در $years سال قبل';
|
||
}
|
||
} catch (e) {
|
||
return isoDate;
|
||
}
|
||
}
|
||
}
|