PageSourceSearch

https://cdn.yoursash.com/assets/controllers/bulk_print_controller-f160fccb.js

js yoursash.com collected 2026-10-05 09:36:02 UTC 5,537 bytes, 167 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3export default class extends Controller {
4  static targets = ["container", "loading", "error", "form", "submitBtn"]
5
6  async open(event) {
7    event.preventDefault()
8    
9    // Find the modal element
10    const modalElement = document.getElementById('bulkPrintModal')
11    if (!modalElement) {
12      console.error("Bulk print modal not found")
13      return
14    }
15
16    this.resetUi(modalElement)
17    
18    const bulkSelectController = this.application.getControllerForElementAndIdentifier(
19      document.querySelector('[data-controller~="bulk-select"]'),
20      "bulk-select"
21    )
22    
23    const ids = bulkSelectController?.selectedIds || []
24    
25    if (!ids.length) {
26      alert("Please select at least one order")
27      return
28    }
29
30    // Show modal (Bootstrap 3)
31    window.jQuery(modalElement).modal("show")
32    
33    this.loading(modalElement).style.display = ""
34    this.form(modalElement).style.display = "none"
35    this.submitBtn(modalElement).disabled = true
36
37    try {
38      const url = this.data.get("ratesUrl")
39      const data = await this.postJSON(url, { ids })
40      this.renderRates(modalElement, data)
41    } catch(err) {
42      this.showError(modalElement, err.message || "Failed to fetch rates")
43    } finally {
44      this.loading(modalElement).style.display = "none"
45    }
46  }
47
48  resetUi(modal) {
49    this.container(modal).innerHTML = ""
50    const error = this.error(modal)
51    error.style.display = "none"
52    error.textContent = ""
53    this.loading(modal).style.display = "none"
54    this.form(modal).style.display = ""
55    this.submitBtn(modal).disabled = false
56  }
57
58  showError(modal, message) {
59    const error = this.error(modal)
60    error.textContent = message
61    error.style.display = ""
62  }
63
64  renderRates(modal, data) {
65    const container = this.container(modal)
66    container.innerHTML = ""
67    let index = 0
68    
69    Object.entries(data).forEach(([id, value]) => {
70      if (value.error) {
71        const errorDiv = document.createElement("div")
72        errorDiv.className = "alert alert-warning"
73        errorDiv.innerHTML = `<strong>Order #${id}:</strong> ${value.error}`
74        container.appendChild(errorDiv)
75        return
76      }
77
78      const rates = Array.isArray(value.rates) ? value.rates : JSON.parse(value.rates || "[]")
79      let ratesOptions = ""
80      rates.forEach(rate => {
81        const prettyName = rate.ServiceTypePretty || rate.ServiceDescription || `${rate.ServiceType} ${rate.PackageType}`
82        ratesOptions += `<option value='${JSON.stringify(rate)}'>${prettyName} - $${rate.Amount} - ${rate.DeliverDays} days</option>`
83      })
84
85      const itemDiv = document.createElement("div")
86      itemDiv.className = "well well-sm"
87      itemDiv.innerHTML = `
88        <div style="margin-bottom: 10px;">
89          <span class='strong'>Order #</span>${id} 
90          <span class='strong'>Due Date:</span> ${value.due} 
91          <span class='strong'>Quantity:</span> ${value.quantity}
92          <input type='hidden' value='${id}' name='bulk_rate[${index}][id]'>
93        </div>
94        <div>
95          <select name='bulk_rate[${index}][rate]' class="form-control" style="width: 100%;">
96            ${ratesOptions}
97          </select>
98        </div>
99      `
100      container.appendChild(itemDiv)
101      index++
102    })
103
104    this.form(modal).style.display = ""
105    this.submitBtn(modal).disabled = false
106  }
107
108  async submit(event) {
109    event.preventDefault()
110    const modal = document.getElementById('bulkPrintModal')
111    const submitBtn = this.submitBtn(modal)
112
113    submitBtn.disabled = true
114    submitBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i> Processing...'
115    
116    try {
117      const url = this.data.get("printUrl")
118      const formData = new FormData(this.form(modal))
119      
120      const response = await fetch(url, {
121        method: "POST",
122        headers: { 
123          "X-CSRF-Token": document.querySelector('meta[name="csrf-token"]')?.content 
124        },
125        body: formData
126      })
127      
128      const data = await response.json()
129      
130      if (data && data.error) {
131        throw new Error(data.error)
132      } else if (data && data.url) {
133        window.open(data.url)
134        window.location.reload()
135      } else {
136        throw new Error("Label generation failed (no URL returned)")
137      }
138    } catch(err) {
139      this.showError(modal, err.message || "Failed to print labels")
140      submitBtn.disabled = false
141      submitBtn.innerHTML = '<i class="fa fa-print"></i> Purchase & Print Selected Labels'
142    }
143  }
144
145  // Helper methods to find targets in the modal since they are outside our controller scope
146  container(modal) { return modal.querySelector('[data-bulk-print-target="container"]') }
147  loading(modal)   { return modal.querySelector('[data-bulk-print-target="loading"]') }
148  error(modal)     { return modal.querySelector('[data-bulk-print-target="error"]') }
149  form(modal)      { return modal.querySelector('[data-bulk-print-target="form"]') }
150  submitBtn(modal) { return modal.querySelector('[data-bulk-print-target="submitBtn"]') }
151
152  async postJSON(url, payload) {
153    const token = document.querySelector('meta[name="csrf-token"]')?.content
154    const resp = await fetch(url, {
155      method: "POST",
156      headers: { 
157        "Content-Type": "application/json", 
158        "X-CSRF-Token": token 
159      },
160      body: JSON.stringify(payload || {})
161    })
162    
163    const data = await resp.json().catch(() => ({}))
164    if (!resp.ok) throw new Error(data.error || "Request failed")
165    return data
166  }
167}

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.