From 9a833dae69553905f7a13f44d759b0d4618659d7 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Thu, 19 May 2016 19:21:43 -0700 Subject: [PATCH 1/2] Replace styles on new-user form This is a new structured approach to styling components. For now I'm placing the files in newcomponents/ directory but once we have replaced styles on the rest of the site the components/ directors will be removed. Individual ember components get a class and then we use mixins as functions to apply the actual styles to the page. Hopefully this gives us a bunch of re-uability without needing to put things in a global style space at all. --- app/components/click-choice-buttons.js | 1 + app/components/new-user.js | 2 +- app/styles/_variables.scss | 1 + app/styles/app.scss | 2 + app/styles/components/_global.scss | 23 -- app/styles/mixins.scss | 1 + app/styles/mixins/ilios-form.scss | 53 +++ app/styles/newcomponents.scss | 1 + app/styles/newcomponents/new-user.scss | 27 ++ app/templates/components/new-user.hbs | 302 +++++++++--------- tests/integration/components/new-user-test.js | 4 +- 11 files changed, 239 insertions(+), 178 deletions(-) create mode 100644 app/styles/mixins.scss create mode 100644 app/styles/mixins/ilios-form.scss create mode 100644 app/styles/newcomponents.scss create mode 100644 app/styles/newcomponents/new-user.scss diff --git a/app/components/click-choice-buttons.js b/app/components/click-choice-buttons.js index 15cb6ddf59..e6beade679 100644 --- a/app/components/click-choice-buttons.js +++ b/app/components/click-choice-buttons.js @@ -3,6 +3,7 @@ import Ember from 'ember'; const { $, Component, on } = Ember; export default Component.extend({ + classNames: ['click-choice-buttons'], firstChoicePicked: true, buttonContent1: null, diff --git a/app/components/new-user.js b/app/components/new-user.js index b06e122676..f41c43bb98 100644 --- a/app/components/new-user.js +++ b/app/components/new-user.js @@ -58,5 +58,5 @@ const Validations = buildValidations({ }); export default Component.extend(NewUser, Validations, { - + classNames: ['new-user'], }); diff --git a/app/styles/_variables.scss b/app/styles/_variables.scss index 1def1e0c53..ef833f21ad 100644 --- a/app/styles/_variables.scss +++ b/app/styles/_variables.scss @@ -74,6 +74,7 @@ $base-link-color: $base-accent-color; $hover-link-color: darken($base-accent-color, 15); // Neat Breakpoints +$small-screen: em(320); $medium-screen: em(640); $large-screen: em(860); $giant-screen: em(1480); diff --git a/app/styles/app.scss b/app/styles/app.scss index b83d5fcf5b..54eb261745 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -60,4 +60,6 @@ @import 'components/school-manager'; @import 'components/assign-students'; @import 'components/pre-fill'; +@import 'mixins'; +@import 'newcomponents'; @import 'layout/layout'; diff --git a/app/styles/components/_global.scss b/app/styles/components/_global.scss index 0513532494..b2f99292f2 100644 --- a/app/styles/components/_global.scss +++ b/app/styles/components/_global.scss @@ -307,29 +307,6 @@ select:hover { width: 1px; } -//scrollbar style */ -::-webkit-scrollbar { - width: 9px; -} - -::-webkit-scrollbar-track { - background: rgba(0, 0, 0, .02); - border-radius: 5px; -} - -::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, .2); - border-radius: 5px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgba(0, 0, 0, .4); -} - -::-webkit-scrollbar-thumb:window-inactive { - background: rgba(0, 0, 0, .05); -} - .list-reset { ul { list-style-position: inside; diff --git a/app/styles/mixins.scss b/app/styles/mixins.scss new file mode 100644 index 0000000000..96db21bfb0 --- /dev/null +++ b/app/styles/mixins.scss @@ -0,0 +1 @@ +@import 'mixins/ilios-form'; diff --git a/app/styles/mixins/ilios-form.scss b/app/styles/mixins/ilios-form.scss new file mode 100644 index 0000000000..3ae84f1eda --- /dev/null +++ b/app/styles/mixins/ilios-form.scss @@ -0,0 +1,53 @@ +@mixin ilios-form () { + label { + @include fill-parent; + display: block; + font-weight: bold; + margin-top: 1em; + } + + input[type=text], + input[type=password], + select { + @include fill-parent; + background-position: right 4px bottom .75em; + height: 2.5em; + } + + input { + @include fill-parent; + background: $white; + border: 1px solid $input-box-grey; + border-radius: $base-border-radius; + } +} + +@mixin ilios-form-item () { + @include fill-parent; + height: 6em; + + @include media($large-screen) { + @include span-columns(4); + } + +} + +@mixin ilios-form-last-item () { + @include fill-parent; + + @include media($large-screen) { + @include span-columns(8); + } +} + +@mixin ilios-form-buttons () { + @include fill-parent; + clear: both; + margin-top: 2em; + padding: 1em 0; + + button { + margin-right: 1em; + } + +} diff --git a/app/styles/newcomponents.scss b/app/styles/newcomponents.scss new file mode 100644 index 0000000000..a15925b4eb --- /dev/null +++ b/app/styles/newcomponents.scss @@ -0,0 +1 @@ +@import 'newcomponents/new-user'; diff --git a/app/styles/newcomponents/new-user.scss b/app/styles/newcomponents/new-user.scss new file mode 100644 index 0000000000..c224393f0f --- /dev/null +++ b/app/styles/newcomponents/new-user.scss @@ -0,0 +1,27 @@ +.new-user { + .new-user-form { + @include ilios-form; + @include fill-parent; + display: block; + + .click-choice-buttons { + @include fill-parent; + @include clearfix; + display: block; + margin-bottom: .5em; + min-height: 1em; + } + + .item { + @include ilios-form-item; + + &.last { + @include ilios-form-last-item; + } + } + + .buttons { + @include ilios-form-buttons; + } + } +} diff --git a/app/templates/components/new-user.hbs b/app/templates/components/new-user.hbs index 500ce71c38..fae5244c74 100644 --- a/app/templates/components/new-user.hbs +++ b/app/templates/components/new-user.hbs @@ -1,166 +1,164 @@
{{t 'user.new'}}
-
-
- -
- {{click-choice-buttons - buttonContent1=(t 'general.nonStudent') - buttonContent2=(t 'general.student') - firstChoicePicked=nonStudentMode - action='setNonStudentMode' - }} -
- -
- {{one-way-input - value=firstName - update=(action (mut firstName)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'firstName') - }} - {{#if (and (v-get this 'firstName' 'isInvalid') (is-in showErrorsFor 'firstName'))}} - {{v-get this 'firstName' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=middleName - update=(action (mut middleName)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'middleName') - }} - {{#if (and (v-get this 'middleName' 'isInvalid') (is-in showErrorsFor 'middleName'))}} - {{v-get this 'middleName' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=lastName - update=(action (mut lastName)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'lastName') - }} - {{#if (and (v-get this 'lastName' 'isInvalid') (is-in showErrorsFor 'lastName'))}} - {{v-get this 'lastName' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=campusId - update=(action (mut campusId)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'campusId') - }} - {{#if (and (v-get this 'campusId' 'isInvalid') (is-in showErrorsFor 'campusId'))}} - {{v-get this 'campusId' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=otherId - update=(action (mut otherId)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'otherId') - }} - {{#if (and (v-get this 'otherId' 'isInvalid') (is-in showErrorsFor 'otherId'))}} - {{v-get this 'otherId' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=email - update=(action (mut email)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'email') - }} - {{#if (and (v-get this 'email' 'isInvalid') (is-in showErrorsFor 'email'))}} - {{v-get this 'email' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=phone - update=(action (mut phone)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'phone') - }} - {{#if (and (v-get this 'phone' 'isInvalid') (is-in showErrorsFor 'phone'))}} - {{v-get this 'phone' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=username - update=(action (mut username)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'username') - }} - {{#if (and (v-get this 'username' 'isInvalid') (is-in showErrorsFor 'username'))}} - {{v-get this 'username' 'message'}} - {{/if}} -
- -
- {{one-way-input - value=password - update=(action (mut password)) - onenter=(action "save") - onescape=(action this.attrs.close) - focusOut=(action 'addErrorDisplayFor' 'password') - }} - {{#if (and (v-get this 'password' 'isInvalid') (is-in showErrorsFor 'password'))}} - {{v-get this 'password' 'message'}} - {{/if}} -
- +
+
+ + {{click-choice-buttons + buttonContent1=(t 'general.nonStudent') + buttonContent2=(t 'general.student') + firstChoicePicked=nonStudentMode + action='setNonStudentMode' + }} +
+
+ + {{one-way-input + value=firstName + update=(action (mut firstName)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'firstName') + }} + {{#if (and (v-get this 'firstName' 'isInvalid') (is-in showErrorsFor 'firstName'))}} + {{v-get this 'firstName' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=middleName + update=(action (mut middleName)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'middleName') + }} + {{#if (and (v-get this 'middleName' 'isInvalid') (is-in showErrorsFor 'middleName'))}} + {{v-get this 'middleName' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=lastName + update=(action (mut lastName)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'lastName') + }} + {{#if (and (v-get this 'lastName' 'isInvalid') (is-in showErrorsFor 'lastName'))}} + {{v-get this 'lastName' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=campusId + update=(action (mut campusId)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'campusId') + }} + {{#if (and (v-get this 'campusId' 'isInvalid') (is-in showErrorsFor 'campusId'))}} + {{v-get this 'campusId' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=otherId + update=(action (mut otherId)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'otherId') + }} + {{#if (and (v-get this 'otherId' 'isInvalid') (is-in showErrorsFor 'otherId'))}} + {{v-get this 'otherId' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=email + update=(action (mut email)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'email') + }} + {{#if (and (v-get this 'email' 'isInvalid') (is-in showErrorsFor 'email'))}} + {{v-get this 'email' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=phone + update=(action (mut phone)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'phone') + }} + {{#if (and (v-get this 'phone' 'isInvalid') (is-in showErrorsFor 'phone'))}} + {{v-get this 'phone' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=username + update=(action (mut username)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'username') + }} + {{#if (and (v-get this 'username' 'isInvalid') (is-in showErrorsFor 'username'))}} + {{v-get this 'username' 'message'}} + {{/if}} +
+
+ + {{one-way-input + value=password + update=(action (mut password)) + onenter=(action "save") + onescape=(action this.attrs.close) + focusOut=(action 'addErrorDisplayFor' 'password') + }} + {{#if (and (v-get this 'password' 'isInvalid') (is-in showErrorsFor 'password'))}} + {{v-get this 'password' 'message'}} + {{/if}} +
+
+ {{#if (and (is-fulfilled schools) (is-fulfilled bestSelectedSchool))}} -
- -
+ {{else}} {{fa-icon 'spinner' spin=true}} {{/if}} - {{#if (and (not nonStudentMode) (is-fulfilled bestSelectedSchool)) class='vertical'}} - +
+ {{#if (and (not nonStudentMode) (is-fulfilled bestSelectedSchool)) class='vertical'}} +
+ {{#if (and loadCohorts.isIdle (is-fulfilled bestSelectedCohort))}} -
- -
+ {{else}} {{fa-icon 'spinner' spin=true}} {{/if}} - {{/if}} -
+
+ {{/if}} -
+
diff --git a/tests/integration/components/new-directory-user-test.js b/tests/integration/components/new-directory-user-test.js index 5021a33157..2febfcb77f 100644 --- a/tests/integration/components/new-directory-user-test.js +++ b/tests/integration/components/new-directory-user-test.js @@ -33,60 +33,22 @@ moduleForComponent('new-directory-user', 'Integration | Component | new director }); test('it renders', function(assert) { - this.set('close', () => {}); - this.render(hbs`{{new-user close=(action close)}}`); - - return wait().then(() => { - let content = this.$().text().trim(); - assert.notEqual(content.search(/New User/), -1); - assert.notEqual(content.search(/First Name/), -1); - assert.notEqual(content.search(/Last Name/), -1); - assert.notEqual(content.search(/Middle Name/), -1); - assert.notEqual(content.search(/Campus ID/), -1); - assert.notEqual(content.search(/Other ID/), -1); - assert.notEqual(content.search(/Email/), -1); - assert.notEqual(content.search(/Phone/), -1); - assert.notEqual(content.search(/Username/), -1); - assert.notEqual(content.search(/Password/), -1); - assert.notEqual(content.search(/Primary School/), -1); - - let options = this.$('option'); - assert.equal(options.length, mockSchools.length); - assert.equal(options.eq(0).text().trim(), 'first'); - assert.equal(options.eq(1).text().trim(), 'second'); - assert.equal(options.eq(2).text().trim(), 'third'); - }); -}); - -test('errors do not show up initially', function(assert) { - this.set('close', () => { - assert.ok(false); //shouldn't be called - }); - this.render(hbs`{{new-user close=(action close)}}`); - - return wait().then(() => { - assert.equal(this.$('.validation-error-message').length, 0); + let storeMock = Service.extend({ + query(what, {filters}){ + assert.equal('cohort', what); + assert.equal(filters.schools[0], 2); + return resolve([]); + } }); -}); + this.register('service:store', storeMock); + this.set('nothing', () => {}); -test('errors show up', function(assert) { - this.set('close', () => { - assert.ok(false); //shouldn't be called - }); - this.render(hbs`{{new-user close=(action close)}}`); + this.render(hbs`{{new-directory-user close=(action nothing) setSearchTerms=(action nothing)}}`); return wait().then(() => { - this.$('.done').click(); - return wait().then(() => { - let boxes = this.$('.form-data'); - assert.ok(boxes.eq(1).text().search(/blank/) > -1); - assert.ok(boxes.eq(3).text().search(/blank/) > -1); - assert.ok(boxes.eq(6).text().search(/blank/) > -1); - assert.ok(boxes.eq(8).text().search(/blank/) > -1); - assert.ok(boxes.eq(9).text().search(/blank/) > -1); - }); - + let content = this.$().text().trim(); + assert.notEqual(content.search(/Search directory for new users/), -1); }); }); diff --git a/tests/integration/components/new-user-test.js b/tests/integration/components/new-user-test.js index 87901a3462..8b7ec68962 100644 --- a/tests/integration/components/new-user-test.js +++ b/tests/integration/components/new-user-test.js @@ -28,7 +28,6 @@ moduleForComponent('new-user', 'Integration | Component | new users', { }, beforeEach(){ this.register('service:current-user', currentUserMock); - this.inject.service('current-user', { as: 'current-user' }); } }); @@ -36,6 +35,16 @@ moduleForComponent('new-user', 'Integration | Component | new users', { test('it renders', function(assert) { this.set('close', () => {}); + let storeMock = Service.extend({ + query(what, {filters}){ + + assert.equal('cohort', what); + assert.equal(filters.schools[0], 2); + return resolve([]); + } + }); + this.register('service:store', storeMock); + this.render(hbs`{{new-user close=(action close)}}`); return wait().then(() => { @@ -52,7 +61,8 @@ test('it renders', function(assert) { assert.notEqual(content.search(/Password/), -1); assert.notEqual(content.search(/Primary School/), -1); - let options = this.$('option'); + const schools = 'select:eq(0) option'; + let options = this.$(schools); assert.equal(options.length, mockSchools.length); assert.equal(options.eq(0).text().trim(), 'first'); assert.equal(options.eq(1).text().trim(), 'second'); @@ -61,6 +71,16 @@ test('it renders', function(assert) { }); test('errors do not show up initially', function(assert) { + + let storeMock = Service.extend({ + query(what, {filters}){ + + assert.equal('cohort', what); + assert.equal(filters.schools[0], 2); + return resolve([]); + } + }); + this.register('service:store', storeMock); this.set('close', () => { assert.ok(false); //shouldn't be called }); @@ -73,6 +93,15 @@ test('errors do not show up initially', function(assert) { }); test('errors show up', function(assert) { + let storeMock = Service.extend({ + query(what, {filters}){ + + assert.equal('cohort', what); + assert.equal(filters.schools[0], 2); + return resolve([]); + } + }); + this.register('service:store', storeMock); this.set('close', () => { assert.ok(false); //shouldn't be called }); @@ -82,11 +111,11 @@ test('errors show up', function(assert) { this.$('.done').click(); return wait().then(() => { let boxes = this.$('.item'); - assert.ok(boxes.eq(1).text().search(/blank/) > -1); - assert.ok(boxes.eq(3).text().search(/blank/) > -1); - assert.ok(boxes.eq(6).text().search(/blank/) > -1); + assert.ok(boxes.eq(0).text().search(/blank/) > -1); + assert.ok(boxes.eq(2).text().search(/blank/) > -1); + assert.ok(boxes.eq(5).text().search(/blank/) > -1); + assert.ok(boxes.eq(7).text().search(/blank/) > -1); assert.ok(boxes.eq(8).text().search(/blank/) > -1); - assert.ok(boxes.eq(9).text().search(/blank/) > -1); }); });