This commit is contained in:
2025-08-23 08:06:05 +00:00
parent 170d3aa432
commit b1ae4c5d82

View File

@@ -11,10 +11,60 @@ const ProductDetail = ({ willDo, setWillDo, subscriptions, product, requestLogin
const [showSubscriptionSelector, setShowSubscriptionSelector] = useState(false);
const [showNamingInput, setShowNamingInput] = useState(false);
const [customName, setCustomName] = useState('');
const navigate = useNavigate();
const [customName, setCustomName] = useState('');
const [status, setStatus] = useState('idle'); // 'idle' | 'checking' | 'available' | 'unavailable' | 'error'
const tokenCookie = document.cookie.split('; ').find(row => row.startsWith('token='));
const token = tokenCookie ? tokenCookie.split('=')[1] : '';
// Helper panggil API kamu (GET + token header)
async function checkProductAvailability(name, token) {
const url = `https://bot.kediritechnopark.com/webhook/store_production/check_p_availability?productId=${product.id}&name=${encodeURIComponent(name)}`;
const res = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/json',
},
});
if (!res.ok) throw new Error(`Server error ${res.status}`);
const data = await res.json(); // expected: { allowed: true|false }
return Boolean(data.allowed);
}
// Auto check saat user mengetik (debounce)
useEffect(() => {
if (product.unique_name == false) return;
const name = customName.trim();
if (!name) {
setStatus('idle');
return;
}
let cancelled = false;
setStatus('checking');
const t = setTimeout(async () => {
try {
const allowed = await checkProductAvailability(name, token);
if (cancelled) return;
setStatus(allowed ? 'available' : 'unavailable');
} catch (e) {
if (cancelled) return;
setStatus('error');
}
}, 500);
return () => {
cancelled = true;
clearTimeout(t);
};
}, [customName, token]);
const onCheckout = () => {
const tokenCookie = document.cookie.split('; ').find(row => row.startsWith('token='));
const token = tokenCookie ? tokenCookie.split('=')[1] : '';
@@ -29,7 +79,7 @@ const ProductDetail = ({ willDo, setWillDo, subscriptions, product, requestLogin
subscriptions.some(sub =>
String(sub.product_id) === String(product.id) || String(sub.product_parent_id) === String(product.id)
);
console.log(hasMatchingSubscription)
// ✅ Check subscription first
if (hasMatchingSubscription) {
const matching = subscriptions.filter(sub =>
@@ -86,7 +136,7 @@ const ProductDetail = ({ willDo, setWillDo, subscriptions, product, requestLogin
if (product.children && product.children.length > 0) {
// dont redirect yet → go to child selector
setShowSubscriptionSelector(false);
setShowSubscriptionSelector(false);
setShowNamingInput(false);
setShowChildSelector(true);
@@ -126,26 +176,38 @@ const ProductDetail = ({ willDo, setWillDo, subscriptions, product, requestLogin
};
useEffect(() => {
if (!product.executeCheckout && willDo === 'checkout') {
if (willDo === 'checkout') {
onCheckout();
}
else if (product.children && product.children.length > 0) {
setShowChildSelector(true);
}
else {
const tokenCookie = document.cookie.split('; ').find(row => row.startsWith('token='));
const token = tokenCookie ? tokenCookie.split('=')[1] : '';
const encodedName = encodeURIComponent(product.name);
const itemsParam = JSON.stringify([product.id]);
window.location.href = `https://checkout.kediritechnopark.com/?token=${token}&itemsId=${itemsParam}&set_name=${encodedName}&redirect_uri=https://kediritechnopark.com/products&redirect_failed=https://kediritechnopark.com`;
}
if (setWillDo) setWillDo('');
}, []);
const priceColor = product.price === 0 ? '#059669' : '#2563eb';
// Komponen kecil untuk menampilkan status teks
const StatusLine = () => {
if (status === 'idle') return null;
const map = {
checking: 'Memeriksa…',
available: 'Nama tersedia',
unavailable: 'Nama tidak tersedia',
error: 'Gagal memeriksa. Coba lagi.',
};
const color =
status === 'available'
? '#16a34a'
: status === 'unavailable'
? '#dc2626'
: status === 'checking'
? '#2563eb'
: '#6b7280';
return (
<div style={{ marginTop: 6, fontSize: 12, color }}>
{map[status]}
</div>
);
};
return (
<div className={styles.container}>
{/* Default view */}
@@ -239,8 +301,8 @@ const ProductDetail = ({ willDo, setWillDo, subscriptions, product, requestLogin
</div>
)}
{/* Naming input */}
{showNamingInput && (
<div className={styles.childSelector}>
<h5>Buat {product.name.split('%%%')[0]} Baru</h5>
@@ -249,18 +311,24 @@ const ProductDetail = ({ willDo, setWillDo, subscriptions, product, requestLogin
placeholder="Nama produk..."
className={styles.input}
value={customName}
onChange={(e) => setCustomName(e.target.value)}
style={{ width: '100%', padding: '8px', marginBottom: '16px', borderRadius: '10px' }}
onChange={(e) => {
const value = e.target.value.replace(/\s+/g, '-'); // Ganti spasi dengan -
setCustomName(value);
}}
style={{ width: '100%', padding: '8px', marginBottom: '8px', borderRadius: '10px' }}
/>
<div className={styles.buttonGroup}>
{product.unique_name && <StatusLine />}
<div className={styles.buttonGroup} style={{ marginTop: 12 }}>
<button className={styles.button} onClick={() => setShowNamingInput(false)}>
Kembali
</button>
<button
className={styles.button}
onClick={onFinalCheckoutNewProduct}
disabled={customName.trim() === ''}
disabled={customName.trim() === '' || status !== 'available'}
title={status !== 'available' ? 'Nama belum tersedia' : 'Lanjut'}
>
Lanjut
</button>