import 'dart:io'; import 'package:business_panel/core/config/app_colors.dart'; import 'package:business_panel/domain/entities/category_entity.dart'; import 'package:business_panel/gen/assets.gen.dart'; import 'package:business_panel/presentation/pages/store_info_display_page.dart'; import 'package:business_panel/presentation/pages/working_hours_dialog.dart'; import 'package:business_panel/presentation/store_info/bloc/store_info_bloc.dart'; import 'package:business_panel/presentation/store_info/bloc/store_info_state.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:image_picker/image_picker.dart'; import 'package:business_panel/presentation/pages/osm_map_picker_page.dart'; import 'package:latlong2/latlong.dart'; class StoreInfoPage extends StatefulWidget { const StoreInfoPage({super.key}); @override State createState() => _StoreInfoPageState(); } class _StoreInfoPageState extends State { final _nameController = TextEditingController(); final _provinceController = TextEditingController(); final _cityController = TextEditingController(); final _addressController = TextEditingController(); final _plaqueController = TextEditingController(); final _postalCodeController = TextEditingController(); final _phoneController = TextEditingController(); final _licenseController = TextEditingController(); @override void initState() { super.initState(); final bloc = context.read(); _nameController.text = bloc.state.storeName; _provinceController.text = bloc.state.province; _cityController.text = bloc.state.city; _addressController.text = bloc.state.address; _plaqueController.text = bloc.state.plaque; _postalCodeController.text = bloc.state.postalCode; _phoneController.text = bloc.state.contactPhone ?? ''; _licenseController.text = bloc.state.licenseNumber ?? ''; } @override void dispose() { _nameController.dispose(); _provinceController.dispose(); _cityController.dispose(); _addressController.dispose(); _plaqueController.dispose(); _postalCodeController.dispose(); _phoneController.dispose(); _licenseController.dispose(); super.dispose(); } Future _pickImage(BuildContext context) async { try { final ImagePicker picker = ImagePicker(); final XFile? image = await picker.pickImage( source: ImageSource.gallery, imageQuality: 80, ); if (image != null && context.mounted) { context.read().add(StoreLogoChanged(image.path)); } } on PlatformException catch (e) { print("خطای دسترسی یا پلتفرم: ${e.message}"); } catch (e) { print("یک خطای ناشناخته رخ داد: $e"); } } Future _showWorkingHoursDialog(BuildContext context) async { final result = await showDialog>( context: context, builder: (context) => const WorkingHoursDialog(), ); if (result != null && context.mounted) { context.read().add( WorkingScheduleChanged( days: result['days'] as List, startTime: result['startTime'] as String, endTime: result['endTime'] as String, ), ); } } final List activityTypes = [ CategoryEntity(id: "6803b940-3e19-48cd-9190-28d9f25421ff", name: "فست فود", emoji: "🍔🍕"), CategoryEntity(id: "71e371f8-a47a-4a58-aee6-4ed0f26bf29b", name: "پوشاک", emoji: "👚👔"), CategoryEntity(id: "42acff41-1165-4e62-89b9-58db7329ec3a", name: "تریا", emoji: "🍨🍹"), CategoryEntity(id: "e33dd7f9-5b20-4273-8eea-59da6ca5f206", name: "لوازم دیجیتال", emoji: "📱📷"), CategoryEntity(id: "b5881239-bfd5-4c27-967a-187316a7e0b7", name: "رستوران", emoji: "🍣🍢"), CategoryEntity(id: "b73a868a-a2d2-4d96-8fd4-615327ed9629", name: "کافی شاپ", emoji: "☕🍰"), CategoryEntity(id: "2f38918c-5566-4aec-a0a9-2c7c48b1e878", name: "کیف و کفش", emoji: "👜👞"), CategoryEntity(id: "52c51010-3a63-4264-a350-e011c889f3dd", name: "سینما", emoji: "🎭🎟️"), CategoryEntity(id: "34185954-f79f-4b9e-8eb2-1702679c40a0", name: "لوازم آرایشی", emoji: "💄💅️"), CategoryEntity(id: "e4517b0c-aacf-4758-94bd-85f45062980f", name: "طلا و زیورآلات", emoji: "💍💎"), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: _buildCustomAppBar(context), body: BlocListener( listener: (context, state) { if (state.isSuccess) { Navigator.of(context).push( MaterialPageRoute( builder: (_) => BlocProvider.value( value: BlocProvider.of(context), child: const StoreInfoDisplayPage(), ), ), ); } if (state.errorMessage != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.errorMessage!), backgroundColor: Colors.red), ); } }, child: SingleChildScrollView( padding: const EdgeInsets.all(24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), const Row( children: [ Text( "لوگوی فروشگاه", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), ), SizedBox(width: 5), Text("(اختیاری)", style: TextStyle(color: Colors.black54)), ], ), const SizedBox(height: 24), Center( child: GestureDetector( onTap: () => _pickImage(context), child: CircleAvatar( radius: 65, backgroundColor: AppColors.uploadElevated, child: BlocBuilder( builder: (context, state) { return Container( decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: const Color.fromARGB( 255, 224, 224, 224, ).withOpacity(0.5), spreadRadius: 1, blurRadius: 40, offset: const Offset(0, 10), ), ], image: state.logoPath != null ? DecorationImage( image: FileImage(File(state.logoPath!)), fit: BoxFit.cover, ) : null, ), child: Stack( alignment: Alignment.center, children: [ Align( alignment: Alignment.bottomRight, child: CircleAvatar( radius: 22, backgroundColor: Colors.white, child: CircleAvatar( radius: 20, backgroundColor: Colors.white, child: SvgPicture.asset(Assets.icons.edit02), ), ), ), ], ), ); }, ), ), ), ), const SizedBox(height: 32), _buildSectionTitle(), const SizedBox(height: 30), _buildTextField( label: "نام فروشگاه", isRequired: true, hint: "مثلاً کافه ایرونی", controller: _nameController, onChanged: (value) => context.read().add( StoreNameChanged(value), ), ), const SizedBox(height: 30), _buildActivityTypeDropdown(context), const SizedBox(height: 30), Row( children: [ Expanded( child: _buildTextField( label: "استان", hint: "اصفهان", controller: _provinceController, onChanged: (value) => context.read().add( ProvinceChanged(value), ), ), ), const SizedBox(width: 16), Expanded( child: _buildTextField( controller: _cityController, label: "شهر", hint: "اصفهان", onChanged: (value) => context.read().add( CityChanged(value), ), ), ), ], ), const SizedBox(height: 30), _buildTextField( controller: _addressController, label: "جزئیات آدرس", maxLines: 3, hint: "خیابان، محله، ساختمان و ....", onChanged: (value) => context.read().add(AddressChanged(value)), ), const SizedBox(height: 30), _buildFeaturesSection(), const SizedBox(height: 50), Row( children: [ Expanded( child: _buildTextField( controller: _plaqueController, label: "پلاک", onChanged: (value) => context.read().add( PlaqueChanged(value), ), ), ), const SizedBox(width: 16), Expanded( child: _buildTextField( controller: _postalCodeController, label: "کد پستی", onChanged: (value) => context .read() .add(PostalCodeChanged(value)), ), ), ], ), const SizedBox(height: 30), Center( child: TextButton.icon( onPressed: () async { final result = await Navigator.of(context).push( MaterialPageRoute( builder: (context) => const OsmMapPickerPage(), ), ); if (result != null) { context.read().add( StoreLocationChanged( latitude: result.latitude, longitude: result.longitude, ), ); } }, icon: SvgPicture.asset( Assets.icons.map, color: AppColors.button, height: 23, ), label: const Text( "انتخاب آدرس فروشگاه روی نقشه", style: TextStyle(color: AppColors.button), ), ), ), Center( child: BlocBuilder( builder: (context, state) { if (state.latitude != null && state.longitude != null) { return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( "آدرس با موفقیت ثبت شد ✓", style: TextStyle( color: Colors.green.shade700, fontWeight: FontWeight.bold, ), ), ); } return const SizedBox.shrink(); }, ), ), const SizedBox(height: 30), _buildTextField( controller: _phoneController, label: "تلفن تماس", keyboardType: TextInputType.phone, hint: "شماره تماس ثابت یا موبایل فروشگاه", onChanged: (value) => context.read().add(ContactPhoneChanged(value)), ), const SizedBox(height: 30), _buildWorkingHoursPicker(context), const SizedBox(height: 30), _buildTextField( controller: _licenseController, label: "شماره جواز کسب", hint: "شناسه صنفی 12 رقمی یکتا", onChanged: (value) => context.read().add(LicenseNumberChanged(value)), ), const SizedBox(height: 44), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (_) => BlocProvider.value( value: BlocProvider.of(context), child: const StoreInfoDisplayPage(), ), ), ); }, child: const Text("تایید و ادامه"), ), ), const SizedBox(height: 34), ], ), ), )); } Widget _buildSectionTitle() { return const Text( "ثبت مشخصات", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ); } Widget _buildTextField({ required String label, bool isRequired = false, String? hint, int maxLines = 1, int? maxLength, TextInputType? keyboardType, TextEditingController? controller, ValueChanged? onChanged, }) { return TextFormField( controller: controller, onChanged: onChanged, maxLines: maxLines, maxLength: maxLength, keyboardType: keyboardType, decoration: InputDecoration( counterText: "", hintText: hint, hintStyle: const TextStyle(fontSize: 15, color: Colors.grey), label: RichText( text: TextSpan( text: label, style: const TextStyle( color: Colors.black, fontFamily: 'Dana', fontSize: 19, fontWeight: FontWeight.bold, ), children: [ if (isRequired) const TextSpan( text: ' *', style: TextStyle(color: Colors.red, fontSize: 16), ), ], ), ), ), ); } Widget _buildFeaturesSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "ویژگی‌های فروشگاه", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), const Text( "حداکثر ۳ ویژگی برای معرفی بهتر فروشگاه خود اضافه کنید.", style: TextStyle(color: Colors.grey, fontSize: 14), ), const SizedBox(height: 16), BlocBuilder( buildWhen: (previous, current) => previous.features != current.features, builder: (context, state) { return Column( children: [ ...state.features.asMap().entries.map((entry) { final index = entry.key; final controller = TextEditingController(text: entry.value) ..selection = TextSelection.fromPosition( TextPosition(offset: entry.value.length), ); return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: Row( children: [ Expanded( child: _buildTextField( controller: controller, label: "ویژگی ${index + 1}", hint: "مثلا: دارای ویوی شهر", maxLength: 60, onChanged: (value) { context .read() .add(StoreFeatureUpdated(index, value)); }, ), ), IconButton( icon: const Icon(Icons.remove_circle_outline, color: Colors.red), onPressed: () { context .read() .add(StoreFeatureRemoved(index)); }, ), ], ), ); }).toList(), if (state.features.length < 3) SizedBox( width: double.infinity, child: OutlinedButton.icon( icon: const Icon(Icons.add), label: const Text("افزودن ویژگی جدید"), onPressed: () { context.read().add(StoreFeatureAdded()); }, ), ), ], ); }, ), ], ); } Widget _buildWorkingHoursPicker(BuildContext context) { return InkWell( onTap: () => _showWorkingHoursDialog(context), child: InputDecorator( decoration: InputDecoration( label: RichText( text: const TextSpan( text: "ساعت کار فروشگاه", style: TextStyle( color: Colors.black, fontFamily: 'Dana', fontSize: 19, fontWeight: FontWeight.bold, ), children: [ TextSpan( text: ' *', style: TextStyle(color: Colors.red, fontSize: 16), ), ], ), ), contentPadding: const EdgeInsets.symmetric( vertical: 18, horizontal: 12, ), ), child: BlocBuilder( buildWhen: (p, c) => p.workingDays != c.workingDays, builder: (context, state) { final hasData = state.workingDays.isNotEmpty && state.startTime != null; const Map dayTranslations = { 'Saturday': 'شنبه', 'Sunday': 'یکشنبه', 'Monday': 'دوشنبه', 'Tuesday': 'سه‌شنبه', 'Wednesday': 'چهارشنبه', 'Thursday': 'پنج‌شنبه', 'Friday': 'جمعه', }; final displayDays = state.workingDays .map((day) => dayTranslations[day] ?? '') .join('، '); String displayText = hasData ? "$displayDays\nاز ساعت ${state.startTime} تا ${state.endTime}" : "انتخاب روز و ساعت کاری"; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( displayText, style: TextStyle( fontSize: 16, color: hasData ? Colors.black : Colors.grey.shade600, height: 1.5, ), textAlign: TextAlign.right, ), ), ], ); }, ), ), ); } Widget _buildActivityTypeDropdown(BuildContext context) { return Theme( data: Theme.of(context).copyWith(canvasColor: const Color(0xFFF6F6F6)), child: DropdownButtonFormField( value: context.watch().state.activityTypeId, icon: SvgPicture.asset( Assets.icons.arrowDown, width: 24, color: Colors.black, ), decoration: InputDecoration( label: RichText( text: const TextSpan( text: "نوع فعالیت", style: TextStyle( color: Colors.black, fontFamily: 'Dana', fontSize: 19, fontWeight: FontWeight.bold, ), children: [ TextSpan( text: ' *', style: TextStyle(color: Colors.red, fontSize: 16), ), ], ), ), ), borderRadius: BorderRadius.circular(12.0), isExpanded: true, items: activityTypes.map((CategoryEntity category) { return DropdownMenuItem( value: category.id, child: Text("${category.emoji} ${category.name}"), ); }).toList(), onChanged: (value) { if (value != null) { context.read().add(ActivityTypeChanged(value)); } }, ), ); } } PreferredSizeWidget _buildCustomAppBar(BuildContext context) { return PreferredSize( preferredSize: const Size.fromHeight(70.0), child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.vertical(bottom: Radius.circular(15)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.08), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10.0), child: Column( children: [ const SizedBox(height: 15), Row( children: [ Padding( padding: const EdgeInsets.only(right: 8), child: SvgPicture.asset(Assets.icons.logoWithName), ), const Spacer(), Row( children: [ IconButton( onPressed: () {}, icon: SvgPicture.asset( Assets.icons.discountShape, color: Colors.black, ), ), IconButton( onPressed: () {}, icon: SvgPicture.asset(Assets.icons.scanBarcode), ), ], ), ], ), ], ), ), ), ), ); } // Future _pickWorkingHours(BuildContext context) async { // // ۱. انتخاب تاریخ شروع // Jalali? startDate = await showPersianDatePicker( // context: context, // initialDate: Jalali.now(), // firstDate: Jalali(1400), // lastDate: Jalali(1405), // ); // if (startDate == null || !context.mounted) return; // // ۲. انتخاب ساعت شروع // TimeOfDay? startTime = await showTimePicker( // context: context, // initialTime: TimeOfDay.now(), // ); // if (startTime == null || !context.mounted) return; // // ۳. انتخاب تاریخ پایان // Jalali? endDate = await showPersianDatePicker( // context: context, // initialDate: startDate, // شروع از تاریخ انتخابی قبلی // firstDate: startDate, // تاریخ پایان نمی‌تواند قبل از شروع باشد // lastDate: Jalali(1405), // ); // if (endDate == null || !context.mounted) return; // // ۴. انتخاب ساعت پایان // TimeOfDay? endTime = await showTimePicker( // context: context, // initialTime: startTime, // ); // if (endTime == null || !context.mounted) return; // // ۵. تبدیل به آبجکت DateTime و ارسال به BLoC // final DateTime startDateTime = startDate.toDateTime().add( // Duration(hours: startTime.hour, minutes: startTime.minute), // ); // final DateTime endDateTime = endDate.toDateTime().add( // Duration(hours: endTime.hour, minutes: endTime.minute), // ); // context.read().add( // WorkingHoursChanged( // startDateTime: startDateTime, // endDateTime: endDateTime, // ), // ); // }