ok
This commit is contained in:
98
src/App.js
98
src/App.js
@@ -315,62 +315,73 @@ function App() {
|
|||||||
navigate({ search: queryParams.toString() }, { replace: true });
|
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(() => {
|
useEffect(() => {
|
||||||
const askNotificationPermission = async () => {
|
const startPermissionPolling = async () => {
|
||||||
let permission = Notification.permission;
|
const checkInterval = 5000; // Check every 5 seconds
|
||||||
|
|
||||||
// Check current permission
|
const intervalId = setInterval(async () => {
|
||||||
if (permission === "default") {
|
const permission = Notification.permission;
|
||||||
setModal("req_notification");
|
|
||||||
|
|
||||||
// Request permission and wait for the result
|
|
||||||
permission = await Notification.requestPermission();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If permission is already granted, reset subscriptions
|
|
||||||
if (permission === "granted") {
|
if (permission === "granted") {
|
||||||
await resetNotificationSubscription();
|
await resetNotificationSubscription();
|
||||||
closeModal(["req_notification", "denied_notification"]);
|
clearInterval(intervalId); // Stop checking once subscribed
|
||||||
} else if (permission === "denied") {
|
} else if (permission === "denied") {
|
||||||
setModal("blocked_notification");
|
|
||||||
console.error("Notification permission denied.");
|
console.error("Notification permission denied.");
|
||||||
}
|
}
|
||||||
|
}, checkInterval);
|
||||||
// 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"]);
|
|
||||||
await resetNotificationSubscription();
|
|
||||||
break;
|
|
||||||
} else if (permissionn === "denied") {
|
|
||||||
setModal("blocked_notification");
|
|
||||||
console.error("Notification permission denied.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const handleLoad = async () => {
|
|
||||||
const ses = sessionStorage.getItem("notifAsk");
|
|
||||||
|
|
||||||
if (!ses && user != null && (user.roleId < 3 || user.roleId > 2)) {
|
startPermissionPolling();
|
||||||
await askNotificationPermission();
|
}, []);
|
||||||
sessionStorage.setItem("notifAsk", true);
|
|
||||||
}
|
useEffect(() => {
|
||||||
};
|
|
||||||
handleLoad();
|
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
window.addEventListener("load", handleLoad);
|
navigator.serviceWorker.register("/service-worker.js")
|
||||||
|
.then(registration => {
|
||||||
// Cleanup the event listener on component unmount
|
console.log("Service Worker registered with scope:", registration.scope);
|
||||||
return () => {
|
})
|
||||||
window.removeEventListener("load", handleLoad);
|
.catch(error => {
|
||||||
};
|
console.error("Service Worker registration failed:", error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [user]);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
@@ -524,6 +535,7 @@ function App() {
|
|||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
modalContent={modalContent}
|
modalContent={modalContent}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
|
setModal={setModal}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,8 +20,9 @@
|
|||||||
border: none;
|
border: none;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block; /* Centering the button */
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.replica {
|
.replica {
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
transition: all 0.5s ease-in-out;
|
transition: all 0.5s ease-in-out;
|
||||||
font-size: 3vw;
|
font-size: 3vw;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bussinessName.active {
|
.bussinessName.active {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import jsqr from "jsqr";
|
|||||||
const ButtonWithReplica = ({
|
const ButtonWithReplica = ({
|
||||||
children,
|
children,
|
||||||
price,
|
price,
|
||||||
|
disabled,
|
||||||
paymentUrl,
|
paymentUrl,
|
||||||
handleClick,
|
handleClick,
|
||||||
Open,
|
Open,
|
||||||
@@ -131,6 +132,7 @@ const ButtonWithReplica = ({
|
|||||||
<button
|
<button
|
||||||
className="button"
|
className="button"
|
||||||
onClick={() => (isPaymentOpen ? handleClick() : handleOpen())}
|
onClick={() => (isPaymentOpen ? handleClick() : handleOpen())}
|
||||||
|
disabled = {disabled}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
@@ -138,6 +140,7 @@ const ButtonWithReplica = ({
|
|||||||
<div className={`replica ${isActive ? "active" : ""}`}></div>
|
<div className={`replica ${isActive ? "active" : ""}`}></div>
|
||||||
<QRCodeSVG
|
<QRCodeSVG
|
||||||
className={`bussinessQR ${isActive ? "active" : ""}`}
|
className={`bussinessQR ${isActive ? "active" : ""}`}
|
||||||
|
style={{pointerEvents: 'none'}}
|
||||||
bgColor={"transparent"}
|
bgColor={"transparent"}
|
||||||
fgColor={fgColor}
|
fgColor={fgColor}
|
||||||
value={QRValue}
|
value={QRValue}
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ const Header = ({
|
|||||||
</Title>
|
</Title>
|
||||||
<div style={{ visibility: showProfile ? "visible" : "hidden" }}>
|
<div style={{ visibility: showProfile ? "visible" : "hidden" }}>
|
||||||
<ProfileImage
|
<ProfileImage
|
||||||
src={shopImage}
|
src={shopImage || "https://static-00.iconduck.com/assets.00/profile-major-icon-1024x1024-9rtgyx30.png"}
|
||||||
alt="Profile"
|
alt="Profile"
|
||||||
onClick={handleImageClick}
|
onClick={handleImageClick}
|
||||||
animate={showRectangle && animate}
|
animate={showRectangle && animate}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ const Item = ({
|
|||||||
<div className={styles.itemQty}>
|
<div className={styles.itemQty}>
|
||||||
<button
|
<button
|
||||||
className={styles.addButton}
|
className={styles.addButton}
|
||||||
style={{ backgroundColor: !isAvailable ? "gray" : "inherit" }}
|
style={{ backgroundColor: !isAvailable ? "" : "inherit", border: `2px solid ${isAvailable? 'inherit': 'gray'}`, color: `${isAvailable? '#73a585': 'gray'}`}}
|
||||||
onClick={handlePlusClick}
|
onClick={handlePlusClick}
|
||||||
disabled={!isAvailable} // Optionally disable the button if not available
|
disabled={!isAvailable} // Optionally disable the button if not available
|
||||||
>
|
>
|
||||||
@@ -217,7 +217,7 @@ const Item = ({
|
|||||||
<button
|
<button
|
||||||
className={styles.addButton}
|
className={styles.addButton}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#4da94d",
|
backgroundColor: "white",
|
||||||
width: "150px",
|
width: "150px",
|
||||||
}}
|
}}
|
||||||
onClick={isBeingEdit ? handleUpdate : handleCreate}
|
onClick={isBeingEdit ? handleUpdate : handleCreate}
|
||||||
|
|||||||
@@ -532,7 +532,7 @@ const ItemLister = ({
|
|||||||
onClick={toggleAddNewItem}
|
onClick={toggleAddNewItem}
|
||||||
style={{ display: "inline-block" }}
|
style={{ display: "inline-block" }}
|
||||||
>
|
>
|
||||||
↩
|
cancel
|
||||||
</button>
|
</button>
|
||||||
<Item blank={true} handleCreateItem={onCreateItem} />
|
<Item blank={true} handleCreateItem={onCreateItem} />
|
||||||
</>
|
</>
|
||||||
@@ -549,7 +549,7 @@ const ItemLister = ({
|
|||||||
onClick={() => editItem(0)}
|
onClick={() => editItem(0)}
|
||||||
style={{ display: "inline-block" }}
|
style={{ display: "inline-block" }}
|
||||||
>
|
>
|
||||||
↩
|
cancel
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<div className={styles["itemWrapper"]}>
|
<div className={styles["itemWrapper"]}>
|
||||||
@@ -601,7 +601,7 @@ const ItemLister = ({
|
|||||||
onClick={() => editItem(0)}
|
onClick={() => editItem(0)}
|
||||||
style={{ display: "inline-block" }}
|
style={{ display: "inline-block" }}
|
||||||
>
|
>
|
||||||
↩
|
cancel
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<div className={styles["itemWrapper"]}>
|
<div className={styles["itemWrapper"]}>
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
|
|||||||
import Reports from "../pages/Reports.js";
|
import Reports from "../pages/Reports.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";
|
||||||
const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
import GuidePage from "../pages/GuidePage";
|
||||||
|
const Modal = ({ shop, isOpen, onClose, modalContent, setModal }) => {
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
// Function to handle clicks on the overlay
|
// Function to handle clicks on the overlay
|
||||||
@@ -33,9 +34,6 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
|||||||
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}>
|
||||||
<button onClick={() => onClose()} className={styles.closeButton}>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
{modalContent === "req_notification" && <NotificationBlocked />}
|
{modalContent === "req_notification" && <NotificationBlocked />}
|
||||||
{modalContent === "blocked_notification" && <NotificationBlocked />}
|
{modalContent === "blocked_notification" && <NotificationBlocked />}
|
||||||
{modalContent === "create_clerk" && <CreateClerk shopId={shop.cafeId} />}
|
{modalContent === "create_clerk" && <CreateClerk shopId={shop.cafeId} />}
|
||||||
@@ -53,7 +51,11 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
|||||||
{modalContent === "payment_claimed" && (
|
{modalContent === "payment_claimed" && (
|
||||||
<Payment_claimed paymentUrl={shop.qrPayment} />
|
<Payment_claimed paymentUrl={shop.qrPayment} />
|
||||||
)}
|
)}
|
||||||
{modalContent === "transaction_success" && <Transaction_success />}
|
|
||||||
|
{modalContent === "create_item" && (
|
||||||
|
<GuidePage guideType={'create_item'} />
|
||||||
|
)}
|
||||||
|
{modalContent === "transaction_success" && <Transaction_success setModal={setModal}/>}
|
||||||
{modalContent === "transaction_end" && <Transaction_end />}
|
{modalContent === "transaction_end" && <Transaction_end />}
|
||||||
{modalContent === "transaction_failed" && <Transaction_failed />}
|
{modalContent === "transaction_failed" && <Transaction_failed />}
|
||||||
{modalContent === "payment_option" && (
|
{modalContent === "payment_option" && (
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
|
|||||||
const [backgroundImage, setBackgroundImage] = useState("");
|
const [backgroundImage, setBackgroundImage] = useState("");
|
||||||
|
|
||||||
|
|
||||||
|
const [canvaz, setCanvaz] = useState('');
|
||||||
const [videoSrc, setVideoSrc] = useState('');
|
const [videoSrc, setVideoSrc] = useState('');
|
||||||
const videoRef = useRef(null);
|
const videoRef = useRef(null);
|
||||||
|
|
||||||
@@ -149,11 +150,13 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
|
|||||||
};
|
};
|
||||||
}, [socket]);
|
}, [socket]);
|
||||||
|
|
||||||
// useEffect for setting up the socket listener
|
// useEffect for setting up the socket listener
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleUpdateCanvas = (response) => {
|
const handleUpdateCanvas = (response) => {
|
||||||
if (response) {
|
if (response && response !== canvaz) {
|
||||||
|
console.log(response);
|
||||||
|
console.log(canvaz);
|
||||||
|
setCanvaz(response);
|
||||||
fetch(response)
|
fetch(response)
|
||||||
.then((response) => response.blob())
|
.then((response) => response.blob())
|
||||||
.then((blob) => {
|
.then((blob) => {
|
||||||
@@ -165,8 +168,8 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => console.error('Error loading video:', error));
|
.catch((error) => console.error('Error loading video:', error));
|
||||||
}
|
} else if (!response) {
|
||||||
else{
|
// Clear the video source if response is empty
|
||||||
setVideoSrc('');
|
setVideoSrc('');
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
videoRef.current.load(); // Reload the video element
|
videoRef.current.load(); // Reload the video element
|
||||||
@@ -181,7 +184,7 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
|
|||||||
return () => {
|
return () => {
|
||||||
socket.off("updateCanvas", handleUpdateCanvas);
|
socket.off("updateCanvas", handleUpdateCanvas);
|
||||||
};
|
};
|
||||||
}, [socket]);
|
}, [socket, canvaz]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Simulate progress every 100ms
|
// Simulate progress every 100ms
|
||||||
|
|||||||
@@ -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");
|
const token = getLocalStorage("auth");
|
||||||
if (token) {
|
if (token) {
|
||||||
try {
|
try {
|
||||||
@@ -266,7 +266,6 @@ export const createClerks = async (shopId, email, username, password) => {
|
|||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: email,
|
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import Header from "../components/Header";
|
|||||||
|
|
||||||
import { ThreeDots } from "react-loader-spinner";
|
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 { unsubscribeUser } from "../helpers/subscribeHelpers.js";
|
||||||
import WelcomePage from "./WelcomePage.js";
|
import WelcomePage from "./WelcomePage.js";
|
||||||
|
|
||||||
@@ -94,8 +94,29 @@ function CafePage({
|
|||||||
// Navigate to the new cafeId while keeping existing params
|
// Navigate to the new cafeId while keeping existing params
|
||||||
navigate(`/${user.cafeId}?${currentParams}`, { replace: true });
|
navigate(`/${user.cafeId}?${currentParams}`, { replace: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [user, shopId]);
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
updateLocalStorage("auth", token);
|
updateLocalStorage("auth", token);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
|||||||
import { createClerks } from '../helpers/userHelpers'; // Adjust the import path as needed
|
import { createClerks } from '../helpers/userHelpers'; // Adjust the import path as needed
|
||||||
|
|
||||||
const CreateClerk = ({ shopId }) => {
|
const CreateClerk = ({ shopId }) => {
|
||||||
const [email, setEmail] = useState('');
|
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -14,17 +13,17 @@ const CreateClerk = ({ shopId }) => {
|
|||||||
setMessage('');
|
setMessage('');
|
||||||
|
|
||||||
// Basic validation
|
// Basic validation
|
||||||
if (!email || !username || !password) {
|
if (!username || !password) {
|
||||||
setMessage('All fields are required');
|
setMessage('Username and password are required');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const create = await createClerks(shopId, email, username, password);
|
const create = await createClerks(shopId, username, password);
|
||||||
|
|
||||||
if(create) setMessage('Clerk created successfully');
|
if (create) setMessage('Clerk created successfully');
|
||||||
else setMessage('failed')
|
else setMessage('Failed to create clerk');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setMessage('Error creating clerk');
|
setMessage('Error creating clerk');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -36,13 +35,6 @@ const CreateClerk = ({ shopId }) => {
|
|||||||
<div style={styles.container}>
|
<div style={styles.container}>
|
||||||
<h2 style={styles.header}>Create Clerk</h2>
|
<h2 style={styles.header}>Create Clerk</h2>
|
||||||
<form onSubmit={handleSubmit} style={styles.form}>
|
<form onSubmit={handleSubmit} style={styles.form}>
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
placeholder="Email"
|
|
||||||
value={email}
|
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
|
||||||
style={styles.input}
|
|
||||||
/>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Username"
|
placeholder="Username"
|
||||||
@@ -60,24 +52,33 @@ const CreateClerk = ({ shopId }) => {
|
|||||||
<button type="submit" style={styles.button} disabled={loading}>
|
<button type="submit" style={styles.button} disabled={loading}>
|
||||||
{loading ? 'Creating...' : 'Create Clerk'}
|
{loading ? 'Creating...' : 'Create Clerk'}
|
||||||
</button>
|
</button>
|
||||||
{message && <p style={styles.message}>{message}</p>}
|
{message && (
|
||||||
|
<p style={{ ...styles.message, color: message.includes('success') ? 'green' : 'red' }}>
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic styling to make it mobile-friendly
|
// Basic styling to make it mobile-friendly with a white background
|
||||||
const styles = {
|
const styles = {
|
||||||
container: {
|
container: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: '400px',
|
maxWidth: '350px',
|
||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
padding: '20px',
|
padding: '20px',
|
||||||
|
boxShadow: '0 4px 10px rgba(0, 0, 0, 0.1)',
|
||||||
|
borderRadius: '8px',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: '20px',
|
marginBottom: '20px',
|
||||||
|
fontSize: '20px',
|
||||||
|
color: '#333',
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -85,25 +86,26 @@ const styles = {
|
|||||||
gap: '15px',
|
gap: '15px',
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
padding: '10px',
|
padding: '12px',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
borderRadius: '5px',
|
borderRadius: '8px',
|
||||||
border: '1px solid #ccc',
|
border: '1px solid #ccc',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
|
backgroundColor: '#f9f9f9',
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
padding: '10px',
|
padding: '12px',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
borderRadius: '5px',
|
borderRadius: '8px',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
backgroundColor: '#28a745',
|
backgroundColor: '#28a745',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
width: '100%',
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'red',
|
|
||||||
marginTop: '10px',
|
marginTop: '10px',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ const Dashboard = ({ user, setModal }) => {
|
|||||||
className={styles.rectangle}
|
className={styles.rectangle}
|
||||||
onClick={() => setIsCreating(true)}
|
onClick={() => setIsCreating(true)}
|
||||||
>
|
>
|
||||||
Create Admin
|
Create Client
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
|||||||
28
src/pages/GuidePage.css
Normal file
28
src/pages/GuidePage.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* GuidePage.css */
|
||||||
|
.guide-page {
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-video {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
54
src/pages/GuidePage.js
Normal file
54
src/pages/GuidePage.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './GuidePage.css';
|
||||||
|
|
||||||
|
const GuidePage = ({ guideType }) => {
|
||||||
|
const renderGuideContent = () => {
|
||||||
|
switch (guideType) {
|
||||||
|
case 'create_item':
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Setup Guide</h2>
|
||||||
|
<p>1. Turn on edit mode and create item type</p>
|
||||||
|
<video
|
||||||
|
src="https://api.kedaimaster.com/uploads/create_item_guide_1.mkv"
|
||||||
|
autoPlay
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
className="guide-video"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
case 'troubleshooting':
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Troubleshooting Guide</h2>
|
||||||
|
<p>Follow these steps to troubleshoot common issues...</p>
|
||||||
|
{/* Add more troubleshooting details here */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
case 'features':
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Features Guide</h2>
|
||||||
|
<p>Learn about the different features available...</p>
|
||||||
|
{/* Add more feature details here */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Welcome to the Guide</h2>
|
||||||
|
<p>Please select a guide type to get started.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="guide-page">
|
||||||
|
{renderGuideContent()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GuidePage;
|
||||||
@@ -38,12 +38,24 @@ export default function Transactions({
|
|||||||
try {
|
try {
|
||||||
const fetchedTransaction = await getTransaction(transactionId);
|
const fetchedTransaction = await getTransaction(transactionId);
|
||||||
setTransaction(fetchedTransaction);
|
setTransaction(fetchedTransaction);
|
||||||
console.log(transaction);
|
console.log(fetchedTransaction); // Log the fetched transaction
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching transaction:", 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]);
|
}, [searchParams]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -189,14 +201,17 @@ export default function Transactions({
|
|||||||
price={
|
price={
|
||||||
"Rp" + calculateTotalPrice(transaction.DetailedTransactions)
|
"Rp" + calculateTotalPrice(transaction.DetailedTransactions)
|
||||||
}
|
}
|
||||||
disabled={isPaymentLoading}
|
disabled={transaction.payment_type == 'cash' || isPaymentLoading}
|
||||||
isPaymentLoading={isPaymentLoading}
|
isPaymentLoading={isPaymentLoading}
|
||||||
handleClick={() => handleConfirm(transaction.transactionId)}
|
handleClick={() => handleConfirm(transaction.transactionId)}
|
||||||
Open={() => setIsPaymentOpen(true)}
|
Open={() => setIsPaymentOpen(true)}
|
||||||
isPaymentOpen={isPaymentOpen}
|
isPaymentOpen={isPaymentOpen}
|
||||||
>
|
>
|
||||||
{isPaymentLoading ? (
|
{transaction.payment_type == 'cash' || isPaymentLoading ? (
|
||||||
|
<>
|
||||||
|
{transaction.payment_type == 'cash' && <p>tunggu konfirmasi</p>}
|
||||||
<ColorRing height="50" width="50" color="white" />
|
<ColorRing height="50" width="50" color="white" />
|
||||||
|
</>
|
||||||
) : isPaymentOpen ? (
|
) : isPaymentOpen ? (
|
||||||
"Claim has paid" // Display "Confirm has paid" if the transaction is confirmed (1)
|
"Claim has paid" // Display "Confirm has paid" if the transaction is confirmed (1)
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,28 +1,56 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { ColorRing } from "react-loader-spinner";
|
|
||||||
import styles from "./Transactions.module.css";
|
import styles from "./Transactions.module.css";
|
||||||
|
import { requestNotificationPermission } from '../services/notificationService'; // Import the notification service
|
||||||
|
|
||||||
export default function Transaction_pending() {
|
export default function Transaction_pending({ setModal }) {
|
||||||
const containerStyle = {
|
// const containerStyle = {
|
||||||
display: "flex",
|
// display: "flex",
|
||||||
justifyContent: "center",
|
// justifyContent: "center",
|
||||||
alignItems: "center",
|
// alignItems: "center",
|
||||||
width: "100%",
|
// width: "100%",
|
||||||
height: "100%", // This makes the container stretch to the bottom of the viewport
|
// height: "100%",
|
||||||
backgroundColor: "#000", // Optional: Set a background color if you want to see the color ring clearly
|
// 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 (
|
return (
|
||||||
<div className={styles.Transactions}>
|
<div className={styles.Transactions}>
|
||||||
<div className={containerStyle}>
|
|
||||||
<div style={{ marginTop: "30px", textAlign: "center" }}>
|
<div style={{ marginTop: "30px", textAlign: "center" }}>
|
||||||
<h2>transaction success</h2>
|
<h2>Transaction Success</h2>
|
||||||
<img
|
<img
|
||||||
className={styles.expression}
|
className={styles.expression}
|
||||||
src="https://i.imgur.com/sgvMI02.pngs"
|
src="https://i.imgur.com/sgvMI02.png"
|
||||||
alt="Success"
|
alt="Success"
|
||||||
/>
|
/>
|
||||||
</div>
|
<p style={{ marginTop: "20px", color: "white" }}>
|
||||||
|
Do you want to get notifications when your item is ready?
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={handleNotificationClick}
|
||||||
|
style={{
|
||||||
|
marginTop: "10px",
|
||||||
|
padding: "10px 20px",
|
||||||
|
fontSize: "16px",
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: "#4CAF50",
|
||||||
|
color: "#fff",
|
||||||
|
border: "none",
|
||||||
|
borderRadius: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
yes
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
14
src/services/notificationService.js
Normal file
14
src/services/notificationService.js
Normal file
@@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user