feat: lang

This commit is contained in:
efrilm 2025-08-20 13:52:49 +07:00
parent f07d07b3a8
commit 5a83bc4049
53 changed files with 3387 additions and 722 deletions

View File

@ -49,5 +49,385 @@
"profile": "Profile",
"@profile": {},
"sales_today": "Sales today",
"@sales_today": {}
"@sales_today": {},
"order": "Order",
"@order": {},
"sales": "Sales",
"@sales": {},
"finance": "Finance",
"@finance": {},
"product": "Product",
"@product": {},
"form": "Form",
"@form": {},
"schedule": "Schedule",
"@schedule": {},
"inventory": "Inventory",
"@inventory": {},
"customer": "Customer",
"@customer": {},
"purchase": "Purchase",
"@purchase": {},
"today_summary": "Today's Summary",
"@today_summary": {},
"today": "Today",
"@today": {},
"new_customer": "New Customer",
"@new_customer": {},
"refund": "Refund",
"@refund": {},
"void_text": "Void",
"@void_text": {},
"increase": "Increase",
"@increase": {},
"today_top_product": "Today's Top Product",
"@today_top_product": {},
"rank": "Rank",
"@rank": {},
"quantity_sold": "Quantity Sold",
"@quantity_sold": {},
"total_orders": "Total Orders",
"@total_orders": {},
"average_price": "Average Price",
"@average_price": {},
"perfomance": "Performance",
"@perfomance": {},
"total_sales": "Total Sales",
"@total_sales": {},
"total_items": "Total Items",
"@total_items": {},
"summary": "Summary",
"@summary": {},
"net_sales": "Net Sales",
"@net_sales": {},
"daily_breakdown": "Daily Breakdown",
"@daily_breakdown": {},
"orders": "Orders",
"@orders": {},
"items": "Items",
"@items": {},
"tax": "Tax",
"@tax": {},
"discount": "Discount",
"@discount": {},
"total_purchase": "Total Purchase",
"@total_purchase": {},
"pending_order": "Pending Order",
"@pending_order": {},
"history_purchase": "History Purchase",
"@history_purchase": {},
"all": "All",
"@all": {},
"select_date_range": "Select Date Range",
"@select_date_range": {},
"no_date_selected": "No date has been selected yet",
"@no_date_selected": {},
"selected_date": "Selected Date",
"@selected_date": {},
"select": "Select",
"@select": {},
"cancel": "Cancel",
"@cancel": {},
"total_revenue": "Total Revenue",
"@total_revenue": {},
"total_expenditures": "Total Expenditures",
"@total_expenditures": {},
"net_profit": "Net Profit",
"@net_profit": {},
"margin_profit": "Margin Profit",
"@margin_profit": {},
"cash_flow_analysis": "Cash Flow Analysis",
"@cash_flow_analysis": {},
"cash_in": "Cash In",
"@cash_in": {},
"cash_out": "Cash Out",
"@cash_out": {},
"net_flow": "Net Flow",
"@net_flow": {},
"cash_flow_chart": "Cash Flow Chart for {days} Last Days",
"@cash_flow_chart": {
"placeholders": {
"days": {
"type": "int",
"example": "7"
}
}
},
"profit_loss_detail": "Profit & Loss Details",
"@profit_loss_detail": {},
"gross_sales": "Gross Sales",
"@gross_sales": {},
"return_text": "Return",
"@return_text": {},
"cogs": "COGS",
"@cogs": {},
"cost_of_goods_sold": "Cost of goods sold",
"@cost_of_goods_sold": {},
"gross_profit": "Gross Profit",
"@gross_profit": {},
"operating_costs": "Operating Costs",
"@operating_costs": {},
"sales_category": "Sales Category",
"@sales_category": {},
"unit": "Unit",
"@unit": {},
"category_no_data": "There are no data categories yet",
"@category_no_data": {},
"category_no_data_desc": "Sales category data will appear here",
"@category_no_data_desc": {},
"product_analytic": "Product Analytic",
"@product_analytic": {},
"view_all": "View All",
"@view_all": {},
"sold": "Sold",
"@sold": {},
"revenue": "Revenue",
"@revenue": {},
"cost": "Cost",
"@cost": {},
"profit_per_unit": "Profit per unit",
"@profit_per_unit": {},
"total_sold": "Total Sold",
"@total_sold": {},
"ingredients": "Ingredients",
"@ingredients": {},
"low_stock": "Low Stock",
"@low_stock": {},
"zero_stock": "Zero Stock",
"@zero_stock": {},
"stock": "Stock",
"@stock": {},
"price": "Price",
"@price": {},
"out_of_stock": "Out of stock",
"@out_of_stock": {},
"out_of_stock_desc": "Product not available for sale",
"@out_of_stock_desc": {},
"in_text": "In",
"@in_text": {},
"out_text": "Out",
"@out_text": {},
"available": "Available",
"@available": {},
"total_products": "Total Products",
"@total_products": {},
"total_ingredients": "Total Ingredients",
"@total_ingredients": {},
"products": "Products",
"@products": {},
"value_text": "Value",
"@value_text": {},
"low_stock_desc": "Immediately reorder at least {stock} pcs",
"@low_stock_desc": {
"placeholders": {
"stock": {
"type": "String",
"example": "0"
}
}
},
"joined": "Joined",
"@joined": {},
"ago": "ago",
"@ago": {},
"active": "Active",
"@active": {},
"inactive": "Inactive",
"@inactive": {},
"total_amount": "Total Amount",
"@total_amount": {},
"table": "Table",
"@table": {},
"remaining": "Remaining",
"@remaining": {},
"payment": "Payment",
"@payment": {},
"completed": "Completed",
"@completed": {},
"pending": "Pending",
"@pending": {},
"no_order_with_status": "No {status} orders found",
"@no_order_with_status": {
"placeholders": {
"status": {
"type": "String",
"example": "pending"
}
}
},
"order_details": "Order Details",
"@order_details": {},
"order_number": "Order Number",
"@order_number": {},
"order_status": "Order Status",
"@order_status": {},
"order_information": "Order Information",
"@order_information": {},
"order_type": "Order Type",
"@order_type": {},
"payment_status": "Payment Status",
"@payment_status": {},
"created": "Created",
"@created": {},
"order_item": "Order Item",
"@order_item": {},
"item": "Item",
"@item": {},
"each": "Each",
"@each": {},
"total_item": "Total Item",
"@total_item": {},
"payment_summary": "Payment Summary",
"@payment_summary": {},
"subtotal": "Subtotal",
"@subtotal": {},
"paid": "Paid",
"@paid": {},
"total": "Total",
"@total": {},
"payment_method": "Payment Method",
"@payment_method": {},
"dine_in": "Dine In",
"@dine_in": {},
"dine_in_experience": "Dine In Experience",
"@dine_in_experience": {},
"note": "Note",
"@note": {},
"sales_chart": "Sales Chart",
"@sales_chart": {},
"no_data_available": "No Data Avaiable",
"@no_data_available": {},
"total_days_overview": "{days} days overview",
"@total_days_overview": {
"placeholders": {
"days": {
"type": "int",
"example": "0"
}
}
},
"sales_data": "Sales Data",
"@sales_data": {},
"no_sales_data": "No Sales Data",
"@no_sales_data": {},
"no_sales_data_desc": "Sales data will appear here once transactions are recorded",
"@no_sales_data_desc": {},
"payment_methods": "Payment Methods",
"@payment_methods": {},
"payment_methods_desc": "Revenue breakdown by payment method ",
"@payment_methods_desc": {},
"revenue_share": "Revenue Share",
"@revenue_share": {},
"no_payment_methods": "No Payment Methods",
"@no_payment_methods": {},
"no_payment_methods_desc": "Payment method data will appear here once transactions are made",
"@no_payment_methods_desc": {},
"best_selling_products": "Best Selling Products",
"@best_selling_products": {},
"highest_sales_ranking": "Highest sales ranking",
"@highest_sales_ranking": {},
"best_seller": "Best Seller",
"@best_seller": {},
"top_performer": "Top Performer",
"@top_performer": {},
"account_information": "Account Information",
"@account_information": {},
"member_since": "Member Since",
"@member_since": {},
"edit_profile": "Edit Profile",
"@edit_profile": {},
"edit_profile_desc": "Update your profile information",
"@edit_profile_desc": {},
"change_password": "Change Password",
"@change_password": {},
"change_password_desc": "Update your password",
"@change_password_desc": {},
"business_settings": "Business Settings",
"@business_settings": {},
"outlet_information": "Outlet Information",
"@outlet_information": {},
"outlet_informatio_desc": "Manage your outlet details",
"@outlet_informatio_desc": {},
"staff_management": "Staff Management",
"@staff_management": {},
"staff_management_desc": "Manage your staff",
"@staff_management_desc": {},
"manage_your_products": "Manage Your Products",
"@manage_your_products": {},
"download_report": "Download Report",
"@download_report": {},
"download_report_desc": "Download your sales report or inventory report",
"@download_report_desc": {},
"app_settings": "App Settings",
"@app_settings": {},
"language_desc": "Select your preferred language",
"@language_desc": {},
"support": "Support",
"@support": {},
"help_center": "Help Center",
"@help_center": {},
"help_center_desc": "Get help from our support team",
"@help_center_desc": {},
"about": "About",
"@about": {},
"about_desc": "Learn more about our app",
"@about_desc": {},
"logout": "Logout",
"@logout": {},
"logout_desc": "Logout of your account",
"@logout_desc": {},
"save": "Save",
"@save": {},
"name": "Name",
"@name": {},
"name_placeholder": "Please enter your name",
"@name_placeholder": {},
"password_changed": "Password Changed",
"@password_changed": {},
"current_password": "Current Password",
"@current_password": {},
"current_password_placeholder": "Please enter your current password",
"@current_password_placeholder": {},
"new_password": "New Password",
"@new_password": {},
"new_password_placeholder": "Please enter your new password",
"@new_password_placeholder": {},
"new_password_not_same": "New password cannot be same as current password",
"@new_password_not_same": {},
"general_information": "General Information",
"@general_information": {},
"address": "Address",
"@address": {},
"phone_number": "Phone Number",
"@phone_number": {},
"currency": "Currency",
"@currency": {},
"tax_rate": "Tax Rate",
"@tax_rate": {},
"status_text": "Status",
"@status_text": {},
"coming_soon": "Coming Soon",
"@coming_soon": {},
"coming_soon_desc": "Something amazing is brewing!\nStay tuned for the big reveal.",
"@coming_soon_desc": {},
"transaction_report": "Transaction Report",
"@transaction_report": {},
"transaction_report_desc": "Export all transaction data with detailed analytics",
"@transaction_report_desc": {},
"invetory_report": "Inventory Report",
"@invetory_report": {},
"invetory_report_desc": "Export inventory and stock data with trends",
"@invetory_report_desc": {},
"about_app": "About App",
"@about_app": {},
"app_information": "App Information",
"@app_information": {},
"app_name": "App Name",
"@app_name": {},
"build_number": "Build Number",
"@build_number": {},
"package_name": "Package Name",
"@package_name": {},
"device": "Device",
"@device": {}
}

View File

