diff --git a/src/components/DailyCharts.js b/src/components/DailyCharts.js index 152da11..53668dd 100644 --- a/src/components/DailyCharts.js +++ b/src/components/DailyCharts.js @@ -23,41 +23,50 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ "21-24", ]; 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 = [] - if(graphFilter == 'transactions'){ - seriesData = [ - dayData.hour0To3Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour3To6Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour6To9Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour9To12Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour12To15Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour15To18Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour18To21Transactions.reduce((acc, t) => acc + t.sold, 0), - dayData.hour21To24Transactions.reduce((acc, t) => acc + t.sold, 0), - ]; - } - else if(graphFilter == 'income'){ + if (graphFilter == 'transactions') { seriesData = [ - dayData.hour0To3Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour3To6Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour6To9Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour9To12Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour12To15Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour15To18Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour18To21Transactions.reduce((acc, t) => acc + t.totalPrice, 0), - dayData.hour21To24Transactions.reduce((acc, t) => acc + t.totalPrice, 0), + sumSold(dayData?.hour0To3Transactions), + sumSold(dayData?.hour3To6Transactions), + sumSold(dayData?.hour6To9Transactions), + sumSold(dayData?.hour9To12Transactions), + sumSold(dayData?.hour12To15Transactions), + sumSold(dayData?.hour15To18Transactions), + sumSold(dayData?.hour18To21Transactions), + sumSold(dayData?.hour21To24Transactions), ]; } - else if(graphFilter == 'outcome'){ + else if (graphFilter == 'income') { seriesData = [ - dayData.hour3To6MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour6To9MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour0To3MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour9To12MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour12To15MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour15To18MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour18To21MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), - dayData.hour21To24MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0), + sumTotal(dayData?.hour0To3Transactions), + sumTotal(dayData?.hour3To6Transactions), + sumTotal(dayData?.hour6To9Transactions), + sumTotal(dayData?.hour9To12Transactions), + sumTotal(dayData?.hour12To15Transactions), + sumTotal(dayData?.hour15To18Transactions), + sumTotal(dayData?.hour18To21Transactions), + sumTotal(dayData?.hour21To24Transactions), + ]; + } + else if (graphFilter == 'outcome') { + seriesData = [ + sumOutcome(dayData?.hour0To3MaterialIds), + sumOutcome(dayData?.hour3To6MaterialIds), + sumOutcome(dayData?.hour6To9MaterialIds), + sumOutcome(dayData?.hour9To12MaterialIds), + sumOutcome(dayData?.hour12To15MaterialIds), + sumOutcome(dayData?.hour15To18MaterialIds), + sumOutcome(dayData?.hour18To21MaterialIds), + sumOutcome(dayData?.hour21To24MaterialIds), ]; } return { @@ -85,21 +94,21 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ 0 ); - const formatDate = (dateString) => { - const date = new Date(dateString); // Parse the date string - - // Create an array of month names (use the same names you had earlier) - const monthNames = [ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - ]; - - // Get the month and day - const month = monthNames[date.getMonth()]; // Month is 0-indexed (January = 0) - const day = date.getDate(); // Get the day of the month - - return { month, day }; // Return the result - }; - + const formatDate = (dateString) => { + const date = new Date(dateString); // Parse the date string + + // Create an array of month names (use the same names you had earlier) + const monthNames = [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + ]; + + // Get the month and day + const month = monthNames[date.getMonth()]; // Month is 0-indexed (January = 0) + const day = date.getDate(); // Get the day of the month + + return { month, day }; // Return the result + }; + return (
{chartData && @@ -119,22 +128,22 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ key={indexx} className={`${styles.dateSelector} ${index === indexx ? styles.dateSelectorActive : styles.dateSelectorInactive }`} - style={{position: 'relative' }} + style={{ position: 'relative' }} onClick={() => type == 'yesterday' && selectedIndex == -1 || type != 'yesterday' && selectedIndex !== index ? setSelectedIndex(index) : setSelectedIndex(-1) } - // style={{ backgroundColor: index === indexx ? colors[index % colors.length] : 'transparent' }} + // style={{ backgroundColor: index === indexx ? colors[index % colors.length] : 'transparent' }} > -
-
+
+
{indexx !== chartData.length - 1 ? ( <> {day}{" "} {(indexx === 0 || (formatDate(chartData[indexx - 1].date).month !== month && type != 'weekly')) && month} ) : ( - 'Kemarin' + 'Hari ini' )}
diff --git a/src/components/Header.js b/src/components/Header.js index f514d1f..38ab8a4 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -368,7 +368,7 @@ const Header = ({ {shopName} - Mode pengembangan   + Mode Edit   setModal("reports")}>Lihat laporan setModal("add_material")}> - Kelola bahan baku + Kelola stok @@ -423,7 +423,7 @@ const Header = ({ {shopName} - Mode pengembangan  + Mode Edit  setModal("add_material")}> - Kelola bahan baku + Kelola stok diff --git a/src/components/Item.js b/src/components/Item.js index fe3b53f..1a952da 100644 --- a/src/components/Item.js +++ b/src/components/Item.js @@ -200,7 +200,7 @@ const Item = ({ lineHeight: '1rem', justifyContent: 'center' }}> - Promo {(((initialPrice - promoPrice) / initialPrice) * 100).toFixed(0)}% + Promo
diff --git a/src/components/ItemConfig.js b/src/components/ItemConfig.js index a3498f4..8b917f8 100644 --- a/src/components/ItemConfig.js +++ b/src/components/ItemConfig.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import styles from "./Modal.module.css"; -import { getImageUrl } from "../helpers/itemHelper.js"; +import { ThreeDots } from "react-loader-spinner"; + const ItemConfig = ({ name: initialName, @@ -24,11 +25,14 @@ const ItemConfig = ({ const fileInputRef = useRef(null); const textareaRef = useRef(null); + const [isSaving, setIsSaving] = useState(false); + + useEffect(() => { // Prevent scrolling when modal is open document.body.style.overflow = "hidden"; - if(selectedImage){ + if (selectedImage) { const reader = new FileReader(); reader.onloadend = () => { setPreviewUrl(reader.result); @@ -79,18 +83,27 @@ const ItemConfig = ({ return () => textarea.removeEventListener("input", handleResize); } }, [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 = () => { - console.log(itemPromoPrice) - handleCreateItem(itemName, itemPrice, selectedImage, previewUrl, itemDescription, itemPromoPrice); - document.body.style.overflow = "auto"; - }; - const handleUpdate = () => { - console.log(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice) - handleUpdateItem(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice); - document.body.style.overflow = "auto"; + const handleUpdate = async () => { + setIsSaving(true); + try { + await handleUpdateItem(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice); + document.body.style.overflow = "auto"; + } finally { + setIsSaving(false); + } }; + return (
@@ -131,7 +144,7 @@ const ItemConfig = ({ transition: 'all 0.3s ease', boxSizing: 'border-box', // Make sure the padding doesn't cause overflow }} - onChange={(e)=>setItemName(e.target.value)} + onChange={(e) => setItemName(e.target.value)} onFocus={(e) => e.target.style.borderColor = '#60d37e'} onBlur={(e) => e.target.style.borderColor = '#ccc'} /> @@ -153,7 +166,7 @@ const ItemConfig = ({ transition: 'all 0.3s ease', boxSizing: 'border-box', }} - onChange={(e)=>setItemPrice(e.target.value)} + onChange={(e) => setItemPrice(e.target.value)} onFocus={(e) => e.target.style.borderColor = '#60d37e'} onBlur={(e) => e.target.style.borderColor = '#ccc'} /> @@ -174,7 +187,7 @@ const ItemConfig = ({ transition: 'all 0.3s ease', boxSizing: 'border-box', }} - onChange={(e)=>setItemPromoPrice(e.target.value)} + onChange={(e) => setItemPromoPrice(e.target.value)} onFocus={(e) => e.target.style.borderColor = '#60d37e'} onBlur={(e) => e.target.style.borderColor = '#ccc'} /> @@ -200,17 +213,40 @@ const ItemConfig = ({ }} placeholder="Tambah deskripsi..." value={itemDescription} - onChange={(e)=>setItemDescription(e.target.value)} + onChange={(e) => setItemDescription(e.target.value)} onFocus={(e) => e.target.style.borderColor = '#60d37e'} onBlur={(e) => e.target.style.borderColor = '#ccc'} />
+
{ + 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 ? ( -
-
{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' + )}
+
); diff --git a/src/components/ItemLister.js b/src/components/ItemLister.js index 39560ba..97ac347 100644 --- a/src/components/ItemLister.js +++ b/src/components/ItemLister.js @@ -713,15 +713,6 @@ const ItemLister = ({ } imageUrl={getImageUrl("uploads/assets/addnew.png")} /> - {/* {typeImage != null && !previewUrl.includes(typeImage) && ( - - handleImageChange(previewUrl, selectedImage) - } - imageUrl={getImageUrl(typeImage)} - /> - )} */} - )} {(isEdit && !isFirstStep || !isEdit) && diff --git a/src/components/ItemLister.module.css b/src/components/ItemLister.module.css index a71335f..5bba86b 100644 --- a/src/components/ItemLister.module.css +++ b/src/components/ItemLister.module.css @@ -24,60 +24,8 @@ /* padding: 10px; */ /* max-height: calc(3 * (25vw - 20px) + 20px); */ 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 { display: flex; diff --git a/src/components/Modal.module.css b/src/components/Modal.module.css index c86453c..bb70d9e 100644 --- a/src/components/Modal.module.css +++ b/src/components/Modal.module.css @@ -36,3 +36,4 @@ .closeButton:hover { color: #f44336; /* Change color on hover for better UX */ } + diff --git a/src/pages/CafePage.js b/src/pages/CafePage.js index eebdc97..26a3a6e 100644 --- a/src/pages/CafePage.js +++ b/src/pages/CafePage.js @@ -19,6 +19,8 @@ import { MusicPlayer } from "../components/MusicPlayer"; import ItemLister from "../components/ItemLister"; import Header from "../components/Header"; +import Switch from "react-switch"; + import { ThreeDots } from "react-loader-spinner"; import { getLocalStorage, updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers"; @@ -152,7 +154,7 @@ function CafePage({ socket.on("joined-room", (response) => { const { isSpotifyNeedLogin, isExceededDeadline } = response; setNeedSpotifyLogin(isSpotifyNeedLogin); - if (isExceededDeadline) setModal("message",{captMessage:'Kafe sedang tidak tersedia'}); + if (isExceededDeadline) setModal("message", { captMessage: 'Kafe sedang tidak tersedia' }); setIsExceededDeadline(isExceededDeadline); }); } @@ -222,133 +224,156 @@ function CafePage({ isFullscreen={true} /> ) : ( */} -
- - {API_BASE_URL != 'https://dev.api.kedaimaster.com' && API_BASE_URL != 'https://api.kedaimaster.com' && -
- } -
-
setIsEditMode(e)} - isEditMode={isEditMode} - /> - -
- setFilterId(e)} - filterId={filterId} - beingEditedType={beingEditedType} - setBeingEditedType={setBeingEditedType} - /> - {/*
*/} -
- {shopItems - .filter( - (itemType) => - filterId == 0 || itemType.itemTypeId === filterId - ) - .map((itemType, index) => ( - moveItemTypeHandler(e, 'up', index)} - moveItemTypeDown={(e) => moveItemTypeHandler(e, 'down', index)} - isEditMode={isEditMode} - beingEditedType={beingEditedType} - setBeingEditedType={setBeingEditedType} - raw={isEditMode || filterId == 0 ? false : true} - handleCreateItem={( - itemTypeID, - name, - price, - selectedImage, - description, - promoPrice, - ) => - createItem( - shopId, - name, - price, - selectedImage, - itemTypeID, - description, - promoPrice, - ) +
+ + {API_BASE_URL != 'https://dev.api.kedaimaster.com' && API_BASE_URL != 'https://api.kedaimaster.com' && +
+ } +
+
setIsEditMode(e)} + isEditMode={isEditMode} + /> + { + user.username !== undefined && + (user.cafeId === shopId || user.user_id === shopOwnerId) && + (user.roleId === 1 || user.roleId === 2) && ( +
+ Mode Edit  + setIsEditMode(!isEditMode)} + /> +
+ ) +} + + setFilterId(e)} + filterId={filterId} + beingEditedType={beingEditedType} + setBeingEditedType={setBeingEditedType} + /> + {/*
*/} +
+ {shopItems + .filter( + (itemType) => + filterId == 0 || itemType.itemTypeId === filterId + ) + .map((itemType, index) => ( + moveItemTypeHandler(e, 'up', index)} + moveItemTypeDown={(e) => moveItemTypeHandler(e, 'down', index)} + isEditMode={isEditMode} + beingEditedType={beingEditedType} + setBeingEditedType={setBeingEditedType} + raw={isEditMode || filterId == 0 ? false : true} + handleCreateItem={( + itemTypeID, + name, + price, + selectedImage, + description, + promoPrice, + ) => + createItem( + shopId, + name, + price, + selectedImage, + itemTypeID, + description, + promoPrice, + ) + } + handleUpdateItem={(itemId, name, price, selectedImage, description, promoPrice) => + updateItem(itemId, name, price, selectedImage, description, promoPrice) + } + /> + ))} + {!isEditMode && (user.username || cartItemsLength > 0) && +
+ {(lastTransaction != null || cartItemsLength > 0) && +
+
{lastTransaction != null && '+'}{cartItemsLength} item
+
+ {((lastTransaction == null || lastTransaction?.payment_type != 'paylater')) ? + Rp{totalPrice} + : + Open bill } - handleUpdateItem={(itemId, name, price, selectedImage, description, promoPrice) => - updateItem(itemId, name, price, selectedImage, description, promoPrice) - } - /> - ))} - {!isEditMode && (user.username || cartItemsLength > 0) && -
- {(lastTransaction != null || cartItemsLength > 0) && -
-
{lastTransaction != null && '+'}{cartItemsLength} item
-
- {((lastTransaction == null || lastTransaction?.payment_type != 'paylater')) ? - Rp{totalPrice} - : - Open bill - } -
- - - -
-
+
+ + +
- } - {user.username && -
0 ? '6px' : '0px' }}> -
-
- - - + + - - - -
-
+ /> + +
- } +
}
-
- + }
+
+ +
{/* )} */} ); diff --git a/src/pages/CreateClerk.js b/src/pages/CreateClerk.js index 12836b1..a5a2dea 100644 --- a/src/pages/CreateClerk.js +++ b/src/pages/CreateClerk.js @@ -28,7 +28,7 @@ const CreateClerk = ({ shopId }) => { try { 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'); } catch (error) { setMessage('Error creating clerk'); diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js index e29faa4..5dae758 100644 --- a/src/pages/Dashboard.js +++ b/src/pages/Dashboard.js @@ -100,7 +100,7 @@ const LinktreePage = ({ user, setModal }) => { const modal = "product"; const productId = 1; - const authorizedUri = "http://localhost:3000?token="; + const authorizedUri = "https://kedaimaster.com?token="; const unauthorizedUri = `${baseUrl}?modal=${modal}&product_id=${productId}`; const url = diff --git a/src/pages/MaterialList.js b/src/pages/MaterialList.js index eb98f7e..86dc0a1 100644 --- a/src/pages/MaterialList.js +++ b/src/pages/MaterialList.js @@ -231,7 +231,7 @@ const SetPaymentQr = ({ cafeId }) => { <> ) : ( <> -

Bahan baku

+

Stok

setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} /> {selectedMaterialIndex !== -1 ? ( <> diff --git a/src/pages/Reports.js b/src/pages/Reports.js index 11cf692..2b006f9 100644 --- a/src/pages/Reports.js +++ b/src/pages/Reports.js @@ -323,8 +323,6 @@ const App = ({ forCafe = true, cafeId = -1, } else if (otherCafes.length === 1) { updatedFullTexts = [ [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) @@ -507,7 +505,7 @@ const App = ({ forCafe = true, cafeId = -1, marginTop: '30px' }}>
- {(filter == 'yesterday' || filter == 'weekly') ? + {(filter == 'weekly') ? `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.`}
@@ -628,7 +628,7 @@ const App = ({ forCafe = true, cafeId = -1, } style={{ color: 'black', position: 'relative' }} > -
Item laku
+
Penjualan