Files
Kifi/kifi-app/lib/features/sales/presentation/sales_channels_screen.dart

279 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import '../domain/sales_channel.dart';
import '../providers/sales_channels_provider.dart';
class SalesChannelsScreen extends ConsumerStatefulWidget {
const SalesChannelsScreen({super.key});
@override
ConsumerState<SalesChannelsScreen> createState() => _SalesChannelsScreenState();
}
class _SalesChannelsScreenState extends ConsumerState<SalesChannelsScreen> {
void _showAddEditChannelSheet([SalesChannel? channel]) {
final nameCtrl = TextEditingController(text: channel?.name ?? '');
final codeCtrl = TextEditingController(text: channel?.code ?? '');
final isEditing = channel != null;
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (ctx) => Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20,
left: 20,
right: 20,
top: 20,
),
decoration: BoxDecoration(
color: Theme.of(ctx).scaffoldBackgroundColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
isEditing ? 'Edit Sales Channel' : 'Add Sales Channel',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(LucideIcons.x),
onPressed: () => Navigator.pop(ctx),
),
],
),
const SizedBox(height: 16),
TextField(
controller: nameCtrl,
decoration: const InputDecoration(
labelText: 'Channel Name *',
hintText: 'e.g. Nykaa, Myntra, Tata CLiQ, Etsy',
border: OutlineInputBorder(),
prefixIcon: Icon(LucideIcons.store),
),
),
const SizedBox(height: 16),
TextField(
controller: codeCtrl,
decoration: const InputDecoration(
labelText: 'Channel Code',
hintText: 'e.g. NYKAA, MYNTRA, ETSY',
border: OutlineInputBorder(),
prefixIcon: Icon(LucideIcons.tag),
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 48,
child: FilledButton(
onPressed: () async {
final name = nameCtrl.text.trim();
if (name.isEmpty) return;
Navigator.pop(ctx);
try {
if (isEditing) {
await ref.read(salesChannelsProvider.notifier).updateChannel(
channel.id!,
SalesChannel(
id: channel.id,
name: name,
code: codeCtrl.text.trim().isNotEmpty
? codeCtrl.text.trim().toUpperCase()
: null,
icon: channel.icon,
isActive: channel.isActive,
),
);
} else {
await ref.read(salesChannelsProvider.notifier).createChannel(
SalesChannel(
name: name,
code: codeCtrl.text.trim().isNotEmpty
? codeCtrl.text.trim().toUpperCase()
: null,
icon: 'shopping-bag',
isActive: true,
),
);
}
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(isEditing
? 'Channel updated successfully'
: 'Channel created successfully'),
backgroundColor: Colors.green,
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red),
);
}
}
},
child: Text(isEditing ? 'Save Changes' : 'Add Channel'),
),
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
final channelsState = ref.watch(salesChannelsProvider);
return Scaffold(
appBar: AppBar(
title: const Text('Sales Channels & Marketplaces'),
actions: [
IconButton(
icon: const Icon(LucideIcons.plus),
tooltip: 'Add Sales Channel',
onPressed: () => _showAddEditChannelSheet(),
),
],
),
body: channelsState.when(
data: (channels) {
if (channels.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(LucideIcons.shoppingBag, size: 48, color: Colors.grey),
const SizedBox(height: 16),
const Text(
'No sales channels found',
style: TextStyle(color: Colors.grey, fontSize: 16),
),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: () => _showAddEditChannelSheet(),
icon: const Icon(LucideIcons.plus),
label: const Text('Add First Channel'),
),
],
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: channels.length,
itemBuilder: (context, index) {
final channel = channels[index];
IconData iconData = LucideIcons.store;
if (channel.code == 'AMAZON' || channel.name.toLowerCase().contains('amazon')) {
iconData = LucideIcons.shoppingCart;
} else if (channel.code == 'FLIPKART' || channel.name.toLowerCase().contains('flipkart')) {
iconData = LucideIcons.package;
} else if (channel.code == 'SHOPIFY' || channel.name.toLowerCase().contains('shopify')) {
iconData = LucideIcons.globe;
} else if (channel.code == 'MEESHO' || channel.name.toLowerCase().contains('meesho')) {
iconData = LucideIcons.tag;
} else if (channel.code == 'QUICK_COMMERCE' || channel.name.toLowerCase().contains('quick')) {
iconData = LucideIcons.zap;
}
final isSystemDefault = channel.userId == null;
return Card(
elevation: 0,
margin: const EdgeInsets.only(bottom: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: Colors.grey.withValues(alpha: 0.2)),
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue.withValues(alpha: 0.1),
child: Icon(iconData, color: Colors.blue, size: 20),
),
title: Row(
children: [
Text(
channel.name,
style: const TextStyle(fontWeight: FontWeight.bold),
),
if (isSystemDefault) ...[
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.grey.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'System',
style: TextStyle(fontSize: 10, color: Colors.grey, fontWeight: FontWeight.bold),
),
),
],
],
),
subtitle: channel.code != null
? Text('Code: ${channel.code}', style: const TextStyle(fontSize: 12))
: null,
trailing: isSystemDefault
? const Icon(LucideIcons.lock, size: 16, color: Colors.grey)
: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(LucideIcons.edit2, size: 18),
onPressed: () => _showAddEditChannelSheet(channel),
),
IconButton(
icon: const Icon(LucideIcons.trash2, size: 18, color: Colors.red),
onPressed: () async {
final confirm = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Delete Channel?'),
content: Text('Are you sure you want to delete ${channel.name}?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(ctx, true),
child: const Text('Delete', style: TextStyle(color: Colors.red)),
),
],
),
);
if (confirm == true) {
await ref.read(salesChannelsProvider.notifier).deleteChannel(channel.id!);
}
},
),
],
),
),
);
},
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('Error: $e')),
),
);
}
}