diff --git a/client/main.styl b/client/main.styl index 836e2ee..001c556 100644 --- a/client/main.styl +++ b/client/main.styl @@ -153,6 +153,10 @@ body overflow: visible !important max-width: none !important +// Keep the custom scroll bars on top so they can be interacted with. They are placed outside the content div that they scroll. +.mCSB_1_scrollbar + z-index: 999 + @import "../imports/ui/styles/effects.import.styl" @import "../imports/ui/styles/buttons.import.styl" @import "../imports/ui/styles/maxHeightLayout.import.styl" diff --git a/imports/api/Sale.js b/imports/api/Sale.js index 4e6e5a1..d3319e5 100644 --- a/imports/api/Sale.js +++ b/imports/api/Sale.js @@ -296,7 +296,7 @@ if(Meteor.isServer) { comment: Match.Optional(String) }); - let dateString = date.toString(); + let dateString = sale.date.toString(); sale.createdAt = new Date(); sale.timestamp = new Date(dateString.substring(0, 4) + "-" + dateString.substring(4, 6) + "-" + dateString.substring(6, 8) + "T00:00:00Z"); diff --git a/imports/api/User.js b/imports/api/User.js index 24626e0..a405878 100644 --- a/imports/api/User.js +++ b/imports/api/User.js @@ -9,22 +9,22 @@ if(Meteor.isServer) { }); Meteor.methods({ - "insertUser": function(user, roles) { + "insertUser": function(user) { check(user, { username: String, - email: String + email: String, + roles: [String] }); - check(roles, [String]); //Verify the currently logged in user has authority to manage users. if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_MANAGE])) { //Verify the user name isn't already used. - if(Meteor.collections.Users.findOne({username: user.username}) == undefined) { + if(Meteor.collections.Users.findOne({username: user.username}) === undefined) { let pwd = Random.secret(20); let id = Accounts.createUser({password: pwd, username: user.username, email: user.email}); //Requires the alanning:roles package. - Roles.addUsersToRoles(id, roles); + Roles.addUsersToRoles(id, user.roles); } else { throw new Meteor.Error(400, "User already exists."); diff --git a/imports/ui/Measures.html b/imports/ui/Measures.html index 86beb8f..28d4ec1 100644 --- a/imports/ui/Measures.html +++ b/imports/ui/Measures.html @@ -2,32 +2,36 @@
| Name {{>MeasureSearch columnName='name'}} | +Postfix {{>MeasureSearch columnName='postfix'}} | +Actions | +
|---|
| Name {{>MeasureSearch columnName='name'}} | -Postfix {{>MeasureSearch columnName='postfix'}} | -Actions | -|||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{name}} | -{{postfix}} | +{{name}} | +{{postfix}} | {{#if hidden}} -/ | +/ | {{else}} {{#if deactivated}} -/ / | +/ / | {{else}} -/ | +/ | {{/if}} {{/if}} {{/if}} diff --git a/imports/ui/Measures.import.styl b/imports/ui/Measures.import.styl index a7d03a9..f868ff4 100644 --- a/imports/ui/Measures.import.styl +++ b/imports/ui/Measures.import.styl @@ -7,20 +7,73 @@ text-align: left .tableControls + display: table + width: 100% text-align: right margin-right: 20px - .controlLabel - font-size: 9px - font-weight: 700 - color: #5a5a5a - position: relative - top: -2px - .toggleShowHidden - margin: 0 40px 0 0 - position: relative - top: -4px - display: inline-block - + .showHidden + display: table-cell + width: 100% + .controlLabel + font-size: 9px + font-weight: 700 + color: #5a5a5a + position: relative + top: -2px + .toggleShowHidden + margin: 0 40px 0 0 + position: relative + top: -4px + display: inline-block + .contentControls + vertical-align: bottom + display: table-cell + text-align: right + min-width: 100px + a + font-size: 12px + font-family: "Arial", san-serif + font-weight: 800 + color: #2d1b8c + text-decoration: none + a:hover + text-decoration: underline + a.disabled + visibility: hidden + .table + table-layout: fixed + min-width: 100% + thead, tbody + > tr + > .name + width: 50% + min-width: 100px + > .postfix + width: 50% + min-width: 100px + > .actions + width: 90px + min-width: 90px + .separatedTableHeader + table + thead + > tr + .actions + text-align: center + .newMeasureButton + margin-top: 4px + padding: 0 12px + .fa-plus-circle + display: inline-block + .fa-times-circle + display: none + .newMeasureButton.active + background-color: #fb557b + color: black + .fa-times-circle + display: inline-block + .fa-plus-circle + display: none .listRow display: table-row .listCell @@ -57,28 +110,8 @@ select2 font-size: .4em > thead - > tr - > th.name - width: auto - > th.postfix - width: auto - > th.actions - width: 90px - text-align: center - .newMeasureButton - margin-top: 4px - padding: 0px 12px - .fa-plus-circle - display: inline-block - .fa-times-circle - display: none - .newMeasureButton.active - background-color: #fb557b - color: black - .fa-times-circle - display: inline-block - .fa-plus-circle - display: none + display: none + visibility: hidden > tbody > tr .actionRemove diff --git a/imports/ui/Measures.js b/imports/ui/Measures.js index 4b67eae..4c9dc96 100644 --- a/imports/ui/Measures.js +++ b/imports/ui/Measures.js @@ -1,7 +1,8 @@ import './Measures.html'; -let QUERY_LIMIT = 20; +let QUERY_LIMIT = 100; +let QUERY_LIMIT_INCREMENT = 100; let PREFIX = "Measures."; Tracker.autorun(function() { @@ -11,6 +12,15 @@ Tracker.autorun(function() { Template.Measures.onCreated(function() { Session.set(PREFIX + "displayNewMeasure", false); Session.set(PREFIX + "showHidden", false); + Session.set(PREFIX + "queryLimit", QUERY_LIMIT); +}); +Template.Measures.onRendered(function() { + $(".tableContainer").mCustomScrollbar({ + scrollButtons: {enable:true}, + theme: "light-thick", + scrollbarPosition: "outside", + scrollEasing: "linear" + }); }); Template.Measures.helpers({ displayNewMeasure: function() { @@ -45,23 +55,16 @@ Template.Measures.helpers({ dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {}; Session.set(PREFIX + 'measureCount', Meteor.collections.Measures.find(dbQuery).count()); //Always get a full count. - return Meteor.collections.Measures.find(dbQuery, {limit: QUERY_LIMIT, skip: skipCount, sort: {order: 1}}); + return Meteor.collections.Measures.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {order: 1}}); }, - disablePrev: function() { - return (Session.get(PREFIX + 'skipCount') || 0) == 0; - }, - disableNext: function() { - return Session.get(PREFIX + 'measureCount') - (Session.get(PREFIX + 'skipCount') || 0) - QUERY_LIMIT <= 0; + disableLoadMore: function() { + return Session.get(PREFIX + 'measureCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0; } }); Template.Measures.events({ - 'click .prevMeasures': function(event, template) { - if(!$(event.target).hasClass('disabled')) - Session.set(PREFIX + 'skipCount', Math.max(0, (Session.get(PREFIX + 'skipCount') || 0) - QUERY_LIMIT)); - }, - 'click .nextMeasures': function(event, template) { - if(!$(event.target).hasClass('disabled')) - Session.set(PREFIX + 'skipCount', (Session.get(PREFIX + 'skipCount') || 0) + QUERY_LIMIT); + 'click .loadMoreLink': function(event, template) { + event.preventDefault(); + Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT); }, 'click .newMeasureButton': function(event, template) { if(template.$('.newMeasureButton').hasClass('active')) { @@ -150,7 +153,7 @@ Template.Measure.events({ "click .actionEdit": function(event, template) { Session.set(PREFIX + "editedMeasure", this._id); Session.set(PREFIX + 'displayNewMeasure', false); //Ensure the new measure editor is closed. - template.$('.newMeasureButton').removeClass('active'); + template.parentTemplate().$('.newMeasureButton').removeClass('active'); }, "click .actionRemove": function(event, template) { Meteor.call('deactivateMeasure', this._id, function(error, result) { diff --git a/imports/ui/Pricing.html b/imports/ui/Pricing.html index f71822a..1aaf878 100644 --- a/imports/ui/Pricing.html +++ b/imports/ui/Pricing.html @@ -6,7 +6,7 @@ @@ -28,23 +28,26 @@ - - Prev - Next - +||||||
| Name | +Current | +Change Date | +Previous | +
|---|
| Name | -Current | -Change Date | -Previous | -||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{name}} | -{{currentPrice}} | -{{priceChangeDate}} | -{{previousPrice}} | +{{name}} | +{{currentPrice}} | +{{priceChangeDate}} | +{{previousPrice}} | ||||||||
| Name {{>ProductTag_ProductSearch columnName='name'}} | +Tags {{>ProductTag_ProductSearch columnName='tags' collectionQueryColumnName='name' collection='ProductTags' collectionResultColumnName='_id'}} | +
|---|
| Name {{>ProductTag_ProductSearch columnName='name'}} | -Tags {{>ProductTag_ProductSearch columnName='tags' collectionQueryColumnName='name' collection='ProductTags' collectionResultColumnName='_id'}} | -||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{name}} | -{{tags}} | +{{name}} | +{{tags}} | ||||||||||||
| Name {{>ProductSearch columnName='name'}} | +Tags {{>ProductSearch columnName='tags' collectionQueryColumnName='name' collection='ProductTags' collectionResultColumnName='_id'}} | +Aliases {{>ProductSearch columnName='aliases'}} | +Measures {{>ProductSearch columnName='measures' collectionQueryColumnName='name' collection='Measures' collectionResultColumnName='_id'}} | +Actions | +
|---|
| Name {{>ProductSearch columnName='name'}} | -Tags {{>ProductSearch columnName='tags' collectionQueryColumnName='name' collection='ProductTags' collectionResultColumnName='_id'}} | -Aliases {{>ProductSearch columnName='aliases'}} | -Measures {{>ProductSearch columnName='measures' collectionQueryColumnName='name' collection='Measures' collectionResultColumnName='_id'}} | -Actions | -{{name}} | -{{tags}} | -{{aliases}} | -{{measures}} | +{{name}} | +{{tags}} | +{{aliases}} | +{{measures}} | {{#if hidden}} -/ / | +/ / | {{else}} {{#if deactivated}} -/ / | +/ / | {{else}} -/ | +/ | {{/if}} {{/if}} {{/if}} diff --git a/imports/ui/Products.import.styl b/imports/ui/Products.import.styl index b070679..2673ba2 100644 --- a/imports/ui/Products.import.styl +++ b/imports/ui/Products.import.styl @@ -9,18 +9,80 @@ .tableControls text-align: right margin-right: 20px - .controlLabel - font-size: 9px - font-weight: 700 - color: #5a5a5a - position: relative - top: -2px - .toggleShowHidden - margin: 0 40px 0 0 - position: relative - top: -4px - display: inline-block + margin-bottom: 4px + display: table + width: 100% + .showHidden + display: table-cell + text-align: right + width: 100% + .controlLabel + font-size: 9px + font-weight: 700 + color: #5a5a5a + position: relative + top: -2px + .toggleShowHidden + margin: 0 40px 0 0 + position: relative + top: -4px + display: inline-block + .contentControls + vertical-align: bottom + display: table-cell + text-align: right + min-width: 100px + a + font-size: 12px + font-family: "Arial", san-serif + font-weight: 800 + color: #2d1b8c + text-decoration: none + a:hover + text-decoration: underline + a.disabled + visibility: hidden + .table + table-layout: fixed + min-width: 100% + thead, tbody + > tr + > .name + //width: auto + width: 100% + > .tags + width: 220px + min-width: 220px + > .aliases + width: 220px + min-width: 220px + > .measures + width: 220px + min-width: 220px + > .actions + width: 90px + min-width: 90px + .separatedTableHeader + table + thead + > tr + > th.actions + text-align: center + .newProductButton + margin-top: 4px + padding: 0 12px + .fa-plus-circle + display: inline-block + .fa-times-circle + display: none + .newProductButton:active + background-color: #fb557b + color: black + .fa-times-circle + display: inline-block + .fa-plus-circle + display: none .listRow display: table-row .listCell @@ -40,8 +102,9 @@ font-size: 12.5px overflow-y: auto table - table-layout: fixed - width: 100% + thead + visibility: hidden + display: none .productSearch margin: 3px 0 2px 1px .productEditorTd @@ -56,33 +119,6 @@ padding-bottom: 4px select2 font-size: .4em - > thead - > tr - > th.name - width: auto - > th.tags - width: 220px - > th.aliases - width: 220px - > th.measures - width: 220px - > th.actions - width: 90px - text-align: center - .newProductButton - margin-top: 4px - padding: 0px 12px - .fa-plus-circle - display: inline-block - .fa-times-circle - display: none - .newProductButton:active - background-color: #fb557b - color: black - .fa-times-circle - display: inline-block - .fa-plus-circle - display: none > tbody > tr .actionRemove diff --git a/imports/ui/Products.js b/imports/ui/Products.js index ff37f54..9894dcc 100644 --- a/imports/ui/Products.js +++ b/imports/ui/Products.js @@ -1,7 +1,8 @@ import './Products.html'; -let QUERY_LIMIT = 20; +let QUERY_LIMIT = 100; +let QUERY_LIMIT_INCREMENT = 100; let PREFIX = "Products."; Tracker.autorun(function() { @@ -13,6 +14,15 @@ Tracker.autorun(function() { Template.Products.onCreated(function() { Session.set(PREFIX + "displayNewProduct", false); Session.set(PREFIX + "showHidden", false); + Session.set(PREFIX + "queryLimit", QUERY_LIMIT); +}); +Template.Products.onRendered(function() { + $(".tableContainer").mCustomScrollbar({ + scrollButtons: {enable:true}, + theme: "light-thick", + scrollbarPosition: "outside", + scrollEasing: "linear" + }); }); Template.Products.helpers({ displayNewProduct: function() { @@ -47,23 +57,16 @@ Template.Products.helpers({ dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {}; Session.set(PREFIX + 'productCount', Meteor.collections.Products.find(dbQuery).count()); //Always get a full count. - return Meteor.collections.Products.find(dbQuery, {limit: QUERY_LIMIT, skip: skipCount, sort: {name: 1}}); + return Meteor.collections.Products.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {name: 1}}); }, - disablePrev: function() { - return (Session.get(PREFIX + 'skipCount') || 0) == 0; - }, - disableNext: function() { - return Session.get(PREFIX + 'productCount') - (Session.get(PREFIX + 'skipCount') || 0) - QUERY_LIMIT <= 0; + disableLoadMore: function() { + return Session.get(PREFIX + 'productCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0; } }); Template.Products.events({ - 'click .prevProducts': function(event, template) { - if(!$(event.target).hasClass('disabled')) - Session.set(PREFIX + 'skipCount', Math.max(0, (Session.get(PREFIX + 'skipCount') || 0) - QUERY_LIMIT)); - }, - 'click .nextProducts': function(event, template) { - if(!$(event.target).hasClass('disabled')) - Session.set(PREFIX + 'skipCount', (Session.get(PREFIX + 'skipCount') || 0) + QUERY_LIMIT); + 'click .loadMoreLink': function(event, template) { + event.preventDefault(); + Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT); }, 'click .newProductButton': function(event, template) { if(template.$('.newProductButton').hasClass('active')) { @@ -181,7 +184,7 @@ Template.Product.events({ Session.set(PREFIX + "editedProduct", this._id); Session.set(PREFIX + 'displayNewProduct', false); //Ensure the new product editor is closed. Session.set(PREFIX + "convertedProduct", undefined); //Clear the converted product so that only one editor is open at a time. - template.$('.newProductButton').removeClass('active'); + template.parentTemplate().$('.newProductButton').removeClass('active'); }, "click .actionDeactivate": function(event, template) { Meteor.call('deactivateProduct', this._id, function(error, result) { diff --git a/imports/ui/Sales.html b/imports/ui/Sales.html index df60d11..742e0dd 100644 --- a/imports/ui/Sales.html +++ b/imports/ui/Sales.html @@ -36,18 +36,6 @@
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{amount}} | -{{productName productId}} | -{{formatPrice price}}{{#if showTotalPrice amount}} ({{formatTotalPrice price amount}}){{/if}} | -{{measureName measureId}} | -{{formatDateAndWeek date}} | -{{formatDateTime createdAt}} | -{{venueName venueId}} | -+ | {{amount}} | +{{productName productId}} | +{{formatPrice price}}{{#if showTotalPrice amount}} ({{formatTotalPrice price amount}}){{/if}} | +{{measureName measureId}} | +{{formatDateAndWeek date weekOfYear}} | +{{formatDateTime createdAt}} | +{{venueName venueId}} | +|
| - | |||||||||||||||