No Beats Ahead - Drop Your Hits
diff --git a/src/components/RouletteWheel.css b/src/components/RouletteWheel.css
deleted file mode 100644
index d6978a7..0000000
--- a/src/components/RouletteWheel.css
+++ /dev/null
@@ -1,94 +0,0 @@
-/* src/RouletteWheel.css */
-/* html,
-body,
-img {
- overflow: hidden;
-} */
-
-.roulette-wheel-container {
- position: fixed;
- left: 50%;
- /* Center the container horizontally */
- top: 30%;
- transform: translate(-40%, 20%);
- scale: 3;
- max-width: 100vw;
- /* Limit container width to viewport width */
- max-height: 100vh;
- /* Limit container height to viewport height */
- overflow: hidden;
- /* Hide overflowing content */
- display: flex;
- align-items: center;
- justify-content: center;
- pointer-events: none;
- -webkit-user-select: none;
- /* Safari */
- -ms-user-select: none;
- /* IE 10 and IE 11 */
- user-select: none;
- /* Standard syntax */
-}
-
-.roulette-wheel {
- width: 300px;
- height: 300px;
- display: flex;
- align-items: center;
- justify-content: center;
- pointer-events: auto;
- border-radius: 50%;
- transition: transform 0.2s ease-out;
-}
-
-.roulette-image {
- width: 200px;
- height: 200px;
- user-select: none;
- /* Prevents the image from being selected */
- pointer-events: none;
-}
-
-.roulette-input {
- position: absolute;
- width: 30%;
- /* Increase size for better visibility */
- height: auto;
- /* Increase size for better visibility */
- border: none;
- /* Remove border for simplicity */
- border-radius: 5px;
- /* Add border radius for rounded corners */
- color: rgb(2, 2, 2);
- /* Text color */
- font-size: 16px;
- /* Font size */
- border: 2px solid #ccc;
-}
-
-.roulette-button {
- z-index: 100;
- position: absolute;
- width: 30%;
- height: auto;
- border: none;
- border-radius: 5px;
- color: rgb(2, 2, 2);
- font-size: 16px;
- border: 2px solid #ccc;
- background-color: #fff;
-}
-
-.roulette-button:disabled {
- opacity: 0.6;
- cursor: not-allowed;
-}
-
-.roulette-button.error {
- background-color: red; /* Change button color on error */
- transition: background-color 0.5s ease-in-out;
-}
-
-.hidden {
- display: none;
-}
diff --git a/src/components/RouletteWheel.js b/src/components/RouletteWheel.js
deleted file mode 100644
index f54f9d3..0000000
--- a/src/components/RouletteWheel.js
+++ /dev/null
@@ -1,257 +0,0 @@
-import React, { useState, useRef, useEffect } from "react";
-import "./RouletteWheel.css";
-import coffeeImage from "./coffee.png"; // Update the path to your image
-
-import { ThreeDots } from "react-loader-spinner";
-
-const RouletteWheel = ({ isForRegister, onSignIn, onSignUp }) => {
- const [rotation, setRotation] = useState(0);
- const [isDragging, setIsDragging] = useState(false);
- const startAngleRef = useRef(0);
- const startRotationRef = useRef(0);
- const wheelRef = useRef(null);
-
- const [email, setEmail] = useState("");
- const [username, setUsername] = useState("");
- const [password, setPassword] = useState("");
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState(false);
-
- const emailInputRef = useRef(null);
- const usernameInputRef = useRef(null);
- const passwordInputRef = useRef(null);
-
- const handleSignIn = () => {
- setError(false); // Reset error state before login attempt
- onSignIn(email, username, password, setLoading, setError);
- };
-
- const handleSignUp = () => {
- setError(false); // Reset error state before login attempt
- onSignUp(email, username, password, setLoading, setError);
- };
- const handleStart = (x, y) => {
- setIsDragging(true);
- startAngleRef.current = getAngle(x, y);
- startRotationRef.current = rotation;
- };
-
- useEffect(() => {
- setError(false);
- }, [error]);
-
- const handleMove = (x, y) => {
- if (isDragging) {
- const angle = getAngle(x, y);
- const deltaAngle = angle - startAngleRef.current;
- setRotation(startRotationRef.current + deltaAngle);
- if (isForRegister) {
- if (rotation + deltaAngle > 30 || rotation + deltaAngle < -210)
- handleEnd();
- } else {
- if (rotation + deltaAngle > 30 || rotation + deltaAngle < -120)
- handleEnd();
- }
- }
- };
-
- const handleEnd = () => {
- setIsDragging(false);
- setRotation((prevRotation) => {
- const snappedRotation = Math.round(prevRotation / 90) * 90;
- return snappedRotation;
- });
- };
-
- const handleMouseDown = (e) => {
- handleStart(e.clientX, e.clientY);
- };
-
- const handleMouseMove = (e) => {
- handleMove(e.clientX, e.clientY);
- };
-
- const handleMouseUp = () => {
- handleEnd();
- };
-
- const handleTouchStart = (e) => {
- const touch = e.touches[0];
- handleStart(touch.clientX, touch.clientY);
- };
-
- const handleTouchMove = (e) => {
- if (!isDragging) return;
- e.preventDefault();
- const touch = e.touches[0];
- handleMove(touch.clientX, touch.clientY);
- };
-
- const handleTouchEnd = (e) => {
- handleEnd();
- };
-
- const handleChildMouseDown = (e) => {
- e.stopPropagation();
- };
-
- const handleChildTouchStart = (e) => {
- e.stopPropagation();
- };
-
- const getAngle = (x, y) => {
- const rect = wheelRef.current.getBoundingClientRect();
- const centerX = rect.left + rect.width / 2;
- const centerY = rect.top + rect.height / 2;
- const dx = x - centerX;
- const dy = y - centerY;
- return Math.atan2(dy, dx) * (180 / Math.PI);
- };
-
- useEffect(() => {
- if (isDragging) {
- document.addEventListener("mousemove", handleMouseMove);
- document.addEventListener("mouseup", handleMouseUp);
- document.addEventListener("touchmove", handleTouchMove, {
- passive: false,
- });
- document.addEventListener("touchend", handleTouchEnd, { passive: false });
- } else {
- document.removeEventListener("mousemove", handleMouseMove);
- document.removeEventListener("mouseup", handleMouseUp);
- document.removeEventListener("touchmove", handleTouchMove);
- document.removeEventListener("touchend", handleTouchEnd);
- }
-
- return () => {
- document.removeEventListener("mousemove", handleMouseMove);
- document.removeEventListener("mouseup", handleMouseUp);
- document.removeEventListener("touchmove", handleTouchMove);
- document.removeEventListener("touchend", handleTouchEnd);
- };
- }, [isDragging]);
-
- const inputPositions = [-90, 0, 90, 180]; // Positions for the inputs
-
- const isVisible = (angle) => {
- const modAngle = ((angle % 360) + 360) % 360;
- return modAngle % 90 === 0;
- };
-
- useEffect(() => {
- if (isForRegister) {
- if (isVisible(rotation % 360 !== -0)) {
- emailInputRef.current.focus();
- } else if (isVisible(rotation % 360 !== -90)) {
- usernameInputRef.current.focus();
- } else if (isVisible(rotation % 360 !== -180)) {
- passwordInputRef.current.focus();
- }
- } else {
- if (isVisible(rotation % 360 !== -0)) {
- usernameInputRef.current.focus();
- } else if (isVisible(rotation % 360 !== -90)) {
- passwordInputRef.current.focus();
- }
- }
- }, [rotation]);
-
- return (
-
- );
-};
-
-export default RouletteWheel;
diff --git a/src/components/TrackPlayer.js b/src/components/TrackPlayer.js
index 5e7a436..8374237 100644
--- a/src/components/TrackPlayer.js
+++ b/src/components/TrackPlayer.js
@@ -1,108 +1,39 @@
-import React, { useState, useEffect, useRef } from 'react';
+import React, { useState } 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);
+export function TrackPlayer({ next, queueList, setQueueList }) {
+ // Initial list of video IDs (YouTube video IDs)
+ const videos = [
+ 'dQw4w9WgXcQ', // Example Video 1
+ 'tgbNymZ7vqY', // Example Video 2
+ 'oHg5SJYRHA0', // Example Video 3
+ ];
- useEffect(() => {
- if (next == null) return;
- if (currentTrack == null) setCurrentTrack(next);
- setNextTrack(next);
- }, [next]);
+ // State to track the current video index
+ const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
- 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
- }
- }
- });
- }
+ // Function to handle video end event
+ const handleVideoEnd = () => {
+ // Update to next video or loop to the first video if at the end
+ setCurrentVideoIndex((prevIndex) => (prevIndex + 1) % videos.length);
};
- 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');
+ // YouTube video player options
+ const opts = {
+ height: '390',
+ width: '640',
+ playerVars: {
+ autoplay: 1, // Automatically play the video
+ },
};
- 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 (
-
- {currentTrack != null && (
-
-
-
- )}
-
Progress: {progress} ms
-
Video Duration: {duration} ms
-
- {isNearEnd &&
Video is near the end (20 seconds left)
}
-
+
+
);
-}
+};
diff --git a/src/helpers/transactionHelpers.js b/src/helpers/transactionHelpers.js
index b23b1bb..802399e 100644
--- a/src/helpers/transactionHelpers.js
+++ b/src/helpers/transactionHelpers.js
@@ -149,7 +149,7 @@ export async function getTransaction(transactionId) {
}
}
-export async function getMyTransactions(shopId, demand) {
+export async function getMyTransactions() {
try {
const token = getLocalStorage("auth");
const response = await fetch(
@@ -163,9 +163,6 @@ export async function getMyTransactions(shopId, demand) {
}
);
- if (!response.ok) {
- return false;
- }
const transactions = await response.json();
return transactions;
diff --git a/src/pages/CafePage.js b/src/pages/CafePage.js
index 2087a54..3c9d31c 100644
--- a/src/pages/CafePage.js
+++ b/src/pages/CafePage.js
@@ -40,6 +40,7 @@ function CafePage({
removeConnectedGuestSides,
setModal,
loading,
+ queue
}) {
const location = useLocation();
const [searchParams] = useSearchParams();
@@ -87,6 +88,7 @@ function CafePage({
}
checkWelcomePageConfig();
}, [welcomePageConfig]);
+
useEffect(() => {
if (user.cafeId != null && user.cafeId !== shopId) {
// Preserve existing query parameters
@@ -232,7 +234,9 @@ function CafePage({
socket={socket}
shopId={shopId}
user={user}
+ shopOwnerId={shopOwnerId}
isSpotifyNeedLogin={isSpotifyNeedLogin}
+ queue={queue}
/>
{
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(true);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [items, setItems] = useState([]);
+ const [isCreating, setIsCreating] = useState(false);
+ const [newItem, setNewItem] = useState({ name: "", type: "" });
+
+ useEffect(() => {
+ if (user && user.roleId === 0) {
+ setLoading(true);
+ getAllCafeOwner()
+ .then((data) => {
+ setItems(data);
+ setLoading(false);
+ })
+ .catch((error) => {
+ console.error("Error fetching cafe owners:", error);
+ setLoading(false);
+ });
+ }
+ if (user && user.roleId === 1) {
+ setLoading(true);
+ getOwnedCafes(user.userId)
+ .then((data) => {
+ setItems(data);
+ setLoading(false);
+ })
+ .catch((error) => {
+ console.error("Error fetching owned cafes:", error);
+ setLoading(false);
+ });
+ }
+ }, [user]);
+
+ const handleModalClose = () => {
+ setIsModalOpen(false);
+ };
+
+ const handleLogout = () => {
+ removeLocalStorage("auth");
+ unsubscribeUser();
+ navigate(0);
+ };
+
+ const handleCreateItem = () => {
+ if (user.roleId < 1) {
+ // Create admin functionality
+ createCafeOwner(newItem.email, newItem.username, newItem.password)
+ .then((newitem) => {
+ setItems([...items, { userId: newitem.userId, name: newitem.username }]);
+ setIsCreating(false);
+ setNewItem({ name: "", type: "" });
+ })
+ .catch((error) => {
+ console.error("Error creating admin:", error);
+ });
+ } else {
+ // Create cafe functionality
+ createCafe(newItem.name)
+ .then((newitem) => {
+ setItems([...items, { cafeId: newitem.cafeId, name: newitem.name }]);
+ setIsCreating(false);
+ setNewItem({ name: "", type: "" });
+ })
+ .catch((error) => {
+ console.error("Error creating cafe:", error);
+ });
+ }
+ };
+// function calculateCafeMetrics(cafes) {
+// let totalIncomeThisMonth = 0;
+// let totalIncomeLastMonth = 0;
+
+// cafes.forEach(cafe => {
+// const currentIncome = cafe.totalIncome;
+// const growth = cafe.growthIncome / 100;
+
+// // Hitung keuntungan bulan lalu
+// const lastMonthIncome = currentIncome / (1 + growth);
+
+// // Tambahkan ke total
+// totalIncomeThisMonth += currentIncome;
+// totalIncomeLastMonth += lastMonthIncome;
+// });
+
+// // Hitung growth total
+// const totalGrowth = ((totalIncomeThisMonth - totalIncomeLastMonth) / totalIncomeLastMonth) * 100;
+
+// return {
+// totalIncomeThisMonth,
+// totalIncomeLastMonth: totalIncomeLastMonth.toFixed(2),
+// totalGrowth: totalGrowth.toFixed(2)
+// };
+// }
+
+ return (
+ <>
+ setIsModalOpen(true)}
+ isLogout={handleLogout}
+ user={user}
+ showProfile={true}
+ setModal={setModal}
+ />
+ {user && user.roleId < 2 && (
+
+ {loading &&
}
+ {items.map((item, index) => (
+
navigate("/" + item.cafeId)}
+ className={styles.rectangle}
+ >
+
{item.name || item.username}
+
{item.report?.totalIncome}
+
+ ))}
+ {user && user.roleId < 1 ? (
+
setIsCreating(true)}
+ >
+ Create Client
+
+ ) : (
+
setIsCreating(true)}
+ >
+ +
+
+ )}
+
+ )}
+
+ {user.username && (
+
+ )}
+
+ {isCreating && (
+
+
Create New {user.roleId < 1 ? "Admin" : "Cafe"}
+ {user.roleId < 1 ?<>
+ setNewItem({ ...newItem, email: e.target.value })}
+ placeholder="email"
+ />
+ setNewItem({ ...newItem, username: e.target.value })}
+ placeholder="username"
+ />
+ setNewItem({ ...newItem, password: e.target.value })}
+ placeholder="Password"
+ />> :
+ setNewItem({ ...newItem, name: e.target.value })}
+ placeholder="Name"
+ />}
+
+
+
+ )}
+ >
+ );
+};
+
+export default Dashboard;
diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js
index dea637e..bd74237 100644
--- a/src/pages/Dashboard.js
+++ b/src/pages/Dashboard.js
@@ -1,22 +1,93 @@
-import React, { useState, useEffect } from "react";
-import styles from "./Dashboard.module.css"; // Import module CSS for styling
-import Header from "../components/Header";
+import React, { useState, useEffect } from 'react';
+import styles from './LinktreePage.module.css'; // Import the module.css file
+import { loginUser } from "../helpers/userHelpers";
+import { ThreeDots } from "react-loader-spinner";
import { useNavigate } from "react-router-dom";
-import AccountUpdateModal from "../components/AccountUpdateModal";
-import { removeLocalStorage } from "../helpers/localStorageHelpers";
+
+import { getLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
import { getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers";
import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers";
-
-import { ThreeDots } from "react-loader-spinner";
+import { getMyTransactions } from "../helpers/transactionHelpers";
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
-const Dashboard = ({ user, setModal }) => {
+import Header from '../components/Header';
+
+const LinktreePage = ({ user, setModal }) => {
const navigate = useNavigate();
- const [loading, setLoading] = useState(true);
- const [isModalOpen, setIsModalOpen] = useState(false);
+ const [inputtingPassword, setInputtingPassword] = useState(false);
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(false);
+
const [items, setItems] = useState([]);
const [isCreating, setIsCreating] = useState(false);
const [newItem, setNewItem] = useState({ name: "", type: "" });
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [expanded, setIsExpand] = useState(false);
+ const [expandedCafeId, setExpandedCafeId] = useState(null); // Track which cafe is expanded
+
+ const handleToggleExpand = (cafeId) => {
+ setExpandedCafeId(expandedCafeId === cafeId ? null : cafeId); // Toggle expand for a specific cafe
+ };
+
+ const handleMyTransactions = async () => {
+ try {
+ setError(false);
+ setLoading(true);
+ const response = await getMyTransactions();
+
+ if (response) {
+ console.log(response)
+ return response;
+ } else {
+ setError(true); // Trigger error state in the button
+ console.error('Login failed');
+ }
+ } catch (error) {
+ setError(true);
+ console.error('Error occurred while logging in:', error.message);
+ } finally {
+ setLoading(false); // Ensure loading state is cleared
+ }
+ };
+
+ const handleLogin = async () => {
+ try {
+ setError(false);
+ setLoading(true);
+ const response = await loginUser(username, password);
+
+ if (response.success) {
+ localStorage.setItem('auth', response.token);
+
+ if (response.cafeId !== null) {
+ window.location.href = response.cafeId;
+ } else {
+ let destination = '/';
+ window.location.href = destination;
+ }
+ } else {
+ setError(true); // Trigger error state in the button
+ console.error('Login failed');
+ }
+ } catch (error) {
+ setError(true);
+ console.error('Error occurred while logging in:', error.message);
+ } finally {
+ setLoading(false); // Ensure loading state is cleared
+ }
+ };
+
+ const handleModalClose = () => {
+ setIsModalOpen(false);
+ };
+
+ const handleLogout = () => {
+ removeLocalStorage("auth");
+ unsubscribeUser();
+ navigate(0);
+ };
useEffect(() => {
if (user && user.roleId === 0) {
@@ -43,18 +114,19 @@ const Dashboard = ({ user, setModal }) => {
setLoading(false);
});
}
+ if (user && user.roleId == 3) {
+ handleMyTransactions()
+ .then((data) => {
+ setItems(data);
+ setLoading(false);
+ })
+ .catch((error) => {
+ console.error("Error fetching owned cafes:", error);
+ setLoading(false);
+ });
+
+ }
}, [user]);
-
- const handleModalClose = () => {
- setIsModalOpen(false);
- };
-
- const handleLogout = () => {
- removeLocalStorage("auth");
- unsubscribeUser();
- navigate(0);
- };
-
const handleCreateItem = () => {
if (user.roleId < 1) {
// Create admin functionality
@@ -80,42 +152,10 @@ const Dashboard = ({ user, setModal }) => {
});
}
};
-// function calculateCafeMetrics(cafes) {
-// let totalIncomeThisMonth = 0;
-// let totalIncomeLastMonth = 0;
-
-// cafes.forEach(cafe => {
-// const currentIncome = cafe.totalIncome;
-// const growth = cafe.growthIncome / 100;
-
-// // Hitung keuntungan bulan lalu
-// const lastMonthIncome = currentIncome / (1 + growth);
-
-// // Tambahkan ke total
-// totalIncomeThisMonth += currentIncome;
-// totalIncomeLastMonth += lastMonthIncome;
-// });
-
-// // Hitung growth total
-// const totalGrowth = ((totalIncomeThisMonth - totalIncomeLastMonth) / totalIncomeLastMonth) * 100;
-
-// return {
-// totalIncomeThisMonth,
-// totalIncomeLastMonth: totalIncomeLastMonth.toFixed(2),
-// totalGrowth: totalGrowth.toFixed(2)
-// };
-// }
-
return (
- <>
- setIsModalOpen(true)}
- isLogout={handleLogout}
- user={user}
- showProfile={true}
- setModal={setModal}
- />
+
+ {/* SVG Icon */}
+
{user && user.roleId < 2 && (
{loading && }
@@ -146,49 +186,204 @@ const Dashboard = ({ user, setModal }) => {
)}
)}
+ {(user.length == 0 || user.roleId > 1) &&
+ <>
+
- {user.username && (
-
- )}
+
+ {/* Main Heading */}
+
+ COBA KEDAIMASTER
+
+
+
pemesanan langsung dari meja
+
pengelolaan pesanan dan keuangan
+
tentukan suasana musik
+
pengelolaan stok dan manajemen
+
jangan pernah ragukan pelanggan
+
+
+ diskon 0%
+
- {isCreating && (
-
-
Create New {user.roleId < 1 ? "Admin" : "Cafe"}
- {user.roleId < 1 ?<>
- setNewItem({ ...newItem, email: e.target.value })}
- placeholder="email"
- />
- setNewItem({ ...newItem, username: e.target.value })}
- placeholder="username"
- />
- setNewItem({ ...newItem, password: e.target.value })}
- placeholder="Password"
- />> :
- setNewItem({ ...newItem, name: e.target.value })}
- placeholder="Name"
- />}
-
-
-
- )}
- >
+ {/* Sub Heading */}
+
+ Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
+
+ {getLocalStorage('auth') == null &&
+
+
+ }
+ {/* Footer Links */}
+
+
+
+

