PageSourceSearch

https://unicheckgh.com/assets/controllers/wizard_controller-b4bb6830.js

js unicheckgh.com collected 2026-09-24 14:20:20 UTC 4,556 bytes, 143 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3export default class extends Controller {
4  static targets = ["step", "prevButton", "nextButton", "submitButton", "nonFormContent"]
5  
6  connect() {
7    this.currentStep = 1
8    this.totalSteps = this.stepTargets.length
9    this.updateButtons()
10  }
11
12  next() {
13    if (this.validateCurrentStep() && this.currentStep < this.totalSteps) {
14      this.stepTargets[this.currentStep - 1].classList.add('hidden')
15      this.stepTargets[this.currentStep].classList.remove('hidden')
16      this.currentStep++
17      this.updateButtons()
18      
19      // Scroll to the top of the form container for better user experience
20      this.scrollToFormTop()
21      
22      // If we're now on the electives step (step 4), trigger electives loading
23      if (this.currentStep === 4) {
24        this.loadElectivesIfNeeded()
25      }
26    }
27  }
28
29  prev() {
30    if (this.currentStep > 1) {
31      this.stepTargets[this.currentStep - 1].classList.add('hidden')
32      this.stepTargets[this.currentStep - 2].classList.remove('hidden')
33      this.currentStep--
34      this.updateButtons()
35      
36      // Scroll to the top of the form container for better user experience
37      this.scrollToFormTop()
38      
39      // If we've navigated back to the electives step, ensure electives are loaded
40      if (this.currentStep === 4) {
41        this.loadElectivesIfNeeded()
42      }
43    }
44  }
45  
46  scrollToFormTop() {
47    // Find the form container or the first step element
48    const formContainer = this.element.closest('form') || this.stepTargets[0].closest('form') || this.element
49    
50    // Scroll to the top of the form container with smooth behavior
51    formContainer.scrollIntoView({ behavior: 'smooth', block: 'start' })
52  }
53  
54  loadElectivesIfNeeded() {
55    // Find the qualification controller to load electives
56    const qualificationController = this.application.getControllerForElementAndIdentifier(
57      document.querySelector('[data-controller*="qualification"]'),
58      'qualification'
59    )
60    
61    // If we found the controller and it has the loadElectives method, call it
62    if (qualificationController && typeof qualificationController.loadElectives === 'function') {
63      console.log('Wizard controller: triggering electives load for step 4')
64      qualificationController.loadElectives(true) // Force reload
65    }
66  }
67
68  validateCurrentStep() {
69    const currentStepEl = this.stepTargets[this.currentStep - 1]
70    const requiredFields = currentStepEl.querySelectorAll('select[required], input[required]')
71    let isValid = true
72
73    requiredFields.forEach(field => {
74      if (!field.value) {
75        isValid = false
76        this.showError(field)
77      } else {
78        this.clearError(field)
79      }
80    })
81
82    // Special validation for electives
83    if (this.currentStep === 4) {
84      const checkedElectives = currentStepEl.querySelectorAll('input[type="checkbox"]:checked').length
85      const compulsoryElectives = currentStepEl.querySelectorAll('.compulsory-elective').length
86      const totalElectives = checkedElectives + compulsoryElectives
87
88      if (totalElectives < 2) {
89        alert("Please select at least 2 elective subjects in total")
90        isValid = false
91      }
92    }
93
94    return isValid
95  }
96
97  showError(field) {
98    field.classList.add('border-red-500')
99    const errorMsg = document.createElement('p')
100    errorMsg.className = 'text-red-500 text-sm mt-1'
101    errorMsg.textContent = 'This field is required'
102    
103    // Remove any existing error message
104    this.clearError(field)
105    
106    field.parentNode.appendChild(errorMsg)
107  }
108
109  clearError(field) {
110    field.classList.remove('border-red-500')
111    const existingError = field.parentNode.querySelector('.text-red-500')
112    if (existingError) {
113      existingError.remove()
114    }
115  }
116
117  updateButtons() {
118    if (this.currentStep === 1) {
119      this.prevButtonTarget.classList.add('hidden')
120    } else {
121      this.prevButtonTarget.classList.remove('hidden')
122    }
123
124    if (this.currentStep === this.totalSteps) {
125      this.nextButtonTarget.classList.add('hidden')
126      this.submitButtonTarget.classList.remove('hidden')
127    } else {
128      this.nextButtonTarget.classList.remove('hidden')
129      this.submitButtonTarget.classList.add('hidden')
130    }
131
132    this.updateNonFormContentVisibility()
133  }
134
135  updateNonFormContentVisibility() {
136    if (!this.hasNonFormContentTarget) return
137
138    const shouldHide = this.currentStep > 1
139    this.nonFormContentTargets.forEach(element => {
140      element.classList.toggle('hidden', shouldHide)
141    })
142  }
143} 

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.