From 2a68d7243655d10969cd34ca1421c18cf52a990c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Tue, 25 Oct 2016 10:44:18 +0200 Subject: [PATCH 1/2] Get in touch with project admins --- CHANGELOG.md | 4 +- app/coffee/modules/resources.coffee | 1 + app/locales/taiga/locale-en.json | 12 ++ .../contact-project-button.controller.coffee | 38 ++++++ ...tact-project-button.controller.spec.coffee | 50 +++++++ .../contact-project-button.directive.coffee | 32 +++++ .../contact-project-button.jade | 10 ++ .../contact-project-button.scss | 14 ++ .../lb-contact-project.controller.coffee | 41 ++++++ .../lb-contact-project.controller.spec.coffee | 85 ++++++++++++ .../lb-contact-project.directive.coffee | 37 +++++ .../lb-contact-project.jade | 27 ++++ .../lb-contact-project.scss | 29 ++++ .../like-project-button.jade | 7 +- .../watch-project-button.jade | 22 +-- app/modules/projects/project/project.jade | 14 +- .../projects-resource.service.coffee | 9 ++ app/partials/admin/admin-project-profile.jade | 12 ++ app/styles/components/track-btn.scss | 126 +++++++++--------- .../modules/admin/admin-project-profile.scss | 11 +- app/styles/modules/home-project.scss | 7 + app/svg/sprite.svg | 3 + e2e/helpers/project-detail-helper.js | 8 ++ .../admin/project/project-detail.e2e.js | 15 +++ e2e/suites/project-home.e2e.js | 26 +++- 25 files changed, 550 insertions(+), 90 deletions(-) create mode 100644 app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee create mode 100644 app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee create mode 100644 app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee create mode 100644 app/modules/projects/components/contact-project-button/contact-project-button.jade create mode 100644 app/modules/projects/components/contact-project-button/contact-project-button.scss create mode 100644 app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee create mode 100644 app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee create mode 100644 app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee create mode 100644 app/modules/projects/components/lb-contact-project/lb-contact-project.jade create mode 100644 app/modules/projects/components/lb-contact-project/lb-contact-project.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 2969887e..d452b6f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # Changelog # - ## 3.1.0 No name yet (no date yet) + +### Features +- Contact with the project: if the projects have this module enabled Taiga users can contact them. - Velocity forecasting. Create sprints according to team velocity. - Remove bower - Add new wysiwyg editor (like the Medunm editor) with emojis, local storage changes, mentions... diff --git a/app/coffee/modules/resources.coffee b/app/coffee/modules/resources.coffee index f8b0a7be..adc6daed 100644 --- a/app/coffee/modules/resources.coffee +++ b/app/coffee/modules/resources.coffee @@ -74,6 +74,7 @@ urls = { "project-unlike": "/projects/%s/unlike" "project-watch": "/projects/%s/watch" "project-unwatch": "/projects/%s/unwatch" + "project-contact": "contact" "project-transfer-validate-token": "/projects/%s/transfer_validate_token" "project-transfer-accept": "/projects/%s/transfer_accept" "project-transfer-reject": "/projects/%s/transfer_reject" diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index 9eb45448..c82506d2 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -194,6 +194,7 @@ "BUTTON_TITLE": "Upvote/Downvote this item", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, + "CUSTOM_ATTRIBUTES": { "CUSTOM_FIELDS": "Custom Fields", "SAVE": "Save Custom Field", @@ -519,6 +520,7 @@ "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Who are you looking for?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Public project", "PRIVATE_PROJECT": "Private project", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", @@ -959,6 +961,10 @@ "UNWATCH": "Unwatch", "UNWATCH_TITLE": "Unwatch this project" } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" } }, "LIGHTBOX": { @@ -1044,6 +1050,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee b/app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee new file mode 100644 index 00000000..839b28b2 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee @@ -0,0 +1,38 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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 Affero 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 . +# +# File: like-project-button.controller.coffee +### + +class ContactProjectButtonController + @.$inject = ['tgLightboxFactory'] + + constructor: (@lightboxFactory)-> + + launchContactForm: () -> + @lightboxFactory.create( + 'tg-lb-contact-project', + { + "class": "lightbox lightbox-contact-project e2e-lightbox-contact-project", + "project": "project" + }, + { + "project": @.project + } + ) + + +angular.module("taigaProjects").controller("ContactProjectButtonCtrl", ContactProjectButtonController) diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee b/app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee new file mode 100644 index 00000000..13c42bc6 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee @@ -0,0 +1,50 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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 Affero 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 . +# +# File: contact-project-button.controller.spec.coffee +### + +describe "ContactProjectButton", -> + provide = null + controller = null + mocks = {} + + _mockTgLightboxFactory = () -> + mocks.tgLightboxFactory = { + create: sinon.stub() + } + + provide.value "tgLightboxFactory", mocks.tgLightboxFactory + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockTgLightboxFactory() + + return null + + beforeEach -> + module "taigaProjects" + + _mocks() + + inject ($controller) -> + controller = $controller + + it "Launch Contact Form", () -> + ctrl = controller("ContactProjectButtonCtrl") + ctrl.launchContactForm() + expect(mocks.tgLightboxFactory.create).have.been.called diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee b/app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee new file mode 100644 index 00000000..ed41564f --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee @@ -0,0 +1,32 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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 Affero 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 . +# +# File: contact-project-button.directive.coffee +### + +ContactProjectButtonDirective = -> + return { + scope: {} + controller: "ContactProjectButtonCtrl", + bindToController: { + project: '=' + layout: '@' + } + controllerAs: "vm", + templateUrl: "projects/components/contact-project-button/contact-project-button.html", + } + +angular.module("taigaProjects").directive("tgContactProjectButton", ContactProjectButtonDirective) diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.jade b/app/modules/projects/components/contact-project-button/contact-project-button.jade new file mode 100644 index 00000000..7b6638f4 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.jade @@ -0,0 +1,10 @@ +button.track-button.contact-team.e2e-contact-team( + title="{{ 'PROJECT.CONTACT_BUTTON.CONTACT_TITLE' | translate }}" + ng-click="vm.launchContactForm()" + ng-class="{'contact-team-large': vm.layout == 'large'}" +) + tg-svg(svg-icon="icon-mail") + span( + ng-if="vm.layout == 'large'" + translate="PROJECT.CONTACT_BUTTON.CONTACT_BUTTON" + ) diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.scss b/app/modules/projects/components/contact-project-button/contact-project-button.scss new file mode 100644 index 00000000..ece4ccba --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.scss @@ -0,0 +1,14 @@ +.contact-team { + margin-left: .75rem; + &-large { + @include font-size(small); + @include font-type(light); + justify-content: center; + margin-left: 0; + width: 100%; + .icon-mail { + margin-right: .5rem; + vertical-align: center; + } + } +} diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee new file mode 100644 index 00000000..33657083 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee @@ -0,0 +1,41 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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 Affero 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 . +# +# File: lb-contact-team.controller.coffee +### + +class ContactProjectLbController + @.$inject = [ + "lightboxService", + "tgResources", + "$tgConfirm", + ] + + constructor: (@lightboxService, @rs, @confirm) -> + @.contact = {} + + contactProject: () -> + project = @.project.get('id') + message = @.contact.message + + promise = @rs.projects.contactProject(project, message) + @.sendingFeedback = true + promise.then => + @lightboxService.closeAll() + @.sendingFeedback = false + @confirm.notify("success") + +angular.module("taigaProjects").controller("ContactProjectLbCtrl", ContactProjectLbController) diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee new file mode 100644 index 00000000..6700e424 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee @@ -0,0 +1,85 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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 Affero 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 . +# +# File: lb/contact-project-button.controller.spec.coffee +### + +describe "LbContactProject", -> + provide = null + controller = null + mocks = {} + + _mockTgLightboxSercice = () -> + mocks.tglightboxService = { + closeAll: sinon.stub() + } + + provide.value "lightboxService", mocks.tglightboxService + + _mockTgResources = () -> + mocks.tgResources = { + projects: { + contactProject: sinon.stub() + } + } + + provide.value "tgResources", mocks.tgResources + + _mockTgConfirm = () -> + mocks.tgConfirm = { + notify: sinon.stub() + } + + provide.value "$tgConfirm", mocks.tgConfirm + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockTgLightboxSercice() + _mockTgResources() + _mockTgConfirm() + + return null + + beforeEach -> + module "taigaProjects" + + _mocks() + + inject ($controller) -> + controller = $controller + + it "Contact Project", (done) -> + ctrl = controller("ContactProjectLbCtrl") + ctrl.contact = { + message: 'abcde' + } + ctrl.project = Immutable.fromJS({ + id: 1 + }) + + project = ctrl.project.get('id') + message = ctrl.contact.message + + promise = mocks.tgResources.projects.contactProject.withArgs(project, message).promise().resolve() + + ctrl.sendingFeedback = true + + ctrl.contactProject().then () -> + expect(mocks.tglightboxService.closeAll).have.been.called + expect(ctrl.sendingFeedback).to.be.false + expect(mocks.tgConfirm.notify).have.been.calledWith("success") + done() diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee b/app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee new file mode 100644 index 00000000..8a8bd88f --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee @@ -0,0 +1,37 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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 Affero 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 . +# +# File: lb-contact-team.directive.coffee +### + +ContactProjectLbDirective = (lightboxService) -> + + @.inject = ['lightboxService'] + + link = (scope, el) -> + lightboxService.open(el) + + return { + controller: "ContactProjectLbCtrl", + bindToController: { + project: '=' + } + controllerAs: "vm", + templateUrl: "projects/components/lb-contact-project/lb-contact-project.html", + link: link + } + +angular.module("taigaProjects").directive("tgLbContactProject", ["lightboxService", ContactProjectLbDirective]) diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.jade b/app/modules/projects/components/lb-contact-project/lb-contact-project.jade new file mode 100644 index 00000000..f43fd711 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.jade @@ -0,0 +1,27 @@ +tg-lightbox-close + +form.lightbox-contact-project-container + img.lightbox-contact-project-logo( + ng-if="vm.project.logo_big_url" + alt="{{vm.project.get('name')}}" + ng-src="vm.project.logo_big_url" + ) + img.lightbox-contact-project-logo( + ng-if="!vm.project.logo_big_url" + tg-project-logo-big-src="vm.project" + alt="{{vm.project.get('name')}}" + ) + h2.lightbox-contact-project-title(translate="LIGHTBOX.CONTACT_PROJECT.TITLE") + h3.lightbox-contact-project-name {{vm.project.get('name')}} + p(translate="LIGHTBOX.CONTACT_PROJECT.WARNING") + textarea.lightbox-contact-project-message.e2e-lightbox-contact-project-message( + ng-model="vm.contact.message" + required + placeholder="{{'LIGHTBOX.CONTACT_PROJECT.PLACEHOLDER' | translate}}" + ) + button.button-green.lightbox-contact-project-button.e2e-lightbox-contact-project-button( + translate="LIGHTBOX.CONTACT_PROJECT.SEND" + ng-click="vm.contactProject()" + tg-loading="vm.sendingFeedback" + ng-disabled="!vm.contact.message.length" + ) diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.scss b/app/modules/projects/components/lb-contact-project/lb-contact-project.scss new file mode 100644 index 00000000..4cc6e3af --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.scss @@ -0,0 +1,29 @@ +.lightbox-contact-project { + align-items: center; + display: flex; + justify-content: center; + &-container { + max-width: 600px; + text-align: center; + width: 90%; + } + &-logo { + width: 5rem; + } + &-title { + margin: 0; + } + &-name { + @include font-size(larger); + color: $primary; + margin-bottom: 1rem; + } + &-message { + max-height: 400px; + } + &-button { + display: block; + margin-top: .5rem; + width: 100%; + } +} diff --git a/app/modules/projects/components/like-project-button/like-project-button.jade b/app/modules/projects/components/like-project-button/like-project-button.jade index de8da23f..57fc69b0 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.jade +++ b/app/modules/projects/components/like-project-button/like-project-button.jade @@ -1,5 +1,4 @@ -a.track-button.like-button.like-container( - href="", +button.track-button.like-button( title="{{ 'PROJECT.LIKE_BUTTON.BUTTON_TITLE' | translate }}" ng-click="vm.toggleLike()" ng-class="{'active':vm.project.get('is_fan'), 'is-hover':vm.project.get('is_fan') && vm.isMouseOver}" @@ -21,9 +20,7 @@ a.track-button.like-button.like-container( ng-if="vm.project.get('is_fan') && vm.isMouseOver" translate="PROJECT.LIKE_BUTTON.UNLIKE" ) - span.track-button-counter( title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_fans\")||0}:'messageformat' }}", tg-loading="vm.loading" - ) - | {{ vm.project.get('total_fans') }} + ) {{ vm.project.get('total_fans') }} diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.jade b/app/modules/projects/components/watch-project-button/watch-project-button.jade index dff7401a..2ad65e58 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.jade +++ b/app/modules/projects/components/watch-project-button/watch-project-button.jade @@ -1,5 +1,4 @@ -a.track-button.watch-button.watch-container( - href="", +button.track-button.watch-button( title="{{ 'PROJECT.WATCH_BUTTON.BUTTON_TITLE' | translate }}" ng-click="vm.toggleWatcherOptions()" ng-class="{'active': vm.project.get('is_watcher')}" @@ -7,24 +6,25 @@ a.track-button.watch-button.watch-container( span.track-inner span.track-icon tg-svg(svg-icon="icon-watch") - span(ng-if="!vm.project.get('is_watcher')", translate="PROJECT.WATCH_BUTTON.WATCH") - span(ng-if="vm.project.get('is_watcher')", translate="PROJECT.WATCH_BUTTON.WATCHING") + span( + ng-if="!vm.project.get('is_watcher')" + translate="PROJECT.WATCH_BUTTON.WATCH" + ) + span( + ng-if="vm.project.get('is_watcher')" + translate="PROJECT.WATCH_BUTTON.WATCHING" + ) tg-svg.watch-options-arrow(svg-icon="icon-arrow-down") span.track-button-counter( - title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_watchers\")||0}:'messageformat' }}", + title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_watchers\")||0}:'messageformat' }}" tg-loading="vm.loading" - ) - | {{ vm.project.get('total_watchers') }} + ) {{ vm.project.get('total_watchers') }} ul.watch-options( ng-class="{'hidden': !vm.showWatchOptions}" ng-mouseleave="vm.closeWatcherOptions()" ) - //- NOTIFY LEVEL CHOICES: - //- 1 - Only involved - //- 2 - Receive all - //- 3 - No notifications li a( diff --git a/app/modules/projects/project/project.jade b/app/modules/projects/project/project.jade index 01feadbc..fd5949e1 100644 --- a/app/modules/projects/project/project.jade +++ b/app/modules/projects/project/project.jade @@ -25,6 +25,10 @@ div.wrapper div.track-buttons-container(ng-if="vm.user") tg-like-project-button(project="vm.project") tg-watch-project-button(project="vm.project") + tg-contact-project-button( + ng-if="vm.project.get('is_contact_activated')" + project="vm.project" + ) div.track-container(ng-if="!vm.user") .list-itemtype-track @@ -56,9 +60,13 @@ div.wrapper src="/#{v}/images/looking-for-people.png" title="{{'PROJECT.LOOKING_FOR_PEOPLE' | translate}}" ) - h3 {{'PROJECT.LOOKING_FOR_PEOPLE' | translate}} - p(ng-if="vm.project.get('looking_for_people_note')") - | {{::vm.project.get('looking_for_people_note')}} + h3(ng-class="{'is-empty': !vm.project.get('looking_for_people_note')}") {{'PROJECT.LOOKING_FOR_PEOPLE' | translate}} + p(ng-if="vm.project.get('looking_for_people_note')") {{::vm.project.get('looking_for_people_note')}} + tg-contact-project-button( + ng-if="vm.project.get('is_contact_activated')" + project="vm.project" + layout="large" + ) h2.title {{"PROJECT.SECTION.TEAM" | translate}} ul.involved-team diff --git a/app/modules/resources/projects-resource.service.coffee b/app/modules/resources/projects-resource.service.coffee index 9df02c3a..82942b37 100644 --- a/app/modules/resources/projects-resource.service.coffee +++ b/app/modules/resources/projects-resource.service.coffee @@ -108,6 +108,15 @@ Resource = (urlsService, http, paginateResponseService) -> url = urlsService.resolve("project-unwatch", projectId) return http.post(url) + service.contactProject = (projectId, message) -> + params = { + project: projectId, + comment: message + } + + url = urlsService.resolve("project-contact") + return http.post(url, params) + service.transferValidateToken = (projectId, token) -> data = { token: token diff --git a/app/partials/admin/admin-project-profile.jade b/app/partials/admin/admin-project-profile.jade index 50a41dc9..bd37c9cb 100644 --- a/app/partials/admin/admin-project-profile.jade +++ b/app/partials/admin/admin-project-profile.jade @@ -119,6 +119,18 @@ div.wrapper( ng-model="project.looking_for_people_note" placeholder="{{ 'ADMIN.PROJECT_PROFILE.RECRUITING_PLACEHOLDER' | translate }}" ) + + fieldset.get-feedback + .get-feedback-inner + span {{ 'ADMIN.PROJECT_PROFILE.FEEDBACK' | translate }} + div.check + input( + type="checkbox", + ng-model="project.is_contact_activated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") tg-admin-project-restrictions(project="project") diff --git a/app/styles/components/track-btn.scss b/app/styles/components/track-btn.scss index 221d893a..62d76f5a 100644 --- a/app/styles/components/track-btn.scss +++ b/app/styles/components/track-btn.scss @@ -1,6 +1,3 @@ -////////////////////// -//Watch like buttons -////////////////////// .track-buttons-container { @include font-size(small); @@ -9,75 +6,80 @@ .track-button { align-items: stretch; - display: inline-flex; - position: relative; - .track-inner { - align-items: center; - background: $mass-white; - border-radius: 4px 0 0 4px; - display: flex; - flex: 1; - flex-basis: 140px; - justify-content: flex-start; - margin-right: .1rem; - min-width: 140px; - &:hover { - background: darken($mass-white, 5%); - transition: background .3s; - } - } - .watch-options-arrow { - margin: 0 .5rem 0 auto; - svg { - @include svg-size(.75rem); - } - } - &:hover { - color: $blackish; - } + display: flex; + margin: 0; + padding: 0; &.active { .track-inner { background: rgba($primary-light, .2); } - .track-icon { - svg { - fill: $primary; - } + .icon { + fill: $primary; + } + .track-button-counter { + background: rgba($primary-light, .4); } } - &.watch-container { - margin-right: 1rem; - position: relative; - } - .track-icon { - padding: .3rem .6rem .3rem .75rem; - svg { - fill: $grayer; - position: relative; - top: 2px; + &.is-hover { + .track-inner { + background: lighten($red, 10%); + color: $whitish; + transition: background .2s; + } + .icon { + fill: $red-light; + } + .track-button-counter { + background: $red; + color: $whitish; + transition: background .2s; } } - .track-button-counter { - align-items: center; - border: 1px solid $whitish; - display: flex; - justify-content: center; - min-width: 2rem; + .watch-options-arrow { + margin-left: auto; + } + .icon-arrow-down { + @include svg-size(.75rem); } } -.watch-button, -.like-button { - &.active { - &.is-hover { - .track-inner { - background: $red; - color: $whitish; - transition: background .3s; - } - svg { - fill: $red-light; - } - } + +.track-inner { + align-items: center; + background: $whitish; + border-radius: 4px 0 0 4px; + display: flex; + flex: 1; + flex-basis: 140px; + justify-content: flex-start; + min-width: 140px; + padding: .25rem 1rem; + &:hover { + background: darken($whitish, 5%); + transition: background .3s; + } +} + +.track-icon { + fill: $grayer; + margin-right: .5rem; + position: relative; + top: 2px; +} + +.track-button-counter { + align-items: center; + background: darken($whitish, 5%); + border-radius: 0 4px 4px 0; + padding: .25rem .75rem; +} + +.contact-team { + background: $whitish; + border-radius: 4px; + padding: .25rem .75rem; + &:hover { + background: darken($whitish, 5%); + transition: background .3s; } } diff --git a/app/styles/modules/admin/admin-project-profile.scss b/app/styles/modules/admin/admin-project-profile.scss index 31060629..0984f6f6 100644 --- a/app/styles/modules/admin/admin-project-profile.scss +++ b/app/styles/modules/admin/admin-project-profile.scss @@ -1,13 +1,18 @@ @import '../dependencies/mixins/profile-form'; .project-details { @include profile-form; - .looking-for-people { + .looking-for-people, + .get-feedback { @include font-type(light); border-bottom: 1px solid $whitish; - border-top: 1px solid $whitish; padding: 1rem 0; } - .looking-for-people-selector { + .looking-for-people { + border-top: 1px solid $whitish; + margin-bottom: 0; + } + .looking-for-people-selector, + .get-feedback-inner { align-items: center; display: flex; svg { diff --git a/app/styles/modules/home-project.scss b/app/styles/modules/home-project.scss index 3da70541..db929b69 100644 --- a/app/styles/modules/home-project.scss +++ b/app/styles/modules/home-project.scss @@ -79,9 +79,16 @@ h3 { @include font-size(small); } + .is-empty { + margin-bottom: .5rem; + } p { @include font-size(small); @include font-type(light); + margin-bottom: .5rem; + } + .contact-team { + margin-bottom: 1rem; } } .involved-data { diff --git a/app/svg/sprite.svg b/app/svg/sprite.svg index 869e7c00..bfbdeb26 100644 --- a/app/svg/sprite.svg +++ b/app/svg/sprite.svg @@ -454,5 +454,8 @@ Broken Link + + + diff --git a/e2e/helpers/project-detail-helper.js b/e2e/helpers/project-detail-helper.js index 88f2c81a..784612d2 100644 --- a/e2e/helpers/project-detail-helper.js +++ b/e2e/helpers/project-detail-helper.js @@ -14,6 +14,14 @@ helper.toggleIsLookingForPeople = function() { helper.lookingForPeople().click(); }; +helper.receiveFeedback = function() { + return $$('.get-feedback input').get(0); +}; + +helper.togglereceiveFeedback = function() { + helper.receiveFeedback().click(); +}; + helper.editLogo = function() { let inputFile = $('#logo-field'); diff --git a/e2e/suites/admin/project/project-detail.e2e.js b/e2e/suites/admin/project/project-detail.e2e.js index 033015a4..2034f4d0 100644 --- a/e2e/suites/admin/project/project-detail.e2e.js +++ b/e2e/suites/admin/project/project-detail.e2e.js @@ -67,6 +67,21 @@ describe('project detail', function() { expect(utils.notifications.success.open()).to.be.eventually.equal(true); }); + it('receive feedback', async function() { + let checked = !! await adminHelper.receiveFeedback().getAttribute('checked'); + + if(!checked) { + adminHelper.togglereceiveFeedback(); + } + + $('button[type="submit"]').click(); + + checked = !! await adminHelper.receiveFeedback().getAttribute('checked'); + + expect(checked).to.be.true; + expect(utils.notifications.success.open()).to.be.eventually.equal(true); + }); + it('edit logo', async function() { let imageContainer = $('.image-container'); diff --git a/e2e/suites/project-home.e2e.js b/e2e/suites/project-home.e2e.js index 087e3477..6278abd7 100644 --- a/e2e/suites/project-home.e2e.js +++ b/e2e/suites/project-home.e2e.js @@ -14,7 +14,7 @@ describe('project home', function() { await utils.common.takeScreenshot("project", "home-like"); //reset - let link = $('tg-like-project-button a'); + let link = $('tg-like-project-button button'); let likeActive = await utils.common.hasClass(link, 'active'); if (!likeActive) { @@ -47,7 +47,7 @@ describe('project home', function() { }); */ it('unlike', async function() { - let link = $('tg-like-project-button a'); + let link = $('tg-like-project-button button'); let likesCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); link.click(); @@ -62,7 +62,7 @@ describe('project home', function() { }); it('like', async function() { - let link = $('tg-like-project-button a'); + let link = $('tg-like-project-button button'); let likesCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); link.click(); @@ -77,8 +77,24 @@ describe('project home', function() { expect(likesCounter).to.be.equal(likesCounterOld + 1); }); + it('contact project', async function() { + $('tg-contact-project-button > .e2e-contact-team').click(); + + let contactProjectLb = $('div[tg-lb-contact-project]'); + + await utils.lightbox.open(contactProjectLb); + await utils.common.takeScreenshot("project", "contact-form"); + + let form = $('.e2e-lightbox-contact-project'); + + await form.$('.e2e-lightbox-contact-project-message').sendKeys('contact'); + form.$('.e2e-lightbox-contact-project-button').click(); + await utils.notifications.success.open(); + + }); + it('unwatch', async function() { - let link = $('tg-watch-project-button > a'); + let link = $('tg-watch-project-button > button'); let watchOptions = $('tg-watch-project-button .watch-options'); let watchCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); @@ -104,7 +120,7 @@ describe('project home', function() { }); it('watch', async function() { - let link = $('tg-watch-project-button > a'); + let link = $('tg-watch-project-button > button'); let watchOptions = $('tg-watch-project-button .watch-options'); let watchCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); From 4a7a09e331a22aefa7bd56ecdbff4849dd2083cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Fri, 28 Oct 2016 13:46:48 +0200 Subject: [PATCH 2/2] Update looking for people image --- app/images/looking-for-people.png | Bin 18714 -> 9013 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/images/looking-for-people.png b/app/images/looking-for-people.png index 8980016496580887560865cfdbdcf72898fac981..01b4e4ed79416eed08899e65d17b03a92020bcf6 100644 GIT binary patch delta 8974 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�Er%=pX=q>8b>}Z>Q-!oLYWRWG;9O4k_*l?j z=5nvXxhn4W50_+^U>iob@3-;b)rRMm@!iRSl&q|%S6ipO|Hu1VWNa)npvig;cCFQM zGzx<{F)=Y{Xh^KJPX&;{@9k25UQ}1d%*M|CD={%hHl69S(*D+Q3^)537DmE&UWy#K z=T=k2XK@vO8F6F#c()!qH_agXL-4pe=qKVPP2||OxO2GuSiZa+!riso8!Q!%QN#1J ztp1U!J8YTpujeJNk5;z6^AA-EHWN8K7y`ccL*xnkAsd}BFLL=juCVgin-g6HbH`36 z^R%C7_FIeL&%^{nX}4Ru-i%GNgZX9m0};UJ=5TW6*bNmLLR(w=_ljL21-wl&9{;px ziAte#GS#~UTZ4v0Ur4cx_Y;ECC}i2yN&~0KuV z0Kp~Brepr_=;f3{?X3y{&p8RS$`VmdAc!ztRAc?{^LV z6&8xqaWnR}l)CN~)8h*Q0pQ4=ndi3WGGSWQtGa#v)=|Q3MfcUFZryOhdgDymx!K>w zQ91>a&$ZM8*{RswFSt_AaxzZP@NmM$#?9cAFSY#q%OujF&&1$viJOl^ot3DNZHijp z_5NSTV4utG2NttGsIOOpD4+EMu-y*IqqpkxzOisSTdv=3{A(r>hsWWxI}{btxL&K@ zxt`bSxFtAWu3RK$3>8#RKmrX7ZS?vG1^}{8$zFD*KT;pm>EmR&T^{SYQbvP!GvlhV z&gL+P%xVihq+56$pB8lPY6P0sOyV(+|Asul_=>DMq}TlAij|7kzREwAa%|VccDv2H zqWa)ND{xe*eECzMS~k<>Yzhzxg+=;px55^S$AQr8`!EuTMy^z6AYf)`X*&25Nvq3? z_5NbxbTRPx_SozF2?Rc^>-}bjcq6T#Fw*9{clGwLmCh@vo!0N%TCGaAi=lmiT_aY> zQ0Akal)lcK10T%JZGR}H&BmYWY(8(J1XgsNOW1@>u4}iO)WB$V&kMXkF{Gkf`-n=j z7=9J$UMJ$PJW5V}Y?>hObAR8=ZmWlo zD!KEb#CECnXuX{s76~t`(bAEMN>*Ne`1R>#w$V~?B8#KSsF@)O2s!F}lIYTFMX6Fj zzup~U7Go_tkL#F$|Lz!iK5%4)&^)W<+0O*Ha(tXLlJ;nL-Ind8%HL8YeGFvgPI!RW zcRd)xny=MgtC1_4+o>NV8Z=E1&?rUQ40y4BeZ86Xx?iz$zB^HehJ^*{wmK}=n|=ui z4Ru`Ga%dGT>pUVs)`OQ?#sjvsOS9H8opMwQ5_E4m(?W8wVjG$IktH!)$!2h z%X*iNYFEOf(%X$}8FKWuv7r+Yx$qOl<#r;0MXuJ8(v^`x7#MJ9zhgtSr=1)ZXS@OU zZ}dspWOAT!0Qx9(T<7e3Yl#$I3dGL49y&oVfbBBd@)PWv8=P*sBV`%2J3v92qGG%G z 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 IM6N<$f(lzd*#H0l