Fixed all known bugs; Modified the menu to hide; Fixed the tables to scroll with a fixed header.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
<div id="measures">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
<div class="tableControls">
|
||||
<div class="showHidden">
|
||||
<span class="controlLabel">Show Hidden</span>
|
||||
<div class="toggleShowHidden checkbox checkbox-slider--b-flat">
|
||||
<label>
|
||||
<input type="checkbox" name="showHidden"><span></span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="pagination">
|
||||
<span class="prevMeasures noselect {{#if disablePrev}}disabled{{/if}}"><i class="fa fa-long-arrow-left" aria-hidden="true"></i> Prev</span>
|
||||
<span class="nextMeasures noselect {{#if disableNext}}disabled{{/if}}">Next <i class="fa fa-long-arrow-right" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer">
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -23,11 +22,16 @@
|
||||
<th class="postfix">Postfix {{>MeasureSearch columnName='postfix'}}</th>
|
||||
<th class="actions">Actions <span class="newMeasureButton btn btn-success"><i class="fa fa-plus-circle" aria-hidden="true"></i><i class="fa fa-times-circle" aria-hidden="true"></i></span></th>
|
||||
</tr>
|
||||
<!--<button type="button" name="newMeasureButton"><i class="fa fa-plus-circle" aria-hidden="true"></i></button>-->
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#if displayNewMeasure}}
|
||||
{{> MeasureEditor isNew=true}}
|
||||
<tr>{{> MeasureEditor isNew=true}}</tr>
|
||||
{{/if}}
|
||||
{{#each measures}}
|
||||
{{> Measure}}
|
||||
@@ -47,15 +51,15 @@
|
||||
{{#if editing}}
|
||||
{{> MeasureEditor}}
|
||||
{{else}}
|
||||
<td class="noselect nonclickable left">{{name}}</td>
|
||||
<td class="noselect nonclickable left">{{postfix}}</td>
|
||||
<td class="name noselect nonclickable left">{{name}}</td>
|
||||
<td class="postfix noselect nonclickable left">{{postfix}}</td>
|
||||
{{#if hidden}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
{{#if deactivated}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionRemove fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionRemove fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
77
imports/ui/Measures.import.styl
vendored
77
imports/ui/Measures.import.styl
vendored
@@ -7,8 +7,13 @@
|
||||
text-align: left
|
||||
|
||||
.tableControls
|
||||
display: table
|
||||
width: 100%
|
||||
text-align: right
|
||||
margin-right: 20px
|
||||
.showHidden
|
||||
display: table-cell
|
||||
width: 100%
|
||||
.controlLabel
|
||||
font-size: 9px
|
||||
font-weight: 700
|
||||
@@ -20,7 +25,55 @@
|
||||
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
|
||||
visibility: hidden
|
||||
> tbody
|
||||
> tr
|
||||
.actionRemove
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<label class='controlLabel'>Selected Measure: </label>
|
||||
<select name="measures">
|
||||
{{#each measures}}
|
||||
<option value="{{_id}}">{{name}}</option>
|
||||
<option class="{{#if deactivated}}deactivated{{/if}}" value="{{_id}}">{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
@@ -28,14 +28,11 @@
|
||||
<input type="date" class="form-control" name="date" data-schema-key='date' required>
|
||||
</div>
|
||||
</div>
|
||||
<span class="pagination">
|
||||
<span class="prevProducts noselect {{#if disablePrev}}disabled{{/if}}"><i class="fa fa-long-arrow-left" aria-hidden="true"></i> Prev</span>
|
||||
<span class="nextProducts noselect {{#if disableNext}}disabled{{/if}}">Next <i class="fa fa-long-arrow-right" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer">
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -45,6 +42,12 @@
|
||||
<th class="previous">Previous</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#each product}}
|
||||
{{> PricingForProduct}}
|
||||
@@ -61,9 +64,9 @@
|
||||
|
||||
<template name="PricingForProduct">
|
||||
<tr class="clickable noselect {{rowClass}}">
|
||||
<td class="tdLarge noselect nonclickable left">{{name}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{currentPrice}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{priceChangeDate}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{previousPrice}}</td>
|
||||
<td class="name tdLarge noselect nonclickable left">{{name}}</td>
|
||||
<td class="current tdLarge noselect nonclickable left">{{currentPrice}}</td>
|
||||
<td class="changeDate tdLarge noselect nonclickable left">{{priceChangeDate}}</td>
|
||||
<td class="previous tdLarge noselect nonclickable left">{{previousPrice}}</td>
|
||||
</tr>
|
||||
</template>
|
||||
44
imports/ui/Pricing.import.styl
vendored
44
imports/ui/Pricing.import.styl
vendored
@@ -18,6 +18,8 @@
|
||||
width: 240px
|
||||
select
|
||||
width: 100%
|
||||
option.deactivated
|
||||
color: #a6a6a6
|
||||
.controlGroup
|
||||
padding: 4px 8px
|
||||
margin: 4px 8px
|
||||
@@ -62,7 +64,38 @@
|
||||
display: inline-block
|
||||
.resetButton
|
||||
margin-left: 20px
|
||||
.contentControls
|
||||
vertical-align: bottom
|
||||
display: table-cell
|
||||
text-align: right
|
||||
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: 100%
|
||||
min-width: 100px
|
||||
> .current
|
||||
width: 200px
|
||||
min-width: 200px
|
||||
> .previous
|
||||
width: 200px
|
||||
min-width: 200px
|
||||
> .changeDate
|
||||
width: 200px
|
||||
min-width: 200px
|
||||
.listRow
|
||||
display: table-row
|
||||
.listCell
|
||||
@@ -85,15 +118,8 @@
|
||||
table-layout: fixed
|
||||
width: 100%
|
||||
> thead
|
||||
> tr
|
||||
> th.name
|
||||
width: auto
|
||||
> th.current
|
||||
width: 200px
|
||||
> th.previous
|
||||
width: 200px
|
||||
> th.changeDate
|
||||
width: 200px
|
||||
visibility: hidden
|
||||
display: none
|
||||
> tbody
|
||||
> tr.deactivated
|
||||
background-color: #fac0d1
|
||||
|
||||
@@ -8,7 +8,8 @@ import './Pricing.html';
|
||||
* Because the structure of the Product object is so complicated, the normal checking that is done by the framework cannot be used.
|
||||
*/
|
||||
|
||||
let QUERY_LIMIT = 20;
|
||||
let QUERY_LIMIT = 100;
|
||||
let QUERY_LIMIT_INCREMENT = 100;
|
||||
let PREFIX = "Pricing.";
|
||||
|
||||
Meteor.subscribe("products");
|
||||
@@ -24,14 +25,22 @@ Tracker.autorun(function() {
|
||||
});
|
||||
|
||||
Template.Pricing.onCreated(function() {
|
||||
Session.set(PREFIX + "queryLimit", QUERY_LIMIT);
|
||||
});
|
||||
Template.Pricing.onRendered(function() {
|
||||
this.$('input[name="date"]').val(new Date().toDateInputValue());
|
||||
// this>$('select[name="measures"]').val()
|
||||
|
||||
$(".tableContainer").mCustomScrollbar({
|
||||
scrollButtons: {enable:true},
|
||||
theme: "light-thick",
|
||||
scrollbarPosition: "outside",
|
||||
scrollEasing: "linear"
|
||||
});
|
||||
});
|
||||
Template.Pricing.helpers({
|
||||
measures: function() {
|
||||
let measures = Meteor.collections.Measures.find({}, {sort: {order: 1}}).fetch();
|
||||
let measures = Meteor.collections.Measures.find({$or: [{hidden: false}, {hidden: {$exists: false}}]}, {sort: {order: 1}}).fetch();
|
||||
|
||||
for(let i = 0; i < measures; i++) {
|
||||
if(Meteor.collections.Products.find({measures: {$all: [measures[i]._id]}}, {sort: {name: 1}}).count() == 0)
|
||||
@@ -46,18 +55,20 @@ Template.Pricing.helpers({
|
||||
let dbQuery = {measures: {$all: [measureId]}, $or: [{hidden: false}, {hidden: {$exists:false}}]};
|
||||
|
||||
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.Pricing.events({
|
||||
'click .loadMoreLink': function(event, template) {
|
||||
event.preventDefault();
|
||||
Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT);
|
||||
},
|
||||
'change select[name="measures"]': function(event, template) {
|
||||
Session.get(PREFIX + 'skipCount', 0);
|
||||
Session.set(PREFIX + 'skipCount', 0);
|
||||
Session.set(PREFIX + 'queryLimit', QUERY_LIMIT);
|
||||
Session.set(PREFIX + "selectedMeasure", $(event.target).val());
|
||||
},
|
||||
'click .applyButton': function(event, template) {
|
||||
@@ -95,14 +106,6 @@ Template.Pricing.events({
|
||||
template.$('input.price').val(0);
|
||||
template.$('input.date').val(new Date().toDateInputValue());
|
||||
template.$('input[name="setPrevious"]').removeProp('checked');
|
||||
},
|
||||
'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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -20,15 +20,12 @@
|
||||
{{> ProductTag}}
|
||||
{{/each}}
|
||||
</span>
|
||||
<span class="pagination">
|
||||
<span class="prevProducts noselect {{#if disablePrev}}disabled{{/if}}"><i class="fa fa-long-arrow-left" aria-hidden="true"></i> Prev</span>
|
||||
<span class="nextProducts noselect {{#if disableNext}}disabled{{/if}}">Next <i class="fa fa-long-arrow-right" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer">
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -36,6 +33,12 @@
|
||||
<th class="tags">Tags {{>ProductTag_ProductSearch columnName='tags' collectionQueryColumnName='name' collection='ProductTags' collectionResultColumnName='_id'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#each products}}
|
||||
{{> ProductTag_Product}}
|
||||
@@ -56,8 +59,8 @@
|
||||
|
||||
<template name="ProductTag_Product">
|
||||
<tr class="{{rowClass}}">
|
||||
<td class="tdLarge noselect nonclickable left">{{name}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{tags}}</td>
|
||||
<td class="name tdLarge noselect nonclickable left">{{name}}</td>
|
||||
<td class="tags tdLarge noselect nonclickable left">{{tags}}</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
|
||||
33
imports/ui/ProductTags.import.styl
vendored
33
imports/ui/ProductTags.import.styl
vendored
@@ -106,10 +106,32 @@
|
||||
border: 0
|
||||
padding: 0
|
||||
margin: 0
|
||||
.pagination
|
||||
.contentControls
|
||||
vertical-align: bottom
|
||||
display: table-cell
|
||||
width: 240px
|
||||
vertical-align: bottom;
|
||||
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: 100%
|
||||
min-width: 100px
|
||||
> .tags
|
||||
width: 100%
|
||||
min-width: 100px
|
||||
.listRow
|
||||
display: table-row
|
||||
.listCell
|
||||
@@ -132,11 +154,6 @@
|
||||
table-layout: fixed
|
||||
width: 100%
|
||||
> thead
|
||||
> tr
|
||||
> th.name
|
||||
width: auto
|
||||
> th.tags
|
||||
width: auto
|
||||
> tbody
|
||||
> tr.deactivated
|
||||
background-color: #fac0d1
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
import './ProductTags.html';
|
||||
|
||||
let QUERY_LIMIT = 20;
|
||||
let QUERY_LIMIT = 100;
|
||||
let QUERY_LIMIT_INCREMENT = 100;
|
||||
let PREFIX = "ProductTags.";
|
||||
|
||||
Tracker.autorun(function() {
|
||||
@@ -11,6 +12,15 @@ Tracker.autorun(function() {
|
||||
|
||||
Template.ProductTags.onCreated(function() {
|
||||
Session.set(PREFIX + "editTags", false);
|
||||
Session.set(PREFIX + "queryLimit", QUERY_LIMIT);
|
||||
});
|
||||
Template.ProductTags.onRendered(function() {
|
||||
$(".tableContainer").mCustomScrollbar({
|
||||
scrollButtons: {enable:true},
|
||||
theme: "light-thick",
|
||||
scrollbarPosition: "outside",
|
||||
scrollEasing: "linear"
|
||||
});
|
||||
});
|
||||
Template.ProductTags.helpers({
|
||||
productTags: function() {
|
||||
@@ -60,13 +70,10 @@ Template.ProductTags.helpers({
|
||||
//Collect a count of the products first, and store it in the session.
|
||||
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.ProductTags.events({
|
||||
@@ -86,14 +93,10 @@ Template.ProductTags.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 .loadMoreLink': function(event, template) {
|
||||
event.preventDefault();
|
||||
Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT);
|
||||
},
|
||||
'click .nextProducts': function(event, template) {
|
||||
if(!$(event.target).hasClass('disabled'))
|
||||
Session.set(PREFIX + 'skipCount', (Session.get(PREFIX + 'skipCount') || 0) + QUERY_LIMIT);
|
||||
}
|
||||
});
|
||||
|
||||
Template.ProductTag.onCreated(function() {
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
<div id="products">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
<div class="tableControls">
|
||||
<div class="showHidden">
|
||||
<span class="controlLabel">Show Hidden</span>
|
||||
<div class="toggleShowHidden checkbox checkbox-slider--b-flat">
|
||||
<label>
|
||||
<input type="checkbox" name="showHidden"><span></span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="pagination">
|
||||
<span class="prevProducts noselect {{#if disablePrev}}disabled{{/if}}"><i class="fa fa-long-arrow-left" aria-hidden="true"></i> Prev</span>
|
||||
<span class="nextProducts noselect {{#if disableNext}}disabled{{/if}}">Next <i class="fa fa-long-arrow-right" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer">
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -25,8 +24,13 @@
|
||||
<th class="measures">Measures {{>ProductSearch columnName='measures' collectionQueryColumnName='name' collection='Measures' collectionResultColumnName='_id'}}</th>
|
||||
<th class="actions">Actions <span class="newProductButton btn btn-success"><i class="fa fa-plus-circle" aria-hidden="true"></i><i class="fa fa-times-circle" aria-hidden="true"></i></span></th>
|
||||
</tr>
|
||||
<!--<button type="button" name="newProductButton"><i class="fa fa-plus-circle" aria-hidden="true"></i></button>-->
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#if displayNewProduct}}
|
||||
{{> ProductEditor isNew=true}}
|
||||
@@ -52,17 +56,17 @@
|
||||
{{#if converting}}
|
||||
{{> ConvertProduct}}
|
||||
{{else}}
|
||||
<td class="noselect nonclickable left">{{name}}</td>
|
||||
<td class="noselect nonclickable left">{{tags}}</td>
|
||||
<td class="noselect nonclickable left">{{aliases}}</td>
|
||||
<td class="noselect nonclickable left">{{measures}}</td>
|
||||
<td class="name noselect nonclickable left">{{name}}</td>
|
||||
<td class="tags noselect nonclickable left">{{tags}}</td>
|
||||
<td class="aliases noselect nonclickable left">{{aliases}}</td>
|
||||
<td class="measures noselect nonclickable left">{{measures}}</td>
|
||||
{{#if hidden}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i> / <i class="actionConvert fa fa-exclamation-triangle fa-lg noselect clickable" title="Convert" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i> / <i class="actionConvert fa fa-exclamation-triangle fa-lg noselect clickable" title="Convert" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
{{#if deactivated}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionDeactivate fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionDeactivate fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
94
imports/ui/Products.import.styl
vendored
94
imports/ui/Products.import.styl
vendored
@@ -9,6 +9,13 @@
|
||||
.tableControls
|
||||
text-align: right
|
||||
margin-right: 20px
|
||||
margin-bottom: 4px
|
||||
display: table
|
||||
width: 100%
|
||||
.showHidden
|
||||
display: table-cell
|
||||
text-align: right
|
||||
width: 100%
|
||||
.controlLabel
|
||||
font-size: 9px
|
||||
font-weight: 700
|
||||
@@ -20,7 +27,62 @@
|
||||
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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -36,18 +36,6 @@
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="amount"></th>
|
||||
<th class="product"></th>
|
||||
<th class="price"></th>
|
||||
<th class="measure"></th>
|
||||
<th class="saleDate"></th>
|
||||
<th class="createdDate"></th>
|
||||
<th class="venue"></th>
|
||||
<th class="actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#if displayNewSale}}
|
||||
{{> InsertSale}}
|
||||
@@ -71,14 +59,14 @@
|
||||
|
||||
<template name="Sale">
|
||||
<tr>
|
||||
<td class="tdLarge noselect nonclickable center">{{amount}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{productName productId}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{formatPrice price}}{{#if showTotalPrice amount}} ({{formatTotalPrice price amount}}){{/if}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{measureName measureId}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{formatDateAndWeek date}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{formatDateTime createdAt}}</td>
|
||||
<td class="tdLarge noselect nonclickable left">{{venueName venueId}}</td>
|
||||
<td class="tdLarge noselect left"><i class="fa fa-pencil-square-o fa-lg actionEdit noselect clickable" title="Edit" aria-hidden="true"></i> <i class="fa fa-commenting fa-lg editComment noselect clickable {{commentClass}}" aria-hidden="true"></i> <i class="fa fa-times-circle fa-lg saleRemove noselect clickable" aria-hidden="true"></i></td>
|
||||
<td class="amount tdLarge noselect nonclickable center">{{amount}}</td>
|
||||
<td class="product tdLarge noselect nonclickable left">{{productName productId}}</td>
|
||||
<td class="price tdLarge noselect nonclickable left">{{formatPrice price}}{{#if showTotalPrice amount}} ({{formatTotalPrice price amount}}){{/if}}</td>
|
||||
<td class="measure tdLarge noselect nonclickable left">{{measureName measureId}}</td>
|
||||
<td class="saleDate tdLarge noselect nonclickable left">{{formatDateAndWeek date weekOfYear}}</td>
|
||||
<td class="createdDate tdLarge noselect nonclickable left">{{formatDateTime createdAt}}</td>
|
||||
<td class="venue tdLarge noselect nonclickable left">{{venueName venueId}}</td>
|
||||
<td class="actions tdLarge noselect left"><i class="fa fa-pencil-square-o fa-lg actionEdit noselect clickable" title="Edit" aria-hidden="true"></i> <i class="fa fa-commenting fa-lg editComment noselect clickable {{commentClass}}" aria-hidden="true"></i> <i class="fa fa-times-circle fa-lg saleRemove noselect clickable" aria-hidden="true"></i></td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
@@ -115,7 +103,7 @@
|
||||
<template name="InsertSale">
|
||||
<tr>
|
||||
<td colspan="8">
|
||||
<form class="insertSaleForm" autocomplete="off">
|
||||
<form name="insertSaleForm" class="insertSaleForm" autocomplete="off">
|
||||
<div class="grid">
|
||||
<div class="col-4-12">
|
||||
<div class="formGroupHeading">New Sale</div>
|
||||
|
||||
49
imports/ui/Sales.import.styl
vendored
49
imports/ui/Sales.import.styl
vendored
@@ -22,37 +22,44 @@
|
||||
.table
|
||||
table-layout: fixed
|
||||
min-width: 100%
|
||||
thead
|
||||
thead, tbody
|
||||
> tr
|
||||
> th.amount
|
||||
> .amount
|
||||
width: 90px
|
||||
> th.product
|
||||
width: auto
|
||||
min-width: 90px
|
||||
> .product
|
||||
width: 100%
|
||||
min-width: 140px
|
||||
> th.price
|
||||
> .price
|
||||
width: 140px
|
||||
> th.measure
|
||||
min-width: 140px
|
||||
> .measure
|
||||
width: 100px
|
||||
> th.saleDate
|
||||
width: 140px
|
||||
> th.createdDate
|
||||
min-width: 100px
|
||||
> .saleDate
|
||||
width: 150px
|
||||
min-width: 150px
|
||||
> .createdDate
|
||||
width: 100px
|
||||
> th.venue
|
||||
min-width: 100px
|
||||
> .venue
|
||||
width: 160px
|
||||
> th.actions
|
||||
min-width: 160px
|
||||
> .actions
|
||||
width: 90px
|
||||
min-width: 90px
|
||||
.separatedTableHeader
|
||||
table
|
||||
thead
|
||||
> tr
|
||||
> th.actions
|
||||
.newSaleButton
|
||||
padding: 0px 12px
|
||||
padding: 0 12px
|
||||
.fa-plus-circle
|
||||
display: inline-block
|
||||
.fa-times-circle
|
||||
display: none
|
||||
.newSaleButton:active
|
||||
.newSaleButton.active
|
||||
background-color: #fb557b
|
||||
color: black
|
||||
.fa-times-circle
|
||||
@@ -67,6 +74,9 @@
|
||||
text-shadow: 0px 0px 10px #ff6d1f
|
||||
.showOnlyComments.on
|
||||
color: white
|
||||
> th.saleDate
|
||||
input
|
||||
width: 130px
|
||||
.listRow
|
||||
display: table-row
|
||||
.listCell
|
||||
@@ -82,16 +92,16 @@
|
||||
right: 0
|
||||
width: auto
|
||||
height: auto
|
||||
//width: 100%
|
||||
//margin-bottom: 20px
|
||||
border: 0
|
||||
font-size: 12.5px
|
||||
overflow-y: scroll
|
||||
//height: 100%
|
||||
label
|
||||
font-size: 10px
|
||||
font-weight: 800
|
||||
table
|
||||
thead
|
||||
visibility: hidden
|
||||
display: none
|
||||
.saleRemove
|
||||
color: red
|
||||
margin-left: 8px
|
||||
@@ -102,9 +112,10 @@
|
||||
color: green
|
||||
.editorCancel
|
||||
color: red
|
||||
thead
|
||||
visibility: hidden
|
||||
display: none
|
||||
.saleDate
|
||||
text-align: left
|
||||
.createdDate
|
||||
text-align: left
|
||||
.editComment
|
||||
color: grey
|
||||
.hasComment
|
||||
|
||||
@@ -38,18 +38,12 @@ Template.Sales.onCreated(function() {
|
||||
});
|
||||
});
|
||||
Template.Sales.onRendered(function() {
|
||||
//$('.tableContainer').mCustomScrollbar();
|
||||
$(".tableContainer").mCustomScrollbar({
|
||||
scrollButtons: {enable:true},
|
||||
theme: "light-thick",
|
||||
scrollbarPosition:"outside"
|
||||
scrollbarPosition: "outside",
|
||||
scrollEasing: "linear"
|
||||
});
|
||||
//(function($){
|
||||
// $(window).on("load",function(){
|
||||
// $(".tableContainer").mCustomScrollbar();
|
||||
// });
|
||||
//})(jQuery);
|
||||
//$('#test').mCustomScrollbar();
|
||||
});
|
||||
Template.Sales.onDestroyed(function() {
|
||||
if(Template.Sales.salesSubscription) {
|
||||
@@ -85,6 +79,11 @@ Template.Sales.events({
|
||||
else {
|
||||
Session.set(PREFIX + 'displayNewSale', true);
|
||||
Session.set(PREFIX + "editedSale", undefined); //Clear the edited sale so that only one editor is open at a time.
|
||||
|
||||
//Set the focus to the date field of the form. Put this in a timeout so that it is queued for processing after the form is added to the DOM.
|
||||
setTimeout(function() {
|
||||
$("form[name='insertSaleForm'] input[name='date']").focus();
|
||||
}, 10);
|
||||
}
|
||||
template.$('.newSaleButton').toggleClass('active');
|
||||
},
|
||||
@@ -123,8 +122,8 @@ Template.Sale.helpers({
|
||||
productName: function(id) {
|
||||
return Meteor.collections.Products.findOne({_id: id}, {fields: {name: 1}}).name;
|
||||
},
|
||||
formatDateAndWeek: function(date) {
|
||||
return moment.utc(date.toString(), "YYYYMMDD").utc().format("MM/DD/YYYY (w)");
|
||||
formatDateAndWeek: function(date, weekOfYear) {
|
||||
return moment.utc(date.toString(), "YYYYMMDD").utc().format("MM/DD/YYYY") + "(" + weekOfYear + ")";
|
||||
},
|
||||
formatDateTime: function(date) {
|
||||
return moment.utc(date).format("MM/DD/YYYY");
|
||||
@@ -146,7 +145,7 @@ Template.Sale.events({
|
||||
"click .actionEdit": function(event, template) {
|
||||
Session.set(PREFIX + "editedSale", this._id);
|
||||
Session.set(PREFIX + 'displayNewSale', false); //Ensure the new sale editor is closed.
|
||||
template.$('.newSaleButton').removeClass('active');
|
||||
template.parentTemplate().$('.newSaleButton').removeClass('active');
|
||||
},
|
||||
"click .saleRemove": function(event, template) {
|
||||
let _this = this;
|
||||
@@ -441,7 +440,6 @@ Template.InsertSale.events({
|
||||
if(error) sAlert.error("Failed to insert the sale!\n" + error);
|
||||
else {
|
||||
sAlert.success("Sale Created");
|
||||
nextMeasure.find(".amount").val(0);
|
||||
|
||||
//Clear the measure quantity fields so the user can enter another sale without the quantities already set.
|
||||
for(let next = 0; next < insertSaleMeasures.length; next++) {
|
||||
@@ -449,6 +447,11 @@ Template.InsertSale.events({
|
||||
|
||||
nextMeasure.find(".amount").val(0);
|
||||
}
|
||||
|
||||
//Set the focus to the product field of the form.
|
||||
$("form[name='insertSaleForm'] input[name='product']").focus();
|
||||
//Clear the product since it is highly unlikely the same product will be added twice for the same date and market.
|
||||
$("form[name='insertSaleForm'] input[name='product']").val("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<template name="SalesSheetEditorConfigurationRow">
|
||||
{{#if isProduct}} {{! PRODUCT }}
|
||||
<div class="product columnContent noselect" data-model="{{productId}}">
|
||||
<div class="name clickable">{{name}}</div>
|
||||
<div class="name clickable"></div>
|
||||
<div class="nameEditor"><input class="form-control" name="name" type="text" tabindex="1" value="{{name}}"/> <i class="fa fa-check-circle accept" aria-hidden="true"></i> <i class="fa fa-times-circle reject" aria-hidden="true"></i></div>
|
||||
{{#if showMeasures}}
|
||||
<div class="measures">
|
||||
@@ -82,7 +82,7 @@
|
||||
</div>
|
||||
{{else}} {{! HEADING }}
|
||||
<div class="heading columnContent noselect">
|
||||
<div class="headingNameRow"><span class="name clickable">{{name}}</span><span class="sort clickable noselect"><i class="fa fa-arrow-down" aria-hidden="true"></i> sort <i class="fa fa-arrow-up" aria-hidden="true"></i></span></div>
|
||||
<div class="headingNameRow"><span class="name clickable"></span><span class="sort clickable noselect"><i class="fa fa-arrow-down" aria-hidden="true"></i> sort <i class="fa fa-arrow-up" aria-hidden="true"></i></span></div>
|
||||
<div class="nameEditor"><input class="form-control" name="name" type="text" tabindex="1" value="{{name}}"/> <i class="fa fa-check-circle accept" aria-hidden="true"></i> <i class="fa fa-times-circle reject" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -354,6 +354,40 @@ Template.SalesSheetEditorConfigurationRow.onCreated(function() {
|
||||
template.$('.product .name').text(name);
|
||||
template.$('.product .nameEditor, .product .name').removeClass('edit');
|
||||
};
|
||||
this.handleHeadingSort = function(event) {
|
||||
let width = event.currentTarget.offsetWidth;
|
||||
let x = event.pageX - event.currentTarget.offsetLeft;
|
||||
let sortAlphabetical = x <= (width / 2);
|
||||
let headingIndex = template.$(event.target).closest(".heading").index();
|
||||
let firstIndex = headingIndex + 1;
|
||||
let products = template.parentTemplate(1).salesSheet.products;
|
||||
let length = 0;
|
||||
|
||||
while(firstIndex + length < products.length && products[firstIndex + length].productId) {
|
||||
length++;
|
||||
}
|
||||
|
||||
//Sort the part of the array that contains products under the sorted heading.
|
||||
products.partialSort(firstIndex, length, function(a, b) {
|
||||
return sortAlphabetical ? (a.name < b.name ? -1 : 1) : (a.name > b.name ? -1 : 1);
|
||||
});
|
||||
|
||||
//Notify anything depending on the products list that they have been modified.
|
||||
template.parentTemplate(1).productsDependency.changed();
|
||||
};
|
||||
});
|
||||
Template.SalesSheetEditorConfigurationRow.onRendered(function() {
|
||||
let template = this;
|
||||
|
||||
Tracker.autorun(function() {
|
||||
let data = Blaze.getData(template.view);
|
||||
|
||||
template.parentTemplate(1).productsDependency.depend();
|
||||
|
||||
if(data) {
|
||||
template.$('.heading .name, .product .name').text(data.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
Template.SalesSheetEditorConfigurationRow.helpers({
|
||||
measureName: function(measureId) {
|
||||
@@ -436,24 +470,6 @@ Template.SalesSheetEditorConfigurationRow.events({
|
||||
this.measureIds.add(measureId);
|
||||
},
|
||||
'click .heading .sort': function(event, template) {
|
||||
let width = event.currentTarget.offsetWidth;
|
||||
let x = event.pageX - event.currentTarget.offsetLeft;
|
||||
let sortAlphabetical = x <= (width / 2);
|
||||
let headingIndex = template.$(event.target).closest(".heading").index();
|
||||
let firstIndex = headingIndex + 1;
|
||||
let products = template.parentTemplate(1).salesSheet.products;
|
||||
let length = 0;
|
||||
|
||||
while(firstIndex + length < products.length && products[firstIndex + length].productId) {
|
||||
length++;
|
||||
}
|
||||
|
||||
//Sort the part of the array that contains products under the sorted heading.
|
||||
products.partialSort(firstIndex, length, function(a, b) {
|
||||
return sortAlphabetical ? (a.name < b.name ? -1 : 1) : (a.name > b.name ? -1 : 1);
|
||||
});
|
||||
|
||||
//Notify anything depending on the products list that they have been modified.
|
||||
template.parentTemplate(1).productsDependency.changed();
|
||||
template.handleHeadingSort(event);
|
||||
}
|
||||
});
|
||||
@@ -29,19 +29,28 @@ Template.SalesSheetForm.onCreated(function() {
|
||||
// Place the sales sheet in a reactive var and put the setting of the reactive var in an autorun.
|
||||
// The autorun is needed apparently to ensure changes to the data force a change in the reactive var.
|
||||
Tracker.autorun(function() {
|
||||
let data = Blaze.getData(template.view);
|
||||
//****
|
||||
// Note: I have commented the code below out because I was unable to get Meteor to properly (according to their docs on Template.currentData() being reactive) call my code when the template's input data changes.
|
||||
// Because of this I have instead used the parent template's session variable "selectedSheet" to detect and handle the template data changing.
|
||||
// To avoid session variable conflicts, I have been using a session variable name prefix that is the template's name followed by a '.' as a convention.
|
||||
//****
|
||||
|
||||
//Force this to be reactive on the current data.
|
||||
try {
|
||||
Template.currentData();
|
||||
} catch(err) {
|
||||
// Ignore it. This always has an error accessing the currentData as the template is destroyed.
|
||||
}
|
||||
//try {
|
||||
// Template.currentData();
|
||||
//} catch(err) {
|
||||
// // Ignore it. This always has an error accessing the currentData as the template is destroyed.
|
||||
//}
|
||||
|
||||
//For some reason the current data is not always set, and does not always equal the template.data. We will use the template.data to get the actual ID of the sales sheet for the query.
|
||||
template.salesSheet.set(Meteor.collections.SalesSheets.findOne(template.data));
|
||||
//template.salesSheet.set(Template.instance() ? Meteor.collections.SalesSheets.findOne(Template.currentData()) : null);
|
||||
//template.salesSheet.set(Session.get("SalesSheets." + "selectedSheet"));
|
||||
template.salesSheet.set(Meteor.collections.SalesSheets.findOne(data));
|
||||
});
|
||||
|
||||
Tracker.autorun(function() {
|
||||
let products = template.salesSheet.get().products;
|
||||
let products = template.salesSheet.get() ? template.salesSheet.get().products : [];
|
||||
let index = 1;
|
||||
|
||||
// Note: We will ignore orphaned data in the dictionary so we don't have to clear the dictionary, or identify the orphans. The orphans are just a few extra product id's mapped to booleans, and should be fairly rare anyway.
|
||||
@@ -103,7 +112,7 @@ Template.SalesSheetForm.events({
|
||||
event.preventDefault();
|
||||
template.$('.sheetHeader').data('bs.validator').validate(function(isValid) {
|
||||
if(isValid) {
|
||||
let date = template.selectedDate.get();
|
||||
let date = ~~(moment(template.selectedDate.get()).format("YYYYMMDD"));
|
||||
let venueId = template.selectedVenue.get()._id;
|
||||
// Track the inserts and errors, display output to the user and log when everything is done.
|
||||
let insertMetadata = {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<label style="margin-right: 10px">Selected Sheet</label>
|
||||
<select name="sheetSelection" class="form-control">
|
||||
{{#each sheets}}
|
||||
<option value="{{_id}}" {{sheetsSelectIsSelected this isFirst}}>{{name}}</option>
|
||||
<option value="{{_id}}" {{isSheetSelected}}>{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<i class="fa fa-wrench editSheet noselect clickable {{#if disableButtons}}disabled{{/if}} {{#if isEditingSheet}}selected{{/if}}" aria-hidden="true">
|
||||
@@ -27,8 +27,8 @@
|
||||
<div class="separator" style="width: 50%; opacity: .25"></div>
|
||||
</section>
|
||||
<section class="tabSection verticalStack vscExpand">
|
||||
{{#if isSheetSelected}}
|
||||
{{>Template.dynamic template=tab data=tabData}}
|
||||
{{#if hasSelectedSheet}}
|
||||
{{>Template.dynamic template=activeTemplateName data=selectedSheetId}}
|
||||
{{/if}}
|
||||
</section>
|
||||
</template>
|
||||
@@ -15,7 +15,7 @@ Template.SalesSheets.onCreated(function() {
|
||||
Template.SalesSheets.onDestroyed(function() {
|
||||
// Reset the view's session variables used for navigation.
|
||||
Session.set(PREFIX + "currentFormName", undefined);
|
||||
Session.set(PREFIX + "tab", undefined);
|
||||
Session.set(PREFIX + "activeTemplateName", undefined);
|
||||
});
|
||||
|
||||
//******************************************************************
|
||||
@@ -24,10 +24,11 @@ Template.SalesSheets.onDestroyed(function() {
|
||||
Template.SalesSheetsMain.onCreated(function() {
|
||||
//Save the previous session state - whether we are editing the selected sheet.
|
||||
//The name of the currently active page tab. This will either be the SalesSheetForm or the SalesSheetEditor.
|
||||
if(!Session.get(PREFIX + "tab")) Session.set(PREFIX + "tab", "SalesSheetForm");
|
||||
if(!Session.get(PREFIX + 'selectedSheet')) {
|
||||
Session.set(PREFIX + 'selectedSheet', Meteor.collections.SalesSheets.findOne({}, {sort: {name: 1}}));
|
||||
}
|
||||
if(!Session.get(PREFIX + "activeTemplateName")) Session.set(PREFIX + "activeTemplateName", "SalesSheetForm");
|
||||
|
||||
this.sheets = Meteor.collections.SalesSheets.find({}, {sort: {name: 1}});
|
||||
let sheetArray = this.sheets.fetch();
|
||||
Session.set(PREFIX + 'selectedSheet', sheetArray.length > 0 ? sheetArray[0] : null);
|
||||
});
|
||||
Template.SalesSheetsMain.helpers({
|
||||
sheets: function() {
|
||||
@@ -36,35 +37,27 @@ Template.SalesSheetsMain.helpers({
|
||||
//if(sheets && sheets.length > 0) sheets[0].isFirst = true;
|
||||
//
|
||||
//return sheets;
|
||||
return Meteor.collections.SalesSheets.find({}, {sort: {name: 1}});
|
||||
return Template.instance().sheets;
|
||||
},
|
||||
sheetsSelectIsSelected: function(sheet, isFirst) {
|
||||
isSheetSelected: function() { // Determines if the passed sheet is the selected sheet and returns either "selected" or "".
|
||||
let selectedSheet = Session.get(PREFIX + "selectedSheet");
|
||||
|
||||
if(!selectedSheet && isFirst) Session.set(PREFIX + "selectedSheet", selectedSheet = sheet);
|
||||
|
||||
return selectedSheet == sheet ? "selected" : "";
|
||||
return selectedSheet == this ? "selected" : "";
|
||||
},
|
||||
disableButtons: function() {
|
||||
//Disable the edit & delete functionality if nothing is selected.
|
||||
disableButtons: function() { // Disable the edit & delete functionality if nothing is selected.
|
||||
return !Session.get(PREFIX + "selectedSheet");
|
||||
},
|
||||
selected: function() {
|
||||
//Get whether the current sheet is selected and return the string for use in the option tag.
|
||||
//return this.isSelected ? "selected" : "";
|
||||
return this._id == Session.get(PREFIX + 'selectedSheet')._id;
|
||||
activeTemplateName: function() { // The name of the template actively being shown to the user in the content area.
|
||||
return Session.get(PREFIX + "activeTemplateName");
|
||||
},
|
||||
tab: function() {
|
||||
return Session.get(PREFIX + "tab");
|
||||
selectedSheetId: function() { // Gets the ID of the sheet currently selected. This is passed to the template being actively show to the user.
|
||||
return Session.get(PREFIX + "selectedSheet") ? Session.get(PREFIX + "selectedSheet")._id : null;
|
||||
},
|
||||
tabData: function() {
|
||||
return Session.get(PREFIX + "selectedSheet")._id;
|
||||
},
|
||||
isSheetSelected: function() {
|
||||
hasSelectedSheet: function() { // Determines whether any sheet has been selected.
|
||||
return Session.get(PREFIX + "selectedSheet");
|
||||
},
|
||||
isEditingSheet: function() {
|
||||
return Session.get(PREFIX + "tab") == "SalesSheetEditor";
|
||||
return Session.get(PREFIX + "activeTemplateName") == "SalesSheetEditor";
|
||||
}
|
||||
});
|
||||
Template.SalesSheetsMain.events({
|
||||
@@ -74,16 +67,16 @@ Template.SalesSheetsMain.events({
|
||||
|
||||
Session.set(PREFIX + "selectedSheet", selected);
|
||||
// Reset the editor button & the displayed tab.
|
||||
Session.set(PREFIX + "tab", "SalesSheetForm");
|
||||
Session.set(PREFIX + "activeTemplateName", "SalesSheetForm");
|
||||
},
|
||||
'click .editSheet': function(event, template) {
|
||||
if(!$(event.target).hasClass("selected")) {
|
||||
// Display the editor for the sheet.
|
||||
Session.set(PREFIX + "tab", "SalesSheetEditor");
|
||||
Session.set(PREFIX + "activeTemplateName", "SalesSheetEditor");
|
||||
}
|
||||
else {
|
||||
// Remove the sheet editor and show the form to fill out the sheet.
|
||||
Session.set(PREFIX + "tab", "SalesSheetForm");
|
||||
Session.set(PREFIX + "activeTemplateName", "SalesSheetForm");
|
||||
// Reset the editor session variables.
|
||||
Session.set(PREFIX + "currentFormName", undefined);
|
||||
}
|
||||
@@ -137,7 +130,7 @@ Template.SalesSheetsMain.events({
|
||||
template.$('select[name="sheetSelection"]').val(id);
|
||||
Session.set(PREFIX + "selectedSheet", selected);
|
||||
//Display the editor tab.
|
||||
Session.set(PREFIX + "tab", "SalesSheetEditor");
|
||||
Session.set(PREFIX + "activeTemplateName", "SalesSheetEditor");
|
||||
clearInterval(interval);
|
||||
}
|
||||
else count++;
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
<template name="UserManagement">
|
||||
<div id="userManagement">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
<div class="insert">
|
||||
{{>UserInsert}}
|
||||
<div class="tableControls">
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
<div class="tableContainer">
|
||||
<table class="dataTable table table-striped table-hover">
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr class="headers">
|
||||
<th class="username">Username</th>
|
||||
<th class="email">Email</th>
|
||||
<tr>
|
||||
<th class="username">Username {{>UserSearch columnName='username'}}</th>
|
||||
<th class="email">Email {{>UserSearch columnName='email' collectionQueryColumnName='name' collection='Items' collectionResultColumnName='_id'}}</th>
|
||||
<th class="roles">Roles</th>
|
||||
<th class="actions">Actions</th>
|
||||
</tr>
|
||||
<tr class="footers">
|
||||
<th>{{>UserSearch columnName='username'}}</th>
|
||||
<th>{{>UserSearch columnName='email' collectionQueryColumnName='name' collection='Items' collectionResultColumnName='_id'}}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th class="actions">Actions <span class="newUserButton btn btn-success"><i class="fa fa-plus-circle" aria-hidden="true"></i><i class="fa fa-times-circle" aria-hidden="true"></i></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="dataTable table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#if displayNewUser}}
|
||||
<tr>{{> UserEditor isNew=true}}</tr>
|
||||
{{/if}}
|
||||
{{#each users}}
|
||||
{{> User}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -35,21 +42,31 @@
|
||||
<template name="User">
|
||||
<tr>
|
||||
{{#if editing}}
|
||||
<td><input name="username" class="form-control" type="text" value="{{username}}" required></td>
|
||||
<td><input name="email" class="form-control" type="text" value="{{email}}" required></td>
|
||||
<td class="roles center" style="font-size: 1.2em">
|
||||
{{> UserEditor}}
|
||||
{{else}}
|
||||
<td class="username tdLarge noselect nonclickable">{{username}}</td>
|
||||
<td class="email tdLarge noselect nonclickable">{{email}}</td>
|
||||
<td class="roles tdLarge noselect nonclickable">{{roles}}</td>
|
||||
<td class="actions center tdLarge"><i class="userRemove fa fa-times-circle fa-lg noselect clickable" aria-hidden="true"></i> / <i class="userEdit fa fa-pencil-square-o fa-lg noselect clickable" aria-hidden="true"></i></td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<template name="UserEditor">
|
||||
<td colspan="3" class="userEditor measureEditorTd">
|
||||
<div>
|
||||
<div class="username editorDiv"><label>User Name:</label><input name="username" class="form-control" type="text" value="{{username}}" autocomplete="off" required></div>
|
||||
<div class="email editorDiv"><label>User Email:</label><input name="email" class="form-control" type="text" value="{{email}}" autocomplete="off" required></div>
|
||||
<div class="rolesContainer editorDiv"><label>Roles:</label>
|
||||
<div class="roles center" style="font-size: 1.2em">
|
||||
{{#each allRoles}}
|
||||
<span class="role {{getRoleState this}} noselect">{{name}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="center tdLarge"><i class="editorApply fa fa-check-square-o fa-lg noselect clickable" aria-hidden="true"></i> / <i class="editorCancel fa fa-times-circle fa-lg noselect clickable" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
<td class="tdLarge noselect nonclickable">{{username}}</td>
|
||||
<td class="tdLarge noselect nonclickable">{{email}}</td>
|
||||
<td class="tdLarge noselect nonclickable">{{roles}}</td>
|
||||
<td class="center tdLarge"><i class="userRemove fa fa-times-circle fa-lg noselect clickable" aria-hidden="true"></i> / <i class="userEdit fa fa-pencil-square-o fa-lg noselect clickable" aria-hidden="true"></i></td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
<td class="actions center measureEditorTd"><i class="editorApply fa fa-check-square-o fa-lg noselect clickable" aria-hidden="true"></i> / <i class="editorCancel fa fa-times-circle fa-lg noselect clickable" aria-hidden="true"></i></td>
|
||||
</template>
|
||||
|
||||
<template name="UserSearch">
|
||||
@@ -57,34 +74,3 @@
|
||||
<input type="text" class="searchInput" placeholder="Filter..." value="{{searchValue}}" style="width: 90%"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="UserInsert">
|
||||
<form name="insert" autocomplete="off">
|
||||
<div class="grid">
|
||||
<div class="col-3-12"></div>
|
||||
<div class="col-6-12">
|
||||
<div class="formGroupHeading">New User</div>
|
||||
<div class="form-group">
|
||||
<label class='control-label'>User Name</label>
|
||||
<input name="username" type="text" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class='control-label'>Email</label>
|
||||
<input name="email" class="form-control" type="text" required/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class='control-label'>Roles</label>
|
||||
<div class="roles">
|
||||
{{#each allRoles}}
|
||||
<span class="role">{{name}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" class="btn btn-success" value="Create">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3-12"></div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
108
imports/ui/UserManagement.import.styl
vendored
108
imports/ui/UserManagement.import.styl
vendored
@@ -1,19 +1,31 @@
|
||||
#userManagement
|
||||
margin: 20px 20px
|
||||
display: table
|
||||
content-box: border-box
|
||||
padding: 10px 20px
|
||||
height: 100%
|
||||
//Flex container options.
|
||||
flex-flow: column nowrap
|
||||
justify-content: space-around //Spacing between sales along the primary axis. (vertical spacing for a column layout)
|
||||
align-items: flex-start //Align the sales within a line along the primary axis. (horizontal alignment for a column layout)
|
||||
align-content: center //Spacing between lines along the secondary axis. (spacing between columns for a column layout)
|
||||
display: -webkit-box
|
||||
display: -moz-box
|
||||
display: -ms-flexbox
|
||||
display: -moz-flex
|
||||
display: -webkit-flex
|
||||
display: flex
|
||||
width: 100%
|
||||
text-align: left
|
||||
|
||||
.tableControls
|
||||
display: table
|
||||
width: 100%
|
||||
text-align: right
|
||||
margin-right: 20px
|
||||
.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
|
||||
.editor
|
||||
height: 100%
|
||||
overflow-y: auto
|
||||
@@ -33,26 +45,64 @@
|
||||
font-style: normal
|
||||
font-variant: normal
|
||||
font-weight: 500
|
||||
.tableContainer
|
||||
width: 100%
|
||||
.table
|
||||
table-layout: fixed
|
||||
min-width: 100%
|
||||
thead, tbody
|
||||
> tr
|
||||
> .username
|
||||
width: 50%
|
||||
min-width: 100px
|
||||
> .email
|
||||
width: 50%
|
||||
min-width: 100px
|
||||
> .roles
|
||||
width: 260px
|
||||
min-width: 260px
|
||||
> .actions
|
||||
width: 80px
|
||||
min-width: 80px
|
||||
.separatedTableHeader
|
||||
.actions
|
||||
text-align: center
|
||||
.newUserButton
|
||||
margin-top: 4px
|
||||
padding: 0 12px
|
||||
.fa-plus-circle
|
||||
display: inline-block
|
||||
.fa-times-circle
|
||||
display: none
|
||||
.newUserButton.active
|
||||
background-color: #fb557b
|
||||
color: black
|
||||
.fa-times-circle
|
||||
display: inline-block
|
||||
.fa-plus-circle
|
||||
display: none
|
||||
.listRow
|
||||
display: table-row
|
||||
.listCell
|
||||
display: table-cell
|
||||
position: relative
|
||||
height: 100%
|
||||
margin-top: 20px
|
||||
margin-bottom: 20px
|
||||
width: 100%
|
||||
.tableContainer
|
||||
position: absolute
|
||||
top: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
right: 0
|
||||
width: auto
|
||||
height: auto
|
||||
border: 0
|
||||
font-size: 12.5px
|
||||
overflow-y: auto
|
||||
table
|
||||
table-layout: fixed
|
||||
width: 100%
|
||||
thead
|
||||
> tr
|
||||
> th.username
|
||||
width: auto
|
||||
> th.email
|
||||
width: auto
|
||||
> th.roles
|
||||
width: 260px
|
||||
> th.actions
|
||||
width: 80px
|
||||
display: none
|
||||
visibility: hidden
|
||||
.userRemove
|
||||
color: red
|
||||
.userEdit
|
||||
@@ -61,6 +111,14 @@
|
||||
color: green
|
||||
.editorCancel
|
||||
color: red
|
||||
.userEditor > div
|
||||
display: table
|
||||
> div
|
||||
display: table-cell
|
||||
padding: 10px
|
||||
.roles
|
||||
.role
|
||||
vertical-align: middle
|
||||
td.roles
|
||||
.role
|
||||
padding: 4px 4px
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import './UserManagement.html';
|
||||
import '/imports/util/selectize/selectize.js'
|
||||
|
||||
let QUERY_LIMIT = 100;
|
||||
let QUERY_LIMIT_INCREMENT = 100;
|
||||
let PREFIX = "UserManagement";
|
||||
|
||||
Tracker.autorun(function() {
|
||||
@@ -9,9 +11,71 @@ Tracker.autorun(function() {
|
||||
Meteor.subscribe("roles");
|
||||
});
|
||||
|
||||
Template.UserManagement.onCreated(function() {
|
||||
Session.set(PREFIX + "displayNewUser", false);
|
||||
Session.set(PREFIX + "queryLimit", QUERY_LIMIT);
|
||||
});
|
||||
Template.UserManagement.onRendered(function() {
|
||||
$(".tableContainer").mCustomScrollbar({
|
||||
scrollButtons: {enable:true},
|
||||
theme: "light-thick",
|
||||
scrollbarPosition: "outside",
|
||||
scrollEasing: "linear"
|
||||
});
|
||||
});
|
||||
Template.UserManagement.helpers({
|
||||
displayNewUser: function() {
|
||||
return Session.get(PREFIX + "displayNewUser");
|
||||
},
|
||||
users: function() {
|
||||
return Meteor.collections.Users.find({}, {sort: {username: 1}});
|
||||
let skipCount = Session.get(PREFIX + 'skipCount') || 0;
|
||||
let query = Session.get(PREFIX + 'searchQuery');
|
||||
let dbQuery = [];
|
||||
|
||||
if(query) {
|
||||
_.each(_.keys(query), function(key) {
|
||||
if(_.isFunction(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]();
|
||||
else if(_.isObject(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]; //Will look something like: {$in: [xxx,xxx,xxx]}
|
||||
else if(_.isNumber(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key];
|
||||
else {
|
||||
//dbQuery[key] = {$regex: query[key], $options: 'i'};
|
||||
let searchValue = query[key];
|
||||
let searches = searchValue && searchValue.length > 0 ? searchValue.split(/\s+/) : undefined;
|
||||
|
||||
for(let search of searches) {
|
||||
dbQuery.push({[key]: {$regex: '\\b' + search, $options: 'i'}});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(!Session.get(PREFIX + "showHidden")) {
|
||||
//Ignore any hidden elements by showing those not hidden, or those without the hidden field.
|
||||
dbQuery.push({$or: [{hidden: false}, {hidden: {$exists:false}}]});
|
||||
}
|
||||
|
||||
dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {};
|
||||
Session.set(PREFIX + 'userCount', Meteor.collections.Users.find(dbQuery).count()); //Always get a full count.
|
||||
return Meteor.collections.Users.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {username: 1}});
|
||||
},
|
||||
disableLoadMore: function() {
|
||||
return Session.get(PREFIX + 'userCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0;
|
||||
}
|
||||
});
|
||||
Template.UserManagement.events({
|
||||
'click .loadMoreLink': function(event, template) {
|
||||
event.preventDefault();
|
||||
Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT);
|
||||
},
|
||||
'click .newUserButton': function(event, template) {
|
||||
if(template.$('.newUserButton').hasClass('active')) {
|
||||
Session.set(PREFIX + 'displayNewUser', false);
|
||||
}
|
||||
else {
|
||||
Session.set(PREFIX + 'displayNewUser', true);
|
||||
Session.set(PREFIX + "editedUser", undefined); //Clear the edited user so that only one editor is open at a time.
|
||||
}
|
||||
template.$('.newUserButton').toggleClass('active');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,7 +84,10 @@ Template.User.onCreated(function() {
|
||||
});
|
||||
Template.User.events({
|
||||
"click .userEdit": function(event, template) {
|
||||
template.edited.set(this);
|
||||
//template.edited.set(this);
|
||||
Session.set(PREFIX + "editedUser", this._id);
|
||||
Session.set(PREFIX + 'displayNewUser', false); //Ensure the new measure editor is closed.
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
},
|
||||
"click .userRemove": function(event, template) {
|
||||
let _this = this;
|
||||
@@ -40,48 +107,6 @@ Template.User.events({
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
"click .editorCancel": function(event, template) {
|
||||
template.edited.set(undefined);
|
||||
},
|
||||
"click .editorApply": function(event, template) {
|
||||
let username = template.$("input[name='username']").val().trim();
|
||||
let email = template.$("input[name='email']").val().trim();
|
||||
let roleSpans = template.$(".roles > span");
|
||||
let roles = [];
|
||||
|
||||
for(let i = 0; i < roleSpans.length; i++) {
|
||||
if($(roleSpans[i]).hasClass("selected")) {
|
||||
roles.push($(roleSpans[i]).text());
|
||||
}
|
||||
}
|
||||
|
||||
//Basic validation.
|
||||
if(username && username.length > 0 && email && email.length > 0) {
|
||||
let emails = _.clone(this.emails);
|
||||
|
||||
if(!emails || emails.length == 0) {
|
||||
emails = [{address: email, verified: true}];
|
||||
}
|
||||
else {
|
||||
emails[0].address = email;
|
||||
emails[0].verified = true;
|
||||
}
|
||||
|
||||
Meteor.call("updateUser", {_id: this._id, username: username, emails: emails, roles: roles}, function(error, result) {
|
||||
if(error) {
|
||||
sAlert.error(error);
|
||||
}
|
||||
else {
|
||||
sAlert.success("User updated.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template.edited.set(undefined);
|
||||
},
|
||||
"click .role": function(event, template) {
|
||||
$(event.target).toggleClass("selected");
|
||||
}
|
||||
});
|
||||
Template.User.helpers({
|
||||
@@ -89,7 +114,15 @@ Template.User.helpers({
|
||||
return this.emails && this.emails.length > 0 ? this.emails[0].address : "";
|
||||
},
|
||||
editing: function() {
|
||||
return Template.instance().edited.get() == this;
|
||||
let editedUser = Session.get(PREFIX + "editedUser");
|
||||
|
||||
return editedUser == this._id;
|
||||
}
|
||||
});
|
||||
|
||||
Template.UserEditor.helpers({
|
||||
email: function() {
|
||||
return this.emails && this.emails.length > 0 ? this.emails[0].address : "";
|
||||
},
|
||||
allRoles: function() {
|
||||
return Meteor.collections.UserRoles.find();
|
||||
@@ -97,7 +130,56 @@ Template.User.helpers({
|
||||
getRoleState: function(role) {
|
||||
let user = Template.parentData(1);
|
||||
|
||||
return user.roles.includes(role.name) ? "selected" : "";
|
||||
return !user.isNew && user.roles.includes(role.name) ? "selected" : "";
|
||||
}
|
||||
});
|
||||
Template.UserEditor.events({
|
||||
"click .editorCancel": function(event, template) {
|
||||
Session.set(PREFIX + "editedUser", undefined);
|
||||
Session.set(PREFIX + 'displayNewUser', false);
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
},
|
||||
"click .editorApply": function(event, template) {
|
||||
let user = {};
|
||||
let roles = [];
|
||||
|
||||
user.username = template.$('input[name="username"]').val();
|
||||
user.email = template.$('input[name="email"]').val();
|
||||
|
||||
let roleSpans = template.$('.role.selected');
|
||||
for(let i = 0; i < roleSpans.length; i++) {
|
||||
roles.push($(roleSpans[i]).text());
|
||||
}
|
||||
|
||||
user.roles = roles;
|
||||
|
||||
if(Session.get(PREFIX + 'displayNewUser')) {
|
||||
Meteor.call('insertUser', user, function(error, result) {
|
||||
if(error) {
|
||||
sAlert.error(error);
|
||||
}
|
||||
else {
|
||||
sAlert.success("User created.");
|
||||
Session.set(PREFIX + 'displayNewUser', false);
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
user._id = this._id;
|
||||
Meteor.call("updateUser", user, function(error, result) {
|
||||
if(error) sAlert.error(error);
|
||||
else {
|
||||
sAlert.success("User updated.");
|
||||
Session.set(PREFIX + "editedUser", undefined);
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
"click .role": function(event, template) {
|
||||
$(event.target).toggleClass("selected");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -139,43 +221,3 @@ Template.UserSearch.helpers({
|
||||
return (searchFields && searchFields[this.columnName]) ? searchFields[this.columnName] : '';
|
||||
}
|
||||
});
|
||||
|
||||
Template.UserInsert.onRendered(function() {
|
||||
this.$('form[name="insert"]').validator();
|
||||
});
|
||||
Template.UserInsert.events({
|
||||
'click input[type="submit"]': function(event, template) {
|
||||
event.preventDefault();
|
||||
template.$('form[name="insert"]').data('bs.validator').validate(function(isValid) {
|
||||
if(isValid) {
|
||||
let user = {};
|
||||
let roles = [];
|
||||
|
||||
user.username = template.$('input[name="username"]').val();
|
||||
user.email = template.$('input[name="email"]').val();
|
||||
|
||||
let roleSpans = template.$('.role.selected');
|
||||
for(let i = 0; i < roleSpans.length; i++) {
|
||||
roles.push($(roleSpans[i]).text());
|
||||
}
|
||||
|
||||
Meteor.call('insertUser', user, roles, function(error, result) {
|
||||
if(error) {
|
||||
sAlert.error(error);
|
||||
}
|
||||
else {
|
||||
sAlert.success("User created.");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"click .role": function(event, template) {
|
||||
$(event.target).toggleClass("selected");
|
||||
}
|
||||
});
|
||||
Template.UserInsert.helpers({
|
||||
allRoles: function() {
|
||||
return Meteor.collections.UserRoles.find();
|
||||
}
|
||||
});
|
||||
@@ -2,20 +2,19 @@
|
||||
<div id="venues">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
<div class="tableControls">
|
||||
<div class="showHidden">
|
||||
<span class="controlLabel">Show Hidden</span>
|
||||
<div class="toggleShowHidden checkbox checkbox-slider--b-flat">
|
||||
<label>
|
||||
<input type="checkbox" name="showHidden"><span></span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="pagination">
|
||||
<span class="prevVenues noselect {{#if disablePrev}}disabled{{/if}}"><i class="fa fa-long-arrow-left" aria-hidden="true"></i> Prev</span>
|
||||
<span class="nextVenues noselect {{#if disableNext}}disabled{{/if}}">Next <i class="fa fa-long-arrow-right" aria-hidden="true"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer">
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -23,8 +22,13 @@
|
||||
<th class="type">Type {{>VenueSearch columnName='type'}}</th>
|
||||
<th class="actions">Actions <span class="newVenueButton btn btn-success"><i class="fa fa-plus-circle" aria-hidden="true"></i><i class="fa fa-times-circle" aria-hidden="true"></i></span></th>
|
||||
</tr>
|
||||
<!--<button type="button" name="newVenueButton"><i class="fa fa-plus-circle" aria-hidden="true"></i></button>-->
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#if displayNewVenue}}
|
||||
{{> VenueEditor isNew=true}}
|
||||
@@ -47,15 +51,15 @@
|
||||
{{#if editing}}
|
||||
{{> VenueEditor}}
|
||||
{{else}}
|
||||
<td class="noselect nonclickable left">{{name}}</td>
|
||||
<td class="noselect nonclickable left">{{type}}</td>
|
||||
<td class="name noselect nonclickable left">{{name}}</td>
|
||||
<td class="type noselect nonclickable left">{{type}}</td>
|
||||
{{#if hidden}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
{{#if deactivated}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||
{{else}}
|
||||
<td class="center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionRemove fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionRemove fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
77
imports/ui/Venues.import.styl
vendored
77
imports/ui/Venues.import.styl
vendored
@@ -7,8 +7,13 @@
|
||||
text-align: left
|
||||
|
||||
.tableControls
|
||||
display: table
|
||||
width: 100%
|
||||
text-align: right
|
||||
margin-right: 20px
|
||||
.showHidden
|
||||
display: table-cell
|
||||
width: 100%
|
||||
.controlLabel
|
||||
font-size: 9px
|
||||
font-weight: 700
|
||||
@@ -20,7 +25,55 @@
|
||||
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
|
||||
> .type
|
||||
width: 50%
|
||||
min-width: 100px
|
||||
> .actions
|
||||
width: 90px
|
||||
min-width: 90px
|
||||
.separatedTableHeader
|
||||
table
|
||||
thead
|
||||
> tr
|
||||
.actions
|
||||
text-align: center
|
||||
.newVenueButton
|
||||
margin-top: 4px
|
||||
padding: 0px 12px
|
||||
.fa-plus-circle
|
||||
display: inline-block
|
||||
.fa-times-circle
|
||||
display: none
|
||||
.newVenueButton.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.type
|
||||
width: auto
|
||||
> th.actions
|
||||
width: 90px
|
||||
text-align: center
|
||||
.newVenueButton
|
||||
margin-top: 4px
|
||||
padding: 0px 12px
|
||||
.fa-plus-circle
|
||||
display: inline-block
|
||||
.fa-times-circle
|
||||
display: none
|
||||
.newVenueButton.active
|
||||
background-color: #fb557b
|
||||
color: black
|
||||
.fa-times-circle
|
||||
display: inline-block
|
||||
.fa-plus-circle
|
||||
display: none
|
||||
visibility: hidden
|
||||
> tbody
|
||||
> tr
|
||||
.actionRemove
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
import './Venues.html';
|
||||
|
||||
let QUERY_LIMIT = 20;
|
||||
let QUERY_LIMIT = 100;
|
||||
let QUERY_LIMIT_INCREMENT = 100;
|
||||
let PREFIX = "Venues.";
|
||||
|
||||
Tracker.autorun(function() {
|
||||
@@ -11,6 +12,15 @@ Tracker.autorun(function() {
|
||||
Template.Venues.onCreated(function() {
|
||||
Session.set(PREFIX + "displayNewVenue", false);
|
||||
Session.set(PREFIX + "showHidden", false);
|
||||
Session.set(PREFIX + "queryLimit", QUERY_LIMIT);
|
||||
});
|
||||
Template.Venues.onRendered(function() {
|
||||
$(".tableContainer").mCustomScrollbar({
|
||||
scrollButtons: {enable:true},
|
||||
theme: "light-thick",
|
||||
scrollbarPosition: "outside",
|
||||
scrollEasing: "linear"
|
||||
});
|
||||
});
|
||||
Template.Venues.helpers({
|
||||
displayNewVenue: function() {
|
||||
@@ -45,23 +55,16 @@ Template.Venues.helpers({
|
||||
|
||||
dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {};
|
||||
Session.set(PREFIX + 'venueCount', Meteor.collections.Venues.find(dbQuery).count()); //Always get a full count.
|
||||
return Meteor.collections.Venues.find(dbQuery, {limit: QUERY_LIMIT, skip: skipCount, sort: {order: 1}});
|
||||
return Meteor.collections.Venues.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 + 'venueCount') - (Session.get(PREFIX + 'skipCount') || 0) - QUERY_LIMIT <= 0;
|
||||
disableLoadMore: function() {
|
||||
return Session.get(PREFIX + 'venueCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0;
|
||||
}
|
||||
});
|
||||
Template.Venues.events({
|
||||
'click .prevVenues': function(event, template) {
|
||||
if(!$(event.target).hasClass('disabled'))
|
||||
Session.set(PREFIX + 'skipCount', Math.max(0, (Session.get(PREFIX + 'skipCount') || 0) - QUERY_LIMIT));
|
||||
},
|
||||
'click .nextVenues': 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 .newVenueButton': function(event, template) {
|
||||
if(template.$('.newVenueButton').hasClass('active')) {
|
||||
@@ -150,7 +153,7 @@ Template.Venue.events({
|
||||
"click .actionEdit": function(event, template) {
|
||||
Session.set(PREFIX + "editedVenue", this._id);
|
||||
Session.set(PREFIX + 'displayNewVenue', false); //Ensure the new venue editor is closed.
|
||||
template.$('.newVenueButton').removeClass('active');
|
||||
template.parentTemplate().$('.newVenueButton').removeClass('active');
|
||||
},
|
||||
"click .actionRemove": function(event, template) {
|
||||
Meteor.call('deactivateVenue', this._id, function(error, result) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template name="Body">
|
||||
{{> sAlert}}
|
||||
<!--<div id="layoutBody" class="verticalStack">-->
|
||||
<div id="mainBody" class="mainBody verticalStack vscExpand">
|
||||
<div class="leftSidebar vscFixed">
|
||||
<div id="mainBody" class="mainBody">
|
||||
<nav class="leftSidebarContainer">
|
||||
<a href="javascript:" class="fa fa-bars leftSidebarMenuButton" aria-hidden="true"></a>
|
||||
<div class="leftSidebar">
|
||||
<div class="logoArea">
|
||||
<i class="fa fa-sign-out fa-2x signOut" aria-hidden="true"></i>
|
||||
<div class="logo">
|
||||
@@ -74,11 +75,11 @@
|
||||
© Petit Teton LLC 2017
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="contentBody verticalStack">
|
||||
{{> Template.dynamic template=content}}
|
||||
</div>
|
||||
</div>
|
||||
<!--</div>-->
|
||||
</template>
|
||||
|
||||
<!--<template name="Body">-->
|
||||
|
||||
261
imports/ui/layouts/Body.import.styl
vendored
261
imports/ui/layouts/Body.import.styl
vendored
@@ -9,8 +9,8 @@
|
||||
|
||||
#mainBody
|
||||
//position: relative
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
//display: flex;
|
||||
//flex-flow: row;
|
||||
//display: inline-block // Requried by Firefox for absolute positioning.
|
||||
margin: 0
|
||||
padding: 0
|
||||
@@ -18,6 +18,69 @@
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
nav.leftSidebarContainer
|
||||
z-index:999
|
||||
position: fixed
|
||||
top: 0
|
||||
width: 220px
|
||||
padding: 0
|
||||
height: 100%
|
||||
border: 0
|
||||
vertical-align: top
|
||||
text-align: left
|
||||
background-color: #90b272 //Old browsers
|
||||
background: -moz-linear-gradient(-180deg, #90b272 0%, #4d7727 100%) //FF3.6-15
|
||||
background: -webkit-linear-gradient(-180deg, #90b272 0%,#4d7727 100%) //Chrome10-25,Safari5.1-6
|
||||
background: linear-gradient(180deg, #90b272 0%,#4d7727 100%) //W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+
|
||||
font-size: 14px
|
||||
font-weight: 700
|
||||
overflow: visible
|
||||
margin: 0 0 0 -220px
|
||||
-webkit-transition: .5s ease-in
|
||||
-moz-transition: .5s ease-in
|
||||
-o-transition: .5s ease-in
|
||||
-ms-transition: .5s ease-in
|
||||
transition: .5s ease-in
|
||||
.leftSidebarMenuButton
|
||||
position: absolute
|
||||
right: -30px
|
||||
top: 10px
|
||||
-webkit-transition: .25s ease-in
|
||||
-moz-transition: .25s ease-in
|
||||
-o-transition: .25s ease-in
|
||||
-ms-transition: .25s ease-in
|
||||
transition: .25s ease-in
|
||||
-webkit-border-top-right-radius: 5px
|
||||
-webkit-border-bottom-right-radius: 5px
|
||||
-moz-border-radius-topright: 5px
|
||||
-moz-border-radius-bottomright: 5px
|
||||
border-top-right-radius: 5px
|
||||
border-bottom-right-radius: 5px
|
||||
color: black
|
||||
font-size: 20px
|
||||
line-height: 20px
|
||||
font-weight: 900
|
||||
text-align: center
|
||||
text-decoration: none
|
||||
width: 30px
|
||||
height: 30px
|
||||
padding: 5px 0
|
||||
background-color: #90b272
|
||||
display: block
|
||||
.leftSidebarMenuButton:hover
|
||||
color: rgba(150,0,0,.5)
|
||||
nav.menuShow
|
||||
margin: 0
|
||||
nav.menuShow .leftSidebarMenuButton
|
||||
right: -15px
|
||||
-webkit-transform: rotate(45deg) !important
|
||||
-moz-transform: rotate(45deg) !important
|
||||
-o-transform: rotate(45deg) !important
|
||||
-ms-transform: rotate(45deg) !important
|
||||
transform: rotate(45deg) !important
|
||||
-moz-border-radius-bottomright: 0
|
||||
border-top-right-radius: 0
|
||||
border-bottom-right-radius: 0
|
||||
.leftSidebar
|
||||
flex: 0 0 auto
|
||||
display: flex
|
||||
@@ -118,198 +181,4 @@
|
||||
-webkit-box-shadow: inset 4px 2px 10px -3px rgba(168,165,168,1)
|
||||
-moz-box-shadow: inset 4px 2px 10px -3px rgba(168,165,168,1)
|
||||
box-shadow: inset 8px 0px 10px -3px rgba(168,165,168,1)
|
||||
//position: absolute
|
||||
//top: 0
|
||||
//bottom: 0
|
||||
//left: 220px
|
||||
//right: 0
|
||||
overflow: hidden
|
||||
|
||||
//.contentBody
|
||||
// //display: table-cell
|
||||
// position: absolute
|
||||
// top: 0
|
||||
// bottom: 0
|
||||
// left: 220px
|
||||
// right: 0
|
||||
// //background: #4d7727
|
||||
//
|
||||
// .contentContainer
|
||||
// display: table
|
||||
// width: 100%
|
||||
// height: 100%
|
||||
// //border-radius 20px
|
||||
// //border: 0;
|
||||
// background: white
|
||||
//
|
||||
// .content
|
||||
// display: table-row
|
||||
// width: 100%
|
||||
// -webkit-box-shadow: inset 4px 2px 10px -3px rgba(168,165,168,1)
|
||||
// -moz-box-shadow: inset 4px 2px 6px 2px rgba(168,165,168,1)
|
||||
// box-shadow: inset 4px 2px 6px 2px rgba(168,165,168,1)
|
||||
|
||||
|
||||
//#layoutBody
|
||||
// width: 100%
|
||||
// height: 100%
|
||||
// display: table
|
||||
// margin: 0
|
||||
// padding: 0
|
||||
// border: 0
|
||||
//
|
||||
// .bodyTable
|
||||
// display: table
|
||||
// margin: 0
|
||||
// padding: 0
|
||||
// border: 0
|
||||
// .bodyTableRow
|
||||
// display: table-row
|
||||
// .bodyTableCell
|
||||
// display: table-cell
|
||||
//
|
||||
// .left
|
||||
// display: table-cell
|
||||
// border: 0
|
||||
// vertical-align: top
|
||||
// padding: 0
|
||||
// text-align: left
|
||||
// width: 220px
|
||||
// height: 100%
|
||||
// //Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#627d4d+0,1f3b08+100;Olive+3D
|
||||
// background: #627d4d //Old browsers
|
||||
// background: -moz-linear-gradient(-180deg, #627d4d 0%, #1f3b08 100%) //FF3.6-15
|
||||
// background: -webkit-linear-gradient(-180deg, #627d4d 0%,#1f3b08 100%) //Chrome10-25,Safari5.1-6
|
||||
// background: linear-gradient(180deg, #627d4d 0%,#1f3b08 100%) //W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+
|
||||
// font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||
// font-size: 14px
|
||||
// font-weight: 700
|
||||
//
|
||||
// ul
|
||||
// padding: 50px 0 0 0
|
||||
// margin: 0
|
||||
// list-style: none
|
||||
//
|
||||
// li:first-child
|
||||
// border-top: 1px solid #e4e5e7
|
||||
// li
|
||||
// border-bottom: 1px solid #e4e5e7
|
||||
// color: #96a2ae
|
||||
// text-transform: uppercase
|
||||
// display: block
|
||||
//
|
||||
// a
|
||||
// color: #96a2ae
|
||||
// padding: 15px 20px
|
||||
// cursor: pointer
|
||||
// text-decoration: none
|
||||
// display: block
|
||||
//
|
||||
// .tag
|
||||
// padding: .2em .5em
|
||||
// font-size: .7em
|
||||
// color: #fff
|
||||
// white-space: nowrap
|
||||
// vertical-align: baseline
|
||||
// border-radius: .25em
|
||||
// border: 1px solid #000000
|
||||
// float: right
|
||||
// li:hover
|
||||
// background-color: #333
|
||||
// li.active
|
||||
// background-color: #333
|
||||
//
|
||||
// .header
|
||||
// height: 1px
|
||||
// background: #627d4d
|
||||
// width: 100%
|
||||
// .content
|
||||
// background: white
|
||||
// .footer
|
||||
// text-align: center
|
||||
// height: 1px;
|
||||
// background: #1f3b08
|
||||
// color: white
|
||||
|
||||
|
||||
|
||||
//
|
||||
//.header
|
||||
// display: table-row
|
||||
// height: 1px
|
||||
// background: #627d4d
|
||||
//
|
||||
//#layoutBody.body
|
||||
// display: table
|
||||
// margin: 0
|
||||
// padding: 0
|
||||
// width: 100%
|
||||
// height: 100%
|
||||
//
|
||||
// .body
|
||||
// display: table-row
|
||||
// width: 100%
|
||||
//
|
||||
// .left
|
||||
// display: table-cell
|
||||
// border: 0
|
||||
// vertical-align: top
|
||||
// padding: 0
|
||||
// text-align: left
|
||||
// width: 220px
|
||||
// //Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#627d4d+0,1f3b08+100;Olive+3D
|
||||
// background: #627d4d //Old browsers
|
||||
// background: -moz-linear-gradient(-180deg, #627d4d 0%, #1f3b08 100%) //FF3.6-15
|
||||
// background: -webkit-linear-gradient(-180deg, #627d4d 0%,#1f3b08 100%) //Chrome10-25,Safari5.1-6
|
||||
// background: linear-gradient(180deg, #627d4d 0%,#1f3b08 100%) //W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+
|
||||
// font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||
// font-size: 14px;
|
||||
// font-weight: 700
|
||||
//
|
||||
// ul
|
||||
// padding: 50px 0 0 0
|
||||
// margin: 0
|
||||
// list-style: none
|
||||
//
|
||||
// li:first-child
|
||||
// border-top: 1px solid #e4e5e7
|
||||
// li
|
||||
// border-bottom: 1px solid #e4e5e7
|
||||
// color: #96a2ae
|
||||
// text-transform: uppercase
|
||||
// display: block
|
||||
//
|
||||
// a
|
||||
// color: #96a2ae
|
||||
// padding: 15px 20px
|
||||
// cursor: pointer
|
||||
// text-decoration: none
|
||||
// display: block
|
||||
//
|
||||
// .tag
|
||||
// padding: .2em .5em
|
||||
// font-size: .7em
|
||||
// color: #fff
|
||||
// white-space: nowrap
|
||||
// vertical-align: baseline
|
||||
// border-radius: .25em
|
||||
// border: 1px solid #000000
|
||||
// float: right
|
||||
// li:hover
|
||||
// background-color: #333
|
||||
// li.active
|
||||
// background-color: #333
|
||||
// .main
|
||||
// display: table-row
|
||||
// background: white
|
||||
// border: 0
|
||||
// vertical-align: top
|
||||
// padding: 0
|
||||
// text-align: left
|
||||
//
|
||||
// .footer
|
||||
// display: table-row
|
||||
// text-align: center
|
||||
// height: 1px;
|
||||
// background: #1f3b08
|
||||
// color: white
|
||||
@@ -5,5 +5,12 @@ import './Body.html';
|
||||
Template.Body.events({
|
||||
"click .signOut": function(event, template) {
|
||||
AccountsTemplates.logout();
|
||||
},
|
||||
"click .leftSidebarMenuButton": function(event, template) {
|
||||
event.preventDefault();
|
||||
$('nav.leftSidebarContainer').toggleClass('menuShow');
|
||||
},
|
||||
"click .menuArea a": function(event, template) {
|
||||
$('nav.leftSidebarContainer').toggleClass('menuShow');
|
||||
}
|
||||
});
|
||||
@@ -38,3 +38,34 @@ Date.prototype.getWeek = function() {
|
||||
|
||||
return weeknum;
|
||||
};
|
||||
|
||||
Date.prototype.getUTCWeek = function() {
|
||||
let dowOffset = 1; // I am fixing this to indicate that the first day of the week is always Monday (weeks end on Sunday), for this application. This was a parameter in the original code.
|
||||
|
||||
//dowOffset = typeof(dowOffset) == 'number' ? dowOffset : 0; //default dowOffset to zero - This should check to ensure that dowOffset is between 0..6
|
||||
let newYear = new Date(this.getUTCFullYear(),0,1);
|
||||
let day = newYear.getDay() - dowOffset; //the day of week the year begins on
|
||||
day = (day >= 0 ? day : day + 7);
|
||||
// The number of days from the beginning of the year to this.day
|
||||
let daynum = Math.floor((this.getTime() - newYear.getTime() - (this.getTimezoneOffset() - newYear.getTimezoneOffset())*60000)/86400000) + 1;
|
||||
let weeknum;
|
||||
|
||||
// I have removed the mid-week starting cutoff detection because in this app we always want to start with week #1 (never have a week zero).
|
||||
//if(day < 4) { //if the year starts before the middle of a week
|
||||
weeknum = Math.floor((daynum + day - 1) / 7) + 1;
|
||||
|
||||
// I have turned off the detection of whether the last days of the year belong to this year's last week or next year's first week. This gets too confusing and does not result in any additional usefulness.
|
||||
//if(weeknum > 52) {
|
||||
// nYear = new Date(this.getFullYear() + 1, 0, 1);
|
||||
// nday = nYear.getDay() - dowOffset;
|
||||
// nday = nday >= 0 ? nday : nday + 7;
|
||||
// // if the next year starts before the middle of the week, it is week #1 of that year
|
||||
// weeknum = nday < 4 ? 1 : 53;
|
||||
//}
|
||||
//}
|
||||
//else {
|
||||
// weeknum = Math.floor((daynum+day-1)/7);
|
||||
//}
|
||||
|
||||
return weeknum;
|
||||
};
|
||||
@@ -16,14 +16,16 @@ Meteor.methods({
|
||||
|
||||
for(let i = 0; i < sales.length; i++) {
|
||||
let dateString = sales[i].date.toString();
|
||||
dateString = dateString.substring(0, 4) + "-" + dateString.substring(4,6) + "-" + dateString.substring(6,8) + "T00:00:00Z";
|
||||
let timestamp = new Date(dateString);
|
||||
let weekOfYear = timestamp.getWeek();
|
||||
let timestamp = new Date(Date.UTC(parseInt(dateString.substring(0, 4)), parseInt(dateString.substring(4,6)) - 1, parseInt(dateString.substring(6,8))));
|
||||
let weekOfYear = timestamp.getUTCWeek();
|
||||
|
||||
//console.log("Converted " + sales[i].date + " to " + timestamp + " using " + dateString);
|
||||
if(sales[i]._id === "s9hJLRsQhha3w3ce2") {
|
||||
console.log(parseInt(dateString.substring(6,8)));
|
||||
console.log("Converted " + sales[i].date + " to " + timestamp + " where the week # is " + weekOfYear);
|
||||
}
|
||||
|
||||
// Save to the database.
|
||||
Sales.update(sales[i]._id, {$set: {timestamp, weekOfYear}}, {bypassCollection2: true}, function(err, id) {
|
||||
Sales.update(sales[i]._id, {$set: {"timestamp": timestamp.getTime(), weekOfYear}}, {bypassCollection2: true}, function(err, id) {
|
||||
if(err) console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user