sync
This commit is contained in:
@@ -1016,12 +1016,17 @@ export default function Drop() {
|
||||
{calculatePrice().toFixed(2)} {currency}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
|
||||
<span style={{ color: 'var(--muted)', fontSize: '14px' }}>{t('drop.shippingFee')}:</span>
|
||||
<span style={{ fontWeight: 500, fontSize: '14px' }}>
|
||||
{loadingShippingFee ? '...' : (shippingFee !== null ? shippingFee.toFixed(2) : '40.00')} {currency}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ marginBottom: '8px', marginLeft: '0', paddingLeft: '0' }}>
|
||||
<span style={{ color: 'var(--muted)', fontSize: '12px', fontStyle: 'italic' }}>
|
||||
{t('drop.shippingFeeNote')}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
@@ -1352,12 +1357,17 @@ export default function Drop() {
|
||||
{paymentData.subtotal?.toFixed(2) || (paymentData.price_amount - (paymentData.shipping_fee || 0)).toFixed(2)} {paymentData.price_currency.toUpperCase()}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
|
||||
<span style={{ color: 'var(--muted)' }}>{t('drop.shippingFee')}:</span>
|
||||
<span style={{ fontWeight: 500 }}>
|
||||
{paymentData.shipping_fee?.toFixed(2) || '0.00'} {paymentData.price_currency.toUpperCase()}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ marginBottom: '8px', marginLeft: '0', paddingLeft: '0' }}>
|
||||
<span style={{ color: 'var(--muted)', fontSize: '12px', fontStyle: 'italic' }}>
|
||||
{t('drop.shippingFeeNote')}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
|
||||
@@ -62,7 +62,7 @@ export default function Nav() {
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
||||
<div className="brand">
|
||||
<a href="/" style={{ display: 'inline-block', textDecoration: 'none' }}>
|
||||
<img src="/header.jpg" alt="420Deals.ch" style={{ height: '40px', width: 'auto' }} />
|
||||
<img src="/header.png" alt="420Deals.ch" style={{ height: '50px', width: 'auto' }} />
|
||||
</a>
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -1,145 +1,40 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useI18n } from '@/lib/i18n'
|
||||
|
||||
export default function Signup() {
|
||||
const { t } = useI18n()
|
||||
const [email, setEmail] = useState('')
|
||||
const [whatsapp, setWhatsapp] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [showPopup, setShowPopup] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
|
||||
// Validate that at least one field is filled
|
||||
if (!email.trim() && !whatsapp.trim()) {
|
||||
setError('Please enter at least an email or phone number')
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/notifications/subscribe', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email.trim(),
|
||||
phone: whatsapp.trim(),
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Failed to subscribe')
|
||||
}
|
||||
|
||||
// Show success popup
|
||||
setShowPopup(true)
|
||||
|
||||
// Clear form
|
||||
setEmail('')
|
||||
setWhatsapp('')
|
||||
|
||||
// Hide popup after 5 seconds
|
||||
setTimeout(() => {
|
||||
setShowPopup(false)
|
||||
}, 5000)
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'An error occurred')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="signup">
|
||||
<h2>{t('signup.title')}</h2>
|
||||
<p>{t('signup.subtitle')}</p>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder={t('signup.email')}
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
disabled={loading}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('signup.whatsapp')}
|
||||
value={whatsapp}
|
||||
onChange={(e) => setWhatsapp(e.target.value)}
|
||||
disabled={loading}
|
||||
/>
|
||||
<br />
|
||||
{error && <div style={{ color: '#ff4444', marginTop: '10px', fontSize: '14px' }}>{error}</div>}
|
||||
<button type="submit" disabled={loading}>
|
||||
{loading ? t('signup.subscribing') : t('signup.getNotified')}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{showPopup && (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
background: '#1c1c1c',
|
||||
border: '1px solid #2a2a2a',
|
||||
borderRadius: '16px',
|
||||
padding: '30px 40px',
|
||||
zIndex: 1000,
|
||||
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.5)',
|
||||
maxWidth: '400px',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
<p style={{ margin: 0, fontSize: '16px', color: '#eaeaea' }}>
|
||||
{t('signup.successMessage')}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => setShowPopup(false)}
|
||||
style={{
|
||||
marginTop: '20px',
|
||||
padding: '10px 20px',
|
||||
background: '#3ddc84',
|
||||
color: '#000',
|
||||
border: 'none',
|
||||
borderRadius: '8px',
|
||||
cursor: 'pointer',
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
{t('common.ok')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showPopup && (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
zIndex: 999,
|
||||
}}
|
||||
onClick={() => setShowPopup(false)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<div className="signup">
|
||||
<h2>{t('signup.title')}</h2>
|
||||
<p>{t('signup.subtitle')}</p>
|
||||
<a
|
||||
href="https://t.me/official420deals"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
marginTop: '20px',
|
||||
padding: '12px 24px',
|
||||
background: '#0088cc',
|
||||
color: '#fff',
|
||||
textDecoration: 'none',
|
||||
borderRadius: '8px',
|
||||
fontSize: '16px',
|
||||
fontWeight: '500',
|
||||
transition: 'background 0.2s',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = '#006ba3'
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = '#0088cc'
|
||||
}}
|
||||
>
|
||||
{t('signup.joinTelegram')}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import { I18nProvider } from '@/lib/i18n'
|
||||
const inter = Inter({ subsets: ['latin'], weight: ['300', '400', '500', '600'] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: '420Deals.ch – Premium Swiss CBD Drops',
|
||||
description: 'Shop together. Wholesale prices for private buyers.',
|
||||
title: 'CBD Großhandelspreise Schweiz | 420deals.ch',
|
||||
description: 'CBD direkt vom Produzenten kaufen. Gemeinsam einkaufen, Retail umgehen und von kollektiven Großhandelspreisen profitieren.',
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -16,7 +16,7 @@ export default function RootLayout({
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<html lang="de">
|
||||
<body className={inter.className}>
|
||||
<I18nProvider>{children}</I18nProvider>
|
||||
</body>
|
||||
|
||||
@@ -109,7 +109,8 @@
|
||||
"amountToPay": "Zu zahlender Betrag",
|
||||
"price": "Preis",
|
||||
"subtotal": "Zwischensumme",
|
||||
"shippingFee": "Versandgebühr",
|
||||
"shippingFee": "Verpackung & Versand",
|
||||
"shippingFeeNote": "A-Post Paketversand mit Unterschrift & Versicherung",
|
||||
"sendPaymentTo": "Senden Sie die Zahlung an diese Adresse",
|
||||
"copyAddress": "Adresse kopieren",
|
||||
"memoRequired": "Memo / Ziel-Tag (Erforderlich)",
|
||||
@@ -129,19 +130,15 @@
|
||||
"infoBox": {
|
||||
"whyCheap": "Warum so günstig?",
|
||||
"whyCheapText": "Retailpreise liegen bei ca. 10 CHF/g. Durch kollektive Sammelbestellungen kaufen wir wie Grosshändler ein – ohne Zwischenstufen.",
|
||||
"taxesLegal": "Steuern & Recht",
|
||||
"taxesLegalText": "Bulk-Verkauf mit 2.5% MWST. Keine Retail-Verpackung, keine Tabaksteuer.",
|
||||
"taxesLegal": "Laborbericht",
|
||||
"taxesLegalText": "Unabhängige Labortests für jeden Drop. Vollständiges Cannabinoid-Profil und Reinheitsergebnisse verfügbar für Transparenz und Qualitätssicherung.",
|
||||
"dropModel": "Drop-Modell",
|
||||
"dropModelText": "Pro Drop nur eine Sorte. Erst ausverkauft – dann der nächste Drop."
|
||||
},
|
||||
"signup": {
|
||||
"title": "Drop-Benachrichtigungen",
|
||||
"subtitle": "Erhalte Updates zu neuen Drops per E-Mail oder WhatsApp.",
|
||||
"email": "E-Mail",
|
||||
"whatsapp": "WhatsApp Nummer",
|
||||
"getNotified": "Benachrichtigen lassen",
|
||||
"subscribing": "Wird abonniert...",
|
||||
"successMessage": "Du erhältst eine Benachrichtigung, sobald ein neuer Drop verfügbar ist."
|
||||
"subtitle": "Tritt diesem Telegram-Kanal bei, um über neue Drops etc. benachrichtigt zu werden.",
|
||||
"joinTelegram": "Telegram-Kanal beitreten"
|
||||
},
|
||||
"pastDrops": {
|
||||
"title": "Vergangene Drops",
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
"amountToPay": "Amount to Pay",
|
||||
"price": "Price",
|
||||
"subtotal": "Subtotal",
|
||||
"shippingFee": "Shipping Fee",
|
||||
"shippingFee": "Packaging & Shipping",
|
||||
"shippingFeeNote": "A-Post parcel delivery with signature & insurance",
|
||||
"sendPaymentTo": "Send payment to this address",
|
||||
"memoRequired": "Memo / Destination Tag (Required)",
|
||||
"copyMemo": "Copy Memo",
|
||||
@@ -126,19 +127,15 @@
|
||||
"infoBox": {
|
||||
"whyCheap": "Why so cheap?",
|
||||
"whyCheapText": "Retail prices are around 10 CHF/g. Through collective bulk orders, we buy like wholesalers – without intermediaries.",
|
||||
"taxesLegal": "Taxes & Legal",
|
||||
"taxesLegalText": "Bulk sale with 2.5% VAT. No retail packaging, no tobacco tax.",
|
||||
"taxesLegal": "Lab Report",
|
||||
"taxesLegalText": "Independent lab testing for every drop. Full cannabinoid profile and purity results available for transparency and quality assurance.",
|
||||
"dropModel": "Drop Model",
|
||||
"dropModelText": "One variety per drop. Only when sold out – then the next drop."
|
||||
},
|
||||
"signup": {
|
||||
"title": "Drop Notifications",
|
||||
"subtitle": "Receive updates about new drops via email or WhatsApp.",
|
||||
"email": "E-Mail",
|
||||
"whatsapp": "WhatsApp Number",
|
||||
"getNotified": "Get Notified",
|
||||
"subscribing": "Subscribing...",
|
||||
"successMessage": "You will receive a notification as soon as a new drop drops."
|
||||
"subtitle": "Join this telegram channel to be notified on new drops etc.",
|
||||
"joinTelegram": "Join Telegram Channel"
|
||||
},
|
||||
"pastDrops": {
|
||||
"title": "Past Drops",
|
||||
|
||||
BIN
public/header.png
Normal file
BIN
public/header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Reference in New Issue
Block a user