Skip to content

Commit b039f0c

Browse files
committed
reorganize, add realtime validation
1 parent b0afbd7 commit b039f0c

File tree

4 files changed

+307
-268
lines changed

4 files changed

+307
-268
lines changed

_includes/list-nomination.js

+289
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
2+
// Constants - configure here if the Betriebsrat law changes!
3+
const employeeThreshholds = {
4+
5: 0,
5+
21: 1,
6+
51: 3,
7+
101: 5,
8+
201: 7,
9+
401: 9,
10+
701: 11,
11+
1001: 13,
12+
1501: 15,
13+
2001: 17,
14+
2501: 19,
15+
3001: 21,
16+
3501: 23,
17+
4001: 25,
18+
4501: 27,
19+
5001: 29,
20+
6001: 31,
21+
7001: 33,
22+
9001: 35
23+
}
24+
25+
// Seed data for the example generator
26+
27+
const lastNames = ["Schmidt", "Miller", "Xi", "Patel", "Ortez", "Goldman", "Shevchenko", "Melnyk", "Popova"]
28+
const firstNames = ["Chris", "Sam", "Hannah", "Raj", "Aditi", "Thomas", "Marie", "Mahmoud"];
29+
const jobTitles = ["Vulture capitalist", "Customer support", "Working student", "Warehouse picker", "IT support", "QA engineer", "Delivery rider", "Marketing manager", "Software engineer"]
30+
31+
32+
let exampleEmployeeCount = 0;
33+
34+
function onLoad() {
35+
let employee_count = localStorage.getItem('election.employee_count')
36+
document.getElementById('employee_count').value = employee_count;
37+
document.getElementById('candidate_count').value = localStorage.getItem('election.candidate_count');
38+
document.getElementById('list_name').value = localStorage.getItem('election.list_name');
39+
document.getElementById('list_owners').value = localStorage.getItem('election.list_owners');
40+
41+
if (employee_count) {
42+
handleTemplateGeneratorFormSubmit();
43+
handleEmployeeCount();
44+
}
45+
}
46+
47+
function handleTemplateGeneratorFormSubmit() {
48+
persistForm()
49+
signaturesTable()
50+
candidateTable()
51+
}
52+
53+
function handleTemplateGeneratorExampleFormSubmit() {
54+
exampleEmployeeCount = Math.floor(Math.random() * (1000 - 25 + 1)) + 25;
55+
signaturesTable(true)
56+
candidateTable(true)
57+
}
58+
59+
function handleEmployeeCount() {
60+
persistValue('employee_count')
61+
62+
const countField = document.getElementById('candidate_count')
63+
const minCandidates = worksCouncil();
64+
if(minCandidates) {
65+
countField.setAttribute('min', `${minCandidates}`)
66+
document.getElementById('minimum-candidates').innerText = `Note: you must include at least ${minCandidates} candidates`
67+
}
68+
69+
}
70+
71+
function persistValue(id) {
72+
const value = document.getElementById(id).value;
73+
window.localStorage.setItem("election." + id, value || '')
74+
}
75+
76+
function persistForm() {
77+
persistValue('employee_count')
78+
persistValue('candidate_count')
79+
persistValue('list_owners')
80+
persistValue('list_name')
81+
}
82+
83+
function listOwners() {
84+
// currently no option to directly enter candidate names, but when that happens this can be generated from that
85+
return localStorage.getItem('election.list_owners') || ''
86+
}
87+
88+
function listName() {
89+
// if a list name is not provided, the first two names on list suffice
90+
return (localStorage.getItem('election.list_name') || listOwners()) || ''
91+
}
92+
93+
function employeeCount(isExample) {
94+
return isExample ? exampleEmployeeCount : parseInt(localStorage.getItem('election.employee_count'))
95+
}
96+
97+
function candidateTable(isExample) {
98+
const tableBody = document.querySelector("#candidates_id");
99+
const caption = document.querySelector("#candidate_table > caption");
100+
101+
let caption_text = `${worksCouncil(isExample)} coworkers will represent you and your ${employeeCount(isExample) - 1} co-workers in your future Works Council.
102+
Candidate list proposal: ${listName()} ideally has ${candidates(isExample)} candidates.
103+
${supporters(isExample)} supporting signature(s) are also necessary, once all the candidates for ${listName()} list are finalized.
104+
`
105+
106+
let tableData = ""
107+
if (!isExample) {
108+
for (let i = 0; i < candidates(); i++) {
109+
tableData +=
110+
`<tr>
111+
<td>${i == 0 ? candidate1() : ''}</td>
112+
<td></td>
113+
<td></td>
114+
<td></td>
115+
<td></td>
116+
<td></td>
117+
</tr>`
118+
}
119+
} else {
120+
for (let i = 0; i < candidates(isExample); i++) {
121+
genders = ["male", "female", "diverse", "non-binary"];
122+
tableData +=
123+
`<tr>
124+
<td>${randomItem(firstNames)}</td>
125+
<td>${randomItem(lastNames)}</td>
126+
<td>${randomDate()}</td>
127+
<td>${randomItem(genders)}</td>
128+
<td>${randomItem(jobTitles)}</td>
129+
<td>${randomItem(["😅", "🙈", "✊", "👾"])}</td>
130+
</tr>`
131+
}
132+
}
133+
134+
tableBody.innerHTML = tableData;
135+
caption.innerHTML = caption_text
136+
}
137+
138+
function candidate1() {
139+
if (listOwners()) {
140+
return listOwners().split(",")[0]
141+
} else {
142+
return ''
143+
}
144+
}
145+
146+
function randomItem(items) {
147+
return items[Math.floor(Math.random() * items.length)]
148+
}
149+
150+
function getRandomInt(max) {
151+
return Math.floor(Math.random() * max);
152+
}
153+
154+
function randomDate() {
155+
let start = new Date('1970-01-01')
156+
let end = new Date('2004-12-31')
157+
158+
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString();
159+
}
160+
161+
function getTableData(isExample) {
162+
let tableData = ""
163+
if (!isExample) {
164+
for (let i = 0; i < supporters(); i++) {
165+
let bgColor = i + 1 < supporters() ? "#FFCCCB" : "#66FF99"
166+
let text = "#FFCCCB" == bgColor ? "Almost" : "Congrats!"
167+
tableData +=
168+
`<tr>
169+
<td></td>
170+
<td></td>
171+
<td></td>
172+
<td style="background-color:${bgColor}">${text}</td>
173+
</tr>`
174+
}
175+
tableData += extraSupporterRows()
176+
} else {
177+
for (let i = 0; i < supporters(isExample); i++) {
178+
let bgColor = i + 1 < supporters(isExample) ? "#FFCCCB" : "#66FF99"
179+
let text = "#FFCCCB" == bgColor ? "Almost" : "Congrats!"
180+
tableData +=
181+
`<tr>
182+
<td>${randomItem(firstNames)}</td>
183+
<td>${randomItem(lastNames)}</td>
184+
<td>${randomItem(["😅", "🙈", "✊", "👾"])}</td>
185+
<td style="background-color:${bgColor}">${text}</td>
186+
</tr>`
187+
}
188+
}
189+
return tableData
190+
}
191+
192+
function getCandidateData(isExample) {
193+
let candidateData = ""
194+
195+
const numCandidates = candidates()
196+
197+
if (!isExample) {
198+
for (let i = 0; i < numCandidates; i++) {
199+
candidateData +=
200+
`<tr>
201+
<td>#${i + 1}</td>
202+
<td>${i == 0 ? candidate1() : ''}</td>
203+
<td></td>
204+
<td></td>
205+
<td></td>
206+
<td></td>
207+
</tr>`
208+
}
209+
} else {
210+
for (let i = 0; i < numCandidates; i++) {
211+
genders = ["male", "female", "diverse", "non-binary"];
212+
candidateData +=
213+
`<tr>
214+
<td>#${i + 1}</td>
215+
<td>${randomItem(firstNames)}</td>
216+
<td>${randomItem(lastNames)}</td>
217+
<td>${randomDate()}</td>
218+
<td>${randomItem(genders)}</td>
219+
<td>${randomItem(jobTitles)}</td>
220+
</tr>`
221+
}
222+
}
223+
224+
return candidateData
225+
}
226+
227+
function signaturesTable(isExample) {
228+
const tableSignatureBody = document.querySelector("#signatures_id");
229+
const tableCandidateSignatureBody = document.querySelector("#signatures_candidate_id");
230+
const caption = document.querySelector("#signature_candidate_table > caption");
231+
let caption_text = `
232+
List proposal Solidarity needs at least ${supporters(isExample)} supporting signatures
233+
for the following candidates of the Solidarity list nomination.`
234+
235+
if (!isExample) {
236+
caption_text = `List proposal ${listName()} needs at least ${supporters()} supporting signatures
237+
for the following candidates of the ${listName()} list nomination.`
238+
}
239+
240+
tableSignatureBody.innerHTML = getTableData(isExample);
241+
tableCandidateSignatureBody.innerHTML = getCandidateData(isExample);
242+
caption.innerHTML = caption_text
243+
}
244+
245+
function extraSupporterRows() {
246+
// when no signatures are required, extras are not either
247+
if (supporters() < 2) {
248+
return ''
249+
} else {
250+
return `<tr>
251+
<td></td>
252+
<td></td>
253+
<td></td>
254+
<td style="background-color:#FFD2669">Optional extra signatures</td>
255+
</tr>`.repeat(Math.min(supporters(), 5))
256+
}
257+
}
258+
259+
260+
function worksCouncil(isExample) {
261+
let employees = employeeCount(isExample)
262+
for (const limit in employeeThreshholds) {
263+
if (employees < limit) {
264+
return employeeThreshholds[limit];
265+
}
266+
}
267+
// if the lookup table doesn't furnish a provided limit
268+
return Math.ceil((employees - 9000) / 3000) * 2 + 35
269+
}
270+
271+
function candidates(isExample) {
272+
if (isExample) {
273+
return 2 * worksCouncil(isExample)
274+
}
275+
// if unknown, double works council size is recommended
276+
return parseInt(localStorage.getItem('election.candidate_count')) || 2 * worksCouncil()
277+
}
278+
279+
function supporters(isExample) {
280+
let employees = employeeCount(isExample)
281+
if (employees < 21) {
282+
return 0
283+
} else if (employees < 101) {
284+
return 2
285+
} else
286+
return Math.min(Math.ceil(employees * 1.0 / 20), 50)
287+
}
288+
289+
onLoad();

0 commit comments

Comments
 (0)