Add MemberManage dashboard

This commit is contained in:
2022-10-24 11:17:36 -04:00
parent cb5f92e58f
commit bdaa3ab3d5
34 changed files with 2834 additions and 13 deletions
@@ -0,0 +1,149 @@
/**
* @ngdoc controller
* @name MemberManager.Dialogs.Member.EditController
* @function
*
* @description
* The controller for the member editor
*
* @param {any} $scope Scope
* @param {any} $routeParams Route Parameters
* @param {any} $q Queue
* @param {any} memberResource Member Resource
* @param {any} entityResource Entity Resource
* @param {any} serverValidationManager Server Validation Manager
* @param {any} contentEditingHelper Content Editing Helper
* @param {any} fileManager File Manager
* @param {any} formHelper Form Helper
*/
function MemberEditDialogController($scope, $routeParams, $q, memberResource, entityResource, serverValidationManager, contentEditingHelper, fileManager, formHelper) {
//setup scope vars
$scope.model = {};
$scope.model.defaultButton = null;
$scope.model.subButtons = [];
$scope.model.nodeId = 0;
$scope.loaded = false;
var dialogOptions = $scope.$parent.dialogOptions;
function performGet() {
var deferred = $q.defer();
if (angular.isObject(dialogOptions.entity)) {
$scope.loaded = true;
deferred.resolve(dialogOptions.entity);
} else {
if (dialogOptions.create) {
//we are creating so get an empty member item
memberResource.getScaffold(dialogOptions.contentType)
.then(function (data) {
$scope.loaded = true;
deferred.resolve(data);
});
}
else {
if (dialogOptions.key && dialogOptions.key.toString().length < 9) {
entityResource.getById(dialogOptions.key, "Member").then(function (entity) {
memberResource.getByKey(entity.key).then(function (data) {
//in one particular special case, after we've created a new item we redirect back to the edit
// route but there might be server validation errors in the collection which we need to display
// after the redirect, so we will bind all subscriptions which will show the server validation errors
// if there are any and then clear them so the collection no longer persists them.
serverValidationManager.executeAndClearAllSubscriptions();
$scope.loaded = true;
deferred.resolve(data);
});
});
}
else {
//we are editing so get the content item from the server
memberResource.getByKey(dialogOptions.key)
.then(function (data) {
$scope.loaded = true;
//in one particular special case, after we've created a new item we redirect back to the edit
// route but there might be server validation errors in the collection which we need to display
// after the redirect, so we will bind all subscriptions which will show the server validation errors
// if there are any and then clear them so the collection no longer persists them.
serverValidationManager.executeAndClearAllSubscriptions();
deferred.resolve(data);
});
}
}
}
return deferred.promise;
}
function performSave(args) {
var deferred = $q.defer();
$scope.busy = true;
if (formHelper.submitForm({ scope: $scope, statusMessage: args.statusMessage })) {
$scope.busy = true;
args.saveMethod($scope.model.entity, $routeParams.create, fileManager.getFiles())
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
savedContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.model.entity, data)
});
$scope.busy = false;
deferred.resolve(data);
}, function (err) {
contentEditingHelper.handleSaveError({
redirectOnFailure: false,
err: err,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.model.entity, err.data)
});
$scope.busy = false;
deferred.reject(err);
});
} else {
$scope.busy = false;
deferred.reject();
}
return deferred.promise;
}
performGet().then(function (content) {
$scope.model.entity = $scope.filterTabs(content, dialogOptions.tabFilter);
});
$scope.filterTabs = function (entity, blackList) {
if (blackList) {
_.each(entity.tabs, function (tab) {
tab.hide = _.contains(blackList, tab.alias);
});
}
return entity;
};
$scope.save = function () {
performSave({ saveMethod: memberResource.save, statusMessage: "Saving..." })
.then(function (content) {
if (dialogOptions.closeOnSave) {
$scope.submit(content);
}
});
};
}
angular.module("umbraco").controller("MemberManager.Dialogs.Member.EditController", MemberEditDialogController);
@@ -0,0 +1,45 @@
<form novalidate name="contentForm"
ng-controller="MemberManager.Dialogs.Member.EditController"
ng-show="loaded"
ng-submit="save()"
val-form-manager>
<div class="umb-panel">
<div class="umb-panel-header">
<umb-content-name placeholder="@placeholders_entername"
ng-model="model.entity.name" />
</div>
<div class="umb-panel-body with-footer">
<div id="tab{{tab.id}}" ng-repeat="tab in model.entity.tabs">
<div class="umb-pane" ng-if="!tab.hide">
<h5>{{tab.label}}</h5>
<umb-property property="property"
ng-repeat="property in tab.properties">
<umb-editor model="property"></umb-editor>
</umb-property>
</div>
</div>
</div>
<div class="umb-panel-footer">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<a href ng-click="close()" class="btn btn-link">
<localize key="general_close">Close</localize>
</a>
<div class="btn-group dropup">
<!-- primary button -->
<a class="btn btn-success" href="#" ng-click="save()" prevent-default>
Save
</a>
</div>
</div>
</div>
</div>
</div>
</form>
@@ -0,0 +1,116 @@
angular.module("umbraco").controller("MemberManager.Dialogs.Member.ExportController",
function ($scope, memberExtResource) {
$scope.defaultButton = null;
$scope.subButtons = [];
var dialogOptions = $scope.$parent.dialogOptions;
$scope.filterData = dialogOptions.filterData;
$scope.columns = dialogOptions.columns;
//$scope.memberType = dialogOptions.filterData.memberType;
$scope.totalItems = dialogOptions.totalItems;
$scope.memberTypes = dialogOptions.memberTypes;
$scope.format = "Excel";
$scope.allColumnsSelected = false;
function init() {
var buttons = {
defaultButton: createButtonDefinition("E"),
subButtons: []
};
$scope.defaultButton = buttons.defaultButton;
$scope.subButtons = buttons.subButtons;
memberExtResource.getMemberColumns(dialogOptions.filterData.memberType).then(function (data) {
// We use this to preserve the original filter data.
$scope.columnList = setSelected(data, $scope.columns);
$scope.allColumnsSelected = $scope.allSelected($scope.columnList);
});
}
function createButtonDefinition(ch) {
switch (ch) {
case "E":
//export action
return {
letter: ch,
labelKey: "memberManager_export",
label: "Export",
handler: $scope.export,
hotKey: "ctrl+e",
hotKeyWhenHidden: true,
alias: "export"
};
default:
return null;
}
}
// Loop through a list of select options and set selected for values that appear in a filter list
setSelected = function (list, filter) {
// Convert string arrays to a select item object.
list = _.map(list, function (item) {
if (typeof item === "string") {
let value = item;
item = {
id: value.replace(" ", "_"),
name: value,
alias: value,
selected: false
};
}
return item;
});
if (filter) {
for (var i = 0; i < filter.length; i++) {
for (var j = 0; j < list.length; j++) {
if (list[j].id === filter[i].replace(" ", "_")) {
list[j].selected = true;
}
}
}
}
return list;
};
processColumnList = function (list) {
var filteredList = _.filter(list, function (i) {
return i.selected;
});
return _.map(filteredList, function (item) {
return item.alias;
});
};
// Methods to manage select/deselect all in checkbox lists.
$scope.selectAll = function (selectionList) {
_.each(selectionList, function (item) { item.selected = $scope.allColumnsSelected; });
};
$scope.allSelected = function (selectionList) {
return _.filter(selectionList, function (item) { return item.selected; }).length === selectionList.length;
};
$scope.export = function () {
$scope.submit(processColumnList($scope.columnList));
};
// this method is called for all action buttons and then we proxy based on the btn definition
$scope.performAction = function (btn) {
if (!btn || !angular.isFunction(btn.handler)) {
throw "btn.handler must be a function reference";
}
btn.handler.apply(this);
};
init();
});
@@ -0,0 +1,90 @@
<form novalidate name="contentForm"
ng-controller="MemberManager.Dialogs.Member.ExportController"
ng-submit="export()"
val-form-manager
class="umb-mini-editor">
<div class="umb-panel">
<div class="umb-panel-header">
<h1>
<localize key="memberManager_export">Export</localize>
</h1>
</div>
<div class="umb-panel-body with-footer">
<div class="umb-pane filter-options">
<div class="umb-el-wrap">
<label class="control-label">Exportable records:</label> <span>{{totalItems}} members</span>
<div class="alert alert-warning" ng-if="totalItems > 100">Exporting a large number of members may take some time.</div>
</div>
<div class="umb-el-wrap" ng-if="filterData.display">
<label class="control-label">Applied Filters: </label>
<div class="filter-display">
<div ng-repeat="displayFilter in filterData.display">
<strong>{{displayFilter.title}}</strong>
<span>{{displayFilter.value}}</span>
</div>
</div>
</div>
<div class="umb-el-wrap filter-checkbox-list" ng-show="columnList && columnList.length > 1">
<h5>Columns</h5>
<p>Select the columns to include in the exported data</p>
<div class="filter-header">
<div>
<input type="checkbox" ng-model="allColumnsSelected" ng-click="selectAll(columnList)" id="column-all" />
<label class="control-label" for="column-all">Select / deselect all columns</label>
</div>
</div>
<div class="filter-content">
<div ng-repeat="column in columnList">
<input type="checkbox" ng-model="column.selected" id="column-{{column.id}}" />
<label class="control-label" for="column-{{column.id}}">{{column.name}}</label>
</div>
</div>
</div>
<div class="umb-el-wrap">
<label class="control-label">Format: </label>
<div class="controls controls-row">
<select ng-model="format">
<option value="Excel">Excel Spreadsheet (*.xlsx)</option>
<option value="CSV">Comma Separated Values (*.csv)</option>
</select>
</div>
</div>
</div>
</div>
<div class="umb-panel-footer">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<a ng-click="close()" class="btn btn-link">
<localize key="general_close">Close</localize>
</a>
<div class="btn-group dropup" ng-if="defaultButton">
<!-- primary button -->
<a class="btn btn-success" href="#" ng-click="performAction(defaultButton)" prevent-default>
<localize key="{{defaultButton.labelKey}}">{{defaultButton.label}}</localize>
</a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
<span class="caret"></span>
</a>
<!-- sub buttons -->
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel" ng-if="subButtons.length > 0">
<li ng-repeat="btn in subButtons">
<a href="#" ng-click="performAction(btn)" prevent-default>
<localize key="{{btn.labelKey}}">{{btn.label}}</localize>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</form>
@@ -0,0 +1,167 @@
angular.module("umbraco").controller("MemberManager.Dialogs.Member.FilterController",
function ($scope) {
$scope.defaultButton = null;
$scope.subButtons = [];
var dialogOptions = $scope.$parent.dialogOptions;
$scope.filterData = dialogOptions.filterData;
$scope.memberTypes = dialogOptions.memberTypes;
$scope.memberGroups = dialogOptions.memberGroups;
function init() {
var buttons = {
defaultButton: createButtonDefinition("F"),
subButtons: [
createButtonDefinition("C")
]
};
$scope.defaultButton = buttons.defaultButton;
$scope.subButtons = buttons.subButtons;
// We use this to preserve the original filter data.
$scope.memberGroupFilter = setSelected($scope.memberGroups, $scope.filterData.memberGroups);
}
function createButtonDefinition(ch) {
switch (ch) {
case "F":
//publish action
return {
letter: ch,
labelKey: "memberManager_applyFilter",
label: "Apply Filter",
handler: $scope.applyFilter,
hotKey: "ctrl+f",
hotKeyWhenHidden: true,
alias: "applyFilter"
};
case "C":
//send to publish
return {
letter: ch,
labelKey: "memberManager_clearFilter",
label: "Clear Filter",
handler: $scope.clearFilter,
hotKey: "ctrl+c",
hotKeyWhenHidden: true,
alias: "sendToPublish"
};
default:
return null;
}
}
// Generate model for representing the search
getFilterModel = function () {
var displaySearch = new Array();
//if ($scope.filterData.filter) {
// displaySearch.push({ title: "Search", value: $scope.filterData.filter });
//}
if ($scope.filterData.memberType) {
displaySearch.push({ title: "Member Type", value: _getMemberTypeName() });
}
if ($scope.filterData.f_umbracoMemberApproved) {
displaySearch.push({ title: "Approved", value: $scope.filterData.f_umbracoMemberApproved === "true,1" ? "Approved" : "Suspended" });
}
if ($scope.filterData.f_umbracoMemberLockedOut) {
displaySearch.push({ title: "Locked Out", value: $scope.filterData.f_umbracoMemberLockedOut === "true,1" ? "Locked Out" : "Active" });
}
return {
filter: $scope.filterData.filter,
memberType: $scope.filterData.memberType,
memberGroups: processFilterList(displaySearch, "Member Groups", $scope.memberGroupFilter),
f_umbracoMemberApproved: !$scope.filterData.f_umbracoMemberApproved ? "" : $scope.filterData.f_umbracoMemberApproved,
f_umbracoMemberLockedOut: !$scope.filterData.f_umbracoMemberLockedOut ? "" : $scope.filterData.f_umbracoMemberLockedOut,
display: displaySearch
};
};
function _getMemberTypeName() {
var type = _.filter($scope.memberTypes, function (item) {
return item.alias === $scope.filterData.memberType;
});
return _.map(type, function (item) {
return ' ' + item.name;
}).join();
}
// Loop through a list of select options and set selected for values that appear in a filter list
setSelected = function (list, filter) {
// Convert string arrays to a select item object.
list = _.map(list, function (item) {
if (typeof item === "string") {
let value = item;
item = {
id: value.replace(" ", "_"),
name: value,
alias: value,
selected: false
};
}
return item;
});
if (filter) {
for (var i = 0; i < filter.length; i++) {
for (var j = 0; j < list.length; j++) {
if (list[j].id === filter[i].replace(" ", "_")) {
list[j].selected = true;
}
}
}
}
return list;
};
processFilterList = function (display, title, list) {
var filteredList = _.filter(list, function (i) {
return i.selected;
});
var displayVal = _.map(filteredList, function (item) {
return ' ' + item.name;
}).join();
if (displayVal) {
display.push({ title: title, value: displayVal });
}
return _.map(filteredList, function (item) {
return item.alias;
});
};
$scope.applyFilter = function () {
$scope.submit(getFilterModel());
};
$scope.clearFilter = function () {
$scope.filterData = {
filter: null
};
$scope.submit($scope.filterData);
};
// this method is called for all action buttons and then we proxy based on the btn definition
$scope.performAction = function (btn) {
if (!btn || !angular.isFunction(btn.handler)) {
throw "btn.handler must be a function reference";
}
btn.handler.apply(this);
};
init();
});
@@ -0,0 +1,95 @@
<form novalidate name="contentForm"
ng-controller="MemberManager.Dialogs.Member.FilterController"
ng-submit="applyFilter()"
val-form-manager
class="umb-mini-editor">
<div class="umb-panel">
<div class="umb-panel-header">
<h1>
<localize key="memberManager_filter">Filter</localize>
</h1>
</div>
<div class="umb-panel-body with-footer">
<div class="umb-pane filter-options">
<div class="umb-property">
<label class="control-label">Search</label>
<div class="controls controls-row">
<input type="text" ng-model="filterData.filter" />
</div>
</div>
<div class="umb-el-wrap" ng-show="memberTypes && memberTypes.length > 1">
<label class="control-label">Member Type</label>
<div class="controls controls-row">
<select ng-model="filterData.memberType">
<option value="">- All -</option>
<option ng-repeat="memberType in memberTypes" ng-value="{{memberType.alias}}">{{memberType.name}}</option>
</select>
</div>
</div>
<div class="filter-checkbox-list" ng-show="memberGroupFilter && memberGroupFilter.length > 1">
<h5>Member Groups</h5>
<div class="filter-content">
<div ng-repeat="group in memberGroupFilter">
<input type="checkbox" ng-model="group.selected" id="group-{{group.id}}" />
<label class="control-label" for="group-{{group.id}}">{{group.name}}</label>
</div>
</div>
</div>
<div class="umb-el-wrap">
<label class="control-label">Approved</label>
<div class="controls controls-row">
<select ng-model="filterData.f_umbracoMemberApproved">
<option value="">- All -</option>
<option value="true,1">Approved Only</option>
<option value="false,0">Suspended Only</option>
</select>
</div>
</div>
<div class="umb-el-wrap">
<label class="control-label">Locked Out</label>
<div class="controls controls-row">
<select ng-model="filterData.f_umbracoMemberLockedOut">
<option value="">- All -</option>
<option value="true,1">Locked Out Only</option>
<option value="false,0">Active Only</option>
</select>
</div>
</div>
</div>
</div>
<div class="umb-panel-footer">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<a ng-click="close()" class="btn btn-link">
<localize key="general_close">Close</localize>
</a>
<div class="btn-group dropup" ng-if="defaultButton">
<!-- primary button -->
<a class="btn btn-success" href="#" ng-click="performAction(defaultButton)" prevent-default>
<localize key="{{defaultButton.labelKey}}">{{defaultButton.label}}</localize>
</a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
<span class="caret"></span>
</a>
<!-- sub buttons -->
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel" ng-if="subButtons.length > 0">
<li ng-repeat="btn in subButtons">
<a href="#" ng-click="performAction(btn)" prevent-default>
<localize key="{{btn.labelKey}}">{{btn.label}}</localize>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</form>