59 KiB
Flutter Mobile App - Worker (EuroTile & Vasta Stone) Expert Guidelines
🎯 App Overview
A Flutter-based mobile application designed for contractors, distributors, architects, and brokers in the tile, interior, and construction industry. The app combines a powerful loyalty program with convenient ordering tools and project management capabilities.
🎯 Main Objectives:
- Powerful loyalty platform with rewards and membership tiers (Diamond/Platinum/Gold)
- Quick and efficient product ordering system
- Project, contract, and quote management
- Integration with promotions and special offers
- Real-time chat support
👥 Target Users:
- Contractors (Thầu thợ): Construction project managers
- Architects (Kiến trúc sư): Design professionals
- Distributors (Đại lý phân phối): Product resellers
- Real estate brokers (Môi giới): Real estate and construction brokers
📁 Reference Materials:
The html/ folder contains UI/UX reference mockups that show the desired design and flow. These HTML files serve as design specifications for the Flutter implementation.
🤖 SUBAGENT DELEGATION SYSTEM 🤖
CRITICAL: BE PROACTIVE WITH SUBAGENTS! YOU HAVE SPECIALIZED EXPERTS AVAILABLE!
🚨 DELEGATION MINDSET
Instead of thinking "I'll handle this myself" Think: "Which specialist is BEST suited for this task?"
📋 AVAILABLE SPECIALISTS
You have access to these expert subagents - USE THEM PROACTIVELY:
🎨 flutter-widget-expert
- MUST BE USED for: Loyalty cards, member cards, product grids, order cards, project cards, chat UI, form layouts, bottom navigation
- Triggers: "create widget", "build UI", "card design", "layout", "animation", "custom widget", "loyalty card", "member card"
📊 riverpod-expert
- MUST BE USED for: Cart state, authentication state, loyalty points state, product state, order state, project state
- Triggers: "state management", "provider", "riverpod", "async state", "data flow", "cart", "auth state"
🗄️ hive-expert
- MUST BE USED for: Local database, offline storage, cart persistence, user data caching, loyalty points cache
- Triggers: "database", "cache", "hive", "local storage", "persistence", "offline", "box"
🌐 api-integration-expert
- MUST BE USED for: Authentication API, OTP verification, product API, loyalty API, order API, project API
- Triggers: "API", "HTTP", "dio", "REST", "backend", "authentication", "OTP", "sync"
🏗️ architecture-expert
- MUST BE USED for: Feature organization, clean architecture setup, dependency injection, navigation structure
- Triggers: "architecture", "structure", "organization", "clean code", "refactor", "navigation"
⚡ performance-expert
- MUST BE USED for: Image caching, list optimization, memory management, app performance
- Triggers: "performance", "optimization", "memory", "image cache", "slow", "lag", "scroll"
🎯 DELEGATION STRATEGY
BEFORE starting ANY task, ASK YOURSELF:
- "Which of my specialists could handle this better?"
- "Should I break this into parts for different specialists?"
- "Would a specialist complete this faster and better?"
💼 WORK BALANCE RECOMMENDATION:
- Simple Tasks (20%): Handle independently - quick fixes, minor updates
- Complex Tasks (80%): Delegate to specialists for expert-level results
🔧 HOW TO DELEGATE
# Explicit delegation examples:
> Use the flutter-widget-expert to create the Diamond/Platinum/Gold loyalty card widget
> Have the riverpod-expert design the authentication and user session state management
> Ask the hive-expert to create the local database schema for products and orders
> Use the api-integration-expert to implement OTP authentication flow
> Have the architecture-expert organize the loyalty program feature structure
> Ask the performance-expert to optimize the product grid scrolling
Flutter Best Practices
- Use Flutter 3.x features and Material 3 design
- Implement clean architecture with Riverpod for state management
- Use Hive for local database and offline functionality
- Follow proper dependency injection with Riverpod DI
- Implement proper error handling and user feedback
- Follow iOS and Android platform-specific design guidelines
- Support Vietnamese language (primary) and English (secondary)
- Mobile-first design optimized for phone screens
Hive Best Practices
IMPORTANT: Box Type Management
When working with Hive boxes, always use Box<dynamic> in data sources and apply .whereType<T>() for type-safe queries:
// ✅ CORRECT - Use Box<dynamic> with type filtering
Box<dynamic> get _box {
return Hive.box<dynamic>(HiveBoxNames.favoriteBox);
}
Future<List<FavoriteModel>> getAllFavorites(String userId) async {
try {
final favorites = _box.values
.whereType<FavoriteModel>() // Type-safe filtering
.where((fav) => fav.userId == userId)
.toList();
return favorites;
} catch (e) {
debugPrint('[DataSource] Error: $e');
rethrow;
}
}
// ❌ INCORRECT - Will cause HiveError
Box<FavoriteModel> get _box {
return Hive.box<FavoriteModel>(HiveBoxNames.favoriteBox);
}
Reason: Hive boxes are opened as Box<dynamic> in the central HiveService. Re-opening with a specific type causes HiveError: The box is already open and of type Box<dynamic>.
AppBar Standardization
ALL AppBars must follow this standard pattern (reference: products_page.dart):
AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => context.pop(),
),
title: const Text('Page Title', style: TextStyle(color: Colors.black)),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
centerTitle: false,
actions: [
// Custom actions here
const SizedBox(width: AppSpacing.sm), // Always end with spacing
],
)
Key Requirements:
- Black back arrow with explicit color
- Black text title with TextStyle
- Left-aligned title (
centerTitle: false) - White background (
AppColors.white) - Use
AppBarSpecs.elevation(not hardcoded values) - Always add
SizedBox(width: AppSpacing.sm)after actions
For SliverAppBar (in CustomScrollView):
SliverAppBar(
pinned: true,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
elevation: AppBarSpecs.elevation,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => context.pop(),
),
title: const Text('Page Title', style: TextStyle(color: Colors.black)),
centerTitle: false,
actions: [
// Custom actions
const SizedBox(width: AppSpacing.sm),
],
)
Worker App Project Structure
lib/
core/
constants/
api_constants.dart # API endpoints, timeouts
app_constants.dart # App config, defaults, loyalty tiers
ui_constants.dart # Spacing, sizes, colors
storage_constants.dart # Hive box names, keys
theme/
app_theme.dart # Material 3 theme (primary blue #005B9A)
colors.dart # Brand color schemes
typography.dart # Roboto text styles
network/
dio_client.dart # HTTP client setup
api_interceptor.dart # Auth token, logging interceptors
network_info.dart # Connectivity status
errors/
exceptions.dart # Custom exceptions
failures.dart # Failure classes
utils/
formatters.dart # Currency, date, phone formatters
validators.dart # Form validation (Vietnamese phone, email)
extensions.dart # Dart extensions
qr_generator.dart # QR code generation for member cards
widgets/
custom_button.dart # Primary, secondary buttons
loading_indicator.dart # Loading states
error_widget.dart # Error displays
empty_state.dart # Empty list UI
bottom_nav_bar.dart # Main bottom navigation
floating_chat_button.dart # FAB for chat
features/
auth/
data/
datasources/
auth_remote_datasource.dart # Login, OTP, register APIs
auth_local_datasource.dart # Token storage
models/
user_model.dart # User with tier info
otp_response_model.dart
repositories/
auth_repository_impl.dart
domain/
entities/
user.dart # id, name, phone, email, tier, points
repositories/
auth_repository.dart
usecases/
login_with_phone.dart
verify_otp.dart
register_user.dart
logout.dart
get_current_user.dart
presentation/
providers/
auth_provider.dart
otp_timer_provider.dart
pages/
login_page.dart # Phone input
otp_verification_page.dart # 6-digit OTP
register_page.dart # Full registration form
widgets/
phone_input_field.dart
otp_input_field.dart # Auto-focus 6 digits
user_type_selector.dart # Contractor/Architect/etc
home/
data/
datasources/
member_card_local_datasource.dart
models/
member_card_model.dart
presentation/
providers/
member_card_provider.dart
pages:
home_page.dart # Main dashboard
widgets:
diamond_member_card.dart # Gradient card with QR
platinum_member_card.dart
gold_member_card.dart
quick_action_grid.dart
loyalty/
data/
datasources:
loyalty_remote_datasource.dart
loyalty_local_datasource.dart
models:
loyalty_points_model.dart
loyalty_transaction_model.dart
reward_model.dart
gift_model.dart
referral_model.dart
repositories:
loyalty_repository_impl.dart
domain:
entities:
loyalty_points.dart # currentPoints, tier, nextTierPoints
loyalty_transaction.dart # id, type, amount, description, date
reward.dart # id, title, pointsCost, image, expiry
gift.dart # id, code, status, validFrom, validTo
referral.dart # code, link, totalReferrals, pointsEarned
repositories:
loyalty_repository.dart
usecases:
get_loyalty_points.dart
get_points_history.dart
redeem_reward.dart
get_available_rewards.dart
get_my_gifts.dart
get_referral_info.dart
share_referral.dart
presentation:
providers:
loyalty_points_provider.dart
points_history_provider.dart
rewards_provider.dart
gifts_provider.dart
referral_provider.dart
pages:
loyalty_page.dart # Progress bar, tier info
rewards_page.dart # Grid of redeemable rewards
points_history_page.dart # Transaction list
referral_page.dart # Referral link & code
my_gifts_page.dart # Tabs: Active/Used/Expired
widgets:
tier_progress_bar.dart
points_badge.dart
reward_card.dart
gift_card.dart
referral_share_sheet.dart
products/
data:
datasources:
product_remote_datasource.dart
product_local_datasource.dart
models:
product_model.dart # Tile/construction products
category_model.dart
repositories:
product_repository_impl.dart
domain:
entities:
product.dart # id, name, sku, price, images, category
category.dart
repositories:
product_repository.dart
usecases:
get_all_products.dart
search_products.dart
get_products_by_category.dart
get_product_details.dart
presentation:
providers:
products_provider.dart
product_search_provider.dart
categories_provider.dart
pages:
products_page.dart # Grid with search & filters
product_detail_page.dart
widgets:
product_grid.dart
product_card.dart
product_search_bar.dart
category_filter_chips.dart
cart/
data:
datasources:
cart_local_datasource.dart # Hive persistence
models:
cart_item_model.dart
repositories:
cart_repository_impl.dart
domain:
entities:
cart_item.dart # productId, quantity, price
repositories:
cart_repository.dart
usecases:
add_to_cart.dart
remove_from_cart.dart
update_quantity.dart
clear_cart.dart
get_cart_items.dart
calculate_cart_total.dart
presentation:
providers:
cart_provider.dart
cart_total_provider.dart
pages:
cart_page.dart
checkout_page.dart
order_success_page.dart
widgets:
cart_item_card.dart
cart_summary.dart
quantity_selector.dart
payment_method_selector.dart
orders/
data:
datasources:
order_remote_datasource.dart
order_local_datasource.dart
models:
order_model.dart
order_item_model.dart
payment_model.dart
repositories:
order_repository_impl.dart
domain:
entities:
order.dart # orderNumber, items, total, status
order_item.dart
payment.dart
repositories:
order_repository.dart
usecases:
create_order.dart
get_orders.dart
get_order_details.dart
get_payments.dart
presentation:
providers:
orders_provider.dart
order_filter_provider.dart
payments_provider.dart
pages:
orders_page.dart # Tabs by status
order_detail_page.dart
payments_page.dart
widgets:
order_card.dart
order_status_badge.dart
order_timeline.dart
payment_card.dart
projects/
data:
datasources:
project_remote_datasource.dart
project_local_datasource.dart
models:
project_model.dart
quote_model.dart
repositories:
project_repository_impl.dart
domain:
entities:
project.dart # name, client, location, progress, status
quote.dart # number, client, amount, validity, status
repositories:
project_repository.dart
usecases:
create_project.dart
get_projects.dart
update_project_progress.dart
create_quote.dart
get_quotes.dart
presentation:
providers:
projects_provider.dart
project_form_provider.dart
quotes_provider.dart
pages:
projects_page.dart # List with progress bars
project_create_page.dart # Form
project_detail_page.dart
quotes_page.dart
quote_create_page.dart
widgets:
project_card.dart
project_progress_bar.dart
quote_card.dart
project_form.dart
chat/
data:
datasources:
chat_remote_datasource.dart # WebSocket/REST
chat_local_datasource.dart
models:
message_model.dart
chat_room_model.dart
repositories:
chat_repository_impl.dart
domain:
entities:
message.dart # id, text, senderId, timestamp, isRead
chat_room.dart
repositories:
chat_repository.dart
usecases:
send_message.dart
get_messages.dart
mark_as_read.dart
presentation:
providers:
chat_provider.dart
messages_provider.dart
typing_indicator_provider.dart
pages:
chat_page.dart
widgets:
message_bubble.dart
message_input.dart
typing_indicator.dart
chat_app_bar.dart
account/
data:
datasources:
profile_remote_datasource.dart
profile_local_datasource.dart
address_datasource.dart
models:
profile_model.dart
address_model.dart
repositories:
profile_repository_impl.dart
address_repository_impl.dart
domain:
entities:
profile.dart # Extended user info
address.dart # Delivery addresses
repositories:
profile_repository.dart
address_repository.dart
usecases:
get_profile.dart
update_profile.dart
upload_avatar.dart
change_password.dart
get_addresses.dart
add_address.dart
update_address.dart
delete_address.dart
presentation:
providers:
profile_provider.dart
avatar_provider.dart
addresses_provider.dart
pages:
account_page.dart # Menu
profile_edit_page.dart
addresses_page.dart
address_form_page.dart
password_change_page.dart
widgets:
profile_header.dart
account_menu_item.dart
address_card.dart
avatar_picker.dart
promotions/
data:
datasources:
promotion_remote_datasource.dart
models:
promotion_model.dart
repositories:
promotion_repository_impl.dart
domain:
entities:
promotion.dart # title, description, discount, validity
repositories:
promotion_repository.dart
usecases:
get_active_promotions.dart
presentation:
providers:
promotions_provider.dart
pages:
promotions_page.dart
widgets:
promotion_card.dart
promotion_banner.dart
notifications/
data:
datasources:
notification_remote_datasource.dart
notification_local_datasource.dart
models:
notification_model.dart
repositories:
notification_repository_impl.dart
domain:
entities:
notification.dart # title, body, type, isRead, timestamp
repositories:
notification_repository.dart
usecases:
get_notifications.dart
mark_as_read.dart
clear_all.dart
presentation:
providers:
notifications_provider.dart
notification_badge_provider.dart
pages:
notifications_page.dart # Tabs: All/Orders/System/Promos
widgets:
notification_card.dart
notification_badge.dart
shared/
widgets/
custom_app_bar.dart
gradient_card.dart # For member cards
status_badge.dart
price_display.dart
vietnamese_phone_field.dart
date_picker_field.dart
main.dart
app.dart # Root widget with ProviderScope
test/
unit/
features/
auth/
loyalty/
products/
cart/
orders/
projects/
widget/
widgets/
integration/
App Context - Worker Mobile App
About This App
A comprehensive Flutter mobile application designed for workers in the tile and construction industry. The app enables contractors, architects, distributors, and brokers to manage their loyalty rewards, browse products, create orders, manage construction projects, and track business performance—all through an intuitive mobile interface optimized for speed and efficiency.
Design References
The html/ folder contains 25+ HTML mockup files that serve as UI/UX design references:
- Visual design and layout specifications
- Color schemes and branding
- User flow and navigation patterns
- Component designs and interactions
- Form layouts and validation patterns
These HTML files should be referenced when building Flutter widgets to match the desired design.
Core Features
🔐 Authentication System
Login Flow
Pages: login_page.dart, otp_verification_page.dart, register_page.dart
Features:
- Phone number-based authentication (Vietnamese format)
- 6-digit OTP verification with auto-focus
- Auto-advance between OTP input fields
- Resend OTP with 60-second cooldown timer
- Full registration form with user type selection
- Form validation for all fields
State Management:
final authProvider = AsyncNotifierProvider<AuthNotifier, AuthState>
final otpTimerProvider = StateNotifierProvider<OTPTimerNotifier, int>
Key Widgets:
PhoneInputField: Vietnamese phone number format (+84)OTPInputField: 6-digit auto-focus inputUserTypeSelector: Radio buttons for Contractor/Architect/Distributor/Broker
Design Reference: html/login.html, html/otp.html, html/register.html
🏠 Home Screen with Membership Cards
Purpose: Dashboard showing member tier card and quick access to features
Pages: home_page.dart
Key Features:
-
Membership Card Display:
- Three tier widgets:
DiamondMemberCard,PlatinumMemberCard,GoldMemberCard - Gradient backgrounds (blue-purple for Diamond, grey-silver for Platinum, yellow-gold for Gold)
- Member name, ID, and points balance
- QR code generation for member identification
- Animated card transitions
- Three tier widgets:
-
Quick Action Grid:
- 4-6 icon buttons for main features
- Products, Loyalty, Orders, Projects, Promotions
- Cart badge: Dynamic count from
cartItemCountProvider- Shows cart item count when > 0
- Hidden when cart is empty
- Updates in real-time across all pages
-
Bottom Navigation:
- 5 tabs: Home, Products, Loyalty, Account, More
- Active state indicators
- Badge for notifications
-
Floating Action Button:
- Chat support access
- Positioned bottom-right
- Accent cyan color (#35C6F4)
State Management:
final memberCardProvider = Provider<MemberCard>((ref) {
final user = ref.watch(authProvider).user;
return MemberCard(
tier: user.memberTier,
name: user.name,
memberId: user.id,
points: user.points,
qrCode: generateQRCode(user.id),
);
});
Design Reference: html/index.html
🎁 Loyalty Program System
Main Loyalty Page
Page: loyalty_page.dart
Features:
-
Tier Progress Display:
- Current points and tier
- Progress bar to next tier (%)
- Points needed for next tier
- Animated progress indicator
-
Tier Benefits Cards:
- Points multiplier info
- Special offers access
- Exclusive discounts
- Priority support
-
Quick Actions:
- Navigate to rewards, history, referral, gifts
Widgets:
TierProgressBar: Custom painted progress with gradientPointsBadge: Circular points displayTierBenefitsCard: Expandable card with benefits list
State Management:
final loyaltyPointsProvider = AsyncNotifierProvider<LoyaltyPointsNotifier, LoyaltyPoints>
Design Reference: html/loyalty.html
Rewards Page ✅ IMPLEMENTED
Page: rewards_page.dart
Features:
- Points Balance Card: Gradient blue card showing available points and expiring points
- Category Filter Pills: Horizontal scrollable chips (Tất cả/Voucher/Sản phẩm/Dịch vụ/Ưu đãi đặc biệt)
- Gift Grid: 2-column grid with 6 mock gifts
- Reward Cards (improved UI):
- 120px image with CachedNetworkImage
- Title and description (truncated)
- Points cost and button at bottom (using Spacer())
- Button states: "Đổi quà" (enabled) or "Không đủ điểm" (disabled)
- Redemption Flow:
- Confirmation dialog with gift details and balance after redemption
- Success SnackBar with checkmark icon
- Points deduction via
loyaltyPointsProvider
Widgets (Location: lib/features/loyalty/presentation/):
widgets/points_balance_card.dart: Gradient card with points displaywidgets/reward_card.dart: Individual gift card with bottom-aligned actionpages/rewards_page.dart: Main rewards screen
State Management:
// Providers in lib/features/loyalty/presentation/providers/
@riverpod
class LoyaltyPoints extends _$LoyaltyPoints {
// Manages 9,750 available points, 1,200 expiring
}
@riverpod
class Gifts extends _$Gifts {
// 6 mock gifts matching HTML design
}
@riverpod
List<GiftCatalog> filteredGifts(ref) {
// Filters by selected category
}
final selectedGiftCategoryProvider = StateNotifierProvider...
final hasEnoughPointsProvider = Provider.family<bool, int>...
Navigation:
- Route:
/loyalty/rewards(RouteNames in app_router.dart) - Accessible from home quick action "Đổi quà"
Design Reference: html/loyalty-rewards.html ✅
Points History Page
Page: points_history_page.dart
Features:
- List of all points transactions
- Transaction cards showing:
- Type (earned/spent) with icon and color
- Points amount (+/- display)
- Description
- Date and time
- New balance after transaction
- Filter by date range (Today/Week/Month/All)
- Dispute button for each transaction
- Pull-to-refresh
Widgets:
PointsTransactionCard: Card with transaction detailsDateRangeFilter: Chip filter rowDisputeButton: Opens support dialog
Design Reference: html/points-history.html
Referral Program Page
Page: referral_page.dart
Features:
- User avatar and tier display
- Total referrals count
- Total points earned from referrals
- Referral code (large, copy-able)
- Referral link (copy and share buttons)
- Share sheet integration (WhatsApp, Telegram, etc.)
- Benefits explanation cards
- How it works guide
Widgets:
ReferralInfoCard: Stats displayReferralCodeDisplay: Large code with copy buttonReferralLinkShare: Link with copy/share buttonsReferralShareSheet: Bottom sheet with share options
State Management:
final referralProvider = AsyncNotifierProvider<ReferralNotifier, Referral>
Design Reference: html/referral.html
My Gifts Page
Page: my_gifts_page.dart
Features:
- Tabs: Active (valid), Used, Expired
- Gift cards showing:
- Gift image and title
- Gift code (copy-able)
- Valid from/to dates
- Usage instructions
- Status badge
- Use button (for active gifts)
- Empty state for each tab
- Filter and sort options
Widgets:
GiftCard: Card with gift details and actionsGiftStatusBadge: Color-coded status (green/grey/red)GiftCodeCopy: Code with copy button
Design Reference: html/my-gifts.html
🛍️ Products & Shopping
Products Page
Page: products_page.dart
Features:
- Search bar with real-time filtering
- Category filter chips (horizontal scroll)
- Product grid (2 columns)
- Product cards showing:
- Image with cached_network_image
- Product name and SKU
- Price (with sale price if applicable)
- Stock indicator
- Add to cart button
- Pull-to-refresh
- Infinite scroll pagination
- Empty state
Widgets:
ProductGrid: GridView.builder with paginationProductCard: Card with image, info, and actionsProductSearchBar: Search with clear buttonCategoryFilterChips: Horizontal chip list
State Management:
final productsProvider = AsyncNotifierProvider<ProductsNotifier, List<Product>>
final productSearchProvider = StateProvider<String>
final selectedCategoryProvider = StateProvider<String?>
Design Reference: html/products.html
Cart & Checkout
Pages: cart_page.dart, checkout_page.dart, order_success_page.dart
Cart Features:
- List of cart items
- Item cards with:
- Product image and name
- Price per unit
- Quantity selector (+/-)
- Remove button
- Line total
- Cart summary:
- Subtotal
- Discount (if applied)
- Shipping
- Total
- Clear cart button
- Checkout button
Checkout Features:
- Delivery address selection/entry
- Payment method selection (COD/Bank Transfer/Card/E-wallet)
- Order summary
- Place order button with loading state
- Form validation
Success Features:
- Success animation (Lottie)
- Order number display
- Estimated delivery date
- Order details summary
- Action buttons: View order, Continue shopping
State Management:
final cartProvider = NotifierProvider<CartNotifier, List<CartItem>>
final cartTotalProvider = Provider<double>
Design Reference: html/cart.html, html/checkout.html, html/order-success.html
📦 Orders Management
Pages: orders_page.dart, order_detail_page.dart, payments_page.dart
Orders Features:
- Tab bar for status filtering:
- All, Pending, Processing, Shipping, Completed, Cancelled
- Order cards showing:
- Order number and date
- Customer info (for distributors/brokers)
- Product list (collapsed)
- Total amount
- Status badge (color-coded)
- Action buttons (View details, Track)
- Search by order number
- Filter by date range
- Pull-to-refresh
Order Detail Features:
- Full order information
- Timeline showing order status progression
- Product list with images
- Delivery address
- Payment info
- Action buttons (Contact support, Reorder)
Payments Features:
- List of payment transactions
- Payment cards showing:
- Payment ID
- Order reference
- Amount
- Payment method
- Date
- Status (Processing/Completed)
- Search and filter options
State Management:
final ordersProvider = AsyncNotifierProvider<OrdersNotifier, List<Order>>
final orderFilterProvider = StateProvider<OrderStatus?>
final paymentsProvider = AsyncNotifierProvider<PaymentsNotifier, List<Payment>>
Design Reference: html/orders.html, html/payments.html
🏗️ Projects & Quotes Management
Projects
Pages: projects_page.dart, project_create_page.dart, project_detail_page.dart
Projects Features:
- List of construction projects
- Project cards showing:
- Project name and code
- Client/owner info
- Location
- Start and end dates
- Progress bar (%)
- Status badge (Planning/In Progress/Completed)
- Budget/value
- Create new project FAB
- Filter by status, date, client
- Search projects
Project Create Features:
- Form with fields:
- Project name and code
- Client name and phone
- Location/address
- Start/end dates
- Project type (Residential/Commercial/Industrial)
- Budget
- Description and notes
- Form validation
- Save draft functionality
- Date pickers
- Auto-generate project code option
State Management:
final projectsProvider = AsyncNotifierProvider<ProjectsNotifier, List<Project>>
final projectFormProvider = StateNotifierProvider<ProjectFormNotifier, ProjectFormState>
Design Reference: html/projects.html, html/project-create.html
Quotes
Pages: quotes_page.dart, quote_create_page.dart
Quotes Features:
- List of quotations
- Quote cards showing:
- Quote number and date
- Client info
- Total amount
- Validity period
- Status badge (Draft/Sent/Accepted/Rejected/Expired)
- Actions:
- Create new quote
- Edit draft
- Send to client
- Convert to order
- Duplicate
- Search and filter
Design Reference: html/quotes.html
💬 Chat Support
Pages: chat_page.dart
Features:
- Real-time chat interface
- Message bubbles (sent/received)
- Timestamp for messages
- User avatars
- Typing indicator animation
- Message input with send button
- File attachment button
- Auto-scroll to latest message
- Read receipts
- Support agent info header
Widgets:
MessageBubble: Custom bubble with tailMessageInput: Text field with send buttonTypingIndicator: Animated dotsChatAppBar: Custom app bar with agent info
State Management:
final chatProvider = AsyncNotifierProvider<ChatNotifier, ChatRoom>
final messagesProvider = StreamProvider<List<Message>>
final typingIndicatorProvider = StateProvider<bool>
Design Reference: html/chat.html
👤 Account Management
Account Page
Page: account_page.dart
Features:
- Profile header with avatar, name, tier, points
- Menu sections:
- Personal: Profile, Password, Addresses
- Business: Company info, Tax info
- Settings: Notifications, Language, Theme
- Support: Help, Contact, Terms, Privacy
- App: Version, Logout
- Navigation to sub-pages
- Logout confirmation dialog
Design Reference: html/account.html
Profile Edit
Page: profile_edit_page.dart
Features:
- Avatar upload with image picker
- Image cropping
- Form fields:
- Full name
- Phone (read-only)
- Date of birth
- Gender
- Company name
- Tax ID
- Business address
- User type
- Form validation
- Unsaved changes warning
- Save/cancel buttons
Widgets:
AvatarPicker: Image picker with cropDatePickerField: Date selectionGenderSelector: Radio buttons
Design Reference: html/profile-edit.html
Addresses Management
Pages: addresses_page.dart, address_form_page.dart
Features:
- List of saved addresses
- Address cards with:
- Label (Home/Office/Other)
- Recipient name and phone
- Full address
- Default badge
- Edit/delete actions
- Add new address FAB
- Set as default toggle
- Form with:
- Recipient name
- Phone number
- Address fields (Street, City, District, Ward, Postal code)
- Address type
- Set as default checkbox
- Form validation
Design Reference: html/addresses.html
Change Password
Page: password_change_page.dart
Features:
- Form with:
- Current password
- New password
- Confirm new password
- Show/hide password toggles
- Password strength indicator
- Requirements checklist:
- Min 8 characters
- Uppercase letter
- Lowercase letter
- Number
- Special character
- Real-time validation
- Success message and redirect
Widgets:
PasswordStrengthIndicator: Visual strength meterPasswordRequirements: Checklist with check/cross icons
Design Reference: html/password-change.html
🎉 Promotions & Notifications
Promotions
Page: promotions_page.dart
Features:
- List of active promotions
- Promotion cards with:
- Banner image
- Title and description
- Discount percentage/amount
- Validity period
- Terms and conditions
- Apply/claim button
- Filter by category
- Status indicators (Active/Upcoming/Expired)
Design Reference: html/promotions.html
Notifications
Page: notifications_page.dart
Features:
- Tabs: All, Orders, System, Promotions
- Notification cards with:
- Icon/avatar
- Title and content
- Timestamp
- Read/unread indicator
- Action buttons
- Mark as read
- Clear all button
- Pull-to-refresh
- Badge count on bottom nav
Design Reference: html/notifications.html
UI/UX Design System
Color Palette
// colors.dart
class AppColors {
// Primary
static const primaryBlue = Color(0xFF005B9A);
static const lightBlue = Color(0xFF38B6FF);
static const accentCyan = Color(0xFF35C6F4);
// Status
static const success = Color(0xFF28a745);
static const warning = Color(0xFFffc107);
static const danger = Color(0xFFdc3545);
static const info = Color(0xFF17a2b8);
// Neutrals
static const grey50 = Color(0xFFf8f9fa);
static const grey100 = Color(0xFFe9ecef);
static const grey500 = Color(0xFF6c757d);
static const grey900 = Color(0xFF343a40);
// Tier Gradients
static const diamondGradient = LinearGradient(
colors: [Color(0xFF4A00E0), Color(0xFF8E2DE2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
static const platinumGradient = LinearGradient(
colors: [Color(0xFF7F8C8D), Color(0xFFBDC3C7)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
static const goldGradient = LinearGradient(
colors: [Color(0xFFf7b733), Color(0xFFfc4a1a)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
}
Typography
// typography.dart
class AppTypography {
static const fontFamily = 'Roboto';
static const displayLarge = TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
fontFamily: fontFamily,
);
static const headlineLarge = TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
fontFamily: fontFamily,
);
static const titleLarge = TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
fontFamily: fontFamily,
);
static const bodyLarge = TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: fontFamily,
);
static const labelSmall = TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
fontFamily: fontFamily,
);
}
Component Specifications
Member Card Design
class MemberCardSpecs {
static const double width = double.infinity;
static const double height = 200;
static const double borderRadius = 16;
static const double elevation = 8;
static const EdgeInsets padding = EdgeInsets.all(20);
// QR Code
static const double qrSize = 80;
static const double qrBackgroundSize = 90;
// Points Display
static const double pointsFontSize = 28;
static const FontWeight pointsFontWeight = FontWeight.bold;
}
Status Badges
class StatusBadge extends StatelessWidget {
final String status;
final Color color;
static Color getColorForStatus(OrderStatus status) {
switch (status) {
case OrderStatus.pending:
return AppColors.info;
case OrderStatus.processing:
return AppColors.warning;
case OrderStatus.shipping:
return AppColors.lightBlue;
case OrderStatus.completed:
return AppColors.success;
case OrderStatus.cancelled:
return AppColors.danger;
}
}
}
Bottom Navigation
class BottomNavSpecs {
static const double height = 72;
static const double iconSize = 24;
static const double selectedIconSize = 28;
static const double labelFontSize = 12;
static const Color selectedColor = AppColors.primaryBlue;
static const Color unselectedColor = AppColors.grey500;
}
Floating Action Button
class FABSpecs {
static const double size = 56;
static const double elevation = 6;
static const Color backgroundColor = AppColors.accentCyan;
static const Color iconColor = Colors.white;
static const double iconSize = 24;
static const Offset position = Offset(16, 16); // from bottom-right
}
AppBar (Standardized across all pages)
class AppBarSpecs {
// From ui_constants.dart
static const double elevation = 0.5;
// Standard pattern for all pages
static AppBar standard({
required String title,
required VoidCallback onBack,
List<Widget>? actions,
}) {
return AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
onPressed: onBack,
),
title: Text(title, style: const TextStyle(color: Colors.black)),
elevation: elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
centerTitle: false,
actions: [
...?actions,
const SizedBox(width: AppSpacing.sm),
],
);
}
}
Usage Notes:
- ALL pages use this standard AppBar pattern
- Back arrow is always black with explicit color
- Title is always left-aligned (
centerTitle: false) - Title text is always black
- Background is always white
- Actions always end with
SizedBox(width: AppSpacing.sm)spacing - For SliverAppBar, add
pinned: trueproperty
Technical Architecture
State Management (Riverpod 2.x)
Authentication State
@riverpod
class Auth extends _$Auth {
@override
Future<AuthState> build() async {
final token = await _getStoredToken();
if (token != null) {
final user = await _getUserFromToken(token);
return AuthState.authenticated(user);
}
return const AuthState.unauthenticated();
}
Future<void> loginWithPhone(String phone) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
await ref.read(authRepositoryProvider).requestOTP(phone);
return AuthState.otpSent(phone);
});
}
Future<void> verifyOTP(String phone, String otp) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
final response = await ref.read(authRepositoryProvider).verifyOTP(phone, otp);
await _storeToken(response.token);
return AuthState.authenticated(response.user);
});
}
}
Domain Entities & Data Models
The app follows clean architecture with domain entities and Hive data models based on the database schema in database.md.
Domain Entities (28 files)
Pure business logic entities with no external dependencies. All entities use freezed for immutability.
Auth Feature (lib/features/auth/domain/entities/)
user.dart- User with role, status, loyalty tier, company infouser_session.dart- User session with device tracking
Products Feature (lib/features/products/domain/entities/)
product.dart- Product with images, specs, 360 view, ERPNext integrationstock_level.dart- Inventory tracking (available/reserved/ordered)category.dart- Product categories
Cart Feature (lib/features/cart/domain/entities/)
cart.dart- Shopping cart with sync statuscart_item.dart- Cart line items
Orders Feature (lib/features/orders/domain/entities/)
order.dart- Orders with status, addresses, ERPNext integrationorder_item.dart- Order line items with discountsinvoice.dart- Invoices with type, status, payment trackingpayment_line.dart- Payment transactions with method and status
Loyalty Feature (lib/features/loyalty/domain/entities/)
loyalty_point_entry.dart- Points transactions with type, source, complaintsgift_catalog.dart- Redeemable gifts with category, points costredeemed_gift.dart- User's redeemed gifts with voucher codespoints_record.dart- Invoice submissions for manual points
Projects Feature (lib/features/projects/domain/entities/)
project_submission.dart- Completed project submissions with photosdesign_request.dart- Design consultation requests
Quotes Feature (lib/features/quotes/domain/entities/)
quote.dart- Quotations with status, validity, conversion trackingquote_item.dart- Quote line items with price negotiation
Chat Feature (lib/features/chat/domain/entities/)
chat_room.dart- Chat rooms with type, participantsmessage.dart- Messages with content type, attachments, read status
Notifications Feature (lib/features/notifications/domain/entities/)
notification.dart- User notifications with type-based data
Showrooms Feature (lib/features/showrooms/domain/entities/)
showroom.dart- Virtual showrooms with 360 views, galleryshowroom_product.dart- Products used in showrooms
Account Feature (lib/features/account/domain/entities/)
payment_reminder.dart- Payment reminders with schedulingaudit_log.dart- System audit trail
Home Feature (lib/features/home/domain/entities/)
member_card.dart- Membership card displaypromotion.dart- Promotional campaigns
Hive Data Models (25 files)
Hive CE models for offline-first local storage. All models extend HiveObject with proper type adapters.
Type ID Allocation:
- Models: 0-24 (user_model=0, user_session_model=1, product_model=2, etc.)
- Enums: 30-50 (UserRole=30, UserStatus=31, LoyaltyTier=32, etc.)
Model Features:
@HiveTypewith unique typeId@HiveFieldfor all propertiesfromJson()/toJson()for API serializationtoEntity()/fromEntity()for domain conversion- Helper methods for JSONB fields
- Full documentation
All models are located in: lib/features/*/data/models/
- Auth:
user_model.dart,user_session_model.dart - Products:
product_model.dart,stock_level_model.dart - Cart:
cart_model.dart,cart_item_model.dart - Orders:
order_model.dart,order_item_model.dart,invoice_model.dart,payment_line_model.dart - Loyalty:
loyalty_point_entry_model.dart,gift_catalog_model.dart,redeemed_gift_model.dart,points_record_model.dart - Projects:
project_submission_model.dart,design_request_model.dart - Quotes:
quote_model.dart,quote_item_model.dart - Chat:
chat_room_model.dart,message_model.dart - Notifications:
notification_model.dart - Showrooms:
showroom_model.dart,showroom_product_model.dart - Account:
payment_reminder_model.dart,audit_log_model.dart
Enums (21 types)
All enums are defined in lib/core/database/models/enums.dart with Hive type adapters:
User & Auth:
UserRole- admin, customer, contractor, architect, distributor, brokerUserStatus- active, inactive, pending, suspended, bannedLoyaltyTier- diamond, platinum, gold
Orders & Payments:
OrderStatus- draft, pending, confirmed, processing, shipped, delivered, completed, cancelled, returned, refundedInvoiceType- sales, proforma, credit_note, debit_noteInvoiceStatus- draft, sent, viewed, overdue, paid, partially_paid, cancelledPaymentMethod- cash, bank_transfer, credit_card, debit_card, e_wallet, codPaymentStatus- pending, processing, completed, failed, refunded
Loyalty & Gifts:
EntryType- earn, spend, adjust, expire, reversalEntrySource- purchase, referral, promotion, bonus, manual, project_submission, design_request, points_recordComplaintStatus- pending, reviewing, approved, rejected, resolvedGiftCategory- voucher, product, service, experience, discountGiftStatus- active, used, expired, cancelledPointsStatus- pending, approved, rejected
Projects & Quotes:
ProjectType- residential, commercial, industrial, hospitality, retail, office, otherSubmissionStatus- pending, reviewing, approved, rejectedDesignStatus- submitted, assigned, in_progress, completed, delivered, revision_requested, approved, cancelledQuoteStatus- draft, sent, viewed, negotiating, accepted, rejected, expired, converted
Chat:
RoomType- support, sales, quote, orderContentType- text, image, file, product, locationReminderType- payment_due, overdue, final_notice, custom
Detailed Documentation:
- See
DOMAIN_ENTITIES_SUMMARY.mdfor entity details - See
HIVE_MODELS_REFERENCE.mdfor model templates and usage - See
lib/core/constants/storage_constants.dartfor Type ID reference
Performance Optimization
Image Caching
// Use cached_network_image for all remote images
CachedNetworkImage(
imageUrl: product.images.first,
placeholder: (context, url) => const ShimmerPlaceholder(),
errorWidget: (context, url, error) => const Icon(Icons.error),
fit: BoxFit.cover,
memCacheWidth: 400, // Optimize memory usage
fadeInDuration: const Duration(milliseconds: 300),
)
List Performance
// Use ListView.builder with RepaintBoundary for long lists
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return RepaintBoundary(
child: ProductCard(product: items[index]),
);
},
cacheExtent: 1000, // Pre-render items
)
// Use AutomaticKeepAliveClientMixin for expensive widgets
class ProductCard extends StatefulWidget {
@override
State<ProductCard> createState() => _ProductCardState();
}
class _ProductCardState extends State<ProductCard>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Card(...);
}
}
State Optimization
// Use .select() to avoid unnecessary rebuilds
final userName = ref.watch(authProvider.select((state) => state.user?.name));
// Use family modifiers for parameterized providers
@riverpod
Future<Product> product(ProductRef ref, String id) async {
return await ref.read(productRepositoryProvider).getProduct(id);
}
// Keep providers outside build method
final productsProvider = ...;
class ProductsPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final products = ref.watch(productsProvider);
return ...;
}
}
Offline Strategy
Data Sync Flow
@riverpod
class DataSync extends _$DataSync {
@override
Future<SyncStatus> build() async {
// Listen to connectivity changes
ref.listen(connectivityProvider, (previous, next) {
if (next == ConnectivityStatus.connected) {
syncData();
}
});
return SyncStatus.idle;
}
Future<void> syncData() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
// Sync in order of dependency
await _syncUserData();
await _syncProducts();
await _syncOrders();
await _syncProjects();
await _syncLoyaltyData();
await ref.read(settingsRepositoryProvider).updateLastSyncTime();
return SyncStatus.success;
});
}
Future<void> _syncUserData() async {
final user = await ref.read(authRepositoryProvider).getCurrentUser();
await ref.read(authLocalDataSourceProvider).saveUser(user);
}
Future<void> _syncProducts() async {
final products = await ref.read(productRepositoryProvider).getAllProducts();
await ref.read(productLocalDataSourceProvider).saveProducts(products);
}
// ... other sync methods
}
Offline Queue
// Queue failed requests for retry when online
class OfflineQueue {
final HiveInterface hive;
late Box<Map> _queueBox;
Future<void> init() async {
_queueBox = await hive.openBox('offline_queue');
}
Future<void> addToQueue(ApiRequest request) async {
await _queueBox.add({
'endpoint': request.endpoint,
'method': request.method,
'body': request.body,
'timestamp': DateTime.now().toIso8601String(),
});
}
Future<void> processQueue() async {
final requests = _queueBox.values.toList();
for (var i = 0; i < requests.length; i++) {
try {
await _executeRequest(requests[i]);
await _queueBox.deleteAt(i);
} catch (e) {
// Keep in queue for next retry
}
}
}
}
Localization (Vietnamese Primary)
Setup
// l10n.yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
// lib/l10n/app_vi.arb (Vietnamese)
{
"@@locale": "vi",
"appTitle": "Worker App",
"login": "Đăng nhập",
"phone": "Số điện thoại",
"enterPhone": "Nhập số điện thoại",
"continue": "Tiếp tục",
"verifyOTP": "Xác thực OTP",
"enterOTP": "Nhập mã OTP 6 số",
"resendOTP": "Gửi lại mã",
"home": "Trang chủ",
"products": "Sản phẩm",
"loyalty": "Hội viên",
"account": "Tài khoản",
"points": "Điểm",
"cart": "Giỏ hàng",
"checkout": "Thanh toán",
"orders": "Đơn hàng",
"projects": "Công trình",
"quotes": "Báo giá",
"myGifts": "Quà của tôi",
"referral": "Giới thiệu bạn bè",
"pointsHistory": "Lịch sử điểm"
}
// lib/l10n/app_en.arb (English)
{
"@@locale": "en",
"appTitle": "Worker App",
"login": "Login",
"phone": "Phone Number",
"enterPhone": "Enter phone number",
"continue": "Continue",
...
}
Usage
class LoginPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(l10n.login),
),
body: Column(
children: [
TextField(
decoration: InputDecoration(
labelText: l10n.phone,
hintText: l10n.enterPhone,
),
),
ElevatedButton(
onPressed: () {},
child: Text(l10n.continue),
),
],
),
);
}
}
Deployment
Android
// android/app/build.gradle
android {
compileSdkVersion 34
defaultConfig {
applicationId "com.eurotile.worker"
minSdkVersion 21
targetSdkVersion 34
versionCode 1
versionName "1.0.0"
}
signingConfigs {
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
iOS
# ios/Podfile
platform :ios, '13.0'
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
end
Development Workflow
Feature Development Process
- Review HTML Reference: Check
html/folder for design spec - Design Data Layer: Models, repositories, data sources
- Implement Domain Layer: Entities, use cases
- Create Providers: Riverpod state management
- Build UI: Match HTML (in 375px width) reference design
- Test: Unit, widget, integration tests
- Optimize: Performance profiling
Code Review Checklist
- Matches HTML reference design
- Follows clean architecture
- Proper error handling
- Online-first approach
- Performance optimized
- Proper state management with Riverpod
- Hive models properly defined
- Vietnamese localization
- Tests written and passing
- Code documented
Roadmap
Phase 1 - Core Features ✅
- ✅ Authentication (login, OTP, register)
- ✅ Home with member cards (3 tiers)
- ✅ Product browsing with search and filters
- ✅ Shopping cart with dynamic badge
- ✅ Favorites system with Hive persistence
- ✅ Order management
- ✅ Project and quote management
- ✅ Account management
- ✅ Promotions with detail pages
Phase 1.5 - Loyalty System ✅ RECENT
- ✅ Rewards/Gift Redemption Page (Dec 2024)
- Points balance card with gradient
- Category filtering (Voucher/Product/Service/Discount)
- 2-column gift grid with 6 mock items
- Redemption flow with confirmation dialog
- Points deduction and success feedback
- ✅ UI Standardization (Dec 2024)
- All AppBars now follow consistent pattern
- Dynamic cart badge across all pages
- Hive Box best practices documented
- 🔄 Points history page (planned)
- 🔄 Referral program page (planned)
- 🔄 My gifts page (planned)
- 🔄 Chat support (planned)
Phase 2 - Backend Integration 🔄
- REST API integration
- Real-time WebSocket for chat
- Push notifications (FCM)
- Payment gateway
- Cloud image storage
- Analytics tracking
Phase 3 - Advanced Features 📋
- QR code scanner (loyalty & products)
- Barcode scanning
- Geolocation for nearby stores
- Photo gallery for projects
- PDF report generation
- Biometric authentication
- Offline mode with background sync
- AR product visualization
Remember: ALWAYS DELEGATE TO SPECIALISTS FOR BETTER RESULTS!
When working on this Flutter Worker app:
- UI Tasks → flutter-widget-expert
- State Management → riverpod-expert
- Database/Caching → hive-expert
- API Integration → api-integration-expert
- Architecture Decisions → architecture-expert
- Performance Issues → performance-expert
Think delegation first, implementation second!
Recent Updates & Implementation Notes (December 2024)
✅ Rewards/Gift Redemption System
Status: Fully implemented with mock data
Implementation Details:
-
Providers (
lib/features/loyalty/presentation/providers/):loyalty_points_provider.dart- Manages user points (9,750 available, 1,200 expiring)gifts_provider.dart- 6 mock gifts matching HTML designselectedGiftCategoryProvider- Category filter statefilteredGiftsProvider- Category-based filteringhasEnoughPointsProvider.family- Points validation per gift
-
Widgets (
lib/features/loyalty/presentation/widgets/):points_balance_card.dart- Gradient blue card with points displayreward_card.dart- Gift card with bottom-aligned action button
-
Pages (
lib/features/loyalty/presentation/pages/):rewards_page.dart- Main screen with RefreshIndicator
-
Route:
/loyalty/rewardsinapp_router.dart
Key Features:
- 2-column grid layout with
childAspectRatio: 0.7 - Category filtering: Tất cả/Voucher/Sản phẩm/Dịch vụ/Ưu đãi đặc biệt
- Bottom-aligned buttons using
Expanded+Spacer() - Redemption dialog with points calculation
- Success feedback with SnackBar
✅ AppBar Standardization
Status: Completed across all pages
Standard Pattern:
AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => context.pop(),
),
title: const Text('Title', style: TextStyle(color: Colors.black)),
elevation: AppBarSpecs.elevation,
backgroundColor: AppColors.white,
foregroundColor: AppColors.grey900,
centerTitle: false,
actions: [..., const SizedBox(width: AppSpacing.sm)],
)
Updated Pages:
cart_page.dart- Lines 84-103favorites_page.dart- Lines 79-115rewards_page.dart- Lines 35-48promotion_detail_page.dart- Lines 59-86 (loading/error), 130-161 (SliverAppBar)product_detail_page.dart- Already correct ✅
✅ Dynamic Cart Badge
Status: Implemented across home and products pages
Implementation:
// Added provider in cart_provider.dart
@riverpod
int cartItemCount(CartItemCountRef ref) {
final cartState = ref.watch(cartProvider);
return cartState.items.fold(0, (sum, item) => sum + item.quantity);
}
// Used in home_page.dart and products_page.dart
final cartItemCount = ref.watch(cartItemCountProvider);
QuickAction(
badge: cartItemCount > 0 ? '$cartItemCount' : null,
)
Behavior:
- Shows total quantity across all cart items
- Hidden when cart is empty
- Updates in real-time via Riverpod
- Navigation via
RouteNames.cartconstant
✅ Hive Box Type Management
Status: Best practices documented and implemented
Problem Solved:
HiveError: The box "favorite_box" is already open and of type Box<dynamic>
Solution Applied:
- All data sources now use
Box<dynamic>getters - Type-safe queries via
.whereType<T>() - Applied to
favorites_local_datasource.dart
Pattern:
Box<dynamic> get _box => Hive.box<dynamic>(boxName);
Future<List<FavoriteModel>> getAllFavorites() async {
return _box.values
.whereType<FavoriteModel>() // Type-safe!
.where((fav) => fav.userId == userId)
.toList();
}
🔄 Next Steps (Planned)
- Points history page with transaction list
- Referral program page with share functionality
- My gifts page with tabs (Active/Used/Expired)
- Backend API integration for loyalty endpoints
- Real redemption flow with gift codes
📝 Code Quality Checklist
All recent implementations follow:
- ✅ Clean architecture (data/domain/presentation)
- ✅ Riverpod state management
- ✅ Hive for local persistence
- ✅ Material 3 design system
- ✅ Vietnamese localization
- ✅ AppBar standardization
- ✅ CachedNetworkImage for all remote images
- ✅ Proper error handling
- ✅ Loading states (CircularProgressIndicator)
- ✅ Empty states with helpful messages