mirror of
https://github.com/we-promise/sure.git
synced 2026-05-10 06:05:00 +00:00
* Complete Sophtron account mapping * Clarify Sophtron login challenge flow * Add Sophtron connection UI timeout * Treat Sophtron timeout jobs as failed * Reset failed Sophtron connection state * Handle stale Sophtron connection jobs * Advance Sophtron polling timeout * Shorten Sophtron connection timeout * Fix Sophtron modal polling updates * Stabilize Sophtron MFA polling * Give Sophtron OTP challenges more time * Clarify Sophtron institution login failures * Extend Sophtron polling during login progress * Probe Sophtron accounts after completed MFA step * Align Sophtron dialogs with design system * Start Sophtron initial load after linking accounts * Fix Sophtron initial transaction load * Fail Sophtron sync without institution connection * Fix tests * Wrap Sophtron account linking in transaction * Wrap Sophtron provider responses * Fix Sophtron MFA security tests * Guard Sophtron MFA challenge arrays * Respect Sophtron initial load window * Use unique Sophtron MFA answer field ids * Address Sophtron review follow-ups * Fix Sophtron transaction sync refresh * Avoid blocking Sophtron refresh polling * Move Sophtron account helpers to model * Keep Sophtron grouping provider-level * Start new Sophtron institution links * Isolate Sophtron institution connections --------- Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
115 lines
2.7 KiB
JavaScript
115 lines
2.7 KiB
JavaScript
import { Controller } from "@hotwired/stimulus";
|
|
|
|
// Connects to data-controller="polling"
|
|
// Automatically refreshes a turbo frame at a specified interval
|
|
export default class extends Controller {
|
|
static values = {
|
|
url: String,
|
|
interval: { type: Number, default: 3000 },
|
|
frameId: String,
|
|
};
|
|
|
|
connect() {
|
|
this.startPolling();
|
|
}
|
|
|
|
disconnect() {
|
|
this.stopPolling();
|
|
}
|
|
|
|
startPolling() {
|
|
if (!this.hasUrlValue) return;
|
|
|
|
this.poll = setInterval(() => {
|
|
this.refresh();
|
|
}, this.intervalValue);
|
|
}
|
|
|
|
stopPolling() {
|
|
if (this.poll) {
|
|
clearInterval(this.poll);
|
|
this.poll = null;
|
|
}
|
|
}
|
|
|
|
async refresh() {
|
|
try {
|
|
const frame = this.frameElement();
|
|
if (!frame) {
|
|
this.stopPolling();
|
|
return;
|
|
}
|
|
|
|
const response = await fetch(this.urlValue, {
|
|
headers: {
|
|
Accept: "text/html",
|
|
"Turbo-Frame": frame.id,
|
|
},
|
|
});
|
|
|
|
if (response.ok) {
|
|
const html = await response.text();
|
|
const template = document.createElement("template");
|
|
template.innerHTML = html;
|
|
|
|
const newFrame = template.content.querySelector(
|
|
`turbo-frame#${this.cssEscape(frame.id)}`,
|
|
);
|
|
if (newFrame) {
|
|
if (frame === this.element) {
|
|
this.syncPollingAttributes(newFrame);
|
|
}
|
|
frame.innerHTML = newFrame.innerHTML;
|
|
|
|
// Check if we should stop polling (no more pending/processing exports)
|
|
if (
|
|
frame === this.element &&
|
|
!newFrame.hasAttribute("data-polling-url-value")
|
|
) {
|
|
this.stopPolling();
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Polling error:", error);
|
|
}
|
|
}
|
|
|
|
frameElement() {
|
|
if (this.hasFrameIdValue) {
|
|
return document.getElementById(this.frameIdValue);
|
|
}
|
|
|
|
if (this.element.tagName.toLowerCase() === "turbo-frame") {
|
|
return this.element;
|
|
}
|
|
|
|
return this.element.closest("turbo-frame");
|
|
}
|
|
|
|
cssEscape(value) {
|
|
if (window.CSS?.escape) return CSS.escape(value);
|
|
|
|
return value.replaceAll('"', '\\"');
|
|
}
|
|
|
|
syncPollingAttributes(newFrame) {
|
|
const pollingUrl = newFrame.getAttribute("data-polling-url-value");
|
|
const pollingInterval = newFrame.getAttribute(
|
|
"data-polling-interval-value",
|
|
);
|
|
|
|
if (pollingUrl) {
|
|
this.element.setAttribute("data-polling-url-value", pollingUrl);
|
|
} else {
|
|
this.element.removeAttribute("data-polling-url-value");
|
|
}
|
|
|
|
if (pollingInterval) {
|
|
this.element.setAttribute("data-polling-interval-value", pollingInterval);
|
|
} else {
|
|
this.element.removeAttribute("data-polling-interval-value");
|
|
}
|
|
}
|
|
}
|