Skip to content

Commit

Permalink
Merge pull request #61 from daveb-501commons/feature/NPSPMigration
Browse files Browse the repository at this point in the history
Feature/npsp migration
  • Loading branch information
Evan Callahan authored Nov 5, 2018
2 parents 9f8e8c4 + f695103 commit 6eddf84
Show file tree
Hide file tree
Showing 86 changed files with 6,206 additions and 1,580 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ salesforce-food-bank.sublime-workspace
/resource-bundles/.DS_Store
/resource-bundles/Angular.resource/mmui.log
/resource-bundles/Angular.resource/mmst.log
/resource-bundles/Angular.resource/bower_components
/resource-bundles/Angular.resource/bower_components*
.sfdx/
.vscode/
test_results*
/temp
~*
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
salesforce-food-bank
====================

Food Bank Manager built on Salesforce using Angular.js
Food Bank Service built on Salesforce using Angular.js

This is a Salesforce.com and AngularJS application that tracks clients and service delivery for food banks.

Expand Down Expand Up @@ -44,7 +44,7 @@ Here is a 5-minute video introduction: http://youtu.be/vzvGtpBY08E
* **Salesforce Instance Setup**
```
Edit System Administrator Profile > Field-Level Security for custom objects Client, Client Household, and Client Visit & give View/Edit permissions on all fields
Edit System Administrator Profile > Field-Level Security for custom objects Client, Client Household, and Food Bank Visit & give View/Edit permissions on all fields
```
* **Open Food Bank App**
Expand All @@ -67,10 +67,13 @@ There is an alternate home page, as well as a Jasmine Test Runner page. For exa
* For the home page, open your web browser to: http://localhost:8000/
* For the test runner, open to: http://localhost:8000/test/TestRunner.html
## Instance Setup Steps
* Ensure the default record type for any profile using the Food Bank is set to Household. Otherwise you'll receive an error trying to add new Accounts.
## Implementation Notes
This unmanaged package is built on 3 primary custom objects; Client, Client Household, and Client Visit. There is no dependency or integration with Salesforce NPSP (https://github.com/SalesforceFoundation/Cumulus) although that is a future goal.
This unmanaged package is built on 3 primary custom objects; Client, Client Household, and Food Bank Visit. There is no dependency or integration with Salesforce NPSP (https://github.com/SalesforceFoundation/Cumulus) although that is a future goal.
## Description of Files and Directories
Expand Down
2 changes: 2 additions & 0 deletions cumulusci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ project:
name: salesforce-food-bank
package:
name: salesforce-food-bank
dependencies:
- github: https://github.com/SalesforceFoundation/Cumulus
Binary file added docs/V4SF-Setup.docx
Binary file not shown.
9 changes: 4 additions & 5 deletions resource-bundles/Angular.resource/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ angular.module('foodBankApp', [
}
}
})
.when('/client/:clientId/:action?', {
.when('/client/:clientId/:clientContactId/:action?', {
templateUrl: basePath + '/app/client/client.html',
controller: 'clientController',
resolve: {
Expand All @@ -58,7 +58,7 @@ angular.module('foodBankApp', [
}
}
})
.when('/new_client/:fullName?', {
.when('/new_client/', {
templateUrl: basePath + '/app/client_edit/client_edit.html',
controller: 'clientEditController',
resolve: {
Expand All @@ -67,13 +67,12 @@ angular.module('foodBankApp', [
},
foundHousehold: function($q, $route) {
var deferred = $q.defer();
var fullName = $route.current.params.fullName;
deferred.resolve({name: 'New Client', members: [{ firstName: fullName, lastName: fullName }]});
deferred.resolve({name: 'Unknown', members: [{ firstName: ''}]});
return deferred.promise;
}
}
})
.when('/log_visit/:clientId', {
.when('/log_visit/:clientId/:clientContactId', {
templateUrl: basePath + '/app/log_visit/log_visit.html',
controller: 'logVisitController',
resolve: {
Expand Down
6 changes: 5 additions & 1 deletion resource-bundles/Angular.resource/app/client/address.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@
<input type="text" class="form-control" name="address" placeholder="0000 Main St"
ng-maxlength="50" ng-model="data.addressData.address" ng-disabled="data.addressData.homeless">
</div>
<div class="form-group col-sm-4 text-right">
<div class="form-group col-sm-4 text-left">
<input type="checkbox" name="homeless" ng-model="data.addressData.homeless"></input>&nbsp;
<label>Homeless</label>
</div>
<div class="form-group col-sm-4 text-left">
<input type="checkbox" name="outofarea" ng-model="data.addressData.outofarea"></input>&nbsp;
<label>Out of Area</label>
</div>
<div class="form-group col-sm-6">
<label>City</label>
<input type="text" class="form-control" name="city" placeholder="Anytown"
Expand Down
108 changes: 58 additions & 50 deletions resource-bundles/Angular.resource/app/client/available.html
Original file line number Diff line number Diff line change
@@ -1,52 +1,60 @@
<div class="panel panel-default">
<div class="panel-heading">
Available This Month
</div>
<div class="panel-body" ng-show="data.household">
<div ng-if="settings.general.trackPoints" style="margin-bottom:24px;">
<p><b>Food Bank Points</b></p>
<div class="progress" ng-show="data.ptsRemaining > 0 && data.ratio >= 25">
<div class="progress-bar progress-bar-success"
role="progressbar" aria-valuenow="{{data.ratio}}" aria-valuemin="0" aria-valuemax="100"
style="width: {{data.ratio}}%;">
<span class="sr-only" style="position:static;">
{{data.ptsRemaining}} / {{data.ptsMonthly}}
</span>
</div>
</div>
<div class="progress" ng-show="data.ptsRemaining > 0 && data.ratio < 25">
<div class="progress-bar progress-bar-warning"
role="progressbar" aria-valuenow="{{data.ratio}}" aria-valuemin="0" aria-valuemax="100"
style="width: {{data.ratio}}%;">
<span class="sr-only" style="position:static;">
{{data.ptsRemaining}}
</span>
</div>
</div>
<div class="progress" ng-show="data.ptsRemaining == 0">
<div class="progress-bar progress-bar-danger"
role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"
style="width: 100%;">
<span class="sr-only" style="position:static;">0 / {{data.ptsMonthly}}</span>
</div>
</div>
<div class="col-md-12" id="checkInBox">
<form name="visitForm">
<div class="panel panel-info">
<div class="panel-body">
<div class="row">
<div class="col-md-5">
<div class="panel panel-default">
<div class="panel-heading">
Visit Notes
</div>
<div class="panel-body" ng-show="data.household">
<textarea class="form-control" style="height:7em;" ng-model="data.visitNotes"></textarea>
</div>
</div>
</div>
<div class="col-md-7" ng-if="data.commodities">
<div class="panel panel-default">
<div class="panel-heading">Commodities</div>
<div class="panel-body" ng-show="data.household">
<table ng-if="data.commodities" class="table table-condensed" style="margin-top:6px;">
<thead>
<tr>
<th>Item</th>
<th class="text-center">Available</th>
<th class="text-center">Monthly Limit</th>
<th>Used Today</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="comm in data.commodities"
ng-class="{danger: !comm.remaining, warning: (comm.remaining > 0 && comm.remaining < comm.monthlyLimit)}"
ng-form="commForm">

<td>{{comm.name}}</td>
<td class="text-center">{{comm.remaining}}</td>
<td class="text-center">{{comm.monthlyLimit}}</td>
<td>
<div ng-class="{ 'input-group': true, 'input-group-sm': true, 'has-error': commForm.ptsUsed.$invalid }">
<input class="form-control input-sm" type="number"
ng-model="comm.ptsUsed" min="0" max="{{comm.remaining}}" name="ptsUsed"
required="required" style="width:50px" ></input>
<span ng-show="commForm.ptsUsed.$error.required" class="help-block">Enter a number</span>
<span ng-show="commForm.ptsUsed.$error.min" class="help-block">Cannot be negative</span>
<span ng-show="commForm.ptsUsed.$error.max" class="help-block">Only {{comm.remaining}} available</span>
<!--<select class="form-control" ng-model="comm.ptsUsed"
ng-options="v for v in rangeFromZeroTo(comm.remaining)" style="height:30px;" ng-disabled="!comm.remaining"></select> -->
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<table ng-if="data.commodities" class="table table-condensed" style="margin-top:6px;">
<thead>
<tr>
<th>Item</th>
<th class="text-center">Available</th>
<th class="text-center">Monthly Limit</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="comm in data.commodities"
ng-class="{danger: !comm.remaining, warning: (comm.remaining > 0 && comm.remaining < comm.monthlyLimit) }">
<td>{{comm.name}}</td>
<td class="text-center">{{comm.remaining}}</td>
<td class="text-center">{{comm.monthlyLimit}}</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>

10 changes: 6 additions & 4 deletions resource-bundles/Angular.resource/app/client/client.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ <h3 style="margin-top:8px;">{{data.household.name}}</h3>
<div class="panel-btnbar text-center" ng-show="data.household">
<a ng-if="settings.general.checkInRequired" class="btn btn-primary" ng-click="checkIn()" ng-disabled="status.loading || (data.ptsRemaining == 0)">Check In</a>
<a class="btn btn-success" ng-click="recordVisit()" ng-disabled="status.loading || (data.ptsRemaining == 0)">Record Visit</a>
<a class="btn btn-info" ng-click="fullView()">Full View...</a>
<a class="btn btn-info" ng-click="scheduleAppointment()">Schedule...</a>
<a class="btn btn-default" ng-click="cancelEdit()">Cancel</a>
</div>
<div class="panel-body" ng-show="data.household">
Expand All @@ -31,21 +33,21 @@ <h3 style="margin-top:8px;">{{data.household.name}}</h3>
{{visitorWarningMsg()}}
</div>
</div>
<div class="col-md-7">
<div class="col-lg-8">
<div ng-include="basePath + '/app/client/address.html'"></div>
<div ng-include="basePath + '/app/client/members.html'"></div>
<div ng-include="basePath + '/app/client/notes.html'" ng-if="data.commodities || settings.general.trackPoints"></div>
<div ng-include="basePath + '/app/client/history.html'"></div>
</div>
<div class="col-md-5">
<div ng-include="basePath + '/app/client/tags.html'" ng-if="settings.tags"></div>
<div ng-include="basePath + '/app/client/available.html'" ng-if="data.commodities || settings.general.trackPoints"></div>
<div ng-include="basePath + '/app/client/notes.html'" ng-if="!(data.commodities || settings.general.trackPoints)"></div>
</div>
</div>
<div class="panel-footer text-center" ng-show="data.household">
<a ng-if="settings.general.checkInRequired" class="btn btn-primary" ng-click="checkIn()" ng-disabled="status.loading || (data.ptsRemaining == 0)">Check In</a>
<a class="btn btn-success" ng-href="#/log_visit/{{data.household.id}}" ng-disabled="status.loading || (data.ptsRemaining == 0)">Record Visit</a>
<a class="btn btn-success" ng-href="#/log_visit/{{data.household.id}}/{{contactid}}" ng-disabled="status.loading || (data.ptsRemaining == 0)">Record Visit</a>
<a class="btn btn-info" ng-click="fullView()">Full View...</a>
<a class="btn btn-info" ng-click="scheduleAppointment()">Schedule...</a>
<a class="btn btn-default" ng-click="cancelEdit()">Cancel</a>
</div>
</div>
Expand Down
71 changes: 55 additions & 16 deletions resource-bundles/Angular.resource/app/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
/*global _*/
/*global moment*/

Object.defineProperties(Date, {
MIN_VALUE: {
value: -8640000000000000 // A number, not a date
},
MAX_VALUE: {
value: 8640000000000000
},
MIN_BIRTHDATE: {
value: new Date("1/1/1800").getTime()
}
});

/* Controllers for client view page */

angular.module('clientController', [
Expand All @@ -16,20 +28,24 @@ angular.module('clientController')
function($scope, $location, $timeout, $window, $routeParams, $alert, $q, foundSettings, foundHousehold,
fbHouseholdDetail, fbSaveHousehold, fbSaveHouseholdMembers, fbSaveHouseholdAndMembers, fbCheckIn, fbVisitHistory) {

$scope.contactid = $routeParams.clientContactId;

$scope.settings = foundSettings;

$scope.data = {};
$scope.data.household = foundHousehold;

$scope.status = {};
$scope.commodities = [];
$scope.data.commodities = foundSettings.commodities;

if ($scope.settings.general.trackPoints) {
$scope.data.ptsRemaining = foundHousehold.currentPointsRemaining;
$scope.data.ptsMonthly = foundHousehold.monthlyPointsAvailable;
$scope.data.ratio = Math.floor(foundHousehold.currentPointsRemaining * 100 / foundHousehold.monthlyPointsAvailable);
}

$scope.data.visitNotes = '';

$scope.data.boxType = foundHousehold.defaultBox;
if (foundHousehold.commodityAvailability && foundHousehold.commodityAvailability.length > 0) {
$scope.data.commodities = foundHousehold.commodityAvailability;
Expand Down Expand Up @@ -60,7 +76,9 @@ angular.module('clientController')
$scope.visitorWarningMsg = function() {
if (!$scope.data.household.mostRecentVisitDate) {
return;
} else if (foundSettings.general.visitFrequencyLimit.toUpperCase() === 'WEEKLY') {
} else if (typeof foundSettings.general.visitFrequencyLimit == 'undefined') {
return;
}else if (foundSettings.general.visitFrequencyLimit.toUpperCase() === 'WEEKLY') {
//we assume weekly means a visit once per calendar week, with the week starting on Sunday
//first determine the day of th week of today
if (moment().week() === moment($scope.data.household.mostRecentVisitDate).week() &&
Expand Down Expand Up @@ -198,8 +216,17 @@ angular.module('clientController')
};

$scope.checkIn = function() {

// gather the commodity usage for this visit
var comms = {};
_.forEach( $scope.data.commodities, function(v) {
if (v.ptsUsed > 0) {
comms[v.name] = v.ptsUsed;
}
});

$scope.saveAll().then(function() {
fbCheckIn($scope.data.household.id);
fbCheckIn($scope.data.household.id, $scope.contactid, comms, $scope.data.visitNotes);
$window.scrollTo(0,0);
$alert({
title: 'Checked in!',
Expand All @@ -214,7 +241,7 @@ angular.module('clientController')

$scope.recordVisit = function() {
$scope.saveAll().then(function() {
$location.url('/log_visit/' + $scope.data.household.id);
$location.url('/log_visit/' + $scope.data.household.id + '/' + $scope.contactid);
});
};

Expand All @@ -228,6 +255,14 @@ angular.module('clientController')
$scope.cancelEdit = function() {
$location.url('/'); // might want to go somewhere based on routing param
};

$scope.fullView = function () {
$window.open('/one/one.app#/sObject/' + $scope.data.household.id, '_blank');
};

$scope.scheduleAppointment = function () {
$window.open('/flow/C501_Appointment_Schedule?varInputContactId=' + $scope.contactid, '_blank');
};

$scope.queryVisits = function() {
if (!$scope.status.queriedVisits) {
Expand Down Expand Up @@ -272,6 +307,7 @@ angular.module('clientController')
postalCode: $scope.data.household.postalCode,
phone: $scope.data.household.phone,
homeless: $scope.data.household.homeless,
outofarea: $scope.data.household.outofarea,
proofOfAddress: $scope.data.household.proofOfAddress
};
$scope.status.editingAddress = true;
Expand Down Expand Up @@ -411,6 +447,20 @@ angular.module('clientController')
$scope.status.editingMembers = false;
$scope.status.savingMembers = false;

$scope.checkBirthdate = function (date) {

try {
if (date.getTime() <= Date.MIN_BIRTHDATE) {
return null;
}
}
catch(err) {
return null;
}

return date;
};

$scope.editMembers = function() {
_.forEach($scope.data.memberList, function(v) {
v.memberDataEditable = v.memberData;
Expand Down Expand Up @@ -452,15 +502,4 @@ angular.module('clientController')
$scope.cancelMembers = function() {
$scope.status.editingMembers = false;
};
}]);

angular.module('clientController')
.controller('datepickerCtrl', ['$scope', function($scope) {

$scope.openCal = function($event) {
$scope.status.calOpen = !$scope.status.calOpen;
$event.preventDefault();
$event.stopPropagation();
};

}]);
}]);
Loading

0 comments on commit 6eddf84

Please sign in to comment.