This commit is contained in:
Vassshhh
2025-06-23 17:14:40 +07:00
parent 99e79e54a4
commit 85a92c9b23
4 changed files with 79 additions and 52 deletions

View File

@@ -62,7 +62,7 @@ const ChatBot = ({ existingConversation, readOnly, hh }) => {
setIsLoading(true); setIsLoading(true);
try { try {
// Send to backend // Send to backend
const response = await fetch('https://bot.kediritechnopark.com/webhook/master-agent/ask/dev', { const response = await fetch('https://bot.kediritechnopark.com/webhook/master-agent/ask', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pertanyaan: message, sessionId: JSON.parse(localStorage.getItem('session')).sessionId, lastSeen: new Date().toISOString(), name: JSON.parse(localStorage.getItem('session')).name, phoneNumber: JSON.parse(localStorage.getItem('session')).phoneNumber }), body: JSON.stringify({ pertanyaan: message, sessionId: JSON.parse(localStorage.getItem('session')).sessionId, lastSeen: new Date().toISOString(), name: JSON.parse(localStorage.getItem('session')).name, phoneNumber: JSON.parse(localStorage.getItem('session')).phoneNumber }),
@@ -72,7 +72,7 @@ const ChatBot = ({ existingConversation, readOnly, hh }) => {
console.log(data) console.log(data)
// Assuming your backend sends back something like: { answer: "text" } // Assuming your backend sends back something like: { answer: "text" }
// Adjust this according to your actual response shape // Adjust this according to your actual response shape
const botAnswer = data.jawaban || 'Maaf, saya tidak mengerti.'; const botAnswer = data.jawaban || 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti';
// Add bot's reply // Add bot's reply
setMessages(prev => [ setMessages(prev => [
@@ -106,15 +106,29 @@ const ChatBot = ({ existingConversation, readOnly, hh }) => {
function formatBoldText(text) { function formatBoldText(text) {
const parts = text.split(/(\*\*[^\*]+\*\*)/g); const parts = text.split(/(\*\*[^\*]+\*\*)/g);
return parts.map((part, index) => { return parts.flatMap((part, index) => {
const elements = [];
if (part.startsWith('**') && part.endsWith('**')) { if (part.startsWith('**') && part.endsWith('**')) {
return <strong key={index}>{part.slice(2, -2)}</strong>; // Bold text
part = part.slice(2, -2);
part.split('\n').forEach((line, i) => {
if (i > 0) elements.push(<br key={`br-bold-${index}-${i}`} />);
elements.push(<strong key={`bold-${index}-${i}`}>{line}</strong>);
});
} else { } else {
return <span key={index}>{part}</span>; // Normal text
part.split('\n').forEach((line, i) => {
if (i > 0) elements.push(<br key={`br-${index}-${i}`} />);
elements.push(<span key={`text-${index}-${i}`}>{line}</span>);
});
} }
return elements;
}); });
} }
return ( return (
<div className={styles.chatContainer} > <div className={styles.chatContainer} >
<div className={styles.chatHeader}> <div className={styles.chatHeader}>

View File

@@ -22,7 +22,6 @@ const Dashboard = () => {
const [modalContent, setModalContent] = useState(null); const [modalContent, setModalContent] = useState(null);
const [rawData, setRawData] = useState([]); const [rawData, setRawData] = useState([]);
const [loading, setLoading] = useState(true); // ⬅️ Tambahkan state loading const [loading, setLoading] = useState(true); // ⬅️ Tambahkan state loading
const [checkOnce, setCheckOnce] = useState(false); // ⬅️ Tambahkan state loading
const [stats, setStats] = useState({ const [stats, setStats] = useState({
totalChats: 0, totalChats: 0,
@@ -139,54 +138,58 @@ const Dashboard = () => {
} }
}; };
if (!checkOnce && 'serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(function (registration) {
registration.pushManager.getSubscription().then(function (subscription) {
setCheckOnce(true);
if (subscription === null) {
// Not subscribed yet — show modal asking user to subscribe
setModalContent(<NotificationPrompt onAllow={subscribeUser} onDismiss={() => setModalContent('')} />);
} else {
// Already subscribed
setModalContent('')
console.log('User is already subscribed.');
subscribeUser();
}
});
});
}
fetchData(); // Jalankan langsung saat komponen di-mount fetchData(); // Jalankan langsung saat komponen di-mount
const interval = setInterval(fetchData, 60000); // Jalankan setiap 30 detik const interval = setInterval(fetchData, 60000); // Jalankan setiap 30 detik
return () => clearInterval(interval); // Bersihkan interval saat komponen unmount return () => clearInterval(interval); // Bersihkan interval saat komponen unmount
}, [navigate]); }, [navigate]);
const subscribeUser = async () => { useEffect(() => {
const registration = await navigator.serviceWorker.register('/sw.js', { if ('serviceWorker' in navigator) {
scope: '/', navigator.serviceWorker.ready.then(async (registration) => {
const subscription = await registration.pushManager.getSubscription();
if (!subscription) {
// Belum subscribe → tampilkan prompt
setModalContent(
<NotificationPrompt
onAllow={subscribeUser}
onDismiss={() => setModalContent('')}
/>
);
} else {
// Sudah subscribe → tidak perlu panggil subscribeUser lagi
console.log('User is already subscribed.');
setModalContent('');
subscribeUser();
}
}); });
}
}, []);
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('BPT-ypQB0Z7HndmeFhRR7AMjDujCLSbOQ21VoVHLQg9MOfWhEZ7SKH5cMjLqkXHl2sTuxdY2rjHDOAxhRK2G2K4'),
});
const token = localStorage.getItem('token'); const subscribeUser = async () => {
setModalContent('');
const registration = await navigator.serviceWorker.ready;
await fetch('https://bot.kediritechnopark.com/webhook/subscribe', { const subscription = await registration.pushManager.subscribe({
method: 'POST', userVisibleOnly: true,
body: JSON.stringify({ applicationServerKey: urlBase64ToUint8Array('BPT-ypQB0Z7HndmeFhRR7AMjDujCLSbOQ21VoVHLQg9MOfWhEZ7SKH5cMjLqkXHl2sTuxdY2rjHDOAxhRK2G2K4'),
subscription, // ← push subscription object });
}),
headers: { const token = localStorage.getItem('token');
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`, await fetch('https://bot.kediritechnopark.com/webhook/subscribe', {
}, method: 'POST',
}); body: JSON.stringify({ subscription }),
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
});
setModalContent('');
};
setModalContent('')
};
function urlBase64ToUint8Array(base64String) { function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4); const padding = '='.repeat((4 - base64String.length % 4) % 4);

View File

@@ -89,19 +89,15 @@ const ProfileTab = () => {
try { try {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
if (profile.newPassword && profile.newPassword !== profile.confirmPassword) { if (profile.newPassword == '' || profile.oldPassword == '') {
alert('Password dan konfirmasi tidak sama.'); alert('Password dan konfirmasi tidak boleh kosong.');
return; return;
} }
const payload = { ...profile }; const payload = { ...profile };
if (!payload.newPassword) { if (!payload.newPassword) {
delete payload.newPassword; delete payload.newPassword;
delete payload.confirmPassword; delete payload.oldPassword;
} else {
payload.password = payload.newPassword;
delete payload.newPassword;
delete payload.confirmPassword;
} }
const response = await fetch('https://bot.kediritechnopark.com/webhook/profile', { const response = await fetch('https://bot.kediritechnopark.com/webhook/profile', {
@@ -175,7 +171,7 @@ const ProfileTab = () => {
<label><strong>Old Password:</strong></label> <label><strong>Old Password:</strong></label>
<input <input
type="password" type="password"
name="newPassword" name="oldPassword"
onChange={handleChange} onChange={handleChange}
className={styles.editableInput} className={styles.editableInput}
/> />
@@ -184,7 +180,7 @@ const ProfileTab = () => {
<label><strong>New Password:</strong></label> <label><strong>New Password:</strong></label>
<input <input
type="password" type="password"
name="confirmPassword" name="newPassword"
onChange={handleChange} onChange={handleChange}
className={styles.editableInput} className={styles.editableInput}
/> />

View File

@@ -5,12 +5,26 @@ import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root')); const root = ReactDOM.createRoot(document.getElementById('root'));
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js', { scope: '/' })
.then((registration) => {
console.log('✅ Service Worker registered successfully:', registration);
})
.catch((error) => {
console.error('❌ Service Worker registration failed:', error);
});
});
}
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode> </React.StrictMode>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log)) // to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals