Skip to content

Commit 0d36acd

Browse files
committed
added pop up confirm
1 parent c7de720 commit 0d36acd

File tree

1 file changed

+83
-17
lines changed

1 file changed

+83
-17
lines changed

src/components/VoteCard.tsx

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
"use client";
22

3-
import { useReadContract, useAccount, useSendCalls } from "wagmi";
3+
import { useState } from "react"; // Tambahkan useState
4+
import { useReadContract, useSendCalls } from "wagmi";
45
import { encodeFunctionData } from "viem";
56
import { CONTRACT_ADDRESS, CLASS_VOTE_ABI, BUILDER_CODE_HEX } from "~/app/constants";
7+
import { HowToVote } from "@mui/icons-material"; // Import ikon untuk modal
68

79
export default function VoteCard() {
810
const { sendCalls, isPending } = useSendCalls();
11+
12+
// --- STATE UNTUK MODAL ---
13+
const [isModalOpen, setIsModalOpen] = useState(false);
14+
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
15+
916
const { data: candidates, refetch } = useReadContract({
1017
abi: CLASS_VOTE_ABI, address: CONTRACT_ADDRESS, functionName: "getCandidates",
1118
});
1219

13-
const { data: pollTitle } = useReadContract({
14-
abi: CLASS_VOTE_ABI,
15-
address: CONTRACT_ADDRESS,
16-
functionName: "pollTitle",
17-
});
20+
const { data: pollTitle } = useReadContract({
21+
abi: CLASS_VOTE_ABI, address: CONTRACT_ADDRESS, functionName: "pollTitle",
22+
});
1823

19-
const handleVote = async (index: number) => {
20-
const name = (candidates as any[])?.[index]?.name || "kandidat ini";
21-
if (!confirm(`Apakah Anda yakin memilih ${name}?`)) return;
24+
// 1. Fungsi untuk MEMBUKA Modal
25+
const openModal = (index: number) => {
26+
setSelectedIndex(index);
27+
setIsModalOpen(true);
28+
};
2229

30+
// 2. Fungsi untuk EKSEKUSI Vote (setelah klik "YA" di modal)
31+
const executeVote = async () => {
32+
if (selectedIndex === null) return;
33+
2334
const paymasterUrl = process.env.NEXT_PUBLIC_PAYMASTER_URL;
2435
if (!paymasterUrl) return;
2536

@@ -30,33 +41,88 @@ const { data: pollTitle } = useReadContract({
3041
data: `${encodeFunctionData({
3142
abi: CLASS_VOTE_ABI,
3243
functionName: "vote",
33-
args: [BigInt(index)]
34-
})}${BUILDER_CODE_HEX}` as `0x${string}`, // Gabungkan Builder Code
44+
args: [BigInt(selectedIndex)]
45+
})}${BUILDER_CODE_HEX}` as `0x${string}`,
3546
}],
3647
capabilities: { paymasterService: { url: paymasterUrl } }
3748
});
38-
alert("Suara terkirim!");
49+
50+
setIsModalOpen(false); // Tutup modal
51+
alert("Suara sedang diproses secara gasless!");
3952
setTimeout(() => refetch(), 3000);
40-
} catch (e) { alert("Gagal voting."); }
53+
} catch (e) {
54+
alert("Gagal voting.");
55+
setIsModalOpen(false);
56+
}
4157
};
4258

4359
if (!candidates || (candidates as any).length === 0) return null;
4460

61+
const selectedName = selectedIndex !== null ? (candidates as any[])[selectedIndex]?.name : "";
62+
4563
return (
4664
<div className="space-y-4">
4765
<h2 className="text-xl font-black text-center text-blue-600 mb-6 uppercase tracking-tight">
48-
{pollTitle as string || "MEMUAT JUDUL..."}
49-
</h2>
66+
{pollTitle as string || "MEMUAT JUDUL..."}
67+
</h2>
68+
69+
{/* DAFTAR KANDIDAT */}
5070
{(candidates as any[]).map((c, i) => (
5171
<div key={i} className="bg-white p-4 rounded-[28px] border flex items-center gap-4 shadow-sm">
5272
<img src={c.photoUrl || "https://via.placeholder.com/150"} className="w-20 h-20 rounded-2xl object-cover border" alt={c.name} />
53-
<div className="flex-1"><h3 className="font-black text-gray-800 text-lg">{c.name}</h3></div>
54-
<button onClick={() => handleVote(i)} disabled={isPending} className="px-6 py-3 bg-blue-600 text-white rounded-2xl font-black text-xs">
73+
<div className="flex-1">
74+
<h3 className="font-black text-gray-800 text-lg uppercase tracking-tight">{c.name}</h3>
75+
</div>
76+
<button
77+
onClick={() => openModal(i)} // Panggil openModal
78+
disabled={isPending}
79+
className="px-6 py-3 bg-blue-600 text-white rounded-2xl font-black text-xs active:scale-95 transition-transform"
80+
>
5581
{isPending ? "..." : "PILIH"}
5682
</button>
5783
</div>
5884
))}
85+
5986
<p className="text-center text-[9px] text-gray-400 font-bold uppercase py-4 tracking-widest">Biaya Gas ditanggung Sekolah (Paymaster)</p>
87+
88+
{/* --- MODAL KONFIRMASI TENGAH LAYAR --- */}
89+
{isModalOpen && (
90+
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
91+
{/* Latar Belakang Gelap (Overlay) */}
92+
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={() => setIsModalOpen(false)} />
93+
94+
{/* Kotak Modal */}
95+
<div className="relative bg-white dark:bg-zinc-900 w-full max-w-sm rounded-[32px] p-8 shadow-2xl animate-in zoom-in duration-300">
96+
<div className="text-center">
97+
<div className="w-16 h-16 bg-blue-50 dark:bg-blue-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
98+
<HowToVote className="text-blue-600" fontSize="large" />
99+
</div>
100+
101+
<h3 className="text-xl font-black text-zinc-900 dark:text-white uppercase tracking-tighter">Konfirmasi</h3>
102+
<p className="mt-2 text-sm text-zinc-500 font-medium">
103+
Apakah Anda yakin ingin memilih <br/>
104+
<span className="font-black text-blue-600 text-lg">"{selectedName}"</span>?
105+
</p>
106+
</div>
107+
108+
<div className="flex flex-col gap-3 mt-8">
109+
<button
110+
onClick={executeVote}
111+
className="w-full py-4 bg-blue-600 text-white rounded-2xl font-black text-sm active:scale-95 transition-transform shadow-lg shadow-blue-200"
112+
>
113+
YA, SAYA YAKIN
114+
</button>
115+
116+
<button
117+
onClick={() => setIsModalOpen(false)}
118+
className="w-full py-4 bg-zinc-100 dark:bg-zinc-800 text-zinc-500 rounded-2xl font-bold text-sm"
119+
>
120+
BATAL
121+
</button>
122+
</div>
123+
</div>
124+
</div>
125+
)}
60126
</div>
61127
);
62128
}

0 commit comments

Comments
 (0)