mirror of
https://github.com/we-promise/sure.git
synced 2026-04-08 14:54:49 +00:00
* Initial implementation * Add support for reports section too * UI Improvement now it looks a lot nicer :) * Remove duplicate section titles * FIX malformed DIV * Add accessibility and touch support WCAG 2.1 Level AA Compliant - Keyboard operable (Success Criterion 2.1.1) - Focus visible (Success Criterion 2.4.7) - Name, Role, Value (Success Criterion 4.1.2) Screen Reader Support - Clear instructions in aria-label - Proper semantic roles - State changes announced via aria-grabbed * Add proper UI for tab highlight * Add keyboard support to collapse also * FIX js errors * Fix rabbit * FIX we don't need the html * FIX CSRF and error handling * Simplify into one single DB migration --------- Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
98 lines
2.4 KiB
JavaScript
98 lines
2.4 KiB
JavaScript
import { Controller } from "@hotwired/stimulus";
|
|
|
|
export default class extends Controller {
|
|
static targets = ["content", "chevron", "button"];
|
|
static values = {
|
|
sectionKey: String,
|
|
collapsed: Boolean,
|
|
};
|
|
|
|
connect() {
|
|
if (this.collapsedValue) {
|
|
this.collapse(false);
|
|
}
|
|
}
|
|
|
|
toggle(event) {
|
|
event.preventDefault();
|
|
if (this.collapsedValue) {
|
|
this.expand();
|
|
} else {
|
|
this.collapse();
|
|
}
|
|
}
|
|
|
|
handleToggleKeydown(event) {
|
|
// Handle Enter and Space keys for keyboard accessibility
|
|
if (event.key === "Enter" || event.key === " ") {
|
|
event.preventDefault();
|
|
event.stopPropagation(); // Prevent section's keyboard handler from firing
|
|
this.toggle(event);
|
|
}
|
|
}
|
|
|
|
collapse(persist = true) {
|
|
this.contentTarget.classList.add("hidden");
|
|
this.chevronTarget.classList.add("rotate-180");
|
|
this.collapsedValue = true;
|
|
if (this.hasButtonTarget) {
|
|
this.buttonTarget.setAttribute("aria-expanded", "false");
|
|
}
|
|
if (persist) {
|
|
this.savePreference(true);
|
|
}
|
|
}
|
|
|
|
expand() {
|
|
this.contentTarget.classList.remove("hidden");
|
|
this.chevronTarget.classList.remove("rotate-180");
|
|
this.collapsedValue = false;
|
|
if (this.hasButtonTarget) {
|
|
this.buttonTarget.setAttribute("aria-expanded", "true");
|
|
}
|
|
this.savePreference(false);
|
|
}
|
|
|
|
async savePreference(collapsed) {
|
|
const preferences = {
|
|
reports_collapsed_sections: {
|
|
[this.sectionKeyValue]: collapsed,
|
|
},
|
|
};
|
|
|
|
// Safely obtain CSRF token
|
|
const csrfToken = document.querySelector('meta[name="csrf-token"]');
|
|
if (!csrfToken) {
|
|
console.error(
|
|
"[Reports Section] CSRF token not found. Cannot save preferences.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch("/reports/update_preferences", {
|
|
method: "PATCH",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"X-CSRF-Token": csrfToken.content,
|
|
},
|
|
body: JSON.stringify({ preferences }),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
console.error(
|
|
"[Reports Section] Failed to save preferences:",
|
|
response.status,
|
|
errorData,
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error(
|
|
"[Reports Section] Network error saving preferences:",
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
}
|