From e0ef8d5023499033db418a49979451a1cbdfdcdb Mon Sep 17 00:00:00 2001 From: zadit <75159257+insvrgent@users.noreply.github.com> Date: Tue, 21 Jan 2025 07:41:46 +0700 Subject: [PATCH] ok --- src/App.js | 20 +-- src/components/Coupon.css | 56 +++++++++ src/components/Coupon.js | 28 +++++ src/components/Modal.js | 4 +- src/pages/CreateUserWithCoupon.js | 123 ++++++++++++++++++ src/pages/Dashboard.js | 2 +- src/pages/Join.js | 201 ++++++++++++++++++++++-------- 7 files changed, 371 insertions(+), 63 deletions(-) create mode 100644 src/components/Coupon.css create mode 100644 src/components/Coupon.js diff --git a/src/App.js b/src/App.js index 0a37693..b7f8f8d 100644 --- a/src/App.js +++ b/src/App.js @@ -413,27 +413,27 @@ function App() { setModalContent(content) }; - // Function to close the modal const closeModal = (closeTheseContent = []) => { if ( Array.isArray(closeTheseContent) && - (closeTheseContent.length === 0 || - closeTheseContent.includes(modalContent)) + (closeTheseContent.length === 0 || closeTheseContent.includes(modalContent)) ) { setIsModalOpen(false); setModalContent(null); document.body.style.overflow = "auto"; - + const queryParams = new URLSearchParams(location.search); - - // Remove the 'modal' parameter - queryParams.delete("modal"); - queryParams.delete("transactionId"); - - // Update the URL without the 'modal' parameter + + // Clear all query parameters + queryParams.keys() && [...queryParams.keys()].forEach(key => { + queryParams.delete(key); + }); + + // Update the URL without any query parameters navigate({ search: queryParams.toString() }, { replace: true }); } }; + // useEffect(() => { // const askNotificationPermission = async () => { diff --git a/src/components/Coupon.css b/src/components/Coupon.css new file mode 100644 index 0000000..c4514d8 --- /dev/null +++ b/src/components/Coupon.css @@ -0,0 +1,56 @@ +/* Coupon container */ +.coupon { + display: flex; + border: 2px solid #ccc; + height: 50%; + background-color: #f8f8f8; + border-radius: 8px; + font-family: Arial, sans-serif; + align-items: center; + } + + /* Left side (with the rotated code and dotted line) */ + .coupon-left { + width: 80px; + position: relative; + display: flex; + justify-content: center; + align-items: center; + border-right: 2px dotted #ccc; + height: 100%; + } + + .coupon-code { + writing-mode: vertical-rl; + font-size: 18px; + font-weight: bold; + color: #333; + margin: 0; + } + + .dotted-line { + position: absolute; + left: 0; + bottom: 10px; + width: 60px; + border-bottom: 2px dotted #ccc; + } + + /* Right side (coupon details) */ + .coupon-right { + padding: 10px; + flex-grow: 1; + } + .coupon-value { + font-size: clamp(18px, 3vw, 24px); /* Minimum 18px, 6vw (responsive), Maximum 24px */ + font-weight: bold; + color: #2c3e50; + text-align: left; + } + + .coupon-period, + .coupon-expiration { + font-size: 14px; + color: #7f8c8d; + } + \ No newline at end of file diff --git a/src/components/Coupon.js b/src/components/Coupon.js new file mode 100644 index 0000000..0619063 --- /dev/null +++ b/src/components/Coupon.js @@ -0,0 +1,28 @@ +import React from 'react'; +import './Coupon.css'; // Import a CSS file for styling + +const Coupon = ({ code, value, period, type, expiration }) => { + // Format the value based on type + const formattedValue = type === 'fixed' ? `Rp ${value}` : value != 0 ? `${value}%` : 'kupon berlangganan'; + + return ( +
+
+
{code == null ? '404' : code}
+
+
+
+

{code == null ? 'Kupon tidak ditemukan' : formattedValue}

+ {type && {type}} {/* Display type if provided */} +

+ {code == null ? '-' : value == 0 ? `Masa berlangganan ${period} minggu` : `Masa kupon ${period} minggu`} {/* Fixed string concatenation */} +

+

+ {expiration == null ? (code == null ? '-' : 'Tanpa kadaluarsa') : `Berlaku sampai: ${expiration}`} +

