proxibuy_bussiness/lib/presentation/pages/store_info.dart

496 lines
17 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.

import 'dart:io';
import 'package:business_panel/core/config/app_colors.dart';
import 'package:business_panel/gen/assets.gen.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';
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
class StoreInfoPage extends StatelessWidget {
const StoreInfoPage({super.key});
Future<void> _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<StoreInfoBloc>().add(StoreLogoChanged(image.path));
}
} on PlatformException catch (e) {
print("خطای دسترسی یا پلتفرم: ${e.message}");
} catch (e) {
print("یک خطای ناشناخته رخ داد: $e");
}
}
Future<void> _showWorkingHoursDialog(BuildContext context) async {
final result = await showDialog<Map<String, dynamic>>(
context: context,
builder: (context) => const WorkingHoursDialog(),
);
if (result != null && context.mounted) {
context.read<StoreInfoBloc>().add(
WorkingScheduleChanged(
days: result['days'] as List<String>,
startTime: result['startTime'] as String,
endTime: result['endTime'] as String,
),
);
}
}
// Future<void> _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<StoreInfoBloc>().add(
// WorkingHoursChanged(
// startDateTime: startDateTime,
// endDateTime: endDateTime,
// ),
// );
// }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildCustomAppBar(context),
body: 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<StoreInfoBloc, StoreInfoState>(
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: "مثلاً کافه ایرونی",
),
const SizedBox(height: 30),
_buildActivityTypeDropdown(context),
const SizedBox(height: 30),
Row(
children: [
Expanded(
child: _buildTextField(label: "استان", hint: "اصفهان"),
),
const SizedBox(width: 16),
Expanded(child: _buildTextField(label: "شهر", hint: "اصفهان")),
],
),
const SizedBox(height: 30),
_buildTextField(
label: "جزئیات آدرس",
maxLines: 3,
hint: "خیابان، محله، ساختمان و ....",
),
const SizedBox(height: 30),
Row(
children: [
Expanded(child: _buildTextField(label: "پلاک")),
const SizedBox(width: 16),
Expanded(child: _buildTextField(label: "کد پستی")),
],
),
const SizedBox(height: 30),
Center(
child: TextButton.icon(
onPressed: () async {
final result = await Navigator.of(context).push<LatLng?>(
MaterialPageRoute(
builder: (context) => const OsmMapPickerPage(),
),
);
if (result != null) {
context.read<StoreInfoBloc>().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<StoreInfoBloc, StoreInfoState>(
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(
label: "تلفن تماس",
keyboardType: TextInputType.phone,
hint: "شماره تماس ثابت یا موبایل فروشگاه",
),
const SizedBox(height: 30),
_buildWorkingHoursPicker(context),
const SizedBox(height: 30),
_buildTextField(
label: "شماره جواز کسب",
hint: "شناسه صنفی 12 رقمی یکتا",
),
const SizedBox(height: 44),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
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,
TextInputType? keyboardType,
}) {
return TextFormField(
maxLines: maxLines,
keyboardType: keyboardType,
decoration: InputDecoration(
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 _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<StoreInfoBloc, StoreInfoState>(
buildWhen: (p, c) => p.workingDays != c.workingDays,
builder: (context, state) {
final hasData = state.workingDays.isNotEmpty && state.startTime != null;
const Map<String, String> 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) {
final List<String> activityTypes = [
"🍔🍕 فست فود",
"👚👔 پوشاک",
"🍨🍹 تریا",
"📱📷 لوازم دیجیتال",
"🍣🍢 رستوران",
"☕🍰 کافی شاپ",
"👜👞 کیف و کفش",
"🎭🎟️ سینما",
"💄💅️ لوازم آرایشی",
"💍💎 طلا و زیورآلات",
];
return Theme(
data: Theme.of(context).copyWith(canvasColor: const Color(0xFFF6F6F6)),
child: DropdownButtonFormField<String>(
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((String value) {
return DropdownMenuItem<String>(value: value, child: Text(value));
}).toList(),
onChanged: (value) {
if (value != null) {
context.read<StoreInfoBloc>().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),
),
],
),
],
),
],
),
),
),
),
);
}