Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/common/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,6 @@ export function showToast(
type: ToastType = 'info',
options?: ToastOptions
) {
raiseToastLayer()

const theme = TOAST_THEMES[type] || TOAST_THEMES.info
const title = options?.title ?? theme.defaultTitle
const actionText = options?.actionText ?? theme.defaultActionText
Expand All @@ -187,10 +185,6 @@ export function showToast(
playNativeToastSound(type)
}

if (options?.alarmSound) {
playAlarm('success')
}

return toast.custom(
(t) => {
const handleAction = () => {
Expand All @@ -204,9 +198,9 @@ export function showToast(
<div
dir="rtl"
className={cn(
'w-full max-w-[390px] min-w-[320px] rounded-2xl p-3.5 flex items-center justify-between gap-3 shadow-2xl backdrop-blur-xl border select-none transition-all duration-200',
'w-full max-w-[390px] min-w-[320px] rounded-2xl p-3.5 flex items-center justify-between gap-3 shadow-2xl backdrop-blur-xl border select-none transition-all duration-200 pointer-events-auto',
theme.container,
t.visible ? 'animate-enter' : 'animate-leave'
t.visible ? 'opacity-100 translate-y-0 scale-100' : 'opacity-0 -translate-y-2 scale-95'
)}
>
<div className="flex items-center flex-1 min-w-0 gap-3">
Expand Down
175 changes: 175 additions & 0 deletions src/components/gallery/gallery-asset-purchase-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { Button, Modal } from '@/components/ui'
import { UserCoin } from '@/layouts/setting/tabs/account/components/user-coin'
import { callEvent } from '@/common/utils/call-event'
import { showToast } from '@/common/toast'
import type { GalleryAsset } from '@/services/hooks/gallery/get-gallery-assets.hook'
import { usePurchaseGalleryAsset } from '@/services/hooks/gallery/get-gallery-assets.hook'

interface GalleryAssetPurchaseModalProps {
isOpen: boolean
onClose: () => void
asset: GalleryAsset | null
userCoins: number
isVip: boolean
onPurchaseSuccess: (asset: GalleryAsset) => void
onSelectDirectly?: (asset: GalleryAsset) => void
}

export function GalleryAssetPurchaseModal({
isOpen,
onClose,
asset,
userCoins,
isVip,
onPurchaseSuccess,
onSelectDirectly,
}: GalleryAssetPurchaseModalProps) {
const { mutate: purchase, isPending } = usePurchaseGalleryAsset()

if (!asset) return null

const isVipUnlocked = isVip && asset.accessVip
const canAfford = userCoins >= asset.price

const handlePurchase = () => {
if (!canAfford) return

purchase(asset.id, {
onSuccess: (response) => {
showToast(`${asset.title || 'آیتم'} برای همیشه خریداری شد`, 'success')
const updatedAsset = response?.data?.asset || {
...asset,
isOwned: true,
isUnlocked: true,
}
onPurchaseSuccess(updatedAsset)
},
onError: () => {
showToast('خطا در دریافت آیتم', 'error')
},
})
}

const handleUseWithVip = () => {
if (onSelectDirectly) {
onSelectDirectly(asset)
}
onClose()
}

const handleOpenCoins = () => {
onClose()
callEvent('openMarketModal')
setTimeout(() => {
callEvent('market_change_tab', 'coins')
}, 100)
}

return (
<Modal
isOpen={isOpen}
onClose={onClose}
title=" "
size="md"
direction="rtl"
closeOnBackdropClick={!isPending}
showCloseButton={!isPending}
>
<div className="space-y-4">
<div className="relative overflow-hidden rounded-2xl bg-base-200/50 max-h-[340px] flex items-center justify-center">
<img
src={asset.previewUrl || asset.url}
alt={asset.title || 'Asset'}
className="object-contain w-full max-h-[340px] rounded-2xl"
/>
</div>

<div className="space-y-2">
<div className="flex items-center justify-between">
<h3 className="text-base font-semibold text-content">
{asset.title || 'تصویر گالری'}
</h3>
{asset.price > 0 && (
<UserCoin coins={asset.price} title="قیمت خرید دائمی" />
)}
</div>
<p className="text-xs text-muted">
{isVipUnlocked
? 'چون اشتراک پرو داری می‌تونی این تصویر رو رایگان فعال کنی یا با ویج‌کوین دائمی بخریش'
: 'این تصویر رو با ویج‌کوین باز کن و همیشه ازش استفاده کن'}
</p>
</div>

{!isVipUnlocked && !canAfford && (
<div className="flex items-center justify-between px-3 py-2 text-xs rounded-xl bg-error/10 text-error">
<span>
موجودی ویج‌کوین ناکافیه ({asset.price - userCoins} ویج‌کوین کسری
داری)
</span>
<button
type="button"
onClick={handleOpenCoins}
className="font-medium underline cursor-pointer"
>
خرید ویج‌کوین
</button>
</div>
)}

<div className="flex flex-col gap-2 pt-2">
{isVipUnlocked ? (
<div className="flex gap-2.5">
<Button
onClick={handleUseWithVip}
size="md"
className="flex-1"
rounded="2xl"
variant="primary"
>
استفاده رایگان با پرو
</Button>
{asset.price > 0 && (
<Button
onClick={handlePurchase}
size="md"
disabled={!canAfford || isPending}
loading={isPending}
loadingText="در حال خرید..."
className="flex-1"
rounded="2xl"
variant="default"
>
خرید دائمی
</Button>
)}
</div>
) : (
<div className="flex gap-2.5">
<Button
onClick={handlePurchase}
size="md"
disabled={!canAfford || isPending}
loading={isPending}
loadingText="در حال خرید..."
className="flex-1"
rounded="2xl"
variant={canAfford ? 'primary' : 'default'}
>
خرید دائمی
</Button>
<Button
onClick={onClose}
size="md"
variant="default"
rounded="2xl"
disabled={isPending}
>
انصراف
</Button>
</div>
)}
</div>
</div>
</Modal>
)
}
Loading
Loading