e.target.src = '/fallback-image.png'}
+ />
+
+
+ {user.length != 0 &&
+
+
setIsExpand(!expanded)} className={styles.userInfoExpandButton}>
+ {!expanded ?
+
+ :
+
+
+ }
+
+
+
+
+ {items.map((item, index) => (
+
handleToggleExpand(item.cafeId)} key={index}>
+ {/* Render cafes */}
+
+
{item.name || item.username}
+
+
+ {/* Render transactions if the cafe is expanded */}
+ {expandedCafeId === item.cafeId && item.transactions && (
+
+ {item.transactions.map((transaction, transactionIndex) => (
+
+ {transaction.detailedTransactions && transaction.detailedTransactions.map((detailedTransaction, detailedTransactionIndex) => (
+
+
Quantity: {detailedTransaction.qty}
+ {detailedTransaction.Item && (
+
+
Item Name: {detailedTransaction.Item.name}
+
Price: {detailedTransaction.Item.price}
+
+ )}
+
+ ))}
+
+ ))}
+
+ )}
+
+ ))}
+
+
+
+
+ }
+
+ >
+ }
+
);
};
-export default Dashboard;
+export default LinktreePage;
diff --git a/src/pages/Join.js b/src/pages/Join.js
new file mode 100644
index 0000000..4a850b7
--- /dev/null
+++ b/src/pages/Join.js
@@ -0,0 +1,65 @@
+import React from 'react';
+import styles from './Join.module.css'; // Import the module.css file
+
+const LinktreePage = ({ data }) => {
+ return (
+
+
+
+ {/* Main Heading */}
+
+ Nikmati Kemudahan Mengelola Kafe
+
+
+ {/* Sub Heading */}
+
+ Daftarkan kedaimu sekarang dan mulai gunakan semua fitur unggulan kami.
+
+
+ {/* Form Section */}
+
+
+ {/* Footer Links */}
+
+
+
+

+
+
+
+
+ );
+};
+
+export default LinktreePage;
diff --git a/src/pages/Join.module.css b/src/pages/Join.module.css
new file mode 100644
index 0000000..28ae05b
--- /dev/null
+++ b/src/pages/Join.module.css
@@ -0,0 +1,161 @@
+/* General container */
+.linktreePage {
+ padding: 0 1rem;
+ border-radius: 20px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background-color: rgb(232 204 88);
+}
+
+
+.dashboardContainer {
+ z-index: 6;
+ padding-top: 40px;
+}
+
+/* Main Heading */
+.mainHeading {
+ font-weight: 700;
+ font-size: 32px;
+ line-height: 2.25rem;
+ margin-bottom: 1rem;
+ letter-spacing: -1px;
+ color: rgb(37, 79, 26);
+}
+
+.swipeContainer {
+ height: 75px;
+ overflow: hidden;
+ width: 100%;
+ color: rgba(59, 130, 246, 0.5);
+}
+
+.swipeContent {
+ animation: swipeUp 12s infinite;
+}
+
+.swipeItem {
+ overflow: hidden;
+ height: 75px;
+ max-width: 300px;
+ text-wrap: balance;
+ line-height: 34px;
+}
+
+/* Swipe Animation */
+@keyframes swipeUp {
+ 0%, 15% {
+ transform: translateY(0);
+ }
+ 20%, 35% {
+ transform: translateY(-20%);
+ }
+ 40%, 55% {
+ transform: translateY(-40%);
+ }
+ 60%, 75% {
+ transform: translateY(-60%);
+ }
+ 80%, 95% {
+ transform: translateY(-80%);
+ }
+}
+
+/* Sub Heading */
+.subHeading {
+ font-weight: 400;
+ line-height: 1.5rem;
+ font-size: 14px;
+ font-family: 'poppins';
+ color: black;
+ margin-bottom: 1.5rem;
+}
+
+/* Form */
+.linktreeForm {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+.usernameLabel {
+ font-size: 0.875rem;
+ color: #444;
+ margin-bottom: 5px;
+ position: relative;
+}
+
+.usernameInput {
+ width: 250px;
+ height: 55px;
+ padding-left: 10px;
+ font-size: 1rem;
+ background-color: #f0f0f0;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ margin-top: 5px;
+ margin-bottom: 15px;
+}
+
+.claimButton {
+ width: 200px;
+ height: 45px;
+ background-color: #254F1A;
+ color: #D2E823;
+ text-align: center;
+ font-size: 1rem;
+ padding: 10px;
+ border-radius: 30px;
+ border: none;
+ cursor: pointer;
+}
+
+.claimButton span {
+ font-weight: 600;
+}
+
+/* Footer */
+.footer {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ margin-top: 2rem;
+}
+
+.footerLinks {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+}
+
+.footerLink {
+ font-size: 0.875rem;
+ color: #254F1A;
+ margin-bottom: 0.5rem;
+ text-decoration: underline;
+}
+
+.signupButton {
+ background-color: transparent;
+ border: 1px solid #254F1A;
+ color: #254F1A;
+ padding: 12px 30px;
+ border-radius: 30px;
+ text-align: center;
+ font-size: 0.875rem;
+ margin-top: 1.5rem;
+ cursor: pointer;
+}
+
+.footerImage {
+ flex: 1;
+ text-align: center;
+}
+
+.footerImage img {
+ width: 150px;
+ height: 226px;
+ margin-top: -50px;
+ margin-bottom: 30px;
+}
diff --git a/src/pages/LinktreePage.module.css b/src/pages/LinktreePage.module.css
new file mode 100644
index 0000000..a1c5d24
--- /dev/null
+++ b/src/pages/LinktreePage.module.css
@@ -0,0 +1,329 @@
+/* General container */
+.linktreePage {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background-color: rgb(210, 232, 35);
+ }
+
+ .dashboardLine {
+ position: fixed;
+ left: 0px;
+ height: 100vh;
+ width: 30px;
+ border-right: 1px solid black;
+ z-index: 5;
+ }
+
+ .dashboardContainer {
+ background-color: rgb(210, 232, 35);
+ z-index: 6;
+ padding: 0 1rem;
+ padding-top: 40px;
+ }
+
+ /* Main Heading */
+ .mainHeading {
+ font-weight: 700;
+ font-size: 32px;
+ line-height: 2.25rem;
+ margin-bottom: 1rem;
+ letter-spacing: -1px;
+ color: rgb(37, 79, 26);
+ }
+
+ .swipeContainer {
+ height: 75px;
+ overflow: hidden;
+ width: 100%;
+ color: rgb(59 130 246);
+ }
+
+ .swipeContent {
+ animation: swipeUp 12s infinite;
+ }
+
+ .swipeItem {
+ overflow: hidden;
+ height: 75px;
+ max-width: 300px;
+ text-wrap: balance;
+ line-height: 34px;
+ }
+
+ /* Swipe Animation */
+ @keyframes swipeUp {
+ 0%, 15% {
+ transform: translateY(0);
+ }
+ 20%, 35% {
+ transform: translateY(-20%);
+ }
+ 40%, 55% {
+ transform: translateY(-40%);
+ }
+ 60%, 75% {
+ transform: translateY(-60%);
+ }
+ 80%, 95% {
+ transform: translateY(-80%);
+ }
+ }
+
+ /* Sub Heading */
+ .subHeading {
+ font-weight: 400;
+ line-height: 1.5rem;
+ font-size: 14px;
+ font-family: 'poppins';
+ color: black;
+ margin-bottom: 1.5rem;
+ }
+ .LoginForm {
+ display: inline-flex;
+ position: relative;
+ height: 148px;
+ }
+
+ /* Form */
+ .FormUsername {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ position: absolute;
+ left: 0vw;
+ }
+
+ .FormUsername.animateForm {
+ animation: FormUsernameProgress 0.5s forwards; /* Apply the animation when inputtingPassword is true */
+ }
+
+ .FormUsername.reverseForm {
+ animation: FormUsernameReverse 0.5s forwards; /* Reverse animation when inputtingPassword is false */
+ }
+
+ @keyframes FormUsernameProgress {
+ 0% {
+ left: 0vw;
+ }
+ 100% {
+ left: -100vw;
+ }
+ }
+
+ @keyframes FormUsernameReverse {
+ 0% {
+ left: -100vw;
+ }
+ 100% {
+ left: 0vw;
+ }
+ }
+
+ .FormPassword {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ position: absolute;
+ left: 100vw;
+ }
+
+ .FormPassword.animateForm {
+ animation: FormPasswordProgress 0.5s forwards; /* Apply the animation when inputtingPassword is true */
+ }
+
+ .FormPassword.reverseForm {
+ animation: FormPasswordReverse 0.5s forwards; /* Reverse animation when inputtingPassword is false */
+ }
+
+ @keyframes FormPasswordProgress {
+ 0% {
+ left: 100vw;
+ }
+ 100% {
+ left: 0vw;
+ }
+ }
+
+ @keyframes FormPasswordReverse {
+ 0% {
+ left: 0vw;
+ }
+ 100% {
+ left: 100vw;
+ }
+ }
+
+
+ .usernameLabel {
+ font-size: 0.875rem;
+ color: #444;
+ margin-bottom: 5px;
+ position: relative;
+ }
+
+ .usernameInput {
+ width: 250px;
+ height: 55px;
+ padding-left: 10px;
+ font-size: 1rem;
+ background-color: #f0f0f0;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ margin-top: 5px;
+ margin-bottom: 15px;
+ }
+
+ .usernameInputError {
+ width: 250px;
+ height: 55px;
+ padding-left: 10px;
+ font-size: 1rem;
+ background-color: #f0f0f0;
+ border-radius: 5px;
+ border: 2px solid red; /* Red border when error is true */
+ margin-top: 5px;
+ margin-bottom: 15px;
+
+ /* Apply keyframe animation for border color transition */
+ animation: borderTransition 2s ease-in-out forwards;
+ }
+
+ /* Keyframe animation for border color transition */
+ @keyframes borderTransition {
+ 0% {
+ border-color: red; /* Initial red border */
+ }
+ 100% {
+ border-color: transparent; /* Transition to transparent */
+ }
+ }
+
+ .claimButton {
+ width: 200px;
+ height: 45px;
+ background-color: #254F1A;
+ color: #D2E823;
+ text-align: center;
+ font-size: 1rem;
+ padding: 10px;
+ border-radius: 30px;
+ border: none;
+ cursor: pointer;
+ }
+
+ .claimButton span {
+ font-weight: 600;
+ }
+
+ /* Footer */
+ .footer {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ margin-top: 2rem;
+ }
+
+ .footerLinks {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .footerLink {
+ font-size: 0.875rem;
+ color: #254F1A;
+ margin-bottom: 0.5rem;
+ text-decoration: underline;
+ }
+
+ .signupButton {
+ background-color: transparent;
+ border: 1px solid #254F1A;
+ color: #254F1A;
+ padding: 12px 30px;
+ border-radius: 30px;
+ text-align: center;
+ font-size: 0.875rem;
+ margin-top: 1.5rem;
+ cursor: pointer;
+ }
+
+ .footerImage {
+ flex: 1;
+ text-align: center;
+ }
+
+ .footerImage img {
+ width: 150px;
+ height: 226px;
+ margin-top: -50px;
+ }
+
+ .userInfo {
+ width: 100vw;
+ background-color: white;
+ left: 0;
+ position: fixed;
+ border-radius: 20px 20px 0 0;
+ bottom: 0;
+ overflow: hidden;
+
+ top: 75vh;
+ transition: top 0.5s ease, padding 0.5s ease;
+ }
+
+.userInfoExpanded {
+ width: 100vw;
+ background-color: white;
+ left: 0;
+ position: fixed;
+ border-radius: 20px 20px 0 0;
+ bottom: 0;
+ overflow: hidden;
+
+ top: 15vh;
+ transition: top 0.5s ease, padding 0.5s ease;
+}
+ .userInfoExpandButton {
+ width: 100%;
+ background-color: #d1ecdf;
+ height: 30px;
+ position: absolute;
+ }
+
+
+ .ItemContainer {
+ height: 100%;
+ overflow-y: auto;
+ font-size: 10px;
+ }
+
+ .Item {
+ background-color: #fff2a3;
+ border-radius: 20px;
+ margin: 20px;
+ padding: 10px;
+ }
+ .transactionContainer {
+ margin-left: 20px;
+ margin-top: 10px;
+ }
+
+ .transaction {
+ padding: 10px;
+ margin-bottom: 5px;
+ border-radius: 10px;
+ }
+
+
+.rectangle {
+ height: 150px; /* Height of each rectangle */
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 10px; /* Rounded corners */
+ font-size: 24px;
+ background-color: rgb(114, 114, 114);
+}
\ No newline at end of file
diff --git a/src/pages/Login.js b/src/pages/Login.js
new file mode 100644
index 0000000..3be5743
--- /dev/null
+++ b/src/pages/Login.js
@@ -0,0 +1,137 @@
+import React, { useState, useEffect } from 'react';
+import styles from './Login.module.css'; // Import the module.css file
+import { loginUser } from "../helpers/userHelpers";
+import { ThreeDots } from "react-loader-spinner";
+import { useNavigate } from "react-router-dom";
+
+const LinktreePage = ({ user, setModal }) => {
+ const [inputtingPassword, setInputtingPassword] = useState(false);
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(false);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+
+ const handleLogin = async () => {
+ try {
+ setError(false);
+ setLoading(true);
+ const response = await loginUser(username, password);
+
+ if (response.success) {
+ localStorage.setItem('auth', response.token);
+
+ if (response.cafeId !== null) {
+ window.location.href = response.cafeId;
+ } else {
+ let destination = '/';
+ window.location.href = destination;
+ }
+ } else {
+ setError(true); // Trigger error state in the button
+ console.error('Login failed');
+ }
+ } catch (error) {
+ setError(true);
+ console.error('Error occurred while logging in:', error.message);
+ } finally {
+ setLoading(false); // Ensure loading state is cleared
+ }
+ };
+
+ const handleModalClose = () => {
+ setIsModalOpen(false);
+ };
+
+ return (
+
+
+
+
+ COBA KEDAIMASTER
+
+
+
pemesanan langsung dari meja
+
pengelolaan pesanan dan keuangan
+
tentukan suasana musik
+
pengelolaan stok dan manajemen
+
jangan pernah ragukan pelanggan
+
+
+ diskon 0%
+
+
+
+ Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
+
+
+
+
+
+ );
+};
+
+export default LinktreePage;
diff --git a/src/pages/Login.module.css b/src/pages/Login.module.css
new file mode 100644
index 0000000..4f84aa3
--- /dev/null
+++ b/src/pages/Login.module.css
@@ -0,0 +1,320 @@
+/* General container */
+.linktreePage {
+ border-radius: 20px;
+ padding: 0 1rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background-color: rgb(210, 232, 35);
+ overflow: hidden;
+ }
+
+ .dashboardLine {
+ position: fixed;
+ left: 0px;
+ height: 100vh;
+ width: 30px;
+ border-right: 1px solid black;
+ z-index: 5;
+ }
+
+ .dashboardContainer {
+ background-color: rgb(210, 232, 35);
+ z-index: 6;
+ padding-top: 40px;
+ }
+
+ /* Main Heading */
+ .mainHeading {
+ font-weight: 700;
+ font-size: 32px;
+ line-height: 2.25rem;
+ margin-bottom: 1rem;
+ letter-spacing: -1px;
+ color: rgb(37, 79, 26);
+ }
+
+ .swipeContainer {
+ height: 75px;
+ overflow: hidden;
+ width: 100%;
+ color: rgb(59 130 246);
+ }
+
+ .swipeContent {
+ animation: swipeUp 12s infinite;
+ }
+
+ .swipeItem {
+ overflow: hidden;
+ height: 75px;
+ max-width: 300px;
+ text-wrap: balance;
+ line-height: 34px;
+ }
+
+ /* Swipe Animation */
+ @keyframes swipeUp {
+ 0%, 15% {
+ transform: translateY(0);
+ }
+ 20%, 35% {
+ transform: translateY(-20%);
+ }
+ 40%, 55% {
+ transform: translateY(-40%);
+ }
+ 60%, 75% {
+ transform: translateY(-60%);
+ }
+ 80%, 95% {
+ transform: translateY(-80%);
+ }
+ }
+
+ /* Sub Heading */
+ .subHeading {
+ font-weight: 400;
+ line-height: 1.5rem;
+ font-size: 14px;
+ font-family: 'poppins';
+ color: black;
+ margin-bottom: 1.5rem;
+ }
+ .LoginForm {
+ display: inline-flex;
+ position: relative;
+ height: 148px;
+ }
+
+ /* Form */
+ .FormUsername {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ position: absolute;
+ left: 0vw;
+ }
+
+ .FormUsername.animateForm {
+ animation: FormUsernameProgress 0.5s forwards; /* Apply the animation when inputtingPassword is true */
+ }
+
+ .FormUsername.reverseForm {
+ animation: FormUsernameReverse 0.5s forwards; /* Reverse animation when inputtingPassword is false */
+ }
+
+ @keyframes FormUsernameProgress {
+ 0% {
+ left: 0vw;
+ }
+ 100% {
+ left: -100vw;
+ }
+ }
+
+ @keyframes FormUsernameReverse {
+ 0% {
+ left: -100vw;
+ }
+ 100% {
+ left: 0vw;
+ }
+ }
+
+ .FormPassword {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ position: absolute;
+ left: 100vw;
+ }
+
+ .FormPassword.animateForm {
+ animation: FormPasswordProgress 0.5s forwards; /* Apply the animation when inputtingPassword is true */
+ }
+
+ .FormPassword.reverseForm {
+ animation: FormPasswordReverse 0.5s forwards; /* Reverse animation when inputtingPassword is false */
+ }
+
+ @keyframes FormPasswordProgress {
+ 0% {
+ left: 100vw;
+ }
+ 100% {
+ left: 0vw;
+ }
+ }
+
+ @keyframes FormPasswordReverse {
+ 0% {
+ left: 0vw;
+ }
+ 100% {
+ left: 100vw;
+ }
+ }
+
+
+ .usernameLabel {
+ font-size: 0.875rem;
+ color: #444;
+ margin-bottom: 5px;
+ position: relative;
+ }
+
+ .usernameInput {
+ width: 250px;
+ height: 55px;
+ padding-left: 10px;
+ font-size: 1rem;
+ background-color: #f0f0f0;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ margin-top: 5px;
+ margin-bottom: 15px;
+ }
+
+ .usernameInputError {
+ width: 250px;
+ height: 55px;
+ padding-left: 10px;
+ font-size: 1rem;
+ background-color: #f0f0f0;
+ border-radius: 5px;
+ border: 2px solid red; /* Red border when error is true */
+ margin-top: 5px;
+ margin-bottom: 15px;
+
+ /* Apply keyframe animation for border color transition */
+ animation: borderTransition 2s ease-in-out forwards;
+ }
+
+ /* Keyframe animation for border color transition */
+ @keyframes borderTransition {
+ 0% {
+ border-color: red; /* Initial red border */
+ }
+ 100% {
+ border-color: transparent; /* Transition to transparent */
+ }
+ }
+
+ .claimButton {
+ width: 200px;
+ height: 45px;
+ background-color: #254F1A;
+ color: #D2E823;
+ text-align: center;
+ font-size: 1rem;
+ padding: 10px;
+ border-radius: 30px;
+ border: none;
+ cursor: pointer;
+ }
+
+ .claimButton span {
+ font-weight: 600;
+ }
+
+ /* Footer */
+ .footer {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ margin-top: 2rem;
+ }
+
+ .footerLinks {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .footerLink {
+ font-size: 0.875rem;
+ color: #254F1A;
+ margin-bottom: 0.5rem;
+ text-decoration: underline;
+ }
+
+ .signupButton {
+ background-color: transparent;
+ border: 1px solid #254F1A;
+ color: #254F1A;
+ padding: 12px 30px;
+ border-radius: 30px;
+ text-align: center;
+ font-size: 0.875rem;
+ margin-top: 1.5rem;
+ cursor: pointer;
+ }
+
+ .footerImage {
+ flex: 1;
+ text-align: center;
+ }
+
+ .footerImage img {
+ width: 150px;
+ height: 226px;
+ margin-top: -50px;
+ }
+
+ .userInfo {
+ width: 100vw;
+ background-color: white;
+ left: 0;
+ position: fixed;
+ border-radius: 20px 20px 0 0;
+ bottom: 0;
+ overflow: hidden;
+
+ top: 75vh;
+ transition: top 0.5s ease, padding 0.5s ease;
+ }
+
+.userInfoExpanded {
+ width: 100vw;
+ background-color: white;
+ left: 0;
+ position: fixed;
+ border-radius: 20px 20px 0 0;
+ bottom: 0;
+ overflow: hidden;
+
+ top: 15vh;
+ transition: top 0.5s ease, padding 0.5s ease;
+}
+ .userInfoExpandButton {
+ width: 100%;
+ background-color: #d1ecdf;
+ height: 30px;
+ position: absolute;
+ }
+
+
+ .ItemContainer {
+ height: 100%;
+ overflow-y: auto;
+ font-size: 10px;
+ }
+
+ .Item {
+ background-color: #fff2a3;
+ border-radius: 20px;
+ margin: 20px;
+ padding: 10px;
+ }
+ .transactionContainer {
+ margin-left: 20px;
+ margin-top: 10px;
+ }
+
+ .transaction {
+ padding: 10px;
+ margin-bottom: 5px;
+ border-radius: 10px;
+ }
+
\ No newline at end of file
diff --git a/src/pages/LoginPage.css b/src/pages/LoginPage.css
deleted file mode 100644
index 916d1df..0000000
--- a/src/pages/LoginPage.css
+++ /dev/null
@@ -1,57 +0,0 @@
-/* src/Login.css */
-.login-container {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- background-color: #f0f0f0;
- }
-
- .login-form {
- background-color: #ffffff;
- padding: 20px;
- border-radius: 8px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
- width: 100%;
- max-width: 400px;
- }
-
- .login-form h2 {
- margin-bottom: 20px;
- text-align: center;
- color: #333333;
- }
-
- .input-group {
- margin-bottom: 15px;
- }
-
- .input-group label {
- display: block;
- margin-bottom: 5px;
- color: #555555;
- }
-
- .input-group input {
- width: 100%;
- padding: 10px;
- border: 1px solid #cccccc;
- border-radius: 4px;
- box-sizing: border-box;
- }
-
- .login-button {
- width: 100%;
- padding: 10px;
- background-color: #007bff;
- color: #ffffff;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- font-size: 16px;
- }
-
- .login-button:hover {
- background-color: #0056b3;
- }
-
\ No newline at end of file
diff --git a/src/pages/LoginPage.js b/src/pages/LoginPage.js
deleted file mode 100644
index 8baf3c7..0000000
--- a/src/pages/LoginPage.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, { useState } from "react";
-import { useNavigate, useLocation } from "react-router-dom";
-import "./LoginPage.css";
-import RouletteWheel from "../components/RouletteWheel";
-import { loginUser, signUpUser } from "../helpers/userHelpers";
-
-const LoginPage = () => {
- const navigate = useNavigate();
- const location = useLocation();
- const searchParams = new URLSearchParams(location.search);
- const next = searchParams.get("next");
- const table = searchParams.get("table");
-
- const handleLogin = async (
- email,
- username,
- password,
- setLoading,
- setError
- ) => {
- try {
- setLoading(true);
- const response = await loginUser(username, password);
-
- if (response.success) {
- localStorage.setItem("auth", response.token);
-
- if (response.cafeId !== null) {
- window.location.href = response.cafeId;
- } else {
- let destination = "/";
- if (table && !next) {
- console.error('Parameter "table" requires "next" to be present.');
- navigate("/");
- return;
- }
- if (next) {
- destination = `/${next}`;
- if (table) destination += `?table=${table}`;
- }
- window.location.href = destination;
- }
- } else {
- setError(true); // Trigger error state in the button
- console.error("Login failed");
- }
- } catch (error) {
- setError(true);
- console.error("Error occurred while logging in:", error.message);
- } finally {
- setLoading(false); // Ensure loading state is cleared
- }
- };
- const handleSignUp = async (
- email,
- username,
- password,
- setLoading,
- setError
- ) => {
- try {
- setLoading(true);
- const response = await signUpUser(email, username, password);
-
- if (response.success) {
- localStorage.setItem("auth", response.token);
-
- let destination = "/";
-
- window.location.href = destination;
- } else {
- setError(true); // Trigger error state in the button
- console.error("Login failed");
- }
- } catch (error) {
- setError(true);
- console.error("Error occurred while logging in:", error.message);
- } finally {
- setLoading(false); // Ensure loading state is cleared
- }
- };
-
- return (
-
-
-
- );
-};
-
-export default LoginPage;
diff --git a/src/pages/ResetPassword.js b/src/pages/ResetPassword.js
new file mode 100644
index 0000000..dedc6ee
--- /dev/null
+++ b/src/pages/ResetPassword.js
@@ -0,0 +1,70 @@
+import React from 'react';
+import styles from './Join.module.css'; // Import the module.css file
+import { useSearchParams } from "react-router-dom";
+
+const LinktreePage = ({ setModal }) => {
+ const [searchParams] = useSearchParams();
+
+ const username = searchParams.get("username") || "";
+ return (
+
+
+
+ {/* Main Heading */}
+
+ Lupa password
+
+
+ {/* Sub Heading */}
+
+ Masukkan email atau nomor whatsapp, kami akan memberimu kode akses
+
+
+ {/* Form Section */}
+
+
+ {/* Footer Links */}
+
+
+
+

+
+
+
+
+ );
+};
+
+export default LinktreePage;