apskel-owner-flutter/lib/presentation/pages/outlet/outlet_information_page.dart
2025-08-19 11:08:33 +07:00

404 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/outlet/current_outlet_loader/current_outlet_loader_bloc.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/outlet/outlet.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
// Outlet Information Page
@RoutePage()
class OutletInformationPage extends StatefulWidget implements AutoRouteWrapper {
const OutletInformationPage({super.key});
@override
State<OutletInformationPage> createState() => _OutletInformationPageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (_) =>
getIt<CurrentOutletLoaderBloc>()
..add(CurrentOutletLoaderEvent.fetched()),
child: this,
);
}
class _OutletInformationPageState extends State<OutletInformationPage>
with TickerProviderStateMixin {
late ScrollController _scrollController;
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_fadeController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_slideController = AnimationController(
duration: const Duration(milliseconds: 600),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
CurvedAnimation(parent: _slideController, curve: Curves.easeOutBack),
);
// Start animations
_fadeController.forward();
_slideController.forward();
}
@override
void dispose() {
_scrollController.dispose();
_fadeController.dispose();
_slideController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(
controller: _scrollController,
slivers: [
SliverAppBar(
expandedHeight: 120.0,
floating: false,
pinned: true,
flexibleSpace: CustomAppBar(title: 'Outlet Information'),
),
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: _buildContent(),
),
),
),
],
),
);
}
Widget _buildContent() {
return BlocBuilder<CurrentOutletLoaderBloc, CurrentOutletLoaderState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeaderCard(state.outlet),
const SizedBox(height: 20),
_buildInfoSection(state.outlet),
const SizedBox(height: 20),
_buildContactSection(state.outlet),
const SizedBox(height: 20),
_buildBusinessSection(state.outlet),
const SizedBox(height: 20),
_buildStatusSection(state.outlet),
const SizedBox(height: 20),
_buildTimestampSection(state.outlet),
],
),
);
},
);
}
Widget _buildHeaderCard(Outlet outlet) {
return TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 800),
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.8 + (0.2 * value),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: AppColor.primaryGradient,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Icon(Icons.store, color: AppColor.white, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
outlet.name,
style: AppStyle.h5.copyWith(
color: AppColor.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
outlet.businessType,
style: AppStyle.md.copyWith(
color: AppColor.white.withOpacity(0.9),
),
),
],
),
),
],
),
],
),
),
);
},
);
}
Widget _buildInfoSection(Outlet outlet) {
return _buildAnimatedCard(
delay: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('General Information', Icons.info_outline),
const SizedBox(height: 16),
_buildInfoRow('Outlet ID', outlet.id, Icons.fingerprint),
_buildInfoRow(
'Organization ID',
outlet.organizationId,
Icons.business,
),
_buildInfoRow('Address', outlet.address, Icons.location_on),
],
),
);
}
Widget _buildContactSection(Outlet outlet) {
return _buildAnimatedCard(
delay: 400,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Contact Information', Icons.contact_phone),
const SizedBox(height: 16),
_buildInfoRow('Phone Number', outlet.phoneNumber, Icons.phone),
],
),
);
}
Widget _buildBusinessSection(Outlet outlet) {
return _buildAnimatedCard(
delay: 600,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Business Settings', Icons.settings_applications),
const SizedBox(height: 16),
_buildInfoRow('Currency', outlet.currency, Icons.monetization_on),
_buildInfoRow('Tax Rate', '${outlet.taxRate}%', Icons.percent),
],
),
);
}
Widget _buildStatusSection(Outlet outlet) {
return _buildAnimatedCard(
delay: 800,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Status', Icons.toggle_on),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: outlet.isActive
? AppColor.success.withOpacity(0.1)
: AppColor.error.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: outlet.isActive
? AppColor.success.withOpacity(0.3)
: AppColor.error.withOpacity(0.3),
),
),
child: Row(
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: outlet.isActive ? AppColor.success : AppColor.error,
shape: BoxShape.circle,
),
),
const SizedBox(width: 12),
Text(
outlet.isActive ? 'Active' : 'Inactive',
style: AppStyle.md.copyWith(
color: outlet.isActive ? AppColor.success : AppColor.error,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
);
}
Widget _buildTimestampSection(Outlet outlet) {
return _buildAnimatedCard(
delay: 1000,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Timestamps', Icons.schedule),
const SizedBox(height: 16),
_buildInfoRow(
'Created At',
_formatDateTime(outlet.createdAt),
Icons.add_circle_outline,
),
_buildInfoRow(
'Updated At',
_formatDateTime(outlet.updatedAt),
Icons.update,
),
],
),
);
}
Widget _buildAnimatedCard({required Widget child, required int delay}) {
return TweenAnimationBuilder<double>(
duration: Duration(milliseconds: 600 + delay),
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, _) {
return Transform.translate(
offset: Offset(0, 30 * (1 - value)),
child: Opacity(
opacity: value,
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: child,
),
),
);
},
);
}
Widget _buildSectionTitle(String title, IconData icon) {
return Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: AppColor.primary, size: 20),
),
const SizedBox(width: 12),
Text(
title,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
],
);
}
Widget _buildInfoRow(String label, String value, IconData icon) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, color: AppColor.textSecondary, size: 20),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
Text(
value,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
);
}
String _formatDateTime(DateTime dateTime) {
return '${dateTime.day}/${dateTime.month}/${dateTime.year} ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
}
}