715 lines
26 KiB
JavaScript
715 lines
26 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import {
|
|
getReports,
|
|
getAnalytics
|
|
} from "../helpers/transactionHelpers.js";
|
|
import { createCafe } from "../helpers/cafeHelpers.js"
|
|
import { createCoupon } from "../helpers/couponHelpers.js"
|
|
import CircularDiagram from "./CircularDiagram";
|
|
import styles from "./Transactions.module.css";
|
|
import "./Switch.css";
|
|
|
|
import MultiSwitch from "react-multi-switch-toggle";
|
|
import DailyCharts from '../components/DailyCharts.js';
|
|
import PeriodCharts from '../components/PeriodCharts.js';
|
|
|
|
import Coupon from "../components/Coupon.js";
|
|
|
|
const RoundedRectangle = ({
|
|
onClick,
|
|
title,
|
|
value,
|
|
percentage,
|
|
invert,
|
|
fontSize = "15px",
|
|
loading = false,
|
|
children, // Assuming this is a React component or JSX
|
|
isChildren,
|
|
width = 'calc(100% / 2 - 10px)'
|
|
}) => {
|
|
const containerStyle = {
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "flex-start",
|
|
justifyContent: "center",
|
|
width: width,
|
|
height: "auto",
|
|
borderRadius: "15px",
|
|
padding: "20px",
|
|
margin: "5px",
|
|
textAlign: "left",
|
|
fontFamily: "Arial, sans-serif",
|
|
boxSizing: "border-box",
|
|
backgroundColor: loading ? "rgb(127 127 127)" : 'white',
|
|
border: '1px solid #b3b1b1'
|
|
};
|
|
|
|
const titleStyle = {
|
|
fontWeight: "bold",
|
|
marginBottom: "10px",
|
|
width: "100%",
|
|
backgroundColor: loading
|
|
? "rgb(85 85 85)"
|
|
: !isChildren && !children && "inherit",
|
|
color: loading ? "transparent" : "inherit",
|
|
};
|
|
|
|
const valueAndPercentageContainerStyle = {
|
|
display: "flex",
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
width: "100%",
|
|
};
|
|
|
|
const valueStyle = {
|
|
fontSize: loading ? "15px" : fontSize,
|
|
fontWeight: "bold",
|
|
flex: "1",
|
|
textAlign: "left",
|
|
color: loading ? "transparent" : "inherit",
|
|
backgroundColor: loading ? "rgb(85 85 85)" : "transparent",
|
|
overflow: "hidden",
|
|
textOverflow: "ellipsis",
|
|
whiteSpace: "nowrap",
|
|
};
|
|
|
|
const percentageStyle = {
|
|
fontSize: "16px",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
textAlign: "right",
|
|
color: loading ? "black" : percentage >= 0 ? (invert ? "red" : "#2fd45e") : (invert ? "#2fd45e" : "red"),
|
|
};
|
|
|
|
const arrowStyle = {
|
|
marginLeft: "5px",
|
|
};
|
|
|
|
return (
|
|
<div style={containerStyle} onClick={onClick}>
|
|
<div style={titleStyle}>{title}</div>
|
|
{!children && (
|
|
<div style={valueAndPercentageContainerStyle}>
|
|
<div style={valueStyle}>{loading ? "Loading..." : value}</div>
|
|
<div style={percentageStyle}>
|
|
{loading ? "" : percentage}
|
|
{percentage !== undefined && !loading && "%"}
|
|
{percentage !== undefined && !loading && (
|
|
<span style={arrowStyle}>
|
|
{percentage > 0 ? "↗" : percentage === 0 ? "-" : "↘"}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
{children && <div>{children}</div>} {/* Properly render children */}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const App = ({ forCafe = true, cafeId = -1,
|
|
handleClose, otherCafes, coupons, setModal, user }) => {
|
|
const [selectedCafeId, setSelectedCafeId] = useState(cafeId);
|
|
const [analytics, setAnalytics] = useState({});
|
|
const [loading, setLoading] = useState(true);
|
|
const [filter, setFilter] = useState("yesterday");
|
|
const [circularFilter, setCircularFilter] = useState("item");
|
|
const [graphFilter, setGraphFilter] = useState("income");
|
|
|
|
const [itemName, setItemName] = useState('');
|
|
|
|
const fetchData = async (filter) => {
|
|
if (selectedCafeId == '-1') return;
|
|
try {
|
|
setLoading(true);
|
|
// Fetch the analytics data with the selected filter
|
|
const analyticsData = (selectedCafeId !== '' && selectedCafeId !== 0)
|
|
? await getReports(selectedCafeId, filter)
|
|
: await getAnalytics(filter);
|
|
|
|
console.log(analyticsData);
|
|
if (analyticsData) setAnalytics(analyticsData);
|
|
} catch (error) {
|
|
console.error("Error fetching data:", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
setSelectedCafeId(cafeId)
|
|
}, [cafeId]);
|
|
|
|
useEffect(() => {
|
|
fetchData(filter); // Fetch data when filter changes
|
|
}, [filter, selectedCafeId]);
|
|
|
|
const filteredItems = (selectedCafeId != 0 && selectedCafeId != -1) ? (circularFilter == 'item' ? analytics?.itemSales || [] : analytics.materialSpend || []) : analytics?.items || [];
|
|
|
|
const colors = [
|
|
"#af9463", // Bright Red
|
|
"#F4A261", // Soft Orange
|
|
"#FFD166", // Sunshine Yellow
|
|
"#06D6A0", // Mint Green
|
|
"#118AB2", // Rich Teal
|
|
"#9D4EDD", // Vivid Violet
|
|
"#FF66B3", // Bubblegum Pink
|
|
"#FF7F50", // Coral
|
|
"#FFA07A", // Light Salmon
|
|
"#F7CAD0", // Blush Pink
|
|
"#A8DADC", // Aqua Blue
|
|
"#457B9D", // Steel Blue
|
|
"#2A9D8F", // Jungle Green
|
|
"#FFB703", // Mustard Yellow
|
|
"#E9C46A", // Honey Gold
|
|
"#264653", // Charcoal Green
|
|
"#D4A5A5", // Rose Beige
|
|
"#A6D6F0", // Sky Blue
|
|
"#BC4749", // Cranberry Red
|
|
];
|
|
|
|
const totalSoldAcrossAllCafes = filteredItems.reduce((total, cafe) => {
|
|
const cafeTotal = (cafe.report?.itemSales || []).reduce((sum, item) => sum + item.sold, 0);
|
|
return total + cafeTotal;
|
|
}, 0);
|
|
|
|
const totalSpendAcrossAllCafes = filteredItems.reduce((total, cafe) => {
|
|
const cafeTotal = (cafe.report?.materialSpend || []).reduce((sum, item) => sum + item.spend, 0);
|
|
return total + cafeTotal;
|
|
}, 0);
|
|
|
|
// Define a color palette or generate colors dynamically
|
|
const colorPalette = colors;
|
|
|
|
// Ensure that each segment gets a unique color
|
|
let colorIndex = 0;
|
|
|
|
console.log(filteredItems)
|
|
let segments = (selectedCafeId == 0 || selectedCafeId == -1) ? filteredItems.flatMap((cafe) => {
|
|
const cafeItems = cafe.report?.itemSales || [];
|
|
console.log(cafeItems); // Log all items for the cafe
|
|
|
|
return cafeItems.map((item, index) => {
|
|
const percentage = totalSoldAcrossAllCafes > 0
|
|
? ((item.sold / totalSoldAcrossAllCafes) * 100).toFixed(2)
|
|
: 0;
|
|
|
|
console.log(`${item.itemName}: ${(percentage)}%`); // Log item name and percentage
|
|
|
|
// Assign a unique color from the color palette
|
|
const color = colorPalette[colorIndex % colorPalette.length]; // Use modulo to cycle through colors
|
|
|
|
colorIndex++; // Increment to ensure a new color for the next item
|
|
|
|
return {
|
|
itemName: item.itemName,
|
|
sold: item.sold,
|
|
percentage: percentage,
|
|
color: color,
|
|
};
|
|
});
|
|
}) : filteredItems.map((item, index) => {
|
|
const color = colorPalette[colorIndex % colorPalette.length]; // Use modulo to cycle through colors
|
|
colorIndex++; // Increment to ensure a new color for the next item
|
|
return {
|
|
itemName: item.itemName,
|
|
percentage: item.percentage,
|
|
color: color,
|
|
};
|
|
});
|
|
|
|
segments.sort((a, b) => b.sold - a.sold);
|
|
|
|
|
|
let materialSegments = (selectedCafeId == 0 || selectedCafeId == -1) ? filteredItems.flatMap((cafe) => {
|
|
const cafeItems = cafe.report?.materialSpend || [];
|
|
console.log(cafeItems); // Log all items for the cafe
|
|
|
|
return cafeItems.map((item, index) => {
|
|
const percentage = totalSpendAcrossAllCafes > 0
|
|
? ((item.spend / totalSpendAcrossAllCafes) * 100).toFixed(2)
|
|
: 0;
|
|
|
|
console.log(`${item.materialName}: ${(percentage)}%`); // Log item name and percentage
|
|
|
|
// Assign a unique color from the color palette
|
|
const color = colorPalette[colorIndex % colorPalette.length]; // Use modulo to cycle through colors
|
|
|
|
colorIndex++; // Increment to ensure a new color for the next item
|
|
|
|
return {
|
|
itemName: item.materialName,
|
|
sold: item.spend,
|
|
percentage: percentage,
|
|
color: color,
|
|
};
|
|
});
|
|
}) : filteredItems.map((item, index) => {
|
|
const color = colorPalette[colorIndex % colorPalette.length]; // Use modulo to cycle through colors
|
|
colorIndex++; // Increment to ensure a new color for the next item
|
|
return {
|
|
itemName: item.materialName,
|
|
percentage: item.percentage,
|
|
color: color,
|
|
};
|
|
});
|
|
|
|
materialSegments.sort((a, b) => b.spend - a.spend);
|
|
|
|
|
|
console.log(selectedCafeId)
|
|
console.log(segments)
|
|
|
|
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();
|
|
}
|
|
};
|
|
|
|
function roundToInteger(num) {
|
|
return Math.round(num);
|
|
}
|
|
|
|
function onToggle(selectedItem) {
|
|
setAnalytics({});
|
|
const filterMap = ["yesterday", "weekly", "monthly", "yearly"];
|
|
setFilter(filterMap[selectedItem]);
|
|
}
|
|
|
|
const filterTexts = ["1", "7", "30", "365"];
|
|
const comparisonText =
|
|
filterTexts[["yesterday", "weekly", "monthly", "yearly"].indexOf(filter)];
|
|
|
|
const [resetKey, setResetKey] = useState(0); // A key to force re-render
|
|
const [texts, setTexts] = useState(['Buat bisnis']); // initially show only first 3 texts
|
|
const [fullTexts, setFullTexts] = useState(null); // initially show only first 3 texts
|
|
const [fullTextsVisible, setFullTextsVisible] = useState(null); // initially show only first 3 texts
|
|
|
|
useEffect(() => {
|
|
if (otherCafes != null) {
|
|
console.log(otherCafes)
|
|
let updatedFullTexts;
|
|
|
|
if (otherCafes.length === 0) {
|
|
updatedFullTexts = [["Buat bisnis", 0]];
|
|
setSelectedCafeId(0);
|
|
} else if (otherCafes.length === 1) {
|
|
updatedFullTexts = [
|
|
[otherCafes[0].name || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].userId],
|
|
["Buat bisnis", -1]
|
|
];
|
|
|
|
setSelectedCafeId(otherCafes[0].cafeId); // Get the cafeId (second part of the pair)
|
|
} else {
|
|
updatedFullTexts = [
|
|
["semua", 0], // First entry is "semua"
|
|
...otherCafes.map(item => [item.name || item.username, item.cafeId || item.userId]), // Map over cafes to get name and cafeId pairs
|
|
["tambah bisnis +", -1] // Add the "+" entry
|
|
];
|
|
|
|
setSelectedCafeId(0);
|
|
}
|
|
|
|
setFullTexts(updatedFullTexts); // Set fullTexts with the original structure
|
|
// Set fullTextsVisible to an array of names only
|
|
setFullTextsVisible(updatedFullTexts.map(item => item[0])); // Extract just the names (first part of each pair)
|
|
|
|
// Set the first 3 items in texts
|
|
setTexts(updatedFullTexts.map(item => item[0]).slice(0, 3));
|
|
|
|
// Increment resetKey to trigger re-render
|
|
setResetKey(prevKey => prevKey + 1);
|
|
}
|
|
|
|
console.log(otherCafes);
|
|
}, [otherCafes]);
|
|
|
|
|
|
console.log(fullTexts)
|
|
const [selectedSwitch, setSelectedSwitch] = useState(0);
|
|
|
|
const onItemToggle = (index) => {
|
|
|
|
// When user clicks the last visible option (index === 2 in the current view)
|
|
if (index === 2) {
|
|
console.log(fullTexts);
|
|
if (fullTexts.findIndex(item => item[0] === texts[2]) < fullTexts.length - 1) {
|
|
setTexts((prevTexts) => {
|
|
const newTexts = [...prevTexts];
|
|
console.log(prevTexts.length)
|
|
const nextText = fullTexts[fullTexts.findIndex(item => item[0] === texts[2]) + 1][0]; // Get the next item in the full list
|
|
newTexts.shift(); // Remove the first element
|
|
newTexts.push(nextText); // Add the next item to the end
|
|
setSelectedSwitch(1); // Change the selected index
|
|
return newTexts;
|
|
});
|
|
}
|
|
}
|
|
|
|
// When user clicks the first visible option (index === 0 in the current view)
|
|
if (index === 0) {
|
|
// Check if there is a previous text in the full list (before the first visible text)
|
|
if (fullTexts.findIndex(item => item[0] === texts[0]) > 0) {
|
|
setTexts((prevTexts) => {
|
|
const newTexts = [...prevTexts];
|
|
const prevText = fullTexts[fullTexts.findIndex(item => item[0] === newTexts[0]) - 1]; // Get the previous item
|
|
newTexts.pop(); // Remove the last element
|
|
newTexts.unshift(prevText[0]); // Add the previous item to the start
|
|
setSelectedSwitch(1); // Change the selected index
|
|
return newTexts;
|
|
});
|
|
}
|
|
}
|
|
|
|
// Dynamically update selectedSwitch state to trigger re-render
|
|
setSelectedSwitch(index);
|
|
|
|
// Get the cafeId from the selected text based on the index
|
|
const selectedText = texts[index]; // Get the selected name from the texts array
|
|
const selectedItem = fullTexts.find(item => item[0] === selectedText); // Find the corresponding full item
|
|
if (selectedItem) {
|
|
setSelectedCafeId(selectedItem[1]); // Get the cafeId (second part of the pair)
|
|
}
|
|
|
|
setResetKey((prevKey) => prevKey + 1); // Increase the key to force re-render
|
|
};
|
|
|
|
// useEffect(() => {
|
|
// // This effect will run whenever the selectedSwitch changes
|
|
// // We could add logic here if needed for side effects
|
|
// }, [selectedSwitch]);
|
|
|
|
return (
|
|
<div style={{
|
|
position: forCafe ? 'fixed' : 'relative',
|
|
height: '100vh',
|
|
width: '100vw',
|
|
top: 0,
|
|
right: 0,
|
|
backgroundColor: 'white',
|
|
overflowY: forCafe ? 'auto' : 'none',
|
|
color: 'black',
|
|
marginTop: forCafe ? 0 : '-22vh'
|
|
}}
|
|
>
|
|
<div style={{ display: 'flex', alignItems: 'center', padding: forCafe ? '0px 20px' : '0px 15px', justifyContent: forCafe ? 'flex-start' : 'space-between' }}>
|
|
{forCafe && <div style={{ marginTop: '49px', marginRight: '10px' }} onClick={handleClose}><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512"><path d="M48,256c0,114.87,93.13,208,208,208s208-93.13,208-208S370.87,48,256,48,48,141.13,48,256Zm212.65-91.36a16,16,0,0,1,.09,22.63L208.42,240H342a16,16,0,0,1,0,32H208.42l52.32,52.73A16,16,0,1,1,238,347.27l-79.39-80a16,16,0,0,1,0-22.54l79.39-80A16,16,0,0,1,260.65,164.64Z" /></svg></div>}
|
|
<div style={{ marginTop: '10px' }}>
|
|
{!forCafe &&
|
|
<div className={styles.dateSelectorWrapper} style={{ fontSize: '12px' }}>
|
|
{texts.map((item, indexx) => {
|
|
return (
|
|
<div
|
|
key={indexx}
|
|
className={`${styles.dateSelector} ${styles.dateSelectorActive}`} style={{ position: 'relative', width: 'calc(32vw - 30px)' }}
|
|
onClick={() => onItemToggle(indexx)}
|
|
>
|
|
<div style={{ position: 'absolute', bottom: 0, left: '10%', right: '10%', borderBottom: selectedSwitch == indexx ? `1px solid green` : 'none' }}></div>
|
|
<div
|
|
style={{ color: 'black' }}>
|
|
{item}
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
{!forCafe && selectedCafeId != -1 &&
|
|
<div style={{
|
|
textAlign: "center",
|
|
marginTop: '30px'
|
|
}}>
|
|
<MultiSwitch
|
|
texts={["Kemarin", "Minggu ini", "Bulan ini", "Tahun ini"]}
|
|
selectedSwitch={["yesterday", "weekly", "monthly", "yearly"].indexOf(
|
|
filter
|
|
)}
|
|
bgColor={'#f4efe6'}
|
|
borderColor={'transparent'}
|
|
borderWidth={0.1}
|
|
onToggleCallback={onToggle}
|
|
fontColor={"#af9463"}
|
|
selectedFontColor={"black"}
|
|
selectedSwitchColor={"white"}
|
|
eachSwitchWidth={70}
|
|
height={"25px"}
|
|
fontSize={"12px"}
|
|
/>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexWrap: "wrap",
|
|
justifyContent: "center",
|
|
padding: "20px",
|
|
}}
|
|
>
|
|
<RoundedRectangle
|
|
title="Pendapatan"
|
|
fontSize="12px"
|
|
value={!loading && "Rp" + formatIncome(analytics?.currentTotals?.income)}
|
|
percentage={roundToInteger(analytics?.growth?.incomeGrowth)}
|
|
invert={false}
|
|
loading={loading}
|
|
/>
|
|
|
|
<RoundedRectangle
|
|
title="Pengeluaran"
|
|
fontSize="12px"
|
|
value={!loading && "Rp" + formatIncome(analytics?.currentTotals?.outcome)}
|
|
percentage={roundToInteger(analytics?.growth?.outcomeGrowth)}
|
|
invert={true}
|
|
loading={loading}
|
|
/>
|
|
<RoundedRectangle
|
|
title="Transaksi"
|
|
value={analytics?.currentTotals?.transactions}
|
|
percentage={roundToInteger(analytics?.growth?.transactionGrowth)}
|
|
invert={false}
|
|
loading={loading}
|
|
/>
|
|
{analytics?.itemSales &&
|
|
analytics?.itemSales.length > 0 && (
|
|
<RoundedRectangle
|
|
title={"Item favorit"}
|
|
value={analytics?.itemSales[0]?.itemName}
|
|
loading={loading}
|
|
/>
|
|
)}
|
|
{(!analytics?.itemSales ||
|
|
analytics?.itemSales.length === 0) && (
|
|
<RoundedRectangle
|
|
title={"Item favorit"}
|
|
value={"-"}
|
|
loading={loading}
|
|
/>
|
|
)}
|
|
{!forCafe && selectedCafeId != -1 && selectedCafeId != 0 && (
|
|
<RoundedRectangle
|
|
title={"Kunjungi bisnis"}
|
|
loading={loading}
|
|
width="calc(100% - 10px)"
|
|
onClick={() => window.location.href = window.location.origin + '/' + otherCafes.find(item => item.cafeId === selectedCafeId).cafeIdentifyName}
|
|
/>
|
|
)}
|
|
<div
|
|
style={{ display: "flex", alignItems: "center", margin: "10px" }}
|
|
>
|
|
<div style={{ marginRight: "5px", fontSize: "1.2em" }}>ⓘ</div>
|
|
<h6 style={{ margin: 0, textAlign: "left", fontSize: '10px', fontWeight: 500 }}>
|
|
{(filter == 'yesterday' || filter == 'weekly') ?
|
|
`Data dihitung dengan membandingkan
|
|
${comparisonText} hari terakhir dengan ${comparisonText} hari sebelumnya, dengan penghitungan dimulai dari data kemarin.`
|
|
:
|
|
(filter == 'monthly') ? `Data dihitung dengan membandingkan antara awal hingga akhir bulan ini dan bulan lalu, dengan penghitungan berakhir pada data kemarin.` : `Data dihitung dengan membandingkan antara awal hingga akhir tahun ini dan tahun lalu, dengan penghitungan berakhir pada data kemarin.`}
|
|
</h6>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.filterSelectorWrapper}>
|
|
<div className={`${styles.filterSelector} ${circularFilter == 'item' ? '' : styles.filterSelectorInactive}
|
|
}`}
|
|
onClick={() =>
|
|
setCircularFilter('item')
|
|
}
|
|
style={{ color: 'black', position: 'relative' }}
|
|
>
|
|
<div>Item laku</div>
|
|
</div>
|
|
<div
|
|
className={`${styles.filterSelector} ${circularFilter == 'material' ? '' : styles.filterSelectorInactive}
|
|
}`}
|
|
|
|
onClick={() =>
|
|
setCircularFilter('material')
|
|
}
|
|
>
|
|
<div>Bahan baku</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
padding: "20px",
|
|
paddingTop: 0
|
|
}}
|
|
>
|
|
<div style={{ flex: 1 }}>
|
|
<CircularDiagram segments={circularFilter == 'item' ? segments : materialSegments} />
|
|
</div>
|
|
<div style={{ flex: 1, marginLeft: "20px" }}>
|
|
{(circularFilter === 'item' ? segments : materialSegments).map((item, index) => (
|
|
<div
|
|
key={index}
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
margin: "10px",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
marginRight: "5px",
|
|
fontSize: "1.2em",
|
|
color: colors[index],
|
|
}}
|
|
>
|
|
★
|
|
</div>
|
|
<h5 style={{ margin: 0, textAlign: "left" }}>{item.itemName}</h5>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.filterSelectorWrapper}>
|
|
<div className={`${styles.filterSelector} ${graphFilter == 'income' ? '' : styles.filterSelectorInactive}
|
|
}`}
|
|
onClick={() =>
|
|
setGraphFilter('income')
|
|
}
|
|
style={{ color: 'black', position: 'relative' }}
|
|
>
|
|
<div>Pemasukan</div>
|
|
</div>
|
|
<div
|
|
className={`${styles.filterSelector} ${graphFilter == 'outcome' ? '' : styles.filterSelectorInactive}
|
|
}`}
|
|
|
|
onClick={() =>
|
|
setGraphFilter('outcome')
|
|
}
|
|
>
|
|
<div>Pengeluaran</div>
|
|
</div>
|
|
<div
|
|
className={`${styles.filterSelector} ${graphFilter == 'transactions' ? '' : styles.filterSelectorInactive}
|
|
}`}
|
|
|
|
onClick={() =>
|
|
setGraphFilter('transactions')
|
|
}
|
|
>
|
|
<div>Transaksi</div>
|
|
</div>
|
|
</div>
|
|
{filter == 'yesterday' || filter == 'weekly' ?
|
|
<DailyCharts transactionGraph={analytics?.transactionGraph || analytics?.combinedTransactionGraph} materialGraph={analytics?.materialGraph || analytics?.combinedMaterialGraph} type={filter} graphFilter={graphFilter} colors={colors} />
|
|
:
|
|
<PeriodCharts type={filter} graphFilter={graphFilter} aggregatedCurrentReports={analytics?.aggregatedCurrentReports} aggregatedPreviousReports={analytics?.aggregatedPreviousReports} colors={colors} />
|
|
}
|
|
</div>
|
|
}
|
|
{!forCafe && selectedCafeId == -1 &&
|
|
<div style={{
|
|
textAlign: "center",
|
|
}}>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexWrap: "wrap",
|
|
justifyContent: "center",
|
|
padding: "20px",
|
|
}}
|
|
>
|
|
{user?.roleId == 0 ?
|
|
<RoundedRectangle
|
|
title={"Masukkan nama bisnis"}
|
|
width="calc(100% - 10px)"
|
|
>
|
|
<input
|
|
value={itemName}
|
|
onChange={(e) => setItemName(e.target.value)}
|
|
style={{
|
|
width: '70%',
|
|
fontSize: '25px',
|
|
borderRadius: '7px',
|
|
border: '1px solid black'
|
|
}}
|
|
/>
|
|
</RoundedRectangle>
|
|
:
|
|
|
|
<RoundedRectangle
|
|
title={"Masukkan nama bisnis"}
|
|
width="calc(100% - 10px)"
|
|
>
|
|
<input
|
|
value={itemName}
|
|
onChange={(e) => setItemName(e.target.value)}
|
|
style={{
|
|
width: '70%',
|
|
fontSize: '25px',
|
|
borderRadius: '7px',
|
|
border: '1px solid black'
|
|
}}
|
|
/>
|
|
</RoundedRectangle>
|
|
|
|
}
|
|
<RoundedRectangle
|
|
title={user?.roleId === 0 ? "Buat Voucher" : "Buat Bisnis"}
|
|
width="calc(100% - 10px)"
|
|
onClick={() => (user?.roleId === 0 ? createCoupon(itemName) : createCafe(itemName))}
|
|
/>
|
|
</div>
|
|
</div>
|
|
}
|
|
{user?.roleId == 1 &&
|
|
<>
|
|
<div className={`${styles.couponContainer}`}>
|
|
{forCafe && <div style={{ marginTop: '49px', marginRight: '10px' }} onClick={handleClose}><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 512 512"><path d="M48,256c0,114.87,93.13,208,208,208s208-93.13,208-208S370.87,48,256,48,48,141.13,48,256Zm212.65-91.36a16,16,0,0,1,.09,22.63L208.42,240H342a16,16,0,0,1,0,32H208.42l52.32,52.73A16,16,0,1,1,238,347.27l-79.39-80a16,16,0,0,1,0-22.54l79.39-80A16,16,0,0,1,260.65,164.64Z" /></svg></div>}
|
|
<div>
|
|
{!forCafe &&
|
|
<div className={styles.dateSelectorWrapper} style={{ fontSize: '13px' }}>
|
|
<div
|
|
className={`${styles.dateSelector} ${styles.dateSelectorActive}`} style={{ position: 'relative', width: 'calc(32vw - 30px)' }}
|
|
>
|
|
<div style={{ position: 'absolute', bottom: 0, left: '10%', right: '10%', borderBottom: `1px solid green` }}></div>
|
|
<div
|
|
style={{ color: 'black' }}>
|
|
Voucher
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
<div style={{ padding: '25px', paddingTop: '0', paddingBottom: '0' }}>
|
|
|
|
{coupons && coupons.map((coupon) => {
|
|
return <Coupon
|
|
code={coupon?.code || null}
|
|
value={coupon?.discountValue}
|
|
period={coupon?.discountPeriods}
|
|
expiration={coupon?.discountEndDate}
|
|
/>
|
|
})}
|
|
<button className={`${styles.addCoupon}`} onClick={() => setModal('claim-coupon')}>Tambahkan Voucher</button>
|
|
</div>
|
|
</>
|
|
}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default App;
|