diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 5e8f360..8c822f1 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -7,6 +7,7 @@ @import "bootstrap/scss/bootstrap"; @import "font-awesome-sprockets"; @import "font-awesome"; +@import "choices.js/public/assets/styles/choices.min"; // Your CSS partials @import "components/index"; diff --git a/app/assets/stylesheets/pages/_home.scss b/app/assets/stylesheets/pages/_home.scss index 46d8e60..bc2eb9f 100644 --- a/app/assets/stylesheets/pages/_home.scss +++ b/app/assets/stylesheets/pages/_home.scss @@ -97,6 +97,10 @@ font-size: 20px; } +.choices__list--multiple .choices__item { + background-color: #167FFB; +} + .editor-selector { color: #167FFB; font-size: 20px; diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index e8a7261..b8f48cc 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -30,6 +30,8 @@ def home end @confirmRemoveTeam = t 'confirmRemoveTeam' + @selectsOneOrMoreCategories = t 'selectsOneOrMoreCategories' + @resetFilters = t 'resetFilters' end diff --git a/app/javascript/components/datepicker.js b/app/javascript/components/datepicker.js index 922bcf5..ab636b2 100644 --- a/app/javascript/components/datepicker.js +++ b/app/javascript/components/datepicker.js @@ -1,10 +1,10 @@ import $ from 'jquery'; import 'daterangepicker'; import 'moment'; +import { Observable } from 'rxjs'; const initDatepicker = (daysToDisplay) => { - $(document).ready(function () { if (document.getElementById('datefield').value != `01/01/2000 - ${moment().format('DD/MM/YYYY')}`) { $('input[name="daterange"]').daterangepicker({ startDate: moment(), @@ -45,20 +45,9 @@ const initDatepicker = (daysToDisplay) => { }, opens: 'right' }, function (start, end, label) { - const events = document.querySelectorAll('#events') - events.forEach(element => { - const elementSelected = document.getElementById("teams"); - if (elementSelected.options[elementSelected.selectedIndex].value == 0) { - element.style.display = ''; - } - const tournamentDate = element.innerText.trim().substring(6, 10) + "-" + element.innerText.trim().substring(3, 5) + "-" + element.innerText.trim().substring(0, 2) - if (tournamentDate < start.format('YYYY-MM-DD') || tournamentDate > end.format('YYYY-MM-DD')) { - element.style.display = 'none'; - } - }); + // Callback do not use here work with RxJs Subject on Application.js }); } - }); } export { initDatepicker }; \ No newline at end of file diff --git a/app/javascript/components/filter.js b/app/javascript/components/filter.js deleted file mode 100644 index 3c71c1c..0000000 --- a/app/javascript/components/filter.js +++ /dev/null @@ -1,74 +0,0 @@ -import { initDatepicker } from "./datepicker"; - -// const initFilter = (daysToDisplay) => { -// const toggle = document.querySelector('#isTournamentOpen'); -// const events = document.querySelectorAll('#events'); -// toggle.addEventListener('click', () => { -// if (document.querySelector('#isTournamentOpen').value === "true") { -// events.forEach(element => { -// if (element.getElementsByClassName('btn-danger sqValidation')[0]) { -// let eventClosed = element.getElementsByClassName('btn-danger sqValidation')[0].parentNode.parentNode.parentNode.parentNode; -// eventClosed.style.display = ''; -// } -// }); -// document.querySelector('#isTournamentOpen').value = false - -// initializeDatepickeField(daysToDisplay); - -// } else { -// events.forEach(element => { -// if (element.getElementsByClassName('btn-danger sqValidation')[0]) { -// let eventClosed = element.getElementsByClassName('btn-danger sqValidation')[0].parentNode.parentNode.parentNode.parentNode; -// eventClosed.style.display = 'none'; -// } -// }); -// document.querySelector('#isTournamentOpen').value = true -// } -// }); -// } - -const initSelectorFilter = (daysToDisplay) => { - const elementSelected = document.getElementById("teams"); - elementSelected.addEventListener("change", function () { - - const events = document.querySelectorAll('#events'); - events.forEach(element => { - element.style.display = ''; - initializeDatepickeField(daysToDisplay); - }); - - if (elementSelected.options[elementSelected.selectedIndex].value != 0) { - events.forEach(element => { - element.style.display = 'none'; - }); - - const specificTeamEvents = document.querySelectorAll('#team-' + elementSelected.options[elementSelected.selectedIndex].value); - specificTeamEvents.forEach(element => { - element.parentNode.parentNode.parentNode.style.display = ''; - }); - document.getElementById('datefield').value = `01/01/2000 - ${moment().format('DD/MM/YYYY')}`; - } - }); -} - -const initializeDatepickeField = (daysToDisplay) => { - - initDatepicker(daysToDisplay); - - const events = document.querySelectorAll('#events'); - const start = moment(); - const end = moment().add(daysToDisplay, 'days'); - events.forEach(element => { - element.style.display = ''; - const tournamentDate = element.innerText.trim().substring(6, 10) + "-" + element.innerText.trim().substring(3, 5) + "-" + element.innerText.trim().substring(0, 2) - if (tournamentDate < start.format('YYYY-MM-DD') || tournamentDate > end.format('YYYY-MM-DD')) { - element.style.display = 'none'; - } - }); - document.getElementById('datefield').focus(); - -} - -export { - initSelectorFilter -}; \ No newline at end of file diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 918ad51..491e73f 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -1,24 +1,111 @@ import "bootstrap"; +import $ from 'jquery'; + import { initPopover } from "../components/popover"; -import { initSelectorFilter } from "../components/filter"; import { initDatepicker } from "../components/datepicker"; import { initFlashes } from "../components/flashes"; +import Choices from 'choices.js'; +import { Subject } from "rxjs"; + const daysToDisplay = 365 // Days in future displayed by daterangepicker initFlashes(); initPopover(); initDatepicker(daysToDisplay); -initSelectorFilter(daysToDisplay); - -const start = moment(); -const end = moment().add(daysToDisplay, 'days'); -const events = document.querySelectorAll('#events') -events.forEach(element => { - element.style.display = ''; - const tournamentDate = element.innerText.trim().substring(6, 10) + "-" + element.innerText.trim().substring(3, 5) + "-" + element.innerText.trim().substring(0, 2) - if (tournamentDate < start.format('YYYY-MM-DD') || tournamentDate > end.format('YYYY-MM-DD')) { - element.style.display = 'none'; + +const choices = new Choices('#categories-selection', { + removeItemButton: true, + classNames: { + highlightedState: 'is-active', } }); +const subject = new Subject(); + +subject.subscribe({ + next: (picker) => { + // console.log(`observerA: started`) + + // console.log(`StartDate: ${picker.startDate.format('YYYY-MM-DD')}`); + // console.log(`EndDate: ${picker.endDate.format('YYYY-MM-DD')}`); + + const start = picker.startDate; + const end = picker.endDate; + + const teamSelector = document.getElementById("teams"); + const teamSelected = teamSelector.options[teamSelector.selectedIndex].value; + + const events = document.querySelectorAll('#events'); + + events.forEach(element => { + + // Reset all entries if all selectors set to all + + if (teamSelected === "0" && document.getElementById("categories-selection").value === "0") { + element.style.display = ''; + } else { + element.style.display = 'none'; + } + + if (choices.passedElement.element.length === 0) { + choices.setChoiceByValue("0"); + } + + // Filtering consecutivelly by organizer AND category + + if (teamSelected === "0" || teamSelected === element.getElementsByClassName("organizer")[0].firstChild.nextSibling.id.substr(5)) { + for (let i=0; i < element.querySelectorAll(".sqPlaces").length; i++) { + for (let j=0; j < choices.passedElement.element.length; j++) { + if (choices.passedElement.element[j].value === "0" || choices.passedElement.element[j].value === element.querySelectorAll(".sqPlaces")[i].id.substring(9)) { + element.style.display = ''; + } + } + } + } + + // Filter by selected date + + const tournamentDate = element.innerText.trim().substring(6, 10) + "-" + element.innerText.trim().substring(3, 5) + "-" + element.innerText.trim().substring(0, 2) + if (tournamentDate < start.format('YYYY-MM-DD') || tournamentDate > end.format('YYYY-MM-DD')) { + element.style.display = 'none'; + } + }); + } +}); + +const resetBtn = document.getElementById("reset-button"); +resetBtn.addEventListener("click", function () { + $('input[name="daterange"]').data('daterangepicker').setStartDate(moment()); + $('input[name="daterange"]').data('daterangepicker').setEndDate(moment().add(daysToDisplay, 'days')); + let picker = $('input[name="daterange"]').data('daterangepicker') + + document.getElementById("teams").value = 0; + + choices.removeActiveItems(); + choices.setChoiceByValue("0"); + + subject.next(picker); +}); + +$('input[name="daterange"]').on('apply.daterangepicker', function(ev, picker) { + subject.next(picker); +}); + +const teamSelector = document.getElementById("teams"); +teamSelector.addEventListener("change", function () { + let picker = $('input[name="daterange"]').data('daterangepicker') + subject.next(picker); +}); + +choices.passedElement.element.addEventListener('change', function(categoriesEvent) { + + if (categoriesEvent.detail.value === "0") { + choices.removeActiveItems(categoriesEvent.detail.id); + } else { + choices.removeActiveItemsByValue("0"); + } + + let picker = $('input[name="daterange"]').data('daterangepicker') + subject.next(picker, categoriesEvent); +}); \ No newline at end of file diff --git a/app/views/pages/home.html.erb b/app/views/pages/home.html.erb index ebbeb0f..a602471 100644 --- a/app/views/pages/home.html.erb +++ b/app/views/pages/home.html.erb @@ -207,10 +207,10 @@
-
+
<%= t 'daterange' %> :
-
+
@@ -220,22 +220,20 @@
-
- +
+
+ +
-
-
+
+
<%= t "organizer" %> :
-
+
+
+ <%= t "category" %> : +
+
+ + +

