feat(payments): extend payment link expiration to 24 hours

Update default payment link TTL from 30 minutes to 24 hours across frontend and backend. Also modify countdown display to show hours in addition to minutes and seconds.
This commit is contained in:
Tengku Achmad 2025-11-22 11:54:46 +07:00
parent 96c4cd3aba
commit ec96b71161
4 changed files with 14 additions and 11 deletions

View File

@ -124,7 +124,7 @@ const ENABLE = {
// --- Payment Link Config
const EXTERNAL_API_KEY = process.env.EXTERNAL_API_KEY || ''
const PAYMENT_LINK_SECRET = process.env.PAYMENT_LINK_SECRET || ''
const PAYMENT_LINK_TTL_MINUTES = parseInt(process.env.PAYMENT_LINK_TTL_MINUTES || '30', 10)
const PAYMENT_LINK_TTL_MINUTES = parseInt(process.env.PAYMENT_LINK_TTL_MINUTES || '1440', 10)
const PAYMENT_LINK_BASE = process.env.PAYMENT_LINK_BASE || 'http://localhost:5174/pay'
const activeOrders = new Map() // order_id -> expire_at
// Map untuk menyimpan mercant_id per order_id agar notifikasi ERP bisa dinamis
@ -234,7 +234,7 @@ app.get('/api/payment-links/:token', (req, res) => {
if (result.error) {
logWarn('paymentlink.invalid', { error: result.error })
if (isDevEnv()) {
const ttlMin = PAYMENT_LINK_TTL_MINUTES > 0 ? PAYMENT_LINK_TTL_MINUTES : 30
const ttlMin = PAYMENT_LINK_TTL_MINUTES > 0 ? PAYMENT_LINK_TTL_MINUTES : 1440
const fallback = { order_id: token, nominal: 150000, expire_at: Date.now() + ttlMin * 60 * 1000 }
logInfo('paymentlink.dev.fallback', { order_id: fallback.order_id })
return res.json(fallback)
@ -386,7 +386,7 @@ app.post('/createtransaksi', async (req, res) => {
}
const nominal = Number(nominalRaw)
const now = Date.now()
const ttlMin = PAYMENT_LINK_TTL_MINUTES > 0 ? PAYMENT_LINK_TTL_MINUTES : 30
const ttlMin = PAYMENT_LINK_TTL_MINUTES > 0 ? PAYMENT_LINK_TTL_MINUTES : 1440
const expire_at = now + ttlMin * 60 * 1000
// Block jika sudah selesai

View File

@ -14,9 +14,10 @@ function useCountdown(expireAt: number) {
}, [])
const remainMs = Math.max(0, expireAt - now)
const totalSec = Math.floor(remainMs / 1000)
const mm = String(Math.floor(totalSec / 60)).padStart(2, '0')
const hh = String(Math.floor(totalSec / 3600)).padStart(2, '0')
const mm = String(Math.floor((totalSec % 3600) / 60)).padStart(2, '0')
const ss = String(totalSec % 60).padStart(2, '0')
return `${mm}:${ss}`
return `${hh}:${mm}:${ss}`
}
export interface PaymentSheetProps {
@ -93,4 +94,4 @@ export function PaymentSheet({ merchantName = 'Simaya', orderId, amount, expireA
</div>
</div>
)
}
}

View File

@ -19,7 +19,7 @@ export function PayPage() {
const { token } = useParams()
const [orderId, setOrderId] = useState<string>('')
const [amount, setAmount] = useState<number>(0)
const [expireAt, setExpireAt] = useState<number>(Date.now() + 30 * 60 * 1000)
const [expireAt, setExpireAt] = useState<number>(Date.now() + 24 * 60 * 60 * 1000)
const [selectedMethod, setSelectedMethod] = useState<Method>(null)
const [locked, setLocked] = useState<boolean>(false)
const [selectedBank, setSelectedBank] = useState<BankKey | null>(null)
@ -39,7 +39,7 @@ export function PayPage() {
if (cancelled) return
setOrderId(payload.order_id)
setAmount(payload.nominal)
setExpireAt(payload.expire_at ?? Date.now() + 30 * 60 * 1000)
setExpireAt(payload.expire_at ?? Date.now() + 24 * 60 * 60 * 1000)
setAllowedMethods(payload.allowed_methods)
setError(null)
} catch (err) {
@ -245,4 +245,4 @@ export function PayPage() {
</div>
</PaymentSheet>
)
}
}

View File

@ -137,14 +137,16 @@ export async function getPaymentLinkPayload(token: string): Promise<PaymentLinkP
order_id: json.order_id || token,
nominal: Number(json.nominal) || 150000,
customer: json.customer || {},
expire_at: json.expire_at || Date.now() + 30 * 60 * 1000,
expire_at: json.expire_at || Date.now() + 24 * 60 * 60 * 1000
,
allowed_methods: json.allowed_methods || undefined,
}
} catch {
return {
order_id: token,
nominal: 150000,
expire_at: Date.now() + 30 * 60 * 1000,
expire_at: Date.now() + 24 * 60 * 60 * 1000
,
}
}
}