@applite/duticotac-react 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +628 -0
- package/dist/index.d.mts +102 -0
- package/dist/index.d.ts +102 -0
- package/dist/index.js +720 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +677 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/payment-modal.tsx","../src/components/provider-selector.tsx","../src/utils/cn.ts","../src/components/phone-input.tsx","../src/components/otp-input.tsx","../src/components/transaction-status.tsx","../src/utils/format.ts","../src/utils/validation.ts"],"sourcesContent":["// Components\nexport { DuticotacPaymentModal } from \"./components/payment-modal\";\nexport type { DuticotacPaymentModalProps } from \"./components/payment-modal\";\n\nexport { ProviderSelector } from \"./components/provider-selector\";\nexport type { ProviderSelectorProps } from \"./components/provider-selector\";\n\nexport { PhoneInput } from \"./components/phone-input\";\nexport type { PhoneInputProps } from \"./components/phone-input\";\n\nexport { OtpInput } from \"./components/otp-input\";\nexport type { OtpInputProps } from \"./components/otp-input\";\n\nexport { TransactionStatus } from \"./components/transaction-status\";\nexport type { TransactionStatusProps } from \"./components/transaction-status\";\n\n// Utilities\nexport { cn } from \"./utils/cn\";\nexport { formatCFA } from \"./utils/format\";\nexport {\n getPhoneRegex,\n validatePhone,\n normalizePhone,\n needsOtp,\n} from \"./utils/validation\";\n","import * as React from \"react\";\nimport {\n DuticotacSDK,\n DuticotacError,\n getErrorMessage,\n} from \"@applite/duticotac\";\nimport type {\n PaymentProvider,\n TransactionModel,\n CoreApp,\n PlatformType,\n} from \"@applite/duticotac\";\nimport { ProviderSelector } from \"./provider-selector\";\nimport { PhoneInput } from \"./phone-input\";\nimport { OtpInput } from \"./otp-input\";\nimport { TransactionStatus } from \"./transaction-status\";\nimport { cn } from \"../utils/cn\";\nimport { formatCFA } from \"../utils/format\";\nimport { validatePhone, normalizePhone, needsOtp } from \"../utils/validation\";\n\n// ─── Polling helpers ─────────────────────────────────────────────────────────\n\nfunction waitForVisibility(signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (typeof document === \"undefined\" || document.visibilityState === \"visible\") {\n resolve();\n return;\n }\n const handler = () => {\n if (document.visibilityState === \"visible\") {\n document.removeEventListener(\"visibilitychange\", handler);\n resolve();\n }\n };\n document.addEventListener(\"visibilitychange\", handler);\n signal?.addEventListener(\"abort\", () => {\n document.removeEventListener(\"visibilitychange\", handler);\n resolve();\n });\n });\n}\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\ntype Step = \"form\" | \"confirming\" | \"success\" | \"error\";\n\nexport interface DuticotacPaymentModalProps {\n open: boolean;\n onClose: () => void;\n onSuccess?: (transaction: TransactionModel) => void;\n\n /** SDK instance or config to create one. */\n sdk: DuticotacSDK;\n\n /** Amount in the smallest currency unit. */\n amount: number;\n\n /** Available payment providers. */\n providers?: PaymentProvider[];\n\n /** Called to get a unique transaction ID before cashout. */\n getTransactionId: () => Promise<string>;\n\n /** Product reference for the cashout. */\n productReference?: string;\n\n /** Pre-fill phone number. */\n initialPhone?: string;\n\n /** Customer details. */\n name?: string;\n email?: string;\n customerId?: string;\n kolaboReference?: string;\n app?: CoreApp;\n platform?: PlatformType;\n\n /** Custom success message. */\n successMessage?: string;\n\n /** Custom title. */\n title?: string;\n\n /** Polling timeout in ms (default: 90000). */\n pollTimeout?: number;\n\n /** Additional class names for the modal container. */\n className?: string;\n\n /**\n * Render prop for the modal wrapper. Receives children and renders them\n * inside your dialog/modal component. If not provided, a simple overlay is used.\n */\n renderModal?: (props: {\n open: boolean;\n onClose: () => void;\n title: string;\n children: React.ReactNode;\n }) => React.ReactNode;\n}\n\nconst DEFAULT_PROVIDERS: PaymentProvider[] = [\n \"OM_CI\",\n \"MTN_CI\",\n \"MOOV_CI\",\n \"WAVE_CI\",\n];\n\nexport function DuticotacPaymentModal({\n open,\n onClose,\n onSuccess,\n sdk,\n amount,\n providers = DEFAULT_PROVIDERS,\n getTransactionId,\n productReference,\n initialPhone = \"\",\n name: customerName,\n email: customerEmail,\n customerId,\n kolaboReference,\n app,\n platform,\n successMessage,\n title = \"Paiement\",\n pollTimeout = 90_000,\n className,\n renderModal,\n}: DuticotacPaymentModalProps) {\n const [step, setStep] = React.useState<Step>(\"form\");\n const [provider, setProvider] = React.useState<PaymentProvider>(providers[0]!);\n const [phone, setPhone] = React.useState(initialPhone);\n const [otp, setOtp] = React.useState(\"\");\n const [phoneError, setPhoneError] = React.useState<string | null>(null);\n const [errorMessage, setErrorMessage] = React.useState(\"\");\n const [paymentUrl, setPaymentUrl] = React.useState<string | null>(null);\n const [elapsedSeconds, setElapsedSeconds] = React.useState(0);\n const [lastTransaction, setLastTransaction] = React.useState<TransactionModel | null>(null);\n\n const abortRef = React.useRef<AbortController | null>(null);\n const elapsedRef = React.useRef<ReturnType<typeof setInterval> | null>(null);\n\n const cleanup = React.useCallback(() => {\n abortRef.current?.abort();\n abortRef.current = null;\n if (elapsedRef.current) {\n clearInterval(elapsedRef.current);\n elapsedRef.current = null;\n }\n }, []);\n\n React.useEffect(() => {\n if (open) {\n setStep(\"form\");\n setErrorMessage(\"\");\n setOtp(\"\");\n setPaymentUrl(null);\n setElapsedSeconds(0);\n setPhoneError(null);\n setLastTransaction(null);\n } else {\n cleanup();\n }\n }, [open, cleanup]);\n\n React.useEffect(() => () => cleanup(), [cleanup]);\n\n const isFormValid =\n phone.replace(/\\s/g, \"\").length >= 8 &&\n (needsOtp(provider) ? otp.length === 4 : true);\n\n const handleSubmit = async () => {\n // Validate phone\n const phoneErr = validatePhone(phone, provider);\n if (phoneErr) {\n setPhoneError(phoneErr);\n return;\n }\n setPhoneError(null);\n\n setStep(\"confirming\");\n setErrorMessage(\"\");\n cleanup();\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n try {\n const transactionId = await getTransactionId();\n\n const result = await sdk.mobileMoney.cashout({\n transactionId,\n ref: productReference,\n phone: normalizePhone(phone),\n name: customerName ?? \"Duticotac App\",\n email: customerEmail ?? \"\",\n paymentMethod: provider,\n amount,\n otp: needsOtp(provider) ? otp : undefined,\n customerId,\n kolaboReference,\n app,\n plateform: platform,\n });\n\n const tx = result.data;\n\n if (tx?.paymentUrl) {\n setPaymentUrl(tx.paymentUrl);\n try {\n window.open(tx.paymentUrl, \"_blank\");\n } catch {\n // Popup may be blocked\n }\n }\n\n // Start polling\n const startTime = Date.now();\n setElapsedSeconds(0);\n elapsedRef.current = setInterval(() => {\n setElapsedSeconds(Math.floor((Date.now() - startTime) / 1000));\n }, 1000);\n\n const confirmed = await sdk.transaction.poll(tx.id ?? transactionId, {\n timeoutMs: pollTimeout,\n signal: controller.signal,\n onPoll: () => {\n // Wait for visibility before each poll\n },\n });\n\n setLastTransaction(confirmed.data);\n setStep(\"success\");\n onSuccess?.(confirmed.data);\n } catch (e) {\n if (controller.signal.aborted) return;\n\n if (e instanceof DuticotacError) {\n setErrorMessage(e.message);\n } else {\n setErrorMessage(\n getErrorMessage(\"unknown-error\"),\n );\n }\n setStep(\"error\");\n }\n };\n\n const handleRetry = () => {\n setStep(\"form\");\n setErrorMessage(\"\");\n setPaymentUrl(null);\n setElapsedSeconds(0);\n };\n\n // ─── Content ──────────────────────────────────────────────────────────────\n\n const content = (\n <div className={cn(\"space-y-5\", className)}>\n {step === \"form\" && (\n <>\n {/* Offer summary */}\n <div className=\"rounded-lg border-l-4 border-l-primary bg-muted/50 p-4\">\n <p className=\"text-xs text-muted-foreground\">Montant</p>\n <p className=\"text-xl font-bold text-primary\">\n {formatCFA(amount)} FCFA\n </p>\n </div>\n\n {/* Provider selection */}\n <div className=\"space-y-2\">\n <p className=\"text-sm font-semibold text-foreground\">\n Moyen de paiement\n </p>\n <ProviderSelector\n providers={providers}\n value={provider}\n onChange={(p) => {\n setProvider(p);\n if (!needsOtp(p)) setOtp(\"\");\n }}\n />\n </div>\n\n {/* Phone input */}\n <PhoneInput\n value={phone}\n onChange={(v) => {\n setPhone(v);\n setPhoneError(null);\n }}\n error={phoneError}\n autoFocus\n />\n\n {/* OTP input (Orange Money only) */}\n {needsOtp(provider) && (\n <OtpInput value={otp} onChange={setOtp} />\n )}\n\n {/* Actions */}\n <div className=\"flex justify-end gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md border border-border bg-background px-5 py-2.5 text-sm font-semibold text-foreground transition-colors hover:bg-muted\"\n >\n Annuler\n </button>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!isFormValid}\n className=\"rounded-md bg-primary px-5 py-2.5 text-sm font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-50\"\n >\n Payer {formatCFA(amount)} FCFA\n </button>\n </div>\n </>\n )}\n\n {step === \"confirming\" && (\n <TransactionStatus\n status=\"polling\"\n elapsedSeconds={elapsedSeconds}\n paymentUrl={paymentUrl}\n onOpenPaymentUrl={() => {\n if (paymentUrl) window.open(paymentUrl, \"_blank\");\n }}\n onClose={onClose}\n />\n )}\n\n {step === \"success\" && (\n <TransactionStatus\n status=\"success\"\n message={successMessage ?? \"Le paiement a ete effectue avec succes.\"}\n onClose={onClose}\n />\n )}\n\n {step === \"error\" && (\n <TransactionStatus\n status=\"error\"\n errorMessage={errorMessage}\n onRetry={handleRetry}\n onClose={onClose}\n />\n )}\n </div>\n );\n\n // ─── Render ───────────────────────────────────────────────────────────────\n\n if (renderModal) {\n return <>{renderModal({ open, onClose, title, children: content })}</>;\n }\n\n // Default simple overlay modal\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div\n className=\"absolute inset-0 bg-black/50\"\n onClick={onClose}\n />\n <div className=\"relative z-10 w-full max-w-md rounded-xl border border-border bg-background p-6 shadow-xl\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-bold text-foreground\">{title}</h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 18L18 6M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n {content}\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\nimport type { PaymentProvider } from \"@applite/duticotac\";\nimport { getProviderName, getProviderLogo } from \"@applite/duticotac\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ProviderSelectorProps {\n providers: PaymentProvider[];\n value: PaymentProvider;\n onChange: (provider: PaymentProvider) => void;\n disabled?: boolean;\n className?: string;\n}\n\nexport function ProviderSelector({\n providers,\n value,\n onChange,\n disabled,\n className,\n}: ProviderSelectorProps) {\n return (\n <div className={cn(\"grid gap-2\", className)} style={{\n gridTemplateColumns: `repeat(${Math.min(providers.length, 4)}, 1fr)`,\n }}>\n {providers.map((provider) => {\n const selected = value === provider;\n return (\n <button\n key={provider}\n type=\"button\"\n disabled={disabled}\n onClick={() => onChange(provider)}\n className={cn(\n \"relative flex flex-col items-center gap-2 rounded-lg border-2 p-3 transition-all\",\n \"hover:scale-[1.02] disabled:pointer-events-none disabled:opacity-50\",\n selected\n ? \"border-primary bg-primary/5 shadow-sm\"\n : \"border-border bg-background hover:border-primary/40\",\n )}\n >\n {selected && (\n <div className=\"absolute -right-1.5 -top-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M5 12l5 5L20 7\"\n stroke=\"#fff\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n )}\n <img\n src={getProviderLogo(provider)}\n alt={getProviderName(provider)}\n width={44}\n height={44}\n className=\"rounded-lg object-contain\"\n />\n <span\n className={cn(\n \"text-center text-xs leading-tight\",\n selected\n ? \"font-semibold text-primary\"\n : \"font-medium text-muted-foreground\",\n )}\n >\n {getProviderName(provider)}\n </span>\n </button>\n );\n })}\n </div>\n );\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface PhoneInputProps {\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n error?: string | null;\n disabled?: boolean;\n className?: string;\n autoFocus?: boolean;\n}\n\nexport function PhoneInput({\n value,\n onChange,\n label = \"Numero de telephone\",\n placeholder = \"07 01 02 03 04\",\n error,\n disabled,\n className,\n autoFocus,\n}: PhoneInputProps) {\n return (\n <div className={cn(\"space-y-1.5\", className)}>\n {label && (\n <label className=\"block text-sm font-semibold text-foreground\">\n {label}\n </label>\n )}\n <div className=\"flex items-center gap-2\">\n <div className=\"flex h-10 items-center rounded-md border border-border bg-muted px-3 text-sm font-medium text-muted-foreground\">\n +225\n </div>\n <input\n type=\"tel\"\n inputMode=\"numeric\"\n value={value}\n onChange={(e) => {\n const cleaned = e.target.value.replace(/[^\\d\\s]/g, \"\");\n onChange(cleaned);\n }}\n placeholder={placeholder}\n disabled={disabled}\n autoFocus={autoFocus}\n className={cn(\n \"h-10 w-full rounded-md border bg-background px-3 text-sm font-medium outline-none transition-colors\",\n \"placeholder:text-muted-foreground/50\",\n \"focus:border-primary focus:ring-2 focus:ring-primary/20\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n error ? \"border-destructive\" : \"border-border\",\n )}\n />\n </div>\n {error && (\n <p className=\"text-xs font-medium text-destructive\">{error}</p>\n )}\n </div>\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface OtpInputProps {\n value: string;\n onChange: (value: string) => void;\n length?: number;\n disabled?: boolean;\n className?: string;\n}\n\nexport function OtpInput({\n value,\n onChange,\n length = 4,\n disabled,\n className,\n}: OtpInputProps) {\n const inputRefs = React.useRef<(HTMLInputElement | null)[]>([]);\n const digits = value.padEnd(length, \"\").slice(0, length).split(\"\");\n\n const setDigit = (index: number, char: string) => {\n const next = [...digits];\n next[index] = char;\n onChange(next.join(\"\"));\n };\n\n const handleKeyDown = (\n index: number,\n e: React.KeyboardEvent<HTMLInputElement>,\n ) => {\n if (e.key === \"Backspace\") {\n e.preventDefault();\n if (digits[index]?.trim()) {\n setDigit(index, \"\");\n } else if (index > 0) {\n setDigit(index - 1, \"\");\n inputRefs.current[index - 1]?.focus();\n }\n } else if (e.key === \"ArrowLeft\" && index > 0) {\n inputRefs.current[index - 1]?.focus();\n } else if (e.key === \"ArrowRight\" && index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n }\n };\n\n const handleInput = (\n index: number,\n e: React.FormEvent<HTMLInputElement>,\n ) => {\n const val = (e.target as HTMLInputElement).value;\n const char = val.replace(/\\D/g, \"\").slice(-1);\n if (!char) return;\n setDigit(index, char);\n if (index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n }\n };\n\n const handlePaste = (e: React.ClipboardEvent) => {\n e.preventDefault();\n const pasted = e.clipboardData\n .getData(\"text\")\n .replace(/\\D/g, \"\")\n .slice(0, length);\n if (!pasted) return;\n onChange(pasted.padEnd(length, \"\").slice(0, length).replace(/ /g, \"\"));\n const focusIndex = Math.min(pasted.length, length - 1);\n inputRefs.current[focusIndex]?.focus();\n };\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n <label className=\"block text-sm font-semibold text-muted-foreground\">\n Code OTP\n </label>\n <div className=\"flex justify-center gap-3\" onPaste={handlePaste}>\n {Array.from({ length }).map((_, i) => {\n const filled = !!digits[i]?.trim();\n return (\n <input\n key={i}\n ref={(el) => {\n inputRefs.current[i] = el;\n }}\n type=\"text\"\n inputMode=\"numeric\"\n maxLength={1}\n value={digits[i]?.trim() || \"\"}\n onKeyDown={(e) => handleKeyDown(i, e)}\n onInput={(e) => handleInput(i, e)}\n onFocus={(e) => e.target.select()}\n disabled={disabled}\n className={cn(\n \"h-13 w-13 rounded-md border-2 text-center text-xl font-bold outline-none transition-all\",\n \"focus:border-primary focus:ring-2 focus:ring-primary/20 focus:scale-105\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n filled ? \"border-primary/30 bg-primary/5\" : \"border-border bg-background\",\n )}\n />\n );\n })}\n </div>\n <p className=\"text-center text-xs text-muted-foreground\">\n Faites <strong className=\"text-foreground\">#144*82#</strong> pour\n recevoir le code\n </p>\n </div>\n );\n}\n","import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface TransactionStatusProps {\n status: \"polling\" | \"success\" | \"error\";\n elapsedSeconds?: number;\n message?: string;\n errorMessage?: string;\n paymentUrl?: string | null;\n onRetry?: () => void;\n onClose?: () => void;\n onOpenPaymentUrl?: () => void;\n className?: string;\n}\n\nfunction Spinner({ className }: { className?: string }) {\n return (\n <svg\n className={cn(\"animate-spin\", className)}\n width=\"56\"\n height=\"56\"\n viewBox=\"0 0 56 56\"\n fill=\"none\"\n >\n <circle\n cx=\"28\"\n cy=\"28\"\n r=\"24\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n className=\"opacity-20\"\n />\n <path\n d=\"M28 4a24 24 0 0 1 24 24\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n strokeLinecap=\"round\"\n className=\"text-primary\"\n />\n </svg>\n );\n}\n\nexport function TransactionStatus({\n status,\n elapsedSeconds = 0,\n message,\n errorMessage,\n paymentUrl,\n onRetry,\n onClose,\n onOpenPaymentUrl,\n className,\n}: TransactionStatusProps) {\n if (status === \"polling\") {\n return (\n <div className={cn(\"flex flex-col items-center gap-4 py-8\", className)}>\n <Spinner />\n <div className=\"space-y-2 text-center\">\n <p className=\"text-base font-semibold text-foreground\">\n {paymentUrl\n ? \"Finalisez le paiement dans l'onglet ouvert...\"\n : \"Confirmez le paiement sur votre telephone...\"}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {paymentUrl\n ? \"Completez le paiement dans l'onglet, puis revenez ici.\"\n : \"Veuillez valider la transaction sur votre telephone.\"}\n </p>\n {elapsedSeconds > 0 && (\n <p className=\"text-xs text-muted-foreground/70\">\n Verification en cours... {elapsedSeconds}s\n </p>\n )}\n </div>\n {paymentUrl && (\n <div className=\"flex flex-col items-center gap-3\">\n <button\n type=\"button\"\n onClick={onOpenPaymentUrl}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-6 py-2.5 text-sm font-semibold text-primary-foreground transition-opacity hover:opacity-90\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n Ouvrir Wave pour payer\n </button>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-sm text-muted-foreground underline hover:text-foreground\"\n >\n Annuler\n </button>\n </div>\n )}\n </div>\n );\n }\n\n if (status === \"success\") {\n return (\n <div className={cn(\"flex flex-col items-center gap-4 py-8\", className)}>\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-emerald-500 animate-in zoom-in duration-500\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M5 12l5 5L20 7\"\n stroke=\"#fff\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n <div className=\"space-y-2 text-center animate-in fade-in slide-in-from-bottom-4 duration-400 delay-150\">\n <p className=\"text-lg font-bold text-foreground\">\n Paiement reussi !\n </p>\n {message && (\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n )}\n </div>\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md bg-primary px-6 py-2.5 text-sm font-semibold text-primary-foreground transition-opacity hover:opacity-90\"\n >\n Fermer\n </button>\n )}\n </div>\n );\n }\n\n // error\n return (\n <div className={cn(\"flex flex-col items-center gap-4 py-8\", className)}>\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-red-500 animate-in zoom-in duration-500\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M6 18L18 6M6 6l12 12\"\n stroke=\"#fff\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n />\n </svg>\n </div>\n <div className=\"space-y-2 text-center animate-in fade-in slide-in-from-bottom-4 duration-400 delay-150\">\n <p className=\"text-lg font-bold text-foreground\">\n Echec du paiement\n </p>\n {errorMessage && (\n <p className=\"text-sm text-muted-foreground\">{errorMessage}</p>\n )}\n </div>\n <div className=\"flex gap-3\">\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md border border-border bg-background px-5 py-2.5 text-sm font-semibold text-foreground transition-colors hover:bg-muted\"\n >\n Fermer\n </button>\n )}\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-md bg-primary px-5 py-2.5 text-sm font-semibold text-primary-foreground transition-opacity hover:opacity-90\"\n >\n Reessayer\n </button>\n )}\n </div>\n </div>\n );\n}\n","export function formatCFA(n: number): string {\n return new Intl.NumberFormat(\"fr-FR\").format(n);\n}\n","import type { PaymentProvider } from \"@applite/duticotac\";\n\nexport function getPhoneRegex(provider: PaymentProvider): RegExp {\n switch (provider) {\n case \"OM_CI\":\n return /^(\\+225)(07)[0-9]{8}$/;\n case \"MTN_CI\":\n return /^(\\+225)(05)[0-9]{8}$/;\n case \"MOOV_CI\":\n return /^(\\+225)(01)[0-9]{8}$/;\n default:\n return /^(\\+225)(07|05|01)[0-9]{8}$/;\n }\n}\n\nexport function validatePhone(\n phone: string,\n provider: PaymentProvider,\n): string | null {\n if (!phone) return \"Numéro de téléphone requis\";\n const intl = phone.startsWith(\"+225\") ? phone : `+225${phone}`;\n const cleaned = intl.replace(/\\s/g, \"\");\n if (!getPhoneRegex(provider).test(cleaned)) {\n return \"Numéro invalide pour ce provider\";\n }\n return null;\n}\n\nexport function normalizePhone(phone: string): string {\n const cleaned = phone.replace(/\\s/g, \"\");\n return cleaned.startsWith(\"+225\") ? cleaned : `+225${cleaned}`;\n}\n\nexport function needsOtp(provider: PaymentProvider): boolean {\n return provider === \"OM_CI\";\n}\n"],"mappings":"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","names":["React","import_duticotac","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|