fix homepage news, invoice
This commit is contained in:
@@ -131,7 +131,8 @@ class _HomePageState extends ConsumerState<HomePage> {
|
||||
promotions: promotions,
|
||||
onPromotionTap: (promotion) {
|
||||
// Navigate to promotion details
|
||||
context.push('/promotions/${promotion.id}');
|
||||
context.push('/news/${promotion.id}');
|
||||
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
|
||||
@@ -87,6 +87,7 @@ class BuyerInfoModel {
|
||||
final String? wardCode;
|
||||
final String? cityName;
|
||||
final String? wardName;
|
||||
final String? customerName;
|
||||
|
||||
const BuyerInfoModel({
|
||||
this.name,
|
||||
@@ -100,6 +101,7 @@ class BuyerInfoModel {
|
||||
this.wardCode,
|
||||
this.cityName,
|
||||
this.wardName,
|
||||
this.customerName,
|
||||
});
|
||||
|
||||
factory BuyerInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
@@ -115,6 +117,7 @@ class BuyerInfoModel {
|
||||
wardCode: json['ward_code'] as String?,
|
||||
cityName: json['city_name'] as String?,
|
||||
wardName: json['ward_name'] as String?,
|
||||
customerName: json['customer_name'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,6 +133,7 @@ class BuyerInfoModel {
|
||||
'ward_code': wardCode,
|
||||
'city_name': cityName,
|
||||
'ward_name': wardName,
|
||||
'customer_name': customerName,
|
||||
};
|
||||
|
||||
BuyerInfo toEntity() => BuyerInfo(
|
||||
@@ -144,6 +148,7 @@ class BuyerInfoModel {
|
||||
wardCode: wardCode,
|
||||
cityName: cityName,
|
||||
wardName: wardName,
|
||||
customerName: customerName,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class BuyerInfo extends Equatable {
|
||||
final String? wardCode;
|
||||
final String? cityName;
|
||||
final String? wardName;
|
||||
final String? customerName;
|
||||
|
||||
const BuyerInfo({
|
||||
this.name,
|
||||
@@ -88,6 +89,7 @@ class BuyerInfo extends Equatable {
|
||||
this.wardCode,
|
||||
this.cityName,
|
||||
this.wardName,
|
||||
this.customerName
|
||||
});
|
||||
|
||||
/// Get formatted full address
|
||||
@@ -118,6 +120,7 @@ class BuyerInfo extends Equatable {
|
||||
wardCode,
|
||||
cityName,
|
||||
wardName,
|
||||
customerName
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -294,10 +294,10 @@ class InvoiceDetailPage extends ConsumerWidget {
|
||||
|
||||
List<_InfoLine> _buildBuyerInfoLines(Invoice invoice) {
|
||||
return [
|
||||
if (invoice.buyerInfo!.name != null)
|
||||
_InfoLine(label: 'Người mua hàng', value: invoice.buyerInfo!.name!),
|
||||
if (invoice.customerName != null)
|
||||
_InfoLine(label: 'Tên đơn vị', value: invoice.customerName!),
|
||||
if (invoice.buyerInfo!.customerName != null)
|
||||
_InfoLine(label: 'Người mua hàng', value: invoice.buyerInfo!.customerName!),
|
||||
if (invoice.buyerInfo!.addressTitle != null)
|
||||
_InfoLine(label: 'Tên đơn vị', value: invoice.buyerInfo!.addressTitle!),
|
||||
if (invoice.buyerInfo!.taxCode != null)
|
||||
_InfoLine(label: 'Mã số thuế', value: invoice.buyerInfo!.taxCode!),
|
||||
if (invoice.buyerInfo!.fullAddress.isNotEmpty)
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:worker/core/constants/ui_constants.dart';
|
||||
import 'package:worker/core/theme/colors.dart';
|
||||
import 'package:worker/features/products/domain/entities/product.dart';
|
||||
@@ -273,17 +274,14 @@ class ProductCard extends ConsumerWidget {
|
||||
width: double.infinity,
|
||||
height: 36.0,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
// TODO: Open 360 view in browser
|
||||
// For now, show a message
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'Đang phát triển tính năng xem 360°',
|
||||
),
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
onPressed: () async {
|
||||
final url = Uri.parse(product.customLink360!);
|
||||
if (await canLaunchUrl(url)) {
|
||||
await launchUrl(
|
||||
url,
|
||||
mode: LaunchMode.inAppWebView,
|
||||
);
|
||||
}
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: colorScheme.primary,
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:worker/core/constants/ui_constants.dart';
|
||||
import 'package:worker/features/products/domain/entities/product.dart';
|
||||
|
||||
@@ -18,7 +19,6 @@ import 'package:worker/features/products/domain/entities/product.dart';
|
||||
/// - Image indicators (dots)
|
||||
/// - Thumbnail gallery row (horizontal scroll)
|
||||
class ImageGallerySection extends StatefulWidget {
|
||||
|
||||
const ImageGallerySection({super.key, required this.product});
|
||||
final Product product;
|
||||
|
||||
@@ -40,22 +40,15 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
setState(() {
|
||||
_currentImageIndex = index;
|
||||
});
|
||||
_pageController.animateToPage(
|
||||
index,
|
||||
duration: AppDuration.medium,
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
_pageController.animateToPage(index, duration: AppDuration.medium, curve: Curves.easeInOut);
|
||||
}
|
||||
|
||||
void _open360View() {
|
||||
void _open360View() async {
|
||||
if (widget.product.customLink360 != null) {
|
||||
// TODO: Open in browser
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Đang phát triển tính năng xem 360°'),
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
final url = Uri.parse(widget.product.customLink360!);
|
||||
if (await canLaunchUrl(url)) {
|
||||
await launchUrl(url, mode: LaunchMode.inAppWebView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,11 +101,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: Icon(
|
||||
FontAwesomeIcons.image,
|
||||
size: 64,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
child: Icon(FontAwesomeIcons.image, size: 64, color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -131,10 +120,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
onTap: _open360View,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -144,11 +130,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
builder: (context, double value, child) {
|
||||
return Transform.rotate(
|
||||
angle: value * 2 * 3.14159,
|
||||
child: Icon(
|
||||
FontAwesomeIcons.arrowsRotate,
|
||||
size: 10,
|
||||
color: colorScheme.surface,
|
||||
),
|
||||
child: Icon(FontAwesomeIcons.arrowsRotate, size: 10, color: colorScheme.surface),
|
||||
);
|
||||
},
|
||||
onEnd: () {
|
||||
@@ -159,11 +141,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'360°',
|
||||
style: TextStyle(
|
||||
color: colorScheme.surface,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: TextStyle(color: colorScheme.surface, fontSize: 12, fontWeight: FontWeight.w600),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -245,9 +223,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: isActive
|
||||
? colorScheme.primary
|
||||
: Colors.transparent,
|
||||
color: isActive ? colorScheme.primary : Colors.transparent,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
@@ -256,15 +232,10 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: imageUrl,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) =>
|
||||
Container(color: colorScheme.surfaceContainerHighest),
|
||||
placeholder: (context, url) => Container(color: colorScheme.surfaceContainerHighest),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
child: Icon(
|
||||
FontAwesomeIcons.image,
|
||||
size: 20,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
child: Icon(FontAwesomeIcons.image, size: 20, color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -285,12 +256,7 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
|
||||
|
||||
/// Image Lightbox for full-screen image viewing
|
||||
class _ImageLightbox extends StatefulWidget {
|
||||
|
||||
const _ImageLightbox({
|
||||
required this.images,
|
||||
required this.imageCaptions,
|
||||
required this.initialIndex,
|
||||
});
|
||||
const _ImageLightbox({required this.images, required this.imageCaptions, required this.initialIndex});
|
||||
final List<String> images;
|
||||
final Map<String, String> imageCaptions;
|
||||
final int initialIndex;
|
||||
@@ -318,19 +284,13 @@ class _ImageLightboxState extends State<_ImageLightbox> {
|
||||
|
||||
void _nextImage() {
|
||||
if (_currentIndex < widget.images.length - 1) {
|
||||
_pageController.nextPage(
|
||||
duration: AppDuration.medium,
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
_pageController.nextPage(duration: AppDuration.medium, curve: Curves.easeInOut);
|
||||
}
|
||||
}
|
||||
|
||||
void _previousImage() {
|
||||
if (_currentIndex > 0) {
|
||||
_pageController.previousPage(
|
||||
duration: AppDuration.medium,
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
_pageController.previousPage(duration: AppDuration.medium, curve: Curves.easeInOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,11 +332,8 @@ class _ImageLightboxState extends State<_ImageLightbox> {
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: widget.images[index],
|
||||
fit: BoxFit.contain,
|
||||
errorWidget: (context, url, error) => Icon(
|
||||
FontAwesomeIcons.circleExclamation,
|
||||
color: colorScheme.surface,
|
||||
size: 64,
|
||||
),
|
||||
errorWidget: (context, url, error) =>
|
||||
Icon(FontAwesomeIcons.circleExclamation, color: colorScheme.surface, size: 64),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -393,15 +350,9 @@ class _ImageLightboxState extends State<_ImageLightbox> {
|
||||
bottom: 0,
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: Icon(
|
||||
FontAwesomeIcons.chevronLeft,
|
||||
color: colorScheme.surface,
|
||||
size: 32,
|
||||
),
|
||||
icon: Icon(FontAwesomeIcons.chevronLeft, color: colorScheme.surface, size: 32),
|
||||
onPressed: _previousImage,
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.white.withAlpha(51),
|
||||
),
|
||||
style: IconButton.styleFrom(backgroundColor: Colors.white.withAlpha(51)),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -414,15 +365,9 @@ class _ImageLightboxState extends State<_ImageLightbox> {
|
||||
bottom: 0,
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: Icon(
|
||||
FontAwesomeIcons.chevronRight,
|
||||
color: colorScheme.surface,
|
||||
size: 32,
|
||||
),
|
||||
icon: Icon(FontAwesomeIcons.chevronRight, color: colorScheme.surface, size: 32),
|
||||
onPressed: _nextImage,
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.white.withAlpha(51),
|
||||
),
|
||||
style: IconButton.styleFrom(backgroundColor: Colors.white.withAlpha(51)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1166,13 +1166,13 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
||||
height: 24,
|
||||
child: CustomLoadingIndicator(color: Colors.white, size: 20),
|
||||
)
|
||||
: const Row(
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FaIcon(FontAwesomeIcons.paperPlane, size: 16),
|
||||
SizedBox(width: 8),
|
||||
const FaIcon(FontAwesomeIcons.paperPlane, size: 16),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Gửi đăng ký',
|
||||
isEditing ? 'Cập nhật' : 'Gửi đăng ký',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.1+24
|
||||
version: 1.0.1+26
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.0
|
||||
|
||||
Reference in New Issue
Block a user