@ -49,5 +49,385 @@
"profile": "Profil",
"@profile": {},
"sales_today": "Penjualan hari ini",
"@sales_today": {}
"@sales_today": {},
"order": "Pesanan",
"@order": {},
"sales": "Penjualan",
"@sales": {},
"finance": "Keuangan",
"@finance": {},
"product": "Produk",
"@product": {},
"form": "Form",
"@form": {},
"schedule": "Jadwal",
"@schedule": {},
"inventory": "Inventaris",
"@inventory": {},
"customer": "Pelanggan",
"@customer": {},
"purchase": "Pembelian",
"@purchase": {},
"today_summary": "Ringkasan Hari Ini",
"@today_summary": {},
"today": "Hari ini",
"@today": {},
"new_customer": "Pelanggan baru",
"@new_customer": {},
"refund": "Pengembalian dana",
"@refund": {},
"void_text": "Dibatalkan",
"@void_text": {},
"increase": "Bertambah",
"@increase": {},
"today_top_product": "Produk teratas hari ini",
"@today_top_product": {},
"rank": "Pangkat",
"@rank": {},
"quantity_sold": "Kuantiti Terjual",
"@quantity_sold": {},
"total_orders": "Jumlah Pesanan",
"@total_orders": {},
"average_price": "Harga Rata-rata",
"@average_price": {},
"perfomance": "Performa",
"@perfomance": {},
"total_sales": "Jumlah Penjualan",
"@total_sales": {},
"total_items": "Jumlah Barang",
"@total_items": {},
"summary": "Ringkasan",
"@summary": {},
"net_sales": "Penjualan Bersih",
"@net_sales": {},
"daily_breakdown": "Perincian Harian",
"@daily_breakdown": {},
"orders": "Pesanan",
"@orders": {},
"items": "Barang",
"@items": {},
"tax": "Pajak",
"@tax": {},
"discount": "Diskon",
"@discount": {},
"total_purchase": "Jumlah Pembelian",
"@total_purchase": {},
"pending_order": "Pesanan Menunggu",
"@pending_order": {},
"history_purchase": "Riwayat Pembelian",
"@history_purchase": {},
"all": "Semua",
"@all": {},
"select_date_range": "Pilih Rentang Tanggal",
"@select_date_range": {},
"no_date_selected": "Belum ada tanggal dipilih",
"@no_date_selected": {},
"selected_date": "Tanggal Terpilih",
"@selected_date": {},
"select": "Pilih",
"@select": {},
"cancel": "Batal",
"@cancel": {},
"total_revenue": "Jumlah Pendapatan",
"@total_revenue": {},
"total_expenditures": "Jumlah Pengeluaran",
"@total_expenditures": {},
"net_profit": "Keuntungan Bersih",
"@net_profit": {},
"margin_profit": "Keuntungan Margin",
"@margin_profit": {},
"cash_flow_analysis": "Analisis Arus Kas",
"@cash_flow_analysis": {},
"cash_in": "Uang Masuk",
"@cash_in": {},
"cash_out": "Uang Keluar",
"@cash_out": {},
"net_flow": "Arus Bersih",
"@net_flow": {},
"cash_flow_chart": "Grafik Cash Flow ${days} Hari Terakhir",
"@cash_flow_chart": {
"placeholders": {
"days": {
"type": "int",
"example": "7"
}
}
},
"profit_loss_detail": "Detail Untung & Rugi",
"@profit_loss_detail": {},
"gross_sales": "Penjualan Kotor",
"@gross_sales": {},
"return_text": "Retur",
"@return_text": {},
"cogs": "HPP",
"@cogs": {},
"cost_of_goods_sold": "Harga Pokok Penjualan",
"@cost_of_goods_sold": {},
"gross_profit": "Keuntungan Kotor",
"@gross_profit": {},
"operating_costs": "Biaya Operasional",
"@operating_costs": {},
"sales_category": "Kategori Penjualan",
"@sales_category": {},
"unit": "Unit",
"@unit": {},
"category_no_data": "Belum ada data kategori",
"@category_no_data": {},
"category_no_data_desc": "Data kategori penjualan akan muncul di sini",
"@category_no_data_desc": {},
"product_analytic": "Analisis Produk",
"@product_analytic": {},
"view_all": "Lihat Semua",
"@view_all": {},
"sold": "Terjual",
"@sold": {},
"revenue": "Pendapatan",
"@revenue": {},
"cost": "Biaya",
"@cost": {},
"profit_per_unit": "Keuntungan per unit",
"@profit_per_unit": {},
"total_sold": "Jumlah Terjual",
"@total_sold": {},
"ingredients": "Bahan Baku",
"@ingredients": {},
"low_stock": "Stok Rendah",
"@low_stock": {},
"zero_stock": "Stok Kosong",
"@zero_stock": {},
"stock": "Stok",
"@stock": {},
"price": "Harga",
"@price": {},
"out_of_stock": "Stok habis",
"@out_of_stock": {},
"out_of_stock_desc": "Produk tidak tersedia untuk dijual",
"@out_of_stock_desc": {},
"in_text": "Masuk",
"@in_text": {},
"out_text": "Keluar",
"@out_text": {},
"available": "Tersedia",
"@available": {},
"total_products": "Jumlah Produk",
"@total_products": {},
"total_ingredients": "Jumlah Bahan Baku",
"@total_ingredients": {},
"products": "Produk",
"@products": {},
"value_text": "Nilai",
"@value_text": {},
"low_stock_desc": "Segera reorder minimal {stock} pcs",
"@low_stock_desc": {
"placeholders": {
"stock": {
"type": "String",
"example": "0"
}
}
},
"joined": "Bergabung",
"@joined": {},
"ago": "lalu",
"@ago": {},
"active": "Aktif",
"@active": {},
"inactive": "Tidak Aktif",
"@inactive": {},
"total_amount": "Jumlah Total",
"@total_amount": {},
"table": "Meja",
"@table": {},
"remaining": "Sisa",
"@remaining": {},
"payment": "Pembayaran",
"@payment": {},
"completed": "Selesai",
"@completed": {},
"pending": "Menunggu",
"@pending": {},
"no_order_with_status": "Tidak ada pesanan {status} yang ditemukan",
"@no_order_with_status": {
"placeholders": {
"status": {
"type": "String",
"example": "pending"
}
}
},
"order_details": "Detail Pesanan",
"@order_details": {},
"order_number": "Nomor Pesanan",
"@order_number": {},
"order_status": "Status Pesanan",
"@order_status": {},
"order_information": "Informasi Pesanan",
"@order_information": {},
"order_type": "Tipe Pesanan",
"@order_type": {},
"payment_status": "Status Pembayaran",
"@payment_status": {},
"created": "Dibuat",
"@created": {},
"order_item": "Item Pesanan",
"@order_item": {},
"item": "Item",
"@item": {},
"each": "Setiap",
"@each": {},
"total_item": "Jumlah Item",
"@total_item": {},
"payment_summary": "Ringkasan Pembayaran",
"@payment_summary": {},
"subtotal": "Subtotal",
"@subtotal": {},
"paid": "Dibayar",
"@paid": {},
"total": "Jumlah",
"@total": {},
"payment_method": "Metode Pembayaran",
"@payment_method": {},
"dine_in": "Makan di Tempat",
"@dine_in": {},
"dine_in_experience": "Pengalaman Bersantap Di Tempat",
"@dine_in_experience": {},
"note": "Catatan",
"@note": {},
"sales_chart": "Bagan Penjualan",
"@sales_chart": {},
"no_data_available": "Tidak Ada Data Tersedia",
"@no_data_available": {},
"total_days_overview": "ikhtisar {days} hari",
"@total_days_overview": {
"placeholders": {
"days": {
"type": "int",
"example": "0"
}
}
},
"sales_data": "Data Penjualan",
"@sales_data": {},
"no_sales_data": "Tidak ada data penjualan",
"@no_sales_data": {},
"no_sales_data_desc": "Data penjualan akan muncul di sini setelah transaksi dicatat",
"@no_sales_data_desc": {},
"payment_methods": "Metode Pembayaran",
"@payment_methods": {},
"payment_methods_desc": "Rincian pendapatan berdasarkan metode pembayaran ",
"@payment_methods_desc": {},
"revenue_share": "Bagi Hasil",
"@revenue_share": {},
"no_payment_methods": "Tidak Ada Metode Pembayaran",
"@no_payment_methods": {},
"no_payment_methods_desc": "Data metode pembayaran akan muncul di sini setelah transaksi dilakukan",
"@no_payment_methods_desc": {},
"best_selling_products": "Produk Terlaris",
"@best_selling_products": {},
"highest_sales_ranking": "Ranking penjualan tertinggi",
"@highest_sales_ranking": {},
"best_seller": "Penjual Terbaik",
"@best_seller": {},
"top_performer": "Berkinerja Terbaik",
"@top_performer": {},
"account_information": "Informasi Akun",
"@account_information": {},
"member_since": "Member Sejak",
"@member_since": {},
"edit_profile": "Ubah Profil",
"@edit_profile": {},
"edit_profile_desc": "Update informasi profil Anda",
"@edit_profile_desc": {},
"change_password": "Ubah Kata Sandi",
"@change_password": {},
"change_password_desc": "Update kata sandi Anda",
"@change_password_desc": {},
"business_settings": "Pengaturan Bisnis",
"@business_settings": {},
"outlet_information": "Informasi Outlet",
"@outlet_information": {},
"outlet_informatio_desc": "Kelola informasi outlet Anda",
"@outlet_informatio_desc": {},
"staff_management": "Manajemen Staff",
"@staff_management": {},
"staff_management_desc": "Kelola staff Anda",
"@staff_management_desc": {},
"manage_your_products": "Kelola Produk Anda",
"@manage_your_products": {},
"download_report": "Unduh Laporan",
"@download_report": {},
"download_report_desc": "Unduh laporan penjualan atau stok",
"@download_report_desc": {},
"app_settings": "Pengaturan Aplikasi",
"@app_settings": {},
"language_desc": "Pilih bahasa aplikasi Anda",
"@language_desc": {},
"support": "Dukungan",
"@support": {},
"help_center": "Pusat Bantuan",
"@help_center": {},
"help_center_desc": "Hubungi tim dukungan kami",
"@help_center_desc": {},
"about": "Tentang",
"@about": {},
"about_desc": "Tentang Aplikasi",
"@about_desc": {},
"logout": "Keluar",
"@logout": {},
"logout_desc": "Keluar dari akun Anda",
"@logout_desc": {},
"save": "Simpan",
"@save": {},
"name": "Nama",
"@name": {},
"name_placeholder": "Masukkan nama Anda",
"@name_placeholder": {},
"password_changed": "Kata Sandi Berubah",
"@password_changed": {},
"current_password": "Kata Sandi Saat Ini",
"@current_password": {},
"current_password_placeholder": "Masukkan kata sandi saat ini",
"@current_password_placeholder": {},
"new_password": "Kata Sandi Baru",
"@new_password": {},
"new_password_placeholder": "Masukkan kata sandi baru",
"@new_password_placeholder": {},
"new_password_not_same": "Kata Sandi Baru Tidak Sama Dengan Kata Sandi Saat Ini",
"@new_password_not_same": {},
"general_information": "Informasi Umum",
"@general_information": {},
"address": "Alamat",
"@address": {},
"phone_number": "Nomor Telepon",
"@phone_number": {},
"currency": "Mata Uang",
"@currency": {},
"tax_rate": "Tarif Pajak",
"@tax_rate": {},
"status_text": "Status",
"@status_text": {},
"coming_soon": "Segera Hadir",
"@coming_soon": {},
"coming_soon_desc": "Sesuatu yang menakjubkan sedang terjadi!\nNantikan pengungkapan besarnya.",
"@coming_soon_desc": {},
"transaction_report": "Laporan Transaksi",
"@transaction_report": {},
"transaction_report_desc": "Ekspor semua data transaksi dengan analitik terperinci",
"@transaction_report_desc": {},
"invetory_report": "Laporan Inventaris",
"@invetory_report": {},
"invetory_report_desc": "Ekspor inventaris dan data stok dengan tren",
"@invetory_report_desc": {},
"about_app": "Tentang Aplikasi",
"@about_app": {},
"app_information": "Informasi Aplikasi",
"@app_information": {},
"app_name": "Nama Aplikasi",
"@app_name": {},
"build_number": "Nomor Build",
"@build_number": {},
"package_name": "Nama Paket",
"@package_name": {},
"device": "Perangkat",
"@device": {}
}

File diff suppressed because it is too large Load Diff

View File

@ -82,4 +82,540 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get sales_today => 'Sales today';
@override
String get order => 'Order';
@override
String get sales => 'Sales';
@override
String get finance => 'Finance';
@override
String get product => 'Product';
@override
String get form => 'Form';
@override
String get schedule => 'Schedule';
@override
String get inventory => 'Inventory';
@override
String get customer => 'Customer';
@override
String get purchase => 'Purchase';
@override
String get today_summary => 'Today\'s Summary';
@override
String get today => 'Today';
@override
String get new_customer => 'New Customer';
@override
String get refund => 'Refund';
@override
String get void_text => 'Void';
@override
String get increase => 'Increase';
@override
String get today_top_product => 'Today\'s Top Product';
@override
String get rank => 'Rank';
@override
String get quantity_sold => 'Quantity Sold';
@override
String get total_orders => 'Total Orders';
@override
String get average_price => 'Average Price';
@override
String get perfomance => 'Performance';
@override
String get total_sales => 'Total Sales';
@override
String get total_items => 'Total Items';
@override
String get summary => 'Summary';
@override
String get net_sales => 'Net Sales';
@override
String get daily_breakdown => 'Daily Breakdown';
@override
String get orders => 'Orders';
@override
String get items => 'Items';
@override
String get tax => 'Tax';
@override
String get discount => 'Discount';
@override
String get total_purchase => 'Total Purchase';
@override
String get pending_order => 'Pending Order';
@override
String get history_purchase => 'History Purchase';
@override
String get all => 'All';
@override
String get select_date_range => 'Select Date Range';
@override
String get no_date_selected => 'No date has been selected yet';
@override
String get selected_date => 'Selected Date';
@override
String get select => 'Select';
@override
String get cancel => 'Cancel';
@override
String get total_revenue => 'Total Revenue';
@override
String get total_expenditures => 'Total Expenditures';
@override
String get net_profit => 'Net Profit';
@override
String get margin_profit => 'Margin Profit';
@override
String get cash_flow_analysis => 'Cash Flow Analysis';
@override
String get cash_in => 'Cash In';
@override
String get cash_out => 'Cash Out';
@override
String get net_flow => 'Net Flow';
@override
String cash_flow_chart(int days) {
return 'Cash Flow Chart for $days Last Days';
}
@override
String get profit_loss_detail => 'Profit & Loss Details';
@override
String get gross_sales => 'Gross Sales';
@override
String get return_text => 'Return';
@override
String get cogs => 'COGS';
@override
String get cost_of_goods_sold => 'Cost of goods sold';
@override
String get gross_profit => 'Gross Profit';
@override
String get operating_costs => 'Operating Costs';
@override
String get sales_category => 'Sales Category';
@override
String get unit => 'Unit';
@override
String get category_no_data => 'There are no data categories yet';
@override
String get category_no_data_desc => 'Sales category data will appear here';
@override
String get product_analytic => 'Product Analytic';
@override
String get view_all => 'View All';
@override
String get sold => 'Sold';
@override
String get revenue => 'Revenue';
@override
String get cost => 'Cost';
@override
String get profit_per_unit => 'Profit per unit';
@override
String get total_sold => 'Total Sold';
@override
String get ingredients => 'Ingredients';
@override
String get low_stock => 'Low Stock';
@override
String get zero_stock => 'Zero Stock';
@override
String get stock => 'Stock';
@override
String get price => 'Price';
@override
String get out_of_stock => 'Out of stock';
@override
String get out_of_stock_desc => 'Product not available for sale';
@override
String get in_text => 'In';
@override
String get out_text => 'Out';
@override
String get available => 'Available';
@override
String get total_products => 'Total Products';
@override
String get total_ingredients => 'Total Ingredients';
@override
String get products => 'Products';
@override
String get value_text => 'Value';
@override
String low_stock_desc(String stock) {
return 'Immediately reorder at least $stock pcs';
}
@override
String get joined => 'Joined';
@override
String get ago => 'ago';
@override
String get active => 'Active';
@override
String get inactive => 'Inactive';
@override
String get total_amount => 'Total Amount';
@override
String get table => 'Table';
@override
String get remaining => 'Remaining';
@override
String get payment => 'Payment';
@override
String get completed => 'Completed';
@override
String get pending => 'Pending';
@override
String no_order_with_status(String status) {
return 'No $status orders found';
}
@override
String get order_details => 'Order Details';
@override
String get order_number => 'Order Number';
@override
String get order_status => 'Order Status';
@override
String get order_information => 'Order Information';
@override
String get order_type => 'Order Type';
@override
String get payment_status => 'Payment Status';
@override
String get created => 'Created';
@override
String get order_item => 'Order Item';
@override
String get item => 'Item';
@override
String get each => 'Each';
@override
String get total_item => 'Total Item';
@override
String get payment_summary => 'Payment Summary';
@override
String get subtotal => 'Subtotal';
@override
String get paid => 'Paid';
@override
String get total => 'Total';
@override
String get payment_method => 'Payment Method';
@override
String get dine_in => 'Dine In';
@override
String get dine_in_experience => 'Dine In Experience';
@override
String get note => 'Note';
@override
String get sales_chart => 'Sales Chart';
@override
String get no_data_available => 'No Data Avaiable';
@override
String total_days_overview(int days) {
return '$days days overview';
}
@override
String get sales_data => 'Sales Data';
@override
String get no_sales_data => 'No Sales Data';
@override
String get no_sales_data_desc => 'Sales data will appear here once transactions are recorded';
@override
String get payment_methods => 'Payment Methods';
@override
String get payment_methods_desc => 'Revenue breakdown by payment method ';
@override
String get revenue_share => 'Revenue Share';
@override
String get no_payment_methods => 'No Payment Methods';
@override
String get no_payment_methods_desc => 'Payment method data will appear here once transactions are made';
@override
String get best_selling_products => 'Best Selling Products';
@override
String get highest_sales_ranking => 'Highest sales ranking';
@override
String get best_seller => 'Best Seller';
@override
String get top_performer => 'Top Performer';
@override
String get account_information => 'Account Information';
@override
String get member_since => 'Member Since';
@override
String get edit_profile => 'Edit Profile';
@override
String get edit_profile_desc => 'Update your profile information';
@override
String get change_password => 'Change Password';
@override
String get change_password_desc => 'Update your password';
@override
String get business_settings => 'Business Settings';
@override
String get outlet_information => 'Outlet Information';
@override
String get outlet_informatio_desc => 'Manage your outlet details';
@override
String get staff_management => 'Staff Management';
@override
String get staff_management_desc => 'Manage your staff';
@override
String get manage_your_products => 'Manage Your Products';
@override
String get download_report => 'Download Report';
@override
String get download_report_desc => 'Download your sales report or inventory report';
@override
String get app_settings => 'App Settings';
@override
String get language_desc => 'Select your preferred language';
@override
String get support => 'Support';
@override
String get help_center => 'Help Center';
@override
String get help_center_desc => 'Get help from our support team';
@override
String get about => 'About';
@override
String get about_desc => 'Learn more about our app';
@override
String get logout => 'Logout';
@override
String get logout_desc => 'Logout of your account';
@override
String get save => 'Save';
@override
String get name => 'Name';
@override
String get name_placeholder => 'Please enter your name';
@override
String get password_changed => 'Password Changed';
@override
String get current_password => 'Current Password';
@override
String get current_password_placeholder => 'Please enter your current password';
@override
String get new_password => 'New Password';
@override
String get new_password_placeholder => 'Please enter your new password';
@override
String get new_password_not_same => 'New password cannot be same as current password';
@override
String get general_information => 'General Information';
@override
String get address => 'Address';
@override
String get phone_number => 'Phone Number';
@override
String get currency => 'Currency';
@override
String get tax_rate => 'Tax Rate';
@override
String get status_text => 'Status';
@override
String get coming_soon => 'Coming Soon';
@override
String get coming_soon_desc => 'Something amazing is brewing!\nStay tuned for the big reveal.';
@override
String get transaction_report => 'Transaction Report';
@override
String get transaction_report_desc => 'Export all transaction data with detailed analytics';
@override
String get invetory_report => 'Inventory Report';
@override
String get invetory_report_desc => 'Export inventory and stock data with trends';
@override
String get about_app => 'About App';
@override
String get app_information => 'App Information';
@override
String get app_name => 'App Name';
@override
String get build_number => 'Build Number';
@override
String get package_name => 'Package Name';
@override
String get device => 'Device';
}

