This commit is contained in:
Daniel Camargo 2014-05-13 16:13:32 -03:00
parent b03a48d6a0
commit 58753b09f0
12 changed files with 412 additions and 136 deletions

View File

@ -0,0 +1,96 @@
<?php
class Controller_api_driveronboarding extends Crunchbutton_Controller_RestAccount {
public function init() {
$action = c::getPagePiece( 2 );
switch ( $action ) {
case 'save':
$this->_save();
break;
case 'driver':
$this->_driver();
break;
default:
$this->_list();
break;
}
}
private function _driver(){
$id_admin = c::getPagePiece( 3 );
$driver = new Crunchbutton_Admin( $id_admin );
if( $driver->id_admin ){
echo json_encode( $driver->exports() );
} else {
$this->_error( 'invalid object' );
}
}
private function _list(){
$drivers = Crunchbutton_Admin::drivers();
$list = [];
foreach( $drivers as $driver ){
$list[] = $driver->exports();
}
echo json_encode( $list );
}
private function _save(){
if( $this->method() != 'post' ){
$this->_error();
}
$id_admin = c::getPagePiece( 3 );
// saves a new driver
if( !$id_admin ){
$driver = new Crunchbutton_Admin();
// create the new driver as inactive
$driver->active = 0;
} else {
$driver = Crunchbutton_Admin::o( $id_admin );
}
$driver->name = $this->request()[ 'name' ];
$driver->phone = $this->request()[ 'phone' ];
$driver->email = $this->request()[ 'email' ];
$driver->save();
// add the community
$id_community = $this->request()[ 'id_community' ];
// first remove the driver from the delivery groups
$_communities = Crunchbutton_Community::q( 'SELECT * FROM community ORDER BY name ASC' );;
foreach( $_communities as $community ){
$group = $community->groupOfDrivers();
if( $group->id_group ){
$driver->removeGroup( $group->id_group );
}
}
if( $id_community ){
$community = Crunchbutton_Community::o( $id_community );
if( $community->id_community ){
$group = $community->groupOfDrivers();
$adminGroup = new Crunchbutton_Admin_Group();
$adminGroup->id_admin = $driver->id_admin;
$adminGroup->id_group = $group->id_group;
$adminGroup->save();
}
}
echo json_encode( [ 'success' => $driver->exports() ] );
return;
}
private function _error( $error = 'invalid request' ){
echo json_encode( [ 'error' => $error ] );
exit();
}
}

View File

