From 659e25dd7459f4cf336d0ca30c4e116a5de9d9b5 Mon Sep 17 00:00:00 2001 From: Vassshhh Date: Tue, 29 Jul 2025 11:52:38 +0700 Subject: [PATCH] ok --- src/App.css | 10 ++ src/Checkout.css | 327 ---------------------------------------- src/Checkout.js | 313 +++++++++----------------------------- src/Checkout.module.css | 183 ++++++++++++++++++++++ 4 files changed, 262 insertions(+), 571 deletions(-) delete mode 100644 src/Checkout.css create mode 100644 src/Checkout.module.css diff --git a/src/App.css b/src/App.css index 74b5e05..5a88201 100644 --- a/src/App.css +++ b/src/App.css @@ -1,5 +1,15 @@ .App { text-align: center; + + height: 100vh; + width: 100vw; + position: absolute; + top: 0; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + background-color: #dfdfdf; } .App-logo { diff --git a/src/Checkout.css b/src/Checkout.css deleted file mode 100644 index 09f3bd8..0000000 --- a/src/Checkout.css +++ /dev/null @@ -1,327 +0,0 @@ -.checkout-container { - display: flex; - flex-direction: row; - border-radius: 12px; - overflow: hidden; - box-shadow: 0 0 20px rgba(0,0,0,0.2); - max-width: 900px; - margin: 40px auto; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, - Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; -} - -.left-panel { - background-color: #2e2a4a; - color: white; - flex: 1; - padding: 40px 30px; - display: flex; - flex-direction: column; - gap: 20px; - position: relative; -} - -.back-arrow { - font-size: 20px; - cursor: pointer; - margin-bottom: 10px; - user-select: none; -} - -.brand-name { - font-weight: 600; - font-size: 14px; - opacity: 0.8; -} - -.product-name { - font-weight: 600; - font-size: 24px; -} - -.product-price { - font-weight: 600; - font-size: 32px; - margin-bottom: 20px; -} - -.product-image-container { - background-color: #b7c4f9; - border-radius: 8px; - padding: 20px; - display: flex; - justify-content: center; - align-items: center; - max-width: 300px; - max-height: 300px; -} - -.product-image-container img { - max-width: 100%; - max-height: 100%; - object-fit: contain; -} - -.right-panel { - background-color: white; - flex: 1; - padding: 40px 30px; - display: flex; - flex-direction: column; - gap: 20px; - color: #222; -} - -.apple-pay-button { - background-color: black; - color: white; - font-weight: 600; - font-size: 18px; - padding: 15px 0; - border: none; - border-radius: 6px; - cursor: pointer; - box-shadow: 0 4px 8px rgba(0,0,0,0.3); -} - -.separator { - display: flex; - align-items: center; - gap: 10px; - color: #999; - font-size: 14px; -} - -.separator .line { - flex: 1; - border: none; - border-top: 1px solid #ddd; -} - -.shipping-info h3, -.payment-methods h3 { - font-weight: 600; - margin-bottom: 10px; - font-size: 16px; -} - -.shipping-info input, -.shipping-info select { - width: 100%; - margin: 8px 0; - padding: 10px 12px; - border: 1px solid #ccc; - border-radius: 6px; - font-size: 14px; - color: #333; -} - -.manual-address { - font-size: 12px; - color: #666; - text-decoration: underline; - cursor: pointer; - margin-top: 4px; - display: inline-block; -} - -.payment-methods label { - display: flex; - align-items: center; - gap: 10px; - padding: 10px 12px; - border: 1px solid #ddd; - border-radius: 6px; - margin-bottom: 8px; - cursor: pointer; - font-size: 14px; - user-select: none; -} - -.payment-methods input[type="radio"] { - cursor: pointer; -} - -.payment-methods .icon { - display: inline-flex; - justify-content: center; - align-items: center; - width: 20px; - height: 20px; - font-weight: 700; - font-size: 14px; - border-radius: 4px; - background-color: #eee; - color: #555; -} - -.payment-methods .klarna { - background-color: #ff4f8b; - color: white; - font-weight: 700; - font-size: 14px; - padding: 0 4px; - border-radius: 4px; -} - -.payment-methods .ideal { - background-color: #f9a825; - color: white; - font-weight: 700; - font-size: 14px; - padding: 0 4px; - border-radius: 4px; -} - -.klarna-subtext { - font-size: 12px; - color: #999; - margin-left: 30px; - margin-top: -6px; -} - -.pay-button { - background-color: black; - color: white; - font-weight: 600; - font-size: 16px; - padding: 15px 0; - border: none; - border-radius: 6px; - cursor: pointer; - margin-top: 10px; -} - -.pay-button:hover { - background-color: #222; -} - -.footer { - font-size: 12px; - color: #999; - text-align: center; - margin-top: auto; - padding-top: 20px; - user-select: none; -} -/* Responsive styles */ -@media (max-width: 900px) { - .checkout-container { - flex-direction: column; - max-width: 100vw; - min-height: 100vh; - border-radius: 0; - box-shadow: none; - } - .left-panel, .right-panel { - padding: 32px 16px; - min-width: 0; - max-width: 100vw; - } - .left-panel { - border-radius: 0 0 12px 12px; - align-items: center; - text-align: center; - } - .right-panel { - border-radius: 12px 12px 0 0; - } - .product-image-container { - max-width: 220px; - max-height: 220px; - margin: 0 auto; - } -} - -@media (max-width: 600px) { - .checkout-container { - padding: 0; - } - .left-panel, .right-panel { - padding: 20px 6vw; - gap: 14px; - } - .product-name { - font-size: 18px; - } - .product-price { - font-size: 22px; - } - .apple-pay-button, .pay-button { - font-size: 15px; - padding: 12px 0; - } - .shipping-info input, - .shipping-info select { - font-size: 13px; - padding: 8px 10px; - } - .payment-methods label { - font-size: 13px; - padding: 8px 8px; - } - .footer { - font-size: 10px; - padding-top: 10px; - } -} -.checkmark-container { - display: flex; - flex-direction: column; - align-items: center; - animation: fadeIn 0.5s ease-in; -} - -.checkmark { - width: 100px; - height: 100px; - stroke-width: 2; - stroke: #4CAF50; - stroke-miterlimit: 10; - animation: scaleIn 0.3s ease-in-out; -} - -.checkmark-circle { - stroke-dasharray: 166; - stroke-dashoffset: 166; - stroke-width: 2; - stroke: #4CAF50; - fill: none; - animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; -} - -.checkmark-check { - transform-origin: 50% 50%; - stroke-dasharray: 48; - stroke-dashoffset: 48; - stroke: #4CAF50; - stroke-linecap: round; - stroke-linejoin: round; - animation: stroke 0.3s 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; -} - -@keyframes stroke { - to { - stroke-dashoffset: 0; - } -} - -@keyframes scaleIn { - 0% { - transform: scale(0); - } - 100% { - transform: scale(1); - } -} - -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} diff --git a/src/Checkout.js b/src/Checkout.js index 4a7fd22..e640288 100644 --- a/src/Checkout.js +++ b/src/Checkout.js @@ -1,252 +1,77 @@ -import React, { useState, useEffect } from 'react'; -import './Checkout.css'; -import { QRCodeCanvas } from 'qrcode.react'; +import React from 'react'; +import styles from './Checkout.module.css'; -const Checkout = ({ socketId, transactionSuccess }) => { - const [qrisData, setQrisData] = useState(null); // QRIS string - const [value, setValue] = useState(null); // QRIS value (optional) - const [products, setProducts] = useState([]); // Produk dari itemsId - const [loadingProducts, setLoadingProducts] = useState(false); - - // Helper get cookie value - const getCookie = (name) => { - const value = `; ${document.cookie}`; - const parts = value.split(`; ${name}=`); - if (parts.length === 2) return parts.pop().split(';').shift(); - return null; - }; - - useEffect(() => { - // document.cookie = "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoia2VkaXJpdGVjaG5vcGFyayIsImVtYWlsIjoiIiwicHJvZmlsZV9kYXRhIjp7fSwic3Vic2NyaXB0aW9ucyI6e30sImlhdCI6MTc1MzU4MDQ2N30.9TjxL5bV5i3zTAU_Rl7_p5cd76Fn6-O0elRtJw570jY; path=/; max-age=${7 * 24 * 60 * 60}"; - // document.cookie = "itemsId=" + JSON.stringify([1, 2]) + "; path=/; max-age=${7 * 24 * 60 * 60}"; - - - const fetchUserData = async () => { - const token = getCookie('token'); - - if (token) { - try { - const userDataResponse = await fetch('https://bot.kediritechnopark.com/webhook/user-dev/data', { - headers: { - 'Authorization': `Bearer ${token}`, - }, - }); - if (userDataResponse.ok) { - const userData = await userDataResponse.json(); - document.cookie = `token=${userData[0]?.token}; path=/; max-age=${7 * 24 * 60 * 60}`; - console.log('User data:', userData); - // Store user data in state or context if needed - } else { - console.error('Failed to fetch user data:', userDataResponse.status); - // Handle error fetching user data, e.g., logout - document.cookie = 'token=; path=/; max-age=0'; - } - } catch (error) { - console.error('Error fetching user data:', error); - // Handle network or other errors, e.g., logout - document.cookie = 'token=; path=/; max-age=0'; - } - } - }; - - - const fetchProducts = async () => { - const itemsIdRaw = getCookie('itemsId'); - if (!itemsIdRaw) return; - - let itemsId = []; - try { - itemsId = JSON.parse(itemsIdRaw); - } catch (e) { - console.error('Gagal parse itemsId dari cookie:', e); - return; - } - - if (itemsId.length === 0) return; - - setLoadingProducts(true); - - try { - const token = getCookie('token'); - if (!token) { - console.warn('Token tidak ditemukan'); - return; - } - - const params = new URLSearchParams(); - itemsId.forEach(id => params.append('itemsId', id)); - - const res = await fetch(`https://bot.kediritechnopark.com/webhook/store-dev/products`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: params.toString(), - }); - - if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); - - const data = await res.json(); - setProducts(data); - } catch (error) { - console.error('Error fetching products:', error); - } finally { - setLoadingProducts(false); - } - }; - - fetchProducts(); - fetchUserData(); - - }, []); - - - const handlePay = async (e) => { - e.preventDefault(); - - let itemsIdRaw = getCookie('itemsId'); - let token = getCookie('token'); - - if (!itemsIdRaw || !token) { - alert("Token atau itemsId tidak ditemukan di cookies."); - return; - } - - let itemsId = []; - try { - itemsId = JSON.parse(itemsIdRaw); - } catch (e) { - alert("Gagal parsing itemsId."); - return; - } - - try { - const params = new URLSearchParams(); - itemsId.forEach(id => params.append('itemsId', id)); - params.append('socketId', socketId); - - - const response = await fetch('https://bot.kediritechnopark.com/webhook/store-dev/pay', { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Authorization': `Bearer ${token}` - }, - body: params.toString() - }); - - - const result = await response.json(); - - if (response.ok && result.qris_dynamic) { - setQrisData(result.qris_dynamic); - setValue(result.total_price); - } else { - alert(`Gagal mendapatkan QRIS: ${result?.error || 'Unknown error'}`); - } - - } catch (error) { - console.error('Network error:', error); - alert("Terjadi kesalahan jaringan."); - } - }; - - return ( -
-
-
-
Powdur
-
Pure kit
-
$65.00
-
- Powdur Product +const Checkout = () => { + return ( +
+
+ {/* Product List */} +
+

Your Cart

+
    +
  • +
    + Product 1 +
    +

    Pure Kit

    +

    $65.00

    -
    -
    - {!qrisData ? ( - <> -

    Cart Items

    - {loadingProducts ? ( -

    Loading products...

    - ) : products.length === 0 ? ( -

    No products found

    - ) : ( -
      - {products.map((product) => ( -
    • - {product.name} - ${product.price} -
    • - ))} -
    - )} +
    + +
  • -
    -

    Shipping information

    - - - - - Enter address manually - -
    -

    Payment method

    - - - - -
    - - -
    - - ) : ( - <> - {transactionSuccess ? ( -
    -
    - - - - -

    Payment Successful!

    -
    -
    - ) : ( - <> -
    -

    Scan QRIS to Pay

    - -

    {qrisData}

    -
    -

    {value}

    - - )} - - - )} - -
    - Powered by stripe | Terms | Privacy +
  • +
    + Product 2 +
    +

    Energy Drink

    +

    $25.00

    -
    +
  • + + +
- ); + + {/* Checkout form */} +
+
+

Note / Request

+
+ +
+ +
+ + {/* Footer */} +
+ Powered by Stripe •{' '} + Terms •{' '} + Privacy Policy +
+
+
+
+ ); }; export default Checkout; diff --git a/src/Checkout.module.css b/src/Checkout.module.css new file mode 100644 index 0000000..42b54d7 --- /dev/null +++ b/src/Checkout.module.css @@ -0,0 +1,183 @@ +.checkoutCard { + border-radius: 1rem; /* rounded-2xl */ + box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1); + overflow: hidden; + display: flex; + flex-direction: column; /* default mobile: vertical stack */ + max-width: 28rem; /* max-w-md */ + margin-left: auto; + margin-right: auto; + flex-grow: 1; /* agar bisa melebar dalam container flex */ +} + +.cartSection, .checkoutSection { + flex: 1; /* agar keduanya bisa melebar seimbang */ +} + +.cartSection { + padding: 1.5rem 1.5rem; /* p-6 */ + background-color: #ececec; /* gray-50 */ + border-bottom: 1px solid #F3F4F6; /* border-gray-100 */ +} + +.cartTitle { + font-size: 1.25rem; /* text-xl */ + font-weight: 600; /* font-semibold */ + color: #1F2937; /* gray-800 */ + margin-bottom: 1rem; +} + +.cartList { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 1rem; /* space-y-4 */ +} + +.cartItem { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; +} + +.itemDetails { + display: flex; + align-items: center; + gap: 1rem; +} + +.productImage { + width: 3.5rem; /* 14 */ + height: 3.5rem; + border-radius: 0.5rem; + object-fit: cover; +} + +.itemText { + font-weight: 500; + color: #1F2937; + margin: 0; +} + +.itemPrice { + font-size: 0.875rem; /* text-sm */ + color: #6B7280; /* gray-500 */ + margin: 0; +} + +.removeBtn { + font-weight: 700; + font-size: 1.25rem; + color: #EF4444; /* red-500 */ + background: none; + border: none; + cursor: pointer; + transition: color 0.2s ease-in-out; +} + +.removeBtn:hover { + color: #B91C1C; /* red-700 */ +} + +.checkoutSection { + padding: 2rem; /* p-8 */ + display: flex; + flex-direction: column; + justify-content: space-between; + flex-grow: 1; + background-color: white; +} + +.checkoutTitle { + font-size: 1.25rem; + font-weight: 600; + color: #1F2937; + margin-bottom: 1.5rem; +} + +.inputNote { + width: 100%; /* tetap full width agar input memenuhi container */ + padding: 0.75rem 1rem; + border: 1px solid #D1D5DB; /* gray-300 */ + border-radius: 0.5rem; + font-size: 1rem; + transition: box-shadow 0.2s ease, border-color 0.2s ease; + box-sizing: border-box; /* pastikan padding masuk ke width */ +} + +.inputNote:focus { + outline: none; + border-color: #3B82F6; /* blue-500 */ + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5); +} + +.paymentBtn { + width: 100%; /* tombol harus full lebar */ + background-color: #2563EB; /* blue-600 */ + color: white; + font-weight: 700; + padding: 0.75rem 0; + border-radius: 0.5rem; + font-size: 1.125rem; /* text-lg */ + cursor: pointer; + border: none; + box-shadow: 0 4px 6px rgba(37, 99, 235, 0.5); + transition: background-color 0.2s ease; +} + +.paymentBtn:hover { + background-color: #1D4ED8; /* blue-700 */ +} + +.footerText { + font-size: 0.75rem; /* text-xs */ + color: #6B7280; /* gray-500 */ + text-align: center; + margin-top: 2rem; +} + +.footerLink { + display: inline-block; + padding: 0.25rem 0.5rem; + border-radius: 0.375rem; + color: inherit; + text-decoration: none; + transition: background-color 0.2s ease; +} + +.footerLink:hover { + background-color: #E5E7EB; /* gray-200 */ +} + +.footerHighlight { + font-weight: 600; + color: #374151; /* gray-700 */ +} + +/* Responsive layout for desktop */ +@media (min-width: 641px) { + .checkoutCard { + flex-direction: row; /* dua kolom berdampingan */ + max-width: 64rem; /* lebar container desktop */ + } + + .cartSection { + border-bottom: none; /* hilangkan border bawah */ + border-right: 1px solid #F3F4F6; /* border kanan */ + padding: 2rem; + } + + .checkoutSection { + padding: 2rem 3rem; + } +} + +/* Responsive layout for small screens */ +@media (max-width: 640px) { + .checkoutCard { + max-width: 100%; + } +}