ok
This commit is contained in:
@@ -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}>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
14
src/index.js
14
src/index.js
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user