ok
This commit is contained in:
50
package-lock.json
generated
50
package-lock.json
generated
@@ -26,6 +26,7 @@
|
|||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.24.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-switch": "^7.0.0",
|
"react-switch": "^7.0.0",
|
||||||
|
"react-youtube": "^10.1.0",
|
||||||
"smooth-scroll-into-view-if-needed": "^2.0.2",
|
"smooth-scroll-into-view-if-needed": "^2.0.2",
|
||||||
"socket.io-client": "^4.7.5",
|
"socket.io-client": "^4.7.5",
|
||||||
"styled-components": "^6.1.11",
|
"styled-components": "^6.1.11",
|
||||||
@@ -13339,6 +13340,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/load-script": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA=="
|
||||||
|
},
|
||||||
"node_modules/loader-runner": {
|
"node_modules/loader-runner": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
|
||||||
@@ -16220,6 +16226,22 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-youtube": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "3.1.3",
|
||||||
|
"prop-types": "15.8.1",
|
||||||
|
"youtube-player": "5.5.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.x"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=0.14.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@@ -17084,6 +17106,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sister": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA=="
|
||||||
|
},
|
||||||
"node_modules/sisteransi": {
|
"node_modules/sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
@@ -19567,6 +19594,29 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-player": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^2.6.6",
|
||||||
|
"load-script": "^1.0.0",
|
||||||
|
"sister": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-player/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-player/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.24.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-switch": "^7.0.0",
|
"react-switch": "^7.0.0",
|
||||||
|
"react-youtube": "^10.1.0",
|
||||||
"smooth-scroll-into-view-if-needed": "^2.0.2",
|
"smooth-scroll-into-view-if-needed": "^2.0.2",
|
||||||
"socket.io-client": "^4.7.5",
|
"socket.io-client": "^4.7.5",
|
||||||
"styled-components": "^6.1.11",
|
"styled-components": "^6.1.11",
|
||||||
|
|||||||
12
src/App.js
12
src/App.js
@@ -208,6 +208,15 @@ function App() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const checkNotifications = () => {
|
||||||
|
let permission = Notification.permission;
|
||||||
|
|
||||||
|
// Check current permission
|
||||||
|
if (permission !== "granted") {
|
||||||
|
setModal("req_notification");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
socket.on("checkUserTokenRes", async (data) => {
|
socket.on("checkUserTokenRes", async (data) => {
|
||||||
if (data.status !== 200) {
|
if (data.status !== 200) {
|
||||||
removeLocalStorage("auth");
|
removeLocalStorage("auth");
|
||||||
@@ -226,7 +235,7 @@ function App() {
|
|||||||
console.log("getting guest side");
|
console.log("getting guest side");
|
||||||
setDeviceType("clerk");
|
setDeviceType("clerk");
|
||||||
|
|
||||||
// checkNotifications(data.data.user.userId);
|
checkNotifications();
|
||||||
} else {
|
} else {
|
||||||
setDeviceType("guestDevice");
|
setDeviceType("guestDevice");
|
||||||
}
|
}
|
||||||
@@ -315,6 +324,7 @@ function App() {
|
|||||||
navigate({ search: queryParams.toString() }, { replace: true });
|
navigate({ search: queryParams.toString() }, { replace: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// const askNotificationPermission = async () => {
|
// const askNotificationPermission = async () => {
|
||||||
// let permission = Notification.permission;
|
// let permission = Notification.permission;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import Payment_claimed from "../pages/Payment_claimed";
|
|||||||
import MaterialList from "../pages/MaterialList.js";
|
import MaterialList from "../pages/MaterialList.js";
|
||||||
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
|
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
|
||||||
import Reports from "../pages/Reports.js";
|
import Reports from "../pages/Reports.js";
|
||||||
|
import NotificationRequest from "../pages/NotificationRequest.js";
|
||||||
import NotificationBlocked from "../pages/NotificationBlocked.js";
|
import NotificationBlocked from "../pages/NotificationBlocked.js";
|
||||||
import WelcomePageEditor from "../pages/WelcomePageEditor.js";
|
import WelcomePageEditor from "../pages/WelcomePageEditor.js";
|
||||||
import GuidePage from "../pages/GuidePage";
|
import GuidePage from "../pages/GuidePage";
|
||||||
@@ -34,7 +35,7 @@ const Modal = ({ shop, isOpen, onClose, modalContent, setModal }) => {
|
|||||||
return (
|
return (
|
||||||
<div onClick={handleOverlayClick} className={styles.modalOverlay}>
|
<div onClick={handleOverlayClick} className={styles.modalOverlay}>
|
||||||
<div className={styles.modalContent} onClick={handleContentClick}>
|
<div className={styles.modalContent} onClick={handleContentClick}>
|
||||||
{modalContent === "req_notification" && <NotificationBlocked />}
|
{modalContent === "req_notification" && <NotificationRequest setModal={setModal} />}
|
||||||
{modalContent === "blocked_notification" && <NotificationBlocked />}
|
{modalContent === "blocked_notification" && <NotificationBlocked />}
|
||||||
{modalContent === "create_clerk" && <CreateClerk shopId={shop.cafeId} />}
|
{modalContent === "create_clerk" && <CreateClerk shopId={shop.cafeId} />}
|
||||||
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
|
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: -1px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.5);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
108
src/components/TrackPlayer.js
Normal file
108
src/components/TrackPlayer.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import YouTube from 'react-youtube';
|
||||||
|
|
||||||
|
export function TrackPlayer({ next }) {
|
||||||
|
// State to store the progress in milliseconds, video duration, and the next video ID
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
const [duration, setDuration] = useState(0);
|
||||||
|
const [currentTrack, setCurrentTrack] = useState(null); // Initial video ID
|
||||||
|
const [nextTrack, setNextTrack] = useState(null); // Initial video ID
|
||||||
|
const [isNearEnd, setIsNearEnd] = useState(false); // Flag for 20 seconds left
|
||||||
|
const playerRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (next == null) return;
|
||||||
|
if (currentTrack == null) setCurrentTrack(next);
|
||||||
|
setNextTrack(next);
|
||||||
|
}, [next]);
|
||||||
|
|
||||||
|
const handlePlayerStateChange = (event) => {
|
||||||
|
if (event.data === window.YT.PlayerState.PLAYING) {
|
||||||
|
|
||||||
|
// Start tracking progress once the video starts playing
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (playerRef.current) {
|
||||||
|
const currentTime = playerRef.current.getCurrentTime(); // Get current time in seconds
|
||||||
|
setProgress(currentTime * 1000); // Convert to milliseconds
|
||||||
|
// Check if the video is 20 seconds from ending
|
||||||
|
if (currentTime >= duration / 1000 - 20 && !isNearEnd) {
|
||||||
|
setIsNearEnd(true);
|
||||||
|
} else if (currentTime < duration / 1000 - 20 && isNearEnd) {
|
||||||
|
setIsNearEnd(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100); // Update every 100 ms
|
||||||
|
|
||||||
|
// Clean up when the video is paused or finished
|
||||||
|
event.target.addEventListener('onStateChange', (e) => {
|
||||||
|
if (e.data === window.YT.PlayerState.PAUSED || e.data === window.YT.PlayerState.ENDED) {
|
||||||
|
clearInterval(interval);
|
||||||
|
|
||||||
|
// When the video ends, set the next track
|
||||||
|
if (e.data === window.YT.PlayerState.ENDED) {
|
||||||
|
// Logic to set the next video ID (for now, just updating to another static video)
|
||||||
|
setCurrentTrack(nextTrack); // Replace 'newVideoId' with the ID of the next video you want
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlayerReady = (event) => {
|
||||||
|
playerRef.current = event.target;
|
||||||
|
const durationInSeconds = playerRef.current.getDuration(); // Get video duration in seconds
|
||||||
|
setDuration(durationInSeconds * 1000); // Set the duration in milliseconds
|
||||||
|
|
||||||
|
// Set the video quality to the lowest available (typically 360p or smaller)
|
||||||
|
playerRef.current.setPlaybackQuality('small');
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Make sure to load the YouTube iframe API script when the component mounts
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = 'https://www.youtube.com/iframe_api';
|
||||||
|
document.body.appendChild(script);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// Cleanup if needed (for example, removing the script)
|
||||||
|
document.body.removeChild(script);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// When the currentTrack changes, reset progress and duration
|
||||||
|
setProgress(0);
|
||||||
|
setDuration(0);
|
||||||
|
setIsNearEnd(false);
|
||||||
|
}, [currentTrack]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="App" style={{visibility: 'hidden', position: 'fixed'}}>
|
||||||
|
{currentTrack != null && (
|
||||||
|
<div>
|
||||||
|
<YouTube
|
||||||
|
videoId={currentTrack.videoId} // Dynamically change video based on currentTrack
|
||||||
|
opts={{
|
||||||
|
height: '315',
|
||||||
|
width: '560',
|
||||||
|
playerVars: {
|
||||||
|
autoplay: 1,
|
||||||
|
controls: 1,
|
||||||
|
mute: 0,
|
||||||
|
loop: 0, // Do not loop; handle next video manually
|
||||||
|
quality: 'small', // Request small quality (360p or lower)
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onReady={handlePlayerReady} // Get duration and set quality on ready
|
||||||
|
onStateChange={handlePlayerStateChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div>Progress: {progress} ms</div>
|
||||||
|
<div>Video Duration: {duration} ms</div>
|
||||||
|
<div>
|
||||||
|
{isNearEnd && <div>Video is near the end (20 seconds left)</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -59,8 +59,8 @@ const Dashboard = ({ user, setModal }) => {
|
|||||||
if (user.roleId < 1) {
|
if (user.roleId < 1) {
|
||||||
// Create admin functionality
|
// Create admin functionality
|
||||||
createCafeOwner(newItem.email, newItem.username, newItem.password)
|
createCafeOwner(newItem.email, newItem.username, newItem.password)
|
||||||
.then(() => {
|
.then((newitem) => {
|
||||||
setItems([...items, { name: newItem.username }]);
|
setItems([...items, { userId: newitem.userId, name: newitem.username }]);
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
setNewItem({ name: "", type: "" });
|
setNewItem({ name: "", type: "" });
|
||||||
})
|
})
|
||||||
@@ -70,8 +70,8 @@ const Dashboard = ({ user, setModal }) => {
|
|||||||
} else {
|
} else {
|
||||||
// Create cafe functionality
|
// Create cafe functionality
|
||||||
createCafe(newItem.name)
|
createCafe(newItem.name)
|
||||||
.then(() => {
|
.then((newitem) => {
|
||||||
setItems([...items, { name: newItem.name }]);
|
setItems([...items, { cafeId: newitem.cafeId, name: newitem.name }]);
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
setNewItem({ name: "", type: "" });
|
setNewItem({ name: "", type: "" });
|
||||||
})
|
})
|
||||||
@@ -126,8 +126,7 @@ const Dashboard = ({ user, setModal }) => {
|
|||||||
className={styles.rectangle}
|
className={styles.rectangle}
|
||||||
>
|
>
|
||||||
<h1>{item.name || item.username}</h1>
|
<h1>{item.name || item.username}</h1>
|
||||||
|
<div><h1>{item.report?.totalIncome}</h1></div>
|
||||||
<div><h1>{item.report.totalIncome}</h1><h1>{item.report.totalIncome}</h1></div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{user && user.roleId < 1 ? (
|
{user && user.roleId < 1 ? (
|
||||||
|
|||||||
@@ -3,27 +3,42 @@ import React from "react";
|
|||||||
const NotificationBlocked = () => {
|
const NotificationBlocked = () => {
|
||||||
return (
|
return (
|
||||||
<div style={styles.container}>
|
<div style={styles.container}>
|
||||||
<h2 style={styles.header}>Heads Up! Notifications Are Off</h2>
|
<h2 style={styles.header}>Notifikasi Terblokir</h2>
|
||||||
<p style={styles.message}>
|
<p style={styles.message}>
|
||||||
It looks like you’ve got notifications turned off. Turning them on will
|
Sepertinya notifikasi untuk situs ini tidak aktif. Aktifkan notifikasi supaya kamu tetap dapat info pesanan, meski sedang buka aplikasi lain.
|
||||||
make sure you get important updates, like new orders or alerts, right on
|
</p>
|
||||||
your device.
|
<p style={styles.message}>
|
||||||
|
Berikut cara mengaktifkannya:
|
||||||
</p>
|
</p>
|
||||||
<h3 style={styles.instructionsHeader}>Here’s how to turn them on:</h3>
|
|
||||||
<ol style={styles.instructions}>
|
<ol style={styles.instructions}>
|
||||||
<li>Open Chrome and go to our café's website.</li>
|
|
||||||
<li>Tap the menu (three dots) in the top-right corner.</li>
|
|
||||||
<li>
|
<li>
|
||||||
Go to <strong>Settings</strong> > <strong>Site settings</strong>{" "}
|
Klik ikon{" "}
|
||||||
> <strong>Notifications</strong>.
|
<span style={styles.icon}>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="#000000"
|
||||||
|
style={{ verticalAlign: "middle", display: "inline-block" }}
|
||||||
|
>
|
||||||
|
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
|
||||||
|
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
|
||||||
|
<g id="SVGRepo_iconCarrier">
|
||||||
|
<path
|
||||||
|
fill="#000000"
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M4,8 C5.240909,8 6.30584855,8.75341602 6.76233298,9.8277624 L6.82929,10 L14,10 C14.5523,10 15,10.4477 15,11 C15,11.51285 14.613973,11.9355092 14.1166239,11.9932725 L14,12 L6.82929,12 C6.41746,13.1652 5.30622,14 4,14 C2.34315,14 1,12.6569 1,11 C1,9.34315 2.34315,8 4,8 Z M4,10 C3.44772,10 3,10.4477 3,11 C3,11.5523 3.44772,12 4,12 C4.55228,12 5,11.5523 5,11 C5,10.4477 4.55228,10 4,10 Z M12,2 C13.6569,2 15,3.34315 15,5 C15,6.65685 13.6569,8 12,8 C10.75911,8 9.69415335,7.24658397 9.23766716,6.1722376 L9.17071,6 L2,6 C1.44772,6 1,5.55228 1,5 C1,4.48716857 1.38604429,4.06449347 1.88337975,4.0067278 L2,4 L9.17071,4 C9.58254,2.83481 10.6938,2 12,2 Z M12,4 C11.4477,4 11,4.44772 11,5 C11,5.55228 11.4477,6 12,6 C12.5523,6 13,5.55228 13,5 C13,4.44772 12.5523,4 12,4 Z"
|
||||||
|
></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>{" "}
|
||||||
|
di pojok kiri atas
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Find our café in the list and set it to <strong>Allow</strong>.
|
Pilih <strong>Izin</strong> > <strong>Notifikasi</strong> > <strong>Izinkan Notifikasi</strong>.
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p style={styles.footer}>
|
<p style={styles.footer}>
|
||||||
Once you’ve turned on notifications, you’ll start getting updates
|
Setelah itu, kamu bisa terus dapet informasi pesanan meski gak lagi buka situs ini.
|
||||||
instantly. Need a hand? Just ask!
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -44,11 +59,7 @@ const styles = {
|
|||||||
color: "#e74c3c",
|
color: "#e74c3c",
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
marginBottom: "20px",
|
marginBottom: "15px",
|
||||||
},
|
|
||||||
instructionsHeader: {
|
|
||||||
marginTop: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
},
|
},
|
||||||
instructions: {
|
instructions: {
|
||||||
listStyleType: "decimal",
|
listStyleType: "decimal",
|
||||||
@@ -59,6 +70,13 @@ const styles = {
|
|||||||
marginTop: "20px",
|
marginTop: "20px",
|
||||||
fontStyle: "italic",
|
fontStyle: "italic",
|
||||||
},
|
},
|
||||||
|
icon: {
|
||||||
|
display: "inline-block",
|
||||||
|
verticalAlign: "middle",
|
||||||
|
width: "20px",
|
||||||
|
height: "20px",
|
||||||
|
marginBottom: '6px'
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NotificationBlocked;
|
export default NotificationBlocked;
|
||||||
|
|||||||
57
src/pages/NotificationRequest.js
Normal file
57
src/pages/NotificationRequest.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import React from "react";
|
||||||
|
import styles from "./Transactions.module.css";
|
||||||
|
import { requestNotificationPermission } from '../services/notificationService'; // Import the notification service
|
||||||
|
|
||||||
|
export default function Transaction_pending({ setModal }) {
|
||||||
|
// const containerStyle = {
|
||||||
|
// display: "flex",
|
||||||
|
// justifyContent: "center",
|
||||||
|
// alignItems: "center",
|
||||||
|
// width: "100%",
|
||||||
|
// height: "100%",
|
||||||
|
// backgroundColor: "",
|
||||||
|
// };
|
||||||
|
|
||||||
|
const handleNotificationClick = async () => {
|
||||||
|
const permission = await requestNotificationPermission();
|
||||||
|
|
||||||
|
if (permission === "granted") {
|
||||||
|
console.log("Notification permission granted.");
|
||||||
|
// Set up notifications or show a success modal
|
||||||
|
} else {
|
||||||
|
console.error("Notification permission denied.");
|
||||||
|
setModal('blocked_notification'); // Show modal for blocked notifications
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.Transactions}>
|
||||||
|
<div style={{ marginTop: "30px", textAlign: "center" }}>
|
||||||
|
<h2>Aktifkan Notifikasi</h2>
|
||||||
|
<img
|
||||||
|
className={styles.expression}
|
||||||
|
src="https://i.imgur.com/sgvMI02.png"
|
||||||
|
alt="Success"
|
||||||
|
/>
|
||||||
|
<p style={{ marginTop: "20px", color: "black" }}>
|
||||||
|
Sepertinya notifikasi untuk situs ini tidak aktif. Aktifkan notifikasi supaya kamu tetap dapat info pesanan, meski sedang buka aplikasi lain.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={handleNotificationClick}
|
||||||
|
style={{
|
||||||
|
marginTop: "10px",
|
||||||
|
padding: "10px 20px",
|
||||||
|
fontSize: "16px",
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: "#4CAF50",
|
||||||
|
color: "#fff",
|
||||||
|
border: "none",
|
||||||
|
borderRadius: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Aktifkan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user