feat: lang
This commit is contained in:
parent
f07d07b3a8
commit
5a83bc4049
@ -49,5 +49,385 @@
|
|||||||
"profile": "Profile",
|
"profile": "Profile",
|
||||||
"@profile": {},
|
"@profile": {},
|
||||||
"sales_today": "Sales today",
|
"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": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,5 +49,385 @@
|
|||||||
"profile": "Profil",
|
"profile": "Profil",
|
||||||
"@profile": {},
|
"@profile": {},
|
||||||
"sales_today": "Penjualan hari ini",
|
"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
@ -82,4 +82,540 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get sales_today => 'Sales today';
|
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';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,4 +82,540 @@ class AppLocalizationsId extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get sales_today => 'Penjualan hari ini';
|
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';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
|
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
|
||||||
|
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
|
|
||||||
class DateRangePickerBottomSheet {
|
class DateRangePickerBottomSheet {
|
||||||
static Future<DateRangePickerSelectionChangedArgs?> show({
|
static Future<DateRangePickerSelectionChangedArgs?> show({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
@ -9,8 +11,8 @@ class DateRangePickerBottomSheet {
|
|||||||
DateTime? initialEndDate,
|
DateTime? initialEndDate,
|
||||||
DateTime? minDate,
|
DateTime? minDate,
|
||||||
DateTime? maxDate,
|
DateTime? maxDate,
|
||||||
String confirmText = 'Pilih',
|
String? confirmText,
|
||||||
String cancelText = 'Batal',
|
String? cancelText,
|
||||||
Color primaryColor = Colors.blue,
|
Color primaryColor = Colors.blue,
|
||||||
Function(DateTime? startDate, DateTime? endDate)? onChanged,
|
Function(DateTime? startDate, DateTime? endDate)? onChanged,
|
||||||
}) async {
|
}) async {
|
||||||
@ -26,8 +28,8 @@ class DateRangePickerBottomSheet {
|
|||||||
initialEndDate: initialEndDate,
|
initialEndDate: initialEndDate,
|
||||||
minDate: minDate,
|
minDate: minDate,
|
||||||
maxDate: maxDate,
|
maxDate: maxDate,
|
||||||
confirmText: confirmText,
|
confirmText: confirmText ?? context.lang.select,
|
||||||
cancelText: cancelText,
|
cancelText: cancelText ?? context.lang.cancel,
|
||||||
primaryColor: primaryColor,
|
primaryColor: primaryColor,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
),
|
),
|
||||||
@ -104,7 +106,7 @@ class _DateRangePickerBottomSheetState
|
|||||||
return _formatDate(range.startDate!);
|
return _formatDate(range.startDate!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 'Belum ada tanggal dipilih';
|
return context.lang.no_date_selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatDate(DateTime date) {
|
String _formatDate(DateTime date) {
|
||||||
@ -187,7 +189,7 @@ class _DateRangePickerBottomSheetState
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Tanggal Terpilih:',
|
'${context.lang.selected_date}:',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
|
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
|
||||||
|
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../bottom_sheet/date_range_bottom_sheet.dart';
|
import '../bottom_sheet/date_range_bottom_sheet.dart';
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ class DateRangePickerField extends StatefulWidget {
|
|||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
const DateRangePickerField({
|
const DateRangePickerField({
|
||||||
Key? key,
|
super.key,
|
||||||
this.label,
|
this.label,
|
||||||
this.placeholder = 'Pilih rentang tanggal',
|
this.placeholder = 'Pilih rentang tanggal',
|
||||||
this.startDate,
|
this.startDate,
|
||||||
@ -38,7 +39,7 @@ class DateRangePickerField extends StatefulWidget {
|
|||||||
this.placeholderStyle,
|
this.placeholderStyle,
|
||||||
this.decoration,
|
this.decoration,
|
||||||
this.height = 52.0,
|
this.height = 52.0,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DateRangePickerField> createState() => _DateRangePickerFieldState();
|
State<DateRangePickerField> createState() => _DateRangePickerFieldState();
|
||||||
@ -83,7 +84,7 @@ class _DateRangePickerFieldState extends State<DateRangePickerField> {
|
|||||||
|
|
||||||
final result = await DateRangePickerBottomSheet.show(
|
final result = await DateRangePickerBottomSheet.show(
|
||||||
context: context,
|
context: context,
|
||||||
title: widget.label ?? 'Pilih Rentang Tanggal',
|
title: widget.label ?? context.lang.select_date_range,
|
||||||
initialStartDate: widget.startDate,
|
initialStartDate: widget.startDate,
|
||||||
initialEndDate: widget.endDate,
|
initialEndDate: widget.endDate,
|
||||||
minDate: widget.minDate,
|
minDate: widget.minDate,
|
||||||
@ -294,7 +295,7 @@ class _DateRangePickerFieldOutlinedState
|
|||||||
|
|
||||||
final result = await DateRangePickerBottomSheet.show(
|
final result = await DateRangePickerBottomSheet.show(
|
||||||
context: context,
|
context: context,
|
||||||
title: widget.label ?? 'Pilih Rentang Tanggal',
|
title: widget.label ?? context.lang.select_date_range,
|
||||||
initialStartDate: widget.startDate,
|
initialStartDate: widget.startDate,
|
||||||
initialEndDate: widget.endDate,
|
initialEndDate: widget.endDate,
|
||||||
minDate: widget.minDate,
|
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'}',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,7 +3,9 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
|
import '../../components/assets/assets.gen.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class AboutAppPage extends StatefulWidget {
|
class AboutAppPage extends StatefulWidget {
|
||||||
@ -107,7 +109,7 @@ class _AboutAppPageState extends State<AboutAppPage>
|
|||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: _fadeAnimation.value,
|
opacity: _fadeAnimation.value,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Tentang Aplikasi',
|
context.lang.about_app,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -142,7 +144,7 @@ class _AboutAppPageState extends State<AboutAppPage>
|
|||||||
height: 100,
|
height: 100,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
borderRadius: BorderRadius.circular(25),
|
borderRadius: BorderRadius.circular(8),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: AppColor.black.withOpacity(0.2),
|
color: AppColor.black.withOpacity(0.2),
|
||||||
@ -151,10 +153,9 @@ class _AboutAppPageState extends State<AboutAppPage>
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: ClipRRect(
|
||||||
Icons.mobile_friendly,
|
borderRadius: BorderRadius.circular(8),
|
||||||
size: 50,
|
child: Assets.images.logo.image(),
|
||||||
color: AppColor.primary,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@ -247,7 +248,7 @@ class _AboutAppPageState extends State<AboutAppPage>
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Informasi Aplikasi',
|
context.lang.app_information,
|
||||||
style: AppStyle.h6.copyWith(
|
style: AppStyle.h6.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
@ -256,18 +257,24 @@ class _AboutAppPageState extends State<AboutAppPage>
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildInfoRow('Nama Aplikasi', packageInfo?.appName ?? 'Loading...'),
|
|
||||||
_buildInfoRow('Versi', packageInfo?.version ?? 'Loading...'),
|
|
||||||
_buildInfoRow(
|
_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...',
|
packageInfo?.buildNumber ?? 'Loading...',
|
||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
'Package Name',
|
context.lang.package_name,
|
||||||
packageInfo?.packageName ?? 'Loading...',
|
packageInfo?.packageName ?? 'Loading...',
|
||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
'Device',
|
context.lang.device,
|
||||||
deviceInfo.isEmpty ? 'Loading...' : deviceInfo,
|
deviceInfo.isEmpty ? 'Loading...' : deviceInfo,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
@ -114,7 +115,7 @@ class _ComingSoonPageState extends State<ComingSoonPage>
|
|||||||
child: SlideTransition(
|
child: SlideTransition(
|
||||||
position: _slideAnimation,
|
position: _slideAnimation,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Coming Soon',
|
context.lang.coming_soon,
|
||||||
style: AppStyle.h1.copyWith(
|
style: AppStyle.h1.copyWith(
|
||||||
color: AppColor.textWhite,
|
color: AppColor.textWhite,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -134,7 +135,7 @@ class _ComingSoonPageState extends State<ComingSoonPage>
|
|||||||
child: SlideTransition(
|
child: SlideTransition(
|
||||||
position: _slideAnimation,
|
position: _slideAnimation,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Something amazing is brewing!\nStay tuned for the big reveal.',
|
context.lang.coming_soon_desc,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
color: AppColor.textWhite.withOpacity(0.9),
|
color: AppColor.textWhite.withOpacity(0.9),
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
import '../../../application/customer/customer_loader/customer_loader_bloc.dart';
|
import '../../../application/customer/customer_loader/customer_loader_bloc.dart';
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../../domain/customer/customer.dart';
|
import '../../../domain/customer/customer.dart';
|
||||||
import '../../../injection.dart';
|
import '../../../injection.dart';
|
||||||
@ -31,7 +32,7 @@ class CustomerPage extends StatefulWidget implements AutoRouteWrapper {
|
|||||||
class _CustomerPageState extends State<CustomerPage>
|
class _CustomerPageState extends State<CustomerPage>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
bool _isGridView = false;
|
bool _isGridView = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -72,7 +73,7 @@ class _CustomerPageState extends State<CustomerPage>
|
|||||||
floating: false,
|
floating: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Pelanggan'),
|
flexibleSpace: CustomAppBar(title: context.lang.customer),
|
||||||
actions: [
|
actions: [
|
||||||
ActionIconButton(onTap: () {}, icon: LineIcons.search),
|
ActionIconButton(onTap: () {}, icon: LineIcons.search),
|
||||||
],
|
],
|
||||||
@ -148,7 +149,7 @@ class _CustomerPageState extends State<CustomerPage>
|
|||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 16,
|
crossAxisSpacing: 16,
|
||||||
mainAxisSpacing: 16,
|
mainAxisSpacing: 16,
|
||||||
childAspectRatio: 0.8,
|
childAspectRatio: 0.65,
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate((context, index) {
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
final customer = customers[index];
|
final customer = customers[index];
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/customer/customer.dart';
|
import '../../../../domain/customer/customer.dart';
|
||||||
import '../../../components/spacer/spacer.dart';
|
import '../../../components/spacer/spacer.dart';
|
||||||
@ -175,78 +176,6 @@ class CustomerCard extends StatelessWidget {
|
|||||||
const SpaceHeight(12),
|
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
|
// Metadata info
|
||||||
if (customer.metadata.isNotEmpty && _hasRelevantMetadata()) ...[
|
if (customer.metadata.isNotEmpty && _hasRelevantMetadata()) ...[
|
||||||
const SpaceHeight(8),
|
const SpaceHeight(8),
|
||||||
@ -284,7 +213,7 @@ class CustomerCard extends StatelessWidget {
|
|||||||
if (customer.createdAt.isNotEmpty) ...[
|
if (customer.createdAt.isNotEmpty) ...[
|
||||||
const SpaceHeight(8),
|
const SpaceHeight(8),
|
||||||
Text(
|
Text(
|
||||||
'Joined ${_formatDate(customer.createdAt)}',
|
'${context.lang.joined} ${_formatDate(context, customer.createdAt)}',
|
||||||
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
|
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
@ -335,7 +264,7 @@ class CustomerCard extends StatelessWidget {
|
|||||||
return colors[index];
|
return colors[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatDate(String dateStr) {
|
String _formatDate(BuildContext context, String dateStr) {
|
||||||
try {
|
try {
|
||||||
final date = DateTime.parse(dateStr);
|
final date = DateTime.parse(dateStr);
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
@ -346,13 +275,13 @@ class CustomerCard extends StatelessWidget {
|
|||||||
} else if (difference == 1) {
|
} else if (difference == 1) {
|
||||||
return 'yesterday';
|
return 'yesterday';
|
||||||
} else if (difference < 30) {
|
} else if (difference < 30) {
|
||||||
return '${difference}d ago';
|
return '${difference}d ${context.lang.ago}';
|
||||||
} else if (difference < 365) {
|
} else if (difference < 365) {
|
||||||
final months = (difference / 30).floor();
|
final months = (difference / 30).floor();
|
||||||
return '${months}mo ago';
|
return '${months}mo ${context.lang.ago}';
|
||||||
} else {
|
} else {
|
||||||
final years = (difference / 365).floor();
|
final years = (difference / 365).floor();
|
||||||
return '${years}y ago';
|
return '${years}y ${context.lang.ago}';
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return dateStr;
|
return dateStr;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/customer/customer.dart';
|
import '../../../../domain/customer/customer.dart';
|
||||||
import '../../../components/spacer/spacer.dart';
|
import '../../../components/spacer/spacer.dart';
|
||||||
@ -245,7 +246,9 @@ class CustomerTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SpaceWidth(6),
|
const SpaceWidth(6),
|
||||||
Text(
|
Text(
|
||||||
customer.isActive ? 'Active' : 'Inactive',
|
customer.isActive
|
||||||
|
? context.lang.active
|
||||||
|
: context.lang.inactive,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: customer.isActive
|
color: customer.isActive
|
||||||
? AppColor.success
|
? AppColor.success
|
||||||
@ -260,7 +263,7 @@ class CustomerTile extends StatelessWidget {
|
|||||||
// Created date
|
// Created date
|
||||||
if (customer.createdAt.isNotEmpty)
|
if (customer.createdAt.isNotEmpty)
|
||||||
Text(
|
Text(
|
||||||
'Joined ${_formatDate(customer.createdAt)}',
|
'${context.lang.joined} ${_formatDate(context, customer.createdAt)}',
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
),
|
),
|
||||||
@ -326,7 +329,7 @@ class CustomerTile extends StatelessWidget {
|
|||||||
return colors[index];
|
return colors[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatDate(String dateStr) {
|
String _formatDate(BuildContext context, String dateStr) {
|
||||||
try {
|
try {
|
||||||
final date = DateTime.parse(dateStr);
|
final date = DateTime.parse(dateStr);
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
@ -337,13 +340,13 @@ class CustomerTile extends StatelessWidget {
|
|||||||
} else if (difference == 1) {
|
} else if (difference == 1) {
|
||||||
return 'yesterday';
|
return 'yesterday';
|
||||||
} else if (difference < 30) {
|
} else if (difference < 30) {
|
||||||
return '${difference}d ago';
|
return '${difference}d ${context.lang.ago}';
|
||||||
} else if (difference < 365) {
|
} else if (difference < 365) {
|
||||||
final months = (difference / 30).floor();
|
final months = (difference / 30).floor();
|
||||||
return '${months}mo ago';
|
return '${months}mo ${context.lang.ago}';
|
||||||
} else {
|
} else {
|
||||||
final years = (difference / 365).floor();
|
final years = (difference / 365).floor();
|
||||||
return '${years}y ago';
|
return '${years}y ${context.lang.ago}';
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return dateStr;
|
return dateStr;
|
||||||
|
|||||||
@ -113,7 +113,7 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Download Report'),
|
flexibleSpace: CustomAppBar(title: context.lang.download_report),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
@ -134,9 +134,8 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
>(
|
>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return _ReportOptionCard(
|
return _ReportOptionCard(
|
||||||
title: 'Transaction Report',
|
title: context.lang.transaction_report,
|
||||||
subtitle:
|
subtitle: context.lang.transaction_report_desc,
|
||||||
'Export all transaction data with detailed analytics',
|
|
||||||
icon: Icons.receipt_long_outlined,
|
icon: Icons.receipt_long_outlined,
|
||||||
gradient: const [
|
gradient: const [
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
@ -205,9 +204,8 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
BlocBuilder<InventoryReportBloc, InventoryReportState>(
|
BlocBuilder<InventoryReportBloc, InventoryReportState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return _ReportOptionCard(
|
return _ReportOptionCard(
|
||||||
title: 'Inventory Report',
|
title: context.lang.invetory_report,
|
||||||
subtitle:
|
subtitle: context.lang.invetory_report_desc,
|
||||||
'Export inventory and stock data with trends',
|
|
||||||
icon: Icons.inventory_2_outlined,
|
icon: Icons.inventory_2_outlined,
|
||||||
gradient: const [
|
gradient: const [
|
||||||
AppColor.secondary,
|
AppColor.secondary,
|
||||||
@ -479,7 +477,7 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Select Date Range',
|
context.lang.select_date_range,
|
||||||
style: AppStyle.md.copyWith(
|
style: AppStyle.md.copyWith(
|
||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -489,7 +487,7 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
|
|||||||
|
|
||||||
// Date Range Picker Field Style
|
// Date Range Picker Field Style
|
||||||
DateRangePickerField(
|
DateRangePickerField(
|
||||||
placeholder: 'Select date range',
|
placeholder: context.lang.select_date_range,
|
||||||
startDate: widget.startDate,
|
startDate: widget.startDate,
|
||||||
endDate: widget.endDate,
|
endDate: widget.endDate,
|
||||||
onChanged: widget.onDateRangeChanged,
|
onChanged: widget.onDateRangeChanged,
|
||||||
@ -542,7 +540,7 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Download Report',
|
context.lang.download_report,
|
||||||
style: AppStyle.md.copyWith(
|
style: AppStyle.md.copyWith(
|
||||||
color: widget.gradient.first,
|
color: widget.gradient.first,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|||||||
@ -126,7 +126,7 @@ class _FinancePageState extends State<FinancePage>
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
flexibleSpace: CustomAppBar(title: 'Keuangan'),
|
flexibleSpace: CustomAppBar(title: context.lang.finance),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Header dengan filter periode
|
// Header dengan filter periode
|
||||||
@ -221,7 +221,7 @@ class _FinancePageState extends State<FinancePage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FinanceSummaryCard(
|
child: FinanceSummaryCard(
|
||||||
title: 'Total Pendapatan',
|
title: context.lang.total_revenue,
|
||||||
amount: summary.totalRevenue.currencyFormatRp,
|
amount: summary.totalRevenue.currencyFormatRp,
|
||||||
icon: LineIcons.arrowUp,
|
icon: LineIcons.arrowUp,
|
||||||
color: AppColor.success,
|
color: AppColor.success,
|
||||||
@ -231,7 +231,7 @@ class _FinancePageState extends State<FinancePage>
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FinanceSummaryCard(
|
child: FinanceSummaryCard(
|
||||||
title: 'Total Pengeluaran',
|
title: context.lang.total_expenditures,
|
||||||
amount: summary.totalCost.currencyFormatRp,
|
amount: summary.totalCost.currencyFormatRp,
|
||||||
icon: LineIcons.arrowDown,
|
icon: LineIcons.arrowDown,
|
||||||
color: AppColor.error,
|
color: AppColor.error,
|
||||||
@ -245,7 +245,7 @@ class _FinancePageState extends State<FinancePage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FinanceSummaryCard(
|
child: FinanceSummaryCard(
|
||||||
title: 'Keuntungan Bersih',
|
title: context.lang.net_profit,
|
||||||
amount: summary.netProfit.currencyFormatRp,
|
amount: summary.netProfit.currencyFormatRp,
|
||||||
icon: LineIcons.lineChart,
|
icon: LineIcons.lineChart,
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
@ -255,7 +255,7 @@ class _FinancePageState extends State<FinancePage>
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FinanceSummaryCard(
|
child: FinanceSummaryCard(
|
||||||
title: 'Margin Profit',
|
title: context.lang.margin_profit,
|
||||||
amount: '${summary.profitabilityRatio.round()}%',
|
amount: '${summary.profitabilityRatio.round()}%',
|
||||||
icon: LineIcons.percent,
|
icon: LineIcons.percent,
|
||||||
color: AppColor.warning,
|
color: AppColor.warning,
|
||||||
@ -304,14 +304,14 @@ class _FinancePageState extends State<FinancePage>
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(
|
Text(
|
||||||
'Analisis Produk',
|
context.lang.product_analytic,
|
||||||
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Lihat Semua',
|
context.lang.view_all,
|
||||||
style: AppStyle.sm.copyWith(color: AppColor.primary),
|
style: AppStyle.sm.copyWith(color: AppColor.primary),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/analytic/analytic.dart';
|
import '../../../../domain/analytic/analytic.dart';
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ class FinanceCashFlow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(
|
Text(
|
||||||
'Analisis Cash Flow',
|
context.lang.cash_flow_analysis,
|
||||||
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -78,7 +79,7 @@ class FinanceCashFlow extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildCashFlowIndicator(
|
child: _buildCashFlowIndicator(
|
||||||
'Cash In',
|
context.lang.cash_in,
|
||||||
_formatCurrency(totalCashIn),
|
_formatCurrency(totalCashIn),
|
||||||
LineIcons.arrowUp,
|
LineIcons.arrowUp,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
@ -87,7 +88,7 @@ class FinanceCashFlow extends StatelessWidget {
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildCashFlowIndicator(
|
child: _buildCashFlowIndicator(
|
||||||
'Cash Out',
|
context.lang.cash_out,
|
||||||
_formatCurrency(totalCashOut),
|
_formatCurrency(totalCashOut),
|
||||||
LineIcons.arrowDown,
|
LineIcons.arrowDown,
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
@ -96,7 +97,7 @@ class FinanceCashFlow extends StatelessWidget {
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildCashFlowIndicator(
|
child: _buildCashFlowIndicator(
|
||||||
'Net Flow',
|
context.lang.net_flow,
|
||||||
_formatCurrency(netFlow),
|
_formatCurrency(netFlow),
|
||||||
LineIcons.equals,
|
LineIcons.equals,
|
||||||
AppColor.info,
|
AppColor.info,
|
||||||
@ -119,7 +120,7 @@ class FinanceCashFlow extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Grafik Cash Flow ${dailyData.length} Hari Terakhir',
|
context.lang.cash_flow_chart(dailyData.length),
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -136,11 +137,11 @@ class FinanceCashFlow extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
_buildChartLegend('Cash In', AppColor.success),
|
_buildChartLegend(context.lang.cash_in, AppColor.success),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildChartLegend('Cash Out', AppColor.error),
|
_buildChartLegend(context.lang.cash_out, AppColor.error),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
_buildChartLegend('Net Flow', AppColor.info),
|
_buildChartLegend(context.lang.net_flow, AppColor.info),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -51,7 +51,7 @@ class FinanceCategory extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(
|
Text(
|
||||||
'Kategori Penjualan',
|
context.lang.sales_category,
|
||||||
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -60,10 +60,11 @@ class FinanceCategory extends StatelessWidget {
|
|||||||
|
|
||||||
// Show empty state if no categories
|
// Show empty state if no categories
|
||||||
if (categories.isEmpty)
|
if (categories.isEmpty)
|
||||||
_buildEmptyState()
|
_buildEmptyState(context)
|
||||||
else
|
else
|
||||||
...sortedCategories.asMap().entries.map(
|
...sortedCategories.asMap().entries.map(
|
||||||
(entry) => _buildCategoryItem(
|
(entry) => _buildCategoryItem(
|
||||||
|
context,
|
||||||
entry.value,
|
entry.value,
|
||||||
_calculatePercentage(entry.value.totalRevenue, totalRevenue),
|
_calculatePercentage(entry.value.totalRevenue, totalRevenue),
|
||||||
_getCategoryColor(entry.key),
|
_getCategoryColor(entry.key),
|
||||||
@ -75,6 +76,7 @@ class FinanceCategory extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCategoryItem(
|
Widget _buildCategoryItem(
|
||||||
|
BuildContext context,
|
||||||
CategoryAnalyticItem category,
|
CategoryAnalyticItem category,
|
||||||
double percentage,
|
double percentage,
|
||||||
Color color,
|
Color color,
|
||||||
@ -111,7 +113,7 @@ class FinanceCategory extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
'${category.productCount} produk • ${category.orderCount} pesanan',
|
'${category.productCount} ${context.lang.product} • ${category.orderCount} ${context.lang.orders}',
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
),
|
),
|
||||||
@ -134,7 +136,7 @@ class FinanceCategory extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'${NumberFormat('#,###', 'id_ID').format(category.totalQuantity)} unit',
|
'${NumberFormat('#,###', 'id_ID').format(category.totalQuantity)} ${context.lang.unit}',
|
||||||
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
|
style: AppStyle.xs.copyWith(color: AppColor.textSecondary),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -161,10 +163,10 @@ class FinanceCategory extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmptyState() {
|
Widget _buildEmptyState(BuildContext context) {
|
||||||
return EmptyWidget(
|
return EmptyWidget(
|
||||||
title: 'Belum ada data kategori',
|
title: context.lang.category_no_data,
|
||||||
message: 'Data kategori penjualan akan muncul di sini',
|
message: context.lang.category_no_data_desc,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -81,21 +81,21 @@ class ProfitLossProduct extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMetricColumn(
|
child: _buildMetricColumn(
|
||||||
'Pendapatan',
|
context.lang.revenue,
|
||||||
product.revenue.currencyFormatRp,
|
product.revenue.currencyFormatRp,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMetricColumn(
|
child: _buildMetricColumn(
|
||||||
'Biaya',
|
context.lang.cost,
|
||||||
product.cost.currencyFormatRp,
|
product.cost.currencyFormatRp,
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMetricColumn(
|
child: _buildMetricColumn(
|
||||||
'Laba Kotor',
|
context.lang.gross_profit,
|
||||||
product.grossProfit.currencyFormatRp,
|
product.grossProfit.currencyFormatRp,
|
||||||
AppColor.info,
|
AppColor.info,
|
||||||
),
|
),
|
||||||
@ -109,14 +109,14 @@ class ProfitLossProduct extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMetricColumn(
|
child: _buildMetricColumn(
|
||||||
'Harga Rata-rata',
|
context.lang.average_price,
|
||||||
product.averagePrice.currencyFormatRp,
|
product.averagePrice.currencyFormatRp,
|
||||||
AppColor.textSecondary,
|
AppColor.textSecondary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMetricColumn(
|
child: _buildMetricColumn(
|
||||||
'Laba per Unit',
|
context.lang.profit_per_unit,
|
||||||
product.profitPerUnit.currencyFormatRp,
|
product.profitPerUnit.currencyFormatRp,
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(
|
Text(
|
||||||
'Detail Profit & Loss',
|
context.lang.profit_loss_detail,
|
||||||
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -55,7 +55,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Total Revenue (Penjualan Kotor)
|
// Total Revenue (Penjualan Kotor)
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'Penjualan Kotor',
|
context.lang.gross_sales,
|
||||||
data.totalRevenue.currencyFormatRp,
|
data.totalRevenue.currencyFormatRp,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
true,
|
true,
|
||||||
@ -63,7 +63,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Discount (Diskon & Retur)
|
// Discount (Diskon & Retur)
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'Diskon & Retur',
|
'${context.lang.discount} & ${context.lang.return_text}',
|
||||||
'- ${data.totalDiscount.currencyFormatRp}',
|
'- ${data.totalDiscount.currencyFormatRp}',
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
false,
|
false,
|
||||||
@ -73,7 +73,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Net Sales (Penjualan Bersih = Total Revenue - Discount)
|
// Net Sales (Penjualan Bersih = Total Revenue - Discount)
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'Penjualan Bersih',
|
context.lang.net_sales,
|
||||||
(data.totalRevenue - data.totalDiscount).currencyFormatRp,
|
(data.totalRevenue - data.totalDiscount).currencyFormatRp,
|
||||||
AppColor.textPrimary,
|
AppColor.textPrimary,
|
||||||
true,
|
true,
|
||||||
@ -84,7 +84,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Cost of Goods Sold (HPP)
|
// Cost of Goods Sold (HPP)
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'HPP (Harga Pokok Penjualan)',
|
'${context.lang.cogs} (${context.lang.cost_of_goods_sold})',
|
||||||
'- ${data.totalCost.currencyFormatRp}',
|
'- ${data.totalCost.currencyFormatRp}',
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
false,
|
false,
|
||||||
@ -94,7 +94,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Gross Profit (Laba Kotor)
|
// Gross Profit (Laba Kotor)
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'Laba Kotor',
|
context.lang.gross_profit,
|
||||||
data.grossProfit.currencyFormatRp,
|
data.grossProfit.currencyFormatRp,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
true,
|
true,
|
||||||
@ -107,7 +107,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Operational Cost (Biaya Operasional) - calculated as difference
|
// Operational Cost (Biaya Operasional) - calculated as difference
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'Biaya Operasional',
|
context.lang.operating_costs,
|
||||||
'- ${_calculateOperationalCost().currencyFormatRp}',
|
'- ${_calculateOperationalCost().currencyFormatRp}',
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
false,
|
false,
|
||||||
@ -117,7 +117,7 @@ class FinanceProfitLoss extends StatelessWidget {
|
|||||||
|
|
||||||
// Net Profit (Laba Bersih)
|
// Net Profit (Laba Bersih)
|
||||||
_buildPLItem(
|
_buildPLItem(
|
||||||
'Laba Bersih',
|
context.lang.net_profit,
|
||||||
data.netProfit.currencyFormatRp,
|
data.netProfit.currencyFormatRp,
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../router/app_router.gr.dart';
|
import '../../../router/app_router.gr.dart';
|
||||||
import 'feature_tile.dart';
|
import 'feature_tile.dart';
|
||||||
@ -36,25 +37,25 @@ class HomeFeature extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Penjualan',
|
title: context.lang.sales,
|
||||||
color: const Color(0xFF4CAF50),
|
color: const Color(0xFF4CAF50),
|
||||||
icon: LineIcons.receipt,
|
icon: LineIcons.receipt,
|
||||||
onTap: () => context.router.push(SalesRoute()),
|
onTap: () => context.router.push(SalesRoute()),
|
||||||
),
|
),
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Pembelian',
|
title: context.lang.purchase,
|
||||||
color: const Color(0xFF2196F3),
|
color: const Color(0xFF2196F3),
|
||||||
icon: LineIcons.shoppingCart,
|
icon: LineIcons.shoppingCart,
|
||||||
onTap: () => context.router.push(PurchaseRoute()),
|
onTap: () => context.router.push(PurchaseRoute()),
|
||||||
),
|
),
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Keuangan',
|
title: context.lang.finance,
|
||||||
color: const Color(0xFF8BC34A),
|
color: const Color(0xFF8BC34A),
|
||||||
icon: LineIcons.moneyCheck,
|
icon: LineIcons.moneyCheck,
|
||||||
onTap: () => context.router.push(FinanceRoute()),
|
onTap: () => context.router.push(FinanceRoute()),
|
||||||
),
|
),
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Produk',
|
title: context.lang.product,
|
||||||
color: const Color(0xFFFF9800),
|
color: const Color(0xFFFF9800),
|
||||||
icon: LineIcons.box,
|
icon: LineIcons.box,
|
||||||
onTap: () => context.router.push(ProductAnalyticRoute()),
|
onTap: () => context.router.push(ProductAnalyticRoute()),
|
||||||
@ -66,25 +67,25 @@ class HomeFeature extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Form',
|
title: context.lang.form,
|
||||||
color: const Color(0xFFE91E63),
|
color: const Color(0xFFE91E63),
|
||||||
icon: LineIcons.fileAlt,
|
icon: LineIcons.fileAlt,
|
||||||
onTap: () => context.router.push(DailyTasksFormRoute()),
|
onTap: () => context.router.push(DailyTasksFormRoute()),
|
||||||
),
|
),
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Jadwal',
|
title: context.lang.schedule,
|
||||||
color: const Color(0xFF9C27B0),
|
color: const Color(0xFF9C27B0),
|
||||||
icon: LineIcons.calendar,
|
icon: LineIcons.calendar,
|
||||||
onTap: () => context.router.push(ScheduleRoute()),
|
onTap: () => context.router.push(ScheduleRoute()),
|
||||||
),
|
),
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Inventaris',
|
title: context.lang.inventory,
|
||||||
color: const Color(0xFF00BCD4),
|
color: const Color(0xFF00BCD4),
|
||||||
icon: LineIcons.archive,
|
icon: LineIcons.archive,
|
||||||
onTap: () => context.router.push(InventoryRoute()),
|
onTap: () => context.router.push(InventoryRoute()),
|
||||||
),
|
),
|
||||||
HomeFeatureTile(
|
HomeFeatureTile(
|
||||||
title: 'Pelanggan',
|
title: context.lang.customer,
|
||||||
color: const Color(0xFFFF5722),
|
color: const Color(0xFFFF5722),
|
||||||
icon: LineIcons.userPlus,
|
icon: LineIcons.userPlus,
|
||||||
onTap: () => context.router.push(CustomerRoute()),
|
onTap: () => context.router.push(CustomerRoute()),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/analytic/analytic.dart';
|
import '../../../../domain/analytic/analytic.dart';
|
||||||
import '../../../components/spacer/spacer.dart';
|
import '../../../components/spacer/spacer.dart';
|
||||||
@ -21,30 +22,30 @@ class HomeStats extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
HomeTitle(title: 'Ringkasan Hari Ini'),
|
HomeTitle(title: context.lang.today_summary),
|
||||||
const SpaceHeight(20),
|
const SpaceHeight(20),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: HomeStatsTile(
|
child: HomeStatsTile(
|
||||||
title: 'Pesanan',
|
title: context.lang.order,
|
||||||
value: overview.totalOrders.toString(),
|
value: overview.totalOrders.toString(),
|
||||||
icon: Icons.receipt_long_rounded,
|
icon: Icons.receipt_long_rounded,
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
subtitle: 'Hari ini',
|
subtitle: context.lang.today,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SpaceWidth(16),
|
const SpaceWidth(16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: HomeStatsTile(
|
child: HomeStatsTile(
|
||||||
title: 'Pelanggan Baru',
|
title: context.lang.new_customer,
|
||||||
value: overview.totalCustomers.toString(),
|
value: overview.totalCustomers.toString(),
|
||||||
icon: Icons.person_add_outlined,
|
icon: Icons.person_add_outlined,
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
subtitle: overview.totalCustomers < 1
|
subtitle: overview.totalCustomers < 1
|
||||||
? 'Hari ini'
|
? context.lang.today
|
||||||
: 'bertambah',
|
: context.lang.increase,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -54,21 +55,21 @@ class HomeStats extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: HomeStatsTile(
|
child: HomeStatsTile(
|
||||||
title: 'Refund',
|
title: context.lang.refund,
|
||||||
value: overview.refundedOrders.toString(),
|
value: overview.refundedOrders.toString(),
|
||||||
icon: LineIcons.alternateExchange,
|
icon: LineIcons.alternateExchange,
|
||||||
color: AppColor.warning,
|
color: AppColor.warning,
|
||||||
subtitle: 'Hari ini',
|
subtitle: context.lang.today,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SpaceWidth(16),
|
const SpaceWidth(16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: HomeStatsTile(
|
child: HomeStatsTile(
|
||||||
title: 'Void',
|
title: context.lang.void_text,
|
||||||
value: overview.voidedOrders.toString(),
|
value: overview.voidedOrders.toString(),
|
||||||
icon: Icons.cancel_rounded,
|
icon: Icons.cancel_rounded,
|
||||||
color: AppColor.error,
|
color: AppColor.error,
|
||||||
subtitle: 'Hari ini',
|
subtitle: context.lang.today,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/analytic/analytic.dart';
|
import '../../../../domain/analytic/analytic.dart';
|
||||||
import '../../../components/spacer/spacer.dart';
|
import '../../../components/spacer/spacer.dart';
|
||||||
@ -19,12 +20,13 @@ class HomeTopProduct extends StatelessWidget {
|
|||||||
).copyWith(bottom: 0),
|
).copyWith(bottom: 0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
HomeTitle(title: 'Product Terlaris Hari Ini'),
|
HomeTitle(title: context.lang.today_top_product),
|
||||||
SpaceHeight(20),
|
SpaceHeight(20),
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: products.length,
|
itemCount: products.length,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return HomeTopProductTile(
|
return HomeTopProductTile(
|
||||||
product: products[index],
|
product: products[index],
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
// Header Row - Ranking dan Revenue
|
// Header Row - Ranking dan Revenue
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
_buildRankingBadge(),
|
_buildRankingBadge(context),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
_buildRevenueDisplay(),
|
_buildRevenueDisplay(),
|
||||||
],
|
],
|
||||||
@ -71,7 +71,7 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
// Metrics dalam Grid 2x2
|
// Metrics dalam Grid 2x2
|
||||||
_buildMetricsGrid(),
|
_buildMetricsGrid(context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -80,7 +80,7 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRankingBadge() {
|
Widget _buildRankingBadge(BuildContext context) {
|
||||||
Color badgeColor;
|
Color badgeColor;
|
||||||
IconData icon;
|
IconData icon;
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
Icon(icon, color: badgeColor, size: 16),
|
Icon(icon, color: badgeColor, size: 16),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
'Rank #$ranking',
|
'${context.lang.rank} #$ranking',
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: badgeColor,
|
color: badgeColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -157,7 +157,7 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMetricsGrid() {
|
Widget _buildMetricsGrid(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -165,14 +165,14 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_buildMetricCard(
|
_buildMetricCard(
|
||||||
icon: Icons.shopping_cart_outlined,
|
icon: Icons.shopping_cart_outlined,
|
||||||
label: 'Quantity Sold',
|
label: context.lang.quantity_sold,
|
||||||
value: product.quantitySold.toString(),
|
value: product.quantitySold.toString(),
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildMetricCard(
|
_buildMetricCard(
|
||||||
icon: Icons.attach_money,
|
icon: Icons.attach_money,
|
||||||
label: 'Average Price',
|
label: context.lang.average_price,
|
||||||
value: product.averagePrice.round().currencyFormatRp,
|
value: product.averagePrice.round().currencyFormatRp,
|
||||||
color: AppColor.success,
|
color: AppColor.success,
|
||||||
),
|
),
|
||||||
@ -185,14 +185,14 @@ class HomeTopProductTile extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_buildMetricCard(
|
_buildMetricCard(
|
||||||
icon: Icons.receipt_outlined,
|
icon: Icons.receipt_outlined,
|
||||||
label: 'Total Orders',
|
label: context.lang.total_orders,
|
||||||
value: product.orderCount.toString(),
|
value: product.orderCount.toString(),
|
||||||
color: AppColor.warning,
|
color: AppColor.warning,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildMetricCard(
|
_buildMetricCard(
|
||||||
icon: Icons.trending_up,
|
icon: Icons.trending_up,
|
||||||
label: 'Performance',
|
label: context.lang.perfomance,
|
||||||
value: 'Top $ranking',
|
value: 'Top $ranking',
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../../application/analytic/inventory_analytic_loader/inventory_analytic_loader_bloc.dart';
|
import '../../../application/analytic/inventory_analytic_loader/inventory_analytic_loader_bloc.dart';
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../../domain/analytic/analytic.dart';
|
import '../../../domain/analytic/analytic.dart';
|
||||||
import '../../../injection.dart';
|
import '../../../injection.dart';
|
||||||
@ -95,11 +96,11 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
String getStatusText(String status) {
|
String getStatusText(String status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'available':
|
case 'available':
|
||||||
return 'Tersedia';
|
return context.lang.available;
|
||||||
case 'low_stock':
|
case 'low_stock':
|
||||||
return 'Stok Rendah';
|
return context.lang.low_stock;
|
||||||
case 'out_of_stock':
|
case 'out_of_stock':
|
||||||
return 'Habis';
|
return context.lang.out_of_stock;
|
||||||
default:
|
default:
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 12,
|
horizontal: 12,
|
||||||
),
|
),
|
||||||
child: const Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment.center,
|
||||||
@ -199,7 +200,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
SizedBox(width: 6),
|
SizedBox(width: 6),
|
||||||
Text('Produk'),
|
Text(context.lang.product),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -210,7 +211,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 12,
|
horizontal: 12,
|
||||||
),
|
),
|
||||||
child: const Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment.center,
|
||||||
@ -220,7 +221,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
SizedBox(width: 6),
|
SizedBox(width: 6),
|
||||||
Text('Bahan'),
|
Text(context.lang.ingredients),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -254,7 +255,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Inventaris'),
|
flexibleSpace: CustomAppBar(title: context.lang.inventory),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +309,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Total Produk',
|
context.lang.total_products,
|
||||||
inventory.totalProducts.toString(),
|
inventory.totalProducts.toString(),
|
||||||
Icons.inventory_2_rounded,
|
Icons.inventory_2_rounded,
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
@ -317,7 +318,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Produk Terjual',
|
context.lang.total_sold,
|
||||||
inventory.totalSoldProducts.toString(),
|
inventory.totalSoldProducts.toString(),
|
||||||
Icons.check_circle_rounded,
|
Icons.check_circle_rounded,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
@ -330,7 +331,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Stok Rendah',
|
context.lang.low_stock,
|
||||||
inventory.lowStockProducts.toString(),
|
inventory.lowStockProducts.toString(),
|
||||||
Icons.warning_rounded,
|
Icons.warning_rounded,
|
||||||
AppColor.warning,
|
AppColor.warning,
|
||||||
@ -339,7 +340,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Stok Kosong',
|
context.lang.zero_stock,
|
||||||
inventory.zeroStockProducts.toString(),
|
inventory.zeroStockProducts.toString(),
|
||||||
Icons.error_rounded,
|
Icons.error_rounded,
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
@ -361,7 +362,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Total Bahan',
|
context.lang.total_ingredients,
|
||||||
inventory.totalIngredients.toString(),
|
inventory.totalIngredients.toString(),
|
||||||
Icons.restaurant_menu_rounded,
|
Icons.restaurant_menu_rounded,
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
@ -370,7 +371,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Bahan Terjual',
|
context.lang.total_sold,
|
||||||
inventory.totalSoldIngredients.toString(),
|
inventory.totalSoldIngredients.toString(),
|
||||||
Icons.check_circle_rounded,
|
Icons.check_circle_rounded,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
@ -383,7 +384,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Stok Kurang',
|
context.lang.low_stock,
|
||||||
inventory.lowStockIngredients.toString(),
|
inventory.lowStockIngredients.toString(),
|
||||||
Icons.warning_rounded,
|
Icons.warning_rounded,
|
||||||
AppColor.warning,
|
AppColor.warning,
|
||||||
@ -392,7 +393,7 @@ class _InventoryPageState extends State<InventoryPage>
|
|||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatCard(
|
child: _buildStatCard(
|
||||||
'Habis',
|
context.lang.zero_stock,
|
||||||
inventory.zeroStockIngredients.toString(),
|
inventory.zeroStockIngredients.toString(),
|
||||||
Icons.error_rounded,
|
Icons.error_rounded,
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
|
|||||||
@ -182,7 +182,11 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_getStatusText(),
|
item.isZeroStock
|
||||||
|
? context.lang.out_of_stock
|
||||||
|
: item.isLowStock
|
||||||
|
? context.lang.low_stock
|
||||||
|
: context.lang.available,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
@ -202,7 +206,7 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildInfoItem(
|
child: _buildInfoItem(
|
||||||
LineIcons.boxes,
|
LineIcons.boxes,
|
||||||
'Stok',
|
context.lang.stock,
|
||||||
'${NumberFormat('#,###', 'id_ID').format(item.quantity)} pcs',
|
'${NumberFormat('#,###', 'id_ID').format(item.quantity)} pcs',
|
||||||
_getQuantityColor(),
|
_getQuantityColor(),
|
||||||
),
|
),
|
||||||
@ -212,7 +216,7 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildInfoItem(
|
child: _buildInfoItem(
|
||||||
LineIcons.dollarSign,
|
LineIcons.dollarSign,
|
||||||
'Nilai',
|
context.lang.value_text,
|
||||||
_formatCurrencyShort(item.totalValue),
|
_formatCurrencyShort(item.totalValue),
|
||||||
AppColor.info,
|
AppColor.info,
|
||||||
),
|
),
|
||||||
@ -259,14 +263,19 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Stok Menipis',
|
context.lang.low_stock,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: AppColor.warning,
|
color: AppColor.warning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
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(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -301,14 +310,14 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Stok Habis',
|
context.lang.out_of_stock,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: AppColor.error,
|
color: AppColor.error,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Produk tidak tersedia untuk dijual',
|
context.lang.out_of_stock_desc,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -330,7 +339,7 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMovementInfo(
|
child: _buildMovementInfo(
|
||||||
LineIcons.arrowUp,
|
LineIcons.arrowUp,
|
||||||
'Masuk',
|
context.lang.in_text,
|
||||||
'${NumberFormat('#,###', 'id_ID').format(item.totalIn)} pcs',
|
'${NumberFormat('#,###', 'id_ID').format(item.totalIn)} pcs',
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
),
|
),
|
||||||
@ -341,7 +350,7 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildMovementInfo(
|
child: _buildMovementInfo(
|
||||||
LineIcons.arrowDown,
|
LineIcons.arrowDown,
|
||||||
'Keluar',
|
context.lang.out_text,
|
||||||
'${NumberFormat('#,###', 'id_ID').format(item.totalOut)} pcs',
|
'${NumberFormat('#,###', 'id_ID').format(item.totalOut)} pcs',
|
||||||
AppColor.error,
|
AppColor.error,
|
||||||
),
|
),
|
||||||
@ -476,12 +485,6 @@ class InventoryProductTile extends StatelessWidget {
|
|||||||
return AppColor.textPrimary;
|
return AppColor.textPrimary;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getStatusText() {
|
|
||||||
if (item.isZeroStock) return 'HABIS';
|
|
||||||
if (item.isLowStock) return 'MINIM';
|
|
||||||
return 'TERSEDIA';
|
|
||||||
}
|
|
||||||
|
|
||||||
IconData _getCategoryIcon() {
|
IconData _getCategoryIcon() {
|
||||||
final category = item.categoryName.toLowerCase();
|
final category = item.categoryName.toLowerCase();
|
||||||
if (category.contains('elektronik') || category.contains('gadget')) {
|
if (category.contains('elektronik') || category.contains('gadget')) {
|
||||||
|
|||||||
@ -33,8 +33,8 @@ class _MainBottomNavbarState extends State<MainBottomNavbar> {
|
|||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: LineIcon(LineIcons.moneyBill),
|
icon: LineIcon(LineIcons.moneyBill),
|
||||||
label: 'Order',
|
label: context.lang.order,
|
||||||
tooltip: 'Order',
|
tooltip: context.lang.order,
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: LineIcon(LineIcons.barChart),
|
icon: LineIcon(LineIcons.barChart),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'dart:math' show cos, sin;
|
import 'dart:math' show cos, sin;
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/order/order.dart';
|
import '../../../../domain/order/order.dart';
|
||||||
import '../../../components/appbar/appbar.dart';
|
import '../../../components/appbar/appbar.dart';
|
||||||
@ -22,33 +23,33 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
expandedHeight: 120,
|
expandedHeight: 120,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: const CustomAppBar(title: "Detail Pesanan"),
|
flexibleSpace: CustomAppBar(title: context.lang.order_details),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Order Status Card
|
// Order Status Card
|
||||||
_buildOrderStatusCard(),
|
_buildOrderStatusCard(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Table Visual Card (for dine-in)
|
// Table Visual Card (for dine-in)
|
||||||
if (_isDineIn()) _buildTableVisualCard(),
|
if (_isDineIn()) _buildTableVisualCard(context),
|
||||||
|
|
||||||
// Order Info Card
|
// Order Info Card
|
||||||
_buildOrderInfoCard(),
|
_buildOrderInfoCard(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Order Items Section
|
// Order Items Section
|
||||||
_buildOrderItemsSection(),
|
_buildOrderItemsSection(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Payment Summary Card
|
// Payment Summary Card
|
||||||
_buildPaymentSummaryCard(),
|
_buildPaymentSummaryCard(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Payment Methods Section
|
// Payment Methods Section
|
||||||
_buildPaymentMethodsSection(),
|
_buildPaymentMethodsSection(context),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -58,7 +59,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildOrderStatusCard() {
|
Widget _buildOrderStatusCard(BuildContext context) {
|
||||||
Color statusColor = _getStatusColor(order.status);
|
Color statusColor = _getStatusColor(order.status);
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.all(16),
|
margin: const EdgeInsets.all(16),
|
||||||
@ -123,7 +124,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Order Number',
|
context.lang.order_number,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -157,7 +158,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Status Pesanan',
|
context.lang.order_status,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -197,7 +198,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Total Amount',
|
context.lang.total_amount,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -222,7 +223,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTableVisualCard() {
|
Widget _buildTableVisualCard(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||||
height: 220, // Increased height
|
height: 220, // Increased height
|
||||||
@ -284,14 +285,14 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Makan di Tempat',
|
context.lang.dine_in,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.white.withOpacity(0.9),
|
color: AppColor.white.withOpacity(0.9),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Dine In Experience',
|
context.lang.dine_in_experience,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -347,7 +348,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'MEJA',
|
context.lang.table,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.primary.withOpacity(
|
color: AppColor.primary.withOpacity(
|
||||||
0.7,
|
0.7,
|
||||||
@ -417,7 +418,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
'${order.orderItems.length} Items',
|
'${order.orderItems.length} ${context.lang.items}',
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -470,7 +471,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildOrderInfoCard() {
|
Widget _buildOrderInfoCard(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -517,7 +518,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'Informasi Pesanan',
|
context.lang.order_information,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
@ -527,24 +528,28 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
if (_shouldShowTableNumber())
|
if (_shouldShowTableNumber())
|
||||||
_buildInfoRow(Icons.table_restaurant, 'Meja', order.tableNumber),
|
_buildInfoRow(
|
||||||
|
Icons.table_restaurant,
|
||||||
|
context.lang.table,
|
||||||
|
order.tableNumber,
|
||||||
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
Icons.delivery_dining,
|
Icons.delivery_dining,
|
||||||
'Tipe Pesanan',
|
context.lang.order_type,
|
||||||
order.orderType,
|
order.orderType,
|
||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
Icons.payment,
|
Icons.payment,
|
||||||
'Status Pembayaran',
|
context.lang.payment_status,
|
||||||
order.paymentStatus,
|
order.paymentStatus,
|
||||||
),
|
),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
Icons.access_time,
|
Icons.access_time,
|
||||||
'Dibuat',
|
context.lang.created,
|
||||||
_formatDateTime(order.createdAt),
|
_formatDateTime(order.createdAt),
|
||||||
),
|
),
|
||||||
if (order.notes.isNotEmpty)
|
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(
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -612,7 +617,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Item Pesanan',
|
context.lang.order_item,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.textPrimary,
|
color: AppColor.textPrimary,
|
||||||
@ -629,7 +634,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${order.orderItems.length} Item',
|
'${order.orderItems.length} ${context.lang.item}',
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -647,7 +652,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
separatorBuilder: (context, index) => const Divider(height: 24),
|
separatorBuilder: (context, index) => const Divider(height: 24),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = order.orderItems[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
|
// 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);
|
Color itemStatusColor = _getItemStatusColor(itemStatus);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
@ -786,7 +791,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Diskon: -Rp ${_formatCurrency(item.discountAmount)}',
|
'${context.lang.discount}: -Rp ${_formatCurrency(item.discountAmount)}',
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.error,
|
color: AppColor.error,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -811,7 +816,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Total Item',
|
context.lang.total_item,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -845,7 +850,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPaymentSummaryCard() {
|
Widget _buildPaymentSummaryCard(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -866,26 +871,38 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Ringkasan Pembayaran',
|
context.lang.payment_summary,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildSummaryRow('Subtotal', order.subtotal),
|
_buildSummaryRow(context.lang.subtotal, order.subtotal),
|
||||||
if (order.discountAmount > 0)
|
if (order.discountAmount > 0)
|
||||||
_buildSummaryRow(
|
_buildSummaryRow(
|
||||||
'Diskon',
|
context.lang.discount,
|
||||||
-order.discountAmount,
|
-order.discountAmount,
|
||||||
isDiscount: true,
|
isDiscount: true,
|
||||||
),
|
),
|
||||||
_buildSummaryRow('Pajak', order.taxAmount),
|
_buildSummaryRow(context.lang.tax, order.taxAmount),
|
||||||
const Divider(height: 24),
|
const Divider(height: 24),
|
||||||
_buildSummaryRow('Total', order.totalAmount, isTotal: true),
|
_buildSummaryRow(
|
||||||
_buildSummaryRow('Dibayar', order.totalPaid, isSuccess: true),
|
context.lang.total,
|
||||||
|
order.totalAmount,
|
||||||
|
isTotal: true,
|
||||||
|
),
|
||||||
|
_buildSummaryRow(
|
||||||
|
context.lang.paid,
|
||||||
|
order.totalPaid,
|
||||||
|
isSuccess: true,
|
||||||
|
),
|
||||||
if (order.remainingAmount > 0)
|
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();
|
if (order.payments.isEmpty) return const SizedBox();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
@ -952,7 +969,7 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 0),
|
padding: const EdgeInsets.fromLTRB(20, 20, 20, 0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Metode Pembayaran',
|
context.lang.payment_method,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.textPrimary,
|
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:
|
// Logic untuk menentukan status item berdasarkan:
|
||||||
// 1. Status order secara keseluruhan
|
// 1. Status order secara keseluruhan
|
||||||
// 2. Jika ada field status di OrderItem model
|
// 2. Jika ada field status di OrderItem model
|
||||||
@ -1167,26 +1184,24 @@ class OrderDetailPage extends StatelessWidget {
|
|||||||
|
|
||||||
switch (order.status.toLowerCase()) {
|
switch (order.status.toLowerCase()) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
return 'Selesai';
|
return context.lang.completed;
|
||||||
case 'pending':
|
case 'pending':
|
||||||
return 'Menunggu';
|
return context.lang.pending;
|
||||||
case 'cancelled':
|
case 'cancelled':
|
||||||
return 'Dibatalkan';
|
return context.lang.void_text;
|
||||||
default:
|
default:
|
||||||
return 'Menunggu';
|
return context.lang.pending;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _getItemStatusColor(String status) {
|
Color _getItemStatusColor(String status) {
|
||||||
switch (status.toLowerCase()) {
|
switch (status.toLowerCase()) {
|
||||||
case 'selesai':
|
case 'completed':
|
||||||
return AppColor.success;
|
return AppColor.success;
|
||||||
case 'diproses':
|
case 'pending':
|
||||||
return AppColor.warning;
|
return AppColor.warning;
|
||||||
case 'dibatalkan':
|
case 'cancelled':
|
||||||
return AppColor.error;
|
return AppColor.error;
|
||||||
case 'siap':
|
|
||||||
return AppColor.info;
|
|
||||||
default:
|
default:
|
||||||
return AppColor.primary;
|
return AppColor.primary;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,15 +3,13 @@ import 'dart:developer';
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
|
||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
import '../../../../application/order/order_loader/order_loader_bloc.dart';
|
import '../../../../application/order/order_loader/order_loader_bloc.dart';
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../injection.dart';
|
import '../../../../injection.dart';
|
||||||
import '../../../components/appbar/appbar.dart';
|
import '../../../components/appbar/appbar.dart';
|
||||||
import '../../../components/button/button.dart';
|
|
||||||
import '../../../components/spacer/spacer.dart';
|
|
||||||
import '../../../components/widgets/empty_widget.dart';
|
import '../../../components/widgets/empty_widget.dart';
|
||||||
import '../../../router/app_router.gr.dart';
|
import '../../../router/app_router.gr.dart';
|
||||||
import 'widgets/filter_header_delegate.dart';
|
import 'widgets/filter_header_delegate.dart';
|
||||||
@ -224,11 +222,10 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
flexibleSpace: CustomAppBar(title: 'Order', isBack: false),
|
flexibleSpace: CustomAppBar(
|
||||||
actions: [
|
title: context.lang.orders,
|
||||||
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
|
isBack: false,
|
||||||
SpaceWidth(8),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// Pinned Filter Section
|
// Pinned Filter Section
|
||||||
@ -285,7 +282,7 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'${state.orders.length} ${state.status.toLowerCase()} order${state.orders.length != 1 ? 's' : ''}',
|
'${state.orders.length} ${state.status.toLowerCase()} ${context.lang.orders}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -300,9 +297,10 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
_buildShimmerList()
|
_buildShimmerList()
|
||||||
else if (state.orders.isEmpty)
|
else if (state.orders.isEmpty)
|
||||||
EmptyWidget(
|
EmptyWidget(
|
||||||
title: 'Order',
|
title: context.lang.order,
|
||||||
message:
|
message: context.lang.no_order_with_status(
|
||||||
'No ${state.status.toLowerCase()} orders found',
|
state.status.toLowerCase(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../../common/extension/extension.dart';
|
||||||
import '../../../../components/field/date_range_picker_field.dart';
|
import '../../../../components/field/date_range_picker_field.dart';
|
||||||
import 'status_tile.dart';
|
import 'status_tile.dart';
|
||||||
|
|
||||||
@ -36,7 +37,6 @@ class FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
double shrinkOffset,
|
double shrinkOffset,
|
||||||
bool overlapsContent,
|
bool overlapsContent,
|
||||||
) {
|
) {
|
||||||
print('FilterHeaderDelegate build called'); // Debug log
|
|
||||||
return Container(
|
return Container(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
@ -50,9 +50,6 @@ class FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate,
|
endDate: endDate,
|
||||||
onChanged: (start, end) {
|
onChanged: (start, end) {
|
||||||
print(
|
|
||||||
'onChanged called in FilterHeaderDelegate: $start - $end',
|
|
||||||
); // Debug log
|
|
||||||
onDateChanged(start, end);
|
onDateChanged(start, end);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -70,7 +67,11 @@ class FilterHeaderDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
right: index < filterOptions.length - 1 ? 8 : 0,
|
right: index < filterOptions.length - 1 ? 8 : 0,
|
||||||
),
|
),
|
||||||
child: OrderStatusTile(
|
child: OrderStatusTile(
|
||||||
label: option,
|
label: option == "All"
|
||||||
|
? context.lang.all
|
||||||
|
: option == "Completed"
|
||||||
|
? context.lang.completed
|
||||||
|
: context.lang.pending,
|
||||||
isSelected: option == selectedFilter,
|
isSelected: option == selectedFilter,
|
||||||
onSelected: (isSelected) {
|
onSelected: (isSelected) {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import '../../../../../common/extension/extension.dart';
|
||||||
import '../../../../../common/theme/theme.dart';
|
import '../../../../../common/theme/theme.dart';
|
||||||
import '../../../../../domain/order/order.dart';
|
import '../../../../../domain/order/order.dart';
|
||||||
|
|
||||||
@ -46,19 +47,19 @@ class OrderTile extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Header Row
|
// Header Row
|
||||||
_buildHeaderRow(),
|
_buildHeaderRow(context),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
// Order Info
|
// Order Info
|
||||||
_buildOrderInfo(),
|
_buildOrderInfo(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Amount Section
|
// Amount Section
|
||||||
_buildAmountSection(),
|
_buildAmountSection(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Footer with Actions
|
// Footer with Actions
|
||||||
_buildFooterActions(),
|
_buildFooterActions(context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -67,7 +68,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHeaderRow() {
|
Widget _buildHeaderRow(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -94,12 +95,12 @@ class OrderTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
_buildStatusChip(),
|
_buildStatusChip(context),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatusChip() {
|
Widget _buildStatusChip(BuildContext context) {
|
||||||
Color statusColor;
|
Color statusColor;
|
||||||
String statusText;
|
String statusText;
|
||||||
IconData statusIcon;
|
IconData statusIcon;
|
||||||
@ -107,27 +108,34 @@ class OrderTile extends StatelessWidget {
|
|||||||
// Check isVoid and isRefund first for display
|
// Check isVoid and isRefund first for display
|
||||||
if (order.isVoid) {
|
if (order.isVoid) {
|
||||||
statusColor = AppColor.error;
|
statusColor = AppColor.error;
|
||||||
statusText = 'Void';
|
statusText = context.lang.void_text;
|
||||||
statusIcon = Icons.block;
|
statusIcon = Icons.block;
|
||||||
} else if (order.isRefund) {
|
} else if (order.isRefund) {
|
||||||
statusColor = AppColor.info;
|
statusColor = AppColor.info;
|
||||||
statusText = 'Refunded';
|
statusText = context.lang.refund;
|
||||||
statusIcon = Icons.undo;
|
statusIcon = Icons.undo;
|
||||||
} else {
|
} else {
|
||||||
// Handle status values (only pending and completed)
|
// Handle status values (only pending and completed)
|
||||||
switch (order.status.toLowerCase()) {
|
switch (order.status.toLowerCase()) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
|
statusColor = AppColor.success;
|
||||||
|
statusText = context.lang.completed;
|
||||||
|
statusIcon = Icons.check_circle;
|
||||||
case 'paid':
|
case 'paid':
|
||||||
case 'finished':
|
case 'finished':
|
||||||
statusColor = AppColor.success;
|
statusColor = AppColor.success;
|
||||||
statusText = 'Completed';
|
statusText = context.lang.completed;
|
||||||
statusIcon = Icons.check_circle;
|
statusIcon = Icons.check_circle;
|
||||||
break;
|
break;
|
||||||
case 'pending':
|
case 'pending':
|
||||||
|
statusColor = AppColor.warning;
|
||||||
|
statusText = context.lang.pending;
|
||||||
|
statusIcon = Icons.schedule;
|
||||||
|
break;
|
||||||
case 'waiting':
|
case 'waiting':
|
||||||
case 'processing':
|
case 'processing':
|
||||||
statusColor = AppColor.warning;
|
statusColor = AppColor.warning;
|
||||||
statusText = 'Pending';
|
statusText = context.lang.pending;
|
||||||
statusIcon = Icons.schedule;
|
statusIcon = Icons.schedule;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -163,7 +171,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildOrderInfo() {
|
Widget _buildOrderInfo(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -177,7 +185,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
_getOrderInfoText(),
|
_getOrderInfoText(context),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -198,7 +206,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
'${order.orderItems.length} items',
|
'${order.orderItems.length} ${context.lang.items}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
@ -239,7 +247,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAmountSection() {
|
Widget _buildAmountSection(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
@ -264,8 +272,8 @@ class OrderTile extends StatelessWidget {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
'Total Amount',
|
context.lang.total_amount,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: AppColor.textWhite,
|
color: AppColor.textWhite,
|
||||||
@ -274,7 +282,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'Rp ${NumberFormat('#,###').format(order.totalAmount)}',
|
order.totalAmount.currencyFormatRp,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -284,7 +292,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
if (order.remainingAmount > 0) ...[
|
if (order.remainingAmount > 0) ...[
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'Remaining: Rp ${NumberFormat('#,###').format(order.remainingAmount)}',
|
'${context.lang.remaining}: ${order.remainingAmount.currencyFormatRp}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: AppColor.textWhite,
|
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
|
// Don't show anything if order is void or refunded
|
||||||
if (order.isVoid || order.isRefund) {
|
if (order.isVoid || order.isRefund) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
@ -326,7 +334,7 @@ class OrderTile extends StatelessWidget {
|
|||||||
if (order.payments.isNotEmpty) ...[
|
if (order.payments.isNotEmpty) ...[
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
'Payment: ${_getPaymentMethods()}',
|
'${context.lang.payment}: ${_getPaymentMethods()}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: AppColor.textLight,
|
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() {
|
IconData _getOrderInfoIcon() {
|
||||||
switch (order.orderType.toLowerCase()) {
|
switch (order.orderType.toLowerCase()) {
|
||||||
case 'dine in':
|
case 'dine in':
|
||||||
@ -406,11 +365,11 @@ class OrderTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getOrderInfoText() {
|
String _getOrderInfoText(BuildContext context) {
|
||||||
switch (order.orderType.toLowerCase()) {
|
switch (order.orderType.toLowerCase()) {
|
||||||
case 'dine in':
|
case 'dine in':
|
||||||
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 'takeaway':
|
||||||
case 'take_away':
|
case 'take_away':
|
||||||
case 'pickup':
|
case 'pickup':
|
||||||
@ -419,8 +378,8 @@ class OrderTile extends StatelessWidget {
|
|||||||
return 'Delivery Order';
|
return 'Delivery Order';
|
||||||
default:
|
default:
|
||||||
return order.tableNumber.isNotEmpty
|
return order.tableNumber.isNotEmpty
|
||||||
? 'Table ${order.tableNumber}'
|
? '${context.lang.table} ${order.tableNumber}'
|
||||||
: 'Order ${order.orderNumber}';
|
: context.lang.order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,12 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../../application/outlet/current_outlet_loader/current_outlet_loader_bloc.dart';
|
import '../../../application/outlet/current_outlet_loader/current_outlet_loader_bloc.dart';
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../../domain/outlet/outlet.dart';
|
import '../../../domain/outlet/outlet.dart';
|
||||||
import '../../../injection.dart';
|
import '../../../injection.dart';
|
||||||
import '../../components/appbar/appbar.dart';
|
import '../../components/appbar/appbar.dart';
|
||||||
|
import '../../components/spacer/spacer.dart';
|
||||||
|
|
||||||
// Outlet Information Page
|
// Outlet Information Page
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
@ -79,14 +81,14 @@ class _OutletInformationPageState extends State<OutletInformationPage>
|
|||||||
expandedHeight: 120.0,
|
expandedHeight: 120.0,
|
||||||
floating: false,
|
floating: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
flexibleSpace: CustomAppBar(title: 'Outlet Information'),
|
flexibleSpace: CustomAppBar(title: context.lang.outlet_information),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: FadeTransition(
|
child: FadeTransition(
|
||||||
opacity: _fadeAnimation,
|
opacity: _fadeAnimation,
|
||||||
child: SlideTransition(
|
child: SlideTransition(
|
||||||
position: _slideAnimation,
|
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>(
|
return BlocBuilder<CurrentOutletLoaderBloc, CurrentOutletLoaderState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return Padding(
|
return Padding(
|
||||||
@ -105,15 +107,11 @@ class _OutletInformationPageState extends State<OutletInformationPage>
|
|||||||
children: [
|
children: [
|
||||||
_buildHeaderCard(state.outlet),
|
_buildHeaderCard(state.outlet),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildInfoSection(state.outlet),
|
_buildInfoSection(context, state.outlet),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildContactSection(state.outlet),
|
_buildBusinessSection(context, state.outlet),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildBusinessSection(state.outlet),
|
_buildStatusSection(context, state.outlet),
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildStatusSection(state.outlet),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildTimestampSection(state.outlet),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -190,62 +188,65 @@ class _OutletInformationPageState extends State<OutletInformationPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildInfoSection(Outlet outlet) {
|
Widget _buildInfoSection(BuildContext context, Outlet outlet) {
|
||||||
return _buildAnimatedCard(
|
return _buildAnimatedCard(
|
||||||
delay: 200,
|
delay: 200,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildSectionTitle('General Information', Icons.info_outline),
|
_buildSectionTitle(
|
||||||
const SizedBox(height: 16),
|
context.lang.outlet_information,
|
||||||
_buildInfoRow('Outlet ID', outlet.id, Icons.fingerprint),
|
Icons.info_outline,
|
||||||
_buildInfoRow(
|
),
|
||||||
'Organization ID',
|
SpaceHeight(20),
|
||||||
outlet.organizationId,
|
_buildInfoRow(
|
||||||
Icons.business,
|
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) {
|
Widget _buildBusinessSection(BuildContext context, 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) {
|
|
||||||
return _buildAnimatedCard(
|
return _buildAnimatedCard(
|
||||||
delay: 600,
|
delay: 600,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildSectionTitle('Business Settings', Icons.settings_applications),
|
_buildSectionTitle(
|
||||||
|
context.lang.business_settings,
|
||||||
|
Icons.settings_applications,
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildInfoRow('Currency', outlet.currency, Icons.monetization_on),
|
_buildInfoRow(
|
||||||
_buildInfoRow('Tax Rate', '${outlet.taxRate}%', Icons.percent),
|
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(
|
return _buildAnimatedCard(
|
||||||
delay: 800,
|
delay: 800,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildSectionTitle('Status', Icons.toggle_on),
|
_buildSectionTitle(context.lang.status_text, Icons.toggle_on),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
@ -272,7 +273,7 @@ class _OutletInformationPageState extends State<OutletInformationPage>
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(
|
Text(
|
||||||
outlet.isActive ? 'Active' : 'Inactive',
|
outlet.isActive ? context.lang.active : context.lang.inactive,
|
||||||
style: AppStyle.md.copyWith(
|
style: AppStyle.md.copyWith(
|
||||||
color: outlet.isActive ? AppColor.success : AppColor.error,
|
color: outlet.isActive ? AppColor.success : AppColor.error,
|
||||||
fontWeight: FontWeight.w600,
|
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}) {
|
Widget _buildAnimatedCard({required Widget child, required int delay}) {
|
||||||
return TweenAnimationBuilder<double>(
|
return TweenAnimationBuilder<double>(
|
||||||
duration: Duration(milliseconds: 600 + delay),
|
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')}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../../../application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart';
|
import '../../../../application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart';
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/analytic/analytic.dart';
|
import '../../../../domain/analytic/analytic.dart';
|
||||||
import '../../../../injection.dart';
|
import '../../../../injection.dart';
|
||||||
@ -136,18 +137,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: FlexibleSpaceBar(
|
flexibleSpace: CustomAppBar(title: context.lang.product_analytic),
|
||||||
background: Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: AppColor.primaryGradient,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const CustomAppBar(title: "Analisis Produk"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +204,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
icon: Icons.monetization_on,
|
icon: Icons.monetization_on,
|
||||||
title: 'Total Pendapatan',
|
title: context.lang.total_revenue,
|
||||||
value: _formatCurrency(stats.totalRevenue),
|
value: _formatCurrency(stats.totalRevenue),
|
||||||
color: AppColor.success,
|
color: AppColor.success,
|
||||||
),
|
),
|
||||||
@ -223,7 +213,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
icon: Icons.shopping_cart,
|
icon: Icons.shopping_cart,
|
||||||
title: 'Total Terjual',
|
title: context.lang.total_sold,
|
||||||
value: _formatNumber(stats.totalQuantity),
|
value: _formatNumber(stats.totalQuantity),
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
),
|
),
|
||||||
@ -236,7 +226,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
icon: Icons.receipt_long,
|
icon: Icons.receipt_long,
|
||||||
title: 'Total Pesanan',
|
title: context.lang.total_orders,
|
||||||
value: _formatNumber(stats.totalOrders),
|
value: _formatNumber(stats.totalOrders),
|
||||||
color: AppColor.warning,
|
color: AppColor.warning,
|
||||||
),
|
),
|
||||||
@ -245,7 +235,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
icon: Icons.trending_up,
|
icon: Icons.trending_up,
|
||||||
title: 'Rata-rata Nilai',
|
title: context.lang.average_price,
|
||||||
value: _formatCurrency(stats.averageOrderValue),
|
value: _formatCurrency(stats.averageOrderValue),
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
),
|
),
|
||||||
@ -541,7 +531,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
Icon(Icons.trending_up, color: AppColor.success, size: 20),
|
Icon(Icons.trending_up, color: AppColor.success, size: 20),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Pendapatan',
|
context.lang.revenue,
|
||||||
style: _getTextStyle(
|
style: _getTextStyle(
|
||||||
AppStyle.sm,
|
AppStyle.sm,
|
||||||
color: AppColor.success,
|
color: AppColor.success,
|
||||||
@ -552,7 +542,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
_formatCurrency(product.revenue.toDouble()),
|
product.revenue.currencyFormatRp,
|
||||||
style: _getTextStyle(
|
style: _getTextStyle(
|
||||||
AppStyle.xl,
|
AppStyle.xl,
|
||||||
color: AppColor.success,
|
color: AppColor.success,
|
||||||
@ -570,14 +560,14 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
_buildStatCard(
|
_buildStatCard(
|
||||||
icon: Icons.shopping_cart_outlined,
|
icon: Icons.shopping_cart_outlined,
|
||||||
value: '${product.quantitySold}',
|
value: '${product.quantitySold}',
|
||||||
label: 'Terjual',
|
label: context.lang.sold,
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildStatCard(
|
_buildStatCard(
|
||||||
icon: Icons.receipt_outlined,
|
icon: Icons.receipt_outlined,
|
||||||
value: '${product.orderCount}',
|
value: '${product.orderCount}',
|
||||||
label: 'Pesanan',
|
label: context.lang.orders,
|
||||||
color: AppColor.warning,
|
color: AppColor.warning,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -645,7 +635,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Harga Rata-rata',
|
context.lang.average_price,
|
||||||
style: _getTextStyle(
|
style: _getTextStyle(
|
||||||
AppStyle.sm,
|
AppStyle.sm,
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
@ -653,7 +643,7 @@ class _ProductAnalyticPageState extends State<ProductAnalyticPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
_formatCurrency(product.averagePrice),
|
product.averagePrice.round().currencyFormatRp,
|
||||||
style: _getTextStyle(
|
style: _getTextStyle(
|
||||||
AppStyle.sm,
|
AppStyle.sm,
|
||||||
color: _getCategoryColor(product.categoryName),
|
color: _getCategoryColor(product.categoryName),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:shimmer/shimmer.dart';
|
|||||||
|
|
||||||
import '../../../../application/category/category_loader/category_loader_bloc.dart';
|
import '../../../../application/category/category_loader/category_loader_bloc.dart';
|
||||||
import '../../../../application/product/product_loader/product_loader_bloc.dart';
|
import '../../../../application/product/product_loader/product_loader_bloc.dart';
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../../domain/category/category.dart';
|
import '../../../../domain/category/category.dart';
|
||||||
import '../../../../domain/product/product.dart';
|
import '../../../../domain/product/product.dart';
|
||||||
@ -83,7 +84,7 @@ class _ProductPageState extends State<ProductPage>
|
|||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
_buildSliverAppBar(),
|
_buildSliverAppBar(context),
|
||||||
_buildCategoryFilter(),
|
_buildCategoryFilter(),
|
||||||
_buildProductContent(state),
|
_buildProductContent(state),
|
||||||
],
|
],
|
||||||
@ -95,13 +96,13 @@ class _ProductPageState extends State<ProductPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSliverAppBar() {
|
Widget _buildSliverAppBar(BuildContext context) {
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
expandedHeight: 120.0,
|
expandedHeight: 120.0,
|
||||||
floating: false,
|
floating: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
flexibleSpace: CustomAppBar(title: 'Produk'),
|
flexibleSpace: CustomAppBar(title: context.lang.product),
|
||||||
actions: [
|
actions: [
|
||||||
ActionIconButton(onTap: () {}, icon: LineIcons.search),
|
ActionIconButton(onTap: () {}, icon: LineIcons.search),
|
||||||
ActionIconButton(
|
ActionIconButton(
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../../../../application/user/change_password_form/change_password_form_bloc.dart';
|
import '../../../../../application/user/change_password_form/change_password_form_bloc.dart';
|
||||||
|
import '../../../../../common/extension/extension.dart';
|
||||||
import '../../../../../common/theme/theme.dart';
|
import '../../../../../common/theme/theme.dart';
|
||||||
import '../../../../../injection.dart';
|
import '../../../../../injection.dart';
|
||||||
import '../../../../components/appbar/appbar.dart';
|
import '../../../../components/appbar/appbar.dart';
|
||||||
@ -39,7 +40,7 @@ class _ProfileChangePasswordPageState extends State<ProfileChangePasswordPage> {
|
|||||||
(f) => AppFlushbar.showUserFailureToast(context, f),
|
(f) => AppFlushbar.showUserFailureToast(context, f),
|
||||||
(user) {
|
(user) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
AppFlushbar.showSuccess(context, 'Password changed');
|
AppFlushbar.showSuccess(context, context.lang.password_changed);
|
||||||
Future.delayed(const Duration(seconds: 2), () {
|
Future.delayed(const Duration(seconds: 2), () {
|
||||||
context.router.back();
|
context.router.back();
|
||||||
});
|
});
|
||||||
@ -59,7 +60,7 @@ class _ProfileChangePasswordPageState extends State<ProfileChangePasswordPage> {
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Change Password'),
|
flexibleSpace: CustomAppBar(title: context.lang.change_password),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child:
|
child:
|
||||||
@ -83,7 +84,7 @@ class _ProfileChangePasswordPageState extends State<ProfileChangePasswordPage> {
|
|||||||
ChangePasswordNewPassword(),
|
ChangePasswordNewPassword(),
|
||||||
SpaceHeight(24),
|
SpaceHeight(24),
|
||||||
AppElevatedButton(
|
AppElevatedButton(
|
||||||
text: 'Save',
|
text: context.lang.save,
|
||||||
isLoading: state.isSubmitting,
|
isLoading: state.isSubmitting,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<ChangePasswordFormBloc>().add(
|
context.read<ChangePasswordFormBloc>().add(
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
import '../../../../../../application/user/change_password_form/change_password_form_bloc.dart';
|
import '../../../../../../application/user/change_password_form/change_password_form_bloc.dart';
|
||||||
|
import '../../../../../../common/extension/extension.dart';
|
||||||
import '../../../../../components/field/field.dart';
|
import '../../../../../components/field/field.dart';
|
||||||
|
|
||||||
class ChangePasswordCurrentPassword extends StatelessWidget {
|
class ChangePasswordCurrentPassword extends StatelessWidget {
|
||||||
@ -11,9 +12,9 @@ class ChangePasswordCurrentPassword extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppPasswordTextFormField(
|
return AppPasswordTextFormField(
|
||||||
title: 'Current Password',
|
title: context.lang.current_password,
|
||||||
prefixIcon: LineIcons.lock,
|
prefixIcon: LineIcons.lock,
|
||||||
hintText: 'Please enter your current password',
|
hintText: context.lang.current_password_placeholder,
|
||||||
onChanged: (value) => context.read<ChangePasswordFormBloc>().add(
|
onChanged: (value) => context.read<ChangePasswordFormBloc>().add(
|
||||||
ChangePasswordFormEvent.currentPasswordChanged(value),
|
ChangePasswordFormEvent.currentPasswordChanged(value),
|
||||||
),
|
),
|
||||||
@ -23,7 +24,7 @@ class ChangePasswordCurrentPassword extends StatelessWidget {
|
|||||||
.state
|
.state
|
||||||
.currentPassword
|
.currentPassword
|
||||||
.isEmpty) {
|
.isEmpty) {
|
||||||
return 'Please enter your current password';
|
return context.lang.current_password_placeholder;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
import '../../../../../../application/user/change_password_form/change_password_form_bloc.dart';
|
import '../../../../../../application/user/change_password_form/change_password_form_bloc.dart';
|
||||||
|
import '../../../../../../common/extension/extension.dart';
|
||||||
import '../../../../../components/field/field.dart';
|
import '../../../../../components/field/field.dart';
|
||||||
|
|
||||||
class ChangePasswordNewPassword extends StatelessWidget {
|
class ChangePasswordNewPassword extends StatelessWidget {
|
||||||
@ -11,20 +12,20 @@ class ChangePasswordNewPassword extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppPasswordTextFormField(
|
return AppPasswordTextFormField(
|
||||||
title: 'New Password',
|
title: context.lang.new_password,
|
||||||
prefixIcon: LineIcons.lock,
|
prefixIcon: LineIcons.lock,
|
||||||
hintText: 'Please enter your new password',
|
hintText: context.lang.new_password_placeholder,
|
||||||
onChanged: (value) => context.read<ChangePasswordFormBloc>().add(
|
onChanged: (value) => context.read<ChangePasswordFormBloc>().add(
|
||||||
ChangePasswordFormEvent.newPasswordChanged(value),
|
ChangePasswordFormEvent.newPasswordChanged(value),
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (context.read<ChangePasswordFormBloc>().state.newPassword.isEmpty) {
|
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 ==
|
if (context.read<ChangePasswordFormBloc>().state.newPassword ==
|
||||||
context.read<ChangePasswordFormBloc>().state.currentPassword) {
|
context.read<ChangePasswordFormBloc>().state.currentPassword) {
|
||||||
return 'New password cannot be same as current password';
|
return context.lang.new_password_not_same;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
|
|
||||||
import '../../../../../application/auth/auth_bloc.dart';
|
import '../../../../../application/auth/auth_bloc.dart';
|
||||||
import '../../../../../application/user/user_edit_form/user_edit_form_bloc.dart';
|
import '../../../../../application/user/user_edit_form/user_edit_form_bloc.dart';
|
||||||
|
import '../../../../../common/extension/extension.dart';
|
||||||
import '../../../../../common/theme/theme.dart';
|
import '../../../../../common/theme/theme.dart';
|
||||||
import '../../../../../domain/user/user.dart';
|
import '../../../../../domain/user/user.dart';
|
||||||
import '../../../../../injection.dart';
|
import '../../../../../injection.dart';
|
||||||
@ -64,7 +65,7 @@ class _ProfileEditPageState extends State<ProfileEditPage> {
|
|||||||
pinned: true,
|
pinned: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Profile Edit'),
|
flexibleSpace: CustomAppBar(title: context.lang.edit_profile),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: BlocBuilder<UserEditFormBloc, UserEditFormState>(
|
child: BlocBuilder<UserEditFormBloc, UserEditFormState>(
|
||||||
@ -85,7 +86,7 @@ class _ProfileEditPageState extends State<ProfileEditPage> {
|
|||||||
ProfileEditNameField(controller: nameController),
|
ProfileEditNameField(controller: nameController),
|
||||||
SpaceHeight(24),
|
SpaceHeight(24),
|
||||||
AppElevatedButton(
|
AppElevatedButton(
|
||||||
text: 'Save',
|
text: context.lang.save,
|
||||||
isLoading: state.isSubmitting,
|
isLoading: state.isSubmitting,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<UserEditFormBloc>().add(
|
context.read<UserEditFormBloc>().add(
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
import '../../../../../../application/user/user_edit_form/user_edit_form_bloc.dart';
|
import '../../../../../../application/user/user_edit_form/user_edit_form_bloc.dart';
|
||||||
|
import '../../../../../../common/extension/extension.dart';
|
||||||
import '../../../../../components/field/field.dart';
|
import '../../../../../components/field/field.dart';
|
||||||
|
|
||||||
class ProfileEditNameField extends StatelessWidget {
|
class ProfileEditNameField extends StatelessWidget {
|
||||||
@ -12,9 +13,9 @@ class ProfileEditNameField extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppTextFormField(
|
return AppTextFormField(
|
||||||
title: 'Name',
|
title: context.lang.name,
|
||||||
prefixIcon: LineIcons.user,
|
prefixIcon: LineIcons.user,
|
||||||
hintText: 'Please enter your name',
|
hintText: context.lang.name_placeholder,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<UserEditFormBloc>().add(
|
context.read<UserEditFormBloc>().add(
|
||||||
@ -23,7 +24,7 @@ class ProfileEditNameField extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (context.read<UserEditFormBloc>().state.name.isEmpty) {
|
if (context.read<UserEditFormBloc>().state.name.isEmpty) {
|
||||||
return 'Please enter your name';
|
return context.lang.name_placeholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:loader_overlay/loader_overlay.dart';
|
|||||||
|
|
||||||
import '../../../application/auth/auth_bloc.dart';
|
import '../../../application/auth/auth_bloc.dart';
|
||||||
import '../../../application/auth/logout_form/logout_form_bloc.dart';
|
import '../../../application/auth/logout_form/logout_form_bloc.dart';
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../../injection.dart';
|
import '../../../injection.dart';
|
||||||
import '../../components/button/button.dart';
|
import '../../components/button/button.dart';
|
||||||
@ -89,7 +90,7 @@ class ProfilePage extends StatelessWidget implements AutoRouteWrapper {
|
|||||||
MainAxisAlignment.spaceBetween,
|
MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Profile',
|
context.lang.profile,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class ProfileAccountInfo extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Account Information',
|
context.lang.account_information,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -45,7 +45,7 @@ class ProfileAccountInfo extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: LineIcons.envelope,
|
icon: LineIcons.envelope,
|
||||||
title: 'Email',
|
title: context.lang.email,
|
||||||
subtitle: user.email,
|
subtitle: user.email,
|
||||||
showArrow: false,
|
showArrow: false,
|
||||||
),
|
),
|
||||||
@ -54,7 +54,7 @@ class ProfileAccountInfo extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: LineIcons.calendarAlt,
|
icon: LineIcons.calendarAlt,
|
||||||
title: 'Member Since',
|
title: context.lang.member_since,
|
||||||
subtitle: user.createdAt.toDate,
|
subtitle: user.createdAt.toDate,
|
||||||
showArrow: false,
|
showArrow: false,
|
||||||
),
|
),
|
||||||
@ -62,15 +62,15 @@ class ProfileAccountInfo extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: LineIcons.userEdit,
|
icon: LineIcons.userEdit,
|
||||||
title: 'Ubah Profil',
|
title: context.lang.edit_profile,
|
||||||
subtitle: 'Ubah profil kamu',
|
subtitle: context.lang.edit_profile_desc,
|
||||||
onTap: () => context.router.push(ProfileEditRoute(user: user)),
|
onTap: () => context.router.push(ProfileEditRoute(user: user)),
|
||||||
),
|
),
|
||||||
ProfileDivider(),
|
ProfileDivider(),
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: LineIcons.lock,
|
icon: LineIcons.lock,
|
||||||
title: 'Change Password',
|
title: context.lang.change_password,
|
||||||
subtitle: 'Change your password',
|
subtitle: context.lang.change_password_desc,
|
||||||
onTap: () => context.router.push(ProfileChangePasswordRoute()),
|
onTap: () => context.router.push(ProfileChangePasswordRoute()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../router/app_router.gr.dart';
|
import '../../../router/app_router.gr.dart';
|
||||||
import 'profile_tile.dart';
|
import 'profile_tile.dart';
|
||||||
@ -37,7 +38,7 @@ class _ProfileAppSettingState extends State<ProfileAppSetting> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'App Settings',
|
context.lang.app_settings,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -74,8 +75,8 @@ class _ProfileAppSettingState extends State<ProfileAppSetting> {
|
|||||||
// ProfileDivider(),
|
// ProfileDivider(),
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.language_outlined,
|
icon: Icons.language_outlined,
|
||||||
title: 'Language',
|
title: context.lang.language,
|
||||||
subtitle: 'English (US)',
|
subtitle: context.lang.language_desc,
|
||||||
onTap: () => context.router.push(LanguageRoute()),
|
onTap: () => context.router.push(LanguageRoute()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../router/app_router.gr.dart';
|
import '../../../router/app_router.gr.dart';
|
||||||
import 'divider.dart';
|
import 'divider.dart';
|
||||||
@ -30,7 +31,7 @@ class ProfileBusinessSetting extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Business Settings',
|
context.lang.business_settings,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -41,8 +42,8 @@ class ProfileBusinessSetting extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.business_outlined,
|
icon: Icons.business_outlined,
|
||||||
title: 'Outlet Information',
|
title: context.lang.outlet_information,
|
||||||
subtitle: 'Manage your Outlet details',
|
subtitle: context.lang.outlet_informatio_desc,
|
||||||
onTap: () => context.router.push(OutletInformationRoute()),
|
onTap: () => context.router.push(OutletInformationRoute()),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -50,8 +51,8 @@ class ProfileBusinessSetting extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.people_outline,
|
icon: Icons.people_outline,
|
||||||
title: 'Staff Management',
|
title: context.lang.staff_management,
|
||||||
subtitle: 'Manage employees and permissions',
|
subtitle: context.lang.staff_management_desc,
|
||||||
onTap: () => context.router.push(ComingSoonRoute()),
|
onTap: () => context.router.push(ComingSoonRoute()),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -59,16 +60,16 @@ class ProfileBusinessSetting extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.inventory_2_outlined,
|
icon: Icons.inventory_2_outlined,
|
||||||
title: 'Product',
|
title: context.lang.products,
|
||||||
subtitle: 'Manage your products',
|
subtitle: context.lang.manage_your_products,
|
||||||
onTap: () => context.router.push(ProductRoute()),
|
onTap: () => context.router.push(ProductRoute()),
|
||||||
),
|
),
|
||||||
ProfileDivider(),
|
ProfileDivider(),
|
||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.download_outlined,
|
icon: Icons.download_outlined,
|
||||||
title: 'Download Report',
|
title: context.lang.download_report,
|
||||||
subtitle: 'Download your sales or inventory report',
|
subtitle: context.lang.download_report_desc,
|
||||||
onTap: () => context.router.push(DownloadReportRoute()),
|
onTap: () => context.router.push(DownloadReportRoute()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../../../application/auth/logout_form/logout_form_bloc.dart';
|
import '../../../../application/auth/logout_form/logout_form_bloc.dart';
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../components/spacer/spacer.dart';
|
|
||||||
import 'profile_tile.dart';
|
import 'profile_tile.dart';
|
||||||
|
|
||||||
class ProfileDangerZone extends StatelessWidget {
|
class ProfileDangerZone extends StatelessWidget {
|
||||||
@ -28,27 +28,10 @@ class ProfileDangerZone extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
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(
|
ProfileTile(
|
||||||
icon: Icons.logout,
|
icon: Icons.logout,
|
||||||
title: 'Logout',
|
title: context.lang.logout,
|
||||||
subtitle: 'Sign out from your account',
|
subtitle: context.lang.logout_desc,
|
||||||
iconColor: AppColor.error,
|
iconColor: AppColor.error,
|
||||||
textColor: AppColor.error,
|
textColor: AppColor.error,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
import '../../../router/app_router.gr.dart';
|
import '../../../router/app_router.gr.dart';
|
||||||
import 'divider.dart';
|
import 'divider.dart';
|
||||||
@ -30,7 +31,7 @@ class ProfileSupport extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Support',
|
context.lang.support,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -41,8 +42,8 @@ class ProfileSupport extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.help_outline,
|
icon: Icons.help_outline,
|
||||||
title: 'Help Center',
|
title: context.lang.help_center,
|
||||||
subtitle: 'Get help and support',
|
subtitle: context.lang.help_center_desc,
|
||||||
onTap: () => context.router.push(ComingSoonRoute()),
|
onTap: () => context.router.push(ComingSoonRoute()),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -60,8 +61,8 @@ class ProfileSupport extends StatelessWidget {
|
|||||||
|
|
||||||
ProfileTile(
|
ProfileTile(
|
||||||
icon: Icons.info_outline,
|
icon: Icons.info_outline,
|
||||||
title: 'About',
|
title: context.lang.about,
|
||||||
subtitle: 'App version and information',
|
subtitle: context.lang.about_desc,
|
||||||
onTap: () => context.router.push(AboutAppRoute()),
|
onTap: () => context.router.push(AboutAppRoute()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../components/appbar/appbar.dart';
|
import '../../components/appbar/appbar.dart';
|
||||||
import 'widgets/purchase_tile.dart';
|
import 'widgets/purchase_tile.dart';
|
||||||
@ -93,7 +94,7 @@ class _PurchasePageState extends State<PurchasePage>
|
|||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
|
|
||||||
flexibleSpace: CustomAppBar(title: 'Pembelian'),
|
flexibleSpace: CustomAppBar(title: context.lang.purchase),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Stats Cards
|
// Stats Cards
|
||||||
@ -105,7 +106,7 @@ class _PurchasePageState extends State<PurchasePage>
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PurchaseStatCard(
|
child: PurchaseStatCard(
|
||||||
title: 'Total Pembelian',
|
title: context.lang.total_purchase,
|
||||||
value: 'Rp 8.340.000',
|
value: 'Rp 8.340.000',
|
||||||
icon: LineIcons.shoppingCart,
|
icon: LineIcons.shoppingCart,
|
||||||
iconColor: AppColor.success,
|
iconColor: AppColor.success,
|
||||||
@ -115,8 +116,8 @@ class _PurchasePageState extends State<PurchasePage>
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PurchaseStatCard(
|
child: PurchaseStatCard(
|
||||||
title: 'Pending Order',
|
title: context.lang.pending_order,
|
||||||
value: '3 Orders',
|
value: '3 ${context.lang.orders}',
|
||||||
icon: LineIcons.clock,
|
icon: LineIcons.clock,
|
||||||
iconColor: AppColor.warning,
|
iconColor: AppColor.warning,
|
||||||
cardAnimation: cardAnimation,
|
cardAnimation: cardAnimation,
|
||||||
@ -139,7 +140,7 @@ class _PurchasePageState extends State<PurchasePage>
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Riwayat Pembelian',
|
context.lang.history_purchase,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@ -154,7 +155,7 @@ class _PurchasePageState extends State<PurchasePage>
|
|||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${purchaseData.length} Orders',
|
'${purchaseData.length} ${context.lang.orders}',
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textWhite,
|
color: AppColor.textWhite,
|
||||||
),
|
),
|
||||||
@ -220,20 +221,6 @@ class _PurchasePageState extends State<PurchasePage>
|
|||||||
const SliverToBoxAdapter(child: SizedBox(height: 80)),
|
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
|
|
||||||
class PurchaseTile extends StatelessWidget {
|
class PurchaseTile extends StatelessWidget {
|
||||||
@ -219,7 +220,7 @@ class PurchaseTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
'${purchase['items']} items',
|
'${purchase['items']} ${context.lang.items}',
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.secondary,
|
color: AppColor.secondary,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -241,7 +242,7 @@ class PurchaseTile extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Total Pembelian',
|
context.lang.total_purchase,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import '../../../application/analytic/dashboard_analytic_loader/dashboard_analytic_loader_bloc.dart';
|
import '../../../application/analytic/dashboard_analytic_loader/dashboard_analytic_loader_bloc.dart';
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../../injection.dart';
|
import '../../../injection.dart';
|
||||||
import '../../components/appbar/appbar.dart';
|
import '../../components/appbar/appbar.dart';
|
||||||
import '../../components/button/button.dart';
|
|
||||||
import '../../components/field/date_range_picker_field.dart';
|
import '../../components/field/date_range_picker_field.dart';
|
||||||
import '../../components/spacer/spacer.dart';
|
import '../../components/spacer/spacer.dart';
|
||||||
import 'widgets/payment_method.dart';
|
import 'widgets/payment_method.dart';
|
||||||
@ -117,17 +116,17 @@ class _ReportPageState extends State<ReportPage> with TickerProviderStateMixin {
|
|||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
flexibleSpace: CustomAppBar(
|
flexibleSpace: CustomAppBar(
|
||||||
title: 'Laporan',
|
title: context.lang.report,
|
||||||
isBack: false,
|
isBack: false,
|
||||||
),
|
),
|
||||||
actions: [
|
// actions: [
|
||||||
ActionIconButton(
|
// ActionIconButton(
|
||||||
onTap: () {},
|
// onTap: () {},
|
||||||
icon: LineIcons.download,
|
// icon: LineIcons.download,
|
||||||
),
|
// ),
|
||||||
ActionIconButton(onTap: () {}, icon: LineIcons.filter),
|
// ActionIconButton(onTap: () {}, icon: LineIcons.filter),
|
||||||
SpaceWidth(8),
|
// SpaceWidth(8),
|
||||||
],
|
// ],
|
||||||
),
|
),
|
||||||
|
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Payment Methods',
|
context.lang.payment_methods,
|
||||||
style: AppStyle.xl.copyWith(
|
style: AppStyle.xl.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.textPrimary,
|
color: AppColor.textPrimary,
|
||||||
@ -65,7 +65,7 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'Revenue breakdown by payment method',
|
context.lang.payment_methods_desc,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
),
|
),
|
||||||
@ -80,7 +80,7 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
|
|
||||||
// Payment Method List
|
// Payment Method List
|
||||||
if (paymentMethods.isEmpty)
|
if (paymentMethods.isEmpty)
|
||||||
_buildEmptyState()
|
_buildEmptyState(context)
|
||||||
else
|
else
|
||||||
ListView.separated(
|
ListView.separated(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
@ -190,12 +190,12 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Stats row with better spacing
|
// Stats row with better spacing
|
||||||
_buildStatsSection(method),
|
_buildStatsSection(context, method),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Enhanced progress bar section
|
// 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(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -426,7 +429,7 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Total Revenue',
|
context.lang.total_revenue,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -457,7 +460,7 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Orders',
|
context.lang.orders,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
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(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -488,7 +495,7 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Revenue Share',
|
context.lang.revenue_share,
|
||||||
style: AppStyle.sm.copyWith(
|
style: AppStyle.sm.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -560,11 +567,10 @@ class ReportPaymentMethod extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmptyState() {
|
Widget _buildEmptyState(BuildContext context) {
|
||||||
return EmptyWidget(
|
return EmptyWidget(
|
||||||
title: 'No Payment Methods',
|
title: context.lang.no_payment_methods,
|
||||||
message:
|
message: context.lang.no_payment_methods_desc,
|
||||||
'Payment method data will appear here once transactions are made',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class ReportQuickStats extends StatelessWidget {
|
|||||||
return Transform.scale(
|
return Transform.scale(
|
||||||
scale: value,
|
scale: value,
|
||||||
child: ReportStatTile(
|
child: ReportStatTile(
|
||||||
title: 'Total Orders',
|
title: context.lang.total_orders,
|
||||||
value: overview.totalOrders.toString(),
|
value: overview.totalOrders.toString(),
|
||||||
icon: Icons.receipt_long,
|
icon: Icons.receipt_long,
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
@ -43,7 +43,7 @@ class ReportQuickStats extends StatelessWidget {
|
|||||||
return Transform.scale(
|
return Transform.scale(
|
||||||
scale: value,
|
scale: value,
|
||||||
child: ReportStatTile(
|
child: ReportStatTile(
|
||||||
title: 'Average Order',
|
title: context.lang.average_price,
|
||||||
value: overview.averageOrderValue
|
value: overview.averageOrderValue
|
||||||
.round()
|
.round()
|
||||||
.currencyFormatRp,
|
.currencyFormatRp,
|
||||||
@ -70,7 +70,7 @@ class ReportQuickStats extends StatelessWidget {
|
|||||||
return Transform.scale(
|
return Transform.scale(
|
||||||
scale: value,
|
scale: value,
|
||||||
child: ReportStatTile(
|
child: ReportStatTile(
|
||||||
title: 'Customers',
|
title: context.lang.customer,
|
||||||
value: overview.totalCustomers.toString(),
|
value: overview.totalCustomers.toString(),
|
||||||
icon: Icons.people,
|
icon: Icons.people,
|
||||||
color: AppColor.success,
|
color: AppColor.success,
|
||||||
@ -89,7 +89,8 @@ class ReportQuickStats extends StatelessWidget {
|
|||||||
return Transform.scale(
|
return Transform.scale(
|
||||||
scale: value,
|
scale: value,
|
||||||
child: ReportStatTile(
|
child: ReportStatTile(
|
||||||
title: 'Void + Refund',
|
title:
|
||||||
|
'${context.lang.void_text} + ${context.lang.refund}',
|
||||||
value: (overview.voidedOrders + overview.refundedOrders)
|
value: (overview.voidedOrders + overview.refundedOrders)
|
||||||
.toString(),
|
.toString(),
|
||||||
|
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class ReportRevenueSummary extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SpaceWidth(12),
|
const SpaceWidth(12),
|
||||||
Text(
|
Text(
|
||||||
'Total Pendapatan',
|
context.lang.total_revenue,
|
||||||
style: AppStyle.lg.copyWith(
|
style: AppStyle.lg.copyWith(
|
||||||
color: AppColor.textWhite,
|
color: AppColor.textWhite,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class ReportSales extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Sales Chart',
|
context.lang.sales_chart,
|
||||||
style: AppStyle.xxl.copyWith(
|
style: AppStyle.xxl.copyWith(
|
||||||
color: AppColor.textPrimary,
|
color: AppColor.textPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -46,8 +46,8 @@ class ReportSales extends StatelessWidget {
|
|||||||
const SpaceHeight(4),
|
const SpaceHeight(4),
|
||||||
Text(
|
Text(
|
||||||
salesData.isEmpty
|
salesData.isEmpty
|
||||||
? 'No data available'
|
? context.lang.no_data_available
|
||||||
: '${salesData.length} days overview',
|
: context.lang.total_days_overview(salesData.length),
|
||||||
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
|
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -71,13 +71,13 @@ class ReportSales extends StatelessWidget {
|
|||||||
|
|
||||||
// Sales Summary Cards
|
// Sales Summary Cards
|
||||||
if (salesData.isNotEmpty) ...[
|
if (salesData.isNotEmpty) ...[
|
||||||
_buildSalesSummary(),
|
_buildSalesSummary(context),
|
||||||
const SpaceHeight(20),
|
const SpaceHeight(20),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Chart Container
|
// Chart Container
|
||||||
salesData.isEmpty
|
salesData.isEmpty
|
||||||
? _buildEmptyChart()
|
? _buildEmptyChart(context)
|
||||||
: Container(
|
: Container(
|
||||||
height: 300,
|
height: 300,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
@ -105,14 +105,16 @@ class ReportSales extends StatelessWidget {
|
|||||||
if (salesData.isNotEmpty)
|
if (salesData.isNotEmpty)
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
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 totalSales = salesData.fold<int>(0, (sum, item) => sum + item.sales);
|
||||||
final totalOrders = salesData.fold<int>(
|
final totalOrders = salesData.fold<int>(
|
||||||
0,
|
0,
|
||||||
@ -137,7 +139,7 @@ class ReportSales extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryItem(
|
child: _buildSummaryItem(
|
||||||
'Total Sales',
|
context.lang.total_sales,
|
||||||
totalSales.currencyFormatRp,
|
totalSales.currencyFormatRp,
|
||||||
Icons.attach_money,
|
Icons.attach_money,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
@ -151,7 +153,7 @@ class ReportSales extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryItem(
|
child: _buildSummaryItem(
|
||||||
'Net Sales',
|
context.lang.net_sales,
|
||||||
totalNetSales.currencyFormatRp,
|
totalNetSales.currencyFormatRp,
|
||||||
Icons.trending_up,
|
Icons.trending_up,
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
@ -164,7 +166,7 @@ class ReportSales extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryItem(
|
child: _buildSummaryItem(
|
||||||
'Total Orders',
|
context.lang.total_orders,
|
||||||
totalOrders.toString(),
|
totalOrders.toString(),
|
||||||
Icons.shopping_cart,
|
Icons.shopping_cart,
|
||||||
AppColor.info,
|
AppColor.info,
|
||||||
@ -178,7 +180,7 @@ class ReportSales extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryItem(
|
child: _buildSummaryItem(
|
||||||
'Total Items',
|
context.lang.total_items,
|
||||||
totalItems.toString(),
|
totalItems.toString(),
|
||||||
Icons.inventory,
|
Icons.inventory,
|
||||||
AppColor.warning,
|
AppColor.warning,
|
||||||
@ -204,11 +206,15 @@ class ReportSales extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Icon(icon, size: 16, color: color),
|
Icon(icon, size: 16, color: color),
|
||||||
const SpaceWidth(6),
|
const SpaceWidth(6),
|
||||||
Text(
|
Expanded(
|
||||||
label,
|
child: Text(
|
||||||
style: AppStyle.xs.copyWith(
|
label,
|
||||||
color: AppColor.textSecondary,
|
style: AppStyle.xs.copyWith(
|
||||||
fontWeight: FontWeight.w500,
|
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(
|
return EmptyWidget(
|
||||||
title: 'No Sales Data',
|
title: context.lang.no_sales_data,
|
||||||
message: 'Sales data will appear here once transactions are recorded',
|
message: context.lang.no_sales_data_desc,
|
||||||
emptyIcon: Icons.show_chart,
|
emptyIcon: Icons.show_chart,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Produk Terlaris',
|
context.lang.best_selling_products,
|
||||||
style: AppStyle.xxl.copyWith(
|
style: AppStyle.xxl.copyWith(
|
||||||
color: AppColor.textPrimary,
|
color: AppColor.textPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -42,7 +42,7 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SpaceHeight(4),
|
const SpaceHeight(4),
|
||||||
Text(
|
Text(
|
||||||
'Ranking penjualan tertinggi',
|
context.lang.highest_sales_ranking,
|
||||||
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
|
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -66,7 +66,11 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return _buildEnhancedProductItem(products[index], index + 1);
|
return _buildEnhancedProductItem(
|
||||||
|
context,
|
||||||
|
products[index],
|
||||||
|
index + 1,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
itemCount: products.length,
|
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 isFirst = rank == 1;
|
||||||
final isTopThree = rank <= 3;
|
final isTopThree = rank <= 3;
|
||||||
|
|
||||||
@ -320,7 +328,7 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
const SpaceWidth(3),
|
const SpaceWidth(3),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Revenue',
|
context.lang.revenue,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -364,7 +372,7 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Avg. Price',
|
context.lang.average_price,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -423,7 +431,7 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
const SpaceWidth(3),
|
const SpaceWidth(3),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Sold',
|
context.lang.sold,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -465,7 +473,7 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Orders',
|
context.lang.orders,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: AppColor.textSecondary,
|
color: AppColor.textSecondary,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -543,7 +551,9 @@ class ReportTopProduct extends StatelessWidget {
|
|||||||
const SpaceWidth(5),
|
const SpaceWidth(5),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
isFirst ? 'Best Seller' : 'Top Performer',
|
isFirst
|
||||||
|
? context.lang.best_seller
|
||||||
|
: context.lang.top_performer,
|
||||||
style: AppStyle.xs.copyWith(
|
style: AppStyle.xs.copyWith(
|
||||||
color: isFirst
|
color: isFirst
|
||||||
? AppColor.warning
|
? AppColor.warning
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
floating: false,
|
floating: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Penjualan'),
|
flexibleSpace: CustomAppBar(title: context.lang.sales),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Date Range Header
|
// Date Range Header
|
||||||
@ -138,7 +138,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Summary',
|
context.lang.summary,
|
||||||
style: AppStyle.xxl.copyWith(
|
style: AppStyle.xxl.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.textPrimary,
|
color: AppColor.textPrimary,
|
||||||
@ -177,7 +177,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Daily Breakdown',
|
context.lang.daily_breakdown,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -412,7 +412,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
'Total Sales',
|
context.lang.total_sales,
|
||||||
state.sales.summary.totalSales.currencyFormatRp,
|
state.sales.summary.totalSales.currencyFormatRp,
|
||||||
Icons.trending_up,
|
Icons.trending_up,
|
||||||
AppColor.success,
|
AppColor.success,
|
||||||
@ -422,7 +422,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
SpaceWidth(12),
|
SpaceWidth(12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
'Total Orders',
|
context.lang.total_orders,
|
||||||
state.sales.summary.totalOrders.toString(),
|
state.sales.summary.totalOrders.toString(),
|
||||||
Icons.shopping_cart,
|
Icons.shopping_cart,
|
||||||
AppColor.info,
|
AppColor.info,
|
||||||
@ -446,7 +446,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
'Avg Order Value',
|
context.lang.average_price,
|
||||||
state.sales.summary.averageOrderValue
|
state.sales.summary.averageOrderValue
|
||||||
.round()
|
.round()
|
||||||
.currencyFormatRp,
|
.currencyFormatRp,
|
||||||
@ -458,7 +458,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
SpaceWidth(12),
|
SpaceWidth(12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildSummaryCard(
|
child: _buildSummaryCard(
|
||||||
'Total Items',
|
context.lang.total_items,
|
||||||
state.sales.summary.totalItems.toString(),
|
state.sales.summary.totalItems.toString(),
|
||||||
Icons.inventory,
|
Icons.inventory,
|
||||||
AppColor.primary,
|
AppColor.primary,
|
||||||
@ -530,7 +530,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Net Sales',
|
context.lang.net_sales,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColor.textWhite.withOpacity(0.9),
|
color: AppColor.textWhite.withOpacity(0.9),
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -668,7 +668,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${dailySale.orders} orders',
|
'${dailySale.orders} ${context.lang.orders}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColor.info,
|
color: AppColor.info,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -683,21 +683,21 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildDetailItem(
|
child: _buildDetailItem(
|
||||||
'Items',
|
context.lang.items,
|
||||||
'${dailySale.items}',
|
'${dailySale.items}',
|
||||||
Icons.inventory_2,
|
Icons.inventory_2,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildDetailItem(
|
child: _buildDetailItem(
|
||||||
'Tax',
|
context.lang.tax,
|
||||||
dailySale.tax.currencyFormatRp,
|
dailySale.tax.currencyFormatRp,
|
||||||
Icons.receipt,
|
Icons.receipt,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildDetailItem(
|
child: _buildDetailItem(
|
||||||
'Discount',
|
context.lang.discount,
|
||||||
dailySale.discount.currencyFormatRp,
|
dailySale.discount.currencyFormatRp,
|
||||||
Icons.local_offer,
|
Icons.local_offer,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:table_calendar/table_calendar.dart';
|
import 'package:table_calendar/table_calendar.dart';
|
||||||
|
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
import '../../components/appbar/appbar.dart';
|
import '../../components/appbar/appbar.dart';
|
||||||
|
|
||||||
@ -213,7 +214,7 @@ class _SchedulePageState extends State<SchedulePage>
|
|||||||
floating: false,
|
floating: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: AppColor.primary,
|
backgroundColor: AppColor.primary,
|
||||||
flexibleSpace: CustomAppBar(title: 'Jadwal'),
|
flexibleSpace: CustomAppBar(title: context.lang.schedule),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user