- Untuk bisa membantu Anda lebih jauh, boleh saya tahu nama dan nomor telepon Anda?
- Informasi ini juga membantu tim admin kami jika perlu melakukan follow-up nantinya 😊
-
-
console.log('Nama focused')}
- />
-
-
+62
+ {isPoppedUp &&
+
+
+ Untuk bisa membantu Anda lebih jauh, boleh saya tahu nama dan nomor telepon Anda?
+ Informasi ini juga membantu tim admin kami jika perlu melakukan follow-up nantinya 😊
+
console.log('Telepon focused')}
- style={{border: 0, width: '100%'}}
+ placeholder="Nama Lengkapmu"
+ onFocus={() => console.log('Nama focused')}
+ value={name}
+ onChange={(e) => setName(e.target.value)}
+ maxLength={40}
/>
-
+
+
+62
+
{
+ const value = e.target.value;
+ // Hanya angka, maksimal 11 karakter
+ if (/^\d{0,11}$/.test(value)) {
+ setPhoneNumber(value);
+ }
+ }}
+ onFocus={() => console.log('Telepon focused')}
+ />
-
- Lanjut
+
+
+
2 && phoneNumber.length >= 10 ? 'black' : '#ccc' }}
+ onClick={() => {
+ if (name.length > 2 && phoneNumber.length >= 10) {
+ const sessionData = JSON.parse(localStorage.getItem('session')) || {};
+
+ sessionData.name = name;
+ sessionData.phoneNumber = phoneNumber;
+
+ localStorage.setItem('session', JSON.stringify(sessionData));
+ setIsPoppedUp(false)
+ }
+ }}
+ >
+ Lanjut
+
-
+ }
);
};
diff --git a/src/ChatBot.module.css b/src/ChatBot.module.css
index eba772f..6d08f27 100644
--- a/src/ChatBot.module.css
+++ b/src/ChatBot.module.css
@@ -129,18 +129,17 @@
.inputGroup {
display: flex;
align-items: center;
- border: 1px solid #ccc;
- border-radius: 20px;
- overflow: hidden;
width: 100%;
}
.prefix {
background-color: #f0f0f0;
padding: 0.5rem 0.75rem;
- border-right: 1px solid #ccc;
+ border-radius: 20px 0px 0px 20px;
font-size: 12px;
color: #555;
+ border: 1px solid #ccc;
+ border-right: 0;
}
.quickReply {
@@ -158,3 +157,30 @@
color: white;
border-color: #075e54;
}
+
+.quickReply:hover::placeholder {
+ color: white;
+}
+
+.quickReply2 {
+ width: 100%;
+ background: #fff;
+ border: 1px solid #ccc;
+ padding: 8px 14px;
+ border-radius: 0 20px 20px 0;
+ border: 1px solid #ccc;
+ font-size: 14px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.quickReply2:hover {
+ background: #075e54;
+ color: white;
+ border-color: #075e54;
+ border: 1px solid #075e54;
+}
+
+.quickReply2:hover::placeholder {
+ color: white;
+}
\ No newline at end of file
diff --git a/src/Dashboard.js b/src/Dashboard.js
index fac9731..499fad4 100644
--- a/src/Dashboard.js
+++ b/src/Dashboard.js
@@ -18,6 +18,7 @@ const Dashboard = () => {
const [modalContent, setModalContent] = useState(null);
const [rawData, setRawData] = useState([]);
const [loading, setLoading] = useState(true); // ⬅️ Tambahkan state loading
+ const [checkOnce, setCheckOnce] = useState(false); // ⬅️ Tambahkan state loading
const [stats, setStats] = useState({
totalChats: 0,
@@ -124,9 +125,49 @@ const Dashboard = () => {
}
};
- fetchData();
+ if (!checkOnce && 'serviceWorker' in navigator) {
+ subscribeUser();
+ setCheckOnce(false);
+ }
+
+ fetchData(); // Jalankan langsung saat komponen di-mount
+ const interval = setInterval(fetchData, 30000); // Jalankan setiap 30 detik
+ return () => clearInterval(interval); // Bersihkan interval saat komponen unmount
+
}, [navigate]);
+ const subscribeUser = async () => {
+ const registration = await navigator.serviceWorker.register('/sw.js', {
+ scope: '/',
+ });
+
+ const subscription = await registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: urlBase64ToUint8Array('BPT-ypQB0Z7HndmeFhRR7AMjDujCLSbOQ21VoVHLQg9MOfWhEZ7SKH5cMjLqkXHl2sTuxdY2rjHDOAxhRK2G2K4'),
+ });
+
+ const token = localStorage.getItem('token');
+
+ await fetch('https://bot.kediritechnopark.com/webhook/subscribe', {
+ method: 'POST',
+ body: JSON.stringify({
+ subscription, // ← push subscription object
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${token}`,
+ },
+ });
+
+ };
+
+ function urlBase64ToUint8Array(base64String) {
+ const padding = '='.repeat((4 - base64String.length % 4) % 4);
+ const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
+ const rawData = atob(base64);
+ return Uint8Array.from([...rawData].map(char => char.charCodeAt(0)));
+ }
+
const openConversationsModal = () => {
setModalContent(
);
};
@@ -147,13 +188,13 @@ const Dashboard = () => {
const prefixLabelMap = {
WEB: 'Web App',
- WAP: 'WhatsApp',
+ TGG: 'Telegram',
DME: 'Instagram',
};
const prefixColors = {
WEB: { border: '#4285F4', background: 'rgba(66, 133, 244, 0.2)' },
- WAP: { border: '#25D366', background: 'rgba(37, 211, 102, 0.2)' },
+ TGG: { border: '#25D366', background: 'rgba(37, 211, 102, 0.2)' },
DME: { border: '#AA00FF', background: 'rgba(170, 0, 255, 0.2)' },
};
@@ -225,18 +266,17 @@ const Dashboard = () => {
{isLoggedIn ? (
-
+
{/* ✅ Pindahkan ref ke sini */}
setIsMenuOpen(!isMenuOpen)}
className={styles.dropdownToggle}
- ref={menuRef}
>
☰ Menu
{isMenuOpen && (
-
+ navigate('/reset-password')} className={styles.dropdownItem}>
Ganti Password
@@ -245,6 +285,7 @@ const Dashboard = () => {
)}
+
) : (
Login
)}
diff --git a/src/Dashboard.module.css b/src/Dashboard.module.css
index e742a07..52dcf65 100644
--- a/src/Dashboard.module.css
+++ b/src/Dashboard.module.css
@@ -50,7 +50,7 @@
.statsGrid {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-top: 20px;
}
@@ -202,8 +202,8 @@ position: absolute;
}
.dropdownToggle {
- background-color: #007bff;
- color: white;
+ background-color: #ffff;
+ color: #255e54;
padding: 8px 12px;
border: none;
border-radius: 4px;
diff --git a/src/ResetPassword.js b/src/ResetPassword.js
new file mode 100644
index 0000000..8500b3d
--- /dev/null
+++ b/src/ResetPassword.js
@@ -0,0 +1,104 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom'; // ⬅️ Tambahkan ini
+import styles from './Login.module.css';
+
+const ResetPassword = () => {
+ const navigate = useNavigate(); // ⬅️ Gunakan ini untuk navigasi
+ const [formData, setFormData] = useState({
+ oldPassword: '',
+ newPassword: ''
+ });
+
+ const [error, setError] = useState('');
+ const [success, setSuccess] = useState('');
+
+ const handleChange = (e) => {
+ setFormData({ ...formData, [e.target.name]: e.target.value });
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setError('');
+ setSuccess('');
+
+ const token = localStorage.getItem('token');
+
+ if (!token) {
+ setError('Anda belum login. Silakan login terlebih dahulu.');
+ return;
+ }
+
+ try {
+ const response = await fetch('https://bot.kediritechnopark.com/webhook/reset-password', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${token}`
+ },
+ body: JSON.stringify({
+ password: formData.oldPassword,
+ newPassword: formData.newPassword
+ })
+ });
+
+ const data = await response.json();
+ if (data?.success) {
+ setSuccess('Password berhasil diubah');
+ setFormData({ oldPassword: '', newPassword: '' });
+ } else {
+ setError(data?.message || 'Gagal mereset password');
+ }
+ } catch (err) {
+ console.error('Reset Error:', err);
+ setError('Gagal terhubung ke server');
+ }
+ };
+
+ return (
+
+
+
+
Ganti Password
+
Masukkan password lama dan yang baru
+
+
+ {/* Tombol kembali */}
+
navigate('/dashboard')}
+ className={styles.button}
+ style={{ marginTop: '12px', backgroundColor: '#777' }}
+ >
+ Kembali ke Dashboard
+
+
+
+ © 2025 Kloowear AI - Admin Panel
+
+
+
+ );
+};
+
+export default ResetPassword;