This commit is contained in:
everythingonblack
2025-04-03 05:19:27 +07:00
parent a64b999a05
commit 931f3f90e8
12 changed files with 849 additions and 58 deletions

View File

@@ -338,6 +338,8 @@ const Header = ({
Ubah profil
</Child>
)}
{user.roleId == 0 && (
<Child onClick={()=>setModal('create_coupon', {})}>Buat Voucher</Child>)}
{shopId && user.roleId == 1 && (
<Child onClick={goToAdminCafes}>Dashboard</Child>)}
{shopId &&

View File

@@ -19,12 +19,12 @@ import MaterialList from "../pages/MaterialList.js";
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
import Reports from "../pages/Reports.js";
import NotificationRequest from "../pages/NotificationRequest.js";
import Unavailable from "../pages/Unavailable.js";
import NotificationBlocked from "../pages/NotificationBlocked.js";
import WelcomePageEditor from "../pages/WelcomePageEditor.js";
import GuidePage from "../pages/GuidePage";
import Join from "../pages/Join";
import Loading from "../pages/Loading";
import Message from "../pages/Message";
import Login from "../pages/Login";
import ResetPassword from "../pages/ResetPassword";
import { getImageUrl } from "../helpers/itemHelper.js";
@@ -76,7 +76,6 @@ const Modal = ({ user, shop, isOpen, onClose, modalContent, deviceType, setModal
{modalContent === "edit_account" && <AccountUpdatePage user={user} />}
{modalContent === "reset-password" && <ResetPassword />}
{modalContent === "req_notification" && <NotificationRequest setModal={setModal} />}
{modalContent === "unavailable" && <Unavailable close={handleContentClick} />}
{modalContent === "blocked_notification" && <NotificationBlocked />}
{modalContent === "create_clerk" && <CreateClerk shopId={shop.cafeId} />}
{modalContent === "create_kedai" && <CreateCafe shopId={shop.cafeId} />}
@@ -124,6 +123,7 @@ const Modal = ({ user, shop, isOpen, onClose, modalContent, deviceType, setModal
{modalContent === "join" && <Join setModal={setModal} />}
{modalContent === "claim-coupon" && <Join setModal={setModal} />}
{modalContent === "loading" && <Loading setModal={setModal} />}
{modalContent === "message" && <Message/>}
</div>
</div>
);

View File

@@ -0,0 +1,49 @@
import React from 'react';
import styles from './StepByStep.module.css'; // Import the CSS Module
const StepByStep = () => {
return (
<div className={styles.container}>
<div className={styles.screen}>
<div className={styles.main}>
<img src="https://i.ibb.co.com/F4VK6KHs/header.jpg" alt="Header" />
<div className={styles.player}>
<img src="https://i.ibb.co.com/6cGq6byM/player1.jpg" alt="Player 1" />
<img src="https://i.ibb.co.com/0VDjJdXV/player2.jpg" alt="Player 2" />
<img src="https://i.ibb.co.com/8D3mSp4g/player3.jpg" alt="Player 3" />
<img src="https://i.ibb.co.com/XxS1DhRy/player4.jpg" alt="Player 4" />
</div>
<div>
<img src="https://i.ibb.co.com/4z5zdsS/body.jpg" alt="Body" />
<div className={styles.escappucino}>
<img src="https://i.ibb.co.com/yFvrPX8z/pesan.png" alt="Escappucino 1" />
<img src="https://i.ibb.co.com/rRwPHtY7/pesan-1.png" alt="Escappucino 2" />
</div>
<div className={styles.chickenkatsu}>
<img src="https://i.ibb.co.com/yFvrPX8z/pesan.png" alt="Chickenkatsu 1" />
<img src="https://i.ibb.co.com/rRwPHtY7/pesan-1.png" alt="Chickenkatsu 2" />
</div>
</div>
</div>
<div className={styles.cartbutton}>
<img src="https://i.ibb.co.com/zVrfGjZw/New-Project.png" alt="Cart Button" />
<img src="https://i.ibb.co.com/Y7wbjGDz/cart-2.png" alt="Cart Icon" />
</div>
<div className={styles.cart}>
<img src="https://i.ibb.co.com/F4Hb7Tqg/cart.jpg" alt="Cart Image" />
<img src="https://i.ibb.co.com/Mxrjc9Dc/checkout.png" alt="Checkout" />
</div>
<div className={styles.transaction}>
<img src="https://i.ibb.co.com/1p7pnnD/transaction.png" alt="Transaction" />
</div>
</div>
<div className={styles.secondscreen}>
<div className={styles.secondmain}>
<img src="https://i.ibb.co.com/LDw21htp/New-Project.jpg"/>
</div>
</div>
</div>
);
};
export default StepByStep;

View File

@@ -0,0 +1,684 @@
.title {
color: #5C6AC4;
}
.container {
width: 188px;
height: 308px;
margin: 10px;
}
.screen {
width: 122px;
height: 264px;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
overflow: hidden;
position: relative;
z-index: 11;
}
.secondscreen {
width: 122px;
height: 264px;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
overflow: hidden;
position: relative;
left: 38%;
top: -62%;
z-index: 10;
}
.secondmain {
width: 100%;
height: 100%;
animation: reportScrollBottom 5s infinite; /* Apply scroll animation only once */
}
.secondmain img {
width: 100%;
}
@keyframes reportScrollBottom {
0% {
transform: translateY(0%); /* Start from the top */
}
30% {
transform: translateY(0%); /* Start from the top */
}
50% {
transform: translateY(-43%); /* Start from the top */
}
80% {
transform: translateY(-43%); /* Start from the top */
}
100% {
transform: translateY(0%); /* Start from the top */
}
}
.main {
width: 100%;
height: 100%; /* Ensure the div fills the container */
display: flex;
flex-direction: column;
justify-content: flex-start;
animation: scrollBottom 20s infinite; /* Apply scroll animation only once */
position: absolute; /* Ensures it moves within the container */
background-color: white;
}
.main img{
width: 100%;
}
.main > div:nth-child(2) {
animation: playerClick 20s infinite;
}
.main > div:nth-child(3) {
animation: bodyDown 20s infinite;
}
/* Keyframes for scrolling the div content down */
@keyframes scrollBottom {
0% {
transform: translateY(0); /* Start from the top */
}
10% {
transform: translateY(0); /* Scale down at 20% */
}
15% {
transform: translateY(-50%); /* Move the content up */
}
57.5% {
transform: translateY(-50%); /* Move the content up */
}
62.5% {
transform: translateY(0%); /* Move the content up */
}
100% {
transform: translateY(0%); /* Move the content up */
}
}
/* New keyframes for scaling and opacity effect */
@keyframes playerClick {
0% {
transform: scale(1); /* Initial scale */
}
64% {
transform: scale(1); /* Initial scale */
}
65% {
transform: scale(0.8); /* Scale down */
}
66% {
transform: scale(1); /* Scale back to original size */
}
67% {
transform: scale(0.8); /* Scale down */
}
68% {
transform: scale(1); /* Scale back to original size */
}
94% {
transform: scale(1); /* Scale back to original size */
}
95% {
transform: scale(0.8); /* Scale back to original size */
}
96% {
transform: scale(1); /* Scale back to original size */
}
100% {
transform: scale(1); /* Scale back to original size */
}
}
/* New keyframes for scaling and opacity effect */
@keyframes bodyDown {
0% {
margin-top: 0%;
}
64% {
margin-top: 0%;
}
65% {
margin-top: 20%;
}
66% {
margin-top: 20%;
}
67% {
margin-top: 96%;
}
90% {
margin-top: 96%;
}
91% {
margin-top: 20%;
}
97% {
margin-top: 20%;
}
98% {
margin-top: 0%;
}
100% {
margin-top: 0%;
}
}
.player img{
width: 100%;
}
.player > img:nth-child(1) {
animation: playerUnexpandedOpacity 20s infinite;
}
.player > img:nth-child(2) {
animation: player2ExpandedOpacity 20s infinite;
position: absolute;
top: 0;
left: 0;
}
.player > img:nth-child(3) {
animation: player3ExpandedOpacity 20s infinite;
position: absolute;
top: 0;
left: 0;
}
.player > img:nth-child(4) {
animation: player4ExpandedOpacity 20s infinite;
position: absolute;
top: 0;
left: 0;
}
/* New keyframes for scaling and opacity effect */
@keyframes playerUnexpandedOpacity {
0% {
filter: opacity(1); /* Initial scale */
}
65% {
filter: opacity(1);
}
66% {
filter: opacity(0);
}
95% {
filter: opacity(0);
}
96% {
filter: opacity(1);
}
100% {
filter: opacity(1); /* Scale back to original size */
}
}
/* New keyframes for scaling and opacity effect */
@keyframes player2ExpandedOpacity {
0% {
filter: opacity(0); /* Initial scale */
}
65% {
filter: opacity(0);
}
66% {
filter: opacity(1);
}
67% {
filter: opacity(0); /* Scale back to original size */
}
100% {
filter: opacity(0); /* Scale back to original size */
}
}
/* New keyframes for scaling and opacity effect */
@keyframes player3ExpandedOpacity {
0% {
filter: opacity(0); /* Initial scale */
}
66% {
filter: opacity(0);
}
67% {
filter: opacity(1);
}
90% {
filter: opacity(1);
}
91% {
filter: opacity(0);
}
100% {
filter: opacity(0); /* Scale back to original size */
}
}
/* New keyframes for scaling and opacity effect */
@keyframes player4ExpandedOpacity {
0% {
filter: opacity(0); /* Initial scale */
}
90% {
filter: opacity(0);
}
91% {
filter: opacity(1);
}
95% {
filter: opacity(1);
}
97% {
filter: opacity(1);
}
98% {
filter: opacity(0);
}
100% {
filter: opacity(0); /* Scale back to original size */
}
}
.escappucino {
position: relative;
top: -63.6%;
width: 100%;
animation: escappucinoscaleAnimation 20s infinite; /* Apply the scale animation */
}
.escappucino img {
width: 100%;
}
.escappucino > img:nth-child(1) {
position: absolute;
animation: escappucinochildOpacityAnimation 20s infinite;
}
.escappucino > img:nth-child(2) {
animation: escappucinochildOpacityAnimation2 20s infinite;
}
/* New keyframes for scaling and opacity effect */
@keyframes escappucinoscaleAnimation {
0% {
transform: scale(1); /* Initial scale */
}
5% {
transform: scale(1); /* Initial scale */
}
7.5% {
transform: scale(0.8); /* Scale down */
}
10% {
transform: scale(1); /* Scale back to original size */
}
100% {
transform: scale(1); /* Scale back to original size */
}
}
@keyframes escappucinochildOpacityAnimation {
0% {
opacity: 1; /* Start visible */
}
5% {
opacity: 1; /* Start visible */
}
7.5% {
opacity: 0; /* Fade out at 70% */
}
10% {
opacity: 0; /* Keep faded out */
}
50% {
opacity: 0; /* Keep faded out */
}
60% {
opacity: 1; /* Keep faded out */
}
100% {
opacity: 1; /* Keep faded out */
}
}
@keyframes escappucinochildOpacityAnimation2 {
0% {
opacity: 0; /* Start invisible */
}
5% {
opacity: 0; /* Start invisible */
}
7.5% {
opacity: 1; /* Fade in at 70% */
}
10% {
opacity: 1; /* Keep visible */
}
50% {
opacity: 1; /* Keep faded out */
}
60% {
opacity: 0; /* Keep faded out */
}
100% {
opacity: 0; /* Keep faded out */
}
}
.chickenkatsu {
position: relative;
top: -27.6%;
width: 100%;
animation: chickenkatsuscaleAnimation 20s infinite; /* Apply the scale animation */
}
.chickenkatsu img {
width: 100%;
}
.chickenkatsu > img:nth-child(1) {
position: absolute;
animation: chickenkatsuchildOpacityAnimation 20s infinite;
}
.chickenkatsu > img:nth-child(2) {
animation: chickenkatsuchildOpacityAnimation2 20s infinite;
}
/* New keyframes for scaling and opacity effect */
@keyframes chickenkatsuscaleAnimation {
0% {
transform: scale(1); /* Initial scale */
}
15% {
transform: scale(1); /* Initial scale */
}
17.5% {
transform: scale(0.8); /* Scale down */
}
20% {
transform: scale(1); /* Scale back to original size */
}
100% {
transform: scale(1); /* Scale back to original size */
}
}
@keyframes chickenkatsuchildOpacityAnimation {
0% {
opacity: 1; /* Start visible */
}
15% {
opacity: 1; /* Start visible */
}
17.5% {
opacity: 0; /* Fade out at 70% */
}
20% {
opacity: 0; /* Keep faded out */
}
50% {
opacity: 0; /* Keep faded out */
}
60% {
opacity: 1; /* Keep faded out */
}
100% {
opacity: 1; /* Keep faded out */
}
}
@keyframes chickenkatsuchildOpacityAnimation2 {
0% {
opacity: 0; /* Start visible */
}
15% {
opacity: 0; /* Start visible */
}
17.5% {
opacity: 1; /* Fade out at 70% */
}
20% {
opacity: 1; /* Keep faded out */
}
50% {
opacity: 1; /* Keep faded out */
}
60% {
opacity: 0; /* Keep faded out */
}
100% {
opacity: 0; /* Keep faded out */
}
}
.cartbutton{
position: absolute;
width: 100%;
top: 86%;
animation: cartbuttonscaleAnimation 20s infinite; /* Apply the scale animation */
}
.cartbutton img {
width: 100%;
}
.cartbutton > img:nth-child(1) {
position: absolute;
animation: cartbuttonchildOpacityAnimation 20s infinite;
}
.cartbutton > img:nth-child(2) {
animation: cartbuttonchildOpacityAnimation2 20s infinite;
}
/* New keyframes for scaling and opacity effect */
@keyframes cartbuttonscaleAnimation {
0% {
transform: scale(1); /* Initial scale */
filter: opacity(0);
}
5% {
transform: scale(1); /* Initial scale */
filter: opacity(0);
}
7.5% {
transform: scale(1); /* Initial scale */
filter: opacity(1);
}
25% {
transform: scale(1); /* Initial scale */
}
27.5% {
transform: scale(0.8); /* Scale down */
}
30% {
transform: scale(1); /* Scale back to original size */
}
50% {
transform: scale(1); /* Scale back to original size */
filter: opacity(1);
}
60% {
transform: scale(1); /* Scale back to original size */
filter: opacity(0);
}
100% {
transform: scale(1); /* Scale back to original size */
filter: opacity(0);
}
}
@keyframes cartbuttonchildOpacityAnimation {
0% {
opacity: 1; /* Start visible */
}
15% {
opacity: 1; /* Start visible */
}
17.5% {
opacity: 0; /* Fade out at 70% */
}
20% {
opacity: 0; /* Keep faded out */
}
100% {
opacity: 0; /* Keep faded out */
}
}
@keyframes cartbuttonchildOpacityAnimation2 {
0% {
opacity: 0; /* Start invisible */
}
15% {
opacity: 0; /* Start invisible */
}
17.5% {
opacity: 1; /* Fade in at 70% */
}
20% {
opacity: 1; /* Keep visible */
}
100% {
opacity: 1; /* Keep visible */
}
}
.cart{
position: absolute;
width: 100%;
height: 100%;
left: 100%;
animation: cartslideinAnimation 20s infinite; /* Apply the scale animation */
}
.cart > img:nth-child(1) {
width: 100%;
height: 100%;
}
.cart > img:nth-child(2) {
width: 100%;
position: absolute;
top: 90.7%;
left: 0;
animation: checkoutbuttonscaleAnimation 20s infinite; /* Apply the scale animation */
}
@keyframes cartslideinAnimation {
0% {
left: 100%;
}
30% {
left: 100%;
}
32.5% {
left: 0%;
}
55% {
left: 0%;
}
57.5% {
left: 100%;
}
100% {
left: 100%;
}
}
/* New keyframes for scaling and opacity effect */
@keyframes checkoutbuttonscaleAnimation {
0% {
transform: scale(1); /* Initial scale */
}
37.5% {
transform: scale(1); /* Initial scale */
}
40% {
transform: scale(0.8); /* Scale down */
}
42.5% {
transform: scale(1); /* Scale back to original size */
}
100% {
transform: scale(1); /* Scale back to original size */
}
}
.transaction{
position: absolute;
width: 100%;
height: 100%;
animation: transactionAnimation 20s infinite;
background-color: #0000006b;
display: flex;
justify-content: center;
align-items: center;
}
.transaction img {
width: 80%;
animation: transactionElementAnimation 20s infinite;
}
/* New keyframes for scaling and opacity effect */
@keyframes transactionAnimation {
0% {
filter: opacity(0);
}
42.5% {
filter: opacity(0);
}
45% {
filter: opacity(1);
}
52.5% {
filter: opacity(1);
}
55% {
filter: opacity(0);
}
100% {
filter: opacity(0);
}
}
/* New keyframes for scaling and opacity effect */
@keyframes transactionElementAnimation {
0% {
transform: scale(0); /* Initial scale */
}
42.5% {
transform: scale(0); /* Initial scale */
}
45% {
transform: scale(1); /* Scale down */
}
52.5% {
transform: scale(1); /* Scale down */
}
55% {
transform: scale(0); /* Scale down */
}
100% {
transform: scale(0); /* Scale back to original size */
}
}

View File

@@ -0,0 +1,17 @@
import React from 'react';
import StepByStep from './StepByStep';
const Watermark = ({dontShowName}) => {
return (
<div style={{ zIndex: 5, marginTop: '30px', backgroundColor: 'rgb(222 237 100)', fontWeight: 700, fontSize: '15px', lineHeight: '1rem', letterSpacing: '-1px', color: 'rgb(37, 79, 26)', padding: '10px' }}>
{!dontShowName && <div>KEDAIMASTER.COM</div>}
<div style={{ display: 'flex' }}>
<div style={{ width: '45vw', marginTop: '10px', fontSize: '5.5vw', lineHeight: '33px' }}>Gak perlu rasain antri panjang yang bikin bosen lagi. Tinggal scan QR yang ada di meja, eh tiba tiba pesanan udah dimejamu</div>
<StepByStep />
</div>
<div style={{ marginTop: '8px' }}>© 2025 KEDIRITECHNOPARK.COM</div>
</div>
);
};
export default Watermark;

View File

@@ -10,6 +10,7 @@ import {
import "../App.css";
import Watermark from "../components/Watermark";
import { getImageUrl, createItem, updateItem, moveItemType } from "../helpers/itemHelper.js";
import SearchInput from "../components/SearchInput";
import ItemTypeLister from "../components/ItemTypeLister";
@@ -139,7 +140,7 @@ function CafePage({
socket.on("joined-room", (response) => {
const { isSpotifyNeedLogin, isExceededDeadline } = response;
setNeedSpotifyLogin(isSpotifyNeedLogin);
if (isExceededDeadline) setModal('unavailable');
if (isExceededDeadline) setModal('message',{returnMessage:'Kafe sedang tidak tersedia'});
setIsExceededDeadline(isExceededDeadline);
});
}
@@ -210,8 +211,8 @@ function CafePage({
/>
) : (
welcomePageConfig != null && (
<div className="Cafe" style={{ filter: isExceededDeadline ? 'grayscale(1)' : '', pointerEvents: isExceededDeadline ? 'none' : '' }}>
<body className="App-header">
<div className="Cafe" style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', minHeight: '100vh', filter: isExceededDeadline ? 'grayscale(1)' : '', pointerEvents: isExceededDeadline ? 'none' : '' }}>
<div className="App-header">
<Header
HeaderText={"Menu"}
showProfile={true}
@@ -359,8 +360,8 @@ function CafePage({
</div>
}
</div>
<div style={{ marginTop: '30px', height: '27px', backgroundColor: 'rgb(222 237 100)', fontWeight: 700, fontSize: '15px', lineHeight: '1rem', letterSpacing: '-1px', color: 'rgb(37, 79, 26)', padding: '10px' }}><div>KEDAIMASTER</div></div>
</body>
</div>
<Watermark/>
</div>
)
)}

View File

@@ -14,6 +14,7 @@ import API_BASE_URL from '../config';
import DailyCharts from '../components/DailyCharts';
import Coupon from '../components/Coupon';
import Reports from './Reports'
import Watermark from '../components/Watermark.js';
const LinktreePage = ({ user, setModal }) => {
const navigate = useNavigate();
@@ -297,7 +298,7 @@ const LinktreePage = ({ user, setModal }) => {
{getLocalStorage('auth') == null && (
<div className={styles.LoginForm}>
<div className={`${styles.FormUsername} ${inputtingPassword ? styles.animateForm : wasInputtingPassword ? styles.reverseForm : ''}`}>
<label htmlFor="username" className={styles.usernameLabel}>---- Masuk -------------------------------</label>
<label htmlFor="username" className={styles.usernameLabel}>---- Masuk -----------------------------</label>
<input
id="username"
placeholder="username"
@@ -316,7 +317,7 @@ const LinktreePage = ({ user, setModal }) => {
<label onClick={() => setInputtingPassword(false)} htmlFor="password" className={styles.usernameLabel}> &lt;--- &lt;-- Kembali </label>
<label htmlFor="password" className={styles.usernameLabel}> &nbsp; ----- &nbsp; </label>
<label onClick={() => setModal('reset-password', { username: username })} className={styles.usernameLabel}>
lupa password? -
lupa password?
</label>
</span>
<input
@@ -360,9 +361,9 @@ const LinktreePage = ({ user, setModal }) => {
onError={(e) => e.target.src = '/fallback-image.png'}
/>
</div>
<a style={{ left: 0, right: 0, bottom: 0, textAlign: 'center', color: '#254F1A', fontSize: '13px', position: 'fixed' }}>©2025 KEDIRITECHNOPARK.COM</a>
</div>
</div>
<Watermark dontShowName={true}/>
</div>
)}
</>

View File

@@ -78,6 +78,8 @@ const LinktreePage = ({ data, setModal }) => {
// Handle manual coupon code check
const handleLogCouponForUser = async (code = couponCode) => {
const result = await logCouponForUser(code); // Call the helper
return result.success;
};
// Listen for query parameter changes (using the `location` object)
@@ -106,20 +108,11 @@ const LinktreePage = ({ data, setModal }) => {
<div className={styles.subHeadingTransparent}>
Daftarkan kedaimu sekarang dan mulai gunakan semua fitur unggulan kami.
</div>
<form className={styles.linktreeForm}>
<label htmlFor="username" className={styles.usernameLabel}>
--------------------------------------------
</label>
<input
id="username"
placeholder="nomor whatsapp atau email"
maxLength="30"
className={styles.usernameInput}
/>
<button type="submit" className={styles.claimButton}>
<span></span>
<div className={styles.linktreeForm}>
<button onClick={()=>window.open("https://api.whatsapp.com/send?phone=6281318894994&text=Saya%20ingin%20coba%20gratis%203%20bulan")} className={styles.claimButton}>
<span>Dapatkan voucher gratis 3 bulan</span>
</button>
</form>
</div>
<div className={styles.footer}>
<div className={styles.footerLinks}>
<a
@@ -131,7 +124,10 @@ const LinktreePage = ({ data, setModal }) => {
Pelajari lebih lanjut
</a>
<a
onClick={() => setIsUsingCoupon(true)}
onClick={(e) => {
e.preventDefault(); // Prevent the default anchor behavior
setIsUsingCoupon(true);
}}
className={styles.footerLink}
>
Gunakan Voucher
@@ -141,14 +137,14 @@ const LinktreePage = ({ data, setModal }) => {
</div>
) : (
<div className={styles.dashboardContainer}>
<div className={styles.mainHeading}>{isOnlyClaimCoupon ? 'Aktifkan Voucher' : 'Daftar Dengan Voucher'}</div>
<div className={styles.voucherHeading}>{isOnlyClaimCoupon ? 'Aktifkan Voucher' : 'Daftar Dengan Voucher'}</div>
<div className={styles.subHeading}>
Voucher dapat digunakan untuk pembuatan akun bisnis maupun untuk memperpanjang masa berlangganan.
</div>
{couponStatus === 0 ? (
<form className={styles.linktreeForm} onSubmit={(e) => e.preventDefault()}>
<label htmlFor="coupon" className={styles.usernameLabel}>
--------------------------------------------
----------------------------------------
</label>
<input
id="coupon"
@@ -179,19 +175,29 @@ const LinktreePage = ({ data, setModal }) => {
<button
className={styles.claimButton}
style={{ width: '266px' }}
onClick={() => {
onClick={async () => {
if (!isOnlyClaimCoupon) {
const secretKey = 'xixixi666'; // Your AES-256 key (32 characters)
// Encrypt couponCode inline
const encryptedCouponCode = CryptoJS.AES.encrypt(couponCode, secretKey).toString();
console.log(encryptedCouponCode)
// If it's only claiming a coupon, trigger claim logic
console.log(encryptedCouponCode);
// If it's not for claiming a coupon, trigger the create user modal logic
setModal('create_user', { codeStatus: 200, c: encryptedCouponCode });
} else {
try {
// Otherwise, handle the coupon for user creation
handleLogCouponForUser();
setModal('loading');
const loggingcoupon = await handleLogCouponForUser(); // Await the coupon logging process
setModal('message', {
returnMessage: loggingcoupon ? 'Kupon berhasil ditambahkan' : 'Kupon gagal ditambahkan'
});
} catch (error) {
console.error('Error during coupon handling:', error);
setModal('message', { returnMessage: 'Kupon gagal ditambahkan' });
}
}
}}
>

View File

@@ -17,6 +17,7 @@
/* Main Heading */
.mainHeading {
width: 222px;
font-weight: 700;
font-size: 32px;
line-height: 2.25rem;
@@ -25,6 +26,15 @@
color: rgb(37, 79, 26);
}
/* Main Heading */
.voucherHeading {
font-weight: 700;
font-size: 32px;
line-height: 2.25rem;
margin-bottom: 1rem;
letter-spacing: -1px;
color: rgb(37, 79, 26);
}
.swipeContainer {
height: 75px;
overflow: hidden;
@@ -109,7 +119,7 @@
}
.claimButton {
width: 200px;
width: 236px;
height: 45px;
background-color: #254F1A;
color: #D2E823;

View File

@@ -1,21 +1,11 @@
/* General container */
.centeredLinktreePage {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
background-color: rgb(222 237 100);
}
.nonCenteredLinktreePage {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: start;
background-color: rgb(255 255 255);
position: relative;
}
.dashboardLine {
position: fixed;
left: 0px;
@@ -29,7 +19,7 @@
background-color: inherit;
z-index: 6;
padding: 0 1rem;
padding-top: 40px;
padding-top: 100px;
}
/* Main Heading */

28
src/pages/Message.js Normal file
View File

@@ -0,0 +1,28 @@
// LinktreePage.js
import React, { useState, useEffect } from 'react';
import styles from './Join.module.css'; // Import the module.css file
const LinktreePage = () => {
const [returnMessage, setReturnMessage] = useState('');
useEffect(() => {
const newQueryParams = new URLSearchParams(window.location.search);
const r = newQueryParams.get('returnMessage');
if (r) {
setReturnMessage(r)
}
}, []);
return (
<div className={styles.linktreePage}>
<div className={styles.dashboardContainer}>
<div className={styles.mainHeading}>{returnMessage}</div>
<div className={styles.subHeadingTransparent}>
Daftarkan kedaimu sekarang dan mulai gunakan semua fitur unggulan kami.
</div>
</div>
</div>
);
};
export default LinktreePage;

View File

@@ -315,27 +315,30 @@ const App = ({ forCafe = true, cafeId = -1,
if (otherCafes != null) {
console.log(otherCafes)
let updatedFullTexts;
if (otherCafes.length === 0) {
updatedFullTexts = [[user.roleId == 0 ? "Buat Voucher" : "Buat bisnis", 0]];
// Only include the role-specific option if user.roleId is 1
updatedFullTexts = user.roleId == 1 ? [["Buat Bisnis", 0]] : [];
setSelectedCafeId(-1);
} else if (otherCafes.length === 1) {
updatedFullTexts = [
[otherCafes[0].name || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].userId],
[user.roleId == 0 ? "Buat Voucher" : "Buat bisnis", -1]
[otherCafes[0].cafeIdentifyName || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].userId],
// Only add the "Buat Bisnis" option for user.roleId == 1
...(user.roleId == 1 ? [["Buat Bisnis", -1]] : [])
];
setSelectedCafeId(otherCafes[0].cafeId); // Get the cafeId (second part of the pair)
} else {
updatedFullTexts = [
["semua", 0], // First entry is "semua"
...otherCafes.map(item => [item.name || item.username, item.cafeId || item.userId]), // Map over cafes to get name and cafeId pairs
[user.roleId == 0 ? "Buat Voucher" : "Tambah Bisnis +", -1] // Add the "+" entry
...otherCafes.map(item => [item.cafeIdentifyName || item.username, item.cafeId || item.userId]), // Map over cafes to get name and cafeId pairs
// Only add "Buat Bisnis +" option for user.roleId == 1
...(user.roleId == 1 ? [["Buat Bisnis +", -1]] : [])
];
setSelectedCafeId(0);
}
setFullTexts(updatedFullTexts); // Set fullTexts with the original structure
// Set fullTextsVisible to an array of names only
setFullTextsVisible(updatedFullTexts.map(item => item[0])); // Extract just the names (first part of each pair)
@@ -400,7 +403,7 @@ const App = ({ forCafe = true, cafeId = -1,
setSelectedCafeId(selectedItem[1]); // Get the cafeId (second part of the pair)
}
let nextSelectedId = selectedItem[1]
if (selectedItem[1] == -1 && user.roleId == 0) setModal('create_coupon', {}, () => { setSelectedSwitch(1); setSelectedCafeId(unSelectedItem[1]); nextSelectedId=unSelectedItem[1] });
console.log(analytics)
if (user && user.roleId === 0 && analytics) {
// Filter the analytics items based on userId
@@ -448,9 +451,9 @@ const App = ({ forCafe = true, cafeId = -1,
} else {
setModal('loading');
const create = await createCafe(itemName);
if (!create) {
setModalStatus('failed');
}
setModal('message', {
returnMessage: create ? 'Berhasil membuat cafe' : 'Gagal membuat cafe'
});
// Add a 2-second delay before proceeding
await delay(2000);