https://rega-softwareone.blogspot.com/2025/08/jastip-jus-sehat-di-kantin-smkn-1.html



 import 'package:flutter/material.dart';

import 'dart:html' as html; // khusus Flutter Web untuk buka link


void main() {

  runApp(const MyApp());

}


class MyApp extends StatelessWidget {

  const MyApp({super.key});


  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      title: 'Pesanan Online Kantin via anak rpl',

      debugShowCheckedModeBanner: false,

      theme: ThemeData(

        colorSchemeSeed: Colors.teal,

        useMaterial3: true,

      ),

      home: const MenuPage(),

    );

  }

}


class MenuPage extends StatefulWidget {

  const MenuPage({super.key});


  @override

  State<MenuPage> createState() => _MenuPageState();

}


class _MenuPageState extends State<MenuPage> {

  final List<Map<String, dynamic>> menuItems = [

    {"nama": "jus alpuket", "harga": 5000, "gambar": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRWWv1iXMc3SyUyOfS9UlakkjXOrKMWAHEXvA&s.jpg"},

    {"nama": "jus jeruk", "harga": 5000, "gambar": "https://cdn.antaranews.com/cache/1200x800/2019/11/27/buah_1.jpg"},

    {"nama": "jus jambu", "harga": 1000, "gambar": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtHxrk0GtXAZx_555As_7u03mhE9S4tbP86Q&s.jpg"},

  ];


  final List<Map<String, dynamic>> keranjang = [];


  void tambahKeKeranjang(Map<String, dynamic> item) {

    setState(() {

      keranjang.add(item);

    });

    ScaffoldMessenger.of(context).showSnackBar(

      SnackBar(

        content: Text("${item['nama']} ditambahkan ke keranjang"),

        behavior: SnackBarBehavior.floating,

        backgroundColor: Colors.teal,

      ),

    );

  }


  void hapusDariKeranjang(int index) {

    setState(() {

      keranjang.removeAt(index);

    });

  }


  int get totalBayar =>

      keranjang.fold(0, (sum, item) => sum + (item['harga'] as int));


  void kirimPesanWhatsApp() {

    const String nomor = "6282228672037"; // nomor penjual WA

    final String daftarPesanan = keranjang.map((item) {

      return "- ${item['nama']} (Rp${item['harga']})";

    }).join("\n");


    final String total = "Total Bayar: Rp$totalBayar";

    final String pesan = "Halo, saya ingin memesan:\n$daftarPesanan\n$total";


    final String encodedPesan = Uri.encodeComponent(pesan);

    final String url = "https://wa.me/$nomor?text=$encodedPesan";


    // buka WhatsApp Web di tab baru

    html.window.open(url, "_blank");

  }


  void bukaKeranjang() {

    showModalBottomSheet(

      context: context,

      isScrollControlled: true,

      backgroundColor: Colors.white,

      shape: const RoundedRectangleBorder(

        borderRadius: BorderRadius.vertical(top: Radius.circular(24)),

      ),

      builder: (context) => DraggableScrollableSheet(

        expand: false,

        initialChildSize: 0.7,

        builder: (context, scrollController) => Padding(

          padding: const EdgeInsets.all(16),

          child: Column(

            children: [

              Container(

                width: 50,

                height: 5,

                margin: const EdgeInsets.only(bottom: 12),

                decoration: BoxDecoration(

                  color: Colors.grey[400],

                  borderRadius: BorderRadius.circular(10),

                ),

              ),

              const Text(

                "Keranjang Pesanan",

                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),

              ),

              const Divider(),

              Expanded(

                child: keranjang.isEmpty

                    ? const Center(child: Text("Keranjang masih kosong."))

                    : ListView.builder(

                        controller: scrollController,

                        itemCount: keranjang.length,

                        itemBuilder: (context, index) {

                          final item = keranjang[index];

                          return Card(

                            margin: const EdgeInsets.symmetric(vertical: 6),

                            shape: RoundedRectangleBorder(

                                borderRadius: BorderRadius.circular(12)),

                            child: ListTile(

                              leading: ClipRRect(

                                borderRadius: BorderRadius.circular(8),

                                child: Image.network(

                                  item['gambar'],

                                  width: 50,

                                  height: 50,

                                  fit: BoxFit.cover,

                                ),

                              ),

                              title: Text(item['nama']),

                              subtitle: Text("Rp${item['harga']}"),

                              trailing: IconButton(

                                icon: const Icon(Icons.delete,

                                    color: Colors.redAccent),

                                onPressed: () => hapusDariKeranjang(index),

                              ),

                            ),

                          );

                        },

                      ),

              ),

              const Divider(),

              Row(

                mainAxisAlignment: MainAxisAlignment.spaceBetween,

                children: [

                  Text(

                    "Total: Rp$totalBayar",

                    style: const TextStyle(

                        fontSize: 18, fontWeight: FontWeight.bold),

                  ),

                  FilledButton.icon(

                    onPressed: keranjang.isEmpty

                        ? null

                        : () {

                            Navigator.pop(context);

                            kirimPesanWhatsApp();

                          },

                    icon: const Icon(Icons.send),

                    label: const Text("Pesan via WhatsApp"),

                  ),

                ],

              ),

            ],

          ),

        ),

      ),

    );

  }


  @override

  Widget build(BuildContext context) {

    return Scaffold(

      backgroundColor: Colors.grey[100],

      appBar: AppBar(

        title: const Text("Pesanan Online Kantin"),

        backgroundColor: Colors.teal,

        foregroundColor: Colors.white,

        elevation: 2,

        shape: const RoundedRectangleBorder(

          borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)),

        ),

        actions: [

          Stack(

            children: [

              IconButton(

                icon: const Icon(Icons.shopping_cart),

                onPressed: bukaKeranjang,

              ),

              if (keranjang.isNotEmpty)

                Positioned(

                  right: 8,

                  top: 8,

                  child: Container(

                    padding: const EdgeInsets.all(4),

                    decoration: const BoxDecoration(

                      color: Colors.red,

                      shape: BoxShape.circle,

                    ),

                    child: Text(

                      "${keranjang.length}",

                      style: const TextStyle(

                          color: Colors.white,

                          fontSize: 12,

                          fontWeight: FontWeight.bold),

                    ),

                  ),

                )

            ],

          )

        ],

      ),

      body: ListView.builder(

        padding: const EdgeInsets.all(12),

        itemCount: menuItems.length,

        itemBuilder: (context, index) {

          final item = menuItems[index];

          return Card(

            margin: const EdgeInsets.symmetric(vertical: 8),

            elevation: 3,

            shape: RoundedRectangleBorder(

              borderRadius: BorderRadius.circular(16),

            ),

            child: Padding(

              padding: const EdgeInsets.all(12),

              child: Row(

                children: [

                  ClipRRect(

                    borderRadius: BorderRadius.circular(12),

                    child: Image.network(

                      item['gambar'],

                      width: 70,

                      height: 70,

                      fit: BoxFit.cover,

                    ),

                  ),

                  const SizedBox(width: 16),

                  Expanded(

                    child: Column(

                      crossAxisAlignment: CrossAxisAlignment.start,

                      children: [

                        Text(item['nama'],

                            style: const TextStyle(

                                fontSize: 16, fontWeight: FontWeight.bold)),

                        const SizedBox(height: 4),

                        Text("Rp${item['harga']}",

                            style: TextStyle(

                                fontSize: 14,

                                color: Colors.grey[700],

                                fontWeight: FontWeight.w500)),

                      ],

                    ),

                  ),

                  FilledButton(

                    style: FilledButton.styleFrom(

                      padding: const EdgeInsets.symmetric(

                          horizontal: 16, vertical: 12),

                      shape: RoundedRectangleBorder(

                          borderRadius: BorderRadius.circular(12)),

                    ),

                    onPressed: () => tambahKeKeranjang(item),

                    child: const Text("Tambah"),

                  ),

                ],

              ),

            ),

          );

        },

      ),

    );

  }

}

Komentar

Postingan populer dari blog ini

Pengembangan Aplikasi Pemesanan Makanan “Kantin baso ikan ” Berbasis Flutter dengan Fitur Keranjang dan Integrasi WhatsApp

Pitch Deck: Marketplace Produk Siswa (SMK)

MEMBUAT CRUD dan MockAPI