From 1ecc6db645458f25e5be2f0aa5f0ff7251930a3c Mon Sep 17 00:00:00 2001 From: zadit <75159257+insvrgent@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:05:30 +0700 Subject: [PATCH] ok --- src/App.js | 106 +++++++++++++++------------ src/components/ButtonWithReplica.css | 4 +- src/components/ButtonWithReplica.js | 3 + src/components/Header.js | 2 +- src/components/Item.js | 4 +- src/components/ItemLister.js | 6 +- src/components/Modal.js | 12 +-- src/components/MusicPlayer.js | 63 ++++++++-------- src/helpers/userHelpers.js | 3 +- src/pages/CafePage.js | 35 +++++++-- src/pages/CreateClerk.js | 44 +++++------ src/pages/Dashboard.js | 2 +- src/pages/GuidePage.css | 28 +++++++ src/pages/GuidePage.js | 54 ++++++++++++++ src/pages/Transaction_confirmed.js | 23 +++++- src/pages/Transaction_success.js | 54 ++++++++++---- src/services/notificationService.js | 14 ++++ 17 files changed, 320 insertions(+), 137 deletions(-) create mode 100644 src/pages/GuidePage.css create mode 100644 src/pages/GuidePage.js create mode 100644 src/services/notificationService.js diff --git a/src/App.js b/src/App.js index 22c32c7..90f51b5 100644 --- a/src/App.js +++ b/src/App.js @@ -315,63 +315,74 @@ function App() { navigate({ search: queryParams.toString() }, { replace: true }); } }; - + // useEffect(() => { + // const askNotificationPermission = async () => { + // let permission = Notification.permission; + + // // Check current permission + // if (permission === "default") { + // setModal("req_notification"); + + // // Request permission and wait for the result + // permission = await Notification.requestPermission(); + // } + + // // Handle permission results + // if (permission === "granted") { + // await resetNotificationSubscription(); + // closeModal(["req_notification", "denied_notification"]); + // } else if (permission === "denied") { + // setModal("blocked_notification"); + // console.error("Notification permission denied."); + // } + // }; + + // const handleTransactionConfirmed = async (data) => { + // console.log("transaction notification", data); + // await askNotificationPermission(); + // setModal("transaction_success", data); + // }; + + // // Add socket listener for transaction confirmations + // socket.on("transaction_success", handleTransactionConfirmed); + + // // Cleanup the socket listener on component unmount + // return () => { + // socket.off("transaction_success", handleTransactionConfirmed); + // }; + // }, [user]); + useEffect(() => { - const askNotificationPermission = async () => { - let permission = Notification.permission; + const startPermissionPolling = async () => { + const checkInterval = 5000; // Check every 5 seconds - // Check current permission - if (permission === "default") { - setModal("req_notification"); + const intervalId = setInterval(async () => { + const permission = Notification.permission; - // Request permission and wait for the result - permission = await Notification.requestPermission(); - } - - // If permission is already granted, reset subscriptions - if (permission === "granted") { - await resetNotificationSubscription(); - closeModal(["req_notification", "denied_notification"]); - } else if (permission === "denied") { - setModal("blocked_notification"); - console.error("Notification permission denied."); - } - - // Continuously check until permission is granted - while (permission !== "granted") { - await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for 1 second - const permissionn = Notification.permission; - - if (permissionn === "granted") { - closeModal(["req_notification", "denied_notification"]); + if (permission === "granted") { await resetNotificationSubscription(); - break; - } else if (permissionn === "denied") { - setModal("blocked_notification"); + clearInterval(intervalId); // Stop checking once subscribed + } else if (permission === "denied") { console.error("Notification permission denied."); - break; } - } + }, checkInterval); }; - const handleLoad = async () => { - const ses = sessionStorage.getItem("notifAsk"); - if (!ses && user != null && (user.roleId < 3 || user.roleId > 2)) { - await askNotificationPermission(); - sessionStorage.setItem("notifAsk", true); - } - }; - handleLoad(); + startPermissionPolling(); + }, []); + + useEffect(() => { if ("serviceWorker" in navigator) { - window.addEventListener("load", handleLoad); - - // Cleanup the event listener on component unmount - return () => { - window.removeEventListener("load", handleLoad); - }; + navigator.serviceWorker.register("/service-worker.js") + .then(registration => { + console.log("Service Worker registered with scope:", registration.scope); + }) + .catch(error => { + console.error("Service Worker registration failed:", error); + }); } - }, [user]); - + }, []); + return (
); diff --git a/src/components/ButtonWithReplica.css b/src/components/ButtonWithReplica.css index 5fad701..9f8872b 100644 --- a/src/components/ButtonWithReplica.css +++ b/src/components/ButtonWithReplica.css @@ -20,8 +20,9 @@ border: none; margin: 0 auto; cursor: pointer; - display: block; /* Centering the button */ + align-items: center; text-align: center; + display: inline-flex; } .replica { @@ -59,6 +60,7 @@ transition: all 0.5s ease-in-out; font-size: 3vw; text-align: center; + pointer-events: none; } .bussinessName.active { diff --git a/src/components/ButtonWithReplica.js b/src/components/ButtonWithReplica.js index 3198a47..d014b11 100644 --- a/src/components/ButtonWithReplica.js +++ b/src/components/ButtonWithReplica.js @@ -8,6 +8,7 @@ import jsqr from "jsqr"; const ButtonWithReplica = ({ children, price, + disabled, paymentUrl, handleClick, Open, @@ -131,6 +132,7 @@ const ButtonWithReplica = ({ @@ -138,6 +140,7 @@ const ButtonWithReplica = ({
@@ -549,7 +549,7 @@ const ItemLister = ({ onClick={() => editItem(0)} style={{ display: "inline-block" }} > - ↩ + cancel )}
@@ -601,7 +601,7 @@ const ItemLister = ({ onClick={() => editItem(0)} style={{ display: "inline-block" }} > - ↩ + cancel )}
diff --git a/src/components/Modal.js b/src/components/Modal.js index b95e3f1..bcc9236 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.js @@ -16,7 +16,8 @@ import MaterialMutationsPage from "../pages/MaterialMutationsPage.js"; import Reports from "../pages/Reports.js"; import NotificationBlocked from "../pages/NotificationBlocked.js"; import WelcomePageEditor from "../pages/WelcomePageEditor.js"; -const Modal = ({ shop, isOpen, onClose, modalContent }) => { +import GuidePage from "../pages/GuidePage"; +const Modal = ({ shop, isOpen, onClose, modalContent, setModal }) => { if (!isOpen) return null; // Function to handle clicks on the overlay @@ -33,9 +34,6 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => { return (
- {modalContent === "req_notification" && } {modalContent === "blocked_notification" && } {modalContent === "create_clerk" && } @@ -53,7 +51,11 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => { {modalContent === "payment_claimed" && ( )} - {modalContent === "transaction_success" && } + + {modalContent === "create_item" && ( + + )} + {modalContent === "transaction_success" && } {modalContent === "transaction_end" && } {modalContent === "transaction_failed" && } {modalContent === "payment_option" && ( diff --git a/src/components/MusicPlayer.js b/src/components/MusicPlayer.js index fb554bc..73e07fa 100644 --- a/src/components/MusicPlayer.js +++ b/src/components/MusicPlayer.js @@ -29,6 +29,7 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) { const [backgroundImage, setBackgroundImage] = useState(""); + const [canvaz, setCanvaz] = useState(''); const [videoSrc, setVideoSrc] = useState(''); const videoRef = useRef(null); @@ -148,40 +149,42 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) { socket.off("searchResponse"); }; }, [socket]); + +// useEffect for setting up the socket listener +useEffect(() => { + const handleUpdateCanvas = (response) => { + if (response && response !== canvaz) { + console.log(response); + console.log(canvaz); + setCanvaz(response); + fetch(response) + .then((response) => response.blob()) + .then((blob) => { + const blobUrl = URL.createObjectURL(blob); + setVideoSrc(blobUrl); - // useEffect for setting up the socket listener - useEffect(() => { - const handleUpdateCanvas = (response) => { - if (response) { - - fetch(response) - .then((response) => response.blob()) - .then((blob) => { - const blobUrl = URL.createObjectURL(blob); - setVideoSrc(blobUrl); - - if (videoRef.current) { - videoRef.current.load(); // Reload the video element - } - }) - .catch((error) => console.error('Error loading video:', error)); + if (videoRef.current) { + videoRef.current.load(); // Reload the video element + } + }) + .catch((error) => console.error('Error loading video:', error)); + } else if (!response) { + // Clear the video source if response is empty + setVideoSrc(''); + if (videoRef.current) { + videoRef.current.load(); // Reload the video element } - else{ - setVideoSrc(''); - if (videoRef.current) { - videoRef.current.load(); // Reload the video element - } - } - }; + } + }; - // Listen for the "updateCanvas" event - socket.on("updateCanvas", handleUpdateCanvas); + // Listen for the "updateCanvas" event + socket.on("updateCanvas", handleUpdateCanvas); - // Clean up the socket listener when the component is unmounted - return () => { - socket.off("updateCanvas", handleUpdateCanvas); - }; - }, [socket]); + // Clean up the socket listener when the component is unmounted + return () => { + socket.off("updateCanvas", handleUpdateCanvas); + }; +}, [socket, canvaz]); useEffect(() => { // Simulate progress every 100ms diff --git a/src/helpers/userHelpers.js b/src/helpers/userHelpers.js index a420179..941e100 100644 --- a/src/helpers/userHelpers.js +++ b/src/helpers/userHelpers.js @@ -253,7 +253,7 @@ export const deleteCafeOwner = async (shopId, email, username, password) => { } }; -export const createClerks = async (shopId, email, username, password) => { +export const createClerks = async (shopId, username, password) => { const token = getLocalStorage("auth"); if (token) { try { @@ -266,7 +266,6 @@ export const createClerks = async (shopId, email, username, password) => { Authorization: `Bearer ${token}`, }, body: JSON.stringify({ - email: email, username: username, password: password, }), diff --git a/src/pages/CafePage.js b/src/pages/CafePage.js index 0138677..44f0bb5 100644 --- a/src/pages/CafePage.js +++ b/src/pages/CafePage.js @@ -20,7 +20,7 @@ import Header from "../components/Header"; import { ThreeDots } from "react-loader-spinner"; -import { updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers"; +import { getLocalStorage, updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers"; import { unsubscribeUser } from "../helpers/subscribeHelpers.js"; import WelcomePage from "./WelcomePage.js"; @@ -94,8 +94,29 @@ function CafePage({ // Navigate to the new cafeId while keeping existing params navigate(`/${user.cafeId}?${currentParams}`, { replace: true }); } + }, [user, shopId]); + useEffect(() => { + function fetchData() { + console.log(user.userId == shopOwnerId) + setModal("create_item"); + + } + console.log(getLocalStorage('auth')) + if (getLocalStorage("auth") != null) { + const executeFetch = async () => { + while (user.length == 0) { + await new Promise((resolve) => setTimeout(resolve, 100)); // Wait until the user is not null + } + console.log(user) + console.log('open') + if (user.length != 0 && user.userId == shopOwnerId && shopItems.length == 0) fetchData(); + }; + executeFetch(); + } + }, [user, shopItems]); + useEffect(() => { if (token) { updateLocalStorage("auth", token); @@ -172,12 +193,12 @@ function CafePage({ setIsEditMode={(e) => setIsEditMode(e)} isEditMode={isEditMode} /> - + { - const [email, setEmail] = useState(''); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [loading, setLoading] = useState(false); @@ -14,17 +13,17 @@ const CreateClerk = ({ shopId }) => { setMessage(''); // Basic validation - if (!email || !username || !password) { - setMessage('All fields are required'); + if (!username || !password) { + setMessage('Username and password are required'); setLoading(false); return; } try { - const create = await createClerks(shopId, email, username, password); + const create = await createClerks(shopId, username, password); - if(create) setMessage('Clerk created successfully'); - else setMessage('failed') + if (create) setMessage('Clerk created successfully'); + else setMessage('Failed to create clerk'); } catch (error) { setMessage('Error creating clerk'); } finally { @@ -36,13 +35,6 @@ const CreateClerk = ({ shopId }) => {

Create Clerk

- setEmail(e.target.value)} - style={styles.input} - /> { - {message &&

{message}

} + {message && ( +

+ {message} +

+ )}
); }; -// Basic styling to make it mobile-friendly +// Basic styling to make it mobile-friendly with a white background const styles = { container: { + backgroundColor: '#fff', width: '100%', - maxWidth: '400px', + maxWidth: '350px', margin: '0 auto', padding: '20px', + boxShadow: '0 4px 10px rgba(0, 0, 0, 0.1)', + borderRadius: '8px', boxSizing: 'border-box', }, header: { textAlign: 'center', marginBottom: '20px', + fontSize: '20px', + color: '#333', }, form: { display: 'flex', @@ -85,25 +86,26 @@ const styles = { gap: '15px', }, input: { - padding: '10px', + padding: '12px', fontSize: '16px', - borderRadius: '5px', + borderRadius: '8px', border: '1px solid #ccc', width: '100%', boxSizing: 'border-box', + backgroundColor: '#f9f9f9', }, button: { - padding: '10px', + padding: '12px', fontSize: '16px', - borderRadius: '5px', + borderRadius: '8px', border: 'none', backgroundColor: '#28a745', color: 'white', cursor: 'pointer', + width: '100%', }, message: { textAlign: 'center', - color: 'red', marginTop: '10px', }, }; diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js index 02cd652..fed3d60 100644 --- a/src/pages/Dashboard.js +++ b/src/pages/Dashboard.js @@ -108,7 +108,7 @@ const Dashboard = ({ user, setModal }) => { className={styles.rectangle} onClick={() => setIsCreating(true)} > - Create Admin + Create Client
) : (
{ + const renderGuideContent = () => { + switch (guideType) { + case 'create_item': + return ( +
+

Setup Guide

+

1. Turn on edit mode and create item type

+
+ ); + case 'troubleshooting': + return ( +
+

Troubleshooting Guide

+

Follow these steps to troubleshoot common issues...

+ {/* Add more troubleshooting details here */} +
+ ); + case 'features': + return ( +
+

Features Guide

+

Learn about the different features available...

+ {/* Add more feature details here */} +
+ ); + default: + return ( +
+

Welcome to the Guide

+

Please select a guide type to get started.

+
+ ); + } + }; + + return ( +
+ {renderGuideContent()} +
+ ); +}; + +export default GuidePage; diff --git a/src/pages/Transaction_confirmed.js b/src/pages/Transaction_confirmed.js index 5600dca..9ac8a5c 100644 --- a/src/pages/Transaction_confirmed.js +++ b/src/pages/Transaction_confirmed.js @@ -38,12 +38,24 @@ export default function Transactions({ try { const fetchedTransaction = await getTransaction(transactionId); setTransaction(fetchedTransaction); - console.log(transaction); + console.log(fetchedTransaction); // Log the fetched transaction } catch (error) { console.error("Error fetching transaction:", error); } }; - fetchData(); + + const waitForLocalStorage = async () => { + while (localStorage.getItem("auth") === null) { + await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second + } + }; + + const initialize = async () => { + await waitForLocalStorage(); + await fetchData(); + }; + + initialize(); }, [searchParams]); useEffect(() => { @@ -189,14 +201,17 @@ export default function Transactions({ price={ "Rp" + calculateTotalPrice(transaction.DetailedTransactions) } - disabled={isPaymentLoading} + disabled={transaction.payment_type == 'cash' || isPaymentLoading} isPaymentLoading={isPaymentLoading} handleClick={() => handleConfirm(transaction.transactionId)} Open={() => setIsPaymentOpen(true)} isPaymentOpen={isPaymentOpen} > - {isPaymentLoading ? ( + {transaction.payment_type == 'cash' || isPaymentLoading ? ( + <> + {transaction.payment_type == 'cash' &&

tunggu konfirmasi

} + ) : isPaymentOpen ? ( "Claim has paid" // Display "Confirm has paid" if the transaction is confirmed (1) ) : ( diff --git a/src/pages/Transaction_success.js b/src/pages/Transaction_success.js index 7a9b72d..f7033ea 100644 --- a/src/pages/Transaction_success.js +++ b/src/pages/Transaction_success.js @@ -1,29 +1,57 @@ import React from "react"; -import { ColorRing } from "react-loader-spinner"; import styles from "./Transactions.module.css"; +import { requestNotificationPermission } from '../services/notificationService'; // Import the notification service -export default function Transaction_pending() { - const containerStyle = { - display: "flex", - justifyContent: "center", - alignItems: "center", - width: "100%", - height: "100%", // This makes the container stretch to the bottom of the viewport - backgroundColor: "#000", // Optional: Set a background color if you want to see the color ring clearly +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 if (permission === "denied") { + console.error("Notification permission denied."); + setModal('blocked_notification'); // Show modal for blocked notifications + } }; return (
-
-

transaction success

+

Transaction Success

Success +

+ Do you want to get notifications when your item is ready? +

+
-
); } diff --git a/src/services/notificationService.js b/src/services/notificationService.js new file mode 100644 index 0000000..8dc0ff4 --- /dev/null +++ b/src/services/notificationService.js @@ -0,0 +1,14 @@ +// notificationService.js +export const requestNotificationPermission = async () => { + let permission = Notification.permission; + + // Check current permission + if (permission === "default") { + const result = await Notification.requestPermission(); + permission = result; // Update permission status + } + + // Return permission status + return permission; + }; + \ No newline at end of file