amanpay / web /src /utils /validate.ts
MHamdan's picture
CI deploy 84761d0
de6cac5 verified
Raw
History Blame Contribute Delete
1.54 kB
import type { MessageKey } from '../i18n/en'
const MAX_MAJOR = 1_000_000 // demo ceiling; backend enforces its own limits
/** Validate a SAR major-unit amount string. Returns an i18n error key or undefined. */
export function validateAmount(raw: string): MessageKey | undefined {
const s = raw.trim()
if (!s) return 'error.amountEmpty'
if (!/^\d*\.?\d*$/.test(s) || s === '.') return 'error.amountInvalid'
const n = Number(s)
if (!Number.isFinite(n)) return 'error.amountInvalid'
if (n < 0) return 'error.amountNegative'
if (n === 0) return 'error.amountZero'
if (n > MAX_MAJOR) return 'error.amountTooLarge'
if (!/^\d+(\.\d{1,2})?$/.test(s)) return 'error.amountInvalid' // SAR = 2 decimals max
return undefined
}
/** Saudi IBAN: "SA" + 22 digits (24 chars), ISO 13616 mod-97 check == 1. */
export function isValidSaudiIban(raw: string): boolean {
const s = raw.replace(/\s+/g, '').toUpperCase()
if (!/^SA\d{22}$/.test(s)) return false
const rearranged = s.slice(4) + s.slice(0, 4)
let rem = 0
for (const ch of rearranged) {
const val = ch >= 'A' && ch <= 'Z' ? String(ch.charCodeAt(0) - 55) : ch
for (const d of val) rem = (rem * 10 + (d.charCodeAt(0) - 48)) % 97
}
return rem === 1
}
export function validateIban(raw: string): MessageKey | undefined {
if (!raw.trim()) return 'error.payeeEmpty'
return isValidSaudiIban(raw) ? undefined : 'error.ibanInvalid'
}
export function validateMerchant(raw: string): MessageKey | undefined {
return raw.trim() ? undefined : 'error.merchantEmpty'
}