Ilo/design/Ilo Checkout.html
2026-05-02 20:01:30 +03:30

609 lines
31 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>پرداخت — ایلو</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css" />
<style>
body { background: var(--bg); }
.nav { background: var(--surface); border-bottom: 1px solid var(--line); }
.nav-inner { max-width: 1100px; margin: 0 auto; padding: 14px 24px; display: flex; align-items: center; gap: 24px; }
.nav-brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; text-decoration: none; color: inherit; }
.nav-mark { width: 30px; height: 30px; border-radius: 8px; background: linear-gradient(140deg, var(--accent), var(--accent-2)); color: white; font-family: var(--font-en); font-weight: 700; font-size: 12px; display: grid; place-items: center; }
.secure-pill { margin-inline-start: auto; display: flex; align-items: center; gap: 6px; padding: 6px 12px; background: oklch(0.94 0.05 155); color: oklch(0.45 0.10 155); border-radius: 999px; font-size: 12px; font-weight: 500; }
.checkout-stepper { max-width: 1100px; margin: 32px auto; padding: 0 24px; display: flex; align-items: center; gap: 8px; }
.cs-step { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.cs-num { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 600; background: var(--surface-2); color: var(--ink-3); border: 1.5px solid var(--line); font-family: var(--font-num); }
.cs-step.active .cs-num { background: var(--accent); color: white; border-color: transparent; }
.cs-step.done .cs-num { background: var(--accent-soft); color: var(--accent-ink); border-color: transparent; }
.cs-label { font-size: 13px; color: var(--ink-3); }
.cs-step.active .cs-label, .cs-step.done .cs-label { color: var(--ink); font-weight: 600; }
.cs-line { flex: 1; height: 2px; background: var(--line); border-radius: 999px; }
.cs-line.done { background: var(--accent); }
.checkout-grid {
max-width: 1100px; margin: 0 auto;
display: grid; grid-template-columns: 1.5fr 1fr; gap: 32px;
padding: 0 24px 56px;
align-items: flex-start;
}
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 28px; }
.panel h2 { margin: 0 0 6px; font-size: 20px; }
.panel .sub { margin: 0 0 24px; font-size: 13px; color: var(--ink-3); }
/* method cards */
.method-grid { display: grid; gap: 10px; }
.method-card {
border: 1.5px solid var(--line);
background: var(--surface);
border-radius: 12px;
padding: 14px 18px;
display: flex; align-items: center; gap: 14px;
cursor: pointer;
transition: all .15s;
}
.method-card:hover { border-color: var(--ink-4); }
.method-card.selected {
border-color: var(--accent);
background: color-mix(in oklch, var(--accent-soft) 60%, var(--surface));
}
.method-radio {
width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid var(--line);
flex-shrink: 0; display: grid; place-items: center;
}
.method-card.selected .method-radio { border-color: var(--accent); }
.method-card.selected .method-radio::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--accent); }
.method-logo {
width: 44px; height: 44px; border-radius: 10px;
background: var(--surface-2);
display: grid; place-items: center;
flex-shrink: 0;
}
.method-meta { flex: 1; }
.method-title { font-size: 14.5px; font-weight: 600; }
.method-desc { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.method-extra { font-size: 11.5px; color: var(--ink-3); }
/* card form */
.field-stack { display: flex; flex-direction: column; gap: 14px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.field-lbl { font-size: 12.5px; font-weight: 500; color: var(--ink-2); margin-bottom: 6px; display: flex; justify-content: space-between; }
.text-input {
width: 100%; box-sizing: border-box;
border: 1px solid var(--line);
background: var(--surface);
border-radius: 10px;
padding: 12px 14px;
font: inherit; font-size: 14px; color: var(--ink);
outline: 0;
transition: border-color .15s, box-shadow .15s;
direction: ltr;
text-align: start;
font-family: var(--font-num);
}
.text-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.pan-wrap { position: relative; }
.pan-wrap .brand-mark {
position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
font-size: 11px; padding: 3px 10px; border-radius: 6px;
background: var(--surface-2); color: var(--ink-3); font-weight: 600;
}
/* coupon */
.coupon-row { display: flex; gap: 8px; }
.coupon-row .text-input { flex: 1; direction: rtl; font-family: inherit; }
/* summary card */
.summary { position: sticky; top: 24px; }
.summary-h { padding: 18px 22px 14px; border-bottom: 1px solid var(--line-soft); }
.course-row { display: flex; gap: 12px; padding: 14px 22px; border-bottom: 1px solid var(--line-soft); }
.course-thumb { width: 64px; height: 48px; border-radius: 8px; background: oklch(0.78 0.12 40); flex-shrink: 0; }
.summary-body { padding: 18px 22px; display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.sb-row { display: flex; justify-content: space-between; }
.sb-row .num { font-family: var(--font-num); }
.sb-row.muted { color: var(--ink-3); }
.sb-row.total { padding-top: 14px; border-top: 1px solid var(--line); font-size: 15px; font-weight: 700; margin-top: 6px; }
.sb-row.discount { color: oklch(0.55 0.13 155); }
.save-banner {
margin: 0 22px;
padding: 10px 12px;
background: oklch(0.94 0.05 155);
color: oklch(0.45 0.10 155);
border-radius: 8px;
font-size: 12px;
display: flex; align-items: center; gap: 8px;
}
.pay-btn {
width: calc(100% - 44px);
margin: 14px 22px 18px;
padding: 14px;
justify-content: center;
font-size: 14px; font-weight: 600;
}
.trust-row {
padding: 12px 22px 18px;
display: flex; gap: 8px; flex-wrap: wrap;
border-top: 1px solid var(--line-soft);
color: var(--ink-3);
font-size: 11.5px;
}
/* otp & processing & success states */
.center-box {
max-width: 480px; margin: 56px auto;
padding: 0 24px;
}
.panel-center {
background: var(--surface);
border: 1px solid var(--line);
border-radius: 14px;
padding: 40px 32px;
text-align: center;
}
.otp-row { display: flex; gap: 8px; direction: ltr; justify-content: center; margin: 24px 0 8px; }
.otp-cell {
width: 52px; height: 60px;
border: 1.5px solid var(--line);
border-radius: 10px;
font-size: 22px; font-weight: 700;
text-align: center; outline: none;
font-family: var(--font-num);
background: var(--surface);
}
.otp-cell:focus, .otp-cell.filled { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.spinner {
width: 56px; height: 56px;
border-radius: 50%;
border: 3px solid var(--line);
border-top-color: var(--accent);
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin { to { transform: rotate(360deg); } }
.success-ic {
width: 80px; height: 80px;
border-radius: 50%;
background: oklch(0.94 0.05 155);
color: oklch(0.55 0.14 155);
margin: 0 auto 24px;
display: grid; place-items: center;
animation: pop .4s cubic-bezier(.18,.9,.32,1.4);
}
@keyframes pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }
@media (max-width: 900px) {
.checkout-grid { grid-template-columns: 1fr; }
.summary { position: static; }
}
</style>
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel" src="icons.jsx"></script>
<script type="text/babel" src="student-data.jsx"></script>
<script type="text/babel">
const fa = (s) => String(s).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d]);
const PAYMENT_METHODS = [
{ id: 'zarinpal', title: 'درگاه پرداخت زرین‌پال', desc: 'کارت بانکی · سریع‌ترین روش', logo: 'ZP', logoBg: 'oklch(0.78 0.16 30)', recommended: true },
{ id: 'idpay', title: 'درگاه آی‌دی‌پی', desc: 'کارت بانکی · بدون کارمزد', logo: 'IDP', logoBg: 'oklch(0.74 0.14 145)' },
{ id: 'wallet', title: 'کیف پول ایلو', desc: 'موجودی فعلی: ۱۲۰٬۰۰۰ تومان', logo: 'IL', logoBg: 'var(--accent)', extra: 'برای پرداخت کامل، ۲٬۳۳۰٬۰۰۰ تومان دیگر نیاز است' },
{ id: 'install', title: 'پرداخت اقساطی (اسنپ‌پی)', desc: '۴ قسط · بدون کارمزد', logo: 'SP', logoBg: 'oklch(0.74 0.14 320)' },
];
const PROMO_CODES = { 'WELCOME10': 0.10, 'STUDENT': 0.15 };
function OtpInput({ value, onChange, autoFocus }) {
const refs = React.useRef([]);
React.useEffect(() => { if (autoFocus) refs.current[0]?.focus(); }, [autoFocus]);
const handle = (i, v) => {
const digit = v.replace(/\D/g, '').slice(-1);
const next = (value + '').padEnd(5, ' ').split('');
next[i] = digit || ' ';
onChange(next.join('').replace(/ /g, ''));
if (digit && i < 4) refs.current[i + 1]?.focus();
};
const handleKey = (i, e) => {
if (e.key === 'Backspace' && !value[i] && i > 0) refs.current[i - 1]?.focus();
};
return (
<div className="otp-row">
{[0,1,2,3,4].map(i => (
<input key={i} ref={el => refs.current[i] = el}
className={`otp-cell ${value[i] ? 'filled' : ''}`}
inputMode="numeric" maxLength={1}
value={value[i] || ''}
onChange={e => handle(i, e.target.value)}
onKeyDown={e => handleKey(i, e)} />
))}
</div>
);
}
function App() {
const c = window.STUDENT_DATA.COURSE_DETAIL;
const [step, setStep] = React.useState('cart'); // cart, payment, otp, processing, success
const [method, setMethod] = React.useState('zarinpal');
const [pan, setPan] = React.useState('');
const [exp, setExp] = React.useState('');
const [cvv, setCvv] = React.useState('');
const [cvv2, setCvv2] = React.useState('');
const [coupon, setCoupon] = React.useState('');
const [appliedDiscount, setAppliedDiscount] = React.useState(0);
const [otp, setOtp] = React.useState('');
const subtotal = 3200000;
const courseDiscount = 750000;
const tax = 0;
const couponAmount = Math.round((subtotal - courseDiscount) * appliedDiscount);
const total = subtotal - courseDiscount - couponAmount + tax;
const totalFa = total.toLocaleString('fa-IR');
const applyCoupon = () => {
const code = coupon.trim().toUpperCase();
if (PROMO_CODES[code]) setAppliedDiscount(PROMO_CODES[code]);
else setAppliedDiscount(-1); // mark error
};
const submitPayment = () => {
setStep('otp');
};
const verifyOtp = () => {
setStep('processing');
setTimeout(() => setStep('success'), 2200);
};
const stepIdx = { cart: 0, payment: 1, otp: 1, processing: 2, success: 2 }[step];
return (
<>
<nav className="nav">
<div className="nav-inner">
<a className="nav-brand" href="Ilo Landing.html">
<div className="nav-mark">il</div>
ایلو
</a>
<span style={{ fontSize: 13, color: 'var(--ink-3)' }}>پرداخت امن</span>
<span className="secure-pill">
<Icon name="check" className="ic-sm" />
اتصال SSL · رمزنگاری ۲۵۶ بیت
</span>
</div>
</nav>
{step !== 'success' && step !== 'processing' && (
<div className="checkout-stepper">
{[['cart','سبد خرید'],['payment','پرداخت'],['success','تکمیل']].map(([k, l], i) => (
<React.Fragment key={k}>
<div className={`cs-step ${stepIdx === i ? 'active' : stepIdx > i ? 'done' : ''}`}>
<div className="cs-num">{stepIdx > i ? <Icon name="check" className="ic-sm" /> : fa(i+1)}</div>
<span className="cs-label">{l}</span>
</div>
{i < 2 && <div className={`cs-line ${stepIdx > i ? 'done' : ''}`} />}
</React.Fragment>
))}
</div>
)}
{/* CART STEP */}
{step === 'cart' && (
<div className="checkout-grid">
<div className="panel">
<h2>سبد خرید</h2>
<p className="sub">۱ دوره · بازنگری و تأیید</p>
<div style={{ display: 'flex', gap: 14, padding: '16px', border: '1px solid var(--line)', borderRadius: 12, marginBottom: 24 }}>
<div style={{ width: 96, height: 64, borderRadius: 10, background: c.color, flexShrink: 0, display: 'grid', placeItems: 'center', color: 'white' }}>
<Icon name="play" />
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14.5, fontWeight: 600 }}>{c.title}</div>
<div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>توسط {c.instructor.name}</div>
<div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 6, display: 'flex', gap: 12 }}>
<span><Icon name="clock" className="ic-sm" /> {fa(c.hours)} ساعت</span>
<span><Icon name="video" className="ic-sm" /> {fa(c.lessons)} درس</span>
</div>
</div>
<div style={{ textAlign: 'end' }}>
<div style={{ fontSize: 11, color: 'var(--ink-3)', textDecoration: 'line-through', fontFamily: 'var(--font-num)' }}>{c.oldPrice}</div>
<div style={{ fontSize: 16, fontWeight: 700, fontFamily: 'var(--font-num)' }}>{c.price}</div>
</div>
</div>
<div style={{ marginBottom: 18 }}>
<label className="field-lbl">کد تخفیف</label>
<div className="coupon-row">
<input className="text-input" placeholder="مثلاً: WELCOME10" value={coupon}
onChange={e => { setCoupon(e.target.value); setAppliedDiscount(0); }} />
<button className="btn primary" onClick={applyCoupon} disabled={!coupon.trim()}>اعمال</button>
</div>
{appliedDiscount > 0 && (
<div style={{ marginTop: 8, fontSize: 12, color: 'oklch(0.55 0.13 155)' }}>
<Icon name="check" className="ic-sm" /> کد «{coupon.toUpperCase()}» اعمال شد · {fa(Math.round(appliedDiscount * 100))}٪ تخفیف بیشتر
</div>
)}
{appliedDiscount === -1 && (
<div style={{ marginTop: 8, fontSize: 12, color: 'oklch(0.55 0.18 25)' }}>
کد تخفیف نامعتبر است
</div>
)}
</div>
<div style={{ background: 'var(--surface-2)', borderRadius: 10, padding: 14, fontSize: 12.5, color: 'var(--ink-2)', display: 'flex', gap: 10 }}>
<Icon name="check" className="ic-sm" style={{ color: 'oklch(0.55 0.13 155)' }} />
<span>گارانتی بازگشت ۷ روزهی وجه اگر از دوره راضی نبودی، تمام مبلغ پرداختی به حسابت برمیگرده.</span>
</div>
</div>
<Summary {...{ c, subtotal, courseDiscount, couponAmount, total, totalFa, appliedDiscount, coupon }}
cta="ادامه به پرداخت" onContinue={() => setStep('payment')} />
</div>
)}
{/* PAYMENT STEP */}
{step === 'payment' && (
<div className="checkout-grid">
<div>
<div className="panel" style={{ marginBottom: 16 }}>
<h2>روش پرداخت</h2>
<p className="sub">یک روش پرداخت انتخاب کن</p>
<div className="method-grid">
{PAYMENT_METHODS.map(m => (
<div key={m.id} className={`method-card ${method === m.id ? 'selected' : ''}`}
onClick={() => setMethod(m.id)}>
<div className="method-radio" />
<div className="method-logo" style={{ background: m.logoBg, color: 'white', fontWeight: 700, fontSize: 12 }}>{m.logo}</div>
<div className="method-meta">
<div className="method-title">{m.title} {m.recommended && <span className="pill accent" style={{ fontSize: 10, marginInlineStart: 6 }}>پیشنهادی</span>}</div>
<div className="method-desc">{m.desc}</div>
{m.extra && <div className="method-extra" style={{ marginTop: 4 }}>{m.extra}</div>}
</div>
</div>
))}
</div>
</div>
{/* card form (zarinpal/idpay) */}
{(method === 'zarinpal' || method === 'idpay') && (
<div className="panel">
<h2>اطلاعات کارت</h2>
<p className="sub">اطلاعات کارت روی درگاه بانک وارد میشود این صفحه فقط برای پیشنمایش است.</p>
<div className="field-stack">
<div>
<label className="field-lbl">
<span>شماره کارت</span>
<span style={{ color: 'var(--ink-3)' }}>۱۶ رقم</span>
</label>
<div className="pan-wrap">
<input className="text-input" style={{ paddingInlineStart: 60 }}
placeholder="۶۰۳۷ ۹۹۷۰ ۱۲۳۴ ۵۶۷۸"
value={pan}
maxLength={19}
onChange={e => {
const digits = e.target.value.replace(/\D/g, '').slice(0, 16);
setPan(digits.replace(/(.{4})/g, '$1 ').trim());
}} />
<span className="brand-mark">{pan.startsWith('6037') ? 'ملی' : pan.startsWith('6219') ? 'سامان' : 'BANK'}</span>
</div>
</div>
<div className="form-row">
<div>
<label className="field-lbl">تاریخ انقضا</label>
<input className="text-input" placeholder="MM / YY" value={exp}
onChange={e => {
let v = e.target.value.replace(/\D/g, '').slice(0, 4);
if (v.length > 2) v = v.slice(0, 2) + ' / ' + v.slice(2);
setExp(v);
}} />
</div>
<div>
<label className="field-lbl">CVV2</label>
<input className="text-input" placeholder="۱۲۳" value={cvv}
maxLength={4}
onChange={e => setCvv(e.target.value.replace(/\D/g, '').slice(0, 4))} />
</div>
</div>
<div>
<label className="field-lbl">رمز دوم پویا</label>
<input className="text-input" placeholder="رمز ۶ یا ۸ رقمی" value={cvv2}
onChange={e => setCvv2(e.target.value.replace(/\D/g, '').slice(0, 8))} />
<div style={{ marginTop: 6, fontSize: 11.5, color: 'var(--ink-3)' }}>
رمز دوم پویا را از اپ بانک یا با کد دستوری <b className="num" dir="ltr">*۷۲۰*</b> دریافت کن.
</div>
</div>
</div>
</div>
)}
{method === 'wallet' && (
<div className="panel">
<div style={{ padding: '24px', textAlign: 'center' }}>
<Icon name="store" style={{ width: 40, height: 40, color: 'var(--accent)', margin: '0 auto 12px', display: 'block' }} />
<div style={{ fontSize: 16, fontWeight: 700 }}>پرداخت با کیف پول ایلو</div>
<div style={{ fontSize: 13, color: 'var(--ink-3)', marginTop: 8 }}>موجودی شما: <b className="num">۱۲۰٬۰۰۰</b> تومان</div>
<div style={{ fontSize: 13, color: 'oklch(0.55 0.18 25)', marginTop: 4 }}>برای پرداخت کامل، نیاز به <b className="num">۲٬۳۳۰٬۰۰۰</b> تومان شارژ بیشتر است</div>
<button className="btn primary" style={{ marginTop: 16 }}>شارژ کیف پول</button>
</div>
</div>
)}
{method === 'install' && (
<div className="panel">
<h2>پرداخت اقساطی</h2>
<p className="sub">مبلغ کل به ۴ قسط مساوی تقسیم میشود</p>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
{[1,2,3,4].map(n => (
<div key={n} style={{ display: 'flex', justifyContent: 'space-between', padding: '12px 16px', background: n === 1 ? 'var(--accent-soft)' : 'var(--surface-2)', borderRadius: 10, fontSize: 13 }}>
<span>قسط {fa(n)} {n === 1 ? '· امروز' : `· ${fa(n-1)} ماه دیگر`}</span>
<b className="num">{Math.round(total/4).toLocaleString('fa-IR')} تومان</b>
</div>
))}
</div>
</div>
)}
</div>
<Summary {...{ c, subtotal, courseDiscount, couponAmount, total, totalFa, appliedDiscount, coupon }}
cta={`پرداخت ${totalFa} تومان`} onContinue={submitPayment} />
</div>
)}
{/* OTP STEP */}
{step === 'otp' && (
<div className="center-box">
<div className="panel-center">
<div style={{ width: 56, height: 56, borderRadius: 14, background: 'var(--accent-soft)', color: 'var(--accent)', display: 'grid', placeItems: 'center', margin: '0 auto 20px' }}>
<Icon name="phone" />
</div>
<h2 style={{ margin: '0 0 8px', fontSize: 20 }}>تأیید پرداخت</h2>
<p style={{ margin: 0, fontSize: 13, color: 'var(--ink-3)', lineHeight: 1.7 }}>
کد ۵ رقمی به شماره <b className="num" dir="ltr">+۹۸ ۹۱۲...۴۵۶۷</b> ارسال شد.<br/>
این کد را برای تأیید تراکنش وارد کنید.
</p>
<OtpInput value={otp} onChange={setOtp} autoFocus />
<div style={{ fontSize: 12, color: 'var(--ink-3)', marginBottom: 20 }}>کد رو دریافت نکردی؟ <a style={{ color: 'var(--accent)', cursor: 'pointer' }}>ارسال مجدد</a></div>
<button className="btn primary full" disabled={otp.length !== 5}
style={{ width: '100%', justifyContent: 'center', padding: '12px', opacity: otp.length === 5 ? 1 : 0.5, cursor: otp.length === 5 ? 'pointer' : 'not-allowed' }}
onClick={verifyOtp}>
تأیید و پرداخت
</button>
</div>
</div>
)}
{/* PROCESSING */}
{step === 'processing' && (
<div className="center-box">
<div className="panel-center">
<div className="spinner" />
<h2 style={{ margin: '0 0 8px', fontSize: 20 }}>در حال پردازش پرداخت</h2>
<p style={{ margin: 0, fontSize: 13, color: 'var(--ink-3)' }}>لطفاً صفحه را نبند یا رفرش نکن</p>
</div>
</div>
)}
{/* SUCCESS */}
{step === 'success' && (
<div className="center-box">
<div className="panel-center">
<div className="success-ic">
<Icon name="check" style={{ width: 36, height: 36, strokeWidth: 2.5 }} />
</div>
<h2 style={{ margin: '0 0 8px', fontSize: 24 }}>تبریک! خریدت موفق بود 🎉</h2>
<p style={{ margin: '0 0 24px', fontSize: 14, color: 'var(--ink-2)' }}>
از این لحظه به محتوای دوره <b>«{c.title}»</b> دسترسی داری.
</p>
<div style={{ background: 'var(--surface-2)', borderRadius: 12, padding: 16, marginBottom: 24, textAlign: 'start' }}>
<div className="sb-row muted" style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12 }}>
<span>کد پیگیری تراکنش</span>
<b className="num" dir="ltr" style={{ color: 'var(--ink)' }}>IL-2024-AB7392X</b>
</div>
<div className="sb-row muted" style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, marginTop: 6 }}>
<span>مبلغ پرداختی</span>
<b className="num" style={{ color: 'var(--ink)' }}>{totalFa} تومان</b>
</div>
<div className="sb-row muted" style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, marginTop: 6 }}>
<span>روش پرداخت</span>
<b style={{ color: 'var(--ink)' }}>{PAYMENT_METHODS.find(m => m.id === method)?.title}</b>
</div>
</div>
<div style={{ display: 'flex', gap: 8 }}>
<a className="btn primary" href="Ilo Student.html" style={{ flex: 1, justifyContent: 'center', padding: '12px', textDecoration: 'none' }}>
شروع یادگیری
<Icon name="chevron" className="ic-sm flipx" />
</a>
<a className="btn" href="Ilo Landing.html" style={{ justifyContent: 'center', padding: '12px', textDecoration: 'none' }}>
دانلود رسید
</a>
</div>
<div style={{ marginTop: 24, fontSize: 12, color: 'var(--ink-3)' }}>
رسید خرید به ایمیل و پیامک شما ارسال شد.
</div>
</div>
</div>
)}
</>
);
}
function Summary({ c, subtotal, courseDiscount, couponAmount, total, totalFa, appliedDiscount, coupon, cta, onContinue }) {
return (
<div className="summary">
<div className="panel" style={{ padding: 0 }}>
<div className="summary-h">
<h2 style={{ margin: 0, fontSize: 16 }}>خلاصه سفارش</h2>
</div>
<div className="course-row">
<div className="course-thumb" style={{ background: c.color }} />
<div style={{ flex: 1 }}>
<div style={{ fontSize: 13.5, fontWeight: 600, lineHeight: 1.4 }}>{c.title}</div>
<div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 4 }}>دسترسی مادامالعمر</div>
</div>
</div>
<div className="summary-body">
<div className="sb-row muted">
<span>قیمت دوره</span>
<span className="num">{subtotal.toLocaleString('fa-IR')} تومان</span>
</div>
<div className="sb-row discount">
<span>تخفیف دوره</span>
<span className="num">{courseDiscount.toLocaleString('fa-IR')}</span>
</div>
{appliedDiscount > 0 && (
<div className="sb-row discount">
<span>کد «{coupon.toUpperCase()}»</span>
<span className="num">{couponAmount.toLocaleString('fa-IR')}</span>
</div>
)}
<div className="sb-row muted">
<span>مالیات بر ارزش افزوده</span>
<span>۰</span>
</div>
<div className="sb-row total">
<span>مبلغ قابل پرداخت</span>
<span className="num">{totalFa} تومان</span>
</div>
</div>
{courseDiscount + couponAmount > 0 && (
<div className="save-banner">
<Icon name="trend" className="ic-sm" />
در این خرید <b className="num" style={{ marginInline: 4 }}>{(courseDiscount + couponAmount).toLocaleString('fa-IR')}</b> تومان صرفهجویی کردی!
</div>
)}
<button className="btn primary pay-btn" onClick={onContinue}>
{cta}
<Icon name="chevron" className="ic-sm flipx" />
</button>
<div className="trust-row">
<span>🔒 پرداخت امن</span>
<span>·</span>
<span>گارانتی ۷ روزه</span>
<span>·</span>
<span>دسترسی مادامالعمر</span>
</div>
</div>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>