@@ -170,6 +170,194 @@ dcrTriggers.forEach((t) => {
170170 ) ;
171171 } ) ;
172172} ) ;
173+
174+ /* Handle credential selection visibility in portal_checkout.tmpl
175+ * HTML is server-rendered, JS only handles show/hide interactivity
176+ */
177+
178+ /* Toggle between create_new and reuse_existing credential options */
179+ document . addEventListener ( 'change' , ( e ) => {
180+ if ( e . target . name !== 'credential_action' ) return ;
181+
182+ const container = e . target . closest ( '.app-credentials' ) ;
183+ if ( ! container ) return ;
184+
185+ const selectDiv = container . querySelector ( '[id^="credential-select-"]' ) ;
186+ const infoDiv = container . querySelector ( '[id^="new-credential-info-"]' ) ;
187+ const dropdownBtn = container . querySelector ( '.credential-dropdown .dropdown-toggle' ) ;
188+ const hiddenInput = container . querySelector ( 'input[name="credential_id"]' ) ;
189+
190+ const isReuse = e . target . value === 'reuse_existing' ;
191+
192+ if ( selectDiv ) {
193+ selectDiv . classList . toggle ( 'd-none' , ! isReuse ) ;
194+ selectDiv . classList . toggle ( 'd-block' , isReuse ) ;
195+ }
196+ if ( infoDiv ) {
197+ infoDiv . classList . toggle ( 'd-none' , isReuse ) ;
198+ infoDiv . classList . toggle ( 'd-block' , ! isReuse ) ;
199+ }
200+ if ( dropdownBtn ) {
201+ dropdownBtn . disabled = ! isReuse ;
202+ if ( ! isReuse ) {
203+ // Reset dropdown to placeholder
204+ dropdownBtn . innerHTML = '<span class="placeholder-text">Select a credential</span>' ;
205+ if ( hiddenInput ) hiddenInput . value = '' ;
206+ }
207+ }
208+ } ) ;
209+
210+ /* Handle credential dropdown item selection */
211+ document . addEventListener ( 'click' , ( e ) => {
212+ const dropdownItem = e . target . closest ( '.credential-dropdown .dropdown-item' ) ;
213+ if ( ! dropdownItem ) return ;
214+
215+ e . preventDefault ( ) ;
216+
217+ const dropdown = dropdownItem . closest ( '.credential-dropdown' ) ;
218+ const dropdownBtn = dropdown . querySelector ( '.dropdown-toggle' ) ;
219+ const hiddenInput = dropdown . querySelector ( 'input[name="credential_id"]' ) ;
220+
221+ const credId = dropdownItem . dataset . value ;
222+ const displayName = dropdownItem . dataset . displayName ;
223+ const plan = dropdownItem . dataset . plan ;
224+ const authType = dropdownItem . dataset . auth ;
225+
226+ // Update hidden input
227+ if ( hiddenInput ) hiddenInput . value = credId ;
228+
229+ // Update button content to show selected credential
230+ dropdownBtn . innerHTML = `
231+ <span class="selected-content">
232+ <span class="credential-label">${ displayName } | ${ plan } </span>
233+ <span class="pill">${ authType } </span>
234+ </span>
235+ ` ;
236+
237+ // Mark item as active
238+ dropdown . querySelectorAll ( '.dropdown-item' ) . forEach ( item => item . classList . remove ( 'active' ) ) ;
239+ dropdownItem . classList . add ( 'active' ) ;
240+ } ) ;
241+
242+ /* Handle app-action radio button changes (create new app vs existing app) */
243+ const appActionRadios = document . querySelectorAll ( 'input[name="app-action"]' ) ;
244+ appActionRadios . forEach ( ( radio ) => {
245+ radio . addEventListener ( "change" , ( e ) => {
246+ const form = e . target . closest ( "form" ) ;
247+ if ( ! form ) return ;
248+
249+ const credentialSection = form . querySelector ( ".credential-selection-section" ) ;
250+ if ( ! credentialSection ) return ;
251+
252+ const newAppCredentials = credentialSection . querySelector ( ".new-app-credentials" ) ;
253+ const allAppCredentials = credentialSection . querySelectorAll ( ".app-credentials" ) ;
254+
255+ if ( e . target . value === "create" ) {
256+ // Show new app credentials section
257+ if ( newAppCredentials ) newAppCredentials . style . display = "block" ;
258+ allAppCredentials . forEach ( ( div ) => {
259+ div . style . display = "none" ;
260+ // Disable credential dropdown when creating new app
261+ const dropdownBtn = div . querySelector ( '.credential-dropdown .dropdown-toggle' ) ;
262+ if ( dropdownBtn ) {
263+ dropdownBtn . disabled = true ;
264+ }
265+ } ) ;
266+ } else if ( e . target . value === "existing" ) {
267+ // Hide new app credentials section
268+ if ( newAppCredentials ) newAppCredentials . style . display = "none" ;
269+
270+ // Show credentials for the selected app
271+ const appSelect = form . querySelector ( "#appsControlSelect" ) ;
272+ if ( appSelect && appSelect . value ) {
273+ showCredentialsForApp ( appSelect , appSelect . value ) ;
274+ }
275+ }
276+ } ) ;
277+ } ) ;
278+
279+ /* Handle app selection changes to show correct credentials */
280+ const appSelects = document . querySelectorAll ( "#appsControlSelect" ) ;
281+ appSelects . forEach ( ( appSelect ) => {
282+ // Listen for app selection changes
283+ appSelect . addEventListener ( "change" , ( e ) => {
284+ const selectedAppId = e . target . value ;
285+ showCredentialsForApp ( e . target , selectedAppId ) ;
286+ } ) ;
287+
288+ // Initialize: disable all credential dropdowns and hidden inputs except for currently selected app
289+ const form = appSelect . closest ( "form" ) ;
290+ if ( form ) {
291+ const credentialSection = form . querySelector ( ".credential-selection-section" ) ;
292+ if ( credentialSection ) {
293+ const allAppCredentials = credentialSection . querySelectorAll ( ".app-credentials" ) ;
294+ allAppCredentials . forEach ( ( div ) => {
295+ const dropdownBtn = div . querySelector ( '.credential-dropdown .dropdown-toggle' ) ;
296+ if ( dropdownBtn ) {
297+ dropdownBtn . disabled = true ;
298+ }
299+ // Disable hidden inputs so they don't get submitted with the form
300+ const hiddenInput = div . querySelector ( 'input[name="credential_id"]' ) ;
301+ if ( hiddenInput ) {
302+ hiddenInput . disabled = true ;
303+ }
304+ } ) ;
305+
306+ // If an app is already selected, enable its credential dropdown and hidden input
307+ if ( appSelect . value ) {
308+ const selectedAppCredentials = credentialSection . querySelector ( `.app-credentials[data-app-id="${ appSelect . value } "]` ) ;
309+ if ( selectedAppCredentials ) {
310+ const dropdownBtn = selectedAppCredentials . querySelector ( '.credential-dropdown .dropdown-toggle' ) ;
311+ if ( dropdownBtn ) {
312+ dropdownBtn . disabled = false ;
313+ }
314+ // Enable the hidden input for the selected app
315+ const hiddenInput = selectedAppCredentials . querySelector ( 'input[name="credential_id"]' ) ;
316+ if ( hiddenInput ) {
317+ hiddenInput . disabled = false ;
318+ }
319+ }
320+ }
321+ }
322+ }
323+ } ) ;
324+
325+ /* Show credentials section for selected app (HTML is server-rendered) */
326+ function showCredentialsForApp ( appSelectElement , appId ) {
327+ const form = appSelectElement . closest ( "form" ) ;
328+ if ( ! form ) return ;
329+
330+ const credentialSection = form . querySelector ( ".credential-selection-section" ) ;
331+ if ( ! credentialSection ) return ;
332+
333+ // Hide all app-credentials divs, disable their dropdowns and hidden inputs
334+ credentialSection . querySelectorAll ( ".app-credentials" ) . forEach ( ( div ) => {
335+ div . style . display = "none" ;
336+ const dropdownBtn = div . querySelector ( '.credential-dropdown .dropdown-toggle' ) ;
337+ if ( dropdownBtn ) dropdownBtn . disabled = true ;
338+ // Disable hidden inputs so they don't get submitted with the form
339+ const hiddenInput = div . querySelector ( 'input[name="credential_id"]' ) ;
340+ if ( hiddenInput ) hiddenInput . disabled = true ;
341+ } ) ;
342+
343+ // Show the credentials div for the selected app
344+ const selectedAppCredentials = credentialSection . querySelector ( `.app-credentials[data-app-id="${ appId } "]` ) ;
345+ if ( ! selectedAppCredentials ) return ;
346+
347+ selectedAppCredentials . style . display = "block" ;
348+
349+ // Enable the hidden input for the selected app so it gets submitted
350+ const selectedHiddenInput = selectedAppCredentials . querySelector ( 'input[name="credential_id"]' ) ;
351+ if ( selectedHiddenInput ) selectedHiddenInput . disabled = false ;
352+
353+ // Enable dropdown only if "reuse_existing" is selected
354+ const dropdownBtn = selectedAppCredentials . querySelector ( '.credential-dropdown .dropdown-toggle' ) ;
355+ const reuseRadio = selectedAppCredentials . querySelector ( 'input[name="credential_action"][value="reuse_existing"]' ) ;
356+ if ( dropdownBtn && reuseRadio && reuseRadio . checked ) {
357+ dropdownBtn . disabled = false ;
358+ }
359+ }
360+
173361//sidebar active
174362let id = "/portal" + window . location . href . split ( "/portal" ) [ 1 ] ;
175363if ( id . includes ( "users" ) ) {
@@ -256,3 +444,33 @@ FilterObserver(
256444 "apps-filter-latency-chart" ,
257445 FilterObserverHanlderForLatencyChart
258446) ;
447+
448+ $ ( document ) . on ( 'show.bs.modal' , '[id^="change-plan-"]' , function ( ) {
449+ const modal = $ ( this ) ;
450+ const plansGrid = modal . find ( '.plans-grid' ) ;
451+ const hiddenInput = modal . find ( 'input[type="hidden"][name="new_plan_id"]' ) ;
452+ const submitBtn = modal . find ( 'button[type="submit"]' ) ;
453+
454+ plansGrid . find ( '.plan-card' ) . on ( 'click' , function ( ) {
455+ if ( $ ( this ) . hasClass ( 'disabled' ) || $ ( this ) . data ( 'is-current' ) ) {
456+ return ;
457+ }
458+
459+ const planId = $ ( this ) . data ( 'plan-id' ) ;
460+ plansGrid . find ( '.plan-card' ) . removeClass ( 'selected' ) ;
461+ $ ( this ) . addClass ( 'selected' ) ;
462+ hiddenInput . val ( planId ) ;
463+ submitBtn . prop ( 'disabled' , false ) ;
464+ } ) ;
465+ } ) ;
466+
467+ $ ( document ) . on ( 'hidden.bs.modal' , '[id^="change-plan-"]' , function ( ) {
468+ const modal = $ ( this ) ;
469+ const plansGrid = modal . find ( '.plans-grid' ) ;
470+ const hiddenInput = modal . find ( 'input[type="hidden"][name="new_plan_id"]' ) ;
471+ const submitBtn = modal . find ( 'button[type="submit"]' ) ;
472+
473+ plansGrid . find ( '.plan-card' ) . removeClass ( 'selected' ) ;
474+ hiddenInput . val ( '' ) ;
475+ submitBtn . prop ( 'disabled' , true ) ;
476+ } ) ;
0 commit comments