This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 18949e2b417e1a30d2522b243698dea0cb134a3d Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Fri Jul 21 12:23:24 2017 +0200 UI des listes de votants pour les sondages restraints --- .../entity/VoterListMemberTopiaDao.java | 6 +- .../chorem/pollen/rest/api/v1/VoterListApi.java | 2 +- .../chorem/pollen/services/bean/VoterListBean.java | 20 ++ .../pollen/services/service/VoterListService.java | 24 ++- pollen-ui-riot-js/src/main/web/conf.js | 2 +- pollen-ui-riot-js/src/main/web/i18n.json | 10 +- pollen-ui-riot-js/src/main/web/js/I18nHelper.js | 8 + pollen-ui-riot-js/src/main/web/js/PollForm.js | 32 +++ .../src/main/web/js/VoterListService.js | 83 +++++++- .../src/main/web/tag/components/Card.tag.html | 4 +- .../web/tag/components/ContextualMenu.tag.html | 19 +- .../main/web/tag/favoriteList/MemberCard.tag.html | 33 --- .../web/tag/favoriteList/MemberEditModal.tag.html | 29 +-- .../src/main/web/tag/poll/EditPoll.tag.html | 8 +- .../src/main/web/tag/poll/Settings.tag.html | 19 ++ .../src/main/web/tag/poll/Voters.tag.html | 149 ------------- .../tag/voterList/ImportFavoritListModal.tag.html | 59 +++++ .../src/main/web/tag/voterList/VoterList.tag.html | 237 ++++++++++++--------- .../web/tag/voterList/VoterListActions.tag.html | 177 --------------- .../main/web/tag/voterList/VoterListCard.tag.html | 82 +++++++ .../web/tag/voterList/VoterListEditModal.tag.html | 77 +++++++ .../web/tag/voterList/VoterListMember.tag.html | 101 --------- .../web/tag/voterList/VoterListMemberCard.tag.html | 81 +++++++ .../VoterListMemberEditModal.tag.html} | 57 +++-- pollen-ui-riot-js/webpack.config.js | 5 +- 25 files changed, 679 insertions(+), 645 deletions(-) diff --git a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoterListMemberTopiaDao.java b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoterListMemberTopiaDao.java index 19251904..5dcd1dfe 100644 --- a/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoterListMemberTopiaDao.java +++ b/pollen-persistence/src/main/java/org/chorem/pollen/persistence/entity/VoterListMemberTopiaDao.java @@ -12,9 +12,9 @@ public class VoterListMemberTopiaDao extends AbstractVoterListMemberTopiaDao<Vot Vote vote = voteDao.forVoterListMemberContains(entity).findUniqueOrNull(); if (vote != null) { vote.removeVoterListMember(entity); - } - if (vote.isVoterListMemberEmpty()) { - voteDao.delete(vote); + if (vote.isVoterListMemberEmpty()) { + voteDao.delete(vote); + } } super.delete(entity); diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java index b843445b..8ac33dd7 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/VoterListApi.java @@ -78,7 +78,7 @@ public class VoterListApi { } - @Path("/polls/{pollId}/voterLists/{voterListId}") + @Path("/polls/{pollId}/voterLists/{voterListId}/lists") @GET public List<VoterListBean> getVoterLists(@Context VoterListService voterListService, @PathParam("pollId") PollenEntityId<Poll> pollId, diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java index 1f8a34b0..2eec3235 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListBean.java @@ -38,6 +38,10 @@ public class VoterListBean extends PollenBean<VoterList> { protected PollenEntityId<VoterList> parentId; + protected long countSubLists; + + protected long countMembers; + public VoterListBean() { super(VoterList.class); } @@ -91,4 +95,20 @@ public class VoterListBean extends PollenBean<VoterList> { public void setParentId(PollenEntityId<VoterList> parentId) { this.parentId = parentId; } + + public long getCountSubLists() { + return countSubLists; + } + + public void setCountSubLists(long countSubLists) { + this.countSubLists = countSubLists; + } + + public long getCountMembers() { + return countMembers; + } + + public void setCountMembers(long countMembers) { + this.countMembers = countMembers; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java index 39312b3a..40bb172f 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java @@ -151,6 +151,22 @@ public class VoterListService extends PollenServiceSupport { }; } + protected VoterListBean voterListBeanFunction(VoterListBean bean) { + + String entityId = bean.getEntityId(); + long countSubLists = getVoterListDao() + .forProperties(VoterList.PROPERTY_PARENT + "." + VoterList.PROPERTY_TOPIA_ID, entityId) + .count(); + + long countMembers = getVoterListMemberDao() + .forProperties(VoterListMember.PROPERTY_VOTER_LIST + "." + VoterList.PROPERTY_TOPIA_ID, entityId) + .count(); + + bean.setCountSubLists(countSubLists); + bean.setCountMembers(countMembers); + return bean; + } + public List<VoterListBean> getVoterLists(String pollId, String parentId) { checkNotNull(pollId); @@ -158,7 +174,7 @@ public class VoterListService extends PollenServiceSupport { Poll poll = getPollService().getPoll0(pollId); List<VoterList> voterLists = getVoterLists0(poll, parentId); - return toBeanList(VoterListBean.class, voterLists); + return toBeanList(VoterListBean.class, voterLists, this::voterListBeanFunction); } @@ -174,7 +190,7 @@ public class VoterListService extends PollenServiceSupport { VoterListBean result = null; if (voterList != null) { - result = toBean(VoterListBean.class, voterList); + result = toBean(VoterListBean.class, voterList, this::voterListBeanFunction); } return result; @@ -187,7 +203,7 @@ public class VoterListService extends PollenServiceSupport { checkPermission(PermissionVerb.readPoll, pollId); VoterList voterList = getVoterList0(pollId, voterListId); - return toBean(VoterListBean.class, voterList); + return toBean(VoterListBean.class, voterList, this::voterListBeanFunction); } @@ -223,7 +239,7 @@ public class VoterListService extends PollenServiceSupport { VoterList result = getVoterListDao().forTopiaIdEquals(voterList.getEntityId()).findUnique(); //TODO Notify - return toBean(VoterListBean.class, result); + return toBean(VoterListBean.class, result, this::voterListBeanFunction); } diff --git a/pollen-ui-riot-js/src/main/web/conf.js b/pollen-ui-riot-js/src/main/web/conf.js index eeb2148f..5b5da95d 100644 --- a/pollen-ui-riot-js/src/main/web/conf.js +++ b/pollen-ui-riot-js/src/main/web/conf.js @@ -1,5 +1,5 @@ window.pollenConf = { - endPoint: "http://localhost:8888/pollen-rest-api", + endPoint: POLLEN_API_URL, piwikUrl: "", // add the piwik url, eg: http://localhost/piwik piwikSiteId: "", // add the site id, eg: 3 defaultMessageTimeout: 15, diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index 2aee07af..8c56ba3d 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -238,6 +238,7 @@ "poll_description_nameNotBlank": "Vote nom ne doit pas être blanc", "poll_description_email": "Votre courriel", "poll_description_emailPlaceHolder": "Renseignez votre courriel", + "poll_settings_restricted": "Sondage restraint ?", "poll_settings_basic_usage": "Options par défaut", "poll_settings_use_basic_usage": "Utiliser les options par défaut", "poll_settings_basic_usage_detail": "Par défaut Pollen vous propose : ", @@ -332,7 +333,6 @@ "poll_step_choices": "Choix", "poll_step_options": "Options", "poll_step_voters": "Participants", - "poll_voters_description": "Qui peut voter ?", "poll_voters_previous": "Précédent", "poll_voters_save": "Enregistrer", "poll_voters_freePoll": "Tout le monde peut voter (Sondage public)", @@ -470,8 +470,12 @@ "favoriteList_import": "Importer", "error_manager_403": "Erreur : Accès refusé", "error_manager_500": "Erreur : Service indisponile", + "voterList_new": "Nouveelle liste", + "voterList_edit": "Modifier la liste", "voterList_name": "Nom", + "voterList_name_error_alreadyExist": "Le Nom existe dèjà dans cette liste", "voterList_weight": "Poids", + "voterList_main_list": "Liste principale", "voterList_addMember": "Ajouter un participant", "voterList_addVoterList": "Ajouter une sous-liste", "voterList_exportFavoriteList": "Exporter dans une nouvelle liste de votants", @@ -484,8 +488,12 @@ "voterList_resendInvitation_success": "invitations sont envoyées", "voterList_resendInvitation_one": "1 invitation est envoyée", "voterList_resendInvitation_none": "Tout les participants de cette liste ont votés", + "voterList_member_new": "Nouveau participant", + "voterList_member_edit": "Modifier le participant", "voterList_member_name": "Nom", + "voterList_member_name_error_alreadyExist": "Le Nom existe dèjà dans cette liste", "voterList_member_email": "Courriel", + "voterList_member_email_error_alreadyExist": "Le Courriel existe dèjà dans cette liste", "voterList_member_weight": "Poids", "voterList_member_delete": "Supprimer le participant", "voterList_member_deleteMessage": "Supprimer le participant ?", diff --git a/pollen-ui-riot-js/src/main/web/js/I18nHelper.js b/pollen-ui-riot-js/src/main/web/js/I18nHelper.js index 5f5e891a..44d05500 100644 --- a/pollen-ui-riot-js/src/main/web/js/I18nHelper.js +++ b/pollen-ui-riot-js/src/main/web/js/I18nHelper.js @@ -58,6 +58,14 @@ module.exports = { return this.i18nformat(this.__[key], params) || key; }, + translateErrors(errors) { + let errorsTranslate = {}; + Object.keys(errors).forEach((key) => { + errorsTranslate[key] = errors[key].map(this._l); + }); + return errorsTranslate; + }, + i18nformat(value, params) { if (!params) { return value; diff --git a/pollen-ui-riot-js/src/main/web/js/PollForm.js b/pollen-ui-riot-js/src/main/web/js/PollForm.js index 9abd9b4d..e7135964 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -50,6 +50,8 @@ class PollForm { this.model = {}; this.choices = []; this.choicesToRemove = []; + this.mainVoterList = {}; + this.currentVoterList = {}; } _loadVoteCountingTypes() { @@ -101,8 +103,10 @@ class PollForm { voterListService.init(this).then(voterList => { this.mainVoterList = voterList; + this.setCurrentVoterList(voterList); }); + this._updateSteps(); this.step = 0; return Promise.resolve(this); @@ -130,9 +134,11 @@ class PollForm { voterListService.init(this).then(voterList => { this.mainVoterList = voterList; + this.setCurrentVoterList(voterList); }); this.isInit = true; + this._updateSteps(); this.setStep(0); }); } @@ -265,6 +271,32 @@ class PollForm { this.model.commentVisibility = "EVERYBODY"; } + togglePollType() { + if (this.model.pollType === "RESTRICTED") { + this.model.pollType = "FREE"; + } else { + this.model.pollType = "RESTRICTED"; + } + this._updateSteps(); + bus.trigger("pollStepsChange", this.steps); + } + + _updateSteps() { + let steps = ["general", "choices", "options"]; + if (this.model.pollType === "RESTRICTED") { + steps.push("voters"); + } + this.steps = steps; + } + + setCurrentVoterList(list) { + return voterListService.loadList(list).then(() => { + this.currentVoterList = list; + return list; + }); + } + + } module.exports = singleton(PollForm); diff --git a/pollen-ui-riot-js/src/main/web/js/VoterListService.js b/pollen-ui-riot-js/src/main/web/js/VoterListService.js index 088347e5..7294960c 100644 --- a/pollen-ui-riot-js/src/main/web/js/VoterListService.js +++ b/pollen-ui-riot-js/src/main/web/js/VoterListService.js @@ -22,7 +22,9 @@ class VoterListService extends FetchService { return { id: this.tempPrefix + this.tempId++, parentId: parent && parent.id, + countSubLists: 0, subLists: [], + countMembers: 0, members: [], name: name, weight: weight || 1, @@ -94,11 +96,37 @@ class VoterListService extends FetchService { return voterListPromise; } + _checkVoterList(parent, name, weight, id) { + let errors = {}; + let sameName = parent.subLists.find(m => m.id !== id && m.name === name); + if (sameName) { + errors.name = ["name_error_alreadyExist"]; + } + return errors; + } + addVoterList(parent, name, weight) { + let errors = this._checkVoterList(parent, name, weight); + if (Object.keys(errors).length > 0) { + return Promise.reject(errors); + } let voterList = this._newVoterList(parent, name, weight); parent.subLists.push(voterList); this.voterListsById[voterList.id] = voterList; - return voterList; + parent.countSubLists = parent.subLists.length; + return Promise.resolve(voterList); + } + + saveVoterList(id, name, weight) { + let voterList = this.voterListsById[id]; + let parent = this.voterListsById[voterList.parentId]; + let errors = this._checkVoterList(parent, name, weight, id); + if (Object.keys(errors).length > 0) { + return Promise.reject(errors); + } + voterList.name = name; + voterList.weight = weight; + return Promise.resolve(voterList); } deleteVoterList(voterList) { @@ -119,6 +147,7 @@ class VoterListService extends FetchService { if (!voterList.id.startsWith(this.tempPrefix)) { this.voterListsToDelete.push(voterList); } + parent.countSubLists = parent.subLists.length; } _deleteVoterList2(voterList) { @@ -128,11 +157,43 @@ class VoterListService extends FetchService { delete this.voterListsById[voterList.id]; } + + _checkMember(parent, name, email, weight, id) { + let errors = {}; + let sameName = parent.members.find(m => m.id !== id && m.name === name); + if (sameName) { + errors.name = ["name_error_alreadyExist"]; + } + let sameEmail = parent.members.find(m => m.id !== id && m.email === email); + if (sameEmail) { + errors.email = ["email_error_alreadyExist"]; + } + return errors; + } + addMember(parent, name, email, weight) { + let errors = this._checkMember(parent, name, email, weight); + if (Object.keys(errors).length > 0) { + return Promise.reject(errors); + } let member = this._newMember(parent, name, email, weight); parent.members.push(member); this.voterListMembersById[member.id] = member; - return member; + parent.countMembers = parent.members.length; + return Promise.resolve(member); + } + + saveMember(id, name, email, weight) { + let member = this.voterListMembersById[id]; + let parent = this.voterListsById[member.voterListId]; + let errors = this._checkMember(parent, name, email, weight, id); + if (Object.keys(errors).length > 0) { + return Promise.reject(errors); + } + member.name = name; + member.email = email; + member.weight = weight; + return Promise.resolve(member); } deleteMember(member) { @@ -144,6 +205,7 @@ class VoterListService extends FetchService { if (!member.id.startsWith(this.tempPrefix)) { this.voterListMembersToDelete.push(member); } + voterList.countMembers = voterList.members.length; } getVoterLists() { @@ -185,7 +247,10 @@ class VoterListService extends FetchService { listsToDelete: this.voterListsToDelete, membersToDelete: this.voterListMembersToDelete }, - {permission: this.pollForm.model.permission}); + {permission: this.pollForm.model.permission}).then(() => { + this.voterListsToDelete = []; + this.voterListMembersToDelete = []; + }); } importFavoriteList(voterList, favoriteListId) { @@ -197,7 +262,9 @@ class VoterListService extends FetchService { }; let importPromises = []; importPromises.push(FavoriteListService.members(favoriteListId, "", pagination).then(result => { - result.elements.forEach(member => {this.addMember(voterList, member.name, member.email, member.weight);}); + result.elements.forEach(member => { + this.addMember(voterList, member.name, member.email, member.weight); + }); return Promise.resolve(); })); let paginationChild = { @@ -207,10 +274,10 @@ class VoterListService extends FetchService { pageNumber: 0 }; importPromises.push(FavoriteListService.childrenLists(favoriteListId, "", paginationChild).then(result => { - let subListImportPromises = []; - result.elements.forEach(childList => { - let subVoterList = this.addVoterList(voterList, childList.child.name, childList.weight); - subListImportPromises.push(this.importFavoriteList(subVoterList, childList.child.id)); + let subListImportPromises = result.elements.map(childList => { + return this.addVoterList(voterList, childList.child.name, childList.weight).then(subVoterList => { + return this.importFavoriteList(subVoterList, childList.child.id); + }); }); return Promise.all(subListImportPromises); })); diff --git a/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html b/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html index 59d80110..307c8aed 100644 --- a/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html @@ -17,11 +17,11 @@ require("./LetterAvatar.tag.html"); <div class="card-content"> - <div if={!opts.href} class="card-avatar"> + <div if={!opts.href && !opts.onletterclick} class="card-avatar"> <LetterAvatar name={opts.name} rounded="true"/> </div> - <a if={opts.href} href={opts.href} class="card-avatar"> + <a if={opts.href || opts.onletterclick} href={opts.href} onclick={opts.onletterclick} class="card-avatar"> <LetterAvatar name={opts.name} rounded="true"/> </a> diff --git a/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html b/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html index 63f27cab..1cffb8f0 100644 --- a/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html @@ -1,5 +1,5 @@ -<ContextualMenu> - <i class="icon fa fa-plus"></i> +<ContextualMenu class={open : opts.openForce}> + <i class="icon fa {opts.icon || 'fa-plus'}"></i> <div class="links"> <yield/> @@ -15,11 +15,8 @@ overflow: hidden; background-color: var(--main); color:var(--background); - } - - contextualmenu:hover { - width: inherit; - height: inherit; + max-width: 90%; + z-index: 3; } .icon { @@ -33,11 +30,11 @@ .links { max-width: 0; max-height: 0; - transition: max-width 0.75s, max-height 0.75s; - + transition: max-width 1s, max-height 1s; } - contextualmenu:hover .links { + contextualmenu:hover .links, + contextualmenu.open .links { max-width: 500px; max-height: 500px; transition: max-width 1s, max-height 1s; @@ -57,7 +54,7 @@ } @media (max-width: 640px) { - contextualmenu { + contextualmenu { right: 1em; bottom: 1em; } diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html index 2f29dc96..6d8f120a 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html @@ -58,39 +58,6 @@ require("./MemberEditModal.tag.html"); text-overflow: ellipsis; } - .member-card-view { - display: flex; - justify-content: space-between; - } - - .member-actions { - display: flex; - align-items: flex-start; - } - - .member-actions button { - margin-left: 3px; - } - - .member-card-edit .o-form-element .c-label:first-child { - width: 25%; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .member-card-edit .o-form-element .c-field { - width: 75%; - display: inline-block; - } - - .member-card-edit .o-form-element .c-toggle, - .member-card-edit .o-form-element .c-hint { - margin-left: 25%; - } - </style> </MemberCard> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html index 2e915c2e..eb3291cf 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html @@ -69,26 +69,19 @@ require("../popup/Modal.tag.html"); let promise; if (member.id) { - promise = favoriteListService.saveMember(this.opts.favoriteList.id, member).then(() => { - this.errors = {}; - }, errors => { - this.errors = errors; - this.bus.trigger("message", new Message(errors, "error")); - this.update(); - return Promise.reject(); - }); + promise = favoriteListService.saveMember(this.opts.favoriteList.id, member); } else { - promise = favoriteListService.addMember(this.opts.favoriteList.id, member).then(() => { - this.errors = {}; - this.update(); - }, errors => { - this.errors = errors; - this.bus.trigger("message", new Message(errors, "error")); - this.update(); - return Promise.reject(); - }); + promise = favoriteListService.addMember(this.opts.favoriteList.id, member); } - return promise; + return promise.then(() => { + this.errors = {}; + this.update(); + }, errors => { + this.errors = errors; + this.bus.trigger("message", errors, "error"); + this.update(); + return Promise.reject(); + }); }; </script> diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html index c5774bf9..e16bd74c 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html @@ -21,7 +21,7 @@ require("./Description.tag.html"); require("./Choices.tag.html"); require("./Settings.tag.html"); -require("./Voters.tag.html"); +require("../voterList/VoterList.tag.html"); require("./Summary.tag.html"); require("../components/HumanInput.tag.html"); @@ -57,7 +57,7 @@ require("../components/HumanInput.tag.html"); <Description if={!showSummary && form.step === 0} form={form}/> <Choices if={!showSummary && form.step === 1} form={form}/> <Settings if={!showSummary && form.step === 2} form={form}/> - <Voters if={!showSummary && form.step === 3} form={form}/> + <VoterList if={!showSummary && form.step === 3 && form.model.pollType === "RESTRICTED"} form={form} ref="voters"/> <Summary if={showSummary} form={form}/> <div class="actions" if={!showSummary}> @@ -176,6 +176,10 @@ require("../components/HumanInput.tag.html"); } }; + this.listen("pollStepsChange", () => { + this.update(); + }); + </script> <style> diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html index 70a521e7..9317a978 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Settings.tag.html @@ -22,6 +22,21 @@ require("../components/date-time-picker.tag.html"); <Settings> <div class="form-section" show={form.creation}> + <div class="o-form-element"> + <label class="c-toggle c-toggle--info"> + {__.restricted} + <input type="checkbox" + name="pollType" + ref="pollType" + disabled={opts.form.hasVotes} + checked={opts.form.model.pollType === "RESTRICTED"} + onclick={togglePollType}> + <div class="c-toggle__track"> + <div class="c-toggle__handle"></div> + </div> + </label> + </div> + <h4><i class="fa fa-cogs"></i> {__.basic_usage}</h4> <div class="o-form-element"> <label class="c-toggle c-toggle--info"> @@ -422,6 +437,10 @@ require("../components/date-time-picker.tag.html"); this.notifyMeBeforePollEnds = !this.notifyMeBeforePollEnds; }; + this.togglePollType = () => { + this.opts.form.togglePollType(); + }; + this.submit = () => { if (!this.showOptions && this.form.creation) { diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html deleted file mode 100644 index 7ae9d685..00000000 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Voters.tag.html +++ /dev/null @@ -1,149 +0,0 @@ -/*- - * #%L - * Pollen :: UI (Riot Js) - * %% - * Copyright (C) 2009 - 2017 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * #L% - */ - require("../voterList/VoterList.tag.html"); - -<Voters> - <div class="o-form-element"> - <label class="c-label"> - {__.description} - </label> - <select class="c-field" - name="pollType" - ref="pollType" - disabled={form.hasVotes} - value={form.model.pollType} - onchange={pollTypeChange} > - <option value="FREE">{__.freePoll}</option> - <option value="RESTRICTED">{__.restrictedPoll}</option> - </select> - </div> - - <div show={!votePrivate}> - <div class="o-form-element" if={form.model.alreadyParticipants && form.model.alreadyParticipants.length}> - <label class="c-label"> - {__.already_invite_label} - </label> - <div class="participants"> - <ul class="c-list"> - <li each={participant in form.model.alreadyParticipants} class="c-list__item"> - {participant} - </li> - </ul> - </div> - </div> - - <div class="o-form-element"> - <label class="c-label"> - {__.new_invite_label} - </label> - <textarea class="c-field" - rows="5" - ref="participants" - name="participants" - value="{participants}"/> - </div> - </div> - <div class="form-section" show={votePrivate}> - <label class="section-title"> - {__.restrictedPoll_participants} - </label> - <div class="section-content"> - <VoterList voter-list={form.mainVoterList} form={opts.form} ref="mainVoterList"/> - </div> - </div> - - <script type="es6"> - this.session = require("../../js/Session"); - this.installBundle(this.session, "poll_voters"); - this.form = this.opts.form; - this.votePrivate = this.form.model.pollType !== "FREE"; - this.participants = ""; - this.pollTypeChange = (e) => { - this.votePrivate = e.target.value !== "FREE"; - }; - - this.submit = () => { - this.form.model.pollType = this.refs.pollType.value; - if (this.refs.participants.value) { - this.form.model.participants = (this.form.model.participants || []).concat(this.refs.participants.value.split(/\s+/)); - } - this.refs.mainVoterList.submit(); - }; - - </script> - <style> - - .o-form-element .participants { - padding: .5em; - } - - .form-section { - display: flex; - flex-wrap: wrap; - } - - .form-section .section-title { - width : 100%; - } - .form-section .section-content { - width : 100%; - } - - @media (min-width: 640px) { - - .form-section .section-title { - width : 25%; - text-align: right; - padding: 1.5em 5px 0 0; - } - .form-section .section-content { - width : 75%; - } - - - .o-form-element .c-label:first-child { - width: 25%; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .o-form-element .c-field, - .o-form-element .participants { - width: 75%; - display: inline-block; - } - - - .o-form-element .participants { - display: inline-block; - } - - .o-form-element .c-toggle { - margin-left: 25%; - } - } - - - </style> -</Voters> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/ImportFavoritListModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/ImportFavoritListModal.tag.html new file mode 100644 index 00000000..d3ed3cc0 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/ImportFavoritListModal.tag.html @@ -0,0 +1,59 @@ +require("../popup/Modal.tag.html"); + +<ImportFavoritListModal> + + <modal header={__.importFavoriteList} + onsubmit={import} + ref="importFavoriteListModal"> + <div show={favoriteLists.length === 0}> + {__.importFavoriteList_none} + </div> + <select class="c-field" + show={favoriteLists.length > 0} + ref="selectFavoriteListToImport"> + <option each={favoriteList in parent.favoriteLists} + value={favoriteList.id}> + {favoriteList.name} + </option> + </select> + </modal> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "voterList"); + let favoriteListService = require("../../js/FavoriteListService"); + let voterListService = require("../../js/VoterListService"); + + this.favoriteLists = []; + + this.open = () => { + let pagination = { + order: "name", + desc: false, + pageSize: -1, + pageNumber: 0 + }; + return favoriteListService.favoriteLists(pagination).then((result) => { + this.favoriteLists = result.elements; + let promise = this.refs.importFavoriteListModal.open(); + this.parent.update(); + return promise; + }); + }; + + this.import = () => { + let favoriteListId = this.refs.importFavoriteListModal.refs.selectFavoriteListToImport.value; + return voterListService.importFavoriteList(this.opts.voterList, favoriteListId).then(() => { + this.errors = {}; + this.update(); + }, errors => { + this.errors = this.translateErrors(errors); + this.bus.trigger("message", this.errors, "error"); + this.update(); + return Promise.reject(); + }); + }; + + </script> + +</ImportFavoritListModal> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html index 4485d767..eb2b8f4f 100644 --- a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterList.tag.html @@ -1,133 +1,168 @@ -require("./VoterListMember.tag.html"); -require("./VoterListActions.tag.html"); -require("../popup/Modal.tag.html"); - -<VoterList class="card"> - <div class="voter-list-header"> - <div class="voter-list-icone" onclick={toggleExpand}> - <i class="fa fa-caret-{expand ? 'down' : 'right'}" aria-hidden="true"></i> - <i class="fa fa-users" aria-hidden="true"></i> - </div> - <div class="voter-list-form"> - <div class="voter-list-fields" - if={opts.voterList.parentId}> - <div class="c-input-group"> - <div class="o-field"> - <input class="c-field" - type="text" - name="name" - ref="name" - disabled={opts.form.model.isClosed} - value={opts.voterList.name} - required - placeholder={__.name}> - </div> - <div class="o-field o-field--icon-left field-weight"> - <i class="fa fa-fw fa-balance-scale c-icon" aria-hidden="true"></i> - <input class="c-field" - type="number" - name="weight" - ref="weight" - disabled={opts.form.model.isClosed} - value={opts.voterList.weight} - required - placeholder={__.weight}> - </div> - </div> - </div> - <VoterListActions voter-list={opts.voterList} form={parent.opts.form}/> - </div> +require("./VoterListCard.tag.html"); +require("./VoterListEditModal.tag.html"); +require("./VoterListMemberCard.tag.html"); +require("./VoterListMemberEditModal.tag.html"); +require("./ImportFavoritListModal.tag.html"); +require("../components/ContextualMenu.tag.html"); + +<VoterList> + <ol class="c-breadcrumbs"> + <li class="c-breadcrumbs__crumb" each={list, index in getVoterListsStack()}> + <a class="c-link" onclick={parent.setCurrent(list)}> + {index === 0 ? parent.__.main_list : list.name} + </a> + </li> + <li class="c-breadcrumbs__crumb c-text--loud"> + {opts.form.currentVoterList.parentId ? opts.form.currentVoterList.name : __.main_list} + </li> + </ol> + + <div class="elements"> + <VoterListCard each={subList in opts.form.currentVoterList.subLists} + voter-list={subList} + form={parent.opts.form} + on-voter-list-change={parent.update} + onletterClick={parent.setCurrent(subList)}/> + <VoterListMemberCard each={member in opts.form.currentVoterList.members} + member={member} + form={parent.opts.form} + on-member-change={parent.update}/> </div> - <div class="voter-list-content" - show={expand}> - <VoterList each={voterlist in opts.voterList.subLists} voter-list={voterlist} form={parent.opts.form} ref="voterLists"/> - <voterListmember each={member in opts.voterList.members} member={member} form={parent.opts.form} ref="voterListMembers"/> - <VoterListActions if={opts.voterList.subLists.length + opts.voterList.members.length > 5} voter-list={opts.voterList} form={parent.opts.form}/> - </div> + <ContextualMenu if={!opts.form.model.isClosed} + icon="fa-ellipsis-v" + open-force={opts.form.currentVoterList.countMembers === 0 && opts.form.currentVoterList.countSubLists === 0}> + <a onclick={parent.addMember} > + <i class="fa fa-plus" aria-hidden="true"></i> + <i class="fa fa-user" aria-hidden="true"></i> + {parent.__.addMember} + </a> + <a onclick={parent.addVoterList} > + <i class="fa fa-plus" aria-hidden="true"></i> + <i class="fa fa-users" aria-hidden="true"></i> + {parent.__.addVoterList} + </a> + <a if={parent.user} + onclick={parent.importFavoriteList} > + <i class="fa fa-arrow-down" aria-hidden="true"></i> + <i class="fa fa-users" aria-hidden="true"></i> + {parent.__.importFavoriteList} + </a> + <a if={parent.user && !parent.opts.form.currentVoterList.temp} + onclick={parent.exportToFavoriteList} > + <i class="fa fa-arrow-up" aria-hidden="true"></i> + <i class="fa fa-users" aria-hidden="true"></i> + {parent.__.exportFavoriteList} + </a> + + <a if={!parent.opts.form.creation && !parent.opts.form.model.isClosed && !parent.opts.form.currentVoterList.temp} + onclick={parent.resendInvitation} > + <i class="fa fa-paper-plane" aria-hidden="true"></i> + {parent.__.resendInvitation} + </a> + + </ContextualMenu> + + <VoterListEditModal ref="createListModal" + parent-list={opts.form.currentVoterList}/> + + <VoterListMemberEditModal ref="creatMemberModal" + voter-list={opts.form.currentVoterList}/> + + <ImportFavoritListModal ref="importFavoriteListModal" + voter-list={opts.form.currentVoterList}/> <script type="es6"> let session = require("../../js/Session"); this.installBundle(session, "voterList"); let voterListService = require("../../js/VoterListService"); let favoriteListsService = require("../../js/FavoriteListService"); + let route = require("riot-route"); - this.expand = false; + this.user = session.getUser(); + + this.onUserChange = user => { + this.user = user; + this.update(); + }; - this.toggleExpand = () => { - if (this.expand) { - this.expand = false; - } else { - this.expandable(); + this.listen("user", this.onUserChange); + + this.getVoterListsStack = () => { + let stack = []; + let current = this.opts.form.currentVoterList; + while (current.parentId) { + current = voterListService.voterListsById[current.parentId]; + stack.push(current); } + return stack.reverse(); }; - this.expandable = () => { - return voterListService.loadList(this.opts.voterList).then(() => { - this.expand = true; + this.setCurrent = list => () => { + this.opts.form.setCurrentVoterList(list).then(() => { this.update(); - return Promise.resolve(); }); }; - this.submit = () => { - if (this.opts.voterList.parentId) { - this.opts.voterList.name = this.refs.name.value; - this.opts.voterList.weight = this.refs.weight.value; - } else { - this.opts.voterList.name = this.__.mainList + this.opts.form.model.title; - this.opts.voterList.weight = 1; - } - if (Array.isArray(this.refs.voterLists)) { - this.refs.voterLists.forEach(voterList => { - voterList.submit(); - }); - } else if (this.refs.voterLists) { - this.refs.voterLists.submit(); - } + this.addMember = () => { + this.refs.creatMemberModal.open().then(() => { + this.update(); + }, () => {}); + this.update(); + }; + + this.addVoterList = () => { + this.refs.createListModal.open().then(() => { + this.update(); + }, () => {}); + this.update(); + }; + + this.importFavoriteList = () => { + this.refs.importFavoriteListModal.open().then(() => { + this.update(); + }, () => {}); + this.update(); + }; - if (Array.isArray(this.refs.voterListMembers)) { - this.refs.voterListMembers.forEach(voterListMember => { - voterListMember.submit(); + this.exportToFavoriteList = () => { + if (session.getUser() && !this.opts.form.currentVoterList.temp) { + favoriteListsService.importFromVoterList(this.opts.form.currentVoterList.id).then((result) => { + route("/favoriteLists/" + result.id); + }, errors => { + this.bus.trigger("message", errors, "error"); + this.parent.update(); }); - } else if (this.refs.voterListMembers) { - this.refs.voterListMembers.submit(); } }; - </script> - - <style> + this.resendInvitation = () => { + voterListService.resendInvitationList(this.opts.form.currentVoterList).then((result) => { + let message; + if (result <= 0) { + message = this.__.resendInvitation_none; + } else if (result === 1) { + message = this.__.resendInvitation_one; + } else { + message = result + " " + this.__.resendInvitation_success; + } + this.bus.trigger("message", message, "info"); + }); + }; - .voter-list-header { - display: flex; - } + this.submit = () => { + this.opts.form.mainVoterList.name = this.__.mainList + this.opts.form.model.title; + }; - .voter-list-icone { - display: flex; - margin: 0.3em 0 auto 0; - font-size: 1.2em; - } + </script> - .voter-list-icone .fa { - margin-right: 5px; - } + <style> - .voter-list-form { - flex-grow: 1; + .elements { display: flex; - justify-content: flex-end;; flex-wrap: wrap; - } - - .voter-list-fields { - flex-grow: 1; - } - - .o-field.field-weight { - min-width: 90px; - flex-grow: 0; + justify-content: flex-start; } </style> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html deleted file mode 100644 index 94559847..00000000 --- a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListActions.tag.html +++ /dev/null @@ -1,177 +0,0 @@ -<VoterListActions> - - <button class="c-button c-button--success" - type="button" - show={!opts.form.model.isClosed} - disabled={opts.form.model.isClosed} - onclick={addMember} - title={__.addMember}> - <i class="fa fa-plus" aria-hidden="true"></i> - <i class="fa fa-user" aria-hidden="true"></i> - </button> - <button class="c-button c-button--success" - type="button" - show={!opts.form.model.isClosed} - disabled={opts.form.model.isClosed} - onclick={addVoterList} - title={__.addVoterList}> - <i class="fa fa-plus" aria-hidden="true"></i> - <i class="fa fa-users" aria-hidden="true"></i> - </button> - - <button class="c-button c-button--success" - type="button" - onclick={importFavoriteList} - show={user && !opts.form.model.isClosed} - disabled={!user || opts.form.model.isClosed} - title={__.importFavoriteList}> - <i class="fa fa-arrow-down" aria-hidden="true"></i> - <i class="fa fa-users" aria-hidden="true"></i> - </button> - - <button class="c-button c-button--info" - type="button" - onclick={exportToFavoriteList} - show={user && !opts.voterList.temp} - disabled={!user || opts.voterList.temp} - title={__.exportFavoriteList}> - <i class="fa fa-arrow-up" aria-hidden="true"></i> - <i class="fa fa-users" aria-hidden="true"></i> - </button> - - <button class="c-button c-button--info" - type="button" - show={!opts.form.creation && !opts.form.model.isClosed} - disabled={opts.form.creation || opts.form.model.isClosed} - onclick={resendInvitation} - title={__.resendInvitation}> - <i class="fa fa-paper-plane" aria-hidden="true"></i> - </button> - - <button class="c-button c-button--error" - type="button" - show={opts.voterList.parentId && !opts.form.model.isClosed} - disabled={!opts.voterList.parentId || opts.form.model.isClosed} - onclick={delete} - title={__.delete}> - <i class="fa fa-times" aria-hidden="true"></i> - </button> - - <modal header={__.importFavoriteList} - ref="importFavoriteListModal"> - <div show={favoriteLists.length === 0}> - {__.importFavoriteList_none} - </div> - <select class="c-field" - show={favoriteLists.length > 0} - ref="selectFavoriteListToImport"> - <option each={favoriteList in parent.favoriteLists} - value={favoriteList.id}> - {favoriteList.name} - </option> - </select> - </modal> - - <script type="es6"> - let session = require("../../js/Session"); - this.installBundle(session, "voterList"); - let voterListService = require("../../js/VoterListService"); - let favoriteListsService = require("../../js/FavoriteListService"); - let route = require("riot-route"); - - this.favoriteLists = []; - this.user = session.getUser(); - - this.onUserChange = user => { - this.user = user; - this.update(); - }; - - this.listen("user", this.onUserChange); - - this.addMember = () => { - this.parent.expandable().then(() => { - voterListService.addMember(this.opts.voterList); - this.parent.update(); - }); - }; - - this.addVoterList = () => { - this.parent.expandable().then(() => { - voterListService.addVoterList(this.opts.voterList); - this.parent.update(); - }); - }; - - this.delete = () => { - if (this.opts.voterList.parentId) { - this.confirm(this.__.deleteMessage).then((confirm) => { - if (confirm) { - voterListService.deleteVoterList(this.opts.voterList); - this.parent.parent.update(); - } - }); - } - }; - - this.importFavoriteList = () => { - if (session.getUser()) { - let pagination = { - order: "name", - desc: false, - pageSize: -1, - pageNumber: 0 - }; - favoriteListsService.favoriteLists(pagination).then((result) => { - this.favoriteLists = result.elements; - this.refs.importFavoriteListModal.open().then(() => { - let favoriteListId = this.refs.importFavoriteListModal.refs.selectFavoriteListToImport.value; - this.parent.expandable().then(() => { - voterListService.importFavoriteList(this.opts.voterList, favoriteListId).then(() => { - return this.parent.expandable(); - }); - }); - }, () => {}); - this.parent.update(); - }); - } - }; - - this.exportToFavoriteList = () => { - if (session.getUser() && !this.opts.voterList.temp) { - favoriteListsService.importFromVoterList(this.opts.voterList.id).then((result) => { - route("/favoriteLists/" + result.id); - }, errors => { - this.bus.trigger("message", errors); - this.parent.update(); - }); - } - }; - - this.resendInvitation = () => { - voterListService.resendInvitationList(this.opts.voterList).then((result) => { - if (result <= 0) { - this.info(this.__.resendInvitation_none); - } else if (result === 1) { - this.info(this.__.resendInvitation_one); - } else { - this.info(result + " " + this.__.resendInvitation_success); - } - }); - }; - </script> - - <style> - - voterlistactions { - display: flex; - justify-content: flex-end; - } - - voterlistactions > .c-button { - margin-left: 5px; - } - - </style> - -</VoterListActions> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListCard.tag.html new file mode 100644 index 00000000..f11fdbc5 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListCard.tag.html @@ -0,0 +1,82 @@ +require("../components/Card.tag.html"); +require("./VoterListEditModal.tag.html"); +<VoterListCard> + + <Card name={opts.voterList.name} + weight={opts.voterList.weight} + ondelete={delete} + onedit={edit} + onletterclick={opts.onletterclick} + class="list-card"> + <yield to="actions"> + <a class="info" + if={!parent.opts.form.creation && !parent.opts.form.model.isClosed && !parent.opts.voterList.temp} + title={parent.__.resendInvitation} + onclick={parent.resendInvitation}> + <i class="fa fa-paper-plane"></i> + </a> + </yield> + <yield to="detail"> + <div> + {parent.opts.voterList.countSubLists} <i class="fa fa-users"></i> + </div> + <div> + {parent.opts.voterList.countMembers} <i class="fa fa-user"></i> + </div> + </yield> + </Card> + + <VoterListEditModal ref="editModal" + voter-list={opts.voterList}/> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "voterList"); + let voterListService = require("../../js/VoterListService"); + + this.edit = () => { + this.refs.editModal.open().then(() => { + if (this.opts.onVoterListChange) { + this.opts.onVoterListChange(); + } else { + this.update(); + } + }, () => {this.update();}); + this.update(); + }; + + this.delete = () => { + this.confirm(this.__.deleteMessage).then((confirm) => { + if (confirm) { + voterListService.deleteVoterList(this.opts.voterList); + if (this.opts.onVoterListChange) { + this.opts.onVoterListChange(); + } + } + }); + }; + + this.resendInvitation = () => { + voterListService.resendInvitationList(this.opts.voterList).then((result) => { + let message; + if (result <= 0) { + message = this.__.resendInvitation_none; + } else if (result === 1) { + message = this.__.resendInvitation_one; + } else { + message = result + " " + this.__.resendInvitation_success; + } + this.bus.trigger("message", message, "info"); + }); + }; + + </script> + + <style> + .card-detail { + display: flex; + justify-content: space-around; + } + </style> + +</VoterListCard> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListEditModal.tag.html new file mode 100644 index 00000000..b33c1357 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListEditModal.tag.html @@ -0,0 +1,77 @@ +require("../popup/Modal.tag.html"); + +<VoterListEditModal> + <Modal ref="modal" + header={opts.voterList.id ? __.edit : __.new} + label={__.save} + type="success" + onsubmit={save}> + <div class="o-form-element"> + <label class="c-label" for="name">{parent.__.name}</label> + <input type="text" + id="name" + ref="name" + class="c-field" + placeholder={parent.__.name_placeholder} + value={parent.opts.voterList.name} + class="c-field {c-field--error : parent.errors.name}"> + </div> + <div class="o-form-element"> + <label class="c-label" for="email">{parent.__.weight}</label> + <input type="number" + id="weight" + ref="weight" + required + value={parent.opts.voterList.weight || 1} + step="0.01" + class="c-field {c-field--error : parent.errors.weight}"> + </div> + </Modal> + + <script type="es6"> + let session = require("../../js/Session"); + let Message = require("../../js/Message"); + this.installBundle(session, "voterList"); + let voterListService = require("../../js/VoterListService"); + + if (!this.opts.voterList) { + this.opts.voterList = {}; + } + + this.errors = {}; + + this.open = () => { + if (!this.opts.voterList.id) { + this.refs.modal.refs.name.value = ""; + this.refs.modal.refs.weight.value = 1; + } + return this.refs.modal.open(); + }; + + this.save = () => { + let promise; + if (this.opts.voterList.id) { + promise = voterListService.saveVoterList( + this.opts.voterList.id, + this.refs.modal.refs.name.value, + this.refs.modal.refs.weight.value); + } else { + promise = voterListService.addVoterList( + this.opts.parentList, + this.refs.modal.refs.name.value, + this.refs.modal.refs.weight.value); + } + return promise.then(() => { + this.errors = {}; + this.update(); + }, errors => { + this.errors = this.translateErrors(errors); + this.bus.trigger("message", this.errors, "error"); + this.update(); + return Promise.reject(); + }); + }; + + </script> + +</VoterListEditModal> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html deleted file mode 100644 index a0c71772..00000000 --- a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMember.tag.html +++ /dev/null @@ -1,101 +0,0 @@ -<VoterlistMember> - <div class="c-input-group"> - <div class="o-field o-field--icon-left o-field--icon-right"> - <i class="fa fa-user c-icon" aria-hidden="true"></i> - <input class="c-field" - type="text" - name="name" - ref="name" - disabled={opts.form.model.isClosed} - value={opts.member.name} - required - placeholder={__.name}> - <i if={!opts.form.creation} - class="fa fa-{opts.member.voting ? 'check-square-o' : 'square-o'} c-icon" aria-hidden="true"></i> - </div> - <div class="o-field"> - <input class="c-field" - type="email" - name="email" - ref="email" - disabled={opts.form.model.isClosed} - value={opts.member.email} - required - placeholder={__.email}> - </div> - <div class="o-field o-field--icon-left field-weight"> - <i class="fa fa-fw fa-balance-scale c-icon" aria-hidden="true"></i> - <input class="c-field" - type="number" - name="weight" - ref="weight" - disabled={opts.form.model.isClosed} - value={opts.member.weight} - required - placeholder={__.weight}> - </div> - <button class="c-button c-button--info" - type="button" - show={!opts.form.creation && !opts.form.model.isClosed} - disabled={opts.form.creation || opts.member.voting || opts.form.model.isClosed} - onclick={resendInvitation} - title={__.resendInvitation}> - <i class="fa fa-paper-plane" aria-hidden="true"></i> - </button> - <button class="c-button c-button--error" - type="button" - show={!opts.form.model.isClosed} - disabled={opts.form.model.isClosed} - onclick={delete} - title={__.delete}> - <i class="fa fa-times" aria-hidden="true"></i> - </button> - </div> - - <script type="es6"> - let session = require("../../js/Session"); - this.installBundle(session, "voterList_member"); - let voterListService = require("../../js/VoterListService"); - - - this.delete = () => { - this.confirm(this.__.deleteMessage).then((result) => { - if (result) { - voterListService.deleteMember(this.opts.member); - this.parent.update(); - } - }); - }; - - this.resendInvitation = () => { - voterListService.resendInvitationMember(this.opts.member).then((result) => { - this.info(result ? this.__.resendInvitation_success : this.__.resendInvitation_none); - }); - }; - - this.submit = () => { - this.opts.member.name = this.refs.name.value; - this.opts.member.email = this.refs.email.value; - this.opts.member.weight = this.refs.weight.value; - }; - - </script> - - <style> - - voterlistmember { - display: block; - margin: 5px auto; - } - - .voter-list-member-fields { - flex-grow: 1; - } - - .o-field.field-weight { - min-width: 90px; - flex-grow: 0; - } - - </style> -</VoterlistMember> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html new file mode 100644 index 00000000..ee7f14fc --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html @@ -0,0 +1,81 @@ +require("../components/Card.tag.html"); +require("./VoterListMemberEditModal.tag.html"); +<VoterListMemberCard> + + <Card name={opts.member.name} + weight={opts.member.weight} + ondelete={delete} + onEdit={edit} + class="member-card"> + <yield to="actions"> + <a class="info" + if={!parent.opts.form.creation && !parent.opts.form.model.isClosed && parent.opts.member.id && !parent.opts.member.voting} + title={parent.__.resendInvitation} + onclick={parent.resendInvitation}> + <i class="fa fa-paper-plane"></i> + </a> + </yield> + <yield to="detail"> + <span title={parent.opts.member.email}> + {parent.opts.member.email} + </span> + <i if={parent.opts.member.voting} class="voting success fa fa-check" aria-hidden="true"></i> + </yield> + </Card> + + <VoterListMemberEditModal ref="editModal" + member={opts.member}/> + + <script type="es6"> + let session = require("../../js/Session"); + this.installBundle(session, "voterList_member"); + let voterListService = require("../../js/VoterListService"); + + this.edit = () => { + this.refs.editModal.open().then(() => { + if (this.opts.onMemberChange) { + this.opts.onMemberChange(); + } else { + this.update(); + } + }, () => {this.update();}); + this.update(); + }; + + this.delete = () => { + this.confirm(this.__.deleteMessage).then((confirm) => { + if (confirm) { + voterListService.deleteMember(this.opts.member); + this.opts.onMemberChange(); + } + }); + }; + + this.resendInvitation = () => { + voterListService.resendInvitationMember(this.opts.member).then((result) => { + this.bus.trigger("message", result ? this.__.resendInvitation_success : this.__.resendInvitation_none, "info"); + }); + }; + + </script> + + <style> + + .card-detail { + font-size: 0.8em; + white-space: nowrap; + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + } + + .voting { + position: absolute; + top: 55px; + font-size: 5em; + left: 93px; + } + + </style> + +</VoterListMemberCard> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberEditModal.tag.html similarity index 56% copy from pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html copy to pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberEditModal.tag.html index 2e915c2e..b98409c0 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberEditModal.tag.html @@ -1,6 +1,6 @@ require("../popup/Modal.tag.html"); -<MemberEditModal> +<VoterListMemberEditModal> <Modal ref="modal" header={opts.member.id ? __.edit : __.new} label={__.save} @@ -12,7 +12,7 @@ require("../popup/Modal.tag.html"); id="name" ref="name" required - class="c-field" + class="c-field {c-field--error: parent.errors.email}" placeholder={parent.__.name_placeholder} value={parent.opts.member.name}> </div> @@ -25,7 +25,6 @@ require("../popup/Modal.tag.html"); class="c-field {c-field--error: parent.errors.email}" placeholder={parent.__.email_placeholder} value={parent.opts.member.email}> - <div class="c-hint c-hint--static c-hint--error" each={error in parent.errors.email}>{error}</div> </div> <div class="o-form-element"> <label class="c-label" for="email">{parent.__.weight}</label> @@ -41,9 +40,8 @@ require("../popup/Modal.tag.html"); <script type="es6"> let session = require("../../js/Session"); - let Message = require("../../js/Message"); - this.installBundle(session, "favoriteList_member"); - let favoriteListService = require("../../js/FavoriteListService"); + this.installBundle(session, "voterList_member"); + let voterListService = require("../../js/VoterListService"); if (!this.opts.member) { this.opts.member = {}; @@ -61,36 +59,31 @@ require("../popup/Modal.tag.html"); }; this.save = () => { - let member = {}; - Object.assign(member, this.opts.member); - member.name = this.refs.modal.refs.name.value; - member.email = this.refs.modal.refs.email.value; - member.weight = this.refs.modal.refs.weight.value; - let promise; - if (member.id) { - promise = favoriteListService.saveMember(this.opts.favoriteList.id, member).then(() => { - this.errors = {}; - }, errors => { - this.errors = errors; - this.bus.trigger("message", new Message(errors, "error")); - this.update(); - return Promise.reject(); - }); + if (this.opts.member.id) { + promise = voterListService.saveMember( + this.opts.member.id, + this.refs.modal.refs.name.value, + this.refs.modal.refs.email.value, + this.refs.modal.refs.weight.value); } else { - promise = favoriteListService.addMember(this.opts.favoriteList.id, member).then(() => { - this.errors = {}; - this.update(); - }, errors => { - this.errors = errors; - this.bus.trigger("message", new Message(errors, "error")); - this.update(); - return Promise.reject(); - }); + promise = voterListService.addMember( + this.opts.voterList, + this.refs.modal.refs.name.value, + this.refs.modal.refs.email.value, + this.refs.modal.refs.weight.value); } - return promise; + return promise.then(() => { + this.errors = {}; + this.update(); + }, errors => { + this.errors = this.translateErrors(errors); + this.bus.trigger("message", this.errors, "error"); + this.update(); + return Promise.reject(); + }); }; </script> -</MemberEditModal> +</VoterListMemberEditModal> diff --git a/pollen-ui-riot-js/webpack.config.js b/pollen-ui-riot-js/webpack.config.js index 7832044d..0a233ab7 100644 --- a/pollen-ui-riot-js/webpack.config.js +++ b/pollen-ui-riot-js/webpack.config.js @@ -32,7 +32,10 @@ module.exports = { new webpack.ProvidePlugin({riot: "riot"}), new CopyWebpackPlugin([ - {from: "src/main/web/conf.js"}, + {from: "src/main/web/conf.js", + transform: function(content) { + return content.toString().replace("POLLEN_API_URL", JSON.stringify(process.env.POLLEN_SERVER_CONTEXT || "http://localhost:8888/pollen-rest-api")); + }}, {from: "src/main/web/index.html"}, {from: "src/main/web/home", to: "home"}, {from: "src/main/web/robots.txt"}, -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.