ok
This commit is contained in:
13
src/App.css
13
src/App.css
@@ -1,6 +1,7 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Aboreto&family=Rubik+Doodle+Shadow&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&ital,wght@0,200..800;1,200..800&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&display");
|
||||
|
||||
:root {
|
||||
--brand-primary: #73a585; /* general brand (e. g., music player) */
|
||||
--brand-sage: #6B8F71; /* sage green for active category */
|
||||
@@ -66,7 +67,15 @@ body {
|
||||
|
||||
/* Ensure sticky cart bar stays above item overlays */
|
||||
.StickyCartBar {
|
||||
z-index: 3000 !important;
|
||||
z-index: 100 !important; /* Menurunkan z-index agar tidak menutupi material list */
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: white;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 15px 20px;
|
||||
border-radius: 20px 20px 0 0;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import styles from "./Carousel.module.css"; // Import CSS module
|
||||
|
||||
const Carousel = ({ selectedIndex, items, onSelect }) => {
|
||||
|
||||
const moveToNext = () => {
|
||||
console.log('aa')
|
||||
if (selectedIndex < items.length - 1) {
|
||||
console.log('bb')
|
||||
onSelect(selectedIndex + 1); // Send the next index to the parent
|
||||
}
|
||||
};
|
||||
|
||||
const moveToPrev = () => {
|
||||
if (selectedIndex > -1) {
|
||||
onSelect(selectedIndex - 1); // Send the previous index to the parent
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.carouselContainer}>
|
||||
<div className={styles.carousel}>
|
||||
{/* Previous Item */}
|
||||
<div
|
||||
className={`${styles.carouselItem} ${styles.prev}`}
|
||||
onClick={moveToPrev}
|
||||
style={{ visibility: selectedIndex === -1 && items.length > 0 ? "hidden" : "visible" , backgroundColor: items.length < 1 ? '#919191':'#007bff'}}
|
||||
>
|
||||
{selectedIndex === -1 ? (items.length > 0 ? "+" : "") : items[selectedIndex - 1]?.name || "+"}
|
||||
</div>
|
||||
|
||||
{/* Current Item */}
|
||||
<div className={`${styles.carouselItem} ${styles.center}`}>
|
||||
{selectedIndex >= 0 ? items[selectedIndex]?.name : "+"}
|
||||
</div>
|
||||
|
||||
{/* Next Item */}
|
||||
<div
|
||||
className={`${styles.carouselItem} ${styles.next}`}
|
||||
onClick={moveToNext}
|
||||
style={{
|
||||
visibility: selectedIndex === items.length -1 && items.length > 0 ? "hidden" : "visible", backgroundColor: items.length < 1 ? '#919191':'#007bff'
|
||||
}}
|
||||
>
|
||||
{selectedIndex < items.length - 1 && items[selectedIndex + 1]?.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Carousel;
|
||||
@@ -1,74 +0,0 @@
|
||||
/* Carousel.module.css */
|
||||
.carouselContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.carouselItem {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
height: 200px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.carouselItem.prev,
|
||||
.carouselItem.next {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.carouselItem.center {
|
||||
transform: scale(1);
|
||||
width: 134%;
|
||||
}
|
||||
|
||||
.prevBtn,
|
||||
.nextBtn {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.prevBtn {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.nextBtn {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.carouselItem {
|
||||
font-size: 18px;
|
||||
height: 110px;
|
||||
}
|
||||
|
||||
.prevBtn,
|
||||
.nextBtn {
|
||||
padding: 8px 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
@@ -149,28 +149,18 @@ const Item = ({
|
||||
)}
|
||||
<div className={styles.itemDetails}>
|
||||
{forInvoice &&
|
||||
<svg
|
||||
className={styles.plusNegative2}
|
||||
onClick={onRemoveClick}
|
||||
clipRule="evenodd"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m12.002 2c5.518 0 9.998 4.48 9.998 9.998 0 5.517-4.48 9.997-9.998 9.997-5.517 0-9.997-4.48-9.997-9.997 0-5.518 4.48-9.998 9.997-9.998zm0 1.5c-4.69 0-8.497 3.808-8.497 8.498s3.807 8.497 8.497 8.497 8.498-3.807 8.498-8.497-3.808-8.498-8.498-8.498zm-.747 7.75h-3.5c-.414 0-.75.336-.75.75s.336.75.75.75h3.5v3.5c0 .414.336.75.75.75s.75-.336.75-.75v-3.5h3.5c.414 0 .75-.336.75-.75s-.336-.75-.75-.75h-3.5v-3.5c0-.414-.336-.75-.75-.75s-.75.336-.75.75z"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div className={styles.plusNegative2} onClick={onRemoveClick}>
|
||||
⌧
|
||||
</div>
|
||||
}
|
||||
{/* Title under image for portrait, non-overlay */}
|
||||
{portrait && null}
|
||||
{!portrait && (
|
||||
<div style={{ marginRight: forInvoice ? 10 : 0 }}>
|
||||
<h3 className={styles.title} style={{ width: forInvoice ? 160 : 'auto' }}>{displayName}</h3>
|
||||
{initialDescription && !forInvoice && (
|
||||
<p className={styles.desc}>{initialDescription}</p>
|
||||
)}
|
||||
{!forInvoice && (
|
||||
<div className={styles.priceRow}>
|
||||
{promoPrice && promoPrice != 0 && promoPrice != '' ? (
|
||||
@@ -207,9 +197,9 @@ const Item = ({
|
||||
!isBeingEdit ? (
|
||||
<div className={styles.itemQty}>
|
||||
<div className={styles.qtyGroup}>
|
||||
<button className={styles.qtyBtn} onClick={handleNegativeClick} aria-label="Kurangi" style={{ width: 32, height: 32, fontSize: 18 }}>-</button>
|
||||
<button className={styles.qtyBtn} onClick={handleNegativeClick} aria-label="Kurangi" style={{ width: 36, height: 36, fontSize: 18 }}>-</button>
|
||||
<span className={styles.qtyVal}>{itemQty}</span>
|
||||
<button className={styles.qtyBtn} onClick={handlePlusClick} aria-label="Tambah" style={{ width: 32, height: 32, fontSize: 18 }}>+</button>
|
||||
<button className={styles.qtyBtn} onClick={handlePlusClick} aria-label="Tambah" style={{ width: 36, height: 36, fontSize: 18 }}>+</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -8,17 +8,22 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
gap: 8px; /* Increased gap for better spacing */
|
||||
padding: 6px 8px; /* Increased padding for better touch targets */
|
||||
margin: 8px 0; /* Increased margin for better separation */
|
||||
border: 1px solid #e3ece6;
|
||||
border-radius: 8px; /* Slightly increased border radius */
|
||||
background: var(--brand-sage-50, #F0F6F2);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.03);
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.08);
|
||||
box-sizing: border-box;
|
||||
transition: box-shadow 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.item:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.08); border-color: #d9e6de; }
|
||||
|
||||
/* Portrait variant for cafe page grid */
|
||||
.itemPortrait {
|
||||
@@ -29,30 +34,84 @@
|
||||
border: none;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.imageWrap { position: relative; border-radius: 8px; overflow: hidden; box-shadow: 0 6px 18px rgba(0,0,0,0.12); }
|
||||
.imageContainer { display: block; width: 100%; height: 100%; object-fit: cover; }
|
||||
.itemPortrait .imageWrap { width: 100%; height: auto; aspect-ratio: 1 / 1; }
|
||||
.itemPortrait .imageContainer { border-radius: 6px; }
|
||||
.itemPortrait .itemDetails { align-items: flex-start; text-align: left; gap: 8px; } /* Increased gap */
|
||||
.itemPortrait .itemQty { justify-content: flex-start; }
|
||||
|
||||
.itemPortrait .title { font-size: 14px; } /* Increased font size */
|
||||
.itemPortrait .priceNow { font-size: 13px; } /* Increased font size */
|
||||
.imageWrap {
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.itemPortrait .imageWrap {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 1 / 1;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.itemPortrait .imageContainer {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.itemDetails {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.itemPortrait .itemDetails {
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
gap: 8px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.itemPortrait .itemQty {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.itemPortrait .title {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.itemPortrait .priceNow {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.notLast {
|
||||
padding-bottom: 12px; /* Increased padding */
|
||||
border-bottom: 2px solid #00000017;
|
||||
border-bottom: none;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.itemInvoice {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
font-size: 20px; /* Increased font size */
|
||||
font-size: 18px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
padding-top: 0px;
|
||||
padding: 16px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.itemInvoice:last-child {
|
||||
@@ -66,27 +125,28 @@
|
||||
|
||||
.item:not(.itemPortrait) .imageContainer {
|
||||
position: relative;
|
||||
width: clamp(80px, 20vw, 110px); /* Increased size */
|
||||
height: clamp(80px, 20vw, 110px); /* Increased size */
|
||||
border-radius: 12px; /* Increased border radius */
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
top: 18px; /* Increased top position */
|
||||
left: 10px; /* Increased left position */
|
||||
right: 10px; /* Increased right position */
|
||||
bottom: 18px; /* Increased bottom position */
|
||||
top: 16px;
|
||||
left: 12px;
|
||||
right: 12px;
|
||||
bottom: 16px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 20px; /* Increased border radius */
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
font-size: 3.8vw; /* Increased font size */
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.overlay:hover {
|
||||
@@ -97,24 +157,18 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.itemDetails {
|
||||
.infoRow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
gap: 8px; /* Increased gap */
|
||||
margin-left: 8px; /* Increased margin */
|
||||
margin-right: 8px; /* Increased margin */
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
.infoRow { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; } /* Increased gap */
|
||||
|
||||
.itemInvoiceDetails {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-left: 12px; /* Increased margin */
|
||||
margin-left: 12px;
|
||||
margin-top: -15px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
@@ -122,40 +176,47 @@
|
||||
.itemName {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-style: normal;
|
||||
width: calc(100% - 18px); /* Adjusted width */
|
||||
font-size: 5.5vw; /* Increased font size */
|
||||
font-weight: 500;
|
||||
width: calc(100% - 20px);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-top: 0;
|
||||
margin: 0 6px; /* Increased margin */
|
||||
color: rgba(88, 55, 50, 1);
|
||||
margin: 0 6px;
|
||||
color: #333;
|
||||
background-color: transparent;
|
||||
text-transform: capitalize;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.itemInvoiceName {
|
||||
width: calc(280% - 18px); /* Adjusted width */
|
||||
width: calc(260% - 20px);
|
||||
background-color: transparent;
|
||||
font-size: 1.4rem; /* Increased font size */
|
||||
font-weight: 500;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.multiplySymbol {
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.qtyInvoice {
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.itemPrice { display: none; }
|
||||
.itemPrice {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.itemPriceInvoice {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 1rem; /* Increased font size */
|
||||
margin-left: 6px; /* Increased margin */
|
||||
color: #d9c61c;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
margin-left: 6px;
|
||||
color: #6B8F71;
|
||||
text-align: right;
|
||||
margin-top: 22px;
|
||||
}
|
||||
@@ -164,30 +225,34 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10px; /* Increased gap */
|
||||
min-height: 36px; /* Increased height */
|
||||
gap: 12px;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.itemQtyValue {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
margin-top: 22px; /* Increased margin */
|
||||
font-weight: 700;
|
||||
margin-top: 22px;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
width: 30px; /* Increased width */
|
||||
width: 32px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.itemQtyInput {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
width: 36px; /* Increased width */
|
||||
font-size: 1rem; /* Increased font size */
|
||||
margin-bottom: 12px; /* Increased margin */
|
||||
font-weight: 700;
|
||||
width: 40px;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 12px;
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
@@ -195,188 +260,266 @@
|
||||
border: 1px solid var(--brand-sage, #6B8F71);
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
font-size: 14px; /* Increased font size */
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
min-width: 85px; /* Increased width */
|
||||
height: 36px; /* Increased height */
|
||||
padding: 0 14px; /* Increased padding */
|
||||
border-radius: 12px; /* Increased border radius */
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
||||
min-width: 90px;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 6px rgba(107, 143, 113, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.addButton:hover { background-color: var(--brand-sage-hover, #7FAE7D); border-color: var(--brand-sage-hover, #7FAE7D); }
|
||||
.addButton:disabled { background-color: var(--brand-sage-muted, #CFD8D3); border-color: var(--brand-sage-muted, #CFD8D3); cursor: default; }
|
||||
|
||||
.addButton:hover {
|
||||
background-color: var(--brand-sage-hover, #5a7a60);
|
||||
border-color: var(--brand-sage-hover, #5a7a60);
|
||||
box-shadow: 0 4px 10px rgba(107, 143, 113, 0.3);
|
||||
}
|
||||
|
||||
.addButton:disabled {
|
||||
background-color: var(--brand-sage-muted, #CFD8D3);
|
||||
border-color: var(--brand-sage-muted, #CFD8D3);
|
||||
cursor: default;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.grayscale {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: gray;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.plusNegative {
|
||||
width: 36px; /* Increased width */
|
||||
height: 36px; /* Increased height */
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ddd;
|
||||
background: #f8f9fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.plusNegative:hover {
|
||||
background: #e9ecef;
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.plusNegative2 {
|
||||
width: 90px; /* Increased width */
|
||||
height: 24px; /* Increased height */
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
left: -38px; /* Adjusted position */
|
||||
top: 24px; /* Adjusted position */
|
||||
right: 16px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ddd;
|
||||
background: #f8f9fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.plusNegative2:hover {
|
||||
background: #e9ecef;
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.remove {
|
||||
width: 30px; /* Increased width */
|
||||
height: 30px; /* Increased height */
|
||||
margin-top: -12px; /* Adjusted margin */
|
||||
margin-right: 12px; /* Adjusted margin */
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
border-radius: 50%;
|
||||
background: #ff4d4d;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 6px rgba(255, 77, 77, 0.3);
|
||||
}
|
||||
|
||||
.remove:hover {
|
||||
background: #ff1a1a;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* New elements for clean cafe item card */
|
||||
.title {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 18px; /* Increased font size */
|
||||
color: #2d2d2d;
|
||||
margin: 0 0 3px 0; /* Increased margin */
|
||||
font-size: 17px;
|
||||
color: #333;
|
||||
margin: 0 0 4px 0;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
text-transform: capitalize;
|
||||
text-align: left;
|
||||
flex: 1; min-width: 0;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Responsive type scale for title and price */
|
||||
@media (min-width: 600px) {
|
||||
.title { font-size: 19px; }
|
||||
.priceNow { font-size: 17px; }
|
||||
.title {
|
||||
font-size: 18px;
|
||||
}
|
||||
.priceNow {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.title { font-size: 20px; }
|
||||
.priceNow { font-size: 18px; }
|
||||
.title {
|
||||
font-size: 19px;
|
||||
}
|
||||
.priceNow {
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: #5f5f5f;
|
||||
font-size: 14px; /* Increased font size */
|
||||
line-height: 1.3;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
.priceRow { display: inline-flex; align-items: center; gap: 10px; } /* Increased gap */
|
||||
|
||||
/* Gaya harga baru untuk item list */
|
||||
.itemPriceList {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
color: #1c1d1d;
|
||||
margin: 2px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.itemPriceList.promo {
|
||||
color: #e53935;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.itemPriceList.original {
|
||||
color: #727272;
|
||||
font-size: 12px;
|
||||
text-decoration: line-through;
|
||||
.priceRow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.promoBadge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 3px 10px; /* Increased padding */
|
||||
height: 24px; /* Increased height */
|
||||
padding: 4px 10px;
|
||||
height: 24px;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(to right, #e52535, #fe6d78);
|
||||
color: #fff;
|
||||
font-size: 13px; /* Increased font size */
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.priceNow {
|
||||
color: #1c1d1d;
|
||||
font-weight: 700;
|
||||
font-size: 16px; /* Increased font size */
|
||||
font-size: 15px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.priceOld {
|
||||
color: #727272;
|
||||
font-size: 14px; /* Increased font size */
|
||||
font-size: 13px;
|
||||
text-decoration: line-through;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.qtyGroup {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border: 1px solid rgba(255,255,255,0.6);
|
||||
border-radius: 10px; /* Increased border radius */
|
||||
height: 30px; /* Increased height */
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 10px;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.qtyBtn {
|
||||
width: 30px; /* Increased width */
|
||||
height: 30px; /* Increased height */
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
background: #f8f9fa;
|
||||
color: #333;
|
||||
border: none;
|
||||
font-size: 20px; /* Increased font size */
|
||||
}
|
||||
.qtyBtn:hover { background: rgba(255,255,255,0.15); }
|
||||
.qtyVal {
|
||||
min-width: 26px; /* Increased width */
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
font-size: 15px; /* Increased font size */
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.actionRow { display: flex; align-items: center; gap: 8px; justify-content: space-between; width: 100%; } /* Increased gap */
|
||||
.qtyBtn:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
.qtyVal {
|
||||
min-width: 30px;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.actionRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Promo pill overlay on image */
|
||||
.promoPill {
|
||||
position: absolute;
|
||||
top: 14px; /* Increased top position */
|
||||
right: 14px; /* Increased right position */
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 2;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 12px; /* Increased padding */
|
||||
padding: 6px 12px;
|
||||
height: auto;
|
||||
border-radius: 10px; /* Increased border radius */
|
||||
border-radius: 8px;
|
||||
background: #e53935;
|
||||
color: #fff;
|
||||
font-size: 13px; /* Increased font size */
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 2px 6px rgba(229, 57, 53, 0.3);
|
||||
}
|
||||
|
||||
/* Info overlay on image (name + price) */
|
||||
.overlayName {
|
||||
position: absolute;
|
||||
top: 14px; /* Increased top position */
|
||||
left: 14px; /* Increased left position */
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
z-index: 2;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 800;
|
||||
font-size: 16px; /* Increased font size */
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
line-height: 1.3;
|
||||
color: #fff;
|
||||
mix-blend-mode: difference;
|
||||
margin: 0;
|
||||
max-width: 75%; /* Increased width */
|
||||
max-width: 70%;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
@@ -384,10 +527,30 @@
|
||||
pointer-events: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
@media (min-width: 600px) { .overlayName { font-size: 17px; } }
|
||||
.overlayPrice { display: flex; align-items: center; gap: 8px; } /* Increased gap */
|
||||
.overlayNow { color: #fff; font-weight: 800; font-size: 14px; } /* Increased font size */
|
||||
.overlayOld { color: rgba(255,255,255,0.8); font-size: 13px; text-decoration: line-through; } /* Increased font size */
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.overlayName {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.overlayPrice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.overlayNow {
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.overlayOld {
|
||||
color: rgba(255,255,255,0.8);
|
||||
font-size: 12px;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
/* Bottom overlay bar: price left, qty right */
|
||||
.bottomOverlay {
|
||||
@@ -399,36 +562,66 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 12px; /* Increased padding */
|
||||
background: rgba(0,0,0,0.55);
|
||||
padding: 10px 12px;
|
||||
background: rgba(0,0,0,0.6);
|
||||
color: #fff;
|
||||
border-radius: 0 0 12px 12px;
|
||||
}
|
||||
|
||||
/* New stacked price for clarity */
|
||||
.overlayPriceCol { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.2; } /* Increased line height */
|
||||
.overlayOriginal { color: rgba(255,255,255,0.85); font-weight: 700; font-size: 12px; text-decoration: line-through; } /* Increased font size */
|
||||
@media (min-width: 600px) { .overlayOriginal { font-size: 13px; } }
|
||||
.overlayPromo { color: #fff; font-weight: 900; font-size: 18px; } /* Increased font size */
|
||||
.overlayPriceCol {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.overlayOriginal {
|
||||
color: rgba(255,255,255,0.85);
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.overlayOriginal { font-size: 16px; } /* Increased font size */
|
||||
.overlayPromo { font-size: 20px; } /* Increased font size */
|
||||
.overlayOriginal {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.overlayPromo {
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.overlayOriginal {
|
||||
font-size: 15px;
|
||||
}
|
||||
.overlayPromo {
|
||||
font-size: 19px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Title text below image for portrait mode */
|
||||
.title {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 16px; /* Increased font size */
|
||||
color: #1c1d1d;
|
||||
margin: 8px 3px 6px 3px; /* Increased margin */
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin: 10px 4px 6px 4px;
|
||||
text-transform: capitalize;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.title { font-size: 17px; } /* Increased font size */
|
||||
.title {
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.itemInvoice .itemDetails {
|
||||
@@ -440,7 +633,7 @@
|
||||
.itemInvoice .itemName,
|
||||
.itemInvoice .itemPrice,
|
||||
.itemInvoice .itemQty .qtyInvoice .multiplySymbol {
|
||||
font-size: 1.1rem; /* Increased font size */
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.blank {
|
||||
@@ -453,6 +646,103 @@
|
||||
|
||||
.createItem {
|
||||
position: absolute;
|
||||
left: 18px; /* Increased position */
|
||||
right: 18px; /* Increased position */
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
}
|
||||
|
||||
/* Item list container */
|
||||
.item-list-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
/* Section header */
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.section-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* Empty state */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.empty-state-icon {
|
||||
font-size: 48px;
|
||||
color: #ccc;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.empty-state-title {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.empty-state-description {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
margin-bottom: 20px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
/* Card variant */
|
||||
.item-card {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
padding: 16px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.item-card:hover {
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* List variant */
|
||||
.item-list-item {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.item-list-item:hover {
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
@@ -25,7 +25,6 @@ const ItemConfig = ({
|
||||
const textareaRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
// Prevent scrolling when modal is open
|
||||
document.body.style.overflow = "hidden";
|
||||
if(selectedImage){
|
||||
@@ -92,11 +91,28 @@ const ItemConfig = ({
|
||||
};
|
||||
|
||||
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={handleContentClick} style={{ display: 'flex', flexDirection: 'column', padding: '18px', backgroundColor: 'white', borderRadius: '24px 24px 0 0', overflowY: 'auto' }}> {/* Increased padding and border radius */}
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div style={{ width: '30vw', height: '30vw', marginRight: '12px' }}> {/* Increased size and margin */}
|
||||
<img style={{ width: '100%', height: '100%', borderRadius: '12px', objectFit: 'cover' }} src={previewUrl} /> {/* Increased border radius */}
|
||||
<div onClick={handleOverlayClick} className={styles.modalOverlay}>
|
||||
<div onClick={handleContentClick} className={styles.modalContent}>
|
||||
<div className={styles.imageSection}>
|
||||
<div className={styles.imagePreview}>
|
||||
<img src={previewUrl} alt="Preview" className={styles.previewImage} />
|
||||
</div>
|
||||
<div className={styles.imageActions}>
|
||||
<button
|
||||
onClick={handleChangeImage}
|
||||
className={styles.actionButton}
|
||||
>
|
||||
{isBeingEdit ? 'Ganti Gambar' : 'Tambah Gambar'}
|
||||
</button>
|
||||
{isBeingEdit && (
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className={`${styles.actionButton} ${styles.deleteButton}`}
|
||||
>
|
||||
Hapus
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
@@ -106,109 +122,63 @@ const ItemConfig = ({
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ width: '68%', height: '30vw', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> {/* Increased size */}
|
||||
<div onClick={() => handleChangeImage()} style={{ width: '160px', marginRight: '12px', height: '48px', alignContent: 'center', textAlign: 'center', borderRadius: '12px', border: '1px solid #60d37e', color: '#60d37e', backgroundColor: 'white', display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: '16px' }}> {/* Increased size and font */}
|
||||
{isBeingEdit ? 'Ganti gambar' : 'Tambah gambar'}
|
||||
</div>
|
||||
<div onClick={handleDelete} style={{ width: '84px', height: '48px', alignContent: 'center', textAlign: 'center', borderRadius: '12px', border: '1px solid rgb(211 96 96)', color: 'rgb(211 96 96)', backgroundColor: 'white', display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: '16px' }}> {/* Increased size and font */}
|
||||
Hapus
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', color: 'black', marginTop: '12px' }}> {/* Increased margin */}
|
||||
<p style={{ marginBottom: '6px', fontWeight: '500', fontSize: '18px' }}>Nama item</p> {/* Increased margin and font size */}
|
||||
<div className={styles.formSection}>
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Nama Item</label>
|
||||
<input
|
||||
value={itemName}
|
||||
style={{
|
||||
padding: '12px', // Increased padding
|
||||
borderRadius: '8px', // Increased border radius
|
||||
border: '1px solid #ccc',
|
||||
fontSize: '16px', // Increased font size
|
||||
width: '100%',
|
||||
marginBottom: '18px', // Increased margin
|
||||
outline: 'none',
|
||||
transition: 'all 0.3s ease',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
className={styles.formInput}
|
||||
onChange={(e)=>setItemName(e.target.value)}
|
||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||
placeholder="Masukkan nama item"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', color: 'black', justifyContent: 'space-between' }}>
|
||||
<div style={{ width: '48%' }}>
|
||||
<p style={{ marginBottom: '6px', fontWeight: '500', marginTop: 0, fontSize: '18px' }}>Harga</p> {/* Increased margin and font size */}
|
||||
<div className={styles.formRow}>
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Harga</label>
|
||||
<input
|
||||
value={itemPrice}
|
||||
style={{
|
||||
padding: '12px', // Increased padding
|
||||
borderRadius: '8px', // Increased border radius
|
||||
border: '1px solid #ccc',
|
||||
fontSize: '16px', // Increased font size
|
||||
width: '100%',
|
||||
marginBottom: '18px', // Increased margin
|
||||
outline: 'none',
|
||||
transition: 'all 0.3s ease',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
className={styles.formInput}
|
||||
onChange={(e)=>setItemPrice(e.target.value)}
|
||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||
placeholder="Rp 0"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ width: '48%' }}>
|
||||
<p style={{ marginBottom: '6px', fontWeight: '500', marginTop: 0, fontSize: '18px' }}>Harga promo</p> {/* Increased margin and font size */}
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Harga Promo</label>
|
||||
<input
|
||||
value={itemPromoPrice}
|
||||
placeholder="Opsional"
|
||||
style={{
|
||||
padding: '12px', // Increased padding
|
||||
borderRadius: '8px', // Increased border radius
|
||||
border: '1px solid #ccc',
|
||||
fontSize: '16px', // Increased font size
|
||||
width: '100%',
|
||||
marginBottom: '18px', // Increased margin
|
||||
outline: 'none',
|
||||
transition: 'all 0.3s ease',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
className={styles.formInput}
|
||||
onChange={(e)=>setItemPromoPrice(e.target.value)}
|
||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||
placeholder="Opsional"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', color: 'black' }}>
|
||||
<p style={{ marginBottom: '6px', fontWeight: '500', marginTop: 0, fontSize: '18px' }}>Deskripsi</p> {/* Increased margin and font size */}
|
||||
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Deskripsi</label>
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
style={{
|
||||
padding: '12px', // Increased padding
|
||||
borderRadius: '8px', // Increased border radius
|
||||
border: '1px solid #ccc',
|
||||
fontSize: '16px', // Increased font size
|
||||
width: '100%',
|
||||
marginBottom: '18px', // Increased margin
|
||||
outline: 'none',
|
||||
transition: 'all 0.3s ease',
|
||||
boxSizing: 'border-box',
|
||||
resize: 'none',
|
||||
}}
|
||||
placeholder="Tambah deskripsi..."
|
||||
className={styles.formTextarea}
|
||||
placeholder="Tambahkan deskripsi item..."
|
||||
value={itemDescription}
|
||||
onChange={(e)=>setItemDescription(e.target.value)}
|
||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ width: '100%', height: '42px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> {/* Increased height */}
|
||||
<div onClick={() => {isBeingEdit ? handleUpdate() : handleCreate()} } style={{ width: '100%', height: '48px', alignContent: 'center', textAlign: 'center', borderRadius: '12px', border: '1px solid #60d37e', color: '#60d37e', backgroundColor: 'white', display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: '18px' }}> {/* Increased height and font size */}
|
||||
{isBeingEdit? 'Simpan' : 'Buat Item'}
|
||||
<div className={styles.formActions}>
|
||||
<button
|
||||
onClick={cancelEdit}
|
||||
className={`${styles.formButton} ${styles.cancelButton}`}
|
||||
>
|
||||
Batal
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {isBeingEdit ? handleUpdate() : handleCreate()}}
|
||||
className={`${styles.formButton} ${styles.saveButton}`}
|
||||
>
|
||||
{isBeingEdit ? 'Simpan Perubahan' : 'Buat Item'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import ItemType from "./ItemType.js";
|
||||
import { createItemType, updateItemDeletionStatus } from "../helpers/itemHelper.js";
|
||||
import ItemConfig from "./ItemConfig.js"
|
||||
import { ArrowUp, ArrowDown, Pencil } from 'lucide-react';
|
||||
import { ArrowUp, ArrowDown, Pencil, Save, X } from 'lucide-react';
|
||||
|
||||
const ItemLister = ({
|
||||
index,
|
||||
@@ -625,7 +625,15 @@ const ItemLister = ({
|
||||
|
||||
{(isEdit && isFirstStep || !isEdit) &&
|
||||
<div className={styles["title-container"]}>
|
||||
{isEdit && <ItemType blank={true} imageUrl={previewUrl} compact={true} />}
|
||||
{isEdit && (
|
||||
<div className={styles["image-preview"]}>
|
||||
<img
|
||||
src={previewUrl}
|
||||
alt="Category Preview"
|
||||
className={styles["preview-image"]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<input
|
||||
className={`${styles.title} ${isEdit ? styles.border : styles.noborder
|
||||
}`}
|
||||
@@ -642,7 +650,7 @@ const ItemLister = ({
|
||||
disabled={index === 0}
|
||||
aria-label="Naikkan kategori"
|
||||
>
|
||||
<ArrowUp size={16} /> {/* Reduced icon size for compact design */}
|
||||
<ArrowUp size={20} />
|
||||
</button>
|
||||
<button
|
||||
className={styles.iconBtn}
|
||||
@@ -650,14 +658,32 @@ const ItemLister = ({
|
||||
disabled={index === indexTotal - 1}
|
||||
aria-label="Turunkan kategori"
|
||||
>
|
||||
<ArrowDown size={16} /> {/* Reduced icon size for compact design */}
|
||||
<ArrowDown size={20} />
|
||||
</button>
|
||||
<button
|
||||
className={styles.iconBtn}
|
||||
onClick={toggleEditTypeItem}
|
||||
aria-label="Edit kategori"
|
||||
>
|
||||
<Pencil size={16} /> {/* Reduced icon size for compact design */}
|
||||
<Pencil size={20} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{isEditMode && isEdit && (
|
||||
<div className={styles.titleActions}>
|
||||
<button
|
||||
className={styles.iconBtn}
|
||||
onClick={handleSaveType}
|
||||
aria-label="Simpan"
|
||||
>
|
||||
<Save size={20} />
|
||||
</button>
|
||||
<button
|
||||
className={styles.iconBtn}
|
||||
onClick={resetItems}
|
||||
aria-label="Batal"
|
||||
>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -673,7 +699,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/addnew.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
{/* {typeImage != null && !previewUrl.includes(typeImage) && (
|
||||
<ItemType
|
||||
@@ -691,7 +717,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/beverage4.jpg")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -699,7 +725,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/beverage1.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -707,7 +733,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/beverage2.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -715,7 +741,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/beverage3.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -723,7 +749,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/snack5.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -731,7 +757,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/dessert1.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -739,7 +765,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/dessert2.jpg")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -747,7 +773,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/food4.jpg")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -755,7 +781,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/food1.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -763,7 +789,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/food2.jpg")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
|
||||
<ItemType
|
||||
@@ -772,7 +798,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/food3.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -780,7 +806,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/packet1.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -788,7 +814,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/packet2.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -796,7 +822,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/snack1.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -804,7 +830,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/snack2.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -812,7 +838,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/snack3.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
<ItemType
|
||||
rectangular={true}
|
||||
@@ -820,7 +846,7 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl("uploads/assets/snack4.png")}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
{Array.from({ length: 16 }, (_, index) => {
|
||||
const sampleNumber = index + 1; // To get numbers from 1 to 16
|
||||
@@ -832,18 +858,42 @@ const ItemLister = ({
|
||||
handleImageChange(previewUrl, selectedImage)
|
||||
}
|
||||
imageUrl={getImageUrl(`uploads/samples/sample (${sampleNumber}).png`)}
|
||||
compact={true}
|
||||
compact={false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<button onClick={() => setIsFirstStep(false)} style={{ width: '100%', height: '40px', borderRadius: '20px' }}>selanjutnya</button>
|
||||
<button onClick={() => setIsFirstStep(false)} className={styles["add-item-button"]}>
|
||||
Selanjutnya
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{(isEdit && !isFirstStep || !isEdit) &&
|
||||
<div key={randomKey}>
|
||||
{isEdit && <div style={{ display: 'flex', justifyContent: 'flex-start' }}><div style={{ marginTop: '49px', marginRight: '10px', marginLeft: '10px' }} onClick={() => setIsFirstStep(true)}><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>
|
||||
<h2 className={styles["item-list-title"]}>{items && items.length < 1 ? 'Buat item' : 'Daftar item'}</h2></div>}
|
||||
{isEdit && (
|
||||
<div className={styles["settings-section"]}>
|
||||
<h3 className={styles["settings-title"]}>Pengaturan Kategori</h3>
|
||||
<div className={styles["setting-row"]}>
|
||||
<span className={styles["setting-label"]}>Visibilitas Kategori</span>
|
||||
<div className={styles["switch-container"]}>
|
||||
<span className={styles["switch-label"]}>
|
||||
{isVisible ? "Tampil" : "Tersembunyi"}
|
||||
</span>
|
||||
<Switch
|
||||
onChange={() => setIsVisible(!isVisible)}
|
||||
checked={isVisible}
|
||||
offColor="#cccccc"
|
||||
onColor="#6B8F71"
|
||||
uncheckedIcon={false}
|
||||
checkedIcon={false}
|
||||
height={24}
|
||||
width={48}
|
||||
handleDiameter={20}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={`${styles["item-list"]} ${(!isEdit && !forInvoice) ? styles["item-grid"] : ""}`}>
|
||||
{user && (
|
||||
user.user_id == shopOwnerId || user.cafeId == shopId) &&
|
||||
@@ -853,13 +903,8 @@ const ItemLister = ({
|
||||
<button
|
||||
className={styles["add-item-button"]}
|
||||
onClick={toggleAddNewItem}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
height: "120px",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
>
|
||||
Tambah item +
|
||||
+ Tambah Item Baru
|
||||
</button>
|
||||
)}
|
||||
{isAddingNewItem && (
|
||||
@@ -895,48 +940,29 @@ const ItemLister = ({
|
||||
{isEditMode && isEditItem != item.itemId && (
|
||||
|
||||
<div className={styles["editModeLayout"]}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', height: '40px', marginLeft: '7.5vw' }}>
|
||||
<div>
|
||||
{isEditMode && (
|
||||
<div className={styles["switch-container"]}>
|
||||
<span className={styles["switch-label"]}>
|
||||
{item.availability ? "Tersedia" : "Tidak Tersedia"}
|
||||
</span>
|
||||
<Switch
|
||||
onChange={() => handleChange(item.itemId)}
|
||||
checked={item.availability}
|
||||
offColor="#cccccc"
|
||||
onColor="#6B8F71"
|
||||
uncheckedIcon={false}
|
||||
checkedIcon={false}
|
||||
height={20}
|
||||
width={40}
|
||||
handleDiameter={16}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<h3>
|
||||
{item.availability ? "Tersedia" : "Tidak tersedia"}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div onClick={() => editItem(item.itemId)} style={{ display: 'flex', alignItems: 'center', height: '40px', marginRight: '7.5vw' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px', // Add a height to the div
|
||||
display: 'flex', // Use flexbox
|
||||
justifyContent: 'center', // Center horizontally
|
||||
alignItems: 'center', // Center vertically
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
fill="white"
|
||||
viewBox="0 0 32 32"
|
||||
style={{ fillRule: 'evenodd', clipRule: 'evenodd', strokeLinejoin: 'round', strokeMiterlimit: 2 }}
|
||||
version="1.1"
|
||||
xmlSpace="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsSerif="http://www.serif.com/"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M12.965,5.462c0,-0 -2.584,0.004 -4.979,0.008c-3.034,0.006 -5.49,2.467 -5.49,5.5l0,13.03c0,1.459 0.579,2.858 1.611,3.889c1.031,1.032 2.43,1.611 3.889,1.611l13.003,0c3.038,-0 5.5,-2.462 5.5,-5.5c0,-2.405 0,-5.004 0,-5.004c0,-0.828 -0.672,-1.5 -1.5,-1.5c-0.827,-0 -1.5,0.672 -1.5,1.5l0,5.004c0,1.381 -1.119,2.5 -2.5,2.5l-13.003,0c-0.663,-0 -1.299,-0.263 -1.768,-0.732c-0.469,-0.469 -0.732,-1.105 -0.732,-1.768l0,-13.03c0,-1.379 1.117,-2.497 2.496,-2.5c2.394,-0.004 4.979,-0.008 4.979,-0.008c0.828,-0.002 1.498,-0.675 1.497,-1.503c-0.001,-0.828 -0.675,-1.499 -1.503,-1.497Z"></path>
|
||||
<path d="M20.046,6.411l-6.845,6.846c-0.137,0.137 -0.232,0.311 -0.271,0.501l-1.081,5.152c-0.069,0.329 0.032,0.671 0.268,0.909c0.237,0.239 0.577,0.343 0.907,0.277l5.194,-1.038c0.193,-0.039 0.371,-0.134 0.511,-0.274l6.845,-6.845l-5.528,-5.528Zm1.415,-1.414l5.527,5.528l1.112,-1.111c1.526,-1.527 1.526,-4.001 -0,-5.527c-0.001,-0 -0.001,-0.001 -0.001,-0.001c-1.527,-1.526 -4.001,-1.526 -5.527,-0l-1.111,1.111Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Edit item</h3>
|
||||
<div onClick={() => editItem(item.itemId)}>
|
||||
<Pencil size={18} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -970,13 +996,6 @@ const ItemLister = ({
|
||||
<div
|
||||
key={item.itemId}>
|
||||
{isEditItem == item.itemId && (
|
||||
// <button
|
||||
// className={styles["add-item-button"]}
|
||||
// onClick={() => editItem(0)}
|
||||
// style={{ display: "inline-block" }}
|
||||
// >
|
||||
// batal
|
||||
// </button>
|
||||
<ItemConfig
|
||||
isBeingEdit={true}
|
||||
name={item.name}
|
||||
@@ -1002,23 +1021,30 @@ const ItemLister = ({
|
||||
<div className={styles["itemWrapper"]}>
|
||||
{(isEditMode && isEditItem != item.itemId || item.willBeDeleted) && (
|
||||
<div className={styles["editModeLayout"]}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', height: '40px', marginLeft: '7.5vw' }}>
|
||||
<div>
|
||||
{!item.willBeDeleted && isEditMode && (
|
||||
<div className={styles["switch-container"]}>
|
||||
<span className={styles["switch-label"]}>
|
||||
{item.availability ? "Tersedia" : "Tidak Tersedia"}
|
||||
</span>
|
||||
<Switch
|
||||
onChange={() => handleChange(item.itemId)}
|
||||
checked={item.availability}
|
||||
offColor="#cccccc"
|
||||
onColor="#6B8F71"
|
||||
uncheckedIcon={false}
|
||||
checkedIcon={false}
|
||||
height={20}
|
||||
width={40}
|
||||
handleDiameter={16}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{item.willBeDeleted ?
|
||||
|
||||
<h3 style={{ backgroundColor: 'black', padding: '13px 26px' }}>
|
||||
{item.willBeDeleted && (
|
||||
<span style={{ backgroundColor: 'black', padding: '6px 12px', borderRadius: '20px' }}>
|
||||
Ditandai untuk dihapus
|
||||
</h3>
|
||||
:
|
||||
<h3>
|
||||
{item.availability ? "Tersedia" : "Tidak tersedia"}
|
||||
</h3>
|
||||
}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div onClick={() => {
|
||||
@@ -1027,38 +1053,8 @@ const ItemLister = ({
|
||||
} else {
|
||||
handleItemDeletionToggle(item.itemId, false);
|
||||
}
|
||||
}}
|
||||
style={{ display: 'flex', alignItems: 'center', height: '40px', marginRight: '7.5vw' }}>
|
||||
{!item.willBeDeleted && <div
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px', // Add a height to the div
|
||||
display: 'flex', // Use flexbox
|
||||
justifyContent: 'center', // Center horizontally
|
||||
alignItems: 'center', // Center vertically
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
fill="white"
|
||||
viewBox="0 0 32 32"
|
||||
style={{ fillRule: 'evenodd', clipRule: 'evenodd', strokeLinejoin: 'round', strokeMiterlimit: 2 }}
|
||||
version="1.1"
|
||||
xmlSpace="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsSerif="http://www.serif.com/"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M12.965,5.462c0,-0 -2.584,0.004 -4.979,0.008c-3.034,0.006 -5.49,2.467 -5.49,5.5l0,13.03c0,1.459 0.579,2.858 1.611,3.889c1.031,1.032 2.43,1.611 3.889,1.611l13.003,0c3.038,-0 5.5,-2.462 5.5,-5.5c0,-2.405 0,-5.004 0,-5.004c0,-0.828 -0.672,-1.5 -1.5,-1.5c-0.827,-0 -1.5,0.672 -1.5,1.5l0,5.004c0,1.381 -1.119,2.5 -2.5,2.5l-13.003,0c-0.663,-0 -1.299,-0.263 -1.768,-0.732c-0.469,-0.469 -0.732,-1.105 -0.732,-1.768l0,-13.03c0,-1.379 1.117,-2.497 2.496,-2.5c2.394,-0.004 4.979,-0.008 4.979,-0.008c0.828,-0.002 1.498,-0.675 1.497,-1.503c-0.001,-0.828 -0.675,-1.499 -1.503,-1.497Z"></path>
|
||||
<path d="M20.046,6.411l-6.845,6.846c-0.137,0.137 -0.232,0.311 -0.271,0.501l-1.081,5.152c-0.069,0.329 0.032,0.671 0.268,0.909c0.237,0.239 0.577,0.343 0.907,0.277l5.194,-1.038c0.193,-0.039 0.371,-0.134 0.511,-0.274l6.845,-6.845l-5.528,-5.528Zm1.415,-1.414l5.527,5.528l1.112,-1.111c1.526,-1.527 1.526,-4.001 -0,-5.527c-0.001,-0 -0.001,-0.001 -0.001,-0.001c-1.527,-1.526 -4.001,-1.526 -5.527,-0l-1.111,1.111Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
}
|
||||
<h3>{item.willBeDeleted ? 'Batalkan' : 'Edit item'}</h3>
|
||||
}}>
|
||||
<Pencil size={18} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -1109,33 +1105,6 @@ const ItemLister = ({
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{isEdit && (
|
||||
<div className={styles.PaymentOption}>
|
||||
<div className={styles.TotalContainer}>
|
||||
<span>Pengaturan</span>
|
||||
<span></span>
|
||||
</div>
|
||||
<div className={styles.OptionContainer}>
|
||||
<span>sembunyikan semua</span>
|
||||
<span>
|
||||
<Switch
|
||||
onChange={() => setIsVisible(!isVisible)}
|
||||
checked={!isVisible}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<button onClick={handleSaveType} className={styles.PayButton}>
|
||||
{false ? (
|
||||
<ColorRing height="50" width="50" color="white" />
|
||||
) : (
|
||||
"Simpan"
|
||||
)}
|
||||
</button>
|
||||
<div className={styles.Pay2Button} onClick={resetItems}>
|
||||
Kembali
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
|
||||
.item-lister {
|
||||
width: 100%;
|
||||
padding: 10px; /* Slightly reduced padding */
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
white-space: break-spaces;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
z-index: 150; /* Memastikan berada di bawah material list */
|
||||
}
|
||||
|
||||
.fullscreen {
|
||||
@@ -21,59 +27,63 @@
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 10px;
|
||||
height: calc(50vw - 20px);
|
||||
gap: 16px;
|
||||
height: calc(52vw - 20px);
|
||||
padding: 16px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@media (min-height: 0px) {
|
||||
.grid-container {
|
||||
height: 28vh;
|
||||
height: 30vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 630px) {
|
||||
.grid-container {
|
||||
height: 28vh;
|
||||
height: 30vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 636px) {
|
||||
.grid-container {
|
||||
height: 30vh;
|
||||
height: 32vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 650px) {
|
||||
.grid-container {
|
||||
height: 36vh;
|
||||
height: 38vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 705px) {
|
||||
.grid-container {
|
||||
height: 39vh;
|
||||
height: 41vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 735px) {
|
||||
.grid-container {
|
||||
height: 40vh;
|
||||
height: 42vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 759px) {
|
||||
.grid-container {
|
||||
height: 42vh;
|
||||
height: 44vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 819px) {
|
||||
.grid-container {
|
||||
height: 46vh;
|
||||
height: 48vh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-height: 830px) {
|
||||
.grid-container {
|
||||
height: 49vh;
|
||||
height: 51vh;
|
||||
}
|
||||
}
|
||||
@media (min-height: 892px) {
|
||||
.grid-container {
|
||||
height: 51vh;
|
||||
height: 53vh;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,30 +91,36 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px; /* Added padding for better spacing */
|
||||
background-color: #f8f9fa; /* Light background for better visual separation */
|
||||
border-radius: 12px; /* Rounded corners */
|
||||
margin-bottom: 16px; /* Space below the title container */
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05); /* Subtle shadow */
|
||||
padding: 16px 20px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
position: relative;
|
||||
z-index: 151;
|
||||
}
|
||||
|
||||
.titleActions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.iconBtn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #e6e6e6;
|
||||
background: #ffffff;
|
||||
color: #2d2d2d;
|
||||
border-radius: 8px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
position: relative;
|
||||
z-index: 152;
|
||||
}
|
||||
.iconBtn:disabled {
|
||||
opacity: 0.5;
|
||||
@@ -113,62 +129,90 @@
|
||||
.iconBtn:hover:not(:disabled) {
|
||||
background: var(--brand-sage-50, #F0F6F2);
|
||||
border-color: var(--brand-sage, #6B8F71);
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.title {
|
||||
background-color: transparent;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600; /* Increased font weight for better visibility */
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-size: 20px;
|
||||
font-size: 22px;
|
||||
color: rgba(88, 55, 50, 1);
|
||||
text-align: left;
|
||||
width: calc(70% - 10px);
|
||||
padding-left: 10px;
|
||||
width: calc(70% - 12px);
|
||||
padding-left: 12px;
|
||||
text-transform: capitalize;
|
||||
border: none;
|
||||
outline: none;
|
||||
position: relative;
|
||||
z-index: 151;
|
||||
}
|
||||
|
||||
.edit-typeItem-button {
|
||||
margin-left: auto;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
padding: 10px 16px;
|
||||
font-size: 14px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
position: relative;
|
||||
z-index: 152;
|
||||
}
|
||||
.edit-typeItem-button:hover {
|
||||
background-color: #0069d9;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.add-item-button {
|
||||
margin-top: 10px;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
margin-top: 16px;
|
||||
padding: 12px 20px;
|
||||
font-size: 16px;
|
||||
background-color: #359d42d1;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 6px rgba(53, 157, 66, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
position: relative;
|
||||
z-index: 151;
|
||||
}
|
||||
.add-item-button:hover {
|
||||
background-color: #2d8a39;
|
||||
box-shadow: 0 4px 10px rgba(53, 157, 66, 0.3);
|
||||
}
|
||||
|
||||
.item-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
position: relative;
|
||||
z-index: 150;
|
||||
}
|
||||
|
||||
/* Grid layout for portrait cards on cafe page */
|
||||
.item-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 8px;
|
||||
gap: 16px;
|
||||
}
|
||||
@media (min-width: 600px) {
|
||||
.item-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.item-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,40 +223,62 @@
|
||||
.noborder {
|
||||
border: 1px solid #ffffff00;
|
||||
}
|
||||
|
||||
.itemWrapper {
|
||||
position: relative;
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.08);
|
||||
transition: all 0.2s ease;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 150;
|
||||
}
|
||||
.itemWrapper:hover {
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.editModeLayout {
|
||||
border-radius: 4px;
|
||||
border-radius: 12px 12px 0 0;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
background-color: #0000008c;
|
||||
z-index: 155; /* Memastikan berada di atas itemWrapper */
|
||||
background-color: #000000cc;
|
||||
width: 100%;
|
||||
top: 6px;
|
||||
bottom: -4px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
padding: 12px 16px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.editModeLayout h3 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.PaymentOption {
|
||||
overflow-x: hidden;
|
||||
background-color: #e9e9e9;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
font-size: calc(12px + 2vmin);
|
||||
color: rgba(88, 55, 50, 1);
|
||||
border-radius: 15px 15px 0 0;
|
||||
|
||||
border-radius: 20px 20px 0 0;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
|
||||
z-index: 300;
|
||||
z-index: 300; /* Menurunkan z-index agar tidak menutupi material list */
|
||||
box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.TotalContainer {
|
||||
@@ -223,20 +289,28 @@
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-size: 1.5em;
|
||||
padding: 10px 0;
|
||||
font-size: 1.8em;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.OptionContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 80vw;
|
||||
margin: 0 auto;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
padding: 10px 0;
|
||||
font-size: 1.1em;
|
||||
padding: 15px 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.OptionContainer span:first-child {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.PayButton {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 500;
|
||||
@@ -244,7 +318,7 @@
|
||||
font-size: 32px;
|
||||
|
||||
width: 80vw;
|
||||
height: 70px;
|
||||
height: 56px;
|
||||
border-radius: 50px;
|
||||
background-color: rgba(88, 55, 50, 1);
|
||||
color: white;
|
||||
@@ -252,14 +326,32 @@
|
||||
margin: 0px auto;
|
||||
cursor: pointer;
|
||||
margin-bottom: 23px;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 4px 12px rgba(88, 55, 50, 0.2);
|
||||
position: relative;
|
||||
z-index: 301;
|
||||
}
|
||||
|
||||
.PayButton:hover {
|
||||
background-color: rgba(70, 45, 40, 1);
|
||||
box-shadow: 0 6px 16px rgba(88, 55, 50, 0.3);
|
||||
}
|
||||
|
||||
.Pay2Button {
|
||||
text-align: center;
|
||||
color: rgba(88, 55, 50, 1);
|
||||
font-size: 1em;
|
||||
margin-bottom: 25px;
|
||||
font-size: 1.2em;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
z-index: 301;
|
||||
}
|
||||
.Pay2Button:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.item-list-title {
|
||||
|
||||
@@ -2,42 +2,264 @@
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: -1px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.modalContent {
|
||||
width: 80vw;
|
||||
max-height: 80vh;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
animation: modalAppear 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes modalAppear {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.imageSection {
|
||||
padding: 24px 24px 16px 24px;
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.imagePreview {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
background: #e9ecef;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.previewImage {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.imageActions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.actionButton {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.actionButton:not(.deleteButton) {
|
||||
background-color: var(--brand-sage, #6B8F71);
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(107, 143, 113, 0.2);
|
||||
}
|
||||
|
||||
.actionButton:not(.deleteButton):hover {
|
||||
background-color: #5a7a60;
|
||||
box-shadow: 0 4px 10px rgba(107, 143, 113, 0.3);
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
background-color: #ff4d4d;
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(255, 77, 77, 0.2);
|
||||
}
|
||||
|
||||
.deleteButton:hover {
|
||||
background-color: #ff1a1a;
|
||||
box-shadow: 0 4px 10px rgba(255, 77, 77, 0.3);
|
||||
}
|
||||
|
||||
.formSection {
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.formGroup {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.formRow {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.formRow .formGroup {
|
||||
flex: 1;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.formLabel {
|
||||
display: block;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.formInput {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ddd;
|
||||
background: #ffffff;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
transition: all 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.formInput:focus {
|
||||
outline: none;
|
||||
border-color: var(--brand-sage, #6B8F71);
|
||||
box-shadow: 0 0 0 3px rgba(107, 143, 113, 0.1);
|
||||
}
|
||||
|
||||
.formTextarea {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ddd;
|
||||
background: #ffffff;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
transition: all 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
min-height: 100px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.formTextarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--brand-sage, #6B8F71);
|
||||
box-shadow: 0 0 0 3px rgba(107, 143, 113, 0.1);
|
||||
}
|
||||
|
||||
.formActions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.formButton {
|
||||
flex: 1;
|
||||
padding: 14px 16px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cancelButton {
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.cancelButton:hover {
|
||||
background-color: #e0e0e0;
|
||||
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.saveButton {
|
||||
background-color: var(--brand-sage, #6B8F71);
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(107, 143, 113, 0.2);
|
||||
}
|
||||
|
||||
.saveButton:hover {
|
||||
background-color: #5a7a60;
|
||||
box-shadow: 0 4px 10px rgba(107, 143, 113, 0.3);
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
position: absolute;
|
||||
top: 12px; /* Increased top position */
|
||||
right: 12px; /* Increased right position */
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 28px; /* Increased font size */
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
padding: 0;
|
||||
width: 30px; /* Increased width */
|
||||
height: 30px; /* Increased height */
|
||||
color: #999;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s ease;
|
||||
z-index: 1001; /* Menambah z-index agar selalu di atas modal */
|
||||
}
|
||||
|
||||
.closeButton:hover {
|
||||
color: #f44336;
|
||||
background: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 600px) {
|
||||
.modalContent {
|
||||
margin: 10px;
|
||||
max-height: 95vh;
|
||||
}
|
||||
|
||||
.imageSection {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.formSection {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.formRow {
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.formActions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,94 @@ body {
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overflow-x: hidden;
|
||||
background-color: #e9e9e9;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
/* Ensure proper scrolling behavior */
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
|
||||
/* Ensure proper z-index stacking */
|
||||
* {
|
||||
z-index: auto;
|
||||
}
|
||||
|
||||
/* Responsive design adjustments */
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-height: 75vh; /* Menaikkan tinggi maksimum pada mobile */
|
||||
}
|
||||
|
||||
.materialCard {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.materialSummary {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.materialName {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.materialStock {
|
||||
font-size: 13px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.detailGrid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.formGrid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* Memastikan MaterialList tetap dapat di-scroll */
|
||||
.MaterialList-module__container {
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
.CheckoutContainer {
|
||||
bottom: 0px;
|
||||
position: fixed;
|
||||
z-index: 100; /* Menurunkan z-index agar tidak menutupi material list */
|
||||
}
|
||||
|
||||
.EmailContainer {
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: rgba(88, 55, 50, 1);
|
||||
background-color: #e9e9e9;
|
||||
position: relative;
|
||||
z-index: 50; /* Memastikan berada di bawah material list */
|
||||
}
|
||||
|
||||
.Invoice-title {
|
||||
@@ -45,6 +47,8 @@
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 100; /* Menurunkan z-index lebih jauh agar tidak menutupi material list */
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.PaymentOptionMargin {
|
||||
@@ -159,6 +163,7 @@
|
||||
padding: 10px 0;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.OrderTypeContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import jsQR from "jsqr";
|
||||
import { getImageUrl } from "../helpers/itemHelper";
|
||||
import {
|
||||
getCafe,
|
||||
saveCafeDetails,
|
||||
setConfirmationStatus,
|
||||
} from "../helpers/cafeHelpers";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
getMaterials,
|
||||
createMaterial,
|
||||
@@ -17,347 +9,497 @@ import {
|
||||
getMaterialMutations,
|
||||
} from "../helpers/materialMutationHelpers";
|
||||
|
||||
import Switch from "react-switch"; // Import the Switch component
|
||||
import Carousel from '../components/Carousel'
|
||||
import styles from './MaterialList.module.css'; // Import the CSS Module
|
||||
import styles from './MaterialList.module.css';
|
||||
|
||||
const SetPaymentQr = ({ cafeId }) => {
|
||||
// All your state and logic goes here (unchanged)
|
||||
const MaterialList = ({ cafeId }) => {
|
||||
// State declarations
|
||||
const [materials, setMaterials] = useState([]);
|
||||
const [mutations, setMutations] = useState([]);
|
||||
const [newMaterialName, setNewMaterialName] = useState("");
|
||||
const [newMaterialUnit, setNewMaterialUnit] = useState("kilogram");
|
||||
const [newMaterialImage, setNewMaterialImage] = useState(null);
|
||||
const [deleting, setDeleting] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [selectedMaterialIndex, setSelectedMaterialIndex] = useState(-1);
|
||||
const [latestMutation, setLatestMutation] = useState([]);
|
||||
const [currentQuantity, setCurrentQuantity] = useState(-1);
|
||||
const [currentPrice, setCurrentPrice] = useState(0);
|
||||
const [newPrice, setNewPrice] = useState(0);
|
||||
const [quantityChange, setQuantityChange] = useState(0);
|
||||
|
||||
// Add material form state
|
||||
const [showAddForm, setShowAddForm] = useState(false);
|
||||
const [newMaterialName, setNewMaterialName] = useState("");
|
||||
const [newMaterialUnit, setNewMaterialUnit] = useState("kilogram");
|
||||
|
||||
// Edit material state
|
||||
const [editingMaterialId, setEditingMaterialId] = useState(null);
|
||||
const [newQuantity, setNewQuantity] = useState(0);
|
||||
const [newPrice, setNewPrice] = useState("");
|
||||
|
||||
// Expand state for each material
|
||||
const [expandedMaterials, setExpandedMaterials] = useState({});
|
||||
|
||||
// View state
|
||||
const [sortOrder, setSortOrder] = useState("desc");
|
||||
const [isEditCurrentPrice, setIsEditCurrentPrice] = useState(false);
|
||||
const [isViewingHistory, setIsViewingHistory] = useState(false);
|
||||
const [isViewingHistory, setIsViewingHistory] = useState({});
|
||||
|
||||
// Format currency helper
|
||||
const formatCurrency = (value) => {
|
||||
if (!value) return "0";
|
||||
return parseInt(value.toString().replace(/\./g, "")).toLocaleString('id-ID');
|
||||
};
|
||||
|
||||
const convertToInteger = (formattedValue) => {
|
||||
// Remove dots and convert to integer
|
||||
return parseInt(formattedValue.replace(/\./g, ""), 10);
|
||||
return parseInt(formattedValue.replace(/\./g, ""), 10) || 0;
|
||||
};
|
||||
|
||||
const formatCurrency = (value) => {
|
||||
if (!value) return "";
|
||||
// Remove existing formatting (dots) and format again
|
||||
const numericValue = value.toString().replace(/\D/g, ""); // Keep only digits
|
||||
return numericValue.replace(/\B(?=(\d{3})+(?!\d))/g, "."); // Add dot as thousands separator
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
// Handle price input change
|
||||
const handlePriceChange = (e) => {
|
||||
const formattedValue = formatCurrency(e.target.value);
|
||||
setNewPrice(formattedValue);
|
||||
};
|
||||
|
||||
// Fetch materials and mutations
|
||||
useEffect(() => {
|
||||
const fetchMaterials = async () => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const data = await getMaterials(cafeId);
|
||||
setMaterials(data);
|
||||
console.log(data)
|
||||
setError(null);
|
||||
if (data.length > 0) {
|
||||
setSelectedMaterialIndex(0);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching materials:", error);
|
||||
setError("Failed to fetch materials.");
|
||||
}
|
||||
};
|
||||
const [materialsData, mutationsData] = await Promise.all([
|
||||
getMaterials(cafeId),
|
||||
getMaterialMutations(cafeId)
|
||||
]);
|
||||
|
||||
const fetchMutations = async () => {
|
||||
try {
|
||||
const data = await getMaterialMutations(cafeId);
|
||||
setMutations(data);
|
||||
setMaterials(materialsData);
|
||||
setMutations(mutationsData);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
console.error("Error fetching data:", err);
|
||||
setError("Gagal memuat data bahan baku.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchMaterials();
|
||||
fetchMutations();
|
||||
if (cafeId) {
|
||||
fetchData();
|
||||
}
|
||||
}, [cafeId]);
|
||||
|
||||
const filteredMutations = mutations.filter((mutation) => mutation.materialId === materials[selectedMaterialIndex]?.materialId) || [];
|
||||
// Handle create material
|
||||
const handleCreateMaterial = async (e) => {
|
||||
e.preventDefault();
|
||||
if (!newMaterialName.trim()) return;
|
||||
|
||||
const sortedMutations = filteredMutations
|
||||
.filter((mutation) => mutation.materialId === materials[selectedMaterialIndex].materialId)
|
||||
.sort((a, b) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append("name", newMaterialName);
|
||||
formData.append("unit", newMaterialUnit);
|
||||
|
||||
await createMaterial(cafeId, formData);
|
||||
|
||||
// Reset form
|
||||
setNewMaterialName("");
|
||||
setNewMaterialUnit("kilogram");
|
||||
setShowAddForm(false);
|
||||
|
||||
// Refresh materials list
|
||||
const data = await getMaterials(cafeId);
|
||||
setMaterials(data);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
console.error("Error creating material:", err);
|
||||
setError("Gagal menambah bahan baku.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle delete material
|
||||
const handleDeleteMaterial = async (materialId) => {
|
||||
if (!window.confirm("Apakah Anda yakin ingin menghapus bahan baku ini?")) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
await deleteMaterial(materialId);
|
||||
|
||||
// Refresh materials list
|
||||
const data = await getMaterials(cafeId);
|
||||
setMaterials(data);
|
||||
|
||||
// Close expanded view if deleted material was expanded
|
||||
setExpandedMaterials(prevState => {
|
||||
const newState = { ...prevState };
|
||||
delete newState[materialId];
|
||||
return newState;
|
||||
});
|
||||
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
console.error("Error deleting material:", err);
|
||||
setError("Gagal menghapus bahan baku.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle update stock
|
||||
const handleUpdateStock = async (materialId) => {
|
||||
if (newQuantity === 0 && !convertToInteger(newPrice)) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const material = materials.find(m => m.materialId === materialId);
|
||||
const currentQuantity = material ? material.currentStock : 0;
|
||||
const finalQuantity = currentQuantity + newQuantity;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("newStock", finalQuantity);
|
||||
formData.append("priceAtp", convertToInteger(newPrice));
|
||||
formData.append("reason", `Update stok: ${newQuantity > 0 ? '+' : ''}${newQuantity}`);
|
||||
|
||||
await createMaterialMutation(materialId, formData);
|
||||
|
||||
// Refresh data
|
||||
const [materialsData, mutationsData] = await Promise.all([
|
||||
getMaterials(cafeId),
|
||||
getMaterialMutations(cafeId)
|
||||
]);
|
||||
|
||||
setMaterials(materialsData);
|
||||
setMutations(mutationsData);
|
||||
|
||||
// Reset form
|
||||
setNewQuantity(0);
|
||||
setNewPrice("");
|
||||
setEditingMaterialId(null);
|
||||
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
console.error("Error updating stock:", err);
|
||||
setError("Gagal memperbarui stok.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Get filtered and sorted mutations for a material
|
||||
const getFilteredMutations = (materialId) => {
|
||||
const filtered = mutations.filter(m => m.materialId === materialId);
|
||||
return filtered.sort((a, b) => {
|
||||
if (sortOrder === "asc") {
|
||||
return new Date(a.createdAt) - new Date(b.createdAt);
|
||||
} else {
|
||||
return new Date(b.createdAt) - new Date(a.createdAt);
|
||||
}
|
||||
});
|
||||
|
||||
const handleCreateMaterial = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("name", newMaterialName);
|
||||
formData.append("unit", newMaterialUnit);
|
||||
if (newMaterialImage) {
|
||||
formData.append("image", newMaterialImage);
|
||||
}
|
||||
|
||||
try {
|
||||
await createMaterial(cafeId, formData);
|
||||
setNewMaterialName("");
|
||||
setNewMaterialUnit("kilogram");
|
||||
setNewMaterialImage(null);
|
||||
setShowForm(false);
|
||||
const data = await getMaterials(cafeId);
|
||||
setMaterials(data);
|
||||
setError(null);
|
||||
if (data.length > 0) {
|
||||
setSelectedMaterialIndex(0);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error creating material:", error);
|
||||
setError("Failed to create material.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteMaterial = async (materialId) => {
|
||||
setDeleting(materialId);
|
||||
try {
|
||||
await deleteMaterial(materialId);
|
||||
const updatedMaterials = materials.filter(
|
||||
(material) => material.materialId !== materialId
|
||||
);
|
||||
setMaterials(updatedMaterials);
|
||||
setError(null);
|
||||
if (selectedMaterialIndex === materialId) {
|
||||
setSelectedMaterialIndex(
|
||||
updatedMaterials.length > 0 ? updatedMaterials[0].materialId : null
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting material:", error);
|
||||
setError("Failed to delete material.");
|
||||
} finally {
|
||||
setDeleting(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleQuantityChange = (change) => {
|
||||
setQuantityChange((prev) => prev + change);
|
||||
if (quantityChange + change < 1) setNewPrice(currentPrice);
|
||||
|
||||
setIsEditCurrentPrice(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setQuantityChange(0);
|
||||
if (materials.length > 0 || selectedMaterialIndex > -1) {
|
||||
const materialMutations = mutations.filter(
|
||||
(mutation) => mutation.materialId === materials[selectedMaterialIndex]?.materialId
|
||||
);
|
||||
console.log(materialMutations)
|
||||
if (materialMutations.length > 0) {
|
||||
const latestMutation = materialMutations.reduce(
|
||||
(latest, current) =>
|
||||
new Date(current.createdAt) > new Date(latest.createdAt)
|
||||
? current
|
||||
: latest,
|
||||
materialMutations[0]
|
||||
);
|
||||
setLatestMutation(latestMutation);
|
||||
setCurrentQuantity(latestMutation.newStock);
|
||||
setCurrentPrice(formatCurrency(latestMutation.priceAtp));
|
||||
setNewPrice(formatCurrency(latestMutation.priceAtp));
|
||||
} else {
|
||||
setCurrentQuantity(0); // Default value if no mutations exist
|
||||
setLatestMutation({ newStock: 0 });
|
||||
setCurrentPrice(0);
|
||||
setNewPrice(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setIsViewingHistory(false);
|
||||
}, [materials, mutations, selectedMaterialIndex]);
|
||||
|
||||
const handleUpdateStock = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const newprice = convertToInteger(newPrice)
|
||||
const newStock = currentQuantity + quantityChange;
|
||||
const formData = new FormData();
|
||||
formData.append("newStock", newStock);
|
||||
formData.append("priceAtp", newprice);
|
||||
formData.append("reason", "Stock update");
|
||||
|
||||
await createMaterialMutation(materials[selectedMaterialIndex].materialId, formData);
|
||||
setQuantityChange(0);
|
||||
const updatedMutations = await getMaterialMutations(cafeId);
|
||||
setMutations(updatedMutations);
|
||||
setCurrentQuantity(newStock);
|
||||
setError(null);
|
||||
} catch (error) {
|
||||
console.error("Error updating stock:", error);
|
||||
setError("Failed to update stock.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const currentMaterial = materials.find(
|
||||
(material) => material.materialId === selectedMaterialIndex
|
||||
);
|
||||
// Format date for display
|
||||
const formatDate = (timestamp) => {
|
||||
const date = new Date(timestamp);
|
||||
return date.toLocaleString();
|
||||
return date.toLocaleString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
// Toggle material expansion
|
||||
const toggleExpand = (materialId) => {
|
||||
setExpandedMaterials(prevState => {
|
||||
const newState = {
|
||||
...prevState,
|
||||
[materialId]: !prevState[materialId]
|
||||
};
|
||||
|
||||
// Reset form when expanding/collapsing
|
||||
if (!prevState[materialId]) {
|
||||
setNewQuantity(0);
|
||||
setNewPrice("");
|
||||
setEditingMaterialId(null);
|
||||
}
|
||||
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
// Toggle history view for a material
|
||||
const toggleHistoryView = (materialId) => {
|
||||
setIsViewingHistory(prevState => ({
|
||||
...prevState,
|
||||
[materialId]: !prevState[materialId]
|
||||
}));
|
||||
};
|
||||
|
||||
// Handle quantity change
|
||||
const handleQuantityChange = (change) => {
|
||||
setNewQuantity(prev => Math.max(0, prev + change));
|
||||
};
|
||||
|
||||
if (loading && materials.length === 0) {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.loading}>
|
||||
<div className={styles.loadingSpinner}>↻</div>
|
||||
<div>Memuat data bahan baku...</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{loading ? (
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
<h3 className={styles.title}>Bahan baku</h3>
|
||||
<Carousel items={materials} onSelect={(e) => setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} />
|
||||
{selectedMaterialIndex !== -1 ? (
|
||||
<>
|
||||
<div className={styles.switchContainer}>
|
||||
<h3>Stok sekarang {currentQuantity}</h3>
|
||||
<div className={styles.header}>
|
||||
<h2 className={styles.title}>Manajemen Bahan Baku</h2>
|
||||
<button
|
||||
className={styles.addButton}
|
||||
onClick={() => setShowAddForm(!showAddForm)}
|
||||
>
|
||||
{showAddForm ? 'Batal' : '+ Tambah Bahan Baku'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={styles.stokContainer}>
|
||||
<button onClick={() => handleQuantityChange(currentQuantity + quantityChange > 0 ? -1 : 0)} className={styles.stockButton}>
|
||||
<div className={styles.content}>
|
||||
{error && (
|
||||
<div className={styles.error} style={{
|
||||
padding: '12px',
|
||||
backgroundColor: '#fff0f0',
|
||||
color: '#dc3545',
|
||||
borderRadius: '8px',
|
||||
marginBottom: '20px'
|
||||
}}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Add Material Form */}
|
||||
{showAddForm && (
|
||||
<div className={styles.addMaterialForm}>
|
||||
<h3 className={styles.sectionTitle}>Tambah Bahan Baku Baru</h3>
|
||||
<form onSubmit={handleCreateMaterial}>
|
||||
<div className={styles.formGrid}>
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Nama Bahan Baku</label>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.formInput}
|
||||
value={newMaterialName}
|
||||
onChange={(e) => setNewMaterialName(e.target.value)}
|
||||
placeholder="Masukkan nama bahan baku"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Satuan</label>
|
||||
<select
|
||||
className={styles.formInput}
|
||||
value={newMaterialUnit}
|
||||
onChange={(e) => setNewMaterialUnit(e.target.value)}
|
||||
>
|
||||
<option value="gram">gram</option>
|
||||
<option value="ons">ons</option>
|
||||
<option value="kilogram">kilogram</option>
|
||||
<option value="kuintal">kuintal</option>
|
||||
<option value="liter">liter</option>
|
||||
<option value="piece">piece</option>
|
||||
<option value="meter">meter</option>
|
||||
<option value="pack">pack</option>
|
||||
<option value="sachet">sachet</option>
|
||||
<option value="box">box</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.formActions}>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.cancelButton}
|
||||
onClick={() => {
|
||||
setShowAddForm(false);
|
||||
setNewMaterialName("");
|
||||
setNewMaterialUnit("kilogram");
|
||||
}}
|
||||
>
|
||||
Batal
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className={styles.saveButton}
|
||||
disabled={!newMaterialName.trim()}
|
||||
>
|
||||
Tambah Bahan Baku
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Materials List */}
|
||||
{materials.length === 0 ? (
|
||||
<div className={styles.emptyState}>
|
||||
<div className={styles.emptyStateIcon}>📭</div>
|
||||
<div className={styles.emptyStateText}>Belum ada bahan baku yang terdaftar</div>
|
||||
<button
|
||||
className={styles.addButton}
|
||||
onClick={() => setShowAddForm(true)}
|
||||
>
|
||||
+ Tambah Bahan Baku Pertama
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.materialsList}>
|
||||
{materials.map((material) => (
|
||||
<div key={material.materialId} className={styles.materialCard}>
|
||||
{/* Material Summary (Always Visible) */}
|
||||
<div
|
||||
className={styles.materialSummary}
|
||||
onClick={() => toggleExpand(material.materialId)}
|
||||
>
|
||||
<h3 className={styles.materialName}>{material.name}</h3>
|
||||
<div className={styles.materialStock}>
|
||||
{material.currentStock} {material.unit}
|
||||
</div>
|
||||
<div className={`${styles.expandIcon} ${expandedMaterials[material.materialId] ? styles.expanded : ''}`}>
|
||||
▼
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Material Detail (Expandable) */}
|
||||
{expandedMaterials[material.materialId] && (
|
||||
<div className={styles.materialDetail}>
|
||||
<div className={styles.detailGrid}>
|
||||
<div className={styles.detailItem}>
|
||||
<span className={styles.detailLabel}>Stok Saat Ini</span>
|
||||
<span className={styles.detailValue}>{material.currentStock} {material.unit}</span>
|
||||
</div>
|
||||
<div className={styles.detailItem}>
|
||||
<span className={styles.detailLabel}>Harga per {material.unit}</span>
|
||||
<span className={styles.detailValue}>Rp {formatCurrency(material.currentPrice || 0)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.detailActions}>
|
||||
<button
|
||||
className={styles.detailButton}
|
||||
onClick={() => {
|
||||
setEditingMaterialId(material.materialId);
|
||||
}}
|
||||
>
|
||||
✏️ Update Stok
|
||||
</button>
|
||||
<button
|
||||
className={styles.detailButton}
|
||||
onClick={() => handleDeleteMaterial(material.materialId)}
|
||||
>
|
||||
🗑️ Hapus
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Stock Update Form */}
|
||||
{editingMaterialId === material.materialId && (
|
||||
<div className={styles.stockUpdateForm}>
|
||||
<h4 className={styles.formTitle}>Update Stok</h4>
|
||||
|
||||
<div className={styles.quantityControls}>
|
||||
<button
|
||||
className={styles.quantityButton}
|
||||
onClick={() => handleQuantityChange(-1)}
|
||||
disabled={newQuantity <= 0}
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<p>{currentQuantity + quantityChange}</p>
|
||||
<button onClick={() => handleQuantityChange(1)} className={styles.stockButton}>
|
||||
<div className={styles.quantityDisplay}>
|
||||
{newQuantity > 0 ? `+${newQuantity}` : newQuantity}
|
||||
</div>
|
||||
<button
|
||||
className={styles.quantityButton}
|
||||
onClick={() => handleQuantityChange(1)}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.uploadMessage}>
|
||||
<p>harga per {materials && materials[selectedMaterialIndex]?.unit} sekarang</p>
|
||||
</div>
|
||||
<div className={styles.resultMessage}>
|
||||
|
||||
<div className={styles.formGroup}>
|
||||
<label className={styles.formLabel}>Harga per {material.unit}</label>
|
||||
<input
|
||||
className={styles.resultMessageInput} // Replace inline style with CSS module class
|
||||
disabled={!isEditCurrentPrice || quantityChange < 1}
|
||||
type="text"
|
||||
className={styles.formInput}
|
||||
value={newPrice}
|
||||
onChange={handleChange}
|
||||
placeholder="Enter amount"
|
||||
onChange={handlePriceChange}
|
||||
placeholder="Masukkan harga"
|
||||
/>
|
||||
<div onClick={() => quantityChange < 1 ? null : setIsEditCurrentPrice(!isEditCurrentPrice)} className={quantityChange < 1 ? styles.changeButtonDisabled : styles.changeButtonEnabled}>
|
||||
{isEditCurrentPrice ? 'Terapkan' : 'Ganti'}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.buttonContainer}>
|
||||
<button onClick={handleUpdateStock} className={styles.saveButton}>
|
||||
Laporkan {quantityChange > 0 ? 'penambahan' : 'stok sekarang'} {quantityChange < 1 ? currentQuantity + quantityChange : quantityChange} {materials[selectedMaterialIndex]?.unit}
|
||||
|
||||
<div className={styles.formActions}>
|
||||
<button
|
||||
className={styles.cancelButton}
|
||||
onClick={() => {
|
||||
setEditingMaterialId(null);
|
||||
setNewQuantity(0);
|
||||
setNewPrice("");
|
||||
}}
|
||||
>
|
||||
Batal
|
||||
</button>
|
||||
<button
|
||||
className={styles.saveButton}
|
||||
onClick={() => handleUpdateStock(material.materialId)}
|
||||
disabled={newQuantity === 0 && !convertToInteger(newPrice)}
|
||||
>
|
||||
Simpan Perubahan
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.historyTab}>
|
||||
<h3 onClick={() => setIsViewingHistory(!isViewingHistory)}> {isViewingHistory ? '˅' : '˃'} Riwayat stok</h3>
|
||||
{selectedMaterialIndex !== -1 && isViewingHistory && !loading && (
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* History Section */}
|
||||
<div className={styles.historySection}>
|
||||
<h4
|
||||
className={styles.historyTitle}
|
||||
onClick={() => toggleHistoryView(material.materialId)}
|
||||
>
|
||||
{isViewingHistory[material.materialId] ? '▲' : '▼'} Riwayat Stok
|
||||
</h4>
|
||||
|
||||
{isViewingHistory[material.materialId] && (
|
||||
<>
|
||||
<div className={styles.sorter} onClick={() => setSortOrder(sortOrder == 'asc' ? 'desc' : 'asc')}>
|
||||
Urutkan: {sortOrder === 'asc' ? "terlama" : "terbaru"} <div style={{ transform: 'rotate(90deg)' }}><></div>
|
||||
<div className={styles.sortControls}>
|
||||
<button
|
||||
className={styles.sortButton}
|
||||
onClick={() => setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc')}
|
||||
>
|
||||
Urutkan: {sortOrder === 'asc' ? 'Terlama' : 'Terbaru'}
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.historyContainer}>
|
||||
<div className={styles.mutationContainer}>
|
||||
{sortedMutations.length > 0 ? (
|
||||
sortedMutations.map((mutation) => (
|
||||
<div key={mutation.id} className={styles.mutationCard}>
|
||||
<div style={{ width: '42px', backgroundColor: '#b9b9b9', borderRadius: '10px', padding: '3px', paddingBottom: '0' }}>
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<g id="Interface / Book">
|
||||
<path id="Vector" d="M5 19.5002V6.2002C5 5.08009 5 4.51962 5.21799 4.0918C5.40973 3.71547 5.71547 3.40973 6.0918 3.21799C6.51962 3 7.08009 3 8.2002 3H17.4002C17.9602 3 18.2407 3 18.4546 3.10899C18.6427 3.20487 18.7948 3.35774 18.8906 3.5459C18.9996 3.75981 19 4.04005 19 4.6001V16.4001C19 16.9601 18.9996 17.2398 18.8906 17.4537C18.7948 17.6419 18.6429 17.7952 18.4548 17.8911C18.2411 18 17.961 18 17.402 18H7.25C6.00736 18 5 19.0074 5 20.25C5 20.6642 5.33579 21 5.75 21H16.402C16.961 21 17.2411 21 17.4548 20.8911C17.6429 20.7952 17.7948 20.642 17.8906 20.4538C17.9996 20.2399 18 19.9601 18 19.4V18" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<div className={styles.historyItems}>
|
||||
{getFilteredMutations(material.materialId).length > 0 ? (
|
||||
getFilteredMutations(material.materialId).map((mutation) => (
|
||||
<div key={mutation.id} className={styles.historyItem}>
|
||||
<div className={styles.historyIcon}>📊</div>
|
||||
<div className={styles.historyContent}>
|
||||
<div className={styles.historyDate}>{formatDate(mutation.createdAt)}</div>
|
||||
<div className={styles.historyDetails}>
|
||||
Stok: {mutation.newStock} {material.unit} |
|
||||
Perubahan: {mutation.newStock - mutation.oldStock > 0 ? '+' : ''}{mutation.newStock - mutation.oldStock} |
|
||||
Harga: Rp {formatCurrency(mutation.priceAtp)}
|
||||
</div>
|
||||
<div className={styles.mutationTitle}>
|
||||
<h4>{formatDate(mutation.createdAt)}</h4>
|
||||
<p>Total stok: {mutation.newStock} || +{mutation.newStock - mutation.oldStock} || {formatCurrency((mutation.newStock - mutation.oldStock) * mutation.priceAtp)}</p>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p>Tidak ada laporan perubahan stok.</p>
|
||||
)}
|
||||
<div className={styles.emptyState} style={{ padding: '20px' }}>
|
||||
<div>Belum ada riwayat perubahan stok</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.description}>
|
||||
<div style={{ marginRight: "5px", fontSize: "1.2em" }}>ⓘ</div>
|
||||
<h6 style={{ margin: 0, textAlign: "left", fontSize: '12px' }}>
|
||||
Fitur ini mempermudah mengelola biaya dan memantau pengeluaran bahan.
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<div className={styles.switchContainer}>
|
||||
<h3>Buat bahan baru</h3>
|
||||
</div>
|
||||
<div className={styles.resultMessage}>
|
||||
<input
|
||||
className={styles.resultMessageInput}
|
||||
value={newMaterialName}
|
||||
onChange={(event) => setNewMaterialName(event.target.value)}
|
||||
placeholder="Masukkan nama barang"
|
||||
style={{width: '100%', height: '31px'}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<select
|
||||
id="materialUnit"
|
||||
value={newMaterialUnit}
|
||||
onChange={(e) => setNewMaterialUnit(e.target.value)}
|
||||
className={styles.unit}
|
||||
style={{height: '37px'}}
|
||||
>
|
||||
<option value="gram">Satuan: gram</option>
|
||||
<option value="ons">Satuan: ons</option>
|
||||
<option value="kilogram">Satuan: kilogram</option>
|
||||
<option value="kuintal">Satuan: kuintal</option>
|
||||
<option value="liter">Satuan: liter</option>
|
||||
<option value="piece">Satuan: piece</option>
|
||||
<option value="meter">Satuan: meter</option>
|
||||
<option value="pack">Satuan: pack</option>
|
||||
<option value="sachet">Satuan: sachet</option>
|
||||
<option value="box">Satuan: box</option>
|
||||
</select>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<button className={styles.saveButton} onClick={handleCreateMaterial}>
|
||||
Buat bahan baku
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SetPaymentQr;
|
||||
export default MaterialList;
|
||||
@@ -1,149 +1,556 @@
|
||||
/* SetPaymentQr.module.css */
|
||||
/* MaterialList.module.css */
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
min-height: 47vh;
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
padding: 0;
|
||||
margin-bottom: 24px;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
z-index: 200; /* Menaikkan z-index agar berada di atas cartbar */
|
||||
max-height: 70vh; /* Membatasi tinggi maksimum */
|
||||
overflow-y: auto; /* Memungkinkan scrolling vertikal */
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #ffffff;
|
||||
z-index: 201; /* Memastikan header berada di atas container */
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
font-weight: 700;
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.uploadMessage {
|
||||
.addButton {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
box-shadow: 0 2px 6px rgba(40, 167, 69, 0.2);
|
||||
position: relative;
|
||||
z-index: 202; /* Memastikan tombol berada di atas header */
|
||||
}
|
||||
|
||||
.changeButtonEnabled {
|
||||
padding-right: 10px;
|
||||
background-color: green;
|
||||
border-radius: 30px;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
padding-left: 10px;
|
||||
padding-height: 10px;
|
||||
.addButton:hover {
|
||||
background-color: #218838;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 10px rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.changeButtonDisabled {
|
||||
padding-right: 10px;
|
||||
.addButton:disabled {
|
||||
background-color: #a1a1a1;
|
||||
border-radius: 30px;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
padding-left: 10px;
|
||||
padding-height: 10px;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.resultMessage {
|
||||
margin-top: -13px;
|
||||
text-align: left;
|
||||
.content {
|
||||
padding: 24px;
|
||||
position: relative;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
/* Materials List Styles */
|
||||
.materialsList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.materialCard {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid #eee;
|
||||
position: relative;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.materialCard:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
.materialSummary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.resultMessage input {
|
||||
padding-left: 8px;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.stokContainer {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
margin-top: -20px;
|
||||
margin-bottom: -15px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
margin-top: 11px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.stockButton {
|
||||
padding: 10px 20px;
|
||||
font-size: 3.5vw;
|
||||
background-color: #28a745;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
padding: 16px 20px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
position: relative;
|
||||
z-index: 201;
|
||||
}
|
||||
|
||||
.materialName {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.materialStock {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 0 16px 0 0;
|
||||
}
|
||||
|
||||
.expandIcon {
|
||||
font-size: 18px;
|
||||
color: #28a745;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.expandIcon.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Material Detail Styles */
|
||||
.materialDetail {
|
||||
padding: 0 20px 20px 20px;
|
||||
border-top: 1px solid #eee;
|
||||
background: #f9f9f9;
|
||||
border-radius: 0 0 12px 12px;
|
||||
position: relative;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.detailGrid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.detailItem {
|
||||
background: #ffffff;
|
||||
padding: 16px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.detailLabel {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.detailValue {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.detailActions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.detailButton {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.updateButton {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(40, 167, 69, 0.2);
|
||||
}
|
||||
|
||||
.updateButton:hover {
|
||||
background-color: #218838;
|
||||
box-shadow: 0 4px 10px rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(220, 53, 69, 0.2);
|
||||
}
|
||||
|
||||
.deleteButton:hover {
|
||||
background-color: #c82333;
|
||||
box-shadow: 0 4px 10px rgba(220, 53, 69, 0.3);
|
||||
}
|
||||
|
||||
/* Stock Update Form */
|
||||
.stockUpdateForm {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
position: relative;
|
||||
z-index: 201;
|
||||
}
|
||||
|
||||
.formTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
.quantityControls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.quantityButton {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #ddd;
|
||||
background: #ffffff;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.quantityButton:hover {
|
||||
border-color: #28a745;
|
||||
background: #f0f8f1;
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.quantityDisplay {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
min-width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.formGroup {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.formLabel {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.formInput {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 16px;
|
||||
transition: all 0.2s ease;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.formInput:focus {
|
||||
outline: none;
|
||||
border-color: #28a745;
|
||||
box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.1);
|
||||
}
|
||||
|
||||
.formActions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.formButton {
|
||||
flex: 1;
|
||||
padding: 14px 16px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.saveButton {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
font-size: 3.5vw;
|
||||
background-color: #28a745;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
color: white;
|
||||
box-shadow: 0 2px 6px rgba(40, 167, 69, 0.2);
|
||||
}
|
||||
|
||||
.switchContainer {
|
||||
margin-top: 20px;
|
||||
text-align: left;
|
||||
.saveButton:hover {
|
||||
background-color: #218838;
|
||||
box-shadow: 0 4px 10px rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.historyTab {
|
||||
text-align: left;
|
||||
.cancelButton {
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.historyContainer {
|
||||
text-align: left;
|
||||
max-height: 15vh;
|
||||
overflow-y: auto;
|
||||
.cancelButton:hover {
|
||||
background-color: #e0e0e0;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.description {
|
||||
display: flex;
|
||||
margin: 10px 0;
|
||||
font-size: 14px;
|
||||
/* Add Material Form */
|
||||
.addMaterialForm {
|
||||
background: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin-top: 24px;
|
||||
position: relative;
|
||||
z-index: 201;
|
||||
}
|
||||
|
||||
.formSection {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 0 20px 0;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.formGrid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.fullWidth {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
/* Empty State */
|
||||
.emptyState {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.emptyStateIcon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 16px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.emptyStateText {
|
||||
font-size: 18px;
|
||||
margin-bottom: 24px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.unit {
|
||||
margin-top: 11px;
|
||||
width: 100%;
|
||||
height: 31px;
|
||||
/* History Section */
|
||||
.historySection {
|
||||
margin-top: 24px;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.sorter {
|
||||
border: 1px solid #c3c3c3;
|
||||
padding: 5px;
|
||||
.historyTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 0 16px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.historyTitle:hover {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.historyItems {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.historyItems::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.historyItems::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mutationCard {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
margin-top: 7px;
|
||||
.historyItems::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.mutationTitle {
|
||||
margin-left: 5px;
|
||||
.historyItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 12px 16px;
|
||||
background: #ffffff;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.mutationTitle h4 {
|
||||
|
||||
.historyIcon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: #b9b9b9;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.historyContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.historyDate {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 0 2px 0;
|
||||
}
|
||||
|
||||
.historyDetails {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mutationTitle p {
|
||||
margin: 0;
|
||||
.sortControls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.sortButton {
|
||||
background: #f0f0f0;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
padding: 6px 14px;
|
||||
font-size: 13px;
|
||||
color: #555;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.sortButton:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
/* Loading State */
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.loadingSpinner {
|
||||
font-size: 32px;
|
||||
margin-bottom: 16px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.header {
|
||||
padding: 16px;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.detailGrid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.formGrid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.historyItems {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.materialSummary {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.materialName {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.materialStock {
|
||||
font-size: 13px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-height: 75vh; /* Menaikkan tinggi maksimum pada mobile */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user