{"id":188,"date":"2026-05-18T21:45:16","date_gmt":"2026-05-18T21:45:16","guid":{"rendered":"https:\/\/cashchat.se\/dir\/?page_id=188"},"modified":"2026-05-18T21:47:50","modified_gmt":"2026-05-18T21:47:50","slug":"start","status":"publish","type":"page","link":"https:\/\/cashchat.se\/dir\/start\/","title":{"rendered":"Start"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Adase Ads \u2013 Wallet &#038; Investment<\/title>\n  <style>\n    * { box-sizing: border-box; }\n    body { font-family: 'Inter', sans-serif; background: #f4f6f9; margin: 0; }\n    .container { max-width: 1200px; margin: auto; padding: 20px; }\n    .card { background: #fff; border-radius: 12px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); }\n    .flex { display: flex; gap: 15px; align-items: center; flex-wrap: wrap; }\n    button, .btn { background: #0a1f44; color: white; border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; }\n    .btn-gold { background: #c49a2b; color: #0a1f44; font-weight: bold; }\n    input, select { padding: 10px; border: 1px solid #ccc; border-radius: 6px; width: 100%; max-width: 300px; }\n    .hidden { display: none; }\n    table { width: 100%; border-collapse: collapse; }\n    th, td { padding: 10px; border-bottom: 1px solid #ddd; text-align: left; }\n    .notification { background: #fff3cd; padding: 10px; border-radius: 6px; margin-bottom: 10px; }\n  <\/style>\n<\/head>\n<body>\n  <div class=\"container\" id=\"app\">\n    <!-- Login\/Register if no token -->\n    <div id=\"authSection\">\n      <div class=\"card\">\n        <h2>Welcome to Adase Ads<\/h2>\n        <div class=\"flex\">\n          <button onclick=\"showForm('login')\">Login<\/button>\n          <button onclick=\"showForm('register')\">Register<\/button>\n        <\/div>\n        <div id=\"loginForm\" class=\"hidden\">\n          <h3>Login<\/h3>\n          <input type=\"email\" id=\"loginEmail\" placeholder=\"Email\"><br><br>\n          <input type=\"password\" id=\"loginPassword\" placeholder=\"Password\"><br><br>\n          <button onclick=\"login()\">Login<\/button>\n        <\/div>\n        <div id=\"registerForm\" class=\"hidden\">\n          <h3>Register<\/h3>\n          <input type=\"text\" id=\"regName\" placeholder=\"Full Name\"><br><br>\n          <input type=\"email\" id=\"regEmail\" placeholder=\"Email\"><br><br>\n          <input type=\"password\" id=\"regPassword\" placeholder=\"Password\"><br><br>\n          <button onclick=\"register()\">Register<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Main Dashboard (hidden until login) -->\n    <div id=\"dashboard\" class=\"hidden\">\n      <div class=\"card flex\" style=\"justify-content: space-between;\">\n        <h2>Dashboard<\/h2>\n        <div>\n          <span id=\"userName\"><\/span> | Wallet: <strong id=\"balanceDisplay\">0<\/strong> UGX\n          <button onclick=\"logout()\" style=\"margin-left:10px;\">Logout<\/button>\n        <\/div>\n      <\/div>\n\n      <!-- Wallet Actions -->\n      <div class=\"card\">\n        <h3>Wallet Actions<\/h3>\n        <div class=\"flex\">\n          <button onclick=\"showWalletAction('topup')\">Add Money<\/button>\n          <button onclick=\"showWalletAction('withdraw')\">Withdraw<\/button>\n          <button onclick=\"showWalletAction('transfer')\">Transfer Ownership<\/button>\n        <\/div>\n        <!-- Topup Form -->\n        <div id=\"topupForm\" class=\"hidden\">\n          <h4>Top-Up Request<\/h4>\n          <input type=\"number\" id=\"topupAmount\" placeholder=\"Amount (UGX)\"><br><br>\n          <button onclick=\"submitTopup()\">Submit Request<\/button>\n          <p class=\"notification hidden\" id=\"adminRequestMsg\">Admin may request payment details. Please check notifications.<\/p>\n        <\/div>\n        <!-- Withdraw Form -->\n        <div id=\"withdrawForm\" class=\"hidden\">\n          <h4>Withdraw Request<\/h4>\n          <input type=\"number\" id=\"withdrawAmount\" placeholder=\"Amount (UGX)\"><br><br>\n          <button onclick=\"submitWithdraw()\">Submit Withdrawal<\/button>\n        <\/div>\n        <!-- Transfer Form -->\n        <div id=\"transferForm\" class=\"hidden\">\n          <h4>Transfer Ownership (Balance to Another User)<\/h4>\n          <input type=\"email\" id=\"transferEmail\" placeholder=\"Recipient Email\"><br><br>\n          <input type=\"number\" id=\"transferAmount\" placeholder=\"Amount (UGX)\"><br><br>\n          <button onclick=\"submitTransfer()\">Request Transfer<\/button>\n        <\/div>\n      <\/div>\n\n      <!-- Buy Convertible Note -->\n      <div class=\"card\">\n        <h3>Buy Convertible Note<\/h3>\n        <p>Minimum 100,000 UGX. Amount will be deducted from your wallet balance when you download the certificate.<\/p>\n        <div class=\"flex\">\n          <input type=\"number\" id=\"investAmount\" placeholder=\"Amount (UGX)\" min=\"100000\">\n          <button id=\"downloadCertBtn\" class=\"btn-gold\" onclick=\"buyAndDownload()\">Buy &#038; Download Certificate<\/button>\n        <\/div>\n        <p id=\"investMsg\"><\/p>\n      <\/div>\n\n      <!-- Notifications -->\n      <div class=\"card\">\n        <h3>Notifications<\/h3>\n        <div id=\"notificationsList\"><\/div>\n      <\/div>\n\n      <!-- Investment History -->\n      <div class=\"card\">\n        <h3>Investment History<\/h3>\n        <table>\n          <thead><tr><th>Certificate No<\/th><th>Principal<\/th><th>Date<\/th><th>Actions<\/th><\/tr><\/thead>\n          <tbody id=\"investHistoryBody\"><\/tbody>\n        <\/table>\n      <\/div>\n\n      <!-- Transaction History -->\n      <div class=\"card\">\n        <h3>Wallet Transactions<\/h3>\n        <table>\n          <thead><tr><th>Type<\/th><th>Amount<\/th><th>Status<\/th><th>Date<\/th><th>Note<\/th><\/tr><\/thead>\n          <tbody id=\"txHistoryBody\"><\/tbody>\n        <\/table>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <script>\n    const API = 'http:\/\/localhost:3000\/api';\n    let token = localStorage.getItem('token');\n    let user = null;\n\n    function showForm(type) {\n      document.getElementById('loginForm').classList.add('hidden');\n      document.getElementById('registerForm').classList.add('hidden');\n      if (type === 'login') document.getElementById('loginForm').classList.remove('hidden');\n      else document.getElementById('registerForm').classList.remove('hidden');\n    }\n\n    async function login() {\n      const email = document.getElementById('loginEmail').value;\n      const password = document.getElementById('loginPassword').value;\n      const res = await fetch(`${API}\/users\/login`, {\n        method: 'POST', headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({ email, password })\n      });\n      const data = await res.json();\n      if (res.ok) {\n        token = data.token;\n        localStorage.setItem('token', token);\n        loadDashboard(data.user);\n      } else alert(data.msg);\n    }\n\n    async function register() {\n      const name = document.getElementById('regName').value;\n      const email = document.getElementById('regEmail').value;\n      const password = document.getElementById('regPassword').value;\n      const res = await fetch(`${API}\/users\/register`, {\n        method: 'POST', headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({ name, email, password })\n      });\n      const data = await res.json();\n      if (res.ok) {\n        token = data.token;\n        localStorage.setItem('token', token);\n        loadDashboard(data.user);\n      } else alert(data.msg);\n    }\n\n    async function loadDashboard(userData) {\n      user = userData;\n      document.getElementById('authSection').classList.add('hidden');\n      document.getElementById('dashboard').classList.remove('hidden');\n      document.getElementById('userName').textContent = user.name;\n      updateBalance(user.walletBalance);\n      fetchNotifications();\n      fetchInvestments();\n      fetchTransactions();\n    }\n\n    async function fetchWithAuth(url, options = {}) {\n      options.headers = { ...options.headers, 'x-auth-token': token, 'Content-Type': 'application\/json' };\n      return fetch(url, options);\n    }\n\n    function updateBalance(bal) {\n      document.getElementById('balanceDisplay').textContent = bal.toLocaleString();\n    }\n\n    async function refreshUser() {\n      const res = await fetchWithAuth(`${API}\/users\/me`);\n      const data = await res.json();\n      user = data;\n      updateBalance(user.walletBalance);\n    }\n\n    function showWalletAction(action) {\n      document.getElementById('topupForm').classList.add('hidden');\n      document.getElementById('withdrawForm').classList.add('hidden');\n      document.getElementById('transferForm').classList.add('hidden');\n      document.getElementById(action + 'Form').classList.remove('hidden');\n    }\n\n    async function submitTopup() {\n      const amount = parseFloat(document.getElementById('topupAmount').value);\n      if (!amount || amount <= 0) return alert('Invalid amount');\n      await fetchWithAuth(`${API}\/wallet\/topup`, { method: 'POST', body: JSON.stringify({ amount }) });\n      alert('Top-up request submitted. Admin will review.');\n      document.getElementById('adminRequestMsg').classList.remove('hidden');\n    }\n\n    async function submitWithdraw() {\n      const amount = parseFloat(document.getElementById('withdrawAmount').value);\n      if (!amount || amount <= 0) return alert('Invalid amount');\n      await fetchWithAuth(`${API}\/wallet\/withdraw`, { method: 'POST', body: JSON.stringify({ amount }) });\n      alert('Withdrawal request submitted.');\n    }\n\n    async function submitTransfer() {\n      const toEmail = document.getElementById('transferEmail').value;\n      const amount = parseFloat(document.getElementById('transferAmount').value);\n      if (!amount || amount <= 0) return alert('Invalid amount');\n      const res = await fetchWithAuth(`${API}\/wallet\/transfer`, {\n        method: 'POST', body: JSON.stringify({ toEmail, amount })\n      });\n      const data = await res.json();\n      alert(data.msg);\n    }\n\n    async function buyAndDownload() {\n      const principal = parseFloat(document.getElementById('investAmount').value);\n      if (principal < 100000) return alert('Minimum 100,000 UGX');\n      const res = await fetchWithAuth(`${API}\/invest`, {\n        method: 'POST', body: JSON.stringify({ principal })\n      });\n      const data = await res.json();\n      if (!res.ok) return alert(data.msg);\n      alert(`Investment successful! Certificate: ${data.certificateNumber}`);\n      await refreshUser();\n      fetchInvestments();\n      fetchTransactions();\n      \/\/ Trigger certificate download (use the cert generator from previous answer)\n      \/\/ We'll call a function that generates and downloads the PDF\/PNG using the certificateNumber\n      downloadCertificate(data.certificateNumber, principal);\n    }\n\n    function downloadCertificate(certNumber, amount) {\n      \/\/ Reuse the certificate generation code from previous dashboard\n      \/\/ For simplicity, we'll just redirect to a download endpoint or create a canvas\n      const name = user.name;\n      const issueDate = new Date().toISOString().split('T')[0];\n      const maturityDate = new Date(new Date().setFullYear(new Date().getFullYear() + 3)).toISOString().split('T')[0];\n      \/\/ Open a new window with the certificate generator (pass params) or use html2canvas\n      \/\/ Here we'll just simulate with an alert, but you can embed the full certificate generator.\n      alert(`Certificate ${certNumber} ready. (Implement full generator as in previous design)`);\n    }\n\n    async function fetchNotifications() {\n      const res = await fetchWithAuth(`${API}\/notifications`);\n      const notifs = await res.json();\n      const container = document.getElementById('notificationsList');\n      container.innerHTML = notifs.map(n => `\n        <div class=\"notification\">\n          <p>${n.message}<\/p>\n          <small>${new Date(n.createdAt).toLocaleString()}<\/small>\n          <button onclick=\"markNotifRead('${n._id}')\">Dismiss<\/button>\n        <\/div>\n      `).join('');\n    }\n\n    async function markNotifRead(id) {\n      await fetchWithAuth(`${API}\/notifications\/read\/${id}`, { method: 'POST' });\n      fetchNotifications();\n    }\n\n    async function fetchInvestments() {\n      const res = await fetchWithAuth(`${API}\/investments`);\n      const invs = await res.json();\n      const tbody = document.getElementById('investHistoryBody');\n      tbody.innerHTML = invs.map(i => `\n        <tr>\n          <td>${i.certificateNumber}<\/td>\n          <td>${i.principal.toLocaleString()} UGX<\/td>\n          <td>${new Date(i.issuedAt).toLocaleDateString()}<\/td>\n          <td><button onclick=\"downloadCertificate('${i.certificateNumber}', ${i.principal})\">Download<\/button><\/td>\n        <\/tr>\n      `).join('');\n    }\n\n    async function fetchTransactions() {\n      const res = await fetchWithAuth(`${API}\/transactions`);\n      const txns = await res.json();\n      const tbody = document.getElementById('txHistoryBody');\n      tbody.innerHTML = txns.map(t => `\n        <tr>\n          <td>${t.type}<\/td>\n          <td>${t.amount.toLocaleString()}<\/td>\n          <td>${t.status}<\/td>\n          <td>${new Date(t.createdAt).toLocaleString()}<\/td>\n          <td>${t.description || ''}<\/td>\n        <\/tr>\n      `).join('');\n    }\n\n    function logout() {\n      localStorage.removeItem('token');\n      location.reload();\n    }\n\n    \/\/ On page load\n    if (token) {\n      fetchWithAuth(`${API}\/users\/me`)\n        .then(res => res.json())\n        .then(user => {\n          if (user.email) loadDashboard(user);\n          else logout();\n        })\n        .catch(logout);\n    }\n  <\/script>\n<\/body>\n<\/html>\n\n\n\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Admin Dashboard \u2013 Adase Ads<\/title>\n  <style>\n    body { font-family: Inter, sans-serif; margin: 20px; background: #f4f6f9; }\n    .card { background: #fff; border-radius: 12px; padding: 20px; margin-bottom: 20px; }\n    .flex { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }\n    button { background: #0a1f44; color: white; border: none; padding: 10px 15px; border-radius: 6px; cursor: pointer; }\n    .badge { padding: 2px 8px; border-radius: 12px; font-size: 12px; }\n    .pending { background: #ffc107; } .approved { background: #28a745; color: white; } .declined { background: #dc3545; color: white; }\n    table { width: 100%; border-collapse: collapse; margin-top: 10px; }\n    th, td { padding: 10px; border-bottom: 1px solid #ddd; }\n  <\/style>\n<\/head>\n<body>\n  <h1>Admin Dashboard<\/h1>\n  <div id=\"loginBox\" class=\"card\">\n    <h2>Login<\/h2>\n    <input type=\"password\" id=\"adminPass\" placeholder=\"Password\">\n    <button onclick=\"adminLogin()\">Login<\/button>\n  <\/div>\n  <div id=\"adminPanel\" class=\"hidden\">\n    <div class=\"card\">\n      <h2>Pending Requests<\/h2>\n      <button onclick=\"loadRequests()\">Refresh<\/button>\n      <div id=\"requestsContainer\"><\/div>\n    <\/div>\n    <div class=\"card\">\n      <h3>Send Notification to User<\/h3>\n      <input type=\"text\" id=\"notifyUserId\" placeholder=\"User ID\">\n      <input type=\"text\" id=\"notifyMsg\" placeholder=\"Message (e.g., Please provide MTN number)\">\n      <button onclick=\"sendNotification()\">Send<\/button>\n    <\/div>\n  <\/div>\n\n  <script>\n    let adminToken = localStorage.getItem('adminToken');\n    const API = 'http:\/\/localhost:3000\/api';\n\n    async function adminLogin() {\n      const password = document.getElementById('adminPass').value;\n      const res = await fetch(`${API}\/admin\/login`, {\n        method: 'POST', headers: { 'Content-Type': 'application\/json' },\n        body: JSON.stringify({ email: 'shares@cashchat.se', password })\n      });\n      const data = await res.json();\n      if (res.ok) {\n        adminToken = data.token;\n        localStorage.setItem('adminToken', adminToken);\n        document.getElementById('loginBox').classList.add('hidden');\n        document.getElementById('adminPanel').classList.remove('hidden');\n        loadRequests();\n      } else alert('Wrong password');\n    }\n\n    async function adminFetch(url, options = {}) {\n      options.headers = { ...options.headers, 'x-admin-token': adminToken, 'Content-Type': 'application\/json' };\n      return fetch(url, options);\n    }\n\n    async function loadRequests() {\n      const res = await adminFetch(`${API}\/admin\/requests`);\n      const { topups, withdraws, transfers } = await res.json();\n      const container = document.getElementById('requestsContainer');\n      container.innerHTML = `\n        <h3>Top\u2011ups<\/h3>\n        ${renderTable(topups, 'topup')}\n        <h3>Withdrawals<\/h3>\n        ${renderTable(withdraws, 'withdraw')}\n        <h3>Transfers<\/h3>\n        ${renderTable(transfers, 'transfer')}\n      `;\n    }\n\n    function renderTable(items, type) {\n      if (!items.length) return '<p>None<\/p>';\n      const headers = type === 'transfer' ? ['From','To','Amount','Status','Actions'] : ['User','Amount','Status','Actions'];\n      let html = '<table><thead><tr>' + headers.map(h => `<th>${h}<\/th>`).join('') + '<\/tr><\/thead><tbody>';\n      items.forEach(item => {\n        if (type === 'topup' || type === 'withdraw') {\n          html += `<tr>\n            <td>${item.userId?.name || 'N\/A'} (${item.userId?.email || ''})<\/td>\n            <td>${item.amount}<\/td>\n            <td><span class=\"badge ${item.status}\">${item.status}<\/span><\/td>\n            <td>${item.status === 'pending' ? `<button onclick=\"approveRequest('${type}','${item._id}')\">Approve<\/button>\n              <button onclick=\"declineRequest('${type}','${item._id}')\">Decline<\/button>\n              <button onclick=\"requestPaymentDetails('${item.userId?._id}')\">Request Payment Details<\/button>` : ''}<\/td>\n          <\/tr>`;\n        } else { \/\/ transfer\n          html += `<tr>\n            <td>${item.fromUserId?.name} (${item.fromUserId?.email})<\/td>\n            <td>${item.toUserEmail}<\/td>\n            <td>${item.amount}<\/td>\n            <td><span class=\"badge ${item.status}\">${item.status}<\/span><\/td>\n            <td>${item.status === 'pending' ? `<button onclick=\"approveRequest('transfer','${item._id}')\">Approve<\/button>\n              <button onclick=\"declineRequest('transfer','${item._id}')\">Decline<\/button>` : ''}<\/td>\n          <\/tr>`;\n        }\n      });\n      html += '<\/tbody><\/table>';\n      return html;\n    }\n\n    async function approveRequest(type, id) {\n      await adminFetch(`${API}\/admin\/${type}\/${id}`, {\n        method: 'POST', body: JSON.stringify({ status: 'approved', adminNote: '' })\n      });\n      loadRequests();\n    }\n    async function declineRequest(type, id) {\n      await adminFetch(`${API}\/admin\/${type}\/${id}`, {\n        method: 'POST', body: JSON.stringify({ status: 'declined', adminNote: 'Declined by admin' })\n      });\n      loadRequests();\n    }\n    async function requestPaymentDetails(userId) {\n      const msg = prompt('Enter message to request payment details (e.g., Please provide your MTN number):');\n      if (msg) {\n        await adminFetch(`${API}\/admin\/notify\/${userId}`, {\n          method: 'POST', body: JSON.stringify({ message: msg })\n        });\n        alert('Notification sent');\n      }\n    }\n    async function sendNotification() {\n      const userId = document.getElementById('notifyUserId').value;\n      const message = document.getElementById('notifyMsg').value;\n      if (!userId || !message) return alert('Fill both fields');\n      await adminFetch(`${API}\/admin\/notify\/${userId}`, {\n        method: 'POST', body: JSON.stringify({ message })\n      });\n      alert('Sent');\n    }\n\n    \/\/ On load\n    if (adminToken) {\n      document.getElementById('loginBox').classList.add('hidden');\n      document.getElementById('adminPanel').classList.remove('hidden');\n      loadRequests();\n    }\n  <\/script>\n<\/body>\n<\/html>\n\n\n\n<!--nextpage-->\n\n\n\nMONGODB_URI=mongodb:\/\/localhost:27017\/adaseads\nJWT_SECRET=adase_super_secret_2026\nADMIN_EMAIL=shares@cashchat.se\nADMIN_PASSWORD_HASH=$2a$10$&#8230; (we&#8217;ll generate below)\nPORT=3000\n\n\n\nproject\/\n\u251c\u2500\u2500 server.js                 # Express backend, API routes, MongoDB models\n\u251c\u2500\u2500 admin.html                # Admin dashboard (login, approve requests, view users)\n\u251c\u2500\u2500 index.html                # Campaign page with wallet &#038; investment panel\n\u251c\u2500\u2500 package.json\n\u2514\u2500\u2500 .env                      # Environment variables (DB URL, JWT secret, admin creds)\n\n\n\nrequire(&#8216;dotenv&#8217;).config();\nconst express = require(&#8216;express&#8217;);\nconst mongoose = require(&#8216;mongoose&#8217;);\nconst bcrypt = require(&#8216;bcryptjs&#8217;);\nconst jwt = require(&#8216;jsonwebtoken&#8217;);\nconst cors = require(&#8216;cors&#8217;);\nconst app = express();\n\napp.use(cors());\napp.use(express.json());\n\n\/\/ &#8212;&#8212;&#8212;- MongoDB Models &#8212;&#8212;&#8212;-\nconst userSchema = new mongoose.Schema({\n  name: String,\n  email: { type: String, unique: true },\n  password: String,\n  walletBalance: { type: Number, default: 0 },\n  createdAt: { type: Date, default: Date.now }\n});\n\nconst transactionSchema = new mongoose.Schema({\n  userId: mongoose.Schema.Types.ObjectId,\n  type: { type: String, enum: [&#8216;topup&#8217;,&#8217;withdraw&#8217;,&#8217;investment&#8217;,&#8217;transfer_in&#8217;,&#8217;transfer_out&#8217;] },\n  amount: Number,\n  status: { type: String, enum: [&#8216;pending&#8217;,&#8217;approved&#8217;,&#8217;declined&#8217;], default: &#8216;pending&#8217; },\n  description: String,\n  adminNote: String,\n  createdAt: { type: Date, default: Date.now }\n});\n\nconst topupRequestSchema = new mongoose.Schema({\n  userId: mongoose.Schema.Types.ObjectId,\n  amount: Number,\n  status: { type: String, enum: [&#8216;pending&#8217;,&#8217;approved&#8217;,&#8217;declined&#8217;], default: &#8216;pending&#8217; },\n  adminNote: String,\n  userPaymentDetails: String,\n  createdAt: { type: Date, default: Date.now }\n});\n\nconst withdrawRequestSchema = new mongoose.Schema({\n  userId: mongoose.Schema.Types.ObjectId,\n  amount: Number,\n  status: { type: String, enum: [&#8216;pending&#8217;,&#8217;approved&#8217;,&#8217;declined&#8217;], default: &#8216;pending&#8217; },\n  adminNote: String,\n  userPaymentDetails: String,\n  createdAt: { type: Date, default: Date.now }\n});\n\nconst transferRequestSchema = new mongoose.Schema({\n  fromUserId: mongoose.Schema.Types.ObjectId,\n  toUserEmail: String,\n  amount: Number,\n  status: { type: String, enum: [&#8216;pending&#8217;,&#8217;approved&#8217;,&#8217;declined&#8217;], default: &#8216;pending&#8217; },\n  adminNote: String,\n  createdAt: { type: Date, default: Date.now }\n});\n\nconst investmentSchema = new mongoose.Schema({\n  userId: mongoose.Schema.Types.ObjectId,\n  principal: Number,\n  interestRate: Number,\n  discountPercent: Number,\n  maturityMonths: Number,\n  certificateNumber: String,\n  issuedAt: { type: Date, default: Date.now }\n});\n\nconst User = mongoose.model(&#8216;User&#8217;, userSchema);\nconst Transaction = mongoose.model(&#8216;Transaction&#8217;, transactionSchema);\nconst TopupRequest = mongoose.model(&#8216;TopupRequest&#8217;, topupRequestSchema);\nconst WithdrawRequest = mongoose.model(&#8216;WithdrawRequest&#8217;, withdrawRequestSchema);\nconst TransferRequest = mongoose.model(&#8216;TransferRequest&#8217;, transferRequestSchema);\nconst Investment = mongoose.model(&#8216;Investment&#8217;, investmentSchema);\n\n\/\/ &#8212;&#8212;&#8212;- Middleware &#8212;&#8212;&#8212;-\nconst auth = (req, res, next) => {\n  const token = req.header(&#8216;x-auth-token&#8217;);\n  if (!token) return res.status(401).json({ msg: &#8216;No token, authorization denied&#8217; });\n  try {\n    const decoded = jwt.verify(token, process.env.JWT_SECRET);\n    req.user = decoded.user;\n    next();\n  } catch (e) {\n    res.status(401).json({ msg: &#8216;Token is not valid&#8217; });\n  }\n};\n\nconst adminAuth = (req, res, next) => {\n  const token = req.header(&#8216;x-admin-token&#8217;);\n  if (!token) return res.status(401).json({ msg: &#8216;Admin token missing&#8217; });\n  try {\n    const decoded = jwt.verify(token, process.env.JWT_SECRET);\n    if (decoded.user.email !== process.env.ADMIN_EMAIL) throw new Error();\n    req.admin = decoded.user;\n    next();\n  } catch (e) {\n    res.status(401).json({ msg: &#8216;Admin authorization failed&#8217; });\n  }\n};\n\n\/\/ &#8212;&#8212;&#8212;- User Registration &#038; Login &#8212;&#8212;&#8212;-\napp.post(&#8216;\/api\/users\/register&#8217;, async (req, res) => {\n  const { name, email, password } = req.body;\n  try {\n    let user = await User.findOne({ email });\n    if (user) return res.status(400).json({ msg: &#8216;User already exists&#8217; });\n    user = new User({ name, email, password });\n    const salt = await bcrypt.genSalt(10);\n    user.password = await bcrypt.hash(password, salt);\n    await user.save();\n    const payload = { user: { id: user.id, email: user.email } };\n    jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: &#8216;7d&#8217; }, (err, token) => {\n      if (err) throw err;\n      res.json({ token, user: { id: user.id, name: user.name, email: user.email, walletBalance: user.walletBalance } });\n    });\n  } catch (err) {\n    console.error(err);\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\napp.post(&#8216;\/api\/users\/login&#8217;, async (req, res) => {\n  const { email, password } = req.body;\n  try {\n    let user = await User.findOne({ email });\n    if (!user) return res.status(400).json({ msg: &#8216;Invalid credentials&#8217; });\n    const isMatch = await bcrypt.compare(password, user.password);\n    if (!isMatch) return res.status(400).json({ msg: &#8216;Invalid credentials&#8217; });\n    const payload = { user: { id: user.id, email: user.email } };\n    jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: &#8216;7d&#8217; }, (err, token) => {\n      if (err) throw err;\n      res.json({ token, user: { id: user.id, name: user.name, email: user.email, walletBalance: user.walletBalance } });\n    });\n  } catch (err) {\n    console.error(err);\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\napp.get(&#8216;\/api\/users\/me&#8217;, auth, async (req, res) => {\n  try {\n    const user = await User.findById(req.user.id).select(&#8216;-password&#8217;);\n    res.json(user);\n  } catch (err) {\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\n\/\/ &#8212;&#8212;&#8212;- Wallet Operations (User) &#8212;&#8212;&#8212;-\napp.post(&#8216;\/api\/wallet\/topup&#8217;, auth, async (req, res) => {\n  const { amount } = req.body;\n  if (amount <= 0) return res.status(400).json({ msg: 'Invalid amount' });\n  try {\n    const req = new TopupRequest({ userId: req.user.id, amount });\n    await req.save();\n    res.json({ msg: 'Top-up request submitted', requestId: req._id });\n  } catch (err) {\n    res.status(500).send('Server error');\n  }\n});\n\napp.post('\/api\/wallet\/withdraw', auth, async (req, res) => {\n  const { amount } = req.body;\n  if (amount <= 0) return res.status(400).json({ msg: 'Invalid amount' });\n  try {\n    const user = await User.findById(req.user.id);\n    if (user.walletBalance < amount) return res.status(400).json({ msg: 'Insufficient balance' });\n    const req = new WithdrawRequest({ userId: req.user.id, amount });\n    await req.save();\n    res.json({ msg: 'Withdrawal request submitted', requestId: req._id });\n  } catch (err) {\n    res.status(500).send('Server error');\n  }\n});\n\napp.post('\/api\/wallet\/transfer', auth, async (req, res) => {\n  const { toEmail, amount } = req.body;\n  if (amount <= 0) return res.status(400).json({ msg: 'Invalid amount' });\n  try {\n    const fromUser = await User.findById(req.user.id);\n    if (fromUser.walletBalance < amount) return res.status(400).json({ msg: 'Insufficient balance' });\n    const toUser = await User.findOne({ email: toEmail });\n    if (!toUser) return res.status(400).json({ msg: 'Recipient not found' });\n    const req = new TransferRequest({ fromUserId: req.user.id, toUserEmail: toEmail, amount });\n    await req.save();\n    res.json({ msg: 'Transfer request submitted for admin approval', requestId: req._id });\n  } catch (err) {\n    res.status(500).send('Server error');\n  }\n});\n\n\/\/ ---------- Investment (Buy Convertible Note) ----------\napp.post('\/api\/invest', auth, async (req, res) => {\n  const { principal } = req.body;\n  if (principal < 100000) return res.status(400).json({ msg: 'Minimum investment is UGX 100,000' });\n  try {\n    const user = await User.findById(req.user.id);\n    if (user.walletBalance < principal) return res.status(400).json({ msg: 'Insufficient wallet balance' });\n    user.walletBalance -= principal;\n    await user.save();\n    const certNumber = 'CN-' + new Date().getFullYear() + '-' + Math.random().toString(36).substr(2, 8).toUpperCase();\n    const investment = new Investment({\n      userId: user.id,\n      principal,\n      interestRate: 17,\n      discountPercent: 20,\n      maturityMonths: 36,\n      certificateNumber: certNumber\n    });\n    await investment.save();\n    await Transaction.create({\n      userId: user.id,\n      type: 'investment',\n      amount: principal,\n      status: 'approved',\n      description: `Convertible note purchase - ${certNumber}`\n    });\n    res.json({ msg: 'Investment successful', certificateNumber: certNumber, newBalance: user.walletBalance });\n  } catch (err) {\n    res.status(500).send('Server error');\n  }\n});\n\napp.get('\/api\/investments', auth, async (req, res) => {\n  try {\n    const investments = await Investment.find({ userId: req.user.id }).sort({ issuedAt: -1 });\n    res.json(investments);\n  } catch (err) {\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\n\/\/ &#8212;&#8212;&#8212;- Transaction History &#8212;&#8212;&#8212;-\napp.get(&#8216;\/api\/transactions&#8217;, auth, async (req, res) => {\n  try {\n    const txns = await Transaction.find({ userId: req.user.id }).sort({ createdAt: -1 });\n    res.json(txns);\n  } catch (err) {\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\n\/\/ &#8212;&#8212;&#8212;- Admin Routes &#8212;&#8212;&#8212;-\napp.post(&#8216;\/api\/admin\/login&#8217;, async (req, res) => {\n  const { email, password } = req.body;\n  if (email !== process.env.ADMIN_EMAIL) return res.status(400).json({ msg: &#8216;Invalid credentials&#8217; });\n  const isMatch = await bcrypt.compare(password, process.env.ADMIN_PASSWORD_HASH);\n  if (!isMatch) return res.status(400).json({ msg: &#8216;Invalid credentials&#8217; });\n  const payload = { user: { id: &#8216;admin&#8217;, email: email } };\n  jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: &#8216;1d&#8217; }, (err, token) => {\n    if (err) throw err;\n    res.json({ token });\n  });\n});\n\napp.get(&#8216;\/api\/admin\/requests&#8217;, adminAuth, async (req, res) => {\n  try {\n    const topups = await TopupRequest.find().populate(&#8216;userId&#8217;,&#8217;name email&#8217;).sort({ createdAt: -1 });\n    const withdraws = await WithdrawRequest.find().populate(&#8216;userId&#8217;,&#8217;name email&#8217;).sort({ createdAt: -1 });\n    const transfers = await TransferRequest.find().populate(&#8216;fromUserId&#8217;,&#8217;name email&#8217;).sort({ createdAt: -1 });\n    res.json({ topups, withdraws, transfers });\n  } catch (err) {\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\napp.post(&#8216;\/api\/admin\/topup\/:id&#8217;, adminAuth, async (req, res) => {\n  const { status, adminNote, userPaymentDetailsRequest } = req.body; \/\/ status: &#8216;approved&#8217; or &#8216;declined&#8217;\n  try {\n    const topup = await TopupRequest.findById(req.params.id);\n    if (!topup) return res.status(404).json({ msg: &#8216;Not found&#8217; });\n    if (status === &#8216;approved&#8217;) {\n      const user = await User.findById(topup.userId);\n      user.walletBalance += topup.amount;\n      await user.save();\n      await Transaction.create({\n        userId: user.id,\n        type: &#8216;topup&#8217;,\n        amount: topup.amount,\n        status: &#8216;approved&#8217;,\n        description: &#8216;Top-up approved&#8217;,\n        adminNote\n      });\n    }\n    topup.status = status;\n    topup.adminNote = adminNote || &#8221;;\n    await topup.save();\n    \/\/ If admin requests payment details, we can send a notification to user (implement via socket or email later)\n    res.json({ msg: `Top-up ${status}`, request: topup });\n  } catch (err) {\n    res.status(500).send(&#8216;Server error&#8217;);\n  }\n});\n\napp.post(&#8216;\/api\/admin\/withdraw\/:id&#8217;, adminAuth, async (req, res) => {\n  const { status, adminNote } = req.body;\n  try {\n    const withdraw = await WithdrawRequest.findById(req.params.id);\n    if (!withdraw) return res.status(404).json({ msg: &#8216;Not found&#8217; });\n    if (status === &#8216;approved&#8217;) {\n      const user = await User.findById(withdraw.userId);\n      if (user.walletBalance < withdraw.amount) return res.status(400).json({ msg: 'Insufficient balance' });\n      user.walletBalance -= withdraw.amount;\n      await user.save();\n      await Transaction.create({\n        userId: user.id,\n        type: 'withdraw',\n        amount: withdraw.amount,\n        status: 'approved',\n        description: 'Withdrawal approved',\n        adminNote\n      });\n    }\n    withdraw.status = status;\n    withdraw.adminNote = adminNote || '';\n    await withdraw.save();\n    res.json({ msg: `Withdrawal ${status}` });\n  } catch (err) {\n    res.status(500).send('Server error');\n  }\n});\n\napp.post('\/api\/admin\/transfer\/:id', adminAuth, async (req, res) => {\n  const { status, adminNote } = req.body;\n  try {\n    const transfer = await TransferRequest.findById(req.params.id);\n    if (!transfer) return res.status(404).json({ msg: &#8216;Not found&#8217; });\n    if (status === &#8216;approved&#8217;) {\n      const fromUser = await User.findById(transfer.fromUserId);\n      const toUser = await User.findOne({ email: transfer.toUserEmail });\n      if (!fromUser || !toUser) return res.status(400).json({ msg: &#8216;User not found&#8217; });\n      if (fromUser.walletBalance < transfer.amount) return res.status(400).json({ msg: 'Insufficient balance' });\n      fromUser.walletBalance -= transfer.amount;\n      toUser.walletBalance += transfer.amount;\n      await fromUser.save();\n      await toUser.save();\n      await Transaction.create({\n        userId: fromUser.id,\n        type: 'transfer_out',\n        amount: transfer.amount,\n        status: 'approved',\n        description: `Transfer to ${transfer.toUserEmail}`\n      });\n      await Transaction.create({\n        userId: toUser.id,\n        type: 'transfer_in',\n        amount: transfer.amount,\n        status: 'approved',\n        description: `Transfer from ${fromUser.email}`\n      });\n    }\n    transfer.status = status;\n    transfer.adminNote = adminNote || '';\n    await transfer.save();\n    res.json({ msg: `Transfer ${status}` });\n  } catch (err) {\n    res.status(500).send('Server error');\n  }\n});\n\n\/\/ Admin can send a popup message to a user about payment details (via a simple endpoint that the frontend polls)\n\/\/ We'll store a notification per user\nconst notificationSchema = new mongoose.Schema({\n  userId: mongoose.Schema.Types.ObjectId,\n  message: String,\n  read: { type: Boolean, default: false },\n  createdAt: { type: Date, default: Date.now }\n});\nconst Notification = mongoose.model('Notification', notificationSchema);\n\napp.post('\/api\/admin\/notify\/:userId', adminAuth, async (req, res) => {\n  const { message } = req.body;\n  await Notification.create({ userId: req.params.userId, message });\n  res.json({ msg: &#8216;Notification sent&#8217; });\n});\n\napp.get(&#8216;\/api\/notifications&#8217;, auth, async (req, res) => {\n  const notifs = await Notification.find({ userId: req.user.id, read: false }).sort({ createdAt: -1 });\n  res.json(notifs);\n});\n\napp.post(&#8216;\/api\/notifications\/read\/:id&#8217;, auth, async (req, res) => {\n  await Notification.findByIdAndUpdate(req.params.id, { read: true });\n  res.json({ msg: &#8216;Marked read&#8217; });\n});\n\n\/\/ &#8212;&#8212;&#8212;- DB Connect &#038; Start &#8212;&#8212;&#8212;-\nmongoose.connect(process.env.MONGODB_URI)\n  .then(() => {\n    console.log(&#8216;MongoDB connected&#8217;);\n    app.listen(process.env.PORT, () => console.log(`Server running on port ${process.env.PORT}`));\n  })\n  .catch(err => console.error(err));\n","protected":false},"excerpt":{"rendered":"<p>Adase Ads \u2013 Wallet &#038; Investment Welcome to Adase Ads Login Register Login Login Register Register Dashboard | Wallet: 0 UGX Logout Wallet Actions Add Money Withdraw Transfer Ownership Top-Up Request Submit Request Admin may request payment details. Please check notifications. Withdraw Request Submit Withdrawal Transfer Ownership (Balance to Another User) Request Transfer Buy Convertible [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"class_list":["post-188","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/pages\/188","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/comments?post=188"}],"version-history":[{"count":3,"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/pages\/188\/revisions"}],"predecessor-version":[{"id":191,"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/pages\/188\/revisions\/191"}],"wp:attachment":[{"href":"https:\/\/cashchat.se\/dir\/wp-json\/wp\/v2\/media?parent=188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}