v3.9.5: Добавлена возможность копирования желаний, исправлена замена изображений
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 48s

This commit is contained in:
poignatov
2026-01-12 17:42:51 +03:00
parent 3cf3cd4edb
commit 705eb2400e
9 changed files with 509 additions and 162 deletions

View File

@@ -150,7 +150,7 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh }) {
return (
<div className="wishlist-detail-conditions">
<h3 className="wishlist-detail-section-title">Условия разблокировки:</h3>
<h3 className="wishlist-detail-section-title">Цели:</h3>
{wishlistItem.unlock_conditions.map((condition, index) => {
let conditionText = ''
let progress = null
@@ -174,19 +174,29 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh }) {
dateText = ' за всё время'
}
conditionText = `${requiredPoints} в ${project}${dateText}`
const remaining = Math.max(0, requiredPoints - currentPoints)
progress = {
type: 'points',
current: currentPoints,
required: requiredPoints,
remaining: remaining,
percentage: requiredPoints > 0 ? Math.min(100, (currentPoints / requiredPoints) * 100) : 0
}
}
const isMet = wishlistItem.unlocked || (progress?.type === 'task' && progress.completed) ||
(progress?.type === 'points' && progress.current >= progress.required)
// Проверяем каждое условие индивидуально
let isMet = false
if (progress?.type === 'task') {
isMet = progress.completed === true
} else if (progress?.type === 'points') {
isMet = progress.current >= progress.required
}
return (
<div key={index} className={`wishlist-detail-condition ${isMet ? 'met' : 'not-met'}`}>
<div
key={index}
className={`wishlist-detail-condition ${isMet ? 'met' : 'not-met'}`}
>
<div className="condition-header">
<svg className="condition-icon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
{isMet ? (
@@ -206,7 +216,10 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh }) {
></div>
</div>
<div className="progress-text">
{Math.round(progress.current)} / {Math.round(progress.required)}
<span>{Math.round(progress.current)} / {Math.round(progress.required)}</span>
{progress.remaining > 0 && (
<span className="progress-remaining">Осталось: {Math.round(progress.remaining)}</span>
)}
</div>
</div>
)}
@@ -259,13 +272,28 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh }) {
)}
{/* Ссылка */}
{wishlistItem.link && (
<div className="wishlist-detail-link">
<a href={wishlistItem.link} target="_blank" rel="noopener noreferrer">
Открыть ссылку
</a>
</div>
)}
{wishlistItem.link && (() => {
try {
const url = new URL(wishlistItem.link)
const host = url.host.replace(/^www\./, '') // Убираем www. если есть
return (
<div className="wishlist-detail-link">
<a href={wishlistItem.link} target="_blank" rel="noopener noreferrer">
{host}
</a>
</div>
)
} catch {
// Если URL некорректный, показываем оригинальный текст
return (
<div className="wishlist-detail-link">
<a href={wishlistItem.link} target="_blank" rel="noopener noreferrer">
Открыть ссылку
</a>
</div>
)
}
})()}
{/* Условия разблокировки */}
{renderUnlockConditions()}