@@ -373,11 +386,11 @@ <% (JSON.parse event["categories"]).keys.each do |categorie| %> <% if (JSON.parse event["categories"])[categorie]["total_places"].to_i > 0 %> <% if (JSON.parse event["categories"])[categorie]["places_left"].to_i > 0 %> - <%= "
".html_safe %> + <%= "
".html_safe %> <% else %> - <%= "
".html_safe %> + <%= "
".html_safe %> <% end %> <% end %> <% end %> diff --git a/config/locales/de.yml b/config/locales/de.yml index ca0cd14..faf8547 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -62,6 +62,8 @@ de: confirmRemoveTeam: 'Sind Sie sicher, dass Sie Ihre Mannschaft aus diesem Turnier entfernen wollen?' teamsInscription: "Registrieren Sie ein Team aus Ihrem Verein" noTeamRegistredForNow: "Zur Zeit ist noch kein Team angemeldet" + selectsOneOrMoreCategories: "Wählt eine oder mehrere Kategorien aus" + resetFilters: "Filtern zurücksetzen" simple_form: labels: defaults: diff --git a/config/locales/en.yml b/config/locales/en.yml index 4a8432a..56ed7e9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -93,6 +93,8 @@ en: confirmRemoveTeam: 'Are you sure you want to remove your team of this tournament ?' teamsInscription: "Register a team from your club" noTeamRegistredForNow: "No team registred for now" + selectsOneOrMoreCategories: "Selects one or more categories" + resetFilters: "Reset filters" simple_form: labels: defaults: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 8753329..df9a120 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -62,6 +62,8 @@ fr: confirmRemoveTeam: 'Êtes-vous sûr de vouloir retirer votre équipe pour ce tournoi ?' teamsInscription: "Inscrire une équipe de votre club" noTeamRegistredForNow: "Aucune équipe inscrite pour le moment" + selectsOneOrMoreCategories: "Sélectionne une ou plusieurs catégories" + resetFilters: "Réinitialiser les filtres" simple_form: labels: defaults: diff --git a/package.json b/package.json index c364070..da3a1cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "swiss-hockey-tool", - "version": "0.5.0-beta", + "version": "0.6.0-beta", "description": "The Swiss Hockey Tool (SHT) is an online tool that provide the ability to administer the organization of an Hockey tournament.", "repository": { "type": "git", @@ -20,9 +20,11 @@ "dependencies": { "@rails/webpacker": "^4.0.7", "bootstrap": "^4.3.1", + "choices.js": "^7.0.0", "daterangepicker": "^3.0.5", "jquery": "^3.4.1", - "popper.js": "^1.15.0" + "popper.js": "^1.15.0", + "rxjs": "^6.5.2" }, "devDependencies": { "webpack-dev-server": "^3.7.2" diff --git a/yarn.lock b/yarn.lock index 417accc..8bd6b82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1522,6 +1522,16 @@ chalk@^2.0, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +choices.js@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/choices.js/-/choices.js-7.0.0.tgz#8db4ff8baaffac5e321960dbf8aeb9519f58351c" + integrity sha512-qK9NEX4/riACBGle27BOWf6dZf+VqitbALB96LERBslqa05Tsn91bicACmLhw2Qym227mQIKN17hcIPwsRZ0mQ== + dependencies: + classnames "^2.2.6" + deepmerge "^2.2.1" + fuse.js "3.4.2" + redux "^3.3.1" + chokidar@^2.0.2, chokidar@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" @@ -1571,6 +1581,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classnames@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -2153,6 +2168,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deepmerge@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -2818,6 +2838,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +fuse.js@3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.2.tgz#d7a638c436ecd7b9c4c0051478c09594eb956212" + integrity sha512-WVbrm+cAxPtyMqdtL7cYhR7aZJPhtOfjNClPya8GKMVukKDYs7pEnPINeRVX1C9WmWgU8MdYGYbUPAP2AJXdoQ== + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -3760,6 +3785,11 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash-es@^4.2.1: + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.14.tgz#12a95a963cc5955683cee3b74e85458954f37ecc" + integrity sha512-7zchRrGa8UZXjD/4ivUWP1867jDkhzTG2c/uj739utSd7O/pFFdxspCemIFKEEjErbcqRzn8nKnGsi7mvTgRPA== + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -3805,7 +3835,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.5, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.5, lodash@^4.2.1, lodash@~4.17.10: version "4.17.14" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== @@ -3815,7 +3845,7 @@ loglevel@^1.6.3: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -5657,6 +5687,16 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +redux@^3.3.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b" + integrity sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A== + dependencies: + lodash "^4.2.1" + lodash-es "^4.2.1" + loose-envify "^1.1.0" + symbol-observable "^1.0.3" + regenerate-unicode-properties@^8.0.2: version "8.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" @@ -5855,6 +5895,13 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" +rxjs@^6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" + integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -6444,6 +6491,11 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + tapable@^1.0.0, tapable@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"