This commit is contained in:
root
2025-12-21 12:46:27 +01:00
parent 5e65144934
commit bb1c5b43d6
18 changed files with 1375 additions and 691 deletions

View File

@@ -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 */}