NFT FOR RETURNED SKATE
We don't belong in your reality, your real life. In your reality, your real life, you can merely meet our avatars in any version. So, stay alert and beware of scams!
title: "NFT Claim System — Prof. NOTA Inc. Skateboards"
author: "Prof. NOTA Inc."
version: "v1.0"
date: "2025-06-24"
🛹 NFT Claim System for Returned Skateboards
🎯 TUJUAN UTAMA
Menghadirkan sistem NFT berbasis Web3 yang menghargai pengguna skateboard Prof. NOTA Inc. yang telah mengembalikan produk rusak atau tidak terpakai. NFT tidak diberikan saat pembelian, melainkan saat pengguna mengembalikan skateboard bekas kepada Prof. NOTA Inc., sebagai bentuk:
Kepedulian lingkungan
Pelestarian sejarah pemakaian
Kontribusi komunitas
🧠 KONSEP DASAR
NFT bukan bukti pembelian, tetapi bukti pengembalian sadar.
Setiap design skateboard memiliki satu token ID NFT.
NFT diberikan setelah deck fisik diterima oleh Prof. NOTA Inc.
Deck yang dikembalikan akan didokumentasikan, dipamerkan, atau digunakan kembali untuk proyek keberlanjutan.
💡 SKENARIO SINGKAT
Siapapun boleh membeli skateboard deck Prof. NOTA Inc. dari manapun.
Jika deck rusak/tidak terpakai → jangan dibuang.
Pemilik mengakses situs:
https://notaskateboards.com/returIsi form dan upload foto → sistem verifikasi manual
Jika valid → pemilik mengirimkan deck ke alamat yang ditentukan
Setelah diterima → NFT dikirim ke wallet pemilik
📦 ARSITEKTUR SISTEM
1. Frontend: Web Form Pengguna
URL:
/returDibangun dengan:
Next.js 15+Tailwind CSSForm input:
Nama lengkap
Email
Alamat Wallet (atau tombol Connect Wallet)
Upload foto skateboard rusak
Pilih desain (dropdown / upload bukti pembelian opsional)
Checklist: “Saya akan mengirim skateboard ini ke alamat Prof. NOTA Inc.”
2. Backend: Sistem Verifikasi & Minting NFT
Dibangun dengan:
Node.js / ExpressDatabase:
MongoDBFitur utama:
Verifikasi manual submission (dashboard internal)
Tandai status (valid / ditolak / pending)
Endpoint minting NFT dengan ThirdWeb SDK
claimWithSignatureataumintTo
3. Smart Contract NFT
Standar: ERC-1155 (tiap desain = token ID)
Diterapkan dengan ThirdWeb Signature Drop
Metadata NFT:
{ "name": "Returned Deck — Phoenix Flame", "description": "You've sent back a used Prof. NOTA Inc. skateboard. This NFT is proof of your journey.", "image": "ipfs://...", "attributes": [ { "trait_type": "Design", "value": "Phoenix Flame" }, { "trait_type": "Claim Date", "value": "2025-06-24" }, { "trait_type": "Condition", "value": "Used" }, { "trait_type": "Return Verified", "value": true } ] }
🔐 STRATEGI ANTI-PENYALAHGUNAAN
Klaim palsu (tidak benar-benar punya deck)
Upload foto, verifikasi manual oleh tim Prof. NOTA
Orang minta NFT tanpa mengirim fisik
NFT hanya dikirim setelah barang diterima dan diperiksa
Spam submission
Rate limiting, CAPTCHA, validasi email
Klaim ganda
Batasi satu NFT per wallet per design / serial / bukti unik
Deck tiruan
Validasi visual, optional QR/sticker atau nomor produksi internal
🛠️ FILE STRUKTUR PROYEK
src/
├── app/
│ └── retur/
│ └── page.tsx # Halaman form pengguna
├── components/
│ ├── ReturForm.tsx # Komponen form utama
│ └── ReturStatus.tsx # Status tracking
├── lib/
│ └── mintNFT.ts # Logika backend mint NFT
├── pages/api/
│ └── retur.ts # Handler API form submission
│ └── verify.ts # Endpoint admin approval💌 ALUR LOGISTIK DAN OPERASIONAL
Pengguna isi form dan upload foto deck rusak.
Sistem mencatat submission dan status = “pending”.
Tim Prof. NOTA melakukan verifikasi manual.
Jika valid:
Email/WhatsApp instruksi pengiriman fisik.
Setelah deck diterima → status updated → NFT dikirim.
Jika tidak valid → user diberi alasan penolakan.
🔧 STACK TEKNOLOGI YANG DIGUNAKAN
Frontend
Next.js 15 + Tailwind CSS
Wallet Integration
ThirdWeb Connect (email opsional)
Backend
Node.js + MongoDB
NFT Contract
ERC-1155 via ThirdWeb SDK v5
Hosting
Vercel
API Gateway (opsional)
Express / Next.js API route
🎁 UTILITY DAN VISI NFT
NFT yang didapat oleh pengirim deck bekas bukan hanya simbol, tapi juga bisa memiliki utility tambahan:
Akses diskon pembelian deck generasi berikutnya
Undangan pameran atau event komunitas
Koleksi unik yang akan dimuseumkan secara digital
Voting desain edisi terbatas
NFT sebagai akses token untuk fitur eksklusif (Discord / event)
📣 PESAN KEPADA PENGGUNA
“Jangan dibuang. Kirimkan saja kembali. Kami akan abadikan jejakmu di blockchain.”
– Prof. NOTA Inc. Skateboards, 2025
✅ TAHAP IMPLEMENTASI
Checklist pengerjaan tahap awal:
📬 KONTAK DAN TANGGUNG JAWAB
Inisiator: Prof. NOTA (v11)
Operasional Teknis: Tim Web3 Prof. NOTA Inc.
Kontak: [email protected]
Versi Dokumen:
v1.0Tanggal Rilis:
2025-06-24
📋 TASK CARD TEKNIS — NFT Claim
🧱 1. FRONTEND – HALAMAN FORM RETUR
Task ID: FE-RETUR-01
Judul: Buat halaman /retur untuk form pengembalian skateboard
Deskripsi:
Form input: Nama, Email, Wallet Address, Foto Skateboard Rusak, Dropdown Desain, Checkbox Komitmen Kirim
Tambahkan integrasi ThirdWeb Connect untuk wallet
Responsive dan minimalis (tailwind-ready)
Dikerjakan oleh: Frontend Developer
Dependency: Desain UI (jika disediakan), komponen ReturForm.tsx
🧩 2. FRONTEND – STATUS SUBMISSION & FEEDBACK
Task ID: FE-RETUR-02 Judul: Tambahkan komponen feedback status Deskripsi:
Setelah form dikirim, tampilkan status:
Pending Review,Approved, atauRejectedBerikan estimasi waktu respon dan link tracking (jika ada)
Dikerjakan oleh: Frontend Developer
Dependency: Backend endpoint /api/retur
🔧 3. BACKEND – FORM HANDLER API
Task ID: BE-RETUR-01 Judul: Buat API handler untuk menyimpan submission form Deskripsi:
Endpoint:
POST /api/returSimpan data ke MongoDB: nama, email, wallet, design, foto URL, status
Validasi minimal: email + foto wajib
Dikerjakan oleh: Backend Developer Dependency: DB setup + image hosting (Cloudinary/IPFS/etc)
🔐 4. BACKEND – DASHBOARD VERIFIKASI
Task ID: BE-ADMIN-01 Judul: Dashboard internal admin untuk approval Deskripsi:
Menampilkan list pengajuan dengan filter status
Tombol: Approve, Reject
Form untuk masukkan nomor resi, catatan, dsb
Dikerjakan oleh: Fullstack Developer Dependency: Login/role management (optional)
✍️ 5. BACKEND – MINT NFT VIA THIRDWEB SDK
Task ID: BE-NFT-01 Judul: Implementasi fungsi mint NFT ke wallet pengguna Deskripsi:
Gunakan
mintToatauclaimWithSignaturedari ThirdWeb SDK v5NFT metadata: nama desain, foto deck, waktu retur
Image dapat diambil dari yang diupload user
Dikerjakan oleh: Web3 Developer Dependency: Smart contract ERC-1155 sudah dideploy
🔗 6. SMART CONTRACT – DEPLOY ERC-1155 UNTUK SETIAP DESAIN
Task ID: SC-DEPLOY-01 Judul: Deploy smart contract NFT ERC-1155 Deskripsi:
1 token ID per desain (misalnya: Phoenix Flame = tokenId
0)Gunakan ThirdWeb dashboard untuk deploy dan setup
Pastikan metadata standar IPFS-ready
Dikerjakan oleh: Smart Contract Engineer / Web3 Dev Dependency: Daftar desain yang tersedia
📁 7. NFT METADATA – TEMPLATE & UPLOAD IPFS
Task ID: META-IPFS-01 Judul: Siapkan metadata NFT tiap desain Deskripsi:
Buat template
.jsonmetadataUpload ke IPFS via ThirdWeb Storage atau Pinata
Simpan link metadata per desain/token ID
Dikerjakan oleh: Web3 Support / Admin Teknis Dependency: Asset gambar dan nama desain
📨 8. NOTIFIKASI – EMAIL / WHATSAPP FOLLOW-UP
Task ID: OPS-NOTIF-01 Judul: Kirim notifikasi setelah verifikasi diterima Deskripsi:
Email atau WhatsApp berisi instruksi pengiriman fisik
Tambahkan nomor referensi dan estimasi NFT dikirim
Dikerjakan oleh: Ops/Support Team Dependency: Admin approval + kontak user valid
🧪 9. TESTING – PILOT RETURN 10 DECK PERTAMA
Task ID: TEST-PILOT-01 Judul: Uji coba pengembalian 10 deck dari komunitas Deskripsi:
Rekrut 10 pengguna pertama
Simulasikan seluruh alur dari form → kirim deck → mint NFT
Catat feedback dan perbaikan UX
Dikerjakan oleh: Tim QA / Ops Dependency: Semua task sebelumnya selesai
📢 10. PUBLIKASI – COPYWRITING & LANDING PAGE
Task ID: PUB-CLAIM-01 Judul: Buat copywriting dan halaman informasi untuk user umum Deskripsi:
Narasi: “Kirim kembali, bukan buang.”
Deskripsi langkah-langkah + FAQ
Sertakan CTA ke form
/retur
Dikerjakan oleh: Content Writer + Frontend Dependency: Final sistem siap digunakan
✅ LABEL & PRIORITAS
FE
Frontend
BE
Backend
SC
Smart Contract
META
Metadata NFT
OPS
Operasional & Support
TEST
Testing dan QA
PUB
Publikasi & Edukasi
🎯 Komponen Pertama: ReturForm.tsx
📦 Tujuan
Formulir untuk pengguna yang ingin mengklaim NFT dengan mengembalikan skateboard deck rusak.
🔧 Fitur Form
Input teks: Nama Lengkap, Email
Wallet: Connect Wallet (ThirdWeb Connect)
Dropdown atau input bebas: Nama Desain Deck
Upload: Foto kondisi skateboard (optional preview)
Checkbox: Komitmen kirim deck ke Prof. NOTA Inc.
Submit button → panggil API /api/retur
📁 File: src/components/ReturForm.tsx
Berikut kode awalnya:
"use client";
// External libraries
import { ConnectWallet, useAddress } from "@thirdweb-dev/react";
import { useState } from "react";
export default function ReturForm() {
const walletAddress = useAddress();
const [nama, setNama] = useState("");
const [email, setEmail] = useState("");
const [design, setDesign] = useState("");
const [photo, setPhoto] = useState<File | null>(null);
const [agreed, setAgreed] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [message, setMessage] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!walletAddress || !agreed || !photo) {
setMessage("Lengkapi semua data dan hubungkan wallet Anda.");
return;
}
const formData = new FormData();
formData.append("nama", nama);
formData.append("email", email);
formData.append("wallet", walletAddress);
formData.append("design", design);
formData.append("photo", photo);
setIsSubmitting(true);
try {
const res = await fetch("/api/retur", {
method: "POST",
body: formData,
});
if (res.ok) {
setMessage("Pengajuan berhasil! Tim kami akan menghubungi Anda.");
setNama("");
setEmail("");
setDesign("");
setPhoto(null);
setAgreed(false);
} else {
const data = await res.json();
setMessage(data.error || "Gagal mengirim form.");
}
} catch (err) {
setMessage("Terjadi kesalahan teknis.");
}
setIsSubmitting(false);
};
return (
<div className="max-w-xl mx-auto px-4 py-6">
<h2 className="text-xl font-bold mb-4">Klaim NFT Skateboard Rusak</h2>
<ConnectWallet className="mb-4" />
<form onSubmit={handleSubmit} className="space-y-4">
<input
type="text"
placeholder="Nama Lengkap"
value={nama}
onChange={(e) => setNama(e.target.value)}
className="w-full border px-3 py-2 rounded"
required
/>
<input
type="email"
placeholder="Email Aktif"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full border px-3 py-2 rounded"
required
/>
<input
type="text"
placeholder="Nama Desain Deck (misalnya: Phoenix Flame)"
value={design}
onChange={(e) => setDesign(e.target.value)}
className="w-full border px-3 py-2 rounded"
required
/>
<input
type="file"
accept="image/*"
onChange={(e) => setPhoto(e.target.files?.[0] || null)}
className="w-full border px-3 py-2 rounded"
required
/>
<label className="flex items-start space-x-2">
<input
type="checkbox"
checked={agreed}
onChange={() => setAgreed(!agreed)}
className="mt-1"
required
/>
<span>
Saya bersedia mengirim skateboard saya ke alamat yang akan
diinformasikan oleh Prof. NOTA Inc.
</span>
</label>
<button
type="submit"
disabled={isSubmitting}
className="bg-black text-white px-4 py-2 rounded disabled:opacity-50"
>
{isSubmitting ? "Mengirim..." : "Kirim Formulir"}
</button>
{message && <p className="text-sm mt-2">{message}</p>}
</form>
</div>
);
}
🛠️ API Endpoint: /api/retur.ts
📌 Tujuan
Menerima data dari ReturForm.tsx
Menyimpan data ke database (simulasi: log ke console atau simpan JSON)
Validasi dasar
Siap dikembangkan untuk integrasi MongoDB dan cloud storage (foto)
📁 File: src/pages/api/retur.ts
import { NextApiRequest, NextApiResponse } from "next";
import formidable from "formidable";
import fs from "fs";
import path from "path";
// Jangan parse body secara default
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Metode tidak diizinkan." });
}
const form = formidable({ multiples: false });
form.parse(req, async (err, fields, files) => {
if (err) {
console.error("Gagal parsing form:", err);
return res.status(500).json({ error: "Gagal membaca data formulir." });
}
const { nama, email, wallet, design } = fields;
const photo = files.photo as formidable.File;
if (!nama || !email || !wallet || !design || !photo) {
return res.status(400).json({ error: "Semua field wajib diisi." });
}
// Simulasi penyimpanan (nantinya ke database)
console.log("📦 Data Pengajuan Masuk:");
console.log({
nama,
email,
wallet,
design,
photoPath: photo.filepath,
});
// Simulasi: pindahkan foto ke folder publik sementara
const tempPath = photo.filepath;
const fileName = `${Date.now()}-${photo.originalFilename}`;
const targetPath = path.join(process.cwd(), "public", "uploads", fileName);
try {
fs.copyFileSync(tempPath, targetPath);
} catch (err) {
console.error("Gagal menyimpan file:", err);
return res.status(500).json({ error: "Gagal menyimpan foto." });
}
// Response sukses
return res.status(200).json({ message: "Formulir berhasil dikirim." });
});
}🧪 Notes Teknis
Formidable dipakai untuk handle file upload (multipart/form-data)
File disimpan ke folder public/uploads (sementara, bisa diganti IPFS/Cloudinary)
Validasi sederhana (semua field wajib)
🧾 Komponen: ReturAdmin.tsx
🎯 Tujuan
Menampilkan daftar semua pengajuan dari endpoint backend
Menyediakan tombol Approve dan Reject
Menampilkan informasi pengirim: nama, email, wallet, desain, foto
Saat diklik “Approve” → update status + lanjut ke proses mint NFT (nanti)
📁 File: src/components/ReturAdmin.tsx
"use client";
// External libraries
import { useEffect, useState } from "react";
type ReturItem = {
id: string;
nama: string;
email: string;
wallet: string;
design: string;
photoUrl: string;
status: "pending" | "approved" | "rejected";
};
export default function ReturAdmin() {
const [returs, setReturs] = useState<ReturItem[]>([]);
const [loading, setLoading] = useState(true);
const fetchReturs = async () => {
setLoading(true);
try {
const res = await fetch("/api/admin/retur");
const data = await res.json();
setReturs(data.returs || []);
} catch (err) {
console.error("Gagal mengambil data pengajuan:", err);
} finally {
setLoading(false);
}
};
const updateStatus = async (id: string, status: "approved" | "rejected") => {
try {
const res = await fetch(`/api/admin/retur`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id, status }),
});
if (res.ok) {
fetchReturs();
}
} catch (err) {
console.error("Gagal update status:", err);
}
};
useEffect(() => {
fetchReturs();
}, []);
if (loading) return <p className="text-center">Memuat data...</p>;
return (
<div className="max-w-4xl mx-auto p-4">
<h2 className="text-xl font-bold mb-4">📋 Daftar Pengajuan Retur</h2>
{returs.length === 0 ? (
<p>Belum ada pengajuan.</p>
) : (
<ul className="space-y-4">
{returs.map((item) => (
<li key={item.id} className="border p-4 rounded shadow-sm">
<p><strong>Nama:</strong> {item.nama}</p>
<p><strong>Email:</strong> {item.email}</p>
<p><strong>Wallet:</strong> {item.wallet}</p>
<p><strong>Design:</strong> {item.design}</p>
<p><strong>Status:</strong> {item.status}</p>
<img
src={item.photoUrl}
alt="Foto Skateboard"
className="w-40 mt-2 border rounded"
/>
{item.status === "pending" && (
<div className="mt-4 space-x-2">
<button
onClick={() => updateStatus(item.id, "approved")}
className="bg-green-600 text-white px-4 py-1 rounded"
>
Approve
</button>
<button
onClick={() => updateStatus(item.id, "rejected")}
className="bg-red-600 text-white px-4 py-1 rounded"
>
Reject
</button>
</div>
)}
</li>
))}
</ul>
)}
</div>
);
}🗃️ Endpoint yang perlu tersedia
GET /api/admin/retur → list semua submission
PATCH /api/admin/retur → update status (approved / rejected)
📁 File: src/pages/api/admin/retur.ts
Untuk tahap awal, kita gunakan simulasi penyimpanan data di file JSON lokal, agar tidak tergantung DB dulu. File data/returs.json akan berisi array objek ReturItem.
🗃️ Simulasi struktur file JSON
[
{
"id": "123456789",
"nama": "Andi",
"email": "[email protected]",
"wallet": "0xABC...",
"design": "Phoenix Flame",
"photoUrl": "/uploads/123456.jpg",
"status": "pending"
}
]🧠 Handler: api/admin/retur.ts
import { NextApiRequest, NextApiResponse } from "next";
import fs from "fs";
import path from "path";
const dataPath = path.join(process.cwd(), "data", "returs.json");
function readReturData() {
if (!fs.existsSync(dataPath)) return [];
const file = fs.readFileSync(dataPath, "utf-8");
return JSON.parse(file);
}
function writeReturData(data: any[]) {
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") {
const data = readReturData();
return res.status(200).json({ returs: data });
}
if (req.method === "PATCH") {
const { id, status } = req.body;
if (!id || !["approved", "rejected"].includes(status)) {
return res.status(400).json({ error: "Data tidak valid." });
}
const data = readReturData();
const index = data.findIndex((item) => item.id === id);
if (index === -1) {
return res.status(404).json({ error: "Pengajuan tidak ditemukan." });
}
data[index].status = status;
writeReturData(data);
return res.status(200).json({ message: "Status diperbarui." });
}
return res.status(405).json({ error: "Metode tidak diizinkan." });
}📁 Struktur Direktori yang Perlu Ada
/data/returs.json ← file database sementara
/public/uploads/ ← tempat menyimpan foto yang diunggah✅ Siap Digunakan
Dashboard admin sekarang akan bekerja secara penuh:
Menampilkan semua submission
Menyimpan update status approved / rejected
🪙 Fungsi: Mint NFT setelah “Approved”
🎯 Tujuan
Saat pengajuan diverifikasi, sistem akan langsung mint NFT ke wallet pengguna.
NFT yang dimintakan akan memiliki metadata sesuai desain yang dikembalikan.
📁 Perubahan pada: api/admin/retur.ts (PATCH section)
Tambahkan logic minting NFT menggunakan ThirdWeb SDK di bagian PATCH.
📦 Tambahan: ThirdWeb SDK Setup
Install jika belum:
npm install thirdwebBuat file lib/mintNFT.ts:
// src/lib/mintNFT.ts
import { ThirdwebSDK } from "thirdweb";
import { BaseGoerli } from "thirdweb/chains";
const sdk = new ThirdwebSDK(BaseGoerli, {
clientId: process.env.THIRDWEB_CLIENT_ID,
secretKey: process.env.THIRDWEB_SECRET_KEY, // only for server
});
export async function mintNFTTo(wallet: string, design: string) {
const contract = await sdk.getContract(process.env.CONTRACT_ADDRESS!); // ERC-1155 contract
const tokenId = getTokenIdByDesign(design);
if (tokenId === undefined) {
throw new Error("Desain tidak dikenali.");
}
const tx = await contract.erc1155.claimTo(wallet, tokenId, 1);
return tx.id;
}
// Simulasi mapping desain ke tokenId
function getTokenIdByDesign(design: string): number | undefined {
const mapping: Record<string, number> = {
"Phoenix Flame": 0,
"Jungle Path": 1,
"Future Glitch": 2,
};
return mapping[design];
}📄 Update api/admin/retur.ts (PATCH block)
Tambahkan di dalam PATCH setelah status === "approved":
import { mintNFTTo } from "@/lib/mintNFT";
...
if (status === "approved") {
try {
const wallet = data[index].wallet;
const design = data[index].design;
const txId = await mintNFTTo(wallet, design);
data[index].txId = txId;
} catch (err) {
console.error("Gagal mint NFT:", err);
return res.status(500).json({ error: "Minting NFT gagal." });
}
}🔐 Environment Variables
Tambahkan ke .env.local:
THIRDWEB_CLIENT_ID=your-client-id
THIRDWEB_SECRET_KEY=your-secret
CONTRACT_ADDRESS=0xYourERC1155ContractAddress✅ Hasil Akhir
Admin klik “Approve” → status berubah + NFT otomatis dikirim
Data returs.json bisa mencatat txId NFT-nya
📬 Notifikasi otomatis via Email atau WhatsApp
🎯 Tujuan
Mengirim pesan kepada pengguna bahwa:
Pengajuan mereka telah disetujui
NFT telah dikirim ke wallet mereka
Opsional: sertakan link txId (jika tersedia)
2 Opsi Notifikasi
Untuk tahap awal kita prioritaskan Email, karena:
Cepat di-setup
Gratis untuk tahap awal
Tidak tergantung pada nomor WA pengguna yang aktif
✅ Implementasi Email dengan Resend
🔧 1. Instalasi
npm install resend📁 2. Buat file lib/sendEmail.ts
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendSuccessEmail(email: string, nama: string, design: string, wallet: string, txId?: string) {
const txLink = txId ? `https://basescan.org/tx/${txId}` : "";
const html = `
<p>Halo ${nama},</p>
<p>Terima kasih telah mengembalikan skateboard desain <strong>${design}</strong>.</p>
<p>Kami telah mengirim NFT kenangan Anda ke wallet berikut:</p>
<p><code>${wallet}</code></p>
${txId ? `<p>Tx Hash: <a href="${txLink}">${txId}</a></p>` : ""}
<br />
<p>Salam hormat,</p>
<p><strong>Tim Prof. NOTA Inc. Skateboards</strong></p>
`;
await resend.emails.send({
from: "[email protected]",
to: email,
subject: `NFT Retur Anda Sudah Dikirim — ${design}`,
html,
});
}🔧 3. Tambahkan ke api/admin/retur.ts (dalam PATCH block):
Tambahkan setelah NFT berhasil dimintakan:
import { sendSuccessEmail } from "@/lib/sendEmail";
...
if (status === "approved") {
...
await sendSuccessEmail(data[index].email, data[index].nama, design, wallet, txId);
}📁 4. Tambahkan di .env.local
RESEND_API_KEY=your_resend_api_key🚀 Hasil Akhir
User mendapatkan email dengan isi:
Ucapan terima kasih
Info desain
Wallet address
(opsional) link transaksi NFT
🧩 LANJUTAN STRATEGIS — NFT Claim Skateboard
Dengan semua fondasi inti telah selesai (formulir, backend, dashboard, minting NFT, dan notifikasi email), berikut adalah daftar fitur dan peningkatan strategis yang dapat dilanjutkan oleh tim internal Prof. NOTA Inc.
✅ TELAH SELESAI
Formulir pengembalian
✅ Siap
API penerimaan submission
✅ Siap
Dashboard admin
✅ Siap
Minting NFT setelah approve
✅ Siap
Email notifikasi sukses
✅ Siap
🧩 FASE LANJUTAN YANG DIREKOMENDASIKAN
1. Integrasi Database Nyata (MongoDB/PostgreSQL)
Menyimpan data secara permanen dan dapat dicari.
Mempermudah laporan dan manajemen pengajuan.
Replacing
returs.json.
Task: Setup koneksi database & schema.
2. Tampilan User untuk Tracking Status
Halaman
/retur/track?wallet=0x...Pengguna bisa cek status pengajuan dan melihat txId jika sudah minting.
Task: Komponen ReturStatus.tsx + endpoint /api/retur/status.
3. Landing Page Publik Edukasi & CTA
Halaman
/retur/infoatau/kenapaCerita gerakan sosial dan etika brand Prof. NOTA Inc.
Langkah-langkah mengirim skateboard
FAQ + ilustrasi
Task: Komponen ReturIntro.tsx + desain visual ringan.
4. Sistem Logistik & Validasi Ongkir
Fitur input nomor resi dari user.
Opsional integrasi API kurir (JNE, Wahana, dll.)
Sistem subsidi ongkir otomatis.
Task: Tambahan field resi di dashboard + logic validasi ongkir.
5. Halaman Museum Digital / Galeri NFT Retur
Rute
/museumatau/pameranMenampilkan NFT hasil klaim publik (metadata ERC-1155)
Bisa filter: desain, waktu, kota
Task: Komponen NFTGallery.tsx + fetch metadata kontrak.
6. Role-Based Access (Admin vs Publik)
Proteksi dashboard
/adminLogin email, auth token, atau ThirdWeb Auth
Level akses: Viewer, Admin, Superadmin
Task: Middleware route & pengelolaan auth.
7. Eksperimen Identitas Web3 (opsional)
Dukungan untuk ENS (.eth) atau Lens Protocol
NFT diklaim langsung ke identitas Web3 pengguna
8. Konversi Proyek ke Repositori GitHub
Semua file
.tsx,.ts,.env.example, dan dokumentasi.mdREADME dengan alur sistem dan cara deploy
CI/CD ringan (Vercel)
🚦 REKOMENDASI URUTAN EKSEKUSI LANJUTAN
🎯 Implementasi DB MongoDB
🔍 Halaman tracking status pengguna
🖼 Museum NFT publik (galeri)
🌍 Landing page edukasi publik
🔒 Proteksi role-based akses dashboard
Silakan lanjut sesuai prioritas proyek dan resource tim. Semua langkah ini bersifat modular, dapat dikerjakan paralel.
—Prof. NOTA
Last updated