@ -475,12 +475,20 @@ class Crunchbutton_Admin extends Cana_Table {
public function exports() {
$permissions = [];
$groups = [];
$communities = [];
if( $this->groups() ){
foreach ($this->groups() as $group) {
$groups[$group->id_group] = $group->name;
}
}
if( $this->communitiesHeDeliveriesFor() ){
foreach( $this->communitiesHeDeliveriesFor() as $community ){
$communities[ $community->id_community ] = $community->name;
}
}
if ($this->permission()->_permissions) {
foreach ($this->permission()->_permissions as $group => $perms) {
foreach ($perms as $key => $value) {
@ -511,7 +519,8 @@ class Crunchbutton_Admin extends Cana_Table {
'timezone' => $this->timezone,
'testphone' => $this->testphone,
'permissions' => $permissions,
'groups' => $groups
'groups' => $groups,
'communities' => $communities
];
return $ex;
}

View File

@ -34,7 +34,6 @@
<!-- AngularJS Filters -->
<script src="/assets/js/filters.js?v=<?=Cana_Util::gitVersion()?>"></script>
<!-- AngularJS Directives -->
<script src="/assets/js/directives.js?v=<?=Cana_Util::gitVersion()?>"></script>

View File

@ -1,56 +1,56 @@
<div class="top-pad"></div>
<div class="content-padding" ng-show="ready">
<div class="content">
<ul class="tab-options">
<li ng-click="tab.change(1);" ng-class="{ 'tab-active' : tab.step == 1 }">
step 1
</li>
<li ng-click="tab.change(2);" ng-class="{ 'tab-active' : tab.step == 2 }">
step 2
</li>
<li ng-click="tab.change(3);" ng-class="{ 'tab-active' : tab.step == 3 }">
step 3
</li>
</ul>
<ul class="tab-content">
<li ng-show="tab.step == 1">
<ul>
<h1 ng-if="!driver.id_admin">New driver</h1>
<h1 ng-if="driver.id_admin">Edit driver</h1>
<form name="form" novalidate>
<ul class="form" ng-class="{'submitted' : submitted}">
<li>
<label for="driver-name">
<div class="label">Name:</div>
<div class="input"><input type="text" name="driver-name" ng-model="driver.name" placeholder="Name"></div>
<div class="input"><input type="text" name="driverName" ng-model="driver.name" required placeholder="Name" ng-minlength="5" ng-maxlength="40" ></div>
</label>
<div class="error" ng-show="submitted && form.driverName.$invalid">
<small class="error" ng-show="form.driverName.$error.required">Required.</small>
<small class="error" ng-show="form.driverName.$error.minlength">Name is too short. Name is required to be at least 5 characters.</small>
<small class="error" ng-show="form.driverName.$error.maxlength">Name cannot be longer than 40 characters.</small>
</div>
</li>
<li>
<label for="driver-phone">
<div class="label">Phone:</div>
<div class="input"><input type="tel" phone="driver-phone" ng-model="driver.phone" placeholder="Phone"></div>
<div class="input"><input type="text" name="driverPhone" ng-model="driver.phone" required phone-validate placeholder="Phone"></div>
</label>
<div class="error" ng-show="submitted && form.driverPhone.$invalid">
<small class="error" ng-show="form.driverPhone.$error.required">Required.</small>
<small class="error" ng-show="form.driverPhone.$error.phoneValidate">Enter a valid phone.</small>
</div>
</li>
<li>
<label for="driver-community">
<div class="label">Community:</div>
<select ng-model="driver.id_community" ng-options="opt.id_community as opt.name for opt in communities" class="cart-customize-select"></select>
<select name="driverIdCommunity" required ng-model="driver.id_community" ng-options="opt.id_community as opt.name for opt in communities" class="cart-customize-select"></select>
</label>
<div class="error" ng-show="submitted && form.driverIdCommunity.$invalid">
<small class="error" ng-show="form.driverIdCommunity.$error.required">Required.</small>
</div>
</li>
<li>
<label for="driver-email">
<div class="label">email:</div>
<div class="input"><input type="email" email="driver-email" ng-model="driver.email" placeholder="Email"></div>
<div class="input"><input type="email" name="driverEmail" ng-model="driver.email" placeholder="Email"></div>
</label>
<div class="error" ng-show="submitted && form.driverEmail.$invalid">
<small class="error" ng-show="form.driverEmail.$invalid">Enter a valid email.</small>
</div>
</li>
</ul>
</li>
<li ng-show="tab.step == 2">
step 2
</li>
<li ng-show="tab.step == 3">
step 3
</li>
</ul>
<li class="buttons">
<button ng-click="save();">Save</button>
<button ng-click="cancel()">Cancel</button>
</li>
</ul>
</form>
</div>
</div>

View File

@ -0,0 +1,21 @@
<div class="top-pad"></div>
<div class="content-padding" ng-show="ready">
<table>
<thead>
<tr>
<td>Name</td>
<td></td>
</tr>
</thead>
<tbody>
<tr ng-repeat="driver in drivers">
<td>{{driver.name}}</td>
<td>
<button ng-click="edit(driver.id_admin)">edit</button>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -1,5 +0,0 @@
<div class="top-pad"></div>
ready: {{ready}}
<div class="content-padding" ng-show="ready">
oi
</div>

View File

@ -114,6 +114,11 @@
<div title="Back" class="nav-back hide-before-init" ng-click="back()" ng-show="hasBack"></div>
<div class="notifications">
<div class="flash-message {{flash.getLevel()}}" ng-show="flash.hasMessage()">
<p>{{flash.getMessage()}}</p>
</div>
<div class="notification notification-orders" ng-click="navigation.link('/drivers/orders')">
<div class="badge" ng-show="newDriverOrders.count">{{newDriverOrders.count}}</div>
<i class="fa fa-truck"></i>

View File

@ -33,7 +33,7 @@ App.NGinit = function() {
}
};
var NGApp = angular.module('NGApp', [ 'ngRoute', 'ngResource'], function( $httpProvider ) {
var NGApp = angular.module('NGApp', [ 'ngRoute', 'ngResource' ], function( $httpProvider ) {
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
var param = function(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
@ -102,11 +102,16 @@ NGApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $l
.when('/drivers/onboarding/', {
action: 'drivers-onboarding',
controller: 'DriversOnboardingCtrl',
templateUrl: 'assets/view/drivers-onboarding.html'
templateUrl: 'assets/view/drivers-onboarding-list.html'
})
.when('/drivers/onboarding/new', {
action: 'drivers-onboarding',
controller: 'DriversOnboardingNewCtrl',
controller: 'DriversOnboardingDetailsCtrl',
templateUrl: 'assets/view/drivers-onboarding-detail.html'
})
.when('/drivers/onboarding/:id', {
action: 'drivers-onboarding',
controller: 'DriversOnboardingDetailsCtrl',
templateUrl: 'assets/view/drivers-onboarding-detail.html'
})
.otherwise({
@ -119,7 +124,7 @@ NGApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $l
}]);
// global route change items
NGApp.controller('AppController', function ($scope, $route, $http, $routeParams, $rootScope, $location, $window, $timeout, MainNavigationService, AccountService, DriverOrdersService ) {
NGApp.controller('AppController', function ($scope, $route, $http, $routeParams, $rootScope, $location, $window, $timeout, MainNavigationService, AccountService, DriverOrdersService, flash ) {
// define external pointers
App.rootScope = $rootScope;
@ -127,6 +132,7 @@ NGApp.controller('AppController', function ($scope, $route, $http, $routeParams,
App.http = $http;
// define global services
$rootScope.flash = flash;
$rootScope.navigation = MainNavigationService;
$rootScope.isPhoneGap = App.isPhoneGap;
$rootScope.server = App.server;
@ -514,3 +520,43 @@ App.dialog = {
return $.magnificPopup && $.magnificPopup.instance && $.magnificPopup.instance.isOpen;
}
};
// Service to show a flash message
NGApp.factory( 'flash', function( $timeout ) {
var message = [];
// $rootScope.$on('$routeChangeSuccess', function() {
// clearMessage();
// } );
var clearMessage = function(){
message = false;
}
service = {};
service.setMessage = function( text, level ){
var level = ( level ) ? level : 'success';
message = { level : level, text : text };
$timeout( function() { clearMessage() }, 5 * 1000 );
}
service.hasMessage = function(){
return message != false;
}
service.getLevel = function(){
if( service.hasMessage() ){
return message.level;
}
}
service.getMessage = function(){
if( service.hasMessage() ){
return message.text;
}
}
return service;
} );

View File

@ -140,22 +140,50 @@ NGApp.controller( 'DriversShiftsCtrl', function ( $scope, DriverShiftsService )
NGApp.controller( 'DriversOnboardingCtrl', function ( $scope, DriverOnboardingService ) {
$scope.ready = false;
});
NGApp.controller( 'DriversOnboardingNewCtrl', function ( $scope, DriverOnboardingService, CommunityService ) {
$scope.tab = { step : 1 };
$scope.tab.change = function( step ){
$scope.tab.step = step;
}
$scope.ready = true;
$scope.communities = [];
// Load the communities and put them at scope
CommunityService.listSimple( function( data ){
$scope.communities = data;
DriverOnboardingService.list( function( data ){
$scope.drivers = data;
$scope.ready = true;
} );
$scope.edit = function( id_admin ){
$scope.navigation.link( '/drivers/onboarding/' + id_admin );
}
} );
NGApp.controller( 'DriversOnboardingDetailsCtrl', function ( $scope, DriverOnboardingService, CommunityService ) {
$scope.ready = false;
$scope.submitted = false;
DriverOnboardingService.get( function( driver ){
$scope.driver = driver;
// Load the communities and put them at scope
$scope.communities = [];
CommunityService.listSimple( function( data ){
$scope.communities = data;
$scope.ready = true;
} );
} );
// method save that saves the driver
$scope.save = function(){
if( $scope.form.$invalid ){
$scope.submitted = true;
return;
}
DriverOnboardingService.save( $scope.driver, function(){
$scope.navigation.link( '/drivers/onboarding/' );
$scope.flash.setMessage( 'Driver saved!' );
} );
}
$scope.cancel = function(){
$scope.navigation.link( '/drivers/onboarding/' );
}
} );

View File

@ -2,35 +2,40 @@ NGApp.factory( 'DriverOnboardingService', function( $rootScope, $resource, $rout
var service = {};
// Create a private resource 'orders'
var orders = $resource( App.service + 'driveronboarding/:action/:id_driver', { id_driver: '@id_driver', action: '@action' }, {
// Create a private resource 'drivers'
var drivers = $resource( App.service + 'driveronboarding/:action/:id_admin', { id_admin: '@id_admin', action: '@action' }, {
// actions
'get' : { 'method': 'GET', params : { 'action' : 'list', 'id' : 0 } },
'add' : { 'method': 'POST', params : { 'action' : 'delivery-accept' } },
'get' : { 'method': 'GET', params : { 'action' : 'driver' } },
'list' : { 'method': 'GET', params : { action: 'list', id_admin: null } },
'save' : { 'method': 'POST', params : { action: 'save' } }
}
);
service.save = function( driver, callback ){
drivers.save( driver, function( driver ){
callback( driver );
} );
}
service.list = function( callback ){
orders.query( {}, function( data ){
var orders = [];
for( var x in data ){
var order = data[ x ];
if( order && order.date && order.date.date ){
order._date = new Date( order.date.date );
orders.push( order );
}
}
service.newOrdersBadge();
callback( orders );
drivers.query( {}, function( drivers ){
callback( drivers );
} );
}
service.get = function( callback ){
var id_driver = $routeParams.id;
orders.get( { 'id_driver': id_driver }, function( order ){
order._date = new Date( order.date );
callback( order );
} );
var id_admin = $routeParams.id;
if( id_admin && id_admin != 'new' ){
drivers.get( { 'id_admin': id_admin }, function( driver ){
if( driver.communities ){
angular.forEach( driver.communities, function( name, id_community ){
driver.id_community = id_community;
} );
}
callback( driver );
} );
}
}
return service;

View File

@ -84,10 +84,10 @@ input[type="submit"]::-moz-focus-inner, input[type="button"]::-moz-focus-inner,
html {
-webkit-text-size-adjust: none;
-moz-text-size-adjust: none;
-ms-text-size-adjust: none;
-o-text-size-adjust: none;
text-size-adjust: none;
-moz-text-size-adjust: none;
-ms-text-size-adjust: none;
-o-text-size-adjust: none;
text-size-adjust: none;
}
* {
@ -113,10 +113,10 @@ html {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
}
@ -204,6 +204,19 @@ p {
}
/* INPUTS */
.form input, .form select, .form textarea{
font-size:1.2em;
border:1px solid #CCC;
width: 30em
}
.form.submitted .ng-invalid{
border:1px solid red;
}
.form .error{
color: red;
margin:3px;
}
/* GLOBAL */
@ -213,10 +226,10 @@ p {
}
.menu{
-webkit-transition: opacity 0.1s;
-moz-transition: opacity 0.1s;
-ms-transition: opacity 0.1s;
-o-transition: opacity 0.1s;
transition: opacity 0.1s;
-moz-transition: opacity 0.1s;
-ms-transition: opacity 0.1s;
-o-transition: opacity 0.1s;
transition: opacity 0.1s;
}
}
@media(max-width: 768px) {
@ -288,10 +301,10 @@ p {
overflow-x:hidden;
-webkit-overflow-scrolling: touch;
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
.snap-content {
position:absolute;
@ -316,15 +329,15 @@ p {
overflow-x:hidden;
-webkit-overflow-scrolling: touch;
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-transition: width 0.3s ease;
-moz-transition: width 0.3s ease;
-ms-transition: width 0.3s ease;
-o-transition: width 0.3s ease;
transition: width 0.3s ease;
-moz-transition: width 0.3s ease;
-ms-transition: width 0.3s ease;
-o-transition: width 0.3s ease;
transition: width 0.3s ease;
}
.snap-drawers {
@ -561,23 +574,23 @@ input {
width: 100%;
-webkit-transition: background linear 0.08s;
-moz-transition: background linear 0.08s;
-ms-transition: background linear 0.08s;
-o-transition: background linear 0.08s;
transition: background linear 0.08s;
-moz-transition: background linear 0.08s;
-ms-transition: background linear 0.08s;
-o-transition: background linear 0.08s;
transition: background linear 0.08s;
}
.button.ani-all {
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-transition: all linear 0.08s;
-moz-transition: all linear 0.08s;
-ms-transition: all linear 0.08s;
-o-transition: all linear 0.08s;
transition: all linear 0.08s;
-moz-transition: all linear 0.08s;
-ms-transition: all linear 0.08s;
-o-transition: all linear 0.08s;
transition: all linear 0.08s;
}
/* colors */
@ -693,6 +706,7 @@ input {
overflow: hidden;
}
/* drivers order list page */
.last-updated{
font-size: 1em;
@ -988,10 +1002,10 @@ input {
overflow: hidden;
-webkit-transition: background .2s;
-moz-transition: background .2s;
-ms-transition: background .2s;
-o-transition: background .2s;
transition: background .2s;
-moz-transition: background .2s;
-ms-transition: background .2s;
-o-transition: background .2s;
transition: background .2s;
}
.wrap {
@ -1022,10 +1036,10 @@ input {
overflow: hidden;
-webkit-transition: background .2s;
-moz-transition: background .2s;
-ms-transition: background .2s;
-o-transition: background .2s;
transition: background .2s;
-moz-transition: background .2s;
-ms-transition: background .2s;
-o-transition: background .2s;
transition: background .2s;
}
.loader-frame {
@ -1041,16 +1055,16 @@ input {
-webkit-transform:translate3d(0,0,0);
-webkit-transform: scale(3);
-moz-transform: scale(3);
-ms-transform: scale(3);
-o-transform: scale(3);
transform: scale(3);
-moz-transform: scale(3);
-ms-transform: scale(3);
-o-transform: scale(3);
transform: scale(3);
-webkit-transition: all .1s;
-moz-transition: all .1s;
-ms-transition: all .1s;
-o-transition: all .1s;
transition: all .1s;
-moz-transition: all .1s;
-ms-transition: all .1s;
-o-transition: all .1s;
transition: all .1s;
}
.loader {
opacity: 1;
@ -1065,10 +1079,10 @@ body.loading {
}
body.loading .loader-frame {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
opacity: 1;
}
@ -1123,4 +1137,22 @@ strong{ font-weight: bold; }
}
.mfp-close {
display: none !important;
}
}
.flash-message {
position: fixed;
font-size: 1em;
padding: 5px 15px;
display: inline-block;
text-align: center;
width: 20em;
top: .5em;
left: 50%;
margin-left: -100px;
border-radius: 5px;
}
.flash-message.success{
background:#dff0d8;
color: #64763d;
border:1px solid #d6e9c6;
}

View File

@ -443,7 +443,7 @@ NGApp.directive( 'modalReset', function( $rootScope ) {
NGApp.directive( 'geoComplete', function() {
return {
restrict: 'A',
scope: { ngModel : '=', geoCompleteEnter : '&' },
scope: { ngModel : '=', geoCompleteEnter : '&' },
link: function( scope, element, attrs ) {
var el = document.getElementById( attrs.id );
if( typeof google == 'object' && google.maps && google.maps.places && google.maps.places.Autocomplete ){
@ -462,4 +462,44 @@ NGApp.directive( 'geoComplete', function() {
}
}
};
});
NGApp.directive( 'phoneValidate', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function ( scope, elm, attrs, ctrl ) {
ctrl.$parsers.unshift( function ( val ) {
var isValid = false;
var phoneVal = val.replace( /[^0-9]/g, '' );
if ( phoneVal || phoneVal.length == 10) {
var phoneVal = phoneVal.split(''), prev;
for (x in phoneVal) {
if (!prev) {
prev = phoneVal[x];
continue;
}
if (phoneVal[x] != prev) {
isValid = true;
}
}
}
if( !isValid ){
ctrl.$setValidity( 'phoneValidate', false );
return undefined;
} else {
ctrl.$setValidity( 'phoneValidate', true );
return val;
}
} );
}
};
});