final
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, Suspense } from 'react'
|
||||
import Image from 'next/image'
|
||||
import AuthModal from './AuthModal'
|
||||
import UnlockModal from './UnlockModal'
|
||||
|
||||
interface DropData {
|
||||
id: number
|
||||
@@ -45,12 +46,29 @@ export default function Drop() {
|
||||
const [processing, setProcessing] = useState(false)
|
||||
const [user, setUser] = useState<User | null>(null)
|
||||
const [checkingAuth, setCheckingAuth] = useState(true)
|
||||
const [isWholesaleUnlocked, setIsWholesaleUnlocked] = useState(false)
|
||||
const [showUnlockModal, setShowUnlockModal] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
fetchActiveDrop()
|
||||
checkAuth()
|
||||
checkWholesaleStatus()
|
||||
}, [])
|
||||
|
||||
const checkWholesaleStatus = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/referrals/status', {
|
||||
credentials: 'include',
|
||||
})
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
setIsWholesaleUnlocked(data.isUnlocked || false)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking wholesale status:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Poll payment status when payment modal is open
|
||||
useEffect(() => {
|
||||
if (!showPaymentModal || !paymentData?.payment_id) return
|
||||
@@ -333,11 +351,10 @@ export default function Drop() {
|
||||
const calculatePrice = () => {
|
||||
if (!drop) return 0
|
||||
// ppu is stored as integer where 1000 = $1.00, so divide by 1000 to get actual price
|
||||
const pricePerUnit = drop.ppu / 1000
|
||||
if (drop.unit === 'kg') {
|
||||
return (selectedSize / 1000) * pricePerUnit
|
||||
}
|
||||
return selectedSize * pricePerUnit
|
||||
// Assuming ppu is per gram
|
||||
const pricePerGram = drop.ppu / 1000
|
||||
const priceToUse = isWholesaleUnlocked ? pricePerGram * 0.76 : pricePerGram
|
||||
return selectedSize * priceToUse
|
||||
}
|
||||
|
||||
const getTimeUntilStart = () => {
|
||||
@@ -426,10 +443,36 @@ export default function Drop() {
|
||||
<div>
|
||||
<h2>{drop.item}</h2>
|
||||
<div className="meta">
|
||||
{formatSize(drop.size, drop.unit)} Batch
|
||||
{formatSize(drop.size, drop.unit)} batch
|
||||
</div>
|
||||
<div className="price">
|
||||
{(drop.ppu / 1000).toFixed(2)} CHF / {drop.unit} · incl. 2.5% VAT
|
||||
{(() => {
|
||||
// ppu is stored as integer where 1000 = $1.00
|
||||
// Assuming ppu is always per gram for display purposes
|
||||
const pricePerGram = drop.ppu / 1000;
|
||||
const wholesalePricePerGram = pricePerGram * 0.76;
|
||||
|
||||
if (isWholesaleUnlocked) {
|
||||
return (
|
||||
<>
|
||||
<strong>Wholesale price: {wholesalePricePerGram.toFixed(2)} CHF / g</strong>
|
||||
<span className="muted" style={{ display: 'block', marginTop: '6px', fontSize: '14px' }}>
|
||||
Standard: {pricePerGram.toFixed(2)} CHF / g
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<strong>Standard price: {pricePerGram.toFixed(2)} CHF / g</strong>
|
||||
<span className="muted">
|
||||
Wholesale: {wholesalePricePerGram.toFixed(2)} CHF / g 🔒 <a href="#unlock" onClick={(e) => { e.preventDefault(); setShowUnlockModal(true); }}>unlock</a>
|
||||
</span>
|
||||
<div className="hint">Unlock once. Keep wholesale forever.</div>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
|
||||
{isUpcoming ? (
|
||||
@@ -444,9 +487,11 @@ export default function Drop() {
|
||||
<span style={{ width: `${progressPercentage}%` }}></span>
|
||||
</div>
|
||||
<div className="meta">
|
||||
{drop.unit === 'kg' ? drop.fill.toFixed(2) : Math.round(drop.fill)}
|
||||
{drop.unit} of {drop.size}
|
||||
{drop.unit} reserved
|
||||
{(() => {
|
||||
const fillDisplay = drop.unit === 'kg' ? Math.round(drop.fill * 1000) : Math.round(drop.fill);
|
||||
const sizeDisplay = drop.unit === 'kg' ? Math.round(drop.size * 1000) : drop.size;
|
||||
return `${fillDisplay}g of ${sizeDisplay}g reserved`;
|
||||
})()}
|
||||
</div>
|
||||
{(() => {
|
||||
const pendingFill = Number(drop.pending_fill) || 0;
|
||||
@@ -476,8 +521,9 @@ export default function Drop() {
|
||||
</div>
|
||||
|
||||
<button className="cta" onClick={handleJoinDrop}>
|
||||
Join Drop
|
||||
Join the drop
|
||||
</button>
|
||||
<div className="cta-note">No subscription · No obligation</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -751,10 +797,18 @@ export default function Drop() {
|
||||
)}
|
||||
|
||||
{/* Auth Modal */}
|
||||
<AuthModal
|
||||
isOpen={showAuthModal}
|
||||
onClose={() => setShowAuthModal(false)}
|
||||
onLogin={handleLogin}
|
||||
<Suspense fallback={null}>
|
||||
<AuthModal
|
||||
isOpen={showAuthModal}
|
||||
onClose={() => setShowAuthModal(false)}
|
||||
onLogin={handleLogin}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
{/* Unlock Modal */}
|
||||
<UnlockModal
|
||||
isOpen={showUnlockModal}
|
||||
onClose={() => setShowUnlockModal(false)}
|
||||
/>
|
||||
|
||||
{/* Success Modal */}
|
||||
|
||||
Reference in New Issue
Block a user