Files
app/src/lib/common/ui/PaymentPage.svelte
2026-09-14 18:18:20 +03:00

330 lines
8.5 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

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.

<script>
let {
onBack = () => {},
totalPrice = 0,
onConfirmPayment = () => {}
} = $props();
const phoneNumber = '+7 (987) 194-97-30'; // Замените на ваш номер
let copySuccess = $state(false);
async function copyPhoneNumber() {
const cleanNumber = phoneNumber.replace(/[^0-9+]/g, '');
let success = false;
// Основной метод (Clipboard API)
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(cleanNumber);
success = true;
} catch (err) {
console.warn('Clipboard API failed:', err);
}
}
// Fallback для мобильных браузеров и HTTP
if (!success) {
try {
const textArea = document.createElement('textarea');
textArea.value = cleanNumber;
textArea.style.position = 'fixed';
textArea.style.left = '-9999px';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
const deprecated = /** @type {any} */ (document).execCommand;
if (deprecated && deprecated.call(document, 'copy')) {
success = true;
}
document.body.removeChild(textArea);
} catch (err) {
console.error('Fallback copy failed:', err);
}
}
if (success) {
copySuccess = true;
setTimeout(() => {
copySuccess = false;
}, 2000);
}
}
</script>
<div class="payment-container">
<header class="payment-header">
<button class="back-btn" onclick={onBack}>←</button>
<h1>Оплата печати</h1>
</header>
<main class="payment-content">
<!-- Сумма -->
<div class="amount-block">
<span class="amount-label">К оплате</span>
<span class="amount-value">{totalPrice}₽</span>
</div>
<!-- Информация о переводе -->
<div class="transfer-info">
<!-- Сначала номер телефона -->
<div class="phone-row">
<span class="phone-number">{phoneNumber}</span>
<button
class="copy-btn"
onclick={copyPhoneNumber}
class:success={copySuccess}
title={copySuccess ? 'Скопировано' : 'Копировать номер'}
aria-label={copySuccess ? 'Скопировано' : 'Копировать номер телефона'}
>
{copySuccess ? '✓' : '📋'}
</button>
</div>
<!-- Под номером — информация о банке -->
<p class="info-text">
Переводить на <span class="bank-name">Т-Банк</span>
</p>
</div>
<!-- Шаги оплаты -->
<div class="steps-block">
<h3 class="steps-title">Как оплатить:</h3>
<ol class="steps-list">
<li>Скопируйте номер телефона</li>
<li>Откройте банковское приложение</li>
<li>Выберите перевод по номеру телефона</li>
<li>Вставьте номер <strong>{phoneNumber}</strong></li>
<li>Укажите банк: <span class="bank-name">Т-Банк</span></li>
<li>Введите сумму <strong>{totalPrice}₽</strong></li>
<li>Подтвердите перевод</li>
<li>Вернитесь сюда и нажмите кнопку ниже</li>
</ol>
</div>
<!-- Кнопка подтверждения -->
<div class="payment-actions">
<button
type="button"
class="confirm-btn"
onclick={onConfirmPayment}
>
Я оплатил(а) — Печать
</button>
</div>
</main>
</div>
<style>
.payment-container {
width: 100%;
min-height: 100dvh;
display: flex;
flex-direction: column;
background: radial-gradient(120% 60% at 50% -10%, rgba(99, 102, 241, 0.18) 0%, transparent 60%);
font-family: system-ui, -apple-system, sans-serif;
color: #f5f7fa;
position: fixed;
top: 0;
left: 0;
z-index: 2000;
/* Предотвращает горизонтальный скролл на мобильных */
overflow-x: hidden;
}
/* --- ИЗМЕНЕНИЯ ЗДЕСЬ --- */
.payment-header {
padding: 20px 16px 8px;
display: flex; /* Включаем флекс */
align-items: center; /* Выравниваем по вертикали */
position: relative;
}
.back-btn {
background: none;
border: none;
color: #6366f1;
font-size: 16px;
font-weight: 600;
cursor: pointer;
padding: 12px 8px;
margin: -8px -8px -8px 0; /* Убираем лишние отступы */
min-height: 44px;
display: inline-flex;
align-items: center;
order: -1; /* Гарантируем, что кнопка будет слева */
margin-right: auto; /* Прижимаем кнопку к левому краю */
}
.payment-header h1 {
margin: 0;
font-size: 26px;
font-weight: 700;
letter-spacing: -0.02em;
position: absolute; /* Абсолютное позиционирование для идеального центра */
left: 50%;
transform: translateX(-50%); /* Сдвиг на 50% собственной ширины влево */
white-space: nowrap; /* Чтобы текст не переносился при сдвиге */
}
/* ----------------------- */
.payment-content {
flex: 1;
padding: 24px 16px 32px;
display: flex;
flex-direction: column;
gap: 28px;
max-width: 520px;
margin: 0 auto;
width: 100%;
box-sizing: border-box;
}
/* ── Сумма ── */
.amount-block {
text-align: center;
display: flex;
flex-direction: column;
gap: 4px;
}
.amount-label {
font-size: 13px;
color: #8b93a1;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.amount-value {
font-size: 48px;
font-weight: 800;
color: #fff;
letter-spacing: -0.03em;
line-height: 1;
}
/* ── Информация о переводе ── */
.transfer-info {
display: flex;
flex-direction: column;
gap: 12px;
align-items: center;
}
.phone-row {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
background: rgba(255, 255, 255, 0.05);
border-radius: 14px;
width: 100%;
box-sizing: border-box;
justify-content: center;
}
.phone-number {
font-size: 20px;
font-weight: 600;
color: #fff;
font-variant-numeric: tabular-nums;
letter-spacing: 0.02em;
}
.copy-btn {
/* Минимум 44px для touch target на мобильных */
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(99, 102, 241, 0.2);
border: 1px solid rgba(99, 102, 241, 0.4);
border-radius: 12px;
color: #fff;
font-size: 22px;
cursor: pointer;
transition: all 0.2s ease;
flex-shrink: 0;
padding: 0;
/* Убирает задержку тапа на мобильных */
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
.copy-btn:hover {
background: rgba(99, 102, 241, 0.35);
border-color: #6366f1;
}
.copy-btn:active {
transform: scale(0.95);
}
.copy-btn.success {
background: rgba(34, 197, 94, 0.25);
border-color: rgba(34, 197, 94, 0.5);
}
.info-text {
color: #a9b0c0;
font-size: 15px;
line-height: 1.5;
margin: 0;
text-align: center;
}
.bank-name {
color: #fbbf24;
font-weight: 700;
}
/* ── Шаги ── */
.steps-block {
display: flex;
flex-direction: column;
gap: 10px;
}
.steps-title {
margin: 0;
font-size: 17px;
font-weight: 600;
color: #f5f7fa;
text-align: left;
}
.steps-list {
margin: 0;
padding-left: 20px;
color: #a9b0c0;
font-size: 15px;
line-height: 1.9;
text-align: left;
}
.steps-list li {
padding-left: 4px;
}
.steps-list strong {
color: #fff;
font-weight: 600;
}
/* ── Кнопка подтверждения ── */
.payment-actions {
display: flex;
flex-direction: column;
gap: 14px;
margin-top: auto;
padding-top: 8px;
}
.confirm-btn {
width: 100%;
/* Увеличенная высота для мобильных */
padding: 20px 24px;
border-radius: 16px;
font-size: 17px;
font-weight: 700;
cursor: pointer;
border: none;
color: #fff;
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
box-shadow: 0 8px 24px -6px rgba(34, 197, 94, 0.4);
transition: all 0.2s ease;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
min-height: 56px;
}
.confirm-btn:hover {
transform: translateY(-2px);
box-shadow: 0 12px 28px -6px rgba(34, 197, 94, 0.5);
}
.confirm-btn:active {
transform: translateY(0);
}
/* Адаптация для очень маленьких экранов */
@media (max-width: 360px) {
.amount-value {
font-size: 40px;
}
.phone-number {
font-size: 18px;
}
.payment-header h1 {
font-size: 22px;
}
}
</style>