+
+
+ ); +}; + +export default Coupon; diff --git a/src/components/Modal.js b/src/components/Modal.js index a979504..bd0161e 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.js @@ -30,6 +30,7 @@ import { getImageUrl } from "../helpers/itemHelper.js"; import CreateCoupon from "../pages/CreateCoupon"; import CheckCoupon from "../pages/CheckCoupon"; +import CreateUserWithCoupon from "../pages/CreateUserWithCoupon"; const Modal = ({ user, shop, isOpen, onClose, modalContent, setModal, handleMoveToTransaction,welcomePageConfig }) => { @@ -60,7 +61,7 @@ const Modal = ({ user, shop, isOpen, onClose, modalContent, setModal, handleMove
{modalContent === "edit_account" && } - {modalContent === "join" && } + {modalContent === "join" && } {modalContent === "reset-password" && } {modalContent === "req_notification" && } {modalContent === "blocked_notification" && } @@ -103,6 +104,7 @@ const Modal = ({ user, shop, isOpen, onClose, modalContent, setModal, handleMove {modalContent === "create_coupon" && } {modalContent === "check_coupon" && } + {modalContent === "create_user" && }
); diff --git a/src/pages/CreateUserWithCoupon.js b/src/pages/CreateUserWithCoupon.js index e69de29..16e7ab5 100644 --- a/src/pages/CreateUserWithCoupon.js +++ b/src/pages/CreateUserWithCoupon.js @@ -0,0 +1,123 @@ +import React, { useState } from 'react'; +import styles from './Join.module.css'; // Import the module.css file +import API_BASE_URL from '../config.js'; + +function getAuthToken() { + return localStorage.getItem('auth'); +} + +const LinktreePage = ({ setModal }) => { + const [isUsingCoupon, setIsUsingCoupon] = useState(false); + const [couponCode, setCouponCode] = useState(''); + const [couponStatus, setCouponStatus] = useState(''); + const [couponDetails, setCouponDetails] = useState(null); + const [username, setUsername] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [retypePassword, setRetypePassword] = useState(''); + + const handleCheckCoupon = async (e) => { + e.preventDefault(); + try { + const response = await fetch(`${API_BASE_URL}/coupon/check/${couponCode}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${getAuthToken()}`, + }, + }); + + if (response.ok) { + const data = await response.json(); + setCouponStatus('Coupon is valid'); + setCouponDetails(data.coupon); + } else { + setCouponStatus('Coupon not found or expired'); + setCouponDetails(null); + } + } catch (error) { + setCouponStatus('Error checking coupon.'); + setCouponDetails(null); + } + }; + + const handleCreateUserWithCoupon = async (e) => { + e.preventDefault(); + + if (password !== retypePassword) { + setCouponStatus('Passwords do not match'); + return; + } + + try { + const response = await fetch(`${API_BASE_URL}/user/create-with-coupon`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${getAuthToken()}`, + }, + body: JSON.stringify({ + username, + email, + password, + couponCode, + }), + }); + + if (response.ok) { + const data = await response.json(); + setCouponStatus('User created successfully with coupon'); + setCouponDetails(null); + console.log(data); + } else { + const errorData = await response.json(); + setCouponStatus(errorData.message || 'Error creating user'); + } + } catch (error) { + setCouponStatus('Error creating user.'); + } + }; + + return ( +
+
+
Gunakan Kupon
+
+ setUsername(e.target.value)} + className={styles.usernameInput} + /> + setEmail(e.target.value)} + className={styles.usernameInput} + /> + setPassword(e.target.value)} + className={styles.usernameInput} + /> + setRetypePassword(e.target.value)} + className={styles.usernameInput} + /> + +
+
+
+ ); +}; + +export default LinktreePage; diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js index 75cae57..5d32462 100644 --- a/src/pages/Dashboard.js +++ b/src/pages/Dashboard.js @@ -946,7 +946,7 @@ const sortedMaterials = allMaterials.sort((a, b) => new Date(a.date) - new Date( onError={(e) => e.target.src = '/fallback-image.png'} /> - ©2025 KEDIRITECHNOPARK + ©2025 KEDIRITECHNOPARK.COM diff --git a/src/pages/Join.js b/src/pages/Join.js index c4e6647..52de2e8 100644 --- a/src/pages/Join.js +++ b/src/pages/Join.js @@ -1,63 +1,162 @@ -import React from 'react'; +import React, { useState } from 'react'; import styles from './Join.module.css'; // Import the module.css file +import API_BASE_URL from '../config.js'; + +import Coupon from '../components/Coupon'; + +function getAuthToken() { + return localStorage.getItem('auth'); +} + +const LinktreePage = ({ data, setModal }) => { + const [isUsingCoupon, setIsUsingCoupon] = useState(false); + const [couponCode, setCouponCode] = useState(''); + const [couponStatus, setCouponStatus] = useState(0); + const [couponDetails, setCouponDetails] = useState(null); + + const handleCheckCoupon = async (e) => { + e.preventDefault(); + try { + const response = await fetch(`${API_BASE_URL}/coupon/check/${couponCode}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${getAuthToken()}`, + }, + }); + + if (response.ok) { + const data = await response.json(); + setCouponStatus(200); + setCouponDetails(data.coupon); + } else { + setCouponStatus(404); + setCouponDetails(null); + } + } catch (error) { + setCouponStatus(404); + setCouponDetails(null); + } + }; -const LinktreePage = ({ data }) => { return (
+ {!isUsingCoupon ? ( +
+ {/* Main Heading */} +
Nikmati Kemudahan Mengelola Kafe
-
- {/* Main Heading */} -
- Nikmati Kemudahan Mengelola Kafe -
- - {/* Sub Heading */} -
- Daftarkan kedaimu sekarang dan mulai gunakan semua fitur unggulan kami. -
- - {/* Form Section */} -
- - - -
- - {/* Footer Links */} -
-
- - Pelajari lebih lanjut - - - Gunakan kupon - + {/* Sub Heading */} +
+ Daftarkan kedaimu sekarang dan mulai gunakan semua fitur unggulan kami.
-
- Linktree visual + + + + + + {/* Footer Links */} +
-
+ ) : ( +
+ {/* Main Heading */} +
Daftar Menggunakan Kupon
+ + {/* Sub Heading */} +
+ Kupon tidak hanya dapat digunakan untuk pembuatan akun penyewa, tetapi juga dapat digunakan untuk memperpanjang masa berlangganan. +
+ + {/* Coupon Check Section */} + {couponStatus == 0 ? +
+ + setCouponCode(e.target.value)} + /> + +
+ : + <> + + + +
+ + +
+ + } + {/* Footer Links */} + +
+ )}
); };