Files
Claper/assets/js/hooks.js
Alex Lion 5bd4793b6e Version 2.4.0
## ⚠️ Breaking changes

- S3 variables are now named: S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_REGION and S3_BUCKET
- Users now have roles. Refer to the `roles` table and assign a role to a user with the `role_id` column in the `users` table.

## Features

- Add Admin Panel to manage users and presentations
- Add user roles: user, admin
- Add `LANGUAGES` setting to configure available languages in the app
- Add hideable presenter attendee count (#183 #155)
- Add Hungarian translation (#161)
- Add Latvian translation (#163)
- Add custom S3 endpoint with `S3_SCHEME`, `S3_HOST`, `S3_PORT` and `S3_PUBLIC_URL`

## Fixes and improvements

- Upgrade JS dependencies
- Upgrade Elixir dependencies, including Phoenix Live View to 1.0.17
- Upgrade to Tailwind 4+
- Refactor view templates to use {} instead of <%= %>
- Fix event name validation to be required
- Docker image is now using Ubuntu instead of Alpine for better dependencies support
- Fix scrollbar not showing in event manager when no presentation file (#164) (@aryel780)
- Fix settings scroll for small screen (#168)
- Fix duplicate key quiz when duplicate (#182)
- Fix email change confirmation (#172)
- Fix italian translation (#179)
- Fix random poll choices (#184)
2025-12-26 14:46:16 +01:00

198 lines
5.3 KiB
JavaScript

// LiveView hooks for client-side functionality
const Hooks = {
// Hook for handling CSV downloads from LiveView
CSVDownloader: {
mounted() {
this.handleEvent("download_csv", ({ filename, content }) => {
// Create a Blob with the CSV content
const blob = new Blob([content], { type: "text/csv" });
// Create a temporary URL for the Blob
const url = window.URL.createObjectURL(blob);
// Create a temporary link element
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", filename);
// Append the link to the document body
document.body.appendChild(link);
// Trigger the download
link.click();
// Clean up
window.URL.revokeObjectURL(url);
document.body.removeChild(link);
});
}
},
// Hook for User Growth Chart
UserGrowthChart: {
mounted() {
// Import Chart.js dynamically
import("chart.js/auto").then(({ default: Chart }) => {
const ctx = this.el.getContext("2d");
const labels = JSON.parse(this.el.dataset.labels);
const values = JSON.parse(this.el.dataset.values);
this.chart = new Chart(ctx, {
type: "line",
data: {
labels: labels,
datasets: [{
label: "New Users",
data: values,
borderColor: "#111827",
backgroundColor: "rgba(17, 24, 39, 0.05)",
borderWidth: 2,
tension: 0.4,
fill: true,
pointRadius: 0,
pointHoverRadius: 0,
pointBackgroundColor: "transparent",
pointBorderColor: "transparent"
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
intersect: false,
mode: 'index'
},
plugins: {
legend: {
display: false
},
tooltip: {
enabled: true,
backgroundColor: "rgba(17, 24, 39, 0.9)",
titleColor: "#fff",
bodyColor: "#fff",
borderColor: "#111827",
borderWidth: 1,
cornerRadius: 4,
displayColors: false,
padding: 8,
titleFont: {
size: 12
},
bodyFont: {
size: 14,
weight: 'bold'
},
callbacks: {
label: function(context) {
return context.parsed.y + ' users';
}
}
}
},
scales: {
x: {
display: false
},
y: {
display: false
}
}
}
});
});
},
destroyed() {
if (this.chart) {
this.chart.destroy();
}
}
},
// Hook for Event Creation Chart
EventCreationChart: {
mounted() {
// Import Chart.js dynamically
import("chart.js/auto").then(({ default: Chart }) => {
const ctx = this.el.getContext("2d");
const labels = JSON.parse(this.el.dataset.labels);
const values = JSON.parse(this.el.dataset.values);
this.chart = new Chart(ctx, {
type: "line",
data: {
labels: labels,
datasets: [{
label: "New Events",
data: values,
borderColor: "#111827",
backgroundColor: "rgba(17, 24, 39, 0.05)",
borderWidth: 2,
tension: 0.4,
fill: true,
pointRadius: 0,
pointHoverRadius: 0,
pointBackgroundColor: "transparent",
pointBorderColor: "transparent"
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
intersect: false,
mode: 'index'
},
plugins: {
legend: {
display: false
},
tooltip: {
enabled: true,
backgroundColor: "rgba(17, 24, 39, 0.9)",
titleColor: "#fff",
bodyColor: "#fff",
borderColor: "#111827",
borderWidth: 1,
cornerRadius: 4,
displayColors: false,
padding: 8,
titleFont: {
size: 12
},
bodyFont: {
size: 14,
weight: 'bold'
},
callbacks: {
label: function(context) {
return context.parsed.y + ' events';
}
}
}
},
scales: {
x: {
display: false
},
y: {
display: false
}
}
}
});
});
},
destroyed() {
if (this.chart) {
this.chart.destroy();
}
}
}
};
export default Hooks;