This commit is contained in:
Vassshhh
2025-08-27 02:53:44 +07:00
parent e039fc8acc
commit ba896106d4
12 changed files with 292 additions and 283 deletions

View File

@@ -23,41 +23,50 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ
"21-24", "21-24",
]; ];
console.log(dayData) console.log(dayData)
const sumSold = (transactions) =>
Array.isArray(transactions) ? transactions.reduce((acc, t) => acc + t.sold, 0) : transactions.transaction || 0;
const sumTotal = (transactions) =>
Array.isArray(transactions) ? transactions.reduce((acc, t) => acc + t.totalPrice, 0) : transactions.income || 0;
const sumOutcome = (transactions) =>
Array.isArray(transactions) ? transactions.reduce((acc, t) => acc + t.materialOutcome || t.price, 0) : transactions.outcome || 0;
let seriesData = [] let seriesData = []
if (graphFilter == 'transactions') { if (graphFilter == 'transactions') {
seriesData = [ seriesData = [
dayData.hour0To3Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour0To3Transactions),
dayData.hour3To6Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour3To6Transactions),
dayData.hour6To9Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour6To9Transactions),
dayData.hour9To12Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour9To12Transactions),
dayData.hour12To15Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour12To15Transactions),
dayData.hour15To18Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour15To18Transactions),
dayData.hour18To21Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour18To21Transactions),
dayData.hour21To24Transactions.reduce((acc, t) => acc + t.sold, 0), sumSold(dayData?.hour21To24Transactions),
]; ];
} }
else if (graphFilter == 'income') { else if (graphFilter == 'income') {
seriesData = [ seriesData = [
dayData.hour0To3Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour0To3Transactions),
dayData.hour3To6Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour3To6Transactions),
dayData.hour6To9Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour6To9Transactions),
dayData.hour9To12Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour9To12Transactions),
dayData.hour12To15Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour12To15Transactions),
dayData.hour15To18Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour15To18Transactions),
dayData.hour18To21Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour18To21Transactions),
dayData.hour21To24Transactions.reduce((acc, t) => acc + t.totalPrice, 0), sumTotal(dayData?.hour21To24Transactions),
]; ];
} }
else if (graphFilter == 'outcome') { else if (graphFilter == 'outcome') {
seriesData = [ seriesData = [
dayData.hour3To6MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour0To3MaterialIds),
dayData.hour6To9MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour3To6MaterialIds),
dayData.hour0To3MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour6To9MaterialIds),
dayData.hour9To12MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour9To12MaterialIds),
dayData.hour12To15MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour12To15MaterialIds),
dayData.hour15To18MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour15To18MaterialIds),
dayData.hour18To21MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour18To21MaterialIds),
dayData.hour21To24MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), sumOutcome(dayData?.hour21To24MaterialIds),
]; ];
} }
return { return {
@@ -134,7 +143,7 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ
{(indexx === 0 || (formatDate(chartData[indexx - 1].date).month !== month && type != 'weekly')) && month} {(indexx === 0 || (formatDate(chartData[indexx - 1].date).month !== month && type != 'weekly')) && month}
</> </>
) : ( ) : (
'Kemarin' 'Hari ini'
)} )}
</div> </div>

View File

@@ -368,7 +368,7 @@ const Header = ({
{shopName} {shopName}
</Child> </Child>
<Child> <Child>
Mode pengembangan &nbsp; Mode Edit &nbsp;
<Switch <Switch
borderRadius={0} borderRadius={0}
checked={isEditMode} checked={isEditMode}
@@ -377,7 +377,7 @@ const Header = ({
</Child> </Child>
<Child onClick={() => setModal("reports")}>Lihat laporan</Child> <Child onClick={() => setModal("reports")}>Lihat laporan</Child>
<Child onClick={() => setModal("add_material")}> <Child onClick={() => setModal("add_material")}>
Kelola bahan baku Kelola stok
</Child> </Child>
<Child hasChildren> <Child hasChildren>
@@ -423,7 +423,7 @@ const Header = ({
<Child>{shopName}</Child> <Child>{shopName}</Child>
<Child> <Child>
Mode pengembangan&nbsp; Mode Edit&nbsp;
<Switch <Switch
borderRadius={0} borderRadius={0}
checked={isEditMode} checked={isEditMode}
@@ -431,7 +431,7 @@ const Header = ({
/> />
</Child> </Child>
<Child onClick={() => setModal("add_material")}> <Child onClick={() => setModal("add_material")}>
Kelola bahan baku Kelola stok
</Child> </Child>
<Child hasChildren> <Child hasChildren>

View File

@@ -200,7 +200,7 @@ const Item = ({
lineHeight: '1rem', lineHeight: '1rem',
justifyContent: 'center' justifyContent: 'center'
}}> }}>
Promo {(((initialPrice - promoPrice) / initialPrice) * 100).toFixed(0)}% Promo
</div> </div>
<div style={{ display: 'flex' }}> <div style={{ display: 'flex' }}>

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import styles from "./Modal.module.css"; import styles from "./Modal.module.css";
import { getImageUrl } from "../helpers/itemHelper.js"; import { ThreeDots } from "react-loader-spinner";
const ItemConfig = ({ const ItemConfig = ({
name: initialName, name: initialName,
@@ -24,6 +25,9 @@ const ItemConfig = ({
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
const textareaRef = useRef(null); const textareaRef = useRef(null);
const [isSaving, setIsSaving] = useState(false);
useEffect(() => { useEffect(() => {
// Prevent scrolling when modal is open // Prevent scrolling when modal is open
@@ -79,18 +83,27 @@ const ItemConfig = ({
return () => textarea.removeEventListener("input", handleResize); return () => textarea.removeEventListener("input", handleResize);
} }
}, [textareaRef.current]); }, [textareaRef.current]);
const handleCreate = async () => {
setIsSaving(true);
try {
await handleCreateItem(itemName, itemPrice, selectedImage, previewUrl, itemDescription, itemPromoPrice);
document.body.style.overflow = "auto";
} finally {
setIsSaving(false);
}
};
const handleCreate = () => { const handleUpdate = async () => {
console.log(itemPromoPrice) setIsSaving(true);
handleCreateItem(itemName, itemPrice, selectedImage, previewUrl, itemDescription, itemPromoPrice); try {
document.body.style.overflow = "auto"; await handleUpdateItem(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice);
};
const handleUpdate = () => {
console.log(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice)
handleUpdateItem(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice);
document.body.style.overflow = "auto"; document.body.style.overflow = "auto";
} finally {
setIsSaving(false);
}
}; };
return ( return (
<div onClick={handleOverlayClick} style={{ position: 'fixed', width: '100vw', height: '100vh', left: 0, bottom: 0, display: 'flex', flexDirection: 'column-reverse', zIndex: 301, backgroundColor: '#00000061' }}> <div onClick={handleOverlayClick} style={{ position: 'fixed', width: '100vw', height: '100vh', left: 0, bottom: 0, display: 'flex', flexDirection: 'column-reverse', zIndex: 301, backgroundColor: '#00000061' }}>
<div onClick={handleContentClick} style={{ display: 'flex', flexDirection: 'column', padding: '15px', backgroundColor: 'white', borderRadius: '20px 20px 0 0', overflowY: 'auto' }}> <div onClick={handleContentClick} style={{ display: 'flex', flexDirection: 'column', padding: '15px', backgroundColor: 'white', borderRadius: '20px 20px 0 0', overflowY: 'auto' }}>
@@ -205,12 +218,35 @@ const ItemConfig = ({
onBlur={(e) => e.target.style.borderColor = '#ccc'} onBlur={(e) => e.target.style.borderColor = '#ccc'}
/> />
</div> </div>
<div
onClick={() => {
if (!isSaving) {
isBeingEdit ? handleUpdate() : handleCreate();
}
}}
style={{
width: '100%',
height: '40px',
alignContent: 'center',
textAlign: 'center',
borderRadius: '10px',
border: '1px solid #60d37e',
color: isSaving ? '#aaa' : '#60d37e',
backgroundColor: 'white',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
cursor: isSaving ? 'not-allowed' : 'pointer'
}}
>
{isSaving ? (
<div style={{ width: '100%', height: '35px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <ThreeDots height={20} width={20} />
<div onClick={() => {isBeingEdit ? handleUpdate() : handleCreate()} } style={{ width: '100%', height: '40px', alignContent: 'center', textAlign: 'center', borderRadius: '10px', border: '1px solid #60d37e', color: '#60d37e', backgroundColor: 'white', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> ) : (
{isBeingEdit? 'Simpan' : 'Buat Item'} isBeingEdit ? 'Simpan' : 'Buat Item'
</div> )}
</div> </div>
</div> </div>
</div> </div>
); );

View File

@@ -713,15 +713,6 @@ const ItemLister = ({
} }
imageUrl={getImageUrl("uploads/assets/addnew.png")} imageUrl={getImageUrl("uploads/assets/addnew.png")}
/> />
{/* {typeImage != null && !previewUrl.includes(typeImage) && (
<ItemType
rectangular={true}
onClick={(previewUrl, selectedImage) =>
handleImageChange(previewUrl, selectedImage)
}
imageUrl={getImageUrl(typeImage)}
/>
)} */}
<ItemType <ItemType
rectangular={true} rectangular={true}
@@ -857,7 +848,6 @@ const ItemLister = ({
); );
})} })}
</div> </div>
<button onClick={() => setIsFirstStep(false)} style={{ width: '100%', height: '40px', borderRadius: '20px' }}>selanjutnya</button>
</> </>
)} )}
{(isEdit && !isFirstStep || !isEdit) && {(isEdit && !isFirstStep || !isEdit) &&

View File

@@ -24,60 +24,8 @@
/* padding: 10px; */ /* padding: 10px; */
/* max-height: calc(3 * (25vw - 20px) + 20px); */ /* max-height: calc(3 * (25vw - 20px) + 20px); */
overflow-y: auto; overflow-y: auto;
height: calc(49vw - 20px);
} }
@media (min-height: 0px) {
.grid-container {
height: 27vh;
}
}
@media (min-height: 630px) {
.grid-container {
height: 27vh;
}
}
@media (min-height: 636px) {
.grid-container {
height: 29vh;
}
}
@media (min-height: 650px) {
.grid-container {
height: 34vh;
}
}
@media (min-height: 705px) {
.grid-container {
height: 37vh;
}
}
@media (min-height: 735px) {
.grid-container {
height: 38vh;
}
}
@media (min-height: 759px) {
.grid-container {
height: 40vh;
}
}
@media (min-height: 819px) {
.grid-container {
height: 44vh;
}
}
@media (min-height: 830px) {
.grid-container {
height: 47vh;
}
}
@media (min-height: 892px) {
.grid-container {
height: 49vh;
}
}
.title-container { .title-container {
display: flex; display: flex;

View File

@@ -36,3 +36,4 @@
.closeButton:hover { .closeButton:hover {
color: #f44336; /* Change color on hover for better UX */ color: #f44336; /* Change color on hover for better UX */
} }

View File

@@ -19,6 +19,8 @@ import { MusicPlayer } from "../components/MusicPlayer";
import ItemLister from "../components/ItemLister"; import ItemLister from "../components/ItemLister";
import Header from "../components/Header"; import Header from "../components/Header";
import Switch from "react-switch";
import { ThreeDots } from "react-loader-spinner"; import { ThreeDots } from "react-loader-spinner";
import { getLocalStorage, updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers"; import { getLocalStorage, updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
@@ -254,8 +256,31 @@ function CafePage({
isSpotifyNeedLogin={isSpotifyNeedLogin} isSpotifyNeedLogin={isSpotifyNeedLogin}
queue={queue} queue={queue}
setModal={setModal} setModal={setModal}
/>{
user.username !== undefined &&
(user.cafeId === shopId || user.user_id === shopOwnerId) &&
(user.roleId === 1 || user.roleId === 2) && (
<div style={{
backgroundColor: '#5c7c5c',
padding: '7px 28px',
margin: '0 10px',
borderRadius: '15px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
textShadow: '2px 2px 4px rgba(0, 0, 0, 0.7)',
fontSize: '16px'
}}>
Mode Edit&nbsp;
<Switch
borderRadius={0}
checked={isEditMode}
onChange={() => setIsEditMode(!isEditMode)}
/> />
<div></div> </div>
)
}
<ItemTypeLister <ItemTypeLister
user={user} user={user}
shopOwnerId={shopOwnerId} shopOwnerId={shopOwnerId}

View File

@@ -28,7 +28,7 @@ const CreateClerk = ({ shopId }) => {
try { try {
const create = await createClerks(shopId || cafeIdParam, username, password); const create = await createClerks(shopId || cafeIdParam, username, password);
if (create) setMessage('Clerk created successfully'); if (create) {setMessage('Clerk created successfully');}
else setMessage('Failed to create clerk'); else setMessage('Failed to create clerk');
} catch (error) { } catch (error) {
setMessage('Error creating clerk'); setMessage('Error creating clerk');

View File

@@ -100,7 +100,7 @@ const LinktreePage = ({ user, setModal }) => {
const modal = "product"; const modal = "product";
const productId = 1; const productId = 1;
const authorizedUri = "http://localhost:3000?token="; const authorizedUri = "https://kedaimaster.com?token=";
const unauthorizedUri = `${baseUrl}?modal=${modal}&product_id=${productId}`; const unauthorizedUri = `${baseUrl}?modal=${modal}&product_id=${productId}`;
const url = const url =

View File

@@ -231,7 +231,7 @@ const SetPaymentQr = ({ cafeId }) => {
<></> <></>
) : ( ) : (
<> <>
<h3 className={styles.title}>Bahan baku</h3> <h3 className={styles.title}>Stok</h3>
<Carousel items={materials} onSelect={(e) => setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} /> <Carousel items={materials} onSelect={(e) => setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} />
{selectedMaterialIndex !== -1 ? ( {selectedMaterialIndex !== -1 ? (
<> <>

View File

@@ -323,8 +323,6 @@ const App = ({ forCafe = true, cafeId = -1,
} else if (otherCafes.length === 1) { } else if (otherCafes.length === 1) {
updatedFullTexts = [ updatedFullTexts = [
[otherCafes[0].cafeIdentifyName || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].user_id], [otherCafes[0].cafeIdentifyName || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].user_id],
...(user.roleId == 1 ? [[-1]] : [])
]; ];
setSelectedCafeId(otherCafes[0].cafeId); // Get the cafeId (second part of the pair) setSelectedCafeId(otherCafes[0].cafeId); // Get the cafeId (second part of the pair)
@@ -507,7 +505,7 @@ const App = ({ forCafe = true, cafeId = -1,
marginTop: '30px' marginTop: '30px'
}}> }}>
<MultiSwitch <MultiSwitch
texts={["Kemarin", "Minggu ini", "Bulan ini", "Tahun ini"]} texts={["Hari ini", "Minggu ini", "Bulan ini", "Tahun ini"]}
selectedSwitch={["yesterday", "weekly", "monthly", "yearly"].indexOf( selectedSwitch={["yesterday", "weekly", "monthly", "yearly"].indexOf(
filter filter
)} )}
@@ -611,9 +609,11 @@ const App = ({ forCafe = true, cafeId = -1,
> >
<div style={{ marginRight: "5px", fontSize: "1.2em" }}></div> <div style={{ marginRight: "5px", fontSize: "1.2em" }}></div>
<h6 style={{ margin: 0, textAlign: "left", fontSize: '10px', fontWeight: 500 }}> <h6 style={{ margin: 0, textAlign: "left", fontSize: '10px', fontWeight: 500 }}>
{(filter == 'yesterday' || filter == 'weekly') ? {(filter == 'weekly') ?
`Data dihitung dengan membandingkan `Data dihitung dengan membandingkan
${comparisonText} hari terakhir dengan ${comparisonText} hari sebelumnya, dengan penghitungan dimulai dari data kemarin.` 7 hari terakhir dengan 7 hari sebelumnya, dengan penghitungan dimulai dari data kemarin.`
:
(filter == 'yesterday') ? `Data dihitung dengan membandingkan antara hari ini dan 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.`} (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> </h6>
@@ -628,7 +628,7 @@ const App = ({ forCafe = true, cafeId = -1,
} }
style={{ color: 'black', position: 'relative' }} style={{ color: 'black', position: 'relative' }}
> >
<div>Item laku</div> <div>Penjualan</div>
</div> </div>
<div <div
className={`${styles.filterSelector} ${circularFilter == 'material' ? '' : styles.filterSelectorInactive} className={`${styles.filterSelector} ${circularFilter == 'material' ? '' : styles.filterSelectorInactive}