files
This commit is contained in:
parent
9818886898
commit
4cdec498ee
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,465 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Quadratic Funding Calculator</title>
|
||||
<style>
|
||||
.matchingAmount,
|
||||
.projectTable,
|
||||
.addProjectCopyURL {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#projectTable {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
#projectTable th,
|
||||
#projectTable td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Rounded corners for the first cell */
|
||||
#projectTable tr:first-child th {
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(to bottom, #22239F, #8586D6);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Red background for the last column title cell */
|
||||
#projectTable tr:first-child th:last-child {
|
||||
background: linear-gradient(to bottom, #AC3600, #D26939) !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#projectTable th {
|
||||
background-color: #f2f2f2;
|
||||
text-align: left;
|
||||
}
|
||||
.contributionTag {
|
||||
display: inline-block;
|
||||
background: #000;
|
||||
margin: 5px;
|
||||
padding: 1px 8px;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
}
|
||||
.contributionTag button {
|
||||
font-size: 8px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
#addProject,
|
||||
#copyURL {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
input {
|
||||
padding: 5px;
|
||||
font-size: 16px;
|
||||
width: 95%;
|
||||
background-color: white; /* White background color */
|
||||
border: none; /* Remove borders */
|
||||
border-radius: 10px; /* Rounded corners */
|
||||
}
|
||||
button.removeProject {
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
padding: 10px;
|
||||
background-color: transparent;
|
||||
color: #C74D16;
|
||||
/* font-weight: 100; */
|
||||
}
|
||||
input#matchAmount {
|
||||
font-size: 40px;
|
||||
width: auto;
|
||||
max-width: 250px;
|
||||
background-color: white; /* White background color */
|
||||
border: none; /* Remove borders */
|
||||
border-radius: 10px; /* Rounded corners */
|
||||
padding: 10px; /* Additional padding */
|
||||
}
|
||||
label {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
button.removeContribution {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
/* TABLE LINES */
|
||||
|
||||
#projectTable {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
#projectTable th,
|
||||
#projectTable td {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#projectTable th:first-child,
|
||||
#projectTable td:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#projectTable th {
|
||||
background-color: #f2f2f2;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#projectTable tr:first-child th {
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
|
||||
#projectTable tr:not(:first-child) td {
|
||||
border-bottom: 2px solid white;
|
||||
}
|
||||
|
||||
#projectTable td {
|
||||
border: none; /* Remove vertical borders */
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="lib/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="calculation">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let quadraticFunding = {
|
||||
matchAmount: 0, // Total match amount per round
|
||||
projects: [],
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Update URL parameters on changes
|
||||
function updateUrl() {
|
||||
let params = new URLSearchParams();
|
||||
params.set("match", quadraticFunding.matchAmount);
|
||||
|
||||
quadraticFunding.projects.forEach((project, i) => {
|
||||
params.append("grant", project.contributions.join("-"));
|
||||
});
|
||||
|
||||
// Update the URL only if it differs from the current state
|
||||
if (window.location.search !== "?" + params.toString()) {
|
||||
window.history.replaceState({}, "", "?" + params.toString());
|
||||
}
|
||||
}
|
||||
|
||||
let matchAmountInput = $("<input>")
|
||||
.attr("id", "matchAmount")
|
||||
.attr("placeholder", "Match Amount")
|
||||
.attr("value", quadraticFunding.matchAmount)
|
||||
.attr("class", "matching-input");
|
||||
|
||||
let addProjectButton = $("<button>")
|
||||
.attr("id", "addProject")
|
||||
.attr("class", "button")
|
||||
.text("Ajouter Projet");
|
||||
let copyURLButton = $("<button>")
|
||||
.attr("id", "copyURL")
|
||||
.attr("class", "button")
|
||||
.text("Copier URL");
|
||||
let projectTable = $("<table>").attr("id", "projectTable");
|
||||
|
||||
$("#calculation").append(
|
||||
$("<div>")
|
||||
.addClass("matchingAmount")
|
||||
.append("<label>Montant Total (Ğ1)</label>")
|
||||
.append(matchAmountInput),
|
||||
$("<div>").addClass("projectTable").append(projectTable),
|
||||
$("<div style='display: flex;'>")
|
||||
.addClass("addProjectCopyURL")
|
||||
.append(addProjectButton)
|
||||
.append(copyURLButton)
|
||||
);
|
||||
|
||||
$("#projectTable").append(
|
||||
$("<tr>").append(
|
||||
$('<th colspan="2">').text("Projet"),
|
||||
$("<th>").text("Contributions"),
|
||||
$("<th>").text("Montant financé"),
|
||||
$("<th>").text("Montant versé"),
|
||||
$("<th>").text("Supprimer")
|
||||
)
|
||||
);
|
||||
|
||||
// Add copy URL functionality
|
||||
$("#copyURL").on("click", function () {
|
||||
let url = window.location.href;
|
||||
let $temp = $("<input>");
|
||||
$("body").append($temp);
|
||||
$temp.val(url).select();
|
||||
document.execCommand("copy");
|
||||
$temp.remove();
|
||||
});
|
||||
|
||||
$("#addProject").on("click", function () {
|
||||
let projectName = "Projet #" + (quadraticFunding.projects.length + 1);
|
||||
|
||||
if (projectName) {
|
||||
quadraticFunding.projects.push({
|
||||
name: projectName,
|
||||
contributions: [],
|
||||
fundedAmount: 0,
|
||||
matchAmount: 0,
|
||||
});
|
||||
|
||||
let projectRow = $("<tr>")
|
||||
.attr("data-project-name", projectName)
|
||||
.append(
|
||||
$("<td>").text(projectName),
|
||||
$("<td>").append(
|
||||
$("<input>")
|
||||
.addClass("contributionInput")
|
||||
.attr("placeholder", "Ajouter une contribution et pressez Enter")
|
||||
),
|
||||
$("<td>").attr("class", "contributions"),
|
||||
$("<td>").attr("class", "fundedAmount").text(0),
|
||||
$("<td>").attr("class", "matchAmount").text(0),
|
||||
$("<td>").append(
|
||||
$("<button>").addClass("removeProject").text("\u2716")
|
||||
)
|
||||
);
|
||||
|
||||
$("#projectTable").append(projectRow);
|
||||
}
|
||||
});
|
||||
|
||||
$("#projectTable").on("click", ".removeProject", function () {
|
||||
let projectName = $(this).closest("tr").data("projectName");
|
||||
|
||||
quadraticFunding.projects = quadraticFunding.projects.filter(function (
|
||||
project
|
||||
) {
|
||||
return project.name !== projectName;
|
||||
});
|
||||
|
||||
$(this).closest("tr").remove();
|
||||
|
||||
calculateMatchAmounts();
|
||||
});
|
||||
|
||||
|
||||
$("#projectTable").on("keypress", ".contributionInput", function (e) {
|
||||
if (e.which === 13) {
|
||||
let contribution = parseFloat($(this).val());
|
||||
let projectName = $(this).closest("tr").data("projectName");
|
||||
|
||||
let project = quadraticFunding.projects.find(function (project) {
|
||||
return project.name === projectName;
|
||||
});
|
||||
|
||||
if (project && !isNaN(contribution)) {
|
||||
project.contributions.push(contribution);
|
||||
project.fundedAmount += contribution;
|
||||
calculateMatchAmounts();
|
||||
|
||||
let contributionTag = $("<div>")
|
||||
.addClass("contributionTag")
|
||||
.append($("<span>").text("(Ğ1) " + contribution))
|
||||
.append(
|
||||
$("<button>").addClass("removeContribution").text("\u2716")
|
||||
);
|
||||
|
||||
// Attach contribution index to the tag
|
||||
contributionTag.attr(
|
||||
"data-contribution-index",
|
||||
project.contributions.length - 1
|
||||
);
|
||||
|
||||
$(this).closest("tr").find(".contributions").append(contributionTag);
|
||||
$(this)
|
||||
.closest("tr")
|
||||
.find(".fundedAmount")
|
||||
.text("(Ğ1) " + project.fundedAmount.toFixed(2));
|
||||
$(this).val("");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$("#projectTable").on("click", ".removeContribution", function (e) {
|
||||
let contributionTag = $(this).parent();
|
||||
let contributionIndex = contributionTag.data("contributionIndex");
|
||||
let projectName = contributionTag.closest("tr").data("projectName");
|
||||
|
||||
let project = quadraticFunding.projects.find(function (project) {
|
||||
return project.name === projectName;
|
||||
});
|
||||
|
||||
if (project && contributionIndex !== undefined) {
|
||||
let contribution = project.contributions[contributionIndex];
|
||||
|
||||
// Use splice to remove the contribution
|
||||
project.contributions.splice(contributionIndex, 1);
|
||||
project.fundedAmount -= contribution;
|
||||
|
||||
calculateMatchAmounts();
|
||||
|
||||
$(this)
|
||||
.closest("tr")
|
||||
.find(".fundedAmount")
|
||||
.text("(Ğ1) " + project.fundedAmount.toFixed(2));
|
||||
|
||||
$(this)
|
||||
.closest("tr")
|
||||
.find(".contributionTag")
|
||||
.each(function (index) {
|
||||
$(this).attr("data-contribution-index", index);
|
||||
});
|
||||
contributionTag.remove();
|
||||
}
|
||||
});
|
||||
|
||||
function calculateMatchAmounts() {
|
||||
const totalDonations = quadraticFunding.projects.reduce(
|
||||
(total, project) => total + project.fundedAmount,
|
||||
0
|
||||
);
|
||||
|
||||
// If no donations are made yet, set matchAmount to 100
|
||||
const matchAmountPerRound = totalDonations > 0 ? totalDonations : 100;
|
||||
|
||||
const squares = quadraticFunding.projects.map((project) => {
|
||||
const sqrtSum = project.contributions.reduce(
|
||||
(sum, contrib) => sum + Math.sqrt(contrib),
|
||||
0
|
||||
);
|
||||
return sqrtSum * sqrtSum;
|
||||
});
|
||||
|
||||
const totalSquares = squares.reduce((sum, sq) => sum + sq, 0);
|
||||
|
||||
const matches = squares.map(
|
||||
(sq) => (sq / totalSquares) * matchAmountPerRound
|
||||
);
|
||||
|
||||
for (let i = 0; i < quadraticFunding.projects.length; i++) {
|
||||
const matchAmount = matches[i];
|
||||
quadraticFunding.projects[i].matchAmount = matchAmount;
|
||||
|
||||
$("#projectTable")
|
||||
.find(
|
||||
`tr[data-project-name='${quadraticFunding.projects[i].name}'] .matchAmount`
|
||||
)
|
||||
.text("(Ğ1) " + matchAmount.toFixed(2));
|
||||
}
|
||||
|
||||
$("#matchAmount").val(totalDonations);
|
||||
|
||||
updateUrl(); // Update URL after recalculating match amounts
|
||||
}
|
||||
|
||||
|
||||
// Load parameters from URL if exist
|
||||
function loadDefaults() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (params.has("match")) {
|
||||
quadraticFunding.matchAmount = parseFloat(params.get("match"));
|
||||
}
|
||||
|
||||
let projectsToLoad = [];
|
||||
|
||||
if (params.has("grant")) {
|
||||
let grants = params.getAll("grant");
|
||||
if (grants.length > 0) {
|
||||
for (let i = 0; i < grants.length; i++) {
|
||||
let contributions = grants[i]
|
||||
.split("-")
|
||||
.map(parseFloat)
|
||||
.filter((num) => !isNaN(num));
|
||||
projectsToLoad.push({
|
||||
name: "Project #" + (i + 1),
|
||||
contributions: contributions,
|
||||
fundedAmount: contributions.reduce((a, b) => a + b, 0),
|
||||
matchAmount: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let project of projectsToLoad) {
|
||||
$("#addProject").click();
|
||||
let projectRow = $("#projectTable").find(
|
||||
`tr[data-project-name='${project.name}']`
|
||||
);
|
||||
|
||||
for (let contribution of project.contributions) {
|
||||
projectRow.find(".contributionInput").val(contribution);
|
||||
projectRow.find(".contributionInput").trigger(
|
||||
jQuery.Event("keypress", {
|
||||
which: 13,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// test if we have no grant in the url, add 4
|
||||
if (!params.has("grant") && !params.has("match")) {
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
$("#addProject").click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadDefaultsFromJson(jsonData) {
|
||||
quadraticFunding.projects = [];
|
||||
|
||||
jsonData.hits.hits.forEach(function(hit) {
|
||||
let projectName = hit._source.comment;
|
||||
let contribution = hit._source.amount;
|
||||
|
||||
if (projectName && contribution) {
|
||||
let project = quadraticFunding.projects.find(function (project) {
|
||||
return project.name === projectName;
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
project = {
|
||||
name: projectName,
|
||||
contributions: [], // Initialize contributions array
|
||||
fundedAmount: 0,
|
||||
matchAmount: 0,
|
||||
};
|
||||
quadraticFunding.projects.push(project);
|
||||
}
|
||||
|
||||
// Push contribution into the contributions array
|
||||
project.contributions.push(parseFloat(contribution)); // Convert to float
|
||||
project.fundedAmount += parseFloat(contribution); // Convert to float
|
||||
}
|
||||
});
|
||||
|
||||
calculateMatchAmounts();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "https://g1.data.e-is.pro/g1/movement/_search?pretty&q=DsEx1pS33vzYZg4MroyBV9hCw98j1gtHEhwiZ5tK7ech",
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
success: function (jsonData) {
|
||||
loadDefaultsFromJson(jsonData);
|
||||
},
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
console.error("Error fetching JSON data:", errorThrown);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Close body and html tags -->
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue