504 lines
28 KiB
Dart
504 lines
28 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:niogu_app/core/components/top_back_bar_app.dart';
|
|
import 'package:niogu_app/core/constants/app_color.dart';
|
|
import 'package:niogu_app/core/constants/app_font_size.dart';
|
|
import 'package:niogu_app/core/widgets/custom_error_screen.dart';
|
|
import 'package:niogu_app/core/providers/app_provider.dart';
|
|
import 'package:niogu_app/core/router/app_route.dart';
|
|
import 'package:niogu_app/core/widgets/custom_empty_screen.dart';
|
|
import 'package:niogu_app/features/outlets/domain/entities/outlet.dart';
|
|
import 'package:niogu_app/features/outlets/presentation/providers/outlet_provider.dart';
|
|
import 'package:niogu_app/features/outlets/presentation/widgets/outlet_shimmer.dart';
|
|
import 'package:niogu_app/features/outlets/presentation/widgets/quota_indicator.dart';
|
|
import 'package:sizer/sizer.dart';
|
|
|
|
class OutletScreen extends ConsumerWidget {
|
|
const OutletScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
return LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final bool isTablet = 100.w >= 600;
|
|
|
|
final outletState = ref.watch(displayOutletStreamProvider);
|
|
|
|
int limitOutlet = 5;
|
|
|
|
final limitOutletState = ref.watch(limitOutletStreamProvider);
|
|
|
|
limitOutletState.whenData((limit) => limitOutlet = limit);
|
|
|
|
bool isLimitReached = false;
|
|
|
|
outletState.whenData((outlets) {
|
|
isLimitReached = outlets.length >= limitOutlet;
|
|
});
|
|
|
|
final userDeletedState = ref.watch(userDeletedByOutletStreamProvider);
|
|
|
|
final List<UserDeletedByOutlet> userDeleted = [];
|
|
|
|
userDeletedState.whenData((u) => userDeleted.addAll(u));
|
|
|
|
final outletEmptyState = ref.watch(displayOutletEmptyProvider);
|
|
|
|
final outletIdByOwnerState = ref.watch(outletIdByOwnerProvider);
|
|
|
|
return SafeArea(
|
|
top: false,
|
|
bottom: true,
|
|
right: false,
|
|
left: false,
|
|
child: Scaffold(
|
|
backgroundColor: const Color(0xFFF9FAFB),
|
|
appBar: TopBackBarApp(
|
|
title: "Outlet Usaha",
|
|
onTap: () => context.pop(),
|
|
),
|
|
body: outletState.when(
|
|
data: (outlets) {
|
|
switch (outletEmptyState) {
|
|
case DisplayOutletEmpty.loading:
|
|
return const SizedBox();
|
|
case DisplayOutletEmpty.empty_database:
|
|
return CustomEmptyScreen(
|
|
title: "Tidak Ada Outlet",
|
|
body: "Kamu belum memiliki outlet",
|
|
);
|
|
case DisplayOutletEmpty.has_data:
|
|
return Column(
|
|
children: [
|
|
QuotaIndicator(current: outlets.length, max: limitOutlet),
|
|
|
|
Expanded(
|
|
child: ListView.builder(
|
|
padding: EdgeInsets.symmetric(horizontal: 5.w),
|
|
itemCount: outlets.length,
|
|
itemBuilder: (context, index) {
|
|
final outlet = outlets[index];
|
|
|
|
final bool imagePathAvailable =
|
|
outlet.bannerPath != null &&
|
|
outlet.bannerPath!.isNotEmpty;
|
|
|
|
final File imageFile = File(
|
|
imagePathAvailable
|
|
? outlet.bannerPath!
|
|
: "image not found",
|
|
);
|
|
|
|
int userStaffAmount = outlet.userStaffAmount;
|
|
|
|
final bool isOutletOwner =
|
|
outletIdByOwnerState != null &&
|
|
outlet.id == outletIdByOwnerState;
|
|
|
|
if (userDeleted.isNotEmpty) {
|
|
for (final user in userDeleted) {
|
|
if (isOutletOwner &&
|
|
user.outletId == outlet.id) {
|
|
userStaffAmount =
|
|
outlet.userStaffAmount -
|
|
user.amount -
|
|
1;
|
|
} else if (user.outletId == outlet.id) {
|
|
userStaffAmount =
|
|
outlet.userStaffAmount -
|
|
user.amount;
|
|
}
|
|
}
|
|
} else {
|
|
if (isOutletOwner) {
|
|
userStaffAmount =
|
|
outlet.userStaffAmount - 1;
|
|
}
|
|
}
|
|
|
|
final bool imageFileExists = imageFile
|
|
.existsSync();
|
|
|
|
return Material(
|
|
color: Colors.transparent,
|
|
type: MaterialType.transparency,
|
|
child: InkWell(
|
|
onTap: () {
|
|
context.pushNamed(
|
|
AppRoute.editOutletScreen,
|
|
pathParameters: {"id": outlet.id},
|
|
);
|
|
},
|
|
child: Container(
|
|
margin: EdgeInsets.only(bottom: 3.h),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(
|
|
4.w,
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(
|
|
0.06,
|
|
),
|
|
blurRadius: 15,
|
|
offset: const Offset(0, 8),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.start,
|
|
children: [
|
|
Stack(
|
|
children: [
|
|
imageFileExists
|
|
? Container(
|
|
height: 22.h,
|
|
width: double.infinity,
|
|
decoration: BoxDecoration(
|
|
borderRadius:
|
|
BorderRadius.vertical(
|
|
top:
|
|
Radius.circular(
|
|
4.w,
|
|
),
|
|
),
|
|
image:
|
|
DecorationImage(
|
|
image:
|
|
FileImage(
|
|
imageFile,
|
|
),
|
|
fit: BoxFit
|
|
.cover,
|
|
),
|
|
),
|
|
)
|
|
: Container(
|
|
height: 22.h,
|
|
width: double.infinity,
|
|
decoration: BoxDecoration(
|
|
borderRadius:
|
|
BorderRadius.vertical(
|
|
top:
|
|
Radius.circular(
|
|
4.w,
|
|
),
|
|
),
|
|
color: Colors
|
|
.grey
|
|
.shade200,
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.center,
|
|
children: [
|
|
Icon(
|
|
Icons
|
|
.store_outlined,
|
|
color:
|
|
Colors.grey,
|
|
size: 20.w,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (imageFileExists)
|
|
Container(
|
|
height: 22.h,
|
|
width: double.infinity,
|
|
decoration: BoxDecoration(
|
|
borderRadius:
|
|
BorderRadius.vertical(
|
|
top:
|
|
Radius.circular(
|
|
4.w,
|
|
),
|
|
),
|
|
gradient: LinearGradient(
|
|
begin:
|
|
Alignment.topCenter,
|
|
end: Alignment
|
|
.bottomCenter,
|
|
colors: [
|
|
Colors.black
|
|
.withOpacity(0.4),
|
|
Colors.transparent,
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
Padding(
|
|
padding: EdgeInsets.all(4.w),
|
|
child: Column(
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.spaceBetween,
|
|
children: [
|
|
Text(
|
|
outlet.name,
|
|
style: TextStyle(
|
|
color: Colors.black87,
|
|
fontSize: isTablet
|
|
? AppFontSize
|
|
.medium
|
|
.sp
|
|
: AppFontSize
|
|
.small
|
|
.sp,
|
|
fontWeight:
|
|
FontWeight.bold,
|
|
),
|
|
),
|
|
Row(
|
|
children: [
|
|
Container(
|
|
width: 2.w,
|
|
height: 2.w,
|
|
decoration: BoxDecoration(
|
|
color:
|
|
outlet
|
|
.isActive
|
|
? Colors.green
|
|
: Colors.red,
|
|
shape: BoxShape
|
|
.circle,
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: 1.5.w,
|
|
),
|
|
Text(
|
|
outlet.isActive
|
|
? 'Aktif / Buka'
|
|
: 'Non Aktif / Tutup',
|
|
style: TextStyle(
|
|
fontSize: isTablet
|
|
? (AppFontSize.medium -
|
|
2)
|
|
.sp
|
|
: (AppFontSize.small -
|
|
2)
|
|
.sp,
|
|
color:
|
|
outlet
|
|
.isActive
|
|
? Colors.green
|
|
: Colors.red,
|
|
fontWeight:
|
|
FontWeight
|
|
.w600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 1.h),
|
|
if (outlet.isMainOutlet)
|
|
Text(
|
|
"• Outlet Utama",
|
|
style: TextStyle(
|
|
color: Colors
|
|
.grey
|
|
.shade700,
|
|
fontSize: isTablet
|
|
? (AppFontSize.medium -
|
|
2)
|
|
.sp
|
|
: (AppFontSize.small -
|
|
2)
|
|
.sp,
|
|
fontWeight:
|
|
FontWeight.bold,
|
|
),
|
|
),
|
|
|
|
if (outlet.fullAddress !=
|
|
null &&
|
|
outlet
|
|
.fullAddress!
|
|
.isNotEmpty) ...[
|
|
SizedBox(height: 1.5.h),
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
Icons
|
|
.location_on_outlined,
|
|
size: 5.w,
|
|
color: Colors.grey,
|
|
),
|
|
SizedBox(width: 2.w),
|
|
Expanded(
|
|
child: Text(
|
|
outlet.fullAddress!,
|
|
style: TextStyle(
|
|
color: Colors
|
|
.grey
|
|
.shade700,
|
|
fontSize: isTablet
|
|
? (AppFontSize.medium -
|
|
1.25)
|
|
.sp
|
|
: (AppFontSize.small -
|
|
1.25)
|
|
.sp,
|
|
),
|
|
maxLines: 1,
|
|
overflow:
|
|
TextOverflow
|
|
.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
SizedBox(height: 1.h),
|
|
Divider(
|
|
color: Colors.grey[100],
|
|
),
|
|
SizedBox(height: 1.h),
|
|
Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment
|
|
.spaceBetween,
|
|
children: [
|
|
_buildInfoMini(
|
|
Icons.people_outline,
|
|
"$userStaffAmount Staf",
|
|
isTablet,
|
|
),
|
|
_buildInfoMini(
|
|
Icons
|
|
.shopping_bag_outlined,
|
|
"${outlet.transactionAmount} Transaksi",
|
|
isTablet,
|
|
),
|
|
Icon(
|
|
Icons.arrow_forward_ios,
|
|
size: 3.5.w,
|
|
color: Colors.grey[400],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
},
|
|
error: (error, stackTrace) {
|
|
return CustomErrorScreen(
|
|
message: "Ups, terjadi kesalahan",
|
|
onRefresh: () {},
|
|
);
|
|
},
|
|
loading: () => const OutletShimmer(),
|
|
),
|
|
bottomNavigationBar: outletState.isLoading
|
|
? null
|
|
: Container(
|
|
padding: EdgeInsets.all(5.w),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, -5),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
ElevatedButton(
|
|
onPressed: isLimitReached
|
|
? null
|
|
: () {
|
|
final outletState = ref.read(
|
|
outletStreamProvider,
|
|
);
|
|
|
|
bool isLimitReached = false;
|
|
|
|
outletState.whenData((outlets) {
|
|
isLimitReached = outlets.length >= 5;
|
|
});
|
|
|
|
if (isLimitReached) {
|
|
} else {
|
|
context.pushNamed(
|
|
AppRoute.addOutletScreen,
|
|
);
|
|
}
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: AppColor.primaryColor,
|
|
minimumSize: Size(double.infinity, 6.5.h),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(3.w),
|
|
),
|
|
disabledBackgroundColor: !isLimitReached
|
|
? null
|
|
: Colors.grey.shade300,
|
|
),
|
|
child: Text(
|
|
"Tambah Outlet Baru",
|
|
style: TextStyle(
|
|
fontSize: AppFontSize.medium.sp,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildInfoMini(IconData icon, String label, bool isTablet) {
|
|
return Row(
|
|
children: [
|
|
Icon(icon, size: 4.w, color: AppColor.primaryColor),
|
|
SizedBox(width: 1.5.w),
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
color: Colors.black54,
|
|
fontSize: isTablet
|
|
? (AppFontSize.medium - 1.25).sp
|
|
: (AppFontSize.small - 1.25).sp,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|