diff --git a/package-lock.json b/package-lock.json index 4f419e7..4a6cb79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "react-scripts": "5.0.1", "react-switch": "^7.0.0", "react-youtube": "^10.1.0", + "recharts": "^2.13.3", "smooth-scroll-into-view-if-needed": "^2.0.2", "socket.io-client": "^4.7.5", "styled-components": "^6.1.11", @@ -4648,6 +4649,11 @@ "@types/node": "*" } }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", @@ -4658,6 +4664,11 @@ "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", @@ -4692,6 +4703,11 @@ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/eslint": { "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", @@ -7534,6 +7550,14 @@ "node": ">=12" } }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-format": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", @@ -7609,6 +7633,14 @@ "node": ">=12" } }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -7696,6 +7728,11 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -9201,6 +9238,14 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -16199,6 +16244,20 @@ "node": ">=10" } }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-switch": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/react-switch/-/react-switch-7.0.0.tgz", @@ -16274,6 +16333,41 @@ "node": ">=8.10.0" } }, + "node_modules/recharts": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.13.3.tgz", + "integrity": "sha512-YDZ9dOfK9t3ycwxgKbrnDlRC4BHdjlY73fet3a0C1+qGMjXVZe6+VXmpOIIhzkje5MMEL8AN4hLIe4AMskBzlA==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, "node_modules/recursive-readdir": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", @@ -18136,6 +18230,11 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -18640,6 +18739,27 @@ "node": ">= 0.8" } }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index 8eea11c..41af52d 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "react-scripts": "5.0.1", "react-switch": "^7.0.0", "react-youtube": "^10.1.0", + "recharts": "^2.13.3", "smooth-scroll-into-view-if-needed": "^2.0.2", "socket.io-client": "^4.7.5", "styled-components": "^6.1.11", diff --git a/src/components/BarChart.js b/src/components/BarChart.js new file mode 100644 index 0000000..86ec90e --- /dev/null +++ b/src/components/BarChart.js @@ -0,0 +1,178 @@ +import React, { useRef, useEffect } from 'react'; +import { BarChart, Bar, XAxis, Tooltip, Legend, CartesianGrid, ResponsiveContainer, LabelList } from 'recharts'; + +// Colors palette +const colors = [ + // **Analogous Colors** (near greens, yellows) + "#D0E14F", // Light green-yellow + "#B2B83D", // Olive yellow + "#A9C96E", // Muted olive green (your bg color itself) + "#A8B64E", // Olive green with yellow undertones + + // **Complementary Colors** (contrast with green) + "#FF6347", // Tomato red + "#FF4500", // Orange red + "#FF8C00", // Dark orange + "#FF7F50", // Coral + + // **Triadic Colors** (balanced vibrant combination) + "#1E90FF", // Dodger blue + "#FF00FF", // Magenta + "#32CD32", // Lime green + + // **Tetradic Colors** (4-color palette: 2 complementary pairs) + "#00CED1", // Dark turquoise + "#FFD700", // Gold + "#FF1493", // Deep pink + "#8A2BE2", // Blue violet + + // **Neutral Tones** (earthy, muted tones to balance the palette) + "#FFDAB9", // Peach + "#F0E68C", // Khaki + "#8B4513", // Saddle brown + "#4B0082", // Indigo + "#C71585", // Medium violet red + + // **Pastels for softer contrast** + "#FFB6C1", // Light pink + "#E6E6FA", // Lavender + "#98FB98", // Pale green + "#F0FFF0", // Honeydew + "#D3D3D3", // Light grey + ]; + + +const SimpleBarChart = ({ Data }) => { + const lastMonthRef = useRef(''); + const lastYearRef = useRef(''); + const usedColors = useRef([]); // Keep track of used colors + + useEffect(() => { + usedColors.current = []; + }, [Data]); + + // Ensure Data is not null or undefined + const transformedData = (Data?.length ? Data.reduce((acc, { date, materialId, priceAtp, stockDifference, name }) => { + function isSameDay(date1, date2) { + const d1 = new Date(date1); + const d2 = new Date(date2); + + return d1.getFullYear() === d2.getFullYear() && + d1.getMonth() === d2.getMonth() && + d1.getDate() === d2.getDate(); + } + + // Assuming `acc` is an array of entries and `date` is the input date you're checking + const existingEntry = acc.find(d => isSameDay(d.date, date)); + + console.log(existingEntry) + if (existingEntry) { + // If it exists, sum the stockDifference (priceAtp * stockDifference) + existingEntry[name] = (existingEntry[name] || 0) + (priceAtp * stockDifference); + } else { + // If it doesn't exist yet, add a new entry + acc.push({ + date, + materialId, + name, + [name]: priceAtp * stockDifference + }); + } + + return acc; + }, []) : []); + + // Sort the data by date (ascending) to easily find the oldest date + const sortedData = [...transformedData].sort((a, b) => new Date(a.date) - new Date(b.date)); + + // The first date in the sorted array will be the oldest + const oldestDate = sortedData[0]?.date; + + // Get the unique materials (names) from the data + const uniqueMaterials = Array.from(new Set(Data?.map(item => item.name) || [])); + + // Function to format date and handle month and year changes + const formatDate = (date) => { + const formattedDate = new Date(date); + const day = formattedDate.getDate(); // Get the day of the month + const month = formattedDate.toLocaleString('en-US', { month: 'short' }); // Get the abbreviated month (e.g., "Nov") + const year = formattedDate.getFullYear().toString().slice(2); // Get the last two digits of the year (e.g., "24") + + // Extract the month and year from the date + const currentMonth = formattedDate.toLocaleDateString('en-US', { month: 'short' }); + const currentYear = formattedDate.getFullYear(); + + // Check if it's the oldest date (first entry) + if (date === oldestDate) { + lastMonthRef.current = currentMonth; // Update lastMonthRef for the first entry + lastYearRef.current = currentYear; // Update lastYearRef for the first entry + return `${day} ${month} ${year}`; // Format as "day month year" (e.g., "4 Nov 24") + } + + // If the year changes, show the full date with year + if (currentYear !== lastYearRef.current) { + lastYearRef.current = currentYear; // Update year reference + return `${day} ${month} ${year}`; // Show full date: day month year + } + + // If the month changes, show the full date with month and year + if (currentMonth !== lastMonthRef.current) { + lastMonthRef.current = currentMonth; // Update month reference + return `${day} ${month} ${year}`; // Show full date: day month year + } + + // Only show the day if the month hasn't changed + return `${day}`; // Show just the day if the month remains the same + }; + + // Function to get the next available color from the palette, starting from a random index + const getNextColor = () => { + // Randomly pick a starting index from the color palette + const randomIndex = Math.floor(Math.random() * colors.length); + + // Find the first unused color from the random starting point + let color = null; + for (let i = 0; i < colors.length; i++) { + const index = (randomIndex + i) % colors.length; + if (!usedColors.current.includes(colors[index])) { + color = colors[index]; + usedColors.current.push(color); // Mark color as used + break; + } + } + + return color || '#000000'; // Fallback color if no colors are available + }; + + // Extract unique dates for the XAxis + const uniqueDates = Array.from(new Set(transformedData.map(item => item.date))); + + return ( +
+ + + {/* Format the XAxis ticks to show only the month when it changes */} + + + + + + {/* Dynamically create bars and labels for each unique material */} + {uniqueMaterials.map((material) => ( + + + + + ))} + + +
+ ); +}; + +export default SimpleBarChart; diff --git a/src/components/Header.js b/src/components/Header.js index 25018aa..c15504b 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -311,7 +311,7 @@ const Header = ({
{ export const getReports = async (cafeId, filter) => { const response = await fetch( - API_BASE_URL + "/transaction/reports/" + cafeId + "?type=" + filter, + API_BASE_URL + "/transaction/get-reports/" + cafeId + "?type=" + filter, { method: "POST", headers: { diff --git a/src/helpers/userHelpers.js b/src/helpers/userHelpers.js index 62ccfe4..a1b8947 100644 --- a/src/helpers/userHelpers.js +++ b/src/helpers/userHelpers.js @@ -171,7 +171,7 @@ export const updateUser = async (formData) => { }; //for super -export const getAllCafeOwner = async (formData) => { +export const getAnalytics = async (formData) => { const token = getLocalStorage("auth"); if (token) { try { diff --git a/src/pages/CircularDiagram.js b/src/pages/CircularDiagram.js index af8d2bc..a5f54af 100644 --- a/src/pages/CircularDiagram.js +++ b/src/pages/CircularDiagram.js @@ -1,17 +1,17 @@ import React from "react"; const CircularDiagram = ({ segments }) => { - const radius = 100; // Radius of the circle - const strokeWidth = 30; // Width of each portion + const radius = 70; // Radius of the circle + const strokeWidth = 20; // Width of each portion const circumference = 2 * Math.PI * (radius - strokeWidth / 2); - let startOffset = 0; // Initial offset for each segment + let startOffset = -63; // Initial offset for each segment const svgStyles = { display: "block", margin: "0 auto", }; - + console.log(segments) return ( { /> {segments.map((segment, index) => { const { percentage, color } = segment; - const segmentLength = (circumference * percentage) / 100; + console.log(percentage) + let p = percentage; + if(p == 'Infinity' || isNaN(p)) p = 0; + const segmentLength = (circumference * p) / 100; const strokeDashoffset = circumference - startOffset; startOffset += segmentLength; diff --git a/src/pages/Dashboard copy.js b/src/pages/Dashboard copy.js index dea637e..bbff574 100644 --- a/src/pages/Dashboard copy.js +++ b/src/pages/Dashboard copy.js @@ -4,7 +4,7 @@ import Header from "../components/Header"; import { useNavigate } from "react-router-dom"; import AccountUpdateModal from "../components/AccountUpdateModal"; import { removeLocalStorage } from "../helpers/localStorageHelpers"; -import { getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers"; +import { getAnalytics, createCafeOwner } from "../helpers/userHelpers"; import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers"; import { ThreeDots } from "react-loader-spinner"; @@ -19,11 +19,12 @@ const Dashboard = ({ user, setModal }) => { const [newItem, setNewItem] = useState({ name: "", type: "" }); useEffect(() => { - if (user && user.roleId === 0) { + if (user && user.roleId < 2) { setLoading(true); - getAllCafeOwner() + getAnalytics() .then((data) => { setItems(data); + console.log(data) setLoading(false); }) .catch((error) => { @@ -31,18 +32,6 @@ const Dashboard = ({ user, setModal }) => { 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 = () => { diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js index 290143b..7383f92 100644 --- a/src/pages/Dashboard.js +++ b/src/pages/Dashboard.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { useNavigate } from "react-router-dom"; import styles from './LinktreePage.module.css'; -import { loginUser, getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers"; +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"; @@ -9,6 +9,8 @@ import { getLocalStorage, removeLocalStorage } from "../helpers/localStorageHelp import { ThreeDots } from "react-loader-spinner"; import Header from '../components/Header'; import CircularDiagram from "./CircularDiagram"; +import API_BASE_URL from '../config'; +import BarChart from '../components/BarChart'; const LinktreePage = ({ user, setModal }) => { const navigate = useNavigate(); @@ -82,10 +84,10 @@ const LinktreePage = ({ user, setModal }) => { setLoading(true); switch (user.roleId) { case 0: - getAllCafeOwner().then(setItems).catch(console.error).finally(() => setLoading(false)); + getAnalytics().then(setItems).catch(console.error).finally(() => setLoading(false)); break; case 1: - getOwnedCafes(user.userId).then(setItems).catch(console.error).finally(() => setLoading(false)); + getAnalytics().then(setItems).catch(console.error).finally(() => setLoading(false)); break; case 3: handleMyTransactions(); @@ -135,60 +137,61 @@ const LinktreePage = ({ user, setModal }) => { } }; const colors = [ - "#FF0000", // Red - "#FF6F00", // Dark Orange - "#FFD700", // Gold - "#32CD32", // Lime Green - "#00CED1", // Dark Turquoise - "#1E90FF", // Dodger Blue - "#8A2BE2", // BlueViolet - "#FF00FF", // Magenta - "#FF1493", // Deep Pink - "#FF4500", // OrangeRed - "#FFDAB9", // Peach Puff - "#4B0082", // Indigo - "#00FF7F", // Spring Green - "#C71585", // Medium Violet Red - "#F0E68C", // Khaki - "#FF6347", // Tomato - "#006400", // Dark Green - "#8B4513", // SaddleBrown - "#00BFFF", // Deep Sky Blue - "#FF69B4", // Hot Pink + // Complementary (for contrast with olive green) + "#FF6347", // Tomato red (complementary to olive green) + "#FF4500", // Orange red (complementary to olive green) + + // Analogous to olive green + "#D0E14F", // Light green-yellow + "#A9C96E", // Muted olive green (your bg color itself) + "#A5B24F", // Earthy olive green + + + // Triadic (balanced and vibrant palette) + "#FF00FF", // Magenta (triadic color) + "#1E90FF", // Dodger blue (triadic color) + "#32CD32", // Lime green (triadic color) + + // Neutral tones + "#FFDAB9", // Peach (light neutral tone) + "#4B0082", // Indigo (dark neutral tone) + "#8B4513", // Saddle brown (earthy neutral) ]; - - const selectedTenant = items.tenants?.find(tenant => tenant.userId === selectedItemId); + + const selectedItems = items.items?.find(item => (item.userId || item.cafeId) === selectedItemId); // If the selected tenant is found, extract the cafes - const selectedTenantCafes = selectedTenant?.cafes || []; - + const selectedSubItems = selectedItems?.subItems || []; + // 1. Optionally combine all report items from cafes of the selected tenant - const allSelectedTenantCafeItems = selectedTenantCafes.flatMap(cafe => cafe.report?.items || []); - + const allSelectedSubItems = selectedSubItems.flatMap(cafe => cafe.report?.items || selectedItems.report.items || []); + // 2. Retrieve the specific cafe's report items if needed - const filteredItems = selectedTenantCafes.find(cafe => cafe.cafeId === selectedSubItemId) || { report: { items: [] } }; - + const filteredItems = selectedSubItems.find(cafe => cafe.cafeId == selectedSubItemId) || { report: { items: [] } }; + // 3. Decide whether to use combined items or individual cafe items - const segments = (selectedItemId != 0 && selectedItemId != -1 && selectedSubItemId == 0 ? allSelectedTenantCafeItems : filteredItems.report.items || []).map((item, index) => ({ - percentage: item.percentage, + const 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.name, color: (colors && colors[index]) || "#cccccc", // Safe check for colors array - })) || []; // Ensure segments is an empty array if no items are available - + })) || []; // Ensure segments is an empty array if no items are availabled // Function to combine items of all cafes for the selected tenant - function combineSelectedTenantCafeReports(selectedTenant) { - return selectedTenant.cafes.flatMap(cafe => cafe.report?.items || []); + console.log(selectedItems) + function combineSelectedTenantCafeReports(selectedItems) { + return selectedItems.cafes.flatMap(cafe => cafe.report?.items || []); } return ( <> {user && user.roleId < 2 ? ( + <>
setIsModalOpen(true)} isLogout={handleLogout} user={user} @@ -199,15 +202,489 @@ const LinktreePage = ({ user, setModal }) => {
-

Total pemasukan {items?.totalIncomeFromAllTenant}

+ {user.roleId == 0 ? ( + selectedItemId == 0 || selectedItemId == -1 ? ( +
+
+ + + + + + + + + + +

Total pemasukan

+

{items?.totalIncome}

+
+
+ + + + + + + + + + +

Total keuntungan

+

{items?.totalIncome * 0.02}

+
+
+ ) : ( +
+
+ + + + + + + + + + + +

{selectedItems?.totalIncome}

+

pemasukan

+
+
+ + + + + + + + + + +

{selectedItems?.totalOutcome}

+

pengeluaran

+
+
+ +

{filteredItems.name}

+
+
+ ) + ) : ( + selectedItemId == 0 || selectedItemId == -1 ? + ( +
+
+ + + + + + + + + + +

Total pemasukan

+

{formatIncome(items?.totalIncome)}

+
+
+ + + + + + + + + + +

Total pengeluaran

+

{formatIncome(items?.totalOutcome)}

+
+
+ ) : ( +
+
+ + + + + + + + + + + +

{formatIncome(selectedItems?.report.totalIncome)}

+

pemasukan

+
+
+ + + + + + + + + + +

{formatIncome(selectedItems?.report.currentOutcome)}

+

pengeluaran

+
+
+ +

{selectedItems.name}

+
+
+ ) + )} +
+
+ -
- +

terlakuu

+
+
+ +
+
+ {segments && segments.map((item, index) => ( +
+
+ ★ +
+
{item.percentage == 'Infinity' || isNaN(item.percentage) ? 0 : item.percentage}%   {item.value}
+
+ ))} + {segments.length < 1 && + <> +
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+ + + } +
+ +
+

penambahan stok

+ +
+ +
Semua {user.roleId < 1 ? 'penyewa' : 'kedai yang dikau miliki'} @@ -218,54 +695,64 @@ const LinktreePage = ({ user, setModal }) => { {user.roleId < 1 &&
setSelectedItemId(selectedItemId == -1 ? 0 : -1)} + onClick={() => { setSelectedItemId(selectedItemId == -1 ? 0 : -1); setModal('add-tenant') }} > Tambah penyewa
} { - items?.tenants?.length > 0 ? ( - items.tenants.map((tenant) => { - const isTenantSelected = selectedItemId === tenant.userId; + items?.items?.length > 0 ? ( + items.items.map((item) => { + const isTenantSelected = selectedItemId === (item.userId || item.cafeId); const tenantBackgroundColor = isTenantSelected && !selectedSubItemId ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)'; - const hasCafes = tenant?.cafes?.length > 0; + const hasSubItems = item?.subItems?.length > 0; return ( -
+
{ - setSelectedItemId(isTenantSelected && !selectedSubItemId ? 0 : tenant.userId); + setSelectedItemId(isTenantSelected && !selectedSubItemId ? 0 : (item.userId || item.cafeId)); setSelectedSubItemId(0); // Reset subitem selection when changing tenant }} style={{ backgroundColor: tenantBackgroundColor }} className={isTenantSelected ? styles.rectangleNLine : styles.rectangle} > -

{tenant.username}

-
- Total Pendapatan: {formatIncome(tenant.totalIncome)} -
+

{item.username || item.name}  

+

+ Rp{formatIncome(item.totalIncome || item.report?.totalIncome) || 0} +

{/* Only show cafes if the tenant is selected */} - {selectedItemId === tenant.userId && hasCafes && tenant.cafes.map((cafe) => { - const isCafeSelected = selectedSubItemId === cafe.cafeId; + {selectedItemId === (item.userId || item.cafeId) && hasSubItems && item.subItems.map((subItem) => { + const isCafeSelected = selectedSubItemId == (subItem.cafeId || subItem.userId); const cafeBackgroundColor = isCafeSelected ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)'; return (
{ - setSelectedSubItemId(isCafeSelected ? 0 : cafe.cafeId); // Toggle subitem selection - setSelectedItemId(tenant.userId); // Ensure tenant stays selected + setSelectedSubItemId(isCafeSelected ? 0 : (subItem.cafeId || subItem.userId)); // Toggle subitem selection + setSelectedItemId(item.userId || item.cafeId); // Ensure tenant stays selected }} style={{ backgroundColor: cafeBackgroundColor }} > - {cafe.name} -  pendapatan {formatIncome(cafe.report?.totalIncome || 0)} + {subItem.name || subItem.username} + {/*  pendapatan {formatIncome(subItem.report?.totalIncome || 0)} */}
); })} + {selectedItemId == item.cafeId && +
{ + }} + style={{}} + > + tambah kasir +
+ }
); }) @@ -273,18 +760,17 @@ const LinktreePage = ({ user, setModal }) => {
No tenants available
) } -
{user.roleId > 0 &&
{ setSelectedItemId(selectedItemId == 0 ? -1 : 0); setModal('create-cafe'); }} + style={{ backgroundColor: selectedItemId == -1 ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)' }} + onClick={() => setSelectedItemId(selectedItemId == -1 ? 0 : -1)} > Tambah kedai
} -
-
+
+
) : (
diff --git a/src/pages/LinktreePage.module.css b/src/pages/LinktreePage.module.css index 9beec76..b0837c6 100644 --- a/src/pages/LinktreePage.module.css +++ b/src/pages/LinktreePage.module.css @@ -1,287 +1,311 @@ /* General container */ .centeredLinktreePage { - height: 100vh; - display: flex; - flex-direction: column; - justify-content: center; - background-color: rgb(210, 232, 35); - } - + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + background-color: rgb(210, 232, 35); +} + .nonCenteredLinktreePage { height: 100vh; display: flex; flex-direction: column; justify-content: start; background-color: rgb(193 201 134); + position: relative; } - .dashboardLine { - position: fixed; - left: 0px; - height: 100vh; - width: 30px; - border-right: 1px solid black; - z-index: 5; +.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); } - - .dashboardContainer { - background-color: rgb(210, 232, 35); - z-index: 6; - padding: 0 1rem; - padding-top: 40px; + + 20%, + 35% { + transform: translateY(-20%); } - - /* Main Heading */ - .mainHeading { - font-weight: 700; - font-size: 32px; - line-height: 2.25rem; - margin-bottom: 1rem; - letter-spacing: -1px; - color: rgb(37, 79, 26); + + 40%, + 55% { + transform: translateY(-40%); } - - .swipeContainer { - height: 75px; - overflow: hidden; - width: 100%; - color: rgb(59 130 246); + + 60%, + 75% { + transform: translateY(-60%); } - - .swipeContent { - animation: swipeUp 12s infinite; + + 80%, + 95% { + transform: translateY(-80%); } - - .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; +} + +/* 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; } - - .FormUsername.animateForm { - animation: FormUsernameProgress 0.5s forwards; /* Apply the animation when inputtingPassword is true */ + + 100% { + left: -100vw; } - - .FormUsername.reverseForm { - animation: FormUsernameReverse 0.5s forwards; /* Reverse animation when inputtingPassword is false */ +} + +@keyframes FormUsernameReverse { + 0% { + left: -100vw; } - - @keyframes FormUsernameProgress { - 0% { - left: 0vw; - } - 100% { - left: -100vw; - } + + 100% { + left: 0vw; } - - @keyframes FormUsernameReverse { - 0% { - left: -100vw; - } - 100% { - left: 0vw; - } - } - - .FormPassword { - display: flex; - flex-direction: column; - align-items: flex-start; - position: absolute; +} + +.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; } - - .FormPassword.animateForm { - animation: FormPasswordProgress 0.5s forwards; /* Apply the animation when inputtingPassword is true */ + + 100% { + left: 0vw; } - - .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; +} + +@keyframes FormPasswordReverse { + 0% { + left: 0vw; } - .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; + 100% { + left: 100vw; } - - /* Keyframe animation for border color transition */ - @keyframes borderTransition { - 0% { - border-color: red; /* Initial red border */ - } - 100% { - border-color: transparent; /* Transition to transparent */ - } +} + + +.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 */ } - .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; + 100% { + border-color: transparent; + /* Transition to transparent */ } - - .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; - } - +} + +.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; @@ -290,122 +314,105 @@ 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; - } + +.userInfoExpandButton { + width: 100%; + background-color: #d1ecdf; + height: 30px; + position: absolute; +} - .ItemContainer { - height: 100%; - overflow-y: auto; - font-size: 10px; - } +.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: 50px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 10px; + font-size: 20px; + background-color: rgb(114, 114, 114); + margin: 5%; + position: relative; + font-weight: 500; + margin-bottom: 20px; + /* Add some space below the rectangle */ +} + +.rectangleNLine { + height: 50px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 10px; + font-size: 20px; + background-color: rgb(114, 114, 114); + margin: 5%; + position: relative; + font-weight: 500; + margin-bottom: 20px; + /* Add some space below the rectangle */ +} + +.subRectangle { + height: 50px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 10px; + font-size: 20px; + background-color: rgb(114, 114, 114); + margin: 5%; + position: relative; + font-weight: 500; + margin-top: 10px; + /* Move it down a little */ + margin-left: 50px; + /* Move it down a little */ +} + + + +/* The arrow at the bottom */ +.subRectangle::before { + left: -14px; + top: 48%; + width: 2px; + height: 54px; + content: ""; + position: absolute; + background-color: rgb(114, 114, 114); + transform: translateY(-50%); +} - .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: 50px; - display: flex; - justify-content: center; - align-items: center; - border-radius: 10px; - font-size: 20px; - background-color: rgb(114, 114, 114); - margin: 5%; - position: relative; - font-weight: 500; - margin-bottom: 20px; /* Add some space below the rectangle */ - } - .rectangleNLine { - height: 50px; - display: flex; - justify-content: center; - align-items: center; - border-radius: 10px; - font-size: 20px; - background-color: rgb(114, 114, 114); - margin: 5%; - position: relative; - font-weight: 500; - margin-bottom: 20px; /* Add some space below the rectangle */ - } - - .subRectangle { - height: 50px; - display: flex; - justify-content: center; - align-items: center; - border-radius: 10px; - font-size: 20px; - background-color: rgb(114, 114, 114); - margin: 5%; - position: relative; - font-weight: 500; - margin-top: 10px; /* Move it down a little */ - margin-left: 50px; /* Move it down a little */ - } - - /* Arrow + line connection */ - .rectangleNLine::after { - content: ""; - position: absolute; - left: -17px; - top: 50%; - width: 18px; - height: 2px; /* Line thickness */ - background-color: rgb(114, 114, 114); /* Line color */ - transform: translateY(-50%); /* Center the line vertically */ - } - - /* Arrow + line connection */ - .subRectangle::after { - content: ""; - position: absolute; - left: -45px; /* Position it to the left of the rectangle */ - top: 50%; /* Center vertically */ - width: 45px; /* Length of the horizontal line */ - height: 2px; /* Line thickness */ - background-color: rgb(114, 114, 114); /* Line color */ - transform: translateY(-50%); /* Center the line vertically */ - } - - /* The arrow at the bottom */ - .subRectangle::before { - content: "-"; - position: absolute; - left: -45px; - top: -21%; - width: 2px; - height: 70px; - content: ""; - position: absolute; - background-color: rgb(114, 114, 114); - transform: translateY(-50%); - } - .header { @@ -413,58 +420,112 @@ top: 0; width: 100%; height: calc(25vh - 25px); - margin-bottom: 15vh; padding-top: 25px; + margin-bottom: 85px; } .headerCardWrapper { - top: 0; - position: absolute; - width: 100%; - bottom: 50vh; - justify-content: center; - display: flex; - align-items: center; + top: 0; + position: absolute; + width: 100%; + bottom: 50vh; + justify-content: center; + display: flex; + align-items: center; } + .headerCard { - background-color: #947257; - position: relative; - width: 90%; - border-radius: 20px; - height: 40%; -} -.cafeListWrapper{ - background-color: white; - border-radius: 20px 20px 0 0; - bottom: 0; - position: absolute; - width: 100%; - max-height: 164.5px; + background-color: #779f94; + position: relative; + width: 90%; + border-radius: 20px; + height: 35%; } -.cafeListHeader{ - background-color: white; - border-radius: 20px 20px 0 0; - bottom: 0; - position: absolute; - width: 100%; - height: 100%; - top: -45px; - background-color: #b09c72; - text-align: center; - padding-top: 10px; - font-weight: 500; -} -.cafeList{ - background-color: white; - border-radius: 20px 20px 0 0; - bottom: 0; - position: absolute; - width: 100%; - height: 100%; +.cardBody { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; /* Center the content */ } -.itemInput{ +.cardImg { + border-radius: 20px; + font-size: 15px; + text-align: center; + margin: 10px; + padding: 5px; + height: 100%; + place-content: center; + +} + +.cardImg img { + width: 100%; + height: auto; + max-width: 85px; + object-fit: contain; + border-radius: 50%; /* Keep the circular shape */ +} + +.cardBody p { + margin: 1vh; + margin-top: 0; + margin-bottom: 0; +} +.cardItem{ + border-radius: 20px; + font-size: 15px; + text-align: center; + margin: 10px; + padding: 5px; +} +.dashboardBody { + padding-left: 5vw; + padding-right: 5vw; +} + +.goCafeButton { + width: 100%; + background-color: rgb(255, 215, 176); + border-radius: 20px; + position: relative; + z-index: 1; +} + +.cafeListWrapper { + background-color: white; + border-radius: 20px 20px 0 0; + top: 83vh; + position: absolute; + width: 100%; +} + +.cafeListHeader { + background-color: white; + border-radius: 20px 20px 0 0; + bottom: 0; + position: absolute; + width: 100%; + height: 100%; + top: -45px; + background-color: #b09c72; + text-align: center; + padding-top: 10px; + font-weight: 500; +} + +.cafeList { + background-color: white; + border-radius: 20px 20px 0 0; + bottom: 0; + position: absolute; + width: 100%; + height: 100%; +} + +.itemInput { width: 50%; height: 60%; border-radius: 14px; diff --git a/src/pages/Reports.js b/src/pages/Reports.js index eb84117..c6220c9 100644 --- a/src/pages/Reports.js +++ b/src/pages/Reports.js @@ -1,9 +1,6 @@ import React, { useEffect, useState } from "react"; -import { ThreeDots } from "react-loader-spinner"; import { - getFavourite, getReports, - getIncome, } from "../helpers/transactionHelpers.js"; import CircularDiagram from "./CircularDiagram"; import styles from "./Transactions.module.css"; @@ -89,8 +86,8 @@ const RoundedRectangle = ({
{loading ? "Loading..." : value}
{loading ? "" : percentage} - {percentage != undefined && !loading && "%"} - {percentage != undefined && !loading && ( + {percentage !== undefined && !loading && "%"} + {percentage !== undefined && !loading && ( {percentage > 0 ? "↗" : percentage === 0 ? "-" : "↘"} @@ -105,11 +102,9 @@ const RoundedRectangle = ({ const App = ({ cafeId, handleClose }) => { - const [favouriteItems, setFavouriteItems] = useState([]); const [analytics, setAnalytics] = useState({}); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState("daily"); - const [viewStock, setViewStock] = useState(false); const fetchData = async (filter) => { try { @@ -129,10 +124,8 @@ const App = ({ cafeId, fetchData(filter); // Fetch data when filter changes }, [filter]); - const [sold, percentage] = analytics[filter] || [0, 0]; const filteredItems = analytics.items || []; - const totalSold = filteredItems.reduce((sum, item) => sum + item.count, 0); const colors = [ "#FF0000", // Red "#FF6F00", // Dark Orange @@ -192,15 +185,15 @@ const App = ({ cafeId, const filterTexts = ["1", "7", "30", "365"]; const comparisonText = filterTexts[["daily", "weekly", "monthly", "yearly"].indexOf(filter)]; - const formatDate = (isoDateString) => { - const date = new Date(isoDateString); - return date.toLocaleDateString("en-US", { - year: "numeric", - month: "long", - day: "numeric", - hour: "numeric", - }); - }; + // const formatDate = (isoDateString) => { + // const date = new Date(isoDateString); + // return date.toLocaleDateString("en-US", { + // year: "numeric", + // month: "long", + // day: "numeric", + // hour: "numeric", + // }); + // }; return (

Laporan