import React, { useState, useEffect } from 'react'; import { useNavigate, useLocation } from "react-router-dom"; import styles from './LinktreePage.module.css'; import { loginUser, getAnalytics, createCafeOwner } from "../helpers/userHelpers"; import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers"; import { getMyTransactions } from "../helpers/transactionHelpers"; import { unsubscribeUser } from "../helpers/subscribeHelpers.js"; import { getLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers"; import { getUserCoupons } from "../helpers/couponHelpers"; import { ThreeDots } from "react-loader-spinner"; import Header from '../components/Header'; import CircularDiagram from "./CircularDiagram"; import API_BASE_URL from '../config'; import DailyCharts from '../components/DailyCharts'; import Coupon from '../components/Coupon'; import Reports from './Reports' import Watermark from '../components/Watermark.js'; const LinktreePage = ({ user, setModal }) => { const navigate = useNavigate(); const location = useLocation(); const [lastModal, setLastModal] = useState(false); const [wasInputtingPassword, setWasInputtingPassword] = 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 [selectedItemId, setSelectedItemId] = useState(0); const [selectedSubItemId, setSelectedSubItemId] = useState(0); const [coupons, setCoupons] = useState(null); useEffect(() => { const urlParams = new URLSearchParams(location.search); const modalParam = urlParams.get('modal'); if (lastModal && !modalParam) { if (selectedItemId == -1) setSelectedItemId(0); else if (selectedSubItemId == -1) setSelectedSubItemId(0); } if (modalParam) { setLastModal(modalParam); } }, [location]); useEffect(() => { const url = new URL(window.location.href); // Get the current URL const searchParams = new URLSearchParams(url.search); // Get the query parameters console.log(selectedItemId) if (selectedItemId != 0 && selectedItemId != -1) { // Add cafeId to the query parameter searchParams.set('cafeId', selectedItemId); } else { // Remove cafeId from the query parameter searchParams.delete('cafeId'); } // Update the URL with the modified query params window.history.replaceState(null, '', `${url.pathname}?${searchParams.toString()}`); }, [selectedItemId]); // Detect query params on component mount useEffect(() => { handleGetkCoupons(); }, []); // Handle manual coupon code check const handleGetkCoupons = async () => { // const result = await getUserCoupons(); // setCoupons(result.coupons); // console.log(result) }; // Handle user transactions const handleMyTransactions = async () => { try { setError(false); setLoading(true); const response = await getMyTransactions(); if (response) { setItems(response); } else { setError(true); } } catch (error) { setError(true); } finally { setLoading(false); console.log(items); } }; // Handle login const handleLogin = async () => { try { setError(false); setLoading(true); const response = await loginUser(username, password); if (response.success) { localStorage.setItem('auth', response.token); console.log(response) window.location.href = response.cafeIdentifyName ? `/${response.cafeIdentifyName}` : '/'; } else { setError(true); } } catch (error) { setError(true); } finally { setLoading(false); } }; // Handle logout const handleLogout = () => { removeLocalStorage("auth"); unsubscribeUser(); navigate(0); }; // Fetch data when the user changes useEffect(() => { if (user) { setLoading(true); document.body.style.backgroundColor = "white"; switch (user.roleId) { case 0: getAnalytics().then(setItems).catch(console.error).finally(() => setLoading(false)); break; case 1: getAnalytics().then(setItems).catch(console.error).finally(() => setLoading(false)); break; case 3: handleMyTransactions(); break; default: setLoading(false); document.body.style.backgroundColor = "rgb(222, 237, 100)"; break; } } console.log(items); }, [user]); // Handle create item (admin or cafe owner) const handleCreateItem = async () => { try { if (user.roleId < 1) { const newOwner = await createCafeOwner(newItem.email, newItem.username, newItem.password); setItems([...items, { userId: newOwner.userId, name: newOwner.username }]); } else { const newCafe = await createCafe(newItem.name); setItems([...items, { cafeId: newCafe.cafeId, name: newCafe.name }]); } setIsCreating(false); setNewItem({ name: "", type: "" }); } catch (error) { console.error("Error creating item:", error); } }; const formatIncome = (amount) => { if (amount >= 1_000_000_000) { // Format for billions const billions = amount / 1_000_000_000; return billions.toFixed(0) + "b"; // No decimal places for billions } else if (amount >= 1_000_000) { // Format for millions const millions = amount / 1_000_000; return millions.toFixed(2).replace(/\.00$/, "") + "m"; // Two decimal places, remove trailing '.00' } else if (amount >= 1_000) { // Format for thousands const thousands = amount / 1_000; return thousands.toFixed(1).replace(/\.0$/, "") + "k"; // One decimal place, remove trailing '.0' } else { // Less than a thousand if (amount != null) return amount.toString(); } }; const colors = [ // Strong contrasting colors for visibility on white background "#333333", // Dark Gray (great contrast for legibility) "#555555", // Medium Gray (slightly lighter, still legible) // Subtle accent colors (not too bright, but distinct) "#4B9F8D", // Muted Teal (offers a soft contrast) "#7F7F7F", // Slate Gray (elegant and balanced) // Softer neutral colors (for less emphasis) "#B0B0B0", // Light Gray (gentle tone for subtle slices) "#D3D3D3", // Silver Gray (light, but still visible on white background) // A touch of color for balance (but still muted) "#9C6E5C", // Muted Brown (earthy, grounded tone) "#A1A1A1", // Silver (neutral highlight) ]; console.log(items) const selectedItems = items?.items?.find(item => (item.userId || item.cafeId) === selectedItemId); // If the selected tenant is found, extract the cafes const selectedSubItems = selectedItems?.subItems || []; // 1. Optionally combine all report items from cafes of the selected tenant let allSelectedSubItems = null; if (user.roleId == 1) allSelectedSubItems = selectedSubItems?.flatMap(cafe => cafe.report?.items || selectedItems.report?.itemSales || []); // 2. Retrieve the specific cafe's report items if needed const filteredItems = selectedSubItems?.find(cafe => cafe.cafeId == selectedSubItemId) || { report: { items: [] } }; // 3. Decide whether to use combined items or individual cafe items let segments = []; if (user.roleId == 1 || user.roleId == 0 && selectedItemId == 0) segments = (selectedItemId != 0 && selectedItemId != -1 && selectedSubItemId == 0 ? allSelectedSubItems : selectedItemId != 0 && selectedItemId != -1 ? filteredItems.report?.items || [] : items?.items || []).map((item, index) => ({ percentage: item.percentage || (items?.totalIncome / item?.totalIncome || items?.totalIncome / item?.report?.totalIncome) * 100, value: item.username || item.itemName || item.name, color: (colors && colors[index]) || "#cccccc", // Safe check for colors array })) || []; // Ensure segments is an empty array if no items are availabled // Function to combine items of all cafes for the selected tenant console.log(selectedItems) console.log(segments) // Check if items and items.items are defined before proceeding const allMaterials = (items?.items || []).flatMap(item => item.report?.materialsPurchased || []); // Sort the merged array by date if it's not empty const sortedMaterials = allMaterials.sort((a, b) => new Date(a.date) - new Date(b.date)); return ( <> {user && user.roleId < 2 ? (
setIsModalOpen(true)} isLogout={handleLogout} user={user} showProfile={true} setModal={setModal} HeaderMargin='0px' />
) : (
{API_BASE_URL == 'https://test.api.kedaimaster.com' ?
KEDAIMASTER CREDITS
{['AI - MUHAMMAD AINUL FIKRI', 'BACKEND - ZADIT TAQWA W.', 'FRONTEND - M. PASHA A. P.', 'FRONTEND - NAUFAL DANIYAL P.', 'FRONTEND - ZADIT TAQWA W.', 'UI/UX - KEVIN DWI WIJAYA', 'UI/UX - LUNA CHELISA A.', 'UI/UX - MAULINA AYU E.', 'UI/UX - NUR ARINDA P.', 'UI/UX - NAURA IZZATI B.',].map((item, index) => (
{item}
))}
gratis 3 bulan pertama
:
COBA KEDAIMASTER
{['pemesanan langsung dari meja', 'pengelolaan pesanan dan keuangan', 'tentukan suasana musik', 'pengelolaan stok dan manajemen', 'jangan pernah ragukan pelanggan'].map((item, index) => (
{item}
))}
Gratis 3 bulan pertama
}
Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
setUsername(e.target.value)} />
setPassword(e.target.value)} />
Pelajari lebih lanjut Tentang kedaimaster.com setModal('join')} > Daftarkan kedaimu
Linktree visual e.target.src = '/fallback-image.png'} />
)} ); }; export default LinktreePage;