From 4572e730f9976e6157dbac91683afb8766d5bb87 Mon Sep 17 00:00:00 2001 From: aymm Date: Sun, 4 Apr 2021 16:59:09 +0200 Subject: [PATCH] Client-side poll creation --- index.php | 4 +++ new_poll.php | 38 ++++++++++++++++++++++++--- scripts/new_poll.js | 52 ++++++++++++++++++++++++++++++++++++ styles/style.css | 64 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 scripts/new_poll.js diff --git a/index.php b/index.php index f2c61f8..9bb3a52 100644 --- a/index.php +++ b/index.php @@ -2,5 +2,9 @@ require_once __DIR__ .'/bootstrap.php'; +// Support the old Dragonpolls links +if (isset($_GET['poll'])) { + redirect('view_poll.php?id='.$_GET['poll']); +} echo get_page_header(); echo get_page_footer(); diff --git a/new_poll.php b/new_poll.php index 787691e..1a568d0 100644 --- a/new_poll.php +++ b/new_poll.php @@ -11,11 +11,43 @@ use APnutI\Entities\Poll; use APnutI\Entities\User; try { - echo get_page_header('New Poll', true, ['poll']); + echo get_page_header('New Poll', true, ['new_poll']); } catch (\Exception $e) { - die('Something went wrong :( "'.$e->getMessage().'"'); + die('Something went wrong :( "'.$e->getMessage().'"' . get_page_footer()); } if (!$api->isAuthenticated(false, true)) { - die('You need to be logged in to create a new poll!'); + die('You need to be logged in to create a new poll!' . get_page_footer()); } +?> + +
+ + + +
+ + /> + +
+ + + + + + + +
+ day(s) + hour(s) + minute(s)
+ +
+ + +
+ \ No newline at end of file diff --git a/scripts/new_poll.js b/scripts/new_poll.js new file mode 100644 index 0000000..4716a8b --- /dev/null +++ b/scripts/new_poll.js @@ -0,0 +1,52 @@ +window.addEventListener('DOMContentLoaded', () => { + for (const el of document.querySelectorAll('.create-poll input')) { + el.onchange = validatePoll; + } +}); + +function validatePoll() { + let errors = []; + const form = document.querySelector('.create-poll'); + if (!form.querySelector('input[name=prompt]').value) { + errors.push('Prompt cannot be empty'); + } + const numOptionsProvided = Array.from(form.querySelectorAll('input[name="option[]"]')) + .map(x => !!x.value) + .filter(x => x) + .length; + if (numOptionsProvided <= 1) { + errors.push('At least two options must be provided'); + } + + const maxOptions = parseInt(form.querySelector('input[name=max_options]').value); + if (numOptionsProvided > 1 && (isNaN(maxOptions) || maxOptions <= 0 || maxOptions >= numOptionsProvided)) { + errors.push(`Max Options needs to be greater than 0 and smaller than ${numOptionsProvided}`); + } + + const durationDays = parseInt(form.querySelector('input[name=duration_days]').value); + const durationHours = parseInt(form.querySelector('input[name=duration_hours]').value); + const durationMinutes = parseInt(form.querySelector('input[name=duration_minutes]').value); + const durationTotalMinutes = durationDays*60*24 + durationHours * 60 + durationMinutes; + // 20160 is the max duration accepted by pnut + if (isNaN(durationTotalMinutes) || durationTotalMinutes < 1 || durationTotalMinutes > 20160) { + errors.push('Duration must be more than 1 and less than 20160 minutes'); + } + + const closesAtLabel = document.getElementById('openUntil'); + if (!isNaN(durationTotalMinutes)) { + // Add duration_total_minutes to the curent Date + const closes_at = new Date(new Date().getTime() + durationTotalMinutes*60000); + closesAtLabel.innerText = `Open until ${closes_at.toLocaleString()}`; + } else { + closesAtLabel.innerText = ''; + } + + const errorSpan = form.querySelector('.error'); + if (errors.length) { + errorSpan.innerHTML = ``; + } else { + errorSpan.innerText = ''; + } + form.querySelector('button[name=submit]').disabled = !!errors.length; + +} \ No newline at end of file diff --git a/styles/style.css b/styles/style.css index 8caaec3..285c016 100644 --- a/styles/style.css +++ b/styles/style.css @@ -182,6 +182,70 @@ datewrapper time { font-size: x-large; } +/* Poll creation */ + +.create-poll { + display: grid; + max-width: 400px; + grid-auto-columns: auto 1fr; + grid-column-gap: 8px; +} +.create-poll input[type=text], +.create-poll input[type=number], +.create-poll input[type=checkbox] { + grid-column: 2; +} +.create-poll input[type=number] { + max-width: 3em; + background-color: var(--secondary-bg-color); + color: var(--main-accent-color); +} +.create-poll input[type=text] { + display: block; + width: 100%; + background-color: var(--secondary-bg-color); + color: var(--main-accent-color); +} +.create-poll input[type=text]:focus { + outline: 1px solid var(--main-accent-color); +} +.create-poll label { + grid-column: 1; +} +.create-poll label[for=options] { + grid-row: 2; +} +.create-poll #options { + grid-row: 2; +} +.create-poll label[for=anonymous] { + grid-row: 3 +} +.create-poll label[for=public] { + grid-row: 4 +} +.create-poll label[for=max_options] { + grid-row: 5 +} +.create-poll label[for=duration] { + grid-row: 6 +} +#duration { + grid-row: 6; +} +.create-poll button[type=submit] { + grid-row: 8; +} + +.create-poll .error { + grid-column: 1/3; + grid-row: 7; + background-color: rgba(255, 0, 0, 0.3); +} +.create-poll .error:not(:empty) { + margin: 8px; +} + /* Footer */ footer { display: flex;