Houshan-Basa/lib/ui/screens/family/add_family.dart

1262 lines
49 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}
}
}