View File

@ -82,4 +82,540 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get sales_today => 'Penjualan hari ini';
@override
String get order => 'Pesanan';
@override
String get sales => 'Penjualan';
@override
String get finance => 'Keuangan';
@override
String get product => 'Produk';
@override
String get form => 'Form';
@override
String get schedule => 'Jadwal';
@override
String get inventory => 'Inventaris';
@override
String get customer => 'Pelanggan';
@override
String get purchase => 'Pembelian';
@override
String get today_summary => 'Ringkasan Hari Ini';
@override
String get today => 'Hari ini';
@override
String get new_customer => 'Pelanggan baru';
@override
String get refund => 'Pengembalian dana';
@override
String get void_text => 'Dibatalkan';
@override
String get increase => 'Bertambah';
@override
String get today_top_product => 'Produk teratas hari ini';
@override
String get rank => 'Pangkat';
@override
String get quantity_sold => 'Kuantiti Terjual';
@override
String get total_orders => 'Jumlah Pesanan';
@override
String get average_price => 'Harga Rata-rata';
@override
String get perfomance => 'Performa';
@override
String get total_sales => 'Jumlah Penjualan';
@override
String get total_items => 'Jumlah Barang';
@override
String get summary => 'Ringkasan';
@override
String get net_sales => 'Penjualan Bersih';
@override
String get daily_breakdown => 'Perincian Harian';
@override
String get orders => 'Pesanan';
@override
String get items => 'Barang';
@override
String get tax => 'Pajak';
@override
String get discount => 'Diskon';
@override
String get total_purchase => 'Jumlah Pembelian';
@override
String get pending_order => 'Pesanan Menunggu';
@override
String get history_purchase => 'Riwayat Pembelian';
@override
String get all => 'Semua';
@override
String get select_date_range => 'Pilih Rentang Tanggal';
@override
String get no_date_selected => 'Belum ada tanggal dipilih';
@override
String get selected_date => 'Tanggal Terpilih';
@override
String get select => 'Pilih';
@override
String get cancel => 'Batal';
@override
String get total_revenue => 'Jumlah Pendapatan';
@override
String get total_expenditures => 'Jumlah Pengeluaran';
@override
String get net_profit => 'Keuntungan Bersih';
@override
String get margin_profit => 'Keuntungan Margin';
@override
String get cash_flow_analysis => 'Analisis Arus Kas';
@override
String get cash_in => 'Uang Masuk';
@override
String get cash_out => 'Uang Keluar';
@override
String get net_flow => 'Arus Bersih';
@override
String cash_flow_chart(int days) {
return 'Grafik Cash Flow \$$days Hari Terakhir';
}
@override
String get profit_loss_detail => 'Detail Untung & Rugi';
@override
String get gross_sales => 'Penjualan Kotor';
@override
String get return_text => 'Retur';
@override
String get cogs => 'HPP';
@override
String get cost_of_goods_sold => 'Harga Pokok Penjualan';
@override
String get gross_profit => 'Keuntungan Kotor';
@override
String get operating_costs => 'Biaya Operasional';
@override
String get sales_category => 'Kategori Penjualan';
@override
String get unit => 'Unit';
@override
String get category_no_data => 'Belum ada data kategori';
@override
String get category_no_data_desc => 'Data kategori penjualan akan muncul di sini';
@override
String get product_analytic => 'Analisis Produk';
@override
String get view_all => 'Lihat Semua';
@override
String get sold => 'Terjual';
@override
String get revenue => 'Pendapatan';
@override
String get cost => 'Biaya';
@override
String get profit_per_unit => 'Keuntungan per unit';
@override
String get total_sold => 'Jumlah Terjual';
@override
String get ingredients => 'Bahan Baku';
@override
String get low_stock => 'Stok Rendah';
@override
String get zero_stock => 'Stok Kosong';
@override
String get stock => 'Stok';
@override
String get price => 'Harga';
@override
String get out_of_stock => 'Stok habis';
@override
String get out_of_stock_desc => 'Produk tidak tersedia untuk dijual';
@override
String get in_text => 'Masuk';
@override
String get out_text => 'Keluar';
@override
String get available => 'Tersedia';
@override
String get total_products => 'Jumlah Produk';
@override
String get total_ingredients => 'Jumlah Bahan Baku';
@override
String get products => 'Produk';
@override
String get value_text => 'Nilai';
@override
String low_stock_desc(String stock) {
return 'Segera reorder minimal $stock pcs';
}
@override
String get joined => 'Bergabung';
@override
String get ago => 'lalu';
@override
String get active => 'Aktif';
@override
String get inactive => 'Tidak Aktif';
@override
String get total_amount => 'Jumlah Total';
@override
String get table => 'Meja';
@override
String get remaining => 'Sisa';
@override
String get payment => 'Pembayaran';
@override
String get completed => 'Selesai';
@override
String get pending => 'Menunggu';
@override
String no_order_with_status(String status) {
return 'Tidak ada pesanan $status yang ditemukan';
}
@override
String get order_details => 'Detail Pesanan';
@override
String get order_number => 'Nomor Pesanan';
@override
String get order_status => 'Status Pesanan';
@override
String get order_information => 'Informasi Pesanan';
@override
String get order_type => 'Tipe Pesanan';
@override
String get payment_status => 'Status Pembayaran';
@override
String get created => 'Dibuat';
@override
String get order_item => 'Item Pesanan';
@override
String get item => 'Item';
@override
String get each => 'Setiap';
@override
String get total_item => 'Jumlah Item';
@override
String get payment_summary => 'Ringkasan Pembayaran';
@override
String get subtotal => 'Subtotal';
@override
String get paid => 'Dibayar';
@override
String get total => 'Jumlah';
@override
String get payment_method => 'Metode Pembayaran';
@override
String get dine_in => 'Makan di Tempat';
@override
String get dine_in_experience => 'Pengalaman Bersantap Di Tempat';
@override
String get note => 'Catatan';
@override
String get sales_chart => 'Bagan Penjualan';
@override
String get no_data_available => 'Tidak Ada Data Tersedia';
@override
String total_days_overview(int days) {
return 'ikhtisar $days hari';
}
@override
String get sales_data => 'Data Penjualan';
@override
String get no_sales_data => 'Tidak ada data penjualan';
@override
String get no_sales_data_desc => 'Data penjualan akan muncul di sini setelah transaksi dicatat';
@override
String get payment_methods => 'Metode Pembayaran';
@override
String get payment_methods_desc => 'Rincian pendapatan berdasarkan metode pembayaran ';
@override
String get revenue_share => 'Bagi Hasil';
@override
String get no_payment_methods => 'Tidak Ada Metode Pembayaran';
@override
String get no_payment_methods_desc => 'Data metode pembayaran akan muncul di sini setelah transaksi dilakukan';
@override
String get best_selling_products => 'Produk Terlaris';
@override
String get highest_sales_ranking => 'Ranking penjualan tertinggi';
@override
String get best_seller => 'Penjual Terbaik';
@override
String get top_performer => 'Berkinerja Terbaik';
@override
String get account_information => 'Informasi Akun';
@override
String get member_since => 'Member Sejak';
@override
String get edit_profile => 'Ubah Profil';
@override
String get edit_profile_desc => 'Update informasi profil Anda';
@override
String get change_password => 'Ubah Kata Sandi';
@override
String get change_password_desc => 'Update kata sandi Anda';
@override
String get business_settings => 'Pengaturan Bisnis';
@override
String get outlet_information => 'Informasi Outlet';
@override
String get outlet_informatio_desc => 'Kelola informasi outlet Anda';
@override
String get staff_management => 'Manajemen Staff';
@override
String get staff_management_desc => 'Kelola staff Anda';
@override
String get manage_your_products => 'Kelola Produk Anda';
@override
String get download_report => 'Unduh Laporan';
@override
String get download_report_desc => 'Unduh laporan penjualan atau stok';
@override
String get app_settings => 'Pengaturan Aplikasi';
@override
String get language_desc => 'Pilih bahasa aplikasi Anda';
@override
String get support => 'Dukungan';
@override
String get help_center => 'Pusat Bantuan';
@override
String get help_center_desc => 'Hubungi tim dukungan kami';
@override
String get about => 'Tentang';
@override
String get about_desc => 'Tentang Aplikasi';
@override
String get logout => 'Keluar';
@override
String get logout_desc => 'Keluar dari akun Anda';
@override
String get save => 'Simpan';
@override
String get name => 'Nama';
@override
String get name_placeholder => 'Masukkan nama Anda';
@override
String get password_changed => 'Kata Sandi Berubah';
@override
String get current_password => 'Kata Sandi Saat Ini';
@override
String get current_password_placeholder => 'Masukkan kata sandi saat ini';
@override
String get new_password => 'Kata Sandi Baru';
@override
String get new_password_placeholder => 'Masukkan kata sandi baru';
@override
String get new_password_not_same => 'Kata Sandi Baru Tidak Sama Dengan Kata Sandi Saat Ini';
@override
String get general_information => 'Informasi Umum';
@override
String get address => 'Alamat';
@override
String get phone_number => 'Nomor Telepon';
@override
String get currency => 'Mata Uang';
@override
String get tax_rate => 'Tarif Pajak';
@override
String get status_text => 'Status';
@override
String get coming_soon => 'Segera Hadir';
@override
String get coming_soon_desc => 'Sesuatu yang menakjubkan sedang terjadi!\nNantikan pengungkapan besarnya.';
@override
String get transaction_report => 'Laporan Transaksi';
@override
String get transaction_report_desc => 'Ekspor semua data transaksi dengan analitik terperinci';
@override
String get invetory_report => 'Laporan Inventaris';
@override
String get invetory_report_desc => 'Ekspor inventaris dan data stok dengan tren';
@override
String get about_app => 'Tentang Aplikasi';
@override
String get app_information => 'Informasi Aplikasi';
@override
String get app_name => 'Nama Aplikasi';
@override
String get build_number => 'Nomor Build';
@override
String get package_name => 'Nama Paket';
@override
String get device => 'Perangkat';
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import '../../../common/extension/extension.dart';
class DateRangePickerBottomSheet {
static Future<DateRangePickerSelectionChangedArgs?> show({
required BuildContext context,
@ -9,8 +11,8 @@ class DateRangePickerBottomSheet {
DateTime? initialEndDate,
DateTime? minDate,
DateTime? maxDate,
String confirmText = 'Pilih',
String cancelText = 'Batal',
String? confirmText,
String? cancelText,
Color primaryColor = Colors.blue,
Function(DateTime? startDate, DateTime? endDate)? onChanged,
}) async {
@ -26,8 +28,8 @@ class DateRangePickerBottomSheet {
initialEndDate: initialEndDate,
minDate: minDate,
maxDate: maxDate,
confirmText: confirmText,
cancelText: cancelText,
confirmText: confirmText ?? context.lang.select,
cancelText: cancelText ?? context.lang.cancel,
primaryColor: primaryColor,
onChanged: onChanged,
),
@ -104,7 +106,7 @@ class _DateRangePickerBottomSheetState
return _formatDate(range.startDate!);
}
}
return 'Belum ada tanggal dipilih';
return context.lang.no_date_selected;
}
String _formatDate(DateTime date) {
@ -187,7 +189,7 @@ class _DateRangePickerBottomSheetState
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Tanggal Terpilih:',
'${context.lang.selected_date}:',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../bottom_sheet/date_range_bottom_sheet.dart';
@ -22,7 +23,7 @@ class DateRangePickerField extends StatefulWidget {
final double height;
const DateRangePickerField({
Key? key,
super.key,
this.label,
this.placeholder = 'Pilih rentang tanggal',
this.startDate,
@ -38,7 +39,7 @@ class DateRangePickerField extends StatefulWidget {
this.placeholderStyle,
this.decoration,
this.height = 52.0,
}) : super(key: key);
});
@override
State<DateRangePickerField> createState() => _DateRangePickerFieldState();
@ -83,7 +84,7 @@ class _DateRangePickerFieldState extends State<DateRangePickerField> {
final result = await DateRangePickerBottomSheet.show(
context: context,
title: widget.label ?? 'Pilih Rentang Tanggal',
title: widget.label ?? context.lang.select_date_range,
initialStartDate: widget.startDate,
initialEndDate: widget.endDate,
minDate: widget.minDate,
@ -294,7 +295,7 @@ class _DateRangePickerFieldOutlinedState
final result = await DateRangePickerBottomSheet.show(
context: context,
title: widget.label ?? 'Pilih Rentang Tanggal',
title: widget.label ?? context.lang.select_date_range,
initialStartDate: widget.startDate,
initialEndDate: widget.endDate,
minDate: widget.minDate,
@ -412,120 +413,3 @@ class _DateRangePickerFieldOutlinedState
);
}
}
// Usage Example Widget
class DateRangePickerExample extends StatefulWidget {
@override
_DateRangePickerExampleState createState() => _DateRangePickerExampleState();
}
class _DateRangePickerExampleState extends State<DateRangePickerExample> {
DateTime? _startDate;
DateTime? _endDate;
DateTime? _startDate2;
DateTime? _endDate2;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Date Range Picker Example'),
backgroundColor: AppColor.primary,
foregroundColor: AppColor.white,
),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Default Style',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
const SizedBox(height: 16),
DateRangePickerField(
label: 'Periode Laporan',
placeholder: 'Pilih tanggal mulai - selesai',
startDate: _startDate,
endDate: _endDate,
primaryColor: AppColor.primary,
onChanged: (start, end) {
setState(() {
_startDate = start;
_endDate = end;
});
},
),
const SizedBox(height: 32),
Text(
'Outlined Style',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
const SizedBox(height: 16),
DateRangePickerFieldOutlined(
label: 'Rentang Waktu',
placeholder: 'Pilih rentang tanggal',
startDate: _startDate2,
endDate: _endDate2,
primaryColor: AppColor.secondary,
onChanged: (start, end) {
setState(() {
_startDate2 = start;
_endDate2 = end;
});
},
),
const SizedBox(height: 24),
// Display selected dates
if (_startDate != null ||
_endDate != null ||
_startDate2 != null ||
_endDate2 != null)
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.background,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Selected Dates:',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
const SizedBox(height: 8),
if (_startDate != null)
Text(
'Default: ${_startDate!} - ${_endDate ?? 'Not selected'}',
),
if (_startDate2 != null)
Text(
'Outlined: ${_startDate2!} - ${_endDate2 ?? 'Not selected'}',
),
],
),
),
],
),
),
);
}
}

View File

@ -3,7 +3,9 @@ import 'package:auto_route/auto_route.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:device_info_plus/device_info_plus.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../components/assets/assets.gen.dart';
@RoutePage()
class AboutAppPage extends StatefulWidget {
@ -107,7 +109,7 @@ class _AboutAppPageState extends State<AboutAppPage>
return Opacity(
opacity: _fadeAnimation.value,
child: Text(
'Tentang Aplikasi',
context.lang.about_app,
style: AppStyle.lg.copyWith(
color: AppColor.white,
fontWeight: FontWeight.bold,
@ -142,7 +144,7 @@ class _AboutAppPageState extends State<AboutAppPage>
height: 100,
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(25),
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.2),
@ -151,10 +153,9 @@ class _AboutAppPageState extends State<AboutAppPage>
),
],
),
child: Icon(
Icons.mobile_friendly,
size: 50,
color: AppColor.primary,
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Assets.images.logo.image(),
),
),
const SizedBox(height: 16),
@ -247,7 +248,7 @@ class _AboutAppPageState extends State<AboutAppPage>
),
const SizedBox(width: 16),
Text(
'Informasi Aplikasi',
context.lang.app_information,
style: AppStyle.h6.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
@ -256,18 +257,24 @@ class _AboutAppPageState extends State<AboutAppPage>
],
),
const SizedBox(height: 20),
_buildInfoRow('Nama Aplikasi', packageInfo?.appName ?? 'Loading...'),
_buildInfoRow('Versi', packageInfo?.version ?? 'Loading...'),
_buildInfoRow(
'Build Number',
context.lang.app_name,
packageInfo?.appName ?? 'Loading...',
),
_buildInfoRow(
context.lang.version,
packageInfo?.version ?? 'Loading...',
),
_buildInfoRow(
context.lang.build_number,
packageInfo?.buildNumber ?? 'Loading...',
),
_buildInfoRow(
'Package Name',
context.lang.package_name,
packageInfo?.packageName ?? 'Loading...',
),
_buildInfoRow(
'Device',
context.lang.device,
deviceInfo.isEmpty ? 'Loading...' : deviceInfo,
),
],

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
@RoutePage()
@ -114,7 +115,7 @@ class _ComingSoonPageState extends State<ComingSoonPage>
child: SlideTransition(
position: _slideAnimation,
child: Text(
'Coming Soon',
context.lang.coming_soon,
style: AppStyle.h1.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.bold,
@ -134,7 +135,7 @@ class _ComingSoonPageState extends State<ComingSoonPage>
child: SlideTransition(
position: _slideAnimation,
child: Text(
'Something amazing is brewing!\nStay tuned for the big reveal.',
context.lang.coming_soon_desc,
style: AppStyle.lg.copyWith(
color: AppColor.textWhite.withOpacity(0.9),
height: 1.5,

View File

@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import '../../../application/customer/customer_loader/customer_loader_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/customer/customer.dart';
import '../../../injection.dart';
@ -31,7 +32,7 @@ class CustomerPage extends StatefulWidget implements AutoRouteWrapper {
class _CustomerPageState extends State<CustomerPage>
with TickerProviderStateMixin {
final TextEditingController _searchController = TextEditingController();
ScrollController _scrollController = ScrollController();
final ScrollController _scrollController = ScrollController();
bool _isGridView = false;
@override
@ -72,7 +73,7 @@ class _CustomerPageState extends State<CustomerPage>
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Pelanggan'),
flexibleSpace: CustomAppBar(title: context.lang.customer),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.search),
],
@ -148,7 +149,7 @@ class _CustomerPageState extends State<CustomerPage>
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.8,
childAspectRatio: 0.65,
),
delegate: SliverChildBuilderDelegate((context, index) {
final customer = customers[index];

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/customer/customer.dart';
import '../../../components/spacer/spacer.dart';
@ -175,78 +176,6 @@ class CustomerCard extends StatelessWidget {
const SpaceHeight(12),
],
// Status Badge
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: customer.isActive
? AppColor.success.withOpacity(0.1)
: AppColor.error.withOpacity(0.1),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: customer.isActive
? AppColor.success.withOpacity(0.3)
: AppColor.error.withOpacity(0.3),
width: 1,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: customer.isActive
? AppColor.success
: AppColor.error,
shape: BoxShape.circle,
),
),
const SpaceWidth(6),
Text(
customer.isActive ? 'Active' : 'Inactive',
style: AppStyle.sm.copyWith(
color: customer.isActive
? AppColor.success
: AppColor.error,
fontWeight: FontWeight.w600,
),
),
],
),
),
// Additional info if available
if (customer.address.isNotEmpty) ...[
const SpaceHeight(8),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.location_on_outlined,
size: 14,
color: AppColor.textSecondary,
),
const SpaceWidth(4),
Flexible(
child: Text(
customer.address,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
),
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
// Metadata info
if (customer.metadata.isNotEmpty && _hasRelevantMetadata()) ...[
const SpaceHeight(8),
@ -284,7 +213,7 @@ class CustomerCard extends StatelessWidget {
if (customer.createdAt.isNotEmpty) ...[
const SpaceHeight(8),
Text(
'Joined ${_formatDate(customer.createdAt)}',
'${context.lang.joined} ${_formatDate(context, customer.createdAt)}',
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
textAlign: TextAlign.center,
),
@ -335,7 +264,7 @@ class CustomerCard extends StatelessWidget {
return colors[index];
}
String _formatDate(String dateStr) {
String _formatDate(BuildContext context, String dateStr) {
try {
final date = DateTime.parse(dateStr);
final now = DateTime.now();
@ -346,13 +275,13 @@ class CustomerCard extends StatelessWidget {
} else if (difference == 1) {
return 'yesterday';
} else if (difference < 30) {
return '${difference}d ago';
return '${difference}d ${context.lang.ago}';
} else if (difference < 365) {
final months = (difference / 30).floor();
return '${months}mo ago';
return '${months}mo ${context.lang.ago}';
} else {
final years = (difference / 365).floor();
return '${years}y ago';
return '${years}y ${context.lang.ago}';
}
} catch (e) {
return dateStr;

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/customer/customer.dart';
import '../../../components/spacer/spacer.dart';
@ -245,7 +246,9 @@ class CustomerTile extends StatelessWidget {
),
const SpaceWidth(6),
Text(
customer.isActive ? 'Active' : 'Inactive',
customer.isActive
? context.lang.active
: context.lang.inactive,
style: AppStyle.sm.copyWith(
color: customer.isActive
? AppColor.success
@ -260,7 +263,7 @@ class CustomerTile extends StatelessWidget {
// Created date
if (customer.createdAt.isNotEmpty)
Text(
'Joined ${_formatDate(customer.createdAt)}',
'${context.lang.joined} ${_formatDate(context, customer.createdAt)}',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
),
@ -326,7 +329,7 @@ class CustomerTile extends StatelessWidget {
return colors[index];
}
String _formatDate(String dateStr) {
String _formatDate(BuildContext context, String dateStr) {
try {
final date = DateTime.parse(dateStr);
final now = DateTime.now();
@ -337,13 +340,13 @@ class CustomerTile extends StatelessWidget {
} else if (difference == 1) {
return 'yesterday';
} else if (difference < 30) {
return '${difference}d ago';
return '${difference}d ${context.lang.ago}';
} else if (difference < 365) {
final months = (difference / 30).floor();
return '${months}mo ago';
return '${months}mo ${context.lang.ago}';
} else {
final years = (difference / 365).floor();
return '${years}y ago';
return '${years}y ${context.lang.ago}';
}
} catch (e) {
return dateStr;

View File

@ -113,7 +113,7 @@ class _DownloadReportPageState extends State<DownloadReportPage>
pinned: true,
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Download Report'),
flexibleSpace: CustomAppBar(title: context.lang.download_report),
),
// Content
@ -134,9 +134,8 @@ class _DownloadReportPageState extends State<DownloadReportPage>
>(
builder: (context, state) {
return _ReportOptionCard(
title: 'Transaction Report',
subtitle:
'Export all transaction data with detailed analytics',
title: context.lang.transaction_report,
subtitle: context.lang.transaction_report_desc,
icon: Icons.receipt_long_outlined,
gradient: const [
AppColor.primary,
@ -205,9 +204,8 @@ class _DownloadReportPageState extends State<DownloadReportPage>
BlocBuilder<InventoryReportBloc, InventoryReportState>(
builder: (context, state) {
return _ReportOptionCard(
title: 'Inventory Report',
subtitle:
'Export inventory and stock data with trends',
title: context.lang.invetory_report,
subtitle: context.lang.invetory_report_desc,
icon: Icons.inventory_2_outlined,
gradient: const [
AppColor.secondary,
@ -479,7 +477,7 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Date Range',
context.lang.select_date_range,
style: AppStyle.md.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w600,
@ -489,7 +487,7 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
// Date Range Picker Field Style
DateRangePickerField(
placeholder: 'Select date range',
placeholder: context.lang.select_date_range,
startDate: widget.startDate,
endDate: widget.endDate,
onChanged: widget.onDateRangeChanged,
@ -542,7 +540,7 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
),
const SizedBox(width: 8),
Text(
'Download Report',
context.lang.download_report,
style: AppStyle.md.copyWith(
color: widget.gradient.first,
fontWeight: FontWeight.bold,

View File

@ -126,7 +126,7 @@ class _FinancePageState extends State<FinancePage>
pinned: true,
backgroundColor: AppColor.primary,
elevation: 0,
flexibleSpace: CustomAppBar(title: 'Keuangan'),
flexibleSpace: CustomAppBar(title: context.lang.finance),
),
// Header dengan filter periode
@ -221,7 +221,7 @@ class _FinancePageState extends State<FinancePage>
children: [
Expanded(
child: FinanceSummaryCard(
title: 'Total Pendapatan',
title: context.lang.total_revenue,
amount: summary.totalRevenue.currencyFormatRp,
icon: LineIcons.arrowUp,
color: AppColor.success,
@ -231,7 +231,7 @@ class _FinancePageState extends State<FinancePage>
const SizedBox(width: 12),
Expanded(
child: FinanceSummaryCard(
title: 'Total Pengeluaran',
title: context.lang.total_expenditures,
amount: summary.totalCost.currencyFormatRp,
icon: LineIcons.arrowDown,
color: AppColor.error,
@ -245,7 +245,7 @@ class _FinancePageState extends State<FinancePage>
children: [
Expanded(
child: FinanceSummaryCard(
title: 'Keuntungan Bersih',
title: context.lang.net_profit,
amount: summary.netProfit.currencyFormatRp,
icon: LineIcons.lineChart,
color: AppColor.info,
@ -255,7 +255,7 @@ class _FinancePageState extends State<FinancePage>
const SizedBox(width: 12),
Expanded(
child: FinanceSummaryCard(
title: 'Margin Profit',
title: context.lang.margin_profit,
amount: '${summary.profitabilityRatio.round()}%',
icon: LineIcons.percent,
color: AppColor.warning,
@ -304,14 +304,14 @@ class _FinancePageState extends State<FinancePage>
),
const SizedBox(width: 12),
Text(
'Analisis Produk',
context.lang.product_analytic,
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
),
const Spacer(),
TextButton(
onPressed: () {},
child: Text(
'Lihat Semua',
context.lang.view_all,
style: AppStyle.sm.copyWith(color: AppColor.primary),
),
),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import 'package:intl/intl.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
@ -57,7 +58,7 @@ class FinanceCashFlow extends StatelessWidget {
),
const SizedBox(width: 12),
Text(
'Analisis Cash Flow',
context.lang.cash_flow_analysis,
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
),
],
@ -78,7 +79,7 @@ class FinanceCashFlow extends StatelessWidget {
children: [
Expanded(
child: _buildCashFlowIndicator(
'Cash In',
context.lang.cash_in,
_formatCurrency(totalCashIn),
LineIcons.arrowUp,
AppColor.success,
@ -87,7 +88,7 @@ class FinanceCashFlow extends StatelessWidget {
const SizedBox(width: 16),
Expanded(
child: _buildCashFlowIndicator(
'Cash Out',
context.lang.cash_out,
_formatCurrency(totalCashOut),
LineIcons.arrowDown,
AppColor.error,
@ -96,7 +97,7 @@ class FinanceCashFlow extends StatelessWidget {
const SizedBox(width: 16),
Expanded(
child: _buildCashFlowIndicator(
'Net Flow',
context.lang.net_flow,
_formatCurrency(netFlow),
LineIcons.equals,
AppColor.info,
@ -119,7 +120,7 @@ class FinanceCashFlow extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Grafik Cash Flow ${dailyData.length} Hari Terakhir',
context.lang.cash_flow_chart(dailyData.length),
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w600,
@ -136,11 +137,11 @@ class FinanceCashFlow extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildChartLegend('Cash In', AppColor.success),
_buildChartLegend(context.lang.cash_in, AppColor.success),
const SizedBox(width: 20),
_buildChartLegend('Cash Out', AppColor.error),
_buildChartLegend(context.lang.cash_out, AppColor.error),
const SizedBox(width: 20),
_buildChartLegend('Net Flow', AppColor.info),
_buildChartLegend(context.lang.net_flow, AppColor.info),
],
),
],

View File

@ -51,7 +51,7 @@ class FinanceCategory extends StatelessWidget {
),
const SizedBox(width: 12),
Text(
'Kategori Penjualan',
context.lang.sales_category,
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
),
],
@ -60,10 +60,11 @@ class FinanceCategory extends StatelessWidget {
// Show empty state if no categories
if (categories.isEmpty)
_buildEmptyState()
_buildEmptyState(context)
else
...sortedCategories.asMap().entries.map(
(entry) => _buildCategoryItem(
context,
entry.value,
_calculatePercentage(entry.value.totalRevenue, totalRevenue),
_getCategoryColor(entry.key),
@ -75,6 +76,7 @@ class FinanceCategory extends StatelessWidget {
}
Widget _buildCategoryItem(
BuildContext context,
CategoryAnalyticItem category,
double percentage,
Color color,
@ -111,7 +113,7 @@ class FinanceCategory extends StatelessWidget {
),
const SizedBox(height: 2),
Text(
'${category.productCount} produk • ${category.orderCount} pesanan',
'${category.productCount} ${context.lang.product}${category.orderCount} ${context.lang.orders}',
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
),
@ -134,7 +136,7 @@ class FinanceCategory extends StatelessWidget {
),
),
Text(
'${NumberFormat('#,###', 'id_ID').format(category.totalQuantity)} unit',
'${NumberFormat('#,###', 'id_ID').format(category.totalQuantity)} ${context.lang.unit}',
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
),
],
@ -161,10 +163,10 @@ class FinanceCategory extends StatelessWidget {
);
}
Widget _buildEmptyState() {
Widget _buildEmptyState(BuildContext context) {
return EmptyWidget(
title: 'Belum ada data kategori',
message: 'Data kategori penjualan akan muncul di sini',
title: context.lang.category_no_data,
message: context.lang.category_no_data_desc,
);
}

View File

@ -81,21 +81,21 @@ class ProfitLossProduct extends StatelessWidget {
children: [
Expanded(
child: _buildMetricColumn(
'Pendapatan',
context.lang.revenue,
product.revenue.currencyFormatRp,
AppColor.success,
),
),
Expanded(
child: _buildMetricColumn(
'Biaya',
context.lang.cost,
product.cost.currencyFormatRp,
AppColor.error,
),
),
Expanded(
child: _buildMetricColumn(
'Laba Kotor',
context.lang.gross_profit,
product.grossProfit.currencyFormatRp,
AppColor.info,
),
@ -109,14 +109,14 @@ class ProfitLossProduct extends StatelessWidget {
children: [
Expanded(
child: _buildMetricColumn(
'Harga Rata-rata',
context.lang.average_price,
product.averagePrice.currencyFormatRp,
AppColor.textSecondary,
),
),
Expanded(
child: _buildMetricColumn(
'Laba per Unit',
context.lang.profit_per_unit,
product.profitPerUnit.currencyFormatRp,
AppColor.primary,
),

View File

@ -46,7 +46,7 @@ class FinanceProfitLoss extends StatelessWidget {
),
const SizedBox(width: 12),
Text(
'Detail Profit & Loss',
context.lang.profit_loss_detail,
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
),
],
@ -55,7 +55,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Total Revenue (Penjualan Kotor)
_buildPLItem(
'Penjualan Kotor',
context.lang.gross_sales,
data.totalRevenue.currencyFormatRp,
AppColor.success,
true,
@ -63,7 +63,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Discount (Diskon & Retur)
_buildPLItem(
'Diskon & Retur',
'${context.lang.discount} & ${context.lang.return_text}',
'- ${data.totalDiscount.currencyFormatRp}',
AppColor.error,
false,
@ -73,7 +73,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Net Sales (Penjualan Bersih = Total Revenue - Discount)
_buildPLItem(
'Penjualan Bersih',
context.lang.net_sales,
(data.totalRevenue - data.totalDiscount).currencyFormatRp,
AppColor.textPrimary,
true,
@ -84,7 +84,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Cost of Goods Sold (HPP)
_buildPLItem(
'HPP (Harga Pokok Penjualan)',
'${context.lang.cogs} (${context.lang.cost_of_goods_sold})',
'- ${data.totalCost.currencyFormatRp}',
AppColor.error,
false,
@ -94,7 +94,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Gross Profit (Laba Kotor)
_buildPLItem(
'Laba Kotor',
context.lang.gross_profit,
data.grossProfit.currencyFormatRp,
AppColor.success,
true,
@ -107,7 +107,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Operational Cost (Biaya Operasional) - calculated as difference
_buildPLItem(
'Biaya Operasional',
context.lang.operating_costs,
'- ${_calculateOperationalCost().currencyFormatRp}',
AppColor.error,
false,
@ -117,7 +117,7 @@ class FinanceProfitLoss extends StatelessWidget {
// Net Profit (Laba Bersih)
_buildPLItem(
'Laba Bersih',
context.lang.net_profit,
data.netProfit.currencyFormatRp,
AppColor.primary,
true,

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../router/app_router.gr.dart';
import 'feature_tile.dart';
@ -36,25 +37,25 @@ class HomeFeature extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HomeFeatureTile(
title: 'Penjualan',
title: context.lang.sales,
color: const Color(0xFF4CAF50),
icon: LineIcons.receipt,
onTap: () => context.router.push(SalesRoute()),
),
HomeFeatureTile(
title: 'Pembelian',
title: context.lang.purchase,
color: const Color(0xFF2196F3),
icon: LineIcons.shoppingCart,
onTap: () => context.router.push(PurchaseRoute()),
),
HomeFeatureTile(
title: 'Keuangan',
title: context.lang.finance,
color: const Color(0xFF8BC34A),
icon: LineIcons.moneyCheck,
onTap: () => context.router.push(FinanceRoute()),
),
HomeFeatureTile(
title: 'Produk',
title: context.lang.product,
color: const Color(0xFFFF9800),
icon: LineIcons.box,
onTap: () => context.router.push(ProductAnalyticRoute()),
@ -66,25 +67,25 @@ class HomeFeature extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HomeFeatureTile(
title: 'Form',
title: context.lang.form,
color: const Color(0xFFE91E63),
icon: LineIcons.fileAlt,
onTap: () => context.router.push(DailyTasksFormRoute()),
),
HomeFeatureTile(
title: 'Jadwal',
title: context.lang.schedule,
color: const Color(0xFF9C27B0),
icon: LineIcons.calendar,
onTap: () => context.router.push(ScheduleRoute()),
),
HomeFeatureTile(
title: 'Inventaris',
title: context.lang.inventory,
color: const Color(0xFF00BCD4),
icon: LineIcons.archive,
onTap: () => context.router.push(InventoryRoute()),
),
HomeFeatureTile(
title: 'Pelanggan',
title: context.lang.customer,
color: const Color(0xFFFF5722),
icon: LineIcons.userPlus,
onTap: () => context.router.push(CustomerRoute()),

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../components/spacer/spacer.dart';
@ -21,30 +22,30 @@ class HomeStats extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HomeTitle(title: 'Ringkasan Hari Ini'),
HomeTitle(title: context.lang.today_summary),
const SpaceHeight(20),
Row(
children: [
Expanded(
child: HomeStatsTile(
title: 'Pesanan',
title: context.lang.order,
value: overview.totalOrders.toString(),
icon: Icons.receipt_long_rounded,
color: AppColor.info,
subtitle: 'Hari ini',
subtitle: context.lang.today,
),
),
const SpaceWidth(16),
Expanded(
child: HomeStatsTile(
title: 'Pelanggan Baru',
title: context.lang.new_customer,
value: overview.totalCustomers.toString(),
icon: Icons.person_add_outlined,
color: AppColor.primary,
subtitle: overview.totalCustomers < 1
? 'Hari ini'
: 'bertambah',
? context.lang.today
: context.lang.increase,
),
),
],
@ -54,21 +55,21 @@ class HomeStats extends StatelessWidget {
children: [
Expanded(
child: HomeStatsTile(
title: 'Refund',
title: context.lang.refund,
value: overview.refundedOrders.toString(),
icon: LineIcons.alternateExchange,
color: AppColor.warning,
subtitle: 'Hari ini',
subtitle: context.lang.today,
),
),
const SpaceWidth(16),
Expanded(
child: HomeStatsTile(
title: 'Void',
title: context.lang.void_text,
value: overview.voidedOrders.toString(),
icon: Icons.cancel_rounded,
color: AppColor.error,
subtitle: 'Hari ini',
subtitle: context.lang.today,
),
),
],

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../components/spacer/spacer.dart';
@ -19,12 +20,13 @@ class HomeTopProduct extends StatelessWidget {
).copyWith(bottom: 0),
child: Column(
children: [
HomeTitle(title: 'Product Terlaris Hari Ini'),
HomeTitle(title: context.lang.today_top_product),
SpaceHeight(20),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: products.length,
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
return HomeTopProductTile(
product: products[index],

View File

@ -44,7 +44,7 @@ class HomeTopProductTile extends StatelessWidget {
// Header Row - Ranking dan Revenue
Row(
children: [
_buildRankingBadge(),
_buildRankingBadge(context),
const Spacer(),
_buildRevenueDisplay(),
],
@ -71,7 +71,7 @@ class HomeTopProductTile extends StatelessWidget {
const SizedBox(height: 12),
// Metrics dalam Grid 2x2
_buildMetricsGrid(),
_buildMetricsGrid(context),
],
),
),
@ -80,7 +80,7 @@ class HomeTopProductTile extends StatelessWidget {
);
}
Widget _buildRankingBadge() {
Widget _buildRankingBadge(BuildContext context) {
Color badgeColor;
IconData icon;
@ -115,7 +115,7 @@ class HomeTopProductTile extends StatelessWidget {
Icon(icon, color: badgeColor, size: 16),
const SizedBox(width: 6),
Text(
'Rank #$ranking',
'${context.lang.rank} #$ranking',
style: AppStyle.sm.copyWith(
color: badgeColor,
fontWeight: FontWeight.bold,
@ -157,7 +157,7 @@ class HomeTopProductTile extends StatelessWidget {
);
}
Widget _buildMetricsGrid() {
Widget _buildMetricsGrid(BuildContext context) {
return Row(
children: [
Expanded(
@ -165,14 +165,14 @@ class HomeTopProductTile extends StatelessWidget {
children: [
_buildMetricCard(
icon: Icons.shopping_cart_outlined,
label: 'Quantity Sold',
label: context.lang.quantity_sold,
value: product.quantitySold.toString(),
color: AppColor.info,
),
const SizedBox(height: 8),
_buildMetricCard(
icon: Icons.attach_money,
label: 'Average Price',
label: context.lang.average_price,
value: product.averagePrice.round().currencyFormatRp,
color: AppColor.success,
),
@ -185,14 +185,14 @@ class HomeTopProductTile extends StatelessWidget {
children: [
_buildMetricCard(
icon: Icons.receipt_outlined,
label: 'Total Orders',
label: context.lang.total_orders,
value: product.orderCount.toString(),
color: AppColor.warning,
),
const SizedBox(height: 8),
_buildMetricCard(
icon: Icons.trending_up,
label: 'Performance',
label: context.lang.perfomance,
value: 'Top $ranking',
color: AppColor.primary,
),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/analytic/inventory_analytic_loader/inventory_analytic_loader_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/analytic/analytic.dart';
import '../../../injection.dart';
@ -95,11 +96,11 @@ class _InventoryPageState extends State<InventoryPage>
String getStatusText(String status) {
switch (status) {
case 'available':
return 'Tersedia';
return context.lang.available;
case 'low_stock':
return 'Stok Rendah';
return context.lang.low_stock;
case 'out_of_stock':
return 'Habis';
return context.lang.out_of_stock;
default:
return 'Unknown';
}
@ -189,7 +190,7 @@ class _InventoryPageState extends State<InventoryPage>
padding: const EdgeInsets.symmetric(
horizontal: 12,
),
child: const Row(
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
@ -199,7 +200,7 @@ class _InventoryPageState extends State<InventoryPage>
size: 16,
),
SizedBox(width: 6),
Text('Produk'),
Text(context.lang.product),
],
),
),
@ -210,7 +211,7 @@ class _InventoryPageState extends State<InventoryPage>
padding: const EdgeInsets.symmetric(
horizontal: 12,
),
child: const Row(
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
@ -220,7 +221,7 @@ class _InventoryPageState extends State<InventoryPage>
size: 16,
),
SizedBox(width: 6),
Text('Bahan'),
Text(context.lang.ingredients),
],
),
),
@ -254,7 +255,7 @@ class _InventoryPageState extends State<InventoryPage>
pinned: true,
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Inventaris'),
flexibleSpace: CustomAppBar(title: context.lang.inventory),
);
}
@ -308,7 +309,7 @@ class _InventoryPageState extends State<InventoryPage>
children: [
Expanded(
child: _buildStatCard(
'Total Produk',
context.lang.total_products,
inventory.totalProducts.toString(),
Icons.inventory_2_rounded,
AppColor.primary,
@ -317,7 +318,7 @@ class _InventoryPageState extends State<InventoryPage>
const SizedBox(width: 16),
Expanded(
child: _buildStatCard(
'Produk Terjual',
context.lang.total_sold,
inventory.totalSoldProducts.toString(),
Icons.check_circle_rounded,
AppColor.success,
@ -330,7 +331,7 @@ class _InventoryPageState extends State<InventoryPage>
children: [
Expanded(
child: _buildStatCard(
'Stok Rendah',
context.lang.low_stock,
inventory.lowStockProducts.toString(),
Icons.warning_rounded,
AppColor.warning,
@ -339,7 +340,7 @@ class _InventoryPageState extends State<InventoryPage>
const SizedBox(width: 16),
Expanded(
child: _buildStatCard(
'Stok Kosong',
context.lang.zero_stock,
inventory.zeroStockProducts.toString(),
Icons.error_rounded,
AppColor.error,
@ -361,7 +362,7 @@ class _InventoryPageState extends State<InventoryPage>
children: [
Expanded(
child: _buildStatCard(
'Total Bahan',
context.lang.total_ingredients,
inventory.totalIngredients.toString(),
Icons.restaurant_menu_rounded,
AppColor.primary,
@ -370,7 +371,7 @@ class _InventoryPageState extends State<InventoryPage>
const SizedBox(width: 16),
Expanded(
child: _buildStatCard(
'Bahan Terjual',
context.lang.total_sold,
inventory.totalSoldIngredients.toString(),
Icons.check_circle_rounded,
AppColor.success,
@ -383,7 +384,7 @@ class _InventoryPageState extends State<InventoryPage>
children: [
Expanded(
child: _buildStatCard(
'Stok Kurang',
context.lang.low_stock,
inventory.lowStockIngredients.toString(),
Icons.warning_rounded,
AppColor.warning,
@ -392,7 +393,7 @@ class _InventoryPageState extends State<InventoryPage>
const SizedBox(width: 16),
Expanded(
child: _buildStatCard(
'Habis',
context.lang.zero_stock,
inventory.zeroStockIngredients.toString(),
Icons.error_rounded,
AppColor.error,

View File

@ -182,7 +182,11 @@ class InventoryProductTile extends StatelessWidget {
],
),
child: Text(
_getStatusText(),
item.isZeroStock
? context.lang.out_of_stock
: item.isLowStock
? context.lang.low_stock
: context.lang.available,
style: AppStyle.xs.copyWith(
fontSize: 10,
fontWeight: FontWeight.w700,
@ -202,7 +206,7 @@ class InventoryProductTile extends StatelessWidget {
Expanded(
child: _buildInfoItem(
LineIcons.boxes,
'Stok',
context.lang.stock,
'${NumberFormat('#,###', 'id_ID').format(item.quantity)} pcs',
_getQuantityColor(),
),
@ -212,7 +216,7 @@ class InventoryProductTile extends StatelessWidget {
Expanded(
child: _buildInfoItem(
LineIcons.dollarSign,
'Nilai',
context.lang.value_text,
_formatCurrencyShort(item.totalValue),
AppColor.info,
),
@ -259,14 +263,19 @@ class InventoryProductTile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Stok Menipis',
context.lang.low_stock,
style: AppStyle.sm.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.warning,
),
),
Text(
'Segera reorder minimal ${NumberFormat('#,###', 'id_ID').format(item.reorderLevel)} pcs',
context.lang.low_stock_desc(
NumberFormat(
'#,###',
'id_ID',
).format(item.reorderLevel),
),
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -301,14 +310,14 @@ class InventoryProductTile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Stok Habis',
context.lang.out_of_stock,
style: AppStyle.sm.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.error,
),
),
Text(
'Produk tidak tersedia untuk dijual',
context.lang.out_of_stock_desc,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -330,7 +339,7 @@ class InventoryProductTile extends StatelessWidget {
Expanded(
child: _buildMovementInfo(
LineIcons.arrowUp,
'Masuk',
context.lang.in_text,
'${NumberFormat('#,###', 'id_ID').format(item.totalIn)} pcs',
AppColor.success,
),
@ -341,7 +350,7 @@ class InventoryProductTile extends StatelessWidget {
Expanded(
child: _buildMovementInfo(
LineIcons.arrowDown,
'Keluar',
context.lang.out_text,
'${NumberFormat('#,###', 'id_ID').format(item.totalOut)} pcs',
AppColor.error,
),
@ -476,12 +485,6 @@ class InventoryProductTile extends StatelessWidget {
return AppColor.textPrimary;
}
String _getStatusText() {
if (item.isZeroStock) return 'HABIS';
if (item.isLowStock) return 'MINIM';
return 'TERSEDIA';
}
IconData _getCategoryIcon() {
final category = item.categoryName.toLowerCase();
if (category.contains('elektronik') || category.contains('gadget')) {

View File

@ -33,8 +33,8 @@ class _MainBottomNavbarState extends State<MainBottomNavbar> {
),
BottomNavigationBarItem(
icon: LineIcon(LineIcons.moneyBill),
label: 'Order',
tooltip: 'Order',
label: context.lang.order,
tooltip: context.lang.order,
),
BottomNavigationBarItem(
icon: LineIcon(LineIcons.barChart),

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'dart:math' show cos, sin;
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/order/order.dart';
import '../../../components/appbar/appbar.dart';
@ -22,33 +23,33 @@ class OrderDetailPage extends StatelessWidget {
expandedHeight: 120,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: const CustomAppBar(title: "Detail Pesanan"),
flexibleSpace: CustomAppBar(title: context.lang.order_details),
elevation: 0,
),
SliverToBoxAdapter(
child: Column(
children: [
// Order Status Card
_buildOrderStatusCard(),
_buildOrderStatusCard(context),
const SizedBox(height: 16),
// Table Visual Card (for dine-in)
if (_isDineIn()) _buildTableVisualCard(),
if (_isDineIn()) _buildTableVisualCard(context),
// Order Info Card
_buildOrderInfoCard(),
_buildOrderInfoCard(context),
const SizedBox(height: 16),
// Order Items Section
_buildOrderItemsSection(),
_buildOrderItemsSection(context),
const SizedBox(height: 16),
// Payment Summary Card
_buildPaymentSummaryCard(),
_buildPaymentSummaryCard(context),
const SizedBox(height: 16),
// Payment Methods Section
_buildPaymentMethodsSection(),
_buildPaymentMethodsSection(context),
const SizedBox(height: 24),
],
),
@ -58,7 +59,7 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildOrderStatusCard() {
Widget _buildOrderStatusCard(BuildContext context) {
Color statusColor = _getStatusColor(order.status);
return Container(
margin: const EdgeInsets.all(16),
@ -123,7 +124,7 @@ class OrderDetailPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Order Number',
context.lang.order_number,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -157,7 +158,7 @@ class OrderDetailPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Status Pesanan',
context.lang.order_status,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -197,7 +198,7 @@ class OrderDetailPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Total Amount',
context.lang.total_amount,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -222,7 +223,7 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildTableVisualCard() {
Widget _buildTableVisualCard(BuildContext context) {
return Container(
margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
height: 220, // Increased height
@ -284,14 +285,14 @@ class OrderDetailPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Makan di Tempat',
context.lang.dine_in,
style: AppStyle.sm.copyWith(
color: AppColor.white.withOpacity(0.9),
fontWeight: FontWeight.w500,
),
),
Text(
'Dine In Experience',
context.lang.dine_in_experience,
style: AppStyle.lg.copyWith(
color: AppColor.white,
fontWeight: FontWeight.bold,
@ -347,7 +348,7 @@ class OrderDetailPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'MEJA',
context.lang.table,
style: AppStyle.xs.copyWith(
color: AppColor.primary.withOpacity(
0.7,
@ -417,7 +418,7 @@ class OrderDetailPage extends StatelessWidget {
),
const SizedBox(width: 6),
Text(
'${order.orderItems.length} Items',
'${order.orderItems.length} ${context.lang.items}',
style: AppStyle.sm.copyWith(
color: AppColor.white,
fontWeight: FontWeight.w500,
@ -470,7 +471,7 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildOrderInfoCard() {
Widget _buildOrderInfoCard(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
@ -517,7 +518,7 @@ class OrderDetailPage extends StatelessWidget {
),
const SizedBox(width: 16),
Text(
'Informasi Pesanan',
context.lang.order_information,
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
@ -527,24 +528,28 @@ class OrderDetailPage extends StatelessWidget {
),
const SizedBox(height: 24),
if (_shouldShowTableNumber())
_buildInfoRow(Icons.table_restaurant, 'Meja', order.tableNumber),
_buildInfoRow(
Icons.table_restaurant,
context.lang.table,
order.tableNumber,
),
_buildInfoRow(
Icons.delivery_dining,
'Tipe Pesanan',
context.lang.order_type,
order.orderType,
),
_buildInfoRow(
Icons.payment,
'Status Pembayaran',
context.lang.payment_status,
order.paymentStatus,
),
_buildInfoRow(
Icons.access_time,
'Dibuat',
context.lang.created,
_formatDateTime(order.createdAt),
),
if (order.notes.isNotEmpty)
_buildInfoRow(Icons.note, 'Catatan', order.notes),
_buildInfoRow(Icons.note, context.lang.note, order.notes),
],
),
),
@ -590,7 +595,7 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildOrderItemsSection() {
Widget _buildOrderItemsSection(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
@ -612,7 +617,7 @@ class OrderDetailPage extends StatelessWidget {
child: Row(
children: [
Text(
'Item Pesanan',
context.lang.order_item,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
@ -629,7 +634,7 @@ class OrderDetailPage extends StatelessWidget {
borderRadius: BorderRadius.circular(12),
),
child: Text(
'${order.orderItems.length} Item',
'${order.orderItems.length} ${context.lang.item}',
style: AppStyle.sm.copyWith(
color: AppColor.primary,
fontWeight: FontWeight.w600,
@ -647,7 +652,7 @@ class OrderDetailPage extends StatelessWidget {
separatorBuilder: (context, index) => const Divider(height: 24),
itemBuilder: (context, index) {
final item = order.orderItems[index];
return _buildOrderItemCard(item);
return _buildOrderItemCard(context, item);
},
),
],
@ -655,9 +660,9 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildOrderItemCard(OrderItem item) {
Widget _buildOrderItemCard(BuildContext context, OrderItem item) {
// Assume we add status to OrderItem model or determine from order status
String itemStatus = _getItemStatus(item);
String itemStatus = _getItemStatus(context, item);
Color itemStatusColor = _getItemStatusColor(itemStatus);
return Container(
@ -786,7 +791,7 @@ class OrderDetailPage extends StatelessWidget {
borderRadius: BorderRadius.circular(6),
),
child: Text(
'Diskon: -Rp ${_formatCurrency(item.discountAmount)}',
'${context.lang.discount}: -Rp ${_formatCurrency(item.discountAmount)}',
style: AppStyle.xs.copyWith(
color: AppColor.error,
fontWeight: FontWeight.w600,
@ -811,7 +816,7 @@ class OrderDetailPage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Item',
context.lang.total_item,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -845,7 +850,7 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildPaymentSummaryCard() {
Widget _buildPaymentSummaryCard(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
@ -866,26 +871,38 @@ class OrderDetailPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Ringkasan Pembayaran',
context.lang.payment_summary,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.primary,
),
),
const SizedBox(height: 16),
_buildSummaryRow('Subtotal', order.subtotal),
_buildSummaryRow(context.lang.subtotal, order.subtotal),
if (order.discountAmount > 0)
_buildSummaryRow(
'Diskon',
context.lang.discount,
-order.discountAmount,
isDiscount: true,
),
_buildSummaryRow('Pajak', order.taxAmount),
_buildSummaryRow(context.lang.tax, order.taxAmount),
const Divider(height: 24),
_buildSummaryRow('Total', order.totalAmount, isTotal: true),
_buildSummaryRow('Dibayar', order.totalPaid, isSuccess: true),
_buildSummaryRow(
context.lang.total,
order.totalAmount,
isTotal: true,
),
_buildSummaryRow(
context.lang.paid,
order.totalPaid,
isSuccess: true,
),
if (order.remainingAmount > 0)
_buildSummaryRow('Sisa', order.remainingAmount, isError: true),
_buildSummaryRow(
context.lang.remaining,
order.remainingAmount,
isError: true,
),
],
),
),
@ -930,7 +947,7 @@ class OrderDetailPage extends StatelessWidget {
);
}
Widget _buildPaymentMethodsSection() {
Widget _buildPaymentMethodsSection(BuildContext context) {
if (order.payments.isEmpty) return const SizedBox();
return Container(
@ -952,7 +969,7 @@ class OrderDetailPage extends StatelessWidget {
Padding(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 0),
child: Text(
'Metode Pembayaran',
context.lang.payment_method,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
@ -1159,7 +1176,7 @@ class OrderDetailPage extends StatelessWidget {
}
}
String _getItemStatus(OrderItem item) {
String _getItemStatus(BuildContext context, OrderItem item) {
// Logic untuk menentukan status item berdasarkan:
// 1. Status order secara keseluruhan
// 2. Jika ada field status di OrderItem model
@ -1167,26 +1184,24 @@ class OrderDetailPage extends StatelessWidget {
switch (order.status.toLowerCase()) {
case 'completed':
return 'Selesai';
return context.lang.completed;
case 'pending':
return 'Menunggu';
return context.lang.pending;
case 'cancelled':
return 'Dibatalkan';
return context.lang.void_text;
default:
return 'Menunggu';
return context.lang.pending;
}
}
Color _getItemStatusColor(String status) {
switch (status.toLowerCase()) {
case 'selesai':
case 'completed':
return AppColor.success;
case 'diproses':
case 'pending':
return AppColor.warning;
case 'dibatalkan':
case 'cancelled':
return AppColor.error;
case 'siap':
return AppColor.info;
default:
return AppColor.primary;
}

View File

@ -3,15 +3,13 @@ import 'dart:developer';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../application/order/order_loader/order_loader_bloc.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../injection.dart';
import '../../../components/appbar/appbar.dart';
import '../../../components/button/button.dart';
import '../../../components/spacer/spacer.dart';
import '../../../components/widgets/empty_widget.dart';
import '../../../router/app_router.gr.dart';
import 'widgets/filter_header_delegate.dart';
@ -224,11 +222,10 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
pinned: true,
backgroundColor: AppColor.primary,
centerTitle: false,
flexibleSpace: CustomAppBar(title: 'Order', isBack: false),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
SpaceWidth(8),
],
flexibleSpace: CustomAppBar(
title: context.lang.orders,
isBack: false,
),
),
// Pinned Filter Section
@ -285,7 +282,7 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
child: Row(
children: [
Text(
'${state.orders.length} ${state.status.toLowerCase()} order${state.orders.length != 1 ? 's' : ''}',
'${state.orders.length} ${state.status.toLowerCase()} ${context.lang.orders}',
style: TextStyle(
color: AppColor.textSecondary,
fontSize: 14,
@ -300,9 +297,10 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
_buildShimmerList()
else if (state.orders.isEmpty)
EmptyWidget(
title: 'Order',
message:
'No ${state.status.toLowerCase()} orders found',
title: context.lang.order,
message: context.lang.no_order_with_status(
state.status.toLowerCase(),
),
)
else
ListView.builder(

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../../../../../common/extension/extension.dart';
import '../../../../components/field/date_range_picker_field.dart';
import 'status_tile.dart';
@ -36,7 +37,6 @@ class FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
double shrinkOffset,
bool overlapsContent,
) {
print('FilterHeaderDelegate build called'); // Debug log
return Container(
color: backgroundColor,
padding: padding,
@ -50,9 +50,6 @@ class FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
startDate: startDate,
endDate: endDate,
onChanged: (start, end) {
print(
'onChanged called in FilterHeaderDelegate: $start - $end',
); // Debug log
onDateChanged(start, end);
},
),
@ -70,7 +67,11 @@ class FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
right: index < filterOptions.length - 1 ? 8 : 0,
),
child: OrderStatusTile(
label: option,
label: option == "All"
? context.lang.all
: option == "Completed"
? context.lang.completed
: context.lang.pending,
isSelected: option == selectedFilter,
onSelected: (isSelected) {
if (isSelected) {

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../../../common/extension/extension.dart';
import '../../../../../common/theme/theme.dart';
import '../../../../../domain/order/order.dart';
@ -46,19 +47,19 @@ class OrderTile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header Row
_buildHeaderRow(),
_buildHeaderRow(context),
const SizedBox(height: 12),
// Order Info
_buildOrderInfo(),
_buildOrderInfo(context),
const SizedBox(height: 16),
// Amount Section
_buildAmountSection(),
_buildAmountSection(context),
const SizedBox(height: 16),
// Footer with Actions
_buildFooterActions(),
_buildFooterActions(context),
],
),
),
@ -67,7 +68,7 @@ class OrderTile extends StatelessWidget {
);
}
Widget _buildHeaderRow() {
Widget _buildHeaderRow(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -94,12 +95,12 @@ class OrderTile extends StatelessWidget {
),
],
),
_buildStatusChip(),
_buildStatusChip(context),
],
);
}
Widget _buildStatusChip() {
Widget _buildStatusChip(BuildContext context) {
Color statusColor;
String statusText;
IconData statusIcon;
@ -107,27 +108,34 @@ class OrderTile extends StatelessWidget {
// Check isVoid and isRefund first for display
if (order.isVoid) {
statusColor = AppColor.error;
statusText = 'Void';
statusText = context.lang.void_text;
statusIcon = Icons.block;
} else if (order.isRefund) {
statusColor = AppColor.info;
statusText = 'Refunded';
statusText = context.lang.refund;
statusIcon = Icons.undo;
} else {
// Handle status values (only pending and completed)
switch (order.status.toLowerCase()) {
case 'completed':
statusColor = AppColor.success;
statusText = context.lang.completed;
statusIcon = Icons.check_circle;
case 'paid':
case 'finished':
statusColor = AppColor.success;
statusText = 'Completed';
statusText = context.lang.completed;
statusIcon = Icons.check_circle;
break;
case 'pending':
statusColor = AppColor.warning;
statusText = context.lang.pending;
statusIcon = Icons.schedule;
break;
case 'waiting':
case 'processing':
statusColor = AppColor.warning;
statusText = 'Pending';
statusText = context.lang.pending;
statusIcon = Icons.schedule;
break;
default:
@ -163,7 +171,7 @@ class OrderTile extends StatelessWidget {
);
}
Widget _buildOrderInfo() {
Widget _buildOrderInfo(BuildContext context) {
return Row(
children: [
Expanded(
@ -177,7 +185,7 @@ class OrderTile extends StatelessWidget {
const SizedBox(width: 6),
Expanded(
child: Text(
_getOrderInfoText(),
_getOrderInfoText(context),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
@ -198,7 +206,7 @@ class OrderTile extends StatelessWidget {
),
const SizedBox(width: 6),
Text(
'${order.orderItems.length} items',
'${order.orderItems.length} ${context.lang.items}',
style: const TextStyle(
fontSize: 13,
color: AppColor.textSecondary,
@ -239,7 +247,7 @@ class OrderTile extends StatelessWidget {
);
}
Widget _buildAmountSection() {
Widget _buildAmountSection(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
@ -264,8 +272,8 @@ class OrderTile extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Total Amount',
Text(
context.lang.total_amount,
style: TextStyle(
fontSize: 14,
color: AppColor.textWhite,
@ -274,7 +282,7 @@ class OrderTile extends StatelessWidget {
),
const SizedBox(height: 4),
Text(
'Rp ${NumberFormat('#,###').format(order.totalAmount)}',
order.totalAmount.currencyFormatRp,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
@ -284,7 +292,7 @@ class OrderTile extends StatelessWidget {
if (order.remainingAmount > 0) ...[
const SizedBox(height: 4),
Text(
'Remaining: Rp ${NumberFormat('#,###').format(order.remainingAmount)}',
'${context.lang.remaining}: ${order.remainingAmount.currencyFormatRp}',
style: const TextStyle(
fontSize: 12,
color: AppColor.textWhite,
@ -311,7 +319,7 @@ class OrderTile extends StatelessWidget {
);
}
Widget _buildFooterActions() {
Widget _buildFooterActions(BuildContext context) {
// Don't show anything if order is void or refunded
if (order.isVoid || order.isRefund) {
return const SizedBox.shrink();
@ -326,7 +334,7 @@ class OrderTile extends StatelessWidget {
if (order.payments.isNotEmpty) ...[
const SizedBox(height: 2),
Text(
'Payment: ${_getPaymentMethods()}',
'${context.lang.payment}: ${_getPaymentMethods()}',
style: const TextStyle(
fontSize: 11,
color: AppColor.textLight,
@ -337,59 +345,10 @@ class OrderTile extends StatelessWidget {
],
),
),
if (order.status.toLowerCase() == 'completed') ...[
_buildActionButton(
icon: Icons.print,
label: 'Print',
onPressed: onPrint,
color: AppColor.info,
),
const SizedBox(width: 8),
_buildActionButton(
icon: Icons.undo,
label: 'Refund',
onPressed: onRefund,
color: AppColor.warning,
),
],
],
);
}
Widget _buildActionButton({
required IconData icon,
required String label,
required VoidCallback? onPressed,
required Color color,
}) {
return Material(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
child: InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: color),
const SizedBox(width: 4),
Text(
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: color,
),
),
],
),
),
),
);
}
IconData _getOrderInfoIcon() {
switch (order.orderType.toLowerCase()) {
case 'dine in':
@ -406,11 +365,11 @@ class OrderTile extends StatelessWidget {
}
}
String _getOrderInfoText() {
String _getOrderInfoText(BuildContext context) {
switch (order.orderType.toLowerCase()) {
case 'dine in':
case 'dine_in':
return 'Table ${order.tableNumber.isNotEmpty ? order.tableNumber : 'N/A'}';
return '${context.lang.table} ${order.tableNumber.isNotEmpty ? order.tableNumber : 'N/A'}';
case 'takeaway':
case 'take_away':
case 'pickup':
@ -419,8 +378,8 @@ class OrderTile extends StatelessWidget {
return 'Delivery Order';
default:
return order.tableNumber.isNotEmpty
? 'Table ${order.tableNumber}'
: 'Order ${order.orderNumber}';
? '${context.lang.table} ${order.tableNumber}'
: context.lang.order;
}
}

View File

@ -3,10 +3,12 @@ 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/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/outlet/outlet.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/spacer/spacer.dart';
// Outlet Information Page
@RoutePage()
@ -79,14 +81,14 @@ class _OutletInformationPageState extends State<OutletInformationPage>
expandedHeight: 120.0,
floating: false,
pinned: true,
flexibleSpace: CustomAppBar(title: 'Outlet Information'),
flexibleSpace: CustomAppBar(title: context.lang.outlet_information),
),
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: _buildContent(),
child: _buildContent(context),
),
),
),
@ -95,7 +97,7 @@ class _OutletInformationPageState extends State<OutletInformationPage>
);
}
Widget _buildContent() {
Widget _buildContent(BuildContext context) {
return BlocBuilder<CurrentOutletLoaderBloc, CurrentOutletLoaderState>(
builder: (context, state) {
return Padding(
@ -105,15 +107,11 @@ class _OutletInformationPageState extends State<OutletInformationPage>
children: [
_buildHeaderCard(state.outlet),
const SizedBox(height: 20),
_buildInfoSection(state.outlet),
_buildInfoSection(context, state.outlet),
const SizedBox(height: 20),
_buildContactSection(state.outlet),
_buildBusinessSection(context, state.outlet),
const SizedBox(height: 20),
_buildBusinessSection(state.outlet),
const SizedBox(height: 20),
_buildStatusSection(state.outlet),
const SizedBox(height: 20),
_buildTimestampSection(state.outlet),
_buildStatusSection(context, state.outlet),
],
),
);
@ -190,62 +188,65 @@ class _OutletInformationPageState extends State<OutletInformationPage>
);
}
Widget _buildInfoSection(Outlet outlet) {
Widget _buildInfoSection(BuildContext context, 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,
_buildSectionTitle(
context.lang.outlet_information,
Icons.info_outline,
),
SpaceHeight(20),
_buildInfoRow(
context.lang.address,
outlet.address,
Icons.location_on,
),
_buildInfoRow(
context.lang.phone_number,
outlet.phoneNumber,
Icons.phone,
),
_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) {
Widget _buildBusinessSection(BuildContext context, Outlet outlet) {
return _buildAnimatedCard(
delay: 600,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Business Settings', Icons.settings_applications),
_buildSectionTitle(
context.lang.business_settings,
Icons.settings_applications,
),
const SizedBox(height: 16),
_buildInfoRow('Currency', outlet.currency, Icons.monetization_on),
_buildInfoRow('Tax Rate', '${outlet.taxRate}%', Icons.percent),
_buildInfoRow(
context.lang.currency,
outlet.currency,
Icons.monetization_on,
),
_buildInfoRow(
context.lang.tax_rate,
'${outlet.taxRate}%',
Icons.percent,
),
],
),
);
}
Widget _buildStatusSection(Outlet outlet) {
Widget _buildStatusSection(BuildContext context, Outlet outlet) {
return _buildAnimatedCard(
delay: 800,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Status', Icons.toggle_on),
_buildSectionTitle(context.lang.status_text, Icons.toggle_on),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
@ -272,7 +273,7 @@ class _OutletInformationPageState extends State<OutletInformationPage>
),
const SizedBox(width: 12),
Text(
outlet.isActive ? 'Active' : 'Inactive',
outlet.isActive ? context.lang.active : context.lang.inactive,
style: AppStyle.md.copyWith(
color: outlet.isActive ? AppColor.success : AppColor.error,
fontWeight: FontWeight.w600,
@ -286,29 +287,6 @@ class _OutletInformationPageState extends State<OutletInformationPage>
);
}
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),
@ -396,8 +374,4 @@ class _OutletInformationPageState extends State<OutletInformationPage>
),
);
}
String _formatDateTime(DateTime dateTime) {
return '${dateTime.day}/${dateTime.month}/${dateTime.year} ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
}
}

View File

@ -3,6 +3,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../../injection.dart';
@ -136,18 +137,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
pinned: true,
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: FlexibleSpaceBar(
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: AppColor.primaryGradient,
),
),
child: const CustomAppBar(title: "Analisis Produk"),
),
),
flexibleSpace: CustomAppBar(title: context.lang.product_analytic),
);
}
@ -214,7 +204,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
Expanded(
child: _buildSummaryCard(
icon: Icons.monetization_on,
title: 'Total Pendapatan',
title: context.lang.total_revenue,
value: _formatCurrency(stats.totalRevenue),
color: AppColor.success,
),
@ -223,7 +213,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
Expanded(
child: _buildSummaryCard(
icon: Icons.shopping_cart,
title: 'Total Terjual',
title: context.lang.total_sold,
value: _formatNumber(stats.totalQuantity),
color: AppColor.info,
),
@ -236,7 +226,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
Expanded(
child: _buildSummaryCard(
icon: Icons.receipt_long,
title: 'Total Pesanan',
title: context.lang.total_orders,
value: _formatNumber(stats.totalOrders),
color: AppColor.warning,
),
@ -245,7 +235,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
Expanded(
child: _buildSummaryCard(
icon: Icons.trending_up,
title: 'Rata-rata Nilai',
title: context.lang.average_price,
value: _formatCurrency(stats.averageOrderValue),
color: AppColor.primary,
),
@ -541,7 +531,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
Icon(Icons.trending_up, color: AppColor.success, size: 20),
const SizedBox(width: 8),
Text(
'Pendapatan',
context.lang.revenue,
style: _getTextStyle(
AppStyle.sm,
color: AppColor.success,
@ -552,7 +542,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
),
const SizedBox(height: 8),
Text(
_formatCurrency(product.revenue.toDouble()),
product.revenue.currencyFormatRp,
style: _getTextStyle(
AppStyle.xl,
color: AppColor.success,
@ -570,14 +560,14 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
_buildStatCard(
icon: Icons.shopping_cart_outlined,
value: '${product.quantitySold}',
label: 'Terjual',
label: context.lang.sold,
color: AppColor.info,
),
const SizedBox(height: 8),
_buildStatCard(
icon: Icons.receipt_outlined,
value: '${product.orderCount}',
label: 'Pesanan',
label: context.lang.orders,
color: AppColor.warning,
),
],
@ -645,7 +635,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Harga Rata-rata',
context.lang.average_price,
style: _getTextStyle(
AppStyle.sm,
color: AppColor.textSecondary,
@ -653,7 +643,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
),
),
Text(
_formatCurrency(product.averagePrice),
product.averagePrice.round().currencyFormatRp,
style: _getTextStyle(
AppStyle.sm,
color: _getCategoryColor(product.categoryName),

View File

@ -6,6 +6,7 @@ import 'package:shimmer/shimmer.dart';
import '../../../../application/category/category_loader/category_loader_bloc.dart';
import '../../../../application/product/product_loader/product_loader_bloc.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/category/category.dart';
import '../../../../domain/product/product.dart';
@ -83,7 +84,7 @@ class _ProductPageState extends State<ProductPage>
child: CustomScrollView(
controller: scrollController,
slivers: [
_buildSliverAppBar(),
_buildSliverAppBar(context),
_buildCategoryFilter(),
_buildProductContent(state),
],
@ -95,13 +96,13 @@ class _ProductPageState extends State<ProductPage>
);
}
Widget _buildSliverAppBar() {
Widget _buildSliverAppBar(BuildContext context) {
return SliverAppBar(
expandedHeight: 120.0,
floating: false,
pinned: true,
elevation: 0,
flexibleSpace: CustomAppBar(title: 'Produk'),
flexibleSpace: CustomAppBar(title: context.lang.product),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.search),
ActionIconButton(

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../application/user/change_password_form/change_password_form_bloc.dart';
import '../../../../../common/extension/extension.dart';
import '../../../../../common/theme/theme.dart';
import '../../../../../injection.dart';
import '../../../../components/appbar/appbar.dart';
@ -39,7 +40,7 @@ class _ProfileChangePasswordPageState extends State<ProfileChangePasswordPage> {
(f) => AppFlushbar.showUserFailureToast(context, f),
(user) {
if (context.mounted) {
AppFlushbar.showSuccess(context, 'Password changed');
AppFlushbar.showSuccess(context, context.lang.password_changed);
Future.delayed(const Duration(seconds: 2), () {
context.router.back();
});
@ -59,7 +60,7 @@ class _ProfileChangePasswordPageState extends State<ProfileChangePasswordPage> {
pinned: true,
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Change Password'),
flexibleSpace: CustomAppBar(title: context.lang.change_password),
),
SliverToBoxAdapter(
child:
@ -83,7 +84,7 @@ class _ProfileChangePasswordPageState extends State<ProfileChangePasswordPage> {
ChangePasswordNewPassword(),
SpaceHeight(24),
AppElevatedButton(
text: 'Save',
text: context.lang.save,
isLoading: state.isSubmitting,
onPressed: () {
context.read<ChangePasswordFormBloc>().add(

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../../../application/user/change_password_form/change_password_form_bloc.dart';
import '../../../../../../common/extension/extension.dart';
import '../../../../../components/field/field.dart';
class ChangePasswordCurrentPassword extends StatelessWidget {
@ -11,9 +12,9 @@ class ChangePasswordCurrentPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AppPasswordTextFormField(
title: 'Current Password',
title: context.lang.current_password,
prefixIcon: LineIcons.lock,
hintText: 'Please enter your current password',
hintText: context.lang.current_password_placeholder,
onChanged: (value) => context.read<ChangePasswordFormBloc>().add(
ChangePasswordFormEvent.currentPasswordChanged(value),
),
@ -23,7 +24,7 @@ class ChangePasswordCurrentPassword extends StatelessWidget {
.state
.currentPassword
.isEmpty) {
return 'Please enter your current password';
return context.lang.current_password_placeholder;
}
return null;
},

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../../../application/user/change_password_form/change_password_form_bloc.dart';
import '../../../../../../common/extension/extension.dart';
import '../../../../../components/field/field.dart';
class ChangePasswordNewPassword extends StatelessWidget {
@ -11,20 +12,20 @@ class ChangePasswordNewPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AppPasswordTextFormField(
title: 'New Password',
title: context.lang.new_password,
prefixIcon: LineIcons.lock,
hintText: 'Please enter your new password',
hintText: context.lang.new_password_placeholder,
onChanged: (value) => context.read<ChangePasswordFormBloc>().add(
ChangePasswordFormEvent.newPasswordChanged(value),
),
validator: (value) {
if (context.read<ChangePasswordFormBloc>().state.newPassword.isEmpty) {
return 'Please enter your new password';
return context.lang.new_password_placeholder;
}
if (context.read<ChangePasswordFormBloc>().state.newPassword ==
context.read<ChangePasswordFormBloc>().state.currentPassword) {
return 'New password cannot be same as current password';
return context.lang.new_password_not_same;
}
return null;
},

View File

@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../application/auth/auth_bloc.dart';
import '../../../../../application/user/user_edit_form/user_edit_form_bloc.dart';
import '../../../../../common/extension/extension.dart';
import '../../../../../common/theme/theme.dart';
import '../../../../../domain/user/user.dart';
import '../../../../../injection.dart';
@ -64,7 +65,7 @@ class _ProfileEditPageState extends State<ProfileEditPage> {
pinned: true,
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Profile Edit'),
flexibleSpace: CustomAppBar(title: context.lang.edit_profile),
),
SliverToBoxAdapter(
child: BlocBuilder<UserEditFormBloc, UserEditFormState>(
@ -85,7 +86,7 @@ class _ProfileEditPageState extends State<ProfileEditPage> {
ProfileEditNameField(controller: nameController),
SpaceHeight(24),
AppElevatedButton(
text: 'Save',
text: context.lang.save,
isLoading: state.isSubmitting,
onPressed: () {
context.read<UserEditFormBloc>().add(

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../../../application/user/user_edit_form/user_edit_form_bloc.dart';
import '../../../../../../common/extension/extension.dart';
import '../../../../../components/field/field.dart';
class ProfileEditNameField extends StatelessWidget {
@ -12,9 +13,9 @@ class ProfileEditNameField extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AppTextFormField(
title: 'Name',
title: context.lang.name,
prefixIcon: LineIcons.user,
hintText: 'Please enter your name',
hintText: context.lang.name_placeholder,
controller: controller,
onChanged: (value) {
context.read<UserEditFormBloc>().add(
@ -23,7 +24,7 @@ class ProfileEditNameField extends StatelessWidget {
},
validator: (value) {
if (context.read<UserEditFormBloc>().state.name.isEmpty) {
return 'Please enter your name';
return context.lang.name_placeholder;
}
return null;

View File

@ -6,6 +6,7 @@ import 'package:loader_overlay/loader_overlay.dart';
import '../../../application/auth/auth_bloc.dart';
import '../../../application/auth/logout_form/logout_form_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../injection.dart';
import '../../components/button/button.dart';
@ -89,7 +90,7 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
MainAxisAlignment.spaceBetween,
children: [
Text(
'Profile',
context.lang.profile,
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.w700,
fontSize: 18,

View File

@ -34,7 +34,7 @@ class ProfileAccountInfo extends StatelessWidget {
Padding(
padding: EdgeInsets.all(16),
child: Text(
'Account Information',
context.lang.account_information,
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -45,7 +45,7 @@ class ProfileAccountInfo extends StatelessWidget {
ProfileTile(
icon: LineIcons.envelope,
title: 'Email',
title: context.lang.email,
subtitle: user.email,
showArrow: false,
),
@ -54,7 +54,7 @@ class ProfileAccountInfo extends StatelessWidget {
ProfileTile(
icon: LineIcons.calendarAlt,
title: 'Member Since',
title: context.lang.member_since,
subtitle: user.createdAt.toDate,
showArrow: false,
),
@ -62,15 +62,15 @@ class ProfileAccountInfo extends StatelessWidget {
ProfileTile(
icon: LineIcons.userEdit,
title: 'Ubah Profil',
subtitle: 'Ubah profil kamu',
title: context.lang.edit_profile,
subtitle: context.lang.edit_profile_desc,
onTap: () => context.router.push(ProfileEditRoute(user: user)),
),
ProfileDivider(),
ProfileTile(
icon: LineIcons.lock,
title: 'Change Password',
subtitle: 'Change your password',
title: context.lang.change_password,
subtitle: context.lang.change_password_desc,
onTap: () => context.router.push(ProfileChangePasswordRoute()),
),
],

View File

@ -1,6 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../router/app_router.gr.dart';
import 'profile_tile.dart';
@ -37,7 +38,7 @@ class _ProfileAppSettingState extends State<ProfileAppSetting> {
Padding(
padding: EdgeInsets.all(16),
child: Text(
'App Settings',
context.lang.app_settings,
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -74,8 +75,8 @@ class _ProfileAppSettingState extends State<ProfileAppSetting> {
// ProfileDivider(),
ProfileTile(
icon: Icons.language_outlined,
title: 'Language',
subtitle: 'English (US)',
title: context.lang.language,
subtitle: context.lang.language_desc,
onTap: () => context.router.push(LanguageRoute()),
),
],

View File

@ -1,6 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../router/app_router.gr.dart';
import 'divider.dart';
@ -30,7 +31,7 @@ class ProfileBusinessSetting extends StatelessWidget {
Padding(
padding: EdgeInsets.all(16),
child: Text(
'Business Settings',
context.lang.business_settings,
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -41,8 +42,8 @@ class ProfileBusinessSetting extends StatelessWidget {
ProfileTile(
icon: Icons.business_outlined,
title: 'Outlet Information',
subtitle: 'Manage your Outlet details',
title: context.lang.outlet_information,
subtitle: context.lang.outlet_informatio_desc,
onTap: () => context.router.push(OutletInformationRoute()),
),
@ -50,8 +51,8 @@ class ProfileBusinessSetting extends StatelessWidget {
ProfileTile(
icon: Icons.people_outline,
title: 'Staff Management',
subtitle: 'Manage employees and permissions',
title: context.lang.staff_management,
subtitle: context.lang.staff_management_desc,
onTap: () => context.router.push(ComingSoonRoute()),
),
@ -59,16 +60,16 @@ class ProfileBusinessSetting extends StatelessWidget {
ProfileTile(
icon: Icons.inventory_2_outlined,
title: 'Product',
subtitle: 'Manage your products',
title: context.lang.products,
subtitle: context.lang.manage_your_products,
onTap: () => context.router.push(ProductRoute()),
),
ProfileDivider(),
ProfileTile(
icon: Icons.download_outlined,
title: 'Download Report',
subtitle: 'Download your sales or inventory report',
title: context.lang.download_report,
subtitle: context.lang.download_report_desc,
onTap: () => context.router.push(DownloadReportRoute()),
),
],

View File

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/auth/logout_form/logout_form_bloc.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../components/spacer/spacer.dart';
import 'profile_tile.dart';
class ProfileDangerZone extends StatelessWidget {
@ -28,27 +28,10 @@ class ProfileDangerZone extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(Icons.warning_outlined, color: AppColor.error, size: 20),
const SpaceWidth(8),
Text(
'Danger Zone',
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.error,
),
),
],
),
),
ProfileTile(
icon: Icons.logout,
title: 'Logout',
subtitle: 'Sign out from your account',
title: context.lang.logout,
subtitle: context.lang.logout_desc,
iconColor: AppColor.error,
textColor: AppColor.error,
onTap: () {

View File

@ -1,6 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../router/app_router.gr.dart';
import 'divider.dart';
@ -30,7 +31,7 @@ class ProfileSupport extends StatelessWidget {
Padding(
padding: EdgeInsets.all(16),
child: Text(
'Support',
context.lang.support,
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
@ -41,8 +42,8 @@ class ProfileSupport extends StatelessWidget {
ProfileTile(
icon: Icons.help_outline,
title: 'Help Center',
subtitle: 'Get help and support',
title: context.lang.help_center,
subtitle: context.lang.help_center_desc,
onTap: () => context.router.push(ComingSoonRoute()),
),
@ -60,8 +61,8 @@ class ProfileSupport extends StatelessWidget {
ProfileTile(
icon: Icons.info_outline,
title: 'About',
subtitle: 'App version and information',
title: context.lang.about,
subtitle: context.lang.about_desc,
onTap: () => context.router.push(AboutAppRoute()),
),
],

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import 'widgets/purchase_tile.dart';
@ -93,7 +94,7 @@ class _PurchasePageState extends State<PurchasePage>
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Pembelian'),
flexibleSpace: CustomAppBar(title: context.lang.purchase),
),
// Stats Cards
@ -105,7 +106,7 @@ class _PurchasePageState extends State<PurchasePage>
children: [
Expanded(
child: PurchaseStatCard(
title: 'Total Pembelian',
title: context.lang.total_purchase,
value: 'Rp 8.340.000',
icon: LineIcons.shoppingCart,
iconColor: AppColor.success,
@ -115,8 +116,8 @@ class _PurchasePageState extends State<PurchasePage>
const SizedBox(width: 12),
Expanded(
child: PurchaseStatCard(
title: 'Pending Order',
value: '3 Orders',
title: context.lang.pending_order,
value: '3 ${context.lang.orders}',
icon: LineIcons.clock,
iconColor: AppColor.warning,
cardAnimation: cardAnimation,
@ -139,7 +140,7 @@ class _PurchasePageState extends State<PurchasePage>
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Riwayat Pembelian',
context.lang.history_purchase,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w600,
),
@ -154,7 +155,7 @@ class _PurchasePageState extends State<PurchasePage>
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${purchaseData.length} Orders',
'${purchaseData.length} ${context.lang.orders}',
style: AppStyle.sm.copyWith(
color: AppColor.textWhite,
),
@ -220,20 +221,6 @@ class _PurchasePageState extends State<PurchasePage>
const SliverToBoxAdapter(child: SizedBox(height: 80)),
],
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
// Navigate to create new purchase
},
backgroundColor: AppColor.secondary,
icon: const Icon(LineIcons.plus, color: AppColor.textWhite),
label: Text(
'Buat Pembelian',
style: AppStyle.md.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w600,
),
),
),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
class PurchaseTile extends StatelessWidget {
@ -219,7 +220,7 @@ class PurchaseTile extends StatelessWidget {
),
const SizedBox(width: 4),
Text(
'${purchase['items']} items',
'${purchase['items']} ${context.lang.items}',
style: AppStyle.xs.copyWith(
color: AppColor.secondary,
fontWeight: FontWeight.w600,
@ -241,7 +242,7 @@ class PurchaseTile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Total Pembelian',
context.lang.total_purchase,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,

View File

@ -1,14 +1,13 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:line_icons/line_icons.dart';
import 'dart:math' as math;
import '../../../application/analytic/dashboard_analytic_loader/dashboard_analytic_loader_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import '../../components/field/date_range_picker_field.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/payment_method.dart';
@ -117,17 +116,17 @@ class _ReportPageState extends State<ReportPage> with TickerProviderStateMixin {
backgroundColor: AppColor.primary,
centerTitle: false,
flexibleSpace: CustomAppBar(
title: 'Laporan',
title: context.lang.report,
isBack: false,
),
actions: [
ActionIconButton(
onTap: () {},
icon: LineIcons.download,
),
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
SpaceWidth(8),
],
// actions: [
// ActionIconButton(
// onTap: () {},
// icon: LineIcons.download,
// ),
// ActionIconButton(onTap: () {}, icon: LineIcons.filter),
// SpaceWidth(8),
// ],
),
SliverToBoxAdapter(

View File

@ -57,7 +57,7 @@ class ReportPaymentMethod extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Payment Methods',
context.lang.payment_methods,
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
@ -65,7 +65,7 @@ class ReportPaymentMethod extends StatelessWidget {
),
const SizedBox(height: 4),
Text(
'Revenue breakdown by payment method',
context.lang.payment_methods_desc,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
@ -80,7 +80,7 @@ class ReportPaymentMethod extends StatelessWidget {
// Payment Method List
if (paymentMethods.isEmpty)
_buildEmptyState()
_buildEmptyState(context)
else
ListView.separated(
shrinkWrap: true,
@ -190,12 +190,12 @@ class ReportPaymentMethod extends StatelessWidget {
const SizedBox(height: 16),
// Stats row with better spacing
_buildStatsSection(method),
_buildStatsSection(context, method),
const SizedBox(height: 16),
// Enhanced progress bar section
_buildProgressSection(method, index),
_buildProgressSection(context, method, index),
],
),
),
@ -410,7 +410,10 @@ class ReportPaymentMethod extends StatelessWidget {
);
}
Widget _buildStatsSection(DashboardPaymentMethod method) {
Widget _buildStatsSection(
BuildContext context,
DashboardPaymentMethod method,
) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
@ -426,7 +429,7 @@ class ReportPaymentMethod extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Total Revenue',
context.lang.total_revenue,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -457,7 +460,7 @@ class ReportPaymentMethod extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Orders',
context.lang.orders,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -480,7 +483,11 @@ class ReportPaymentMethod extends StatelessWidget {
);
}
Widget _buildProgressSection(DashboardPaymentMethod method, int index) {
Widget _buildProgressSection(
BuildContext context,
DashboardPaymentMethod method,
int index,
) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -488,7 +495,7 @@ class ReportPaymentMethod extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Revenue Share',
context.lang.revenue_share,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w600,
@ -560,11 +567,10 @@ class ReportPaymentMethod extends StatelessWidget {
);
}
Widget _buildEmptyState() {
Widget _buildEmptyState(BuildContext context) {
return EmptyWidget(
title: 'No Payment Methods',
message:
'Payment method data will appear here once transactions are made',
title: context.lang.no_payment_methods,
message: context.lang.no_payment_methods_desc,
);
}

View File

@ -24,7 +24,7 @@ class ReportQuickStats extends StatelessWidget {
return Transform.scale(
scale: value,
child: ReportStatTile(
title: 'Total Orders',
title: context.lang.total_orders,
value: overview.totalOrders.toString(),
icon: Icons.receipt_long,
color: AppColor.info,
@ -43,7 +43,7 @@ class ReportQuickStats extends StatelessWidget {
return Transform.scale(
scale: value,
child: ReportStatTile(
title: 'Average Order',
title: context.lang.average_price,
value: overview.averageOrderValue
.round()
.currencyFormatRp,
@ -70,7 +70,7 @@ class ReportQuickStats extends StatelessWidget {
return Transform.scale(
scale: value,
child: ReportStatTile(
title: 'Customers',
title: context.lang.customer,
value: overview.totalCustomers.toString(),
icon: Icons.people,
color: AppColor.success,
@ -89,7 +89,8 @@ class ReportQuickStats extends StatelessWidget {
return Transform.scale(
scale: value,
child: ReportStatTile(
title: 'Void + Refund',
title:
'${context.lang.void_text} + ${context.lang.refund}',
value: (overview.voidedOrders + overview.refundedOrders)
.toString(),

View File

@ -103,7 +103,7 @@ class ReportRevenueSummary extends StatelessWidget {
),
const SpaceWidth(12),
Text(
'Total Pendapatan',
context.lang.total_revenue,
style: AppStyle.lg.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w500,

View File

@ -37,7 +37,7 @@ class ReportSales extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Sales Chart',
context.lang.sales_chart,
style: AppStyle.xxl.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.bold,
@ -46,8 +46,8 @@ class ReportSales extends StatelessWidget {
const SpaceHeight(4),
Text(
salesData.isEmpty
? 'No data available'
: '${salesData.length} days overview',
? context.lang.no_data_available
: context.lang.total_days_overview(salesData.length),
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
),
],
@ -71,13 +71,13 @@ class ReportSales extends StatelessWidget {
// Sales Summary Cards
if (salesData.isNotEmpty) ...[
_buildSalesSummary(),
_buildSalesSummary(context),
const SpaceHeight(20),
],
// Chart Container
salesData.isEmpty
? _buildEmptyChart()
? _buildEmptyChart(context)
: Container(
height: 300,
padding: const EdgeInsets.all(16),
@ -105,14 +105,16 @@ class ReportSales extends StatelessWidget {
if (salesData.isNotEmpty)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [_buildLegendItem('Sales Data', AppColor.primary)],
children: [
_buildLegendItem(context.lang.sales_data, AppColor.primary),
],
),
],
),
);
}
Widget _buildSalesSummary() {
Widget _buildSalesSummary(BuildContext context) {
final totalSales = salesData.fold<int>(0, (sum, item) => sum + item.sales);
final totalOrders = salesData.fold<int>(
0,
@ -137,7 +139,7 @@ class ReportSales extends StatelessWidget {
children: [
Expanded(
child: _buildSummaryItem(
'Total Sales',
context.lang.total_sales,
totalSales.currencyFormatRp,
Icons.attach_money,
AppColor.success,
@ -151,7 +153,7 @@ class ReportSales extends StatelessWidget {
),
Expanded(
child: _buildSummaryItem(
'Net Sales',
context.lang.net_sales,
totalNetSales.currencyFormatRp,
Icons.trending_up,
AppColor.primary,
@ -164,7 +166,7 @@ class ReportSales extends StatelessWidget {
children: [
Expanded(
child: _buildSummaryItem(
'Total Orders',
context.lang.total_orders,
totalOrders.toString(),
Icons.shopping_cart,
AppColor.info,
@ -178,7 +180,7 @@ class ReportSales extends StatelessWidget {
),
Expanded(
child: _buildSummaryItem(
'Total Items',
context.lang.total_items,
totalItems.toString(),
Icons.inventory,
AppColor.warning,
@ -204,11 +206,15 @@ class ReportSales extends StatelessWidget {
children: [
Icon(icon, size: 16, color: color),
const SpaceWidth(6),
Text(
label,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
Expanded(
child: Text(
label,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
@ -395,10 +401,10 @@ class ReportSales extends StatelessWidget {
);
}
Widget _buildEmptyChart() {
Widget _buildEmptyChart(BuildContext context) {
return EmptyWidget(
title: 'No Sales Data',
message: 'Sales data will appear here once transactions are recorded',
title: context.lang.no_sales_data,
message: context.lang.no_sales_data_desc,
emptyIcon: Icons.show_chart,
);
}

View File

@ -34,7 +34,7 @@ class ReportTopProduct extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Produk Terlaris',
context.lang.best_selling_products,
style: AppStyle.xxl.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.bold,
@ -42,7 +42,7 @@ class ReportTopProduct extends StatelessWidget {
),
const SpaceHeight(4),
Text(
'Ranking penjualan tertinggi',
context.lang.highest_sales_ranking,
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
),
],
@ -66,7 +66,11 @@ class ReportTopProduct extends StatelessWidget {
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return _buildEnhancedProductItem(products[index], index + 1);
return _buildEnhancedProductItem(
context,
products[index],
index + 1,
);
},
itemCount: products.length,
),
@ -75,7 +79,11 @@ class ReportTopProduct extends StatelessWidget {
);
}
Widget _buildEnhancedProductItem(DashboardTopProduct product, int rank) {
Widget _buildEnhancedProductItem(
BuildContext context,
DashboardTopProduct product,
int rank,
) {
final isFirst = rank == 1;
final isTopThree = rank <= 3;
@ -320,7 +328,7 @@ class ReportTopProduct extends StatelessWidget {
const SpaceWidth(3),
Flexible(
child: Text(
'Revenue',
context.lang.revenue,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -364,7 +372,7 @@ class ReportTopProduct extends StatelessWidget {
children: [
Flexible(
child: Text(
'Avg. Price',
context.lang.average_price,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -423,7 +431,7 @@ class ReportTopProduct extends StatelessWidget {
const SpaceWidth(3),
Flexible(
child: Text(
'Sold',
context.lang.sold,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -465,7 +473,7 @@ class ReportTopProduct extends StatelessWidget {
children: [
Flexible(
child: Text(
'Orders',
context.lang.orders,
style: AppStyle.xs.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
@ -543,7 +551,9 @@ class ReportTopProduct extends StatelessWidget {
const SpaceWidth(5),
Flexible(
child: Text(
isFirst ? 'Best Seller' : 'Top Performer',
isFirst
? context.lang.best_seller
: context.lang.top_performer,
style: AppStyle.xs.copyWith(
color: isFirst
? AppColor.warning

View File

@ -97,7 +97,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Penjualan'),
flexibleSpace: CustomAppBar(title: context.lang.sales),
),
// Date Range Header
@ -138,7 +138,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Summary',
context.lang.summary,
style: AppStyle.xxl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
@ -177,7 +177,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
child: Text(
'Daily Breakdown',
context.lang.daily_breakdown,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@ -412,7 +412,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
children: [
Expanded(
child: _buildSummaryCard(
'Total Sales',
context.lang.total_sales,
state.sales.summary.totalSales.currencyFormatRp,
Icons.trending_up,
AppColor.success,
@ -422,7 +422,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
SpaceWidth(12),
Expanded(
child: _buildSummaryCard(
'Total Orders',
context.lang.total_orders,
state.sales.summary.totalOrders.toString(),
Icons.shopping_cart,
AppColor.info,
@ -446,7 +446,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
children: [
Expanded(
child: _buildSummaryCard(
'Avg Order Value',
context.lang.average_price,
state.sales.summary.averageOrderValue
.round()
.currencyFormatRp,
@ -458,7 +458,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
SpaceWidth(12),
Expanded(
child: _buildSummaryCard(
'Total Items',
context.lang.total_items,
state.sales.summary.totalItems.toString(),
Icons.inventory,
AppColor.primary,
@ -530,7 +530,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Net Sales',
context.lang.net_sales,
style: TextStyle(
color: AppColor.textWhite.withOpacity(0.9),
fontSize: 14,
@ -668,7 +668,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${dailySale.orders} orders',
'${dailySale.orders} ${context.lang.orders}',
style: TextStyle(
color: AppColor.info,
fontWeight: FontWeight.w500,
@ -683,21 +683,21 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
children: [
Expanded(
child: _buildDetailItem(
'Items',
context.lang.items,
'${dailySale.items}',
Icons.inventory_2,
),
),
Expanded(
child: _buildDetailItem(
'Tax',
context.lang.tax,
dailySale.tax.currencyFormatRp,
Icons.receipt,
),
),
Expanded(
child: _buildDetailItem(
'Discount',
context.lang.discount,
dailySale.discount.currencyFormatRp,
Icons.local_offer,
),

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
@ -213,7 +214,7 @@ class _SchedulePageState extends State<SchedulePage>
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: CustomAppBar(title: 'Jadwal'),
flexibleSpace: CustomAppBar(title: context.lang.schedule),
);
}