@@ -549,12 +549,26 @@ function showCreditTopup(conversationId) {
549549 <button class="credit-btn" data-cents="2500">$25</button>
550550 <button class="credit-btn" data-cents="5000">$50</button>
551551 </div>
552+ <div class="credits-dropdown-custom">
553+ <span>$</span>
554+ <input type="number" min="5" max="1000" step="1" placeholder="custom" class="credits-custom-input" />
555+ <button class="credit-btn credits-custom-btn">add</button>
556+ </div>
552557 <div class="credit-topup-status"></div>
553558 </div>
554559 ` ;
555- el . querySelectorAll ( '.credit-btn' ) . forEach ( ( btn ) => {
560+ el . querySelectorAll ( '.credit-btn[data-cents] ' ) . forEach ( ( btn ) => {
556561 btn . addEventListener ( 'click' , ( ) => handleCreditTopup ( el , Number ( btn . dataset . cents ) , conversationId ) ) ;
557562 } ) ;
563+ const customBtn = el . querySelector ( '.credits-custom-btn' ) ;
564+ const customInput = el . querySelector ( '.credits-custom-input' ) ;
565+ if ( customBtn && customInput ) {
566+ customBtn . addEventListener ( 'click' , ( ) => {
567+ const dollars = parseInt ( customInput . value , 10 ) ;
568+ if ( ! dollars || dollars < 5 || dollars > 1000 ) { customInput . focus ( ) ; return ; }
569+ handleCreditTopup ( el , dollars * 100 , conversationId ) ;
570+ } ) ;
571+ }
558572 const messagesEl = $ ( 'branch-messages' ) ;
559573 if ( messagesEl ) {
560574 messagesEl . appendChild ( el ) ;
@@ -582,7 +596,7 @@ async function handleCreditTopup(widget, amountCents, conversationId) {
582596 buttons . forEach ( ( b ) => { b . disabled = false ; } ) ;
583597 return ;
584598 }
585- statusEl . textContent = `Added $${ ( amountCents / 100 ) . toFixed ( 2 ) } in credits. You can continue working.` ;
599+ statusEl . textContent = `Added $${ amountCents / 100 } in credits. You can continue working.` ;
586600 statusEl . className = 'credit-topup-status success' ;
587601 } catch ( err ) {
588602 statusEl . textContent = 'Network error — try again' ;
@@ -1766,43 +1780,57 @@ else if (mobileMq.addListener) mobileMq.addListener(syncViewportMode);
17661780 document . addEventListener ( 'click' , ( ) => dropdown . classList . remove ( 'open' ) ) ;
17671781 dropdown . addEventListener ( 'click' , ( e ) => e . stopPropagation ( ) ) ;
17681782
1769- dropdown . querySelectorAll ( '.credit-btn' ) . forEach ( ( btn ) => {
1770- btn . addEventListener ( 'click' , ( ) => {
1771- const cents = Number ( btn . dataset . cents ) ;
1772- const statusEl = $ ( 'credits-dropdown-status' ) ;
1773- const buttons = dropdown . querySelectorAll ( '.credit-btn' ) ;
1774- buttons . forEach ( ( b ) => { b . disabled = true ; } ) ;
1775- statusEl . textContent = 'Charging card...' ;
1776- statusEl . className = 'credits-dropdown-status' ;
1777-
1778- fetch ( `${ API } /topup-credits` , {
1779- method : 'POST' ,
1780- headers : { 'Content-Type' : 'application/json' } ,
1781- body : JSON . stringify ( { amountCents : cents } ) ,
1782- } )
1783- . then ( ( r ) => r . json ( ) . then ( ( d ) => ( { ok : r . ok , data : d } ) ) )
1784- . then ( ( { ok, data } ) => {
1785- if ( ! ok ) {
1786- statusEl . textContent = data . error || 'Top-up failed' ;
1787- statusEl . className = 'credits-dropdown-status error' ;
1788- buttons . forEach ( ( b ) => { b . disabled = false ; } ) ;
1789- } else {
1790- statusEl . textContent = `Added $${ ( cents / 100 ) . toFixed ( 2 ) } ` ;
1791- statusEl . className = 'credits-dropdown-status success' ;
1792- setTimeout ( ( ) => {
1793- dropdown . classList . remove ( 'open' ) ;
1794- statusEl . textContent = '' ;
1795- buttons . forEach ( ( b ) => { b . disabled = false ; } ) ;
1796- } , 2000 ) ;
1797- }
1798- } )
1799- . catch ( ( ) => {
1800- statusEl . textContent = 'Network error' ;
1783+ function chargeDropdown ( cents ) {
1784+ const statusEl = $ ( 'credits-dropdown-status' ) ;
1785+ const buttons = dropdown . querySelectorAll ( '.credit-btn' ) ;
1786+ buttons . forEach ( ( b ) => { b . disabled = true ; } ) ;
1787+ statusEl . textContent = 'Charging card...' ;
1788+ statusEl . className = 'credits-dropdown-status' ;
1789+
1790+ fetch ( `${ API } /topup-credits` , {
1791+ method : 'POST' ,
1792+ headers : { 'Content-Type' : 'application/json' } ,
1793+ body : JSON . stringify ( { amountCents : cents } ) ,
1794+ } )
1795+ . then ( ( r ) => r . json ( ) . then ( ( d ) => ( { ok : r . ok , data : d } ) ) )
1796+ . then ( ( { ok, data } ) => {
1797+ if ( ! ok ) {
1798+ statusEl . textContent = data . error || 'Top-up failed' ;
18011799 statusEl . className = 'credits-dropdown-status error' ;
18021800 buttons . forEach ( ( b ) => { b . disabled = false ; } ) ;
1803- } ) ;
1804- } ) ;
1801+ } else {
1802+ statusEl . textContent = `Added $${ ( cents / 100 ) } ` ;
1803+ statusEl . className = 'credits-dropdown-status success' ;
1804+ setTimeout ( ( ) => {
1805+ dropdown . classList . remove ( 'open' ) ;
1806+ statusEl . textContent = '' ;
1807+ buttons . forEach ( ( b ) => { b . disabled = false ; } ) ;
1808+ } , 2000 ) ;
1809+ }
1810+ } )
1811+ . catch ( ( ) => {
1812+ statusEl . textContent = 'Network error' ;
1813+ statusEl . className = 'credits-dropdown-status error' ;
1814+ buttons . forEach ( ( b ) => { b . disabled = false ; } ) ;
1815+ } ) ;
1816+ }
1817+
1818+ dropdown . querySelectorAll ( '.credit-btn[data-cents]' ) . forEach ( ( btn ) => {
1819+ btn . addEventListener ( 'click' , ( ) => chargeDropdown ( Number ( btn . dataset . cents ) ) ) ;
18051820 } ) ;
1821+
1822+ const customBtn = $ ( 'credits-custom-btn' ) ;
1823+ const customInput = $ ( 'credits-custom-amount' ) ;
1824+ if ( customBtn && customInput ) {
1825+ customBtn . addEventListener ( 'click' , ( ) => {
1826+ const dollars = parseInt ( customInput . value , 10 ) ;
1827+ if ( ! dollars || dollars < 5 || dollars > 1000 ) { customInput . focus ( ) ; return ; }
1828+ chargeDropdown ( dollars * 100 ) ;
1829+ } ) ;
1830+ customInput . addEventListener ( 'keydown' , ( e ) => {
1831+ if ( e . key === 'Enter' ) customBtn . click ( ) ;
1832+ } ) ;
1833+ }
18061834} ) ( ) ;
18071835
18081836// =============================================================================
0 commit comments