369 lines
9.2 KiB
Dart
369 lines
9.2 KiB
Dart
// Models
|
||||
|
|
//
|
|||
|
|
// EnakShop adalah toko online. Tahap ini baru katalog; keranjang dan checkout
|
|||
|
|
// menyusul setelah API toko tersedia.
|
|||
|
|
enum ShopCategory {
|
|||
|
|
frozen('Makanan Beku', '🥟'),
|
|||
|
|
sauce('Sambal & Bumbu', '🌶️'),
|
|||
|
|
coffee('Kopi & Minuman', '☕'),
|
|||
|
|
noodle('Mie & Ramen', '🍜'),
|
|||
|
|
snack('Camilan', '🍪'),
|
|||
|
|
merch('Merchandise', '🛍️'),
|
|||
|
|
hampers('Hampers', '🎁');
|
|||
|
|
|
|||
|
|
const ShopCategory(this.label, this.emoji);
|
|||
|
|
|
|||
|
|
final String label;
|
|||
|
|
final String emoji;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Label pojok kartu produk.
|
|||
|
|
enum ShopTag {
|
|||
|
|
bestSeller('Terlaris'),
|
|||
|
|
newArrival('Baru');
|
|||
|
|
|
|||
|
|
const ShopTag(this.label);
|
|||
|
|
|
|||
|
|
final String label;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class ShopProduct {
|
|||
|
|
final String id;
|
|||
|
|
final String name;
|
|||
|
|
final ShopCategory category;
|
|||
|
|
final int price;
|
|||
|
|
|
|||
|
|
/// Harga setelah diskon; `null` bila tidak sedang diskon.
|
|||
|
|
final int? discountPrice;
|
|||
|
|
final String emoji;
|
|||
|
|
|
|||
|
|
/// Warna latar gambar produk, ARGB.
|
|||
|
|
final int tint;
|
|||
|
|
|
|||
|
|
/// Berat atau isi, mis. "500 g" atau "Isi 25 butir".
|
|||
|
|
final String unit;
|
|||
|
|
final String description;
|
|||
|
|
|
|||
|
|
/// Judul pilihan varian, mis. "Ukuran" atau "Level pedas".
|
|||
|
|
final String variantLabel;
|
|||
|
|
final List<String> variants;
|
|||
|
|
final int soldCount;
|
|||
|
|
final int stock;
|
|||
|
|
final ShopTag? tag;
|
|||
|
|
final DateTime addedAt;
|
|||
|
|
|
|||
|
|
const ShopProduct({
|
|||
|
|
required this.id,
|
|||
|
|
required this.name,
|
|||
|
|
required this.category,
|
|||
|
|
required this.price,
|
|||
|
|
required this.emoji,
|
|||
|
|
required this.tint,
|
|||
|
|
required this.unit,
|
|||
|
|
required this.description,
|
|||
|
|
required this.soldCount,
|
|||
|
|
required this.stock,
|
|||
|
|
required this.addedAt,
|
|||
|
|
this.discountPrice,
|
|||
|
|
this.variantLabel = 'Varian',
|
|||
|
|
this.variants = const [],
|
|||
|
|
this.tag,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
bool get isDiscounted => discountPrice != null;
|
|||
|
|
|
|||
|
|
int get finalPrice => discountPrice ?? price;
|
|||
|
|
|
|||
|
|
/// Persen potongan, dibulatkan.
|
|||
|
|
int get discountPercent =>
|
|||
|
|
isDiscounted ? ((price - discountPrice!) * 100 / price).round() : 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Banner promo di beranda toko; mengarah ke satu kategori.
|
|||
|
|
class ShopPromo {
|
|||
|
|
final String id;
|
|||
|
|
final String title;
|
|||
|
|
final String subtitle;
|
|||
|
|
final ShopCategory category;
|
|||
|
|
|
|||
|
|
/// Warna gradasi banner, ARGB.
|
|||
|
|
final List<int> gradient;
|
|||
|
|
|
|||
|
|
const ShopPromo({
|
|||
|
|
required this.id,
|
|||
|
|
required this.title,
|
|||
|
|
required this.subtitle,
|
|||
|
|
required this.category,
|
|||
|
|
required this.gradient,
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Sample Data
|
|||
|
|
DateTime _daysAgo(int days) => DateTime.now().subtract(Duration(days: days));
|
|||
|
|
|
|||
|
|
/// Getter, bukan `final`, supaya perubahan data langsung terbaca saat hot
|
|||
|
|
/// reload (variabel global yang sudah terisi tidak diisi ulang).
|
|||
|
|
List<ShopPromo> get shopPromoSamples => const [
|
|||
|
|
ShopPromo(
|
|||
|
|
id: 'sp1',
|
|||
|
|
title: 'Diskon s.d. 20% Makanan Beku',
|
|||
|
|
subtitle: 'Stok bakso & dimsum di rumah',
|
|||
|
|
category: ShopCategory.frozen,
|
|||
|
|
gradient: [0xFFD90000, 0xFF990000],
|
|||
|
|
),
|
|||
|
|
ShopPromo(
|
|||
|
|
id: 'sp2',
|
|||
|
|
title: 'Hampers Mulai Rp 299 Ribu',
|
|||
|
|
subtitle: 'Kirim rasa Nusantara untuk orang tersayang',
|
|||
|
|
category: ShopCategory.hampers,
|
|||
|
|
gradient: [0xFF43A047, 0xFF1B5E20],
|
|||
|
|
),
|
|||
|
|
ShopPromo(
|
|||
|
|
id: 'sp3',
|
|||
|
|
title: 'Merchandise Diskon s.d. 15%',
|
|||
|
|
subtitle: 'Tumbler, kaos, dan tote bag Enaklo',
|
|||
|
|
category: ShopCategory.merch,
|
|||
|
|
gradient: [0xFFF59E0B, 0xFFC2410C],
|
|||
|
|
),
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
List<ShopProduct> get shopSamples => [
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's1',
|
|||
|
|
name: 'Bakso Sapi Frozen Bakso 343',
|
|||
|
|
category: ShopCategory.frozen,
|
|||
|
|
price: 65000,
|
|||
|
|
discountPrice: 52000,
|
|||
|
|
emoji: '🍲',
|
|||
|
|
tint: 0xFFF6D5D0,
|
|||
|
|
unit: 'Isi 25 butir',
|
|||
|
|
variantLabel: 'Ukuran',
|
|||
|
|
variants: ['Isi 25 butir', 'Isi 50 butir'],
|
|||
|
|
description:
|
|||
|
|
'Bakso sapi resep Bakso 343, dibekukan segera setelah dibuat. Cukup '
|
|||
|
|
'rebus 5 menit. Tahan 3 bulan di freezer.',
|
|||
|
|
soldCount: 320,
|
|||
|
|
stock: 48,
|
|||
|
|
tag: ShopTag.bestSeller,
|
|||
|
|
addedAt: _daysAgo(60),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's2',
|
|||
|
|
name: 'Dimsum Ayam Frozen',
|
|||
|
|
category: ShopCategory.frozen,
|
|||
|
|
price: 48000,
|
|||
|
|
emoji: '🥟',
|
|||
|
|
tint: 0xFFF3E6CF,
|
|||
|
|
unit: 'Isi 20 pcs',
|
|||
|
|
description:
|
|||
|
|
'Dimsum ayam udang dengan kulit tipis. Kukus 10 menit dari beku, '
|
|||
|
|
'sajikan dengan sambal.',
|
|||
|
|
soldCount: 85,
|
|||
|
|
stock: 30,
|
|||
|
|
tag: ShopTag.newArrival,
|
|||
|
|
addedAt: _daysAgo(5),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's3',
|
|||
|
|
name: 'Sambal Woku Pedas',
|
|||
|
|
category: ShopCategory.sauce,
|
|||
|
|
price: 35000,
|
|||
|
|
discountPrice: 29000,
|
|||
|
|
emoji: '🌶️',
|
|||
|
|
tint: 0xFFFBDCC8,
|
|||
|
|
unit: '200 g',
|
|||
|
|
variantLabel: 'Level pedas',
|
|||
|
|
variants: ['Level 2', 'Level 3', 'Level 5'],
|
|||
|
|
description:
|
|||
|
|
'Sambal khas Woku Pedas dengan cabai, kemangi, dan rempah Manado. '
|
|||
|
|
'Tanpa pengawet, simpan di kulkas setelah dibuka.',
|
|||
|
|
soldCount: 540,
|
|||
|
|
stock: 120,
|
|||
|
|
tag: ShopTag.bestSeller,
|
|||
|
|
addedAt: _daysAgo(90),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's4',
|
|||
|
|
name: 'Bumbu Rica-Rica Instan',
|
|||
|
|
category: ShopCategory.sauce,
|
|||
|
|
price: 18000,
|
|||
|
|
emoji: '🧂',
|
|||
|
|
tint: 0xFFF7E2C8,
|
|||
|
|
unit: '100 g',
|
|||
|
|
description:
|
|||
|
|
'Bumbu rica-rica siap pakai untuk 1 kg ayam atau ikan. Tinggal tumis '
|
|||
|
|
'dan masak bersama bahan utama.',
|
|||
|
|
soldCount: 140,
|
|||
|
|
stock: 75,
|
|||
|
|
addedAt: _daysAgo(40),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's5',
|
|||
|
|
name: 'Kopi Tumulu House Blend',
|
|||
|
|
category: ShopCategory.coffee,
|
|||
|
|
price: 85000,
|
|||
|
|
emoji: '☕',
|
|||
|
|
tint: 0xFFE8DCCF,
|
|||
|
|
unit: '250 g',
|
|||
|
|
variantLabel: 'Gilingan',
|
|||
|
|
variants: ['Biji utuh', 'Bubuk halus', 'Bubuk kasar'],
|
|||
|
|
description:
|
|||
|
|
'Campuran arabika Gayo dan robusta Temanggung yang dipakai di Tumulu '
|
|||
|
|
'Coffee. Cocok untuk kopi susu maupun kopi tubruk.',
|
|||
|
|
soldCount: 410,
|
|||
|
|
stock: 64,
|
|||
|
|
tag: ShopTag.bestSeller,
|
|||
|
|
addedAt: _daysAgo(120),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's6',
|
|||
|
|
name: 'Cold Brew Tumulu 1 Liter',
|
|||
|
|
category: ShopCategory.coffee,
|
|||
|
|
price: 75000,
|
|||
|
|
discountPrice: 65000,
|
|||
|
|
emoji: '🧋',
|
|||
|
|
tint: 0xFFE2D6CC,
|
|||
|
|
unit: '1 liter',
|
|||
|
|
description:
|
|||
|
|
'Kopi seduh dingin 18 jam, tinggal tuang ke es dan susu. Simpan di '
|
|||
|
|
'kulkas, habiskan dalam 7 hari.',
|
|||
|
|
soldCount: 95,
|
|||
|
|
stock: 20,
|
|||
|
|
addedAt: _daysAgo(20),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's7',
|
|||
|
|
name: 'Ramen Kit Shoyu Ramenmulu',
|
|||
|
|
category: ShopCategory.noodle,
|
|||
|
|
price: 79000,
|
|||
|
|
discountPrice: 69000,
|
|||
|
|
emoji: '🍜',
|
|||
|
|
tint: 0xFFF5E1C8,
|
|||
|
|
unit: '2 porsi',
|
|||
|
|
description:
|
|||
|
|
'Mie ramen segar, kuah shoyu pekat, chashu, dan telur ajitama untuk '
|
|||
|
|
'2 porsi. Siap dalam 10 menit.',
|
|||
|
|
soldCount: 150,
|
|||
|
|
stock: 18,
|
|||
|
|
tag: ShopTag.newArrival,
|
|||
|
|
addedAt: _daysAgo(3),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's8',
|
|||
|
|
name: 'Mie Ramen Kering',
|
|||
|
|
category: ShopCategory.noodle,
|
|||
|
|
price: 32000,
|
|||
|
|
emoji: '🍝',
|
|||
|
|
tint: 0xFFF4EBD3,
|
|||
|
|
unit: '500 g',
|
|||
|
|
description:
|
|||
|
|
'Mie ramen kering untuk 5 porsi, kenyal seperti mie segar. Rebus '
|
|||
|
|
'3 menit.',
|
|||
|
|
soldCount: 60,
|
|||
|
|
stock: 90,
|
|||
|
|
addedAt: _daysAgo(30),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's9',
|
|||
|
|
name: 'Keripik Kulit Ikan Pedas',
|
|||
|
|
category: ShopCategory.snack,
|
|||
|
|
price: 28000,
|
|||
|
|
emoji: '🍘',
|
|||
|
|
tint: 0xFFF6E7C1,
|
|||
|
|
unit: '100 g',
|
|||
|
|
description:
|
|||
|
|
'Keripik kulit ikan renyah dengan bumbu woku pedas. Camilan pas '
|
|||
|
|
'teman nonton.',
|
|||
|
|
soldCount: 210,
|
|||
|
|
stock: 55,
|
|||
|
|
addedAt: _daysAgo(50),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's10',
|
|||
|
|
name: 'Nastar Keju Premium',
|
|||
|
|
category: ShopCategory.snack,
|
|||
|
|
price: 95000,
|
|||
|
|
discountPrice: 85000,
|
|||
|
|
emoji: '🍪',
|
|||
|
|
tint: 0xFFF7E4B5,
|
|||
|
|
unit: 'Toples 500 g',
|
|||
|
|
description:
|
|||
|
|
'Nastar selai nanas homemade dengan taburan keju edam. Tahan 1 bulan '
|
|||
|
|
'dalam toples tertutup.',
|
|||
|
|
soldCount: 130,
|
|||
|
|
stock: 25,
|
|||
|
|
addedAt: _daysAgo(15),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's11',
|
|||
|
|
name: 'Tumbler Enaklo 500 ml',
|
|||
|
|
category: ShopCategory.merch,
|
|||
|
|
price: 129000,
|
|||
|
|
emoji: '🥤',
|
|||
|
|
tint: 0xFFF3D3D3,
|
|||
|
|
unit: '500 ml',
|
|||
|
|
variantLabel: 'Warna',
|
|||
|
|
variants: ['Merah', 'Hitam', 'Krem'],
|
|||
|
|
description:
|
|||
|
|
'Tumbler stainless dua lapis yang menjaga minuman tetap dingin sampai '
|
|||
|
|
'12 jam. Tutup anti tumpah.',
|
|||
|
|
soldCount: 75,
|
|||
|
|
stock: 40,
|
|||
|
|
tag: ShopTag.bestSeller,
|
|||
|
|
addedAt: _daysAgo(70),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's12',
|
|||
|
|
name: 'Kaos "Enak Lho!"',
|
|||
|
|
category: ShopCategory.merch,
|
|||
|
|
price: 119000,
|
|||
|
|
emoji: '👕',
|
|||
|
|
tint: 0xFFE9E9E9,
|
|||
|
|
unit: 'Katun combed 30s',
|
|||
|
|
variantLabel: 'Ukuran',
|
|||
|
|
variants: ['S', 'M', 'L', 'XL'],
|
|||
|
|
description:
|
|||
|
|
'Kaos katun yang adem dipakai seharian, dengan sablon "Enak Lho!" di '
|
|||
|
|
'bagian depan.',
|
|||
|
|
soldCount: 48,
|
|||
|
|
stock: 32,
|
|||
|
|
addedAt: _daysAgo(35),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's13',
|
|||
|
|
name: 'Tote Bag Kanvas Enaklo',
|
|||
|
|
category: ShopCategory.merch,
|
|||
|
|
price: 90000,
|
|||
|
|
discountPrice: 76500,
|
|||
|
|
emoji: '🛍️',
|
|||
|
|
tint: 0xFFEDE3CF,
|
|||
|
|
unit: '38 × 42 cm',
|
|||
|
|
variantLabel: 'Warna',
|
|||
|
|
variants: ['Natural', 'Hitam'],
|
|||
|
|
description:
|
|||
|
|
'Tote bag kanvas tebal dengan kantong dalam. Cukup untuk laptop 14 '
|
|||
|
|
'inci.',
|
|||
|
|
soldCount: 66,
|
|||
|
|
stock: 3,
|
|||
|
|
tag: ShopTag.newArrival,
|
|||
|
|
addedAt: _daysAgo(8),
|
|||
|
|
),
|
|||
|
|
ShopProduct(
|
|||
|
|
id: 's14',
|
|||
|
|
name: 'Hampers Rasa Nusantara',
|
|||
|
|
category: ShopCategory.hampers,
|
|||
|
|
price: 350000,
|
|||
|
|
discountPrice: 299000,
|
|||
|
|
emoji: '🎁',
|
|||
|
|
tint: 0xFFDCEBD6,
|
|||
|
|
unit: 'Isi 5 produk',
|
|||
|
|
description:
|
|||
|
|
'Sambal Woku Pedas, Kopi Tumulu House Blend, Nastar Keju Premium, '
|
|||
|
|
'Keripik Kulit Ikan Pedas, dan kartu ucapan dalam kotak kayu.',
|
|||
|
|
soldCount: 34,
|
|||
|
|
stock: 12,
|
|||
|
|
tag: ShopTag.newArrival,
|
|||
|
|
addedAt: _daysAgo(6),
|
|||
|
|
),
|
|||
|
|
];
|