--- /dev/null
+<?php
+
+/**
+ * Gaslight Media Members Database
+ * Edit Registration Levels & Charges (rates)
+ *
+ * PHP version 5.5
+ *
+ * @category glmWordPressPlugin
+ * @package glmMembersDatabase
+ * @author Chuck Scott <cscott@gaslightmedia.com>
+ * @license http://www.gaslightmedia.com Gaslightmedia
+ * @version 0.1
+ */
+
+// Load Members data abstract
+//require_once GLM_MEMBERS_REGISTRATIONS_PLUGIN_CLASS_PATH . '/data/dataAccount.php';
+
+/**
+ * This class performs the work of handling images passed to it via
+ * an AJAX call that goes through the WorPress AJAX Handler.
+ *
+ */
+class GlmMembersAdmin_ajax_levelsAndRatesEdit // extends GlmDataRegistrationsAccount
+{
+
+ /**
+ * WordPress Database Object
+ *
+ * @var $wpdb
+ * @access public
+ */
+ public $wpdb;
+ /**
+ * Plugin Configuration Data
+ *
+ * @var $config
+ * @access public
+ */
+ public $config;
+ /**
+ * Required input not provided flag
+ *
+ * @var $requiredNotProvided
+ * @access public
+ */
+ public $requiredNotProvided = false;
+
+ /*
+ * Constructor
+ *
+ * This contructor sets up this model. At this time that only includes
+ * storing away the WordPress data object.
+ *
+ * @return object Class object
+ *
+ */
+ public function __construct ($wpdb, $config)
+ {
+
+ // Save WordPress Database object
+ $this->wpdb = $wpdb;
+
+ // Save plugin configuration object
+ $this->config = $config;
+
+ // Run constructor for data class
+// parent::__construct(false, false);
+
+ }
+
+ /*
+ * Perform Model Action
+ *
+ * This model checks to see if the creditials passed in are correct.
+ *
+ * This model action does not return, it simply does it's work then calls die();
+ *
+ * @param $actionData
+ *
+ * Echos JSON string as response and does not return
+ */
+ public function modelAction( $actionData = false )
+ {
+ // Setup response array
+ $response = array(
+ 'status' => false,
+ 'msg' => false
+ );
+
+ $option = filter_var( $_REQUEST['option'], FILTER_SANITIZE_STRING );
+
+ switch ( $option ) {
+
+ case 'sortLevels':
+
+ // Fields should be in correct order in the submitted array and keys should be sequential from 0
+ foreach ($_REQUEST['sortedIds'] as $sortKey=>$sortVal) {
+
+ // Strip "field_" from field ID number
+ $fieldId = preg_replace("/[^0-9]/", "", $sortVal);
+
+ // Update the field with the key as the order field
+ $res = $this->wpdb->update(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_class',
+ array( 'sort_order' => $sortKey ),
+ array( 'id' => $fieldId ),
+ array( '%d' ),
+ array( '%d' )
+ );
+
+ if ($res !== false) {
+ $response['status'] = true;
+ } else {
+ $response['msg'] = $this->wpdb->last_error;
+ }
+ }
+
+ break;
+
+ case 'addLevel':
+ case 'updateLevel':
+
+ $request = filter_input_array(
+ INPUT_POST,
+ array(
+ 'eventId' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ ),
+ 'levelId' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ ),
+ 'name' => FILTER_SANITIZE_STRING,
+ 'descr' => FILTER_SANITIZE_STRING,
+ 'sort_order'=> array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ )
+ )
+ );
+
+ $msg = '';
+
+ if ($option == 'addLevel') {
+ if ($request['eventId'] === false) {$msg .= "* Required Event ID not a positive integer.<br>";}
+ } else {
+ if ($request['levelId'] === false) {$msg .= "* Required Level ID not a positive integer.<br>";}
+ }
+
+ if (trim($request['name']) == '') {$msg .= "* Level Name not provided<br>";}
+ if (trim($request['descr']) == '') {$msg .= "* Description not provided<br>";}
+
+ if ($msg != '') {
+ $response['msg'] = 'Please check the following...<p style="text-align: left;">'.$msg."</p>";
+ } else {
+
+ // If we have good data
+ if ($request && isset($request['eventId']) && ($request['eventId']-0) > 0) {
+
+ if ($option == 'addLevel') {
+
+ // Add the new level
+ $res = $this->wpdb->insert(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_class',
+ array(
+ 'reg_event' => $request['eventId'],
+ 'name' => $request['name'],
+ 'descr' => $request['descr'],
+ 'sort_order' => $request['sort_order']
+ ),
+ array(
+ '%d',
+ '%s',
+ '%s',
+ '%d'
+ )
+ );
+
+ } else {
+
+ // Update level
+ $res = $this->wpdb->update(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_class',
+ array(
+ 'name' => $request['name'],
+ 'descr' => $request['descr'],
+ ),
+ array( 'id' => $request['levelId'] ),
+ array(
+ '%s',
+ '%s'
+ ),
+ array( '%d' )
+ );
+
+ }
+
+ // If no error
+ if ($res !== false) {
+ $response['status'] = true;
+ if ($option == 'addLevel') {
+ $response['levelId'] = $this->wpdb->insert_id;
+ }
+ $response = array_merge($request, $response); // Appends or replaces $response values into $request
+ } else {
+ $response['msg'] = $this->wpdb->last_error;
+ }
+
+ } else {
+ $response['msg'] = 'Add failed. Please check your data and try again.';
+ }
+
+ }
+
+ break;
+
+ case 'deleteLevel':
+
+ $levelId = filter_var( $_REQUEST['levelId'], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1)));
+
+ if ($levelId && ($levelId-0) > 0 ) {
+
+ // Delete all rates associated with this level
+ $this->wpdb->delete(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_rate',
+ array( 'reg_class' => $levelId )
+ );
+ $res = $this->wpdb->delete(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_class',
+ array( 'id' => $levelId )
+ );
+
+ // If no error
+ if ($res) {
+ $response['status'] = true;
+ } else {
+ $response['msg'] = $this->wpdb->last_error;
+ }
+
+ }
+
+ break;
+
+ case 'addRate':
+ case 'updateRate':
+
+ $request = filter_input_array(
+ INPUT_POST,
+ array(
+ 'eventId' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ ),
+ 'levelId' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ ),
+ 'rateId' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ ),
+ 'name' => FILTER_SANITIZE_STRING,
+ 'start_days' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 1)
+ ),
+ 'end_days' => array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 0)
+ ),
+ 'base_rate' => FILTER_VALIDATE_FLOAT, // Note that PHP filters don't validate range for float
+ 'per_registrant' => FILTER_VALIDATE_FLOAT,
+ 'registrant_credits'=> array(
+ 'filter' => FILTER_VALIDATE_INT,
+ 'options' => array('min_range' => 0)
+ )
+ )
+ );
+
+ // Sanity check all the values
+ $msg = '';
+
+ if ($option == 'addRate') {
+ if ($request['eventId'] === false) {$msg .= "* Required event ID not a positive integer.<br>";}
+ if ($request['levelId'] === false) {$msg .= "* Required registraion Level ID not a positive integer.<br>";}
+ } else {
+ if ($request['rateId'] === false) {$msg .= "* Required registraion Rate ID not a positive integer.<br>";}
+ }
+
+ if (trim($request['name']) == '') {$msg .= "* Rate Name not provided<br>";}
+ if ($request['start_days'] === false) {$msg .= "* Start Days must be greater than 0.<br>";}
+ if ($request['end_days'] === false) {$msg .= "* End Days must not be negative.<br>";}
+ if ($request['start_days'] < $request['end_days']) {$msg .= "* Start days must be greater (earlier) than end days.<br>";}
+ if ($request['base_rate'] < 0) {$msg .= "* Bate Rate must not be negative.<br>";}
+ if ($request['per_registrant'] < 0) {$msg .= "* Rate Per Registrant must not be negative.<br>";}
+ if ($request['registrant_credits'] === false) {$msg .= "* Required Registrant Credits must not be negative.<br>";}
+
+
+ if ($msg != '') {
+ $response['msg'] = 'Please check the following...<p style="text-align: left;">'.$msg."</p>";
+ } else {
+
+ // If we have good data
+ if ($request && isset($request['eventId']) && ($request['eventId']-0) > 0) {
+
+ if ($option == 'addRate') {
+
+ // Add the new rate
+ $res = $this->wpdb->insert(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_rate',
+ array(
+ 'reg_event' => $request['eventId'],
+ 'reg_class' => $request['levelId'],
+ 'name' => $request['name'],
+ 'start_days' => $request['start_days'],
+ 'end_days' => $request['end_days'],
+ 'base_rate' => $request['base_rate'],
+ 'per_registrant' => $request['per_registrant'],
+ 'registrant_credits' => $request['registrant_credits']
+ ),
+ array(
+ '%d', // Event ID
+ '%d', // Level ID
+ '%s', // Name
+ '%d', // Start Days
+ '%d', // End Days
+ '%d', // Base Rate
+ '%f', // Per Registrant
+ '%d' // Registrant Credits
+ )
+ );
+
+ } else {
+
+ // Update rate
+ $res = $this->wpdb->update(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_rate',
+ array(
+ 'name' => $request['name'],
+ 'start_days' => $request['start_days'],
+ 'end_days' => $request['end_days'],
+ 'base_rate' => $request['base_rate'],
+ 'per_registrant' => $request['per_registrant'],
+ 'registrant_credits' => $request['registrant_credits']
+ ),
+ array( 'id' => $request['rateId'] ),
+ array(
+ '%s', // Name
+ '%d', // Start Days
+ '%d', // End Days
+ '%f', // Base Rate
+ '%f', // Per Registrant
+ '%d' // Registrant Credits
+ ),
+ array( '%d' )
+ );
+
+ }
+
+ // If no error
+ if ($res !== false) {
+ $response['status'] = true;
+ if ($option == 'addRate') {
+ $response['rateId'] = $this->wpdb->insert_id;
+ }
+ $response = array_merge($request, $response); // Appends or replaces $response values into $request
+ } else {
+ $response['msg'] = $this->wpdb->last_error;
+ }
+
+ } else {
+ $response['msg'] = 'Add failed. Please check your data and try again.';
+ }
+
+ }
+
+ break;
+
+ case 'deleteRate':
+
+ $rateId = filter_var( $_REQUEST['rateId'], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1)));
+
+ if ($rateId && ($rateId-0) > 0 ) {
+
+ // Delete all rates associated with this level
+ $res = $this->wpdb->delete(
+ GLM_MEMBERS_REGISTRATIONS_PLUGIN_DB_PREFIX.'reg_rate',
+ array( 'id' => $rateId )
+ );
+
+ // If no error
+ if ($res !== false) {
+ $response['status'] = true;
+ } else {
+ $response['msg'] = $this->wpdb->last_error;
+ }
+
+ }
+
+ break;
+
+ }
+
+ if ($response) {
+ header('Content-type:application/json;charset=utf-8', true);
+ echo json_encode( $response );
+ }
+ wp_die();
+ }
+
+}
{include file='admin/registrations/eventHeader.html'}
{include file='admin/registrations/eventSubTabs.html'}
- <h1>
- {if $regEventUpdated}<span class="glm-notice glm-flash-updated">{$terms.reg_term_registration_cap} {$terms.reg_term_event_cap} Updated</span>{/if}
- {if $regEventUpdateError}<span class="glm-error glm-flash-updated">{$terms.reg_term_registration_cap} {$terms.reg_term_event_cap} Update Error</span>{/if}
- {if $regEventAdded}<span class="glm-notice glm-flash-updated">{$terms.reg_term_registration_cap} {$terms.reg_term_event_cap} Added</span>{/if}
- </h1>
-
- {* Event Registration App - Backbone.js *}
- {* Underscore Templates for the Event Registration App *}
-
- {literal}
-
- <script type="text/template" id="regEvent-template">
- <a id="class-add" class="button button-secondary glm-button glm-right">Add a {/literal}{$terms.reg_term_registration_cap}{literal} Level</a>
- <h1>{/literal}{$terms.reg_term_registration_cap}{literal} Levels & Charges</h1>
- </script>
-
- <script type="text/template" id="regClass-template">
- <div style="background-color: white; padding: .25rem; border: 1px solid black;">
- <div class="class-display-template">
- <div class="glm-class-header">
- <div class="glm-right">
- <a class="class-edit button button-secondary glm-button-small">Edit</a>
- <a class="class-delete button button-secondary glm-button-small">Delete</a>
- <a class="class-add-rate button button-secondary glm-button-small">Add Rate</a>
- </div>
- <div class="glm-class-label">
- <h3><%= name %></h3>
- </div>
- </div>
- <%= descr %>
- </div>
- <div class="class-edit-template" style="display: none;">
- <div class="glm-class-header">
- <div class="glm-right">
- <a class="class-cancel button glm-button-small">Cancel</a>
- <a class="class-update button glm-button-small-highlighted">Update</a>
- <a class="class-add button glm-button-small-highlighted" style="display: none;">Add</a>
- <a class="class-delete button button-secondary glm-button-small">Delete</a>
- </div>
- <div class="glm-class-label" style="padding-bottom: .3em;">
- <b>Level Name:</b> <input class="class-name" type="text" name="name_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (name) { %><%- name %><% } %>">
- </div>
- </div>
- <b>Description:</b> <input class="class-descr" type="text" name="reg_descr_<% if (id) { %><%- id %><% } else { %> new <% } %>" size="90" value="<% if (descr) { %><%- descr %><% } %>">
- </div>
- <div class="class-rate-container">
- </div>
+<h1>
+ {if $regEventUpdated}<span class="glm-notice glm-flash-updated">{$terms.reg_term_registration_cap} {$terms.reg_term_event_cap} Updated</span>{/if}
+ {if $regEventUpdateError}<span class="glm-error glm-flash-updated">{$terms.reg_term_registration_cap} {$terms.reg_term_event_cap} Update Error</span>{/if}
+ {if $regEventAdded}<span class="glm-notice glm-flash-updated">{$terms.reg_term_registration_cap} {$terms.reg_term_event_cap} Added</span>{/if}
+</h1>
+
+<a class="reg-level-add-button button button-secondary glm-button glm-right">Add a {$terms.reg_term_registration_cap} {$terms.reg_term_level_cap}</a>
+<h1>{$terms.reg_term_registration_cap} {$terms.reg_term_level_plur_cap} & Charges</h1>
+<p><b class="glm-notice">DRAG TO SORT:</b> The order in which {$terms.reg_term_level_plur} are displayed on the front-end is the same as the order they appear below. Drag a {$terms.reg_term_level} up or down to set the desired order.</p>
+
+<div id="regLevelsContainer" title="Drag me up or down to sort {$terms.reg_term_registration} {$terms.reg_term_level_plur}!">
+{if $regEvent.reg_class}
+ {foreach $regEvent.reg_class as $level}
+
+<!-- Registration Level -->
+<div id="regLevelContainer_{$level.id}" class="reg-level-container ">
+ <div id="regLevelDisplayContainer_{$level.id}" class="reg-level-display-container">
+ <div class="reg-level-header">
+ <div class="glm-right">
+ <a data-option="editLevel" data-id="{$level.id}" class="reg-level-edit-button button button-secondary glm-button-small">Edit</a>
+ <a data-option="deleteLevel" data-id="{$level.id}" class="reg-level-delete-button button button-secondary glm-button-small">Delete</a>
+ <a data-option="addRate" data-id="{$level.id}" class="reg-level-add-rate-button button button-secondary glm-button-small">Add Rate</a>
+ </div>
+ <div class="reg-level-label">
+ <h3 id="regLevelName_{$level.id}">{$level.name}</h3>
+ </div>
+ </div>
+ <div id="regLevelDescr_{$level.id}">{$level.descr}</div>
+ </div>
+ <div id="regLevelEditContainer_{$level.id}" class="reg-level-edit-container">
+ <div class="reg-level-header">
+ <div class="glm-right">
+ <a data-option="cancelEditLevel" data-id="{$level.id}" class="reg-level-edit-cancel-button button glm-button-small">Cancel</a>
+ <a data-option="updateEditLevel" data-id="{$level.id}" class="reg-level-edit-update-button button glm-button-small-highlighted">Update</a>
</div>
- </script>
+ <b class="glm-required">{$terms.reg_term_level_cap} Name:</b> <input id="levelName_{$level.id}" class="level-name" type="text" name="name_{$level.id}" value="{$level.name}">
+ </div>
+ <b class="glm-required">Description:</b> <input id="levelDescr_{$level.id}" class="level-descr" type="text" name="reg_descr_{$level.id}" size="90" value="{$level.descr}">
+ <p class="glm-required">Required fields are in red.</p>
+ </div>
+ <div id="regLevelRatesContainer_{$level.id}" class="reg-level-rates-container">
+ {if $level.reg_rate}
+ {foreach $level.reg_rate as $rate}
- <script type="text/template" id="regRate-template">
- <div class="rate-display-template">
+ <!-- Registration Level Rate -->
+ <div id="regRateContainer_{$rate.id}">
+ <div id="regRateDisplayContainer_{$rate.id}" class="rate-display">
<div class="glm-rate-header">
<div class="glm-right">
- <a class="rate-edit button button-secondary glm-button-small">Edit</a>
- <a class="rate-delete button button-secondary glm-button-small">Delete Rate</a>
+ <a data-option="editRate" data-id="{$rate.id}" data-level="{$level.id}" class="reg-rate-edit-button button button-secondary glm-button-small">Edit</a>
+ <a data-option="deleteRate" data-id="{$rate.id}" data-level="{$level.id}" class="reg-rate-delete-button button button-secondary glm-button-small">Delete Rate</a>
</div>
- <div class="glm-rate-label" style="margin-bottom: .5em;">
- <h3><%= name %></h3>
- Start Days: <%= start_days %>, End Days: <%= end_days %>, Base: $<%= base_rate %>. Per-Registrant: $<%= per_registrant %>. Registrant Credits: <%= registrant_credits %>
+ <div class="reg-rate-label-container">
+ <h3 id="regRateName_{$rate.id}">{$rate.name}</h3>
+ Start Days: <span id="regRateStartDays_{$rate.id}">{$rate.start_days}</span>,
+ End Days: <span id="regRateEndDays_{$rate.id}">{$rate.end_days}</span>,
+ Base: <span id="regRateBaseRate_{$rate.id}">{$rate.base_rate_money}</span>.
+ Per-Registrant: <span id="regRatePerRegistrant_{$rate.id}">{$rate.per_registrant_money}</span>.
+ Registrant Credits: <span id="regRateRegistrantCredits_{$rate.id}">{$rate.registrant_credits}</span>
</div>
</div>
</div>
- <div class="rate-edit-template" style="display: none; border: 1px solid black; padding: 1em; background-color: #f8ffff;">
+ <div id="regRateEditContainer_{$rate.id}" class="reg-rate-edit-container">
<div class="glm-rate-header">
<div class="glm-right">
- <a class="rate-cancel button glm-button-small">Cancel</a>
- <a class="rate-update button glm-button-small-highlighted">Update</a>
- <a class="rate-add button glm-button-small-highlighted" style="display: none;">Add</a>
- <a class="rate-delete button button-secondary glm-button-small">Delete</a>
+ <a data-option="cancelEditRate" data-id="{$rate.id}" class="reg-rate-edit-cancel-button button glm-button-small">Cancel</a>
+ <a data-option="updateEditRate" data-id="{$rate.id}" class="reg-rate-edit-update-button button glm-button-small-highlighted">Update</a>
</div>
<h3>Rate Days and Costs</h3>
<div class="glm-rate-label" style="padding-bottom: .3em;">
<th></th>
<td>
<p>
- {/literal}
"Rates" are a schedule of what is paid to {$terms.reg_term_register} for an {$terms.reg_term_event}. Rates can change based on the number of days until the {$terms.reg_term_event}.
For example, an earier {$terms.reg_term_registration} may be less expensive than a last minute {$terms.reg_term_registration}.
The start and end days for a rate must not overlap that of another rate for the same {$terms.reg_term_registration} level.
The earliest "Start Days" determines the earliest date on which {$terms.reg_term_registration} is available and the last "End Days" closest to the {$terms.reg_term_event} determines the last date on which {$terms.reg_term_registration} is available.
- {literal}
</p>
</td>
</tr>
+ <tr><td> </td><td class="glm-required">Required fields are in red.</td></tr>
<tr>
- <th style="white-space: nowrap;">Rate Name:</th>
+ <th style="white-space: nowrap;" class="glm-required">Rate Name:</th>
<td>
- <input class="rate-name glm-form-text-input" type="text" name="name_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (name) { %><%- name %><% } %>">
+ <input id="rateName_{$rate.id}" class="rate-name glm-form-text-input" type="text" name="name_{$rate.id}" value="{$rate.name}">
</td>
</tr>
<tr>
- <th style="white-space: nowrap;">Start Days</th>
+ <th style="white-space: nowrap;" class="glm-required">Start Days</th>
<td>
- <input class="rate-start-days glm-form-text-input-veryshort" type="text" name="start_days_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (start_days) { %><%- start_days %><% } %>">
- Number of days before {/literal}{$terms.reg_term_event}{literal} that this rate starts. Must not overlap other rates.
+ <input id="rateStartDays_{$rate.id}" class="rate-start-days glm-form-text-input-veryshort" type="text" name="start_days_{$rate.id}" value="{$rate.start_days}">
+ Number of days before {$terms.reg_term_event} that this rate starts. Must not overlap other rates.
</td>
</tr>
<tr>
- <th style="white-space: nowrap;">End Days:</th>
+ <th style="white-space: nowrap;" class="glm-required">End Days:</th>
<td>
- <input class="rate-end-days glm-form-text-input-veryshort" type="text" name="end_days_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (end_days) { %><%- end_days %><% } %>">
- Number of days before {/literal}{$terms.reg_term_event}{literal} that this rate ends. Must not overlap other rates.
+ <input id="rateEndDays_{$rate.id}" class="rate-end-days glm-form-text-input-veryshort" type="text" name="end_days_{$rate.id}" value="{$rate.end_days}">
+ Number of days before {$terms.reg_term_event} that this rate ends. Must not overlap other rates.
</td>
</tr>
<tr>
<th style="white-space: nowrap;">Cost:</th>
<td>
- <span class="glm-nowrap">Base $<input class="rate-base-rate glm-form-text-input-veryshort" type="text" name="base_rate_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (base_rate) { %><%- base_rate %><% } %>"></span>
- <span class="glm-nowrap">Per-Registrant $<input class="rate-per-registrant glm-form-text-input-veryshort" type="text" name="per_registrant_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (per_registrant) { %><%- per_registrant %><% } %>"></span>
- <span class="glm-nowrap">Registrant Credits <input class="rate-registrant-credits glm-form-text-input-veryshort" type="text" name="registrant_credits_<% if (id) { %><%- id %><% } else { %> new <% } %>" value="<% if (registrant_credits) { %><%= registrant_credits %><% } %>"></span>
+ <span class="glm-nowrap"><span class="glm-required"><b>Base Rate</b></span> $<input id="rateBaseRate_{$rate.id}" class="rate-base-rate glm-form-text-input-veryshort" type="text" name="base_rate_{$rate.id}" value="{$rate.base_rate|string_format:"%.2f"}"></span>
+ <span class="glm-nowrap"><span class="glm-required"><b>Rate Per-Registrant</b></span> $<input id="ratePerRegistrant_{$rate.id}" class="rate-per-registrant glm-form-text-input-veryshort" type="text" name="per_registrant_{$rate.id}" value="{$rate.per_registrant|string_format:"%.2f"}"></span>
+ <span class="glm-nowrap"><span class="glm-required"><b>Registrants included in Base Rate</b></span> <input id="rateRegistrantCredits_{$rate.id}" class="rate-registrant-credits glm-form-text-input-veryshort" type="text" name="registrant_credits_{$rate.id}" value="{$rate.registrant_credits}"></span>
<br>
</td>
</tr>
</div>
</div>
</div>
- </script>
+ </div>
+
+ {/foreach} {* Rate *}
+ {/if}
+ </div> <!-- Rates Container -->
- {/literal}
+</div> <!-- Level Container -->
- <div class="glm-reg-event-list" id="regApp">
+ {/foreach} {* Reg Level *}
+{/if}
+</div>
+
+<div id="regLevelTemplate" class="glm-hidden">
+ <div id="regLevelContainer_{ id }" class="reg-level-container ">
+ <div id="regLevelDisplayContainer_{ id }" class="reg-level-display-container">
+ <div class="reg-level-header">
+ <div class="glm-right ">
+ <a data-option="editLevel" data-id="{ id }" class="reg-level-edit-button button button-secondary glm-button-small">Edit</a>
+ <a data-option="deleteLevel" data-id="{ id }" class="reg-level-delete-button button button-secondary glm-button-small">Delete</a>
+ <a data-option="addRate" data-id="{ id }" class="reg-level-add-rate-button button button-secondary glm-button-small">Add Rate</a>
+ </div>
+ <div class="reg-level-label">
+ <h3 id="regLevelName_{ id }">{ pendingName }</h3>
+ </div>
+ </div>
+ <div id="regLevelDescr_{ id }">{ pendingDescr }</div>
+ </div>
+ <div id="regLevelEditContainer_{ id }" class="reg-level-edit-container">
+ <div class="reg-level-header">
+ <div class="glm-right routedEvent">
+ <a data-option="cancelEditLevel" data-id="{ id }" class="reg-level-edit-cancel-button button glm-button-small">Cancel</a>
+ <a data-option="updateEditLevel" data-id="{ id }" class="reg-level-edit-update-button button glm-button-small-highlighted">Update</a>
+ </div>
+ <b class="glm-required">{$terms.reg_term_level_cap} Name:</b> <input id="levelName_{ id }" class="level-name" type="text" name="name_{ id }" value="{ pendingName }">
+ </div>
+ <b class="glm-required">Description:</b> <input id="levelDescr_{ id }" class="level-descr" type="text" name="reg_descr_{ id }" size="90" value="{ pendingDescr }">
+ <p class="glm-required">Required fields are in red.</p>
+ </div>
+ <div id="regLevelRatesContainer_{ id }" class="reg-level-rates-container"></div>
</div>
+</div>
- {* Bootstrap the models needed on page load *}
- {* Need to have RegEvent model created *}
- {* And create the RegClasses collection *}
- <script>
-
- // Start with submit not required as 0, this is incremented for each edit area opened
- var glmSubmitRequired = 0;
-
- //var $=jQuery.noConflict();
- var ajaxUrl = '{$ajaxUrl}?action=glm_members_admin_ajax';
- var app = {
- Models: { Admin: {} },
- Collections: { Admin: {} },
- Views: { Admin: {} },
- };
- var regEvent = '';
-
- jQuery(function($){
- regEvent = new app.Models.Admin.RegEvent;
- regEvent.setClasses({$regClassesJSON});
-// regEvent.setTimes({$regTimesJSON});
- regEvent.set( {$regEventJSON} );
- new app.Views.Admin.EventEditLevels();
-
- // If submit is required and we're laving the page, alert the user - Note, there is no way to change the pop-up message anymore.
- $(window).bind('beforeunload', function() {
- if (glmSubmitRequired) {
- return true;
- }
- });
+<div id="regRateTemplate" class="glm-hidden">
+ <div id="regRateContainer_{ id }">
+ <div id="regRateDisplayContainer_{ id }" class="rate-display">
+ <div class="glm-rate-header">
+ <div class="glm-right">
+ <a data-option="editRate" data-id="{ id }" data-level="{ levelId }" class="reg-rate-edit-button button button-secondary glm-button-small">Edit</a>
+ <a data-option="deleteRate" data-id="{ id }" data-level="{ levelId }" class="reg-rate-delete-button button button-secondary glm-button-small">Delete Rate</a>
+ </div>
+ <div class="reg-rate-label-container">
+ <h3 id="regRateName_{ id }">{ pendingRateName }</h3>
+ Start Days: <span id="regRateStartDays_{ id }">{ pendingRateStartDays }</span>,
+ End Days: <span id="regRateEndDays_{ id }">{ pendingRateEndDays }</span>,
+ Base: <span id="regRateBaseRate_{ id }">${ pendingRateBaseRate }</span>.
+ Per-Registrant: <span id="regRatePerRegistrant_{ id }">${ pendingRatePerRegistrant }</span>,
+ Registrant Credits: <span id="regRateRegistrantCredits_{ id }">{ pendingRateRegistrantCredits }</span>
+ </div>
+ </div>
+ </div>
+ <div id="regRateEditContainer_{ id }" class="reg-rate-edit-container">
+ <div class="glm-rate-header">
+ <div class="glm-right">
+ <a data-option="cancelEditRate" data-id="{ id }" class="reg-rate-edit-cancel-button button glm-button-small">Cancel</a>
+ <a data-option="updateEditRate" data-id="{ id }" class="reg-rate-edit-update-button button glm-button-small-highlighted">Update</a>
+ </div>
+ <h3>Rate Days and Costs</h3>
+ <div class="glm-rate-label" style="padding-bottom: .3em;">
+ <table class="glm-admin-table">
+ <tr>
+ <th></th>
+ <td>
+ <p>
+ "Rates" are a schedule of what is paid to {$terms.reg_term_register} for an {$terms.reg_term_event}. Rates can change based on the number of days until the {$terms.reg_term_event}.
+ For example, an earier {$terms.reg_term_registration} may be less expensive than a last minute {$terms.reg_term_registration}.
+ The start and end days for a rate must not overlap that of another rate for the same {$terms.reg_term_registration} level.
+ The earliest "Start Days" determines the earliest date on which {$terms.reg_term_registration} is available and the last "End Days" closest to the {$terms.reg_term_event} determines the last date on which {$terms.reg_term_registration} is available.
+ </p>
+ </td>
+ </tr>
+ <tr><td> </td><td class="glm-required">Required fields are in red.</td></tr>
+ <tr>
+ <th style="white-space: nowrap;" class="glm-required">Rate Name:</th>
+ <td>
+ <input id="rateName_{ id }" class="rate-name glm-form-text-input" type="text" name="name_{ id }" value="{ pendingRateName }">
+ </td>
+ </tr>
+ <tr>
+ <th style="white-space: nowrap;" class="glm-required">Start Days</th>
+ <td>
+ <input id="rateStartDays_{ id }" class="rate-start-days glm-form-text-input-veryshort" type="text" name="start_days_{ id }" value="{ pendingRateStartDays }">
+ Number of days before {$terms.reg_term_event} that this rate starts. Must not overlap other rates.
+ </td>
+ </tr>
+ <tr>
+ <th style="white-space: nowrap;" class="glm-required">End Days:</th>
+ <td>
+ <input id="rateEndDays_{ id }" class="rate-end-days glm-form-text-input-veryshort" type="text" name="end_days_{ id }" value="{ pendingRateEndDays }">
+ Number of days before {$terms.reg_term_event} that this rate ends. Must not overlap other rates.
+ </td>
+ </tr>
+ <tr>
+ <th style="white-space: nowrap;">Cost:</th>
+ <td>
+ <span class="glm-nowrap"><span class="glm-required"><b>Base Rate</b></span> $<input id="rateBaseRate_{ id }" class="rate-base-rate glm-form-text-input-veryshort" type="text" name="base_rate_{ id }" value="{ pendingRateBaseRate }"></span>
+ <span class="glm-nowrap"><span class="glm-required"><b>Rate Per-Registrant</b></span> $<input id="ratePerRegistrant_{ id }" class="rate-per-registrant glm-form-text-input-veryshort" type="text" name="per_registrant_{ id }" value="{ pendingRatePerRegistrant }"></span>
+ <span class="glm-nowrap"><span class="glm-required"><b>Registrants included in Base Rate</b></span> <input id="rateRegistrantCredits_{ id }" class="rate-registrant-credits glm-form-text-input-veryshort" type="text" name="registrant_credits_{ id }" value="{ pendingRateRegistrantCredits }"></span>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div id="msgDialog" style="text-align: center; font-weight: bold; padding-top: 1.5em;"></div>
+
+<script type="text/javascript">
+ jQuery(document).ready(function($) {
+
+ var editActive = false;
+ var levelEditId = false;
+ var levelId = false;
+ var rateId = false;
+ var newEdit = false;
+ var rateEditId = false;
+ var newItemSortVal = 9000; // Increment for each new item to ensure sane default ordering
+
+ var failMsg = 'Sorry, we could not communicate with our server. Your changes may not have been saved.';
+
+ /*
+ * Operations using deligated events
+ */
+ $("#regLevelsContainer").on("click", "a", function(event) {
+ event.stopPropagation();
+ var eventOption = $(this).data('option');
+ switch (eventOption) {
+
+ case 'editLevel':
+
+ if (!checkEditActive()) {
+
+ levelEditId = $(this).data('id');
+ editActive = true;
+
+ $('#regLevelDisplayContainer_' + levelEditId).hide();
+ $('#regLevelEditContainer_' + levelEditId).show();
+
+ disableSorting();
+ }
+
+ break;
+
+ case 'cancelEditLevel':
+
+ if (editActive && levelEditId) {
+
+ // If this is a new level
+ if (levelEditId == 'newId') {
+ $('#regLevelContainer_newId').remove();
+ } else {
+ $('#regLevelDisplayContainer_' + levelEditId).show();
+ $('#regLevelEditContainer_' + levelEditId).hide();
+ }
+ levelEditId = false;
+ editActive = false;
+
+ enableSorting();
+
+ }
+
+ break;
+
+ case 'updateEditLevel':
+
+ // Build request to update level
+ var formData = {
+ 'action': 'glm_members_admin_ajax',
+ 'glm_action': 'levelsAndRatesEdit',
+ 'option': 'updateLevel',
+ 'eventId': {$regEvent.id},
+ 'levelId': levelEditId,
+ 'name': $('#levelName_' + levelEditId).val(),
+ 'descr': $('#levelDescr_' + levelEditId).val()
+ };
+ if (newEdit) {
+ formData.option = 'addLevel';
+ formData.sort_order = newItemSortVal++;
+ }
+
+ updatingDialog();
+
+ // Send update via AJAX
+ $.ajax({
+ type: 'POST',
+ url: '{$ajaxUrl}',
+ data: formData,
+ encode: true,
+ dataType: 'json'
+ })
+ .done(function(data) {
+
+ updatingDialogClose();
+
+ // If success
+ if (data.status) {
+
+
+ if (newEdit) {
+
+ // Drop temp newId container and create a new one with the correct ID and data
+ $('#regLevelContainer_' + levelEditId ).remove();
+
+ // Get level template
+ var levelTemplate = $('#regLevelTemplate').html();
+
+ // Replace the ID with new ID
+ levelTemplate = levelTemplate.replace(/{ id }/g, data.levelId);
+ levelTemplate = levelTemplate.replace(/{ pendingName }/g, data.name);
+ levelTemplate = levelTemplate.replace(/{ pendingDescr }/g, data.descr);
+
+ // Append to level
+ $('#regLevelsContainer').append(levelTemplate);
+
+ // Show the new Level display and hide edit
+ $('#regLevelDisplayContainer_' + data.levelId).show();
+ $('#regLevelEditContainer_' + data.levelId).hide();
+
+ } else {
+
+ // Set the display data to the new values
+ $('#regLevelName_' + levelEditId).html(data.name);
+ $('#regLevelDescr_' + levelEditId).html(data.descr);
+
+ // Now show the display container and hide the edit container
+ $('#regLevelDisplayContainer_' + levelEditId).show();
+ $('#regLevelEditContainer_' + levelEditId).hide();
+
+ }
+
+ levelEditId = false;
+ editActive = false;
+ newEdit = false;
+
+ enableSorting();
+
+ } else {
+ openMsgDialog(data.msg);
+ }
+ })
+ .fail( function() {
+ updatingDialogClose();
+ alert(failMsg);
+ });
+
+ break;
+
+ case 'deleteLevel':
+
+ levelId = $(this).data('id');
+ if (!checkEditActive() && levelId && confirm('Are you sure you want to delete this {$terms.reg_term_level} and all rates under it?')) {
+
+ // Send delete request via AJAX
+ var formData = {
+ 'action': 'glm_members_admin_ajax',
+ 'glm_action': 'levelsAndRatesEdit',
+ 'option': 'deleteLevel',
+ 'levelId': $(this).data('id')
+ };
+
+ updatingDialog();
+
+ $.ajax({
+ type: 'POST',
+ url: '{$ajaxUrl}',
+ data: formData,
+ encode: true,
+ dataType: 'JSON'
+ })
+ .done(function(data) {
+
+ updatingDialogClose();
+
+ // if success
+ if (data.status) {
+ var deleted = true;
+
+ if (deleted) {
+ $('#regLevelContainer_' + levelId ).remove();
+ }
+ }
+ })
+ .fail( function() {
+ updatingDialogClose();
+ alert(failMsg);
+ });
+
+ }
+
+ break;
+
+ // Setup to enter a new rate
+ case 'addRate':
+
+ if (!checkEditActive()) {
+
+ rateEditId = 'newId';
+ editActive = true;
+ newEdit = true;
+
+ // Get Level for this rate
+ levelId = $(this).data('id');
+
+ // Get rate template
+ var rateTemplate = $('#regRateTemplate').html();
+
+ // Replace the ID with 'newId'
+ rateTemplate = rateTemplate.replace(/{ id }/g, 'newId');
+
+ // Initialize all data fields
+ rateTemplate = rateTemplate.replace(/{ pendingRateName }/g, '');
+ rateTemplate = rateTemplate.replace(/{ pendingRateStartDays }/g, '0');
+ rateTemplate = rateTemplate.replace(/{ pendingRateEndDays }/g, '0');
+ rateTemplate = rateTemplate.replace(/{ pendingRateBaseRate }/g, '0.00');
+ rateTemplate = rateTemplate.replace(/{ pendingRatePerRegistrant }/g, '0.00');
+ rateTemplate = rateTemplate.replace(/{ pendingRateRegistrantCredits }/g, '0');
+
+ // Append to rates in rate's level
+ $('#regLevelRatesContainer_' + levelId).append(rateTemplate);
+
+ $('#regRateDisplayContainer_newId').hide();
+ $('#regRateEditContainer_newId').show();
+
+ disableSorting();
+
+ }
+
+ break;
+
+ // Setup to edit an existing rate
+ case 'editRate':
+
+ if (!checkEditActive()) {
+
+ rateEditId = $(this).data('id');
+ editActive = true;
+
+ // Get Level for this rate
+ levelId = $(this).data('level');
+
+ $('#regRateDisplayContainer_' + rateEditId).hide();
+ $('#regRateEditContainer_' + rateEditId).show();
+
+ disableSorting();
+
+ }
+
+ break;
+
+ // Update or Insert Rate
+ case 'updateEditRate':
+
+ // Build request to update rate
+ var formData = {
+ 'action': 'glm_members_admin_ajax',
+ 'glm_action': 'levelsAndRatesEdit',
+ 'option': 'updateRate',
+ 'eventId': {$regEvent.id},
+ 'levelId': levelId,
+ 'rateId': rateEditId,
+ 'name': $('#rateName_' + rateEditId).val(),
+ 'start_days': $('#rateStartDays_' + rateEditId).val(),
+ 'end_days': $('#rateEndDays_' + rateEditId).val(),
+ 'base_rate': $('#rateBaseRate_' + rateEditId).val(),
+ 'per_registrant': $('#ratePerRegistrant_' + rateEditId).val(),
+ 'registrant_credits': $('#rateRegistrantCredits_' + rateEditId).val()
+ };
+
+ if (newEdit) {
+ formData.option = 'addRate';
+ formData.sort_order = newItemSortVal++;
+ }
+
+ updatingDialog();
+
+ // Send update via AJAX
+ $.ajax({
+ type: 'POST',
+ url: '{$ajaxUrl}',
+ data: formData,
+ encode: true,
+ dataType: 'json'
+ })
+ .done(function(data) {
+
+ updatingDialogClose();
+
+ // If success
+ if (data.status) {
+
+ if (newEdit) {
+
+ // Drop temp newId container and create a new one with the correct ID and data
+ $('#regRateContainer_' + rateEditId ).remove();
+
+ // Get Rate template
+ var rateTemplate = $('#regRateTemplate').html();
+
+ // Set parameters into the form template copy
+ rateTemplate = rateTemplate.replace(/{ id }/g, data.rateId);
+ rateTemplate = rateTemplate.replace(/{ levelId }/g, data.levelId);
+ rateTemplate = rateTemplate.replace(/{ pendingRateName }/g, data.name);
+ rateTemplate = rateTemplate.replace(/{ pendingRateStartDays }/g, data.start_days);
+ rateTemplate = rateTemplate.replace(/{ pendingRateEndDays }/g, data.end_days);
+ rateTemplate = rateTemplate.replace(/{ pendingRateBaseRate }/g, data.base_rate.toFixed(2));
+ rateTemplate = rateTemplate.replace(/{ pendingRatePerRegistrant }/g, data.per_registrant.toFixed(2));
+ rateTemplate = rateTemplate.replace(/{ pendingRateRegistrantCredits }/g, data.registrant_credits);
+
+ // Append to rate
+ $('#regLevelRatesContainer_' + data.levelId).append(rateTemplate);
+
+ // Show the new rate display area and hide new edit area
+ $('#regRateDisplayContainer_' + data.rateId).show();
+ $('#regRateEditContainer_' + data.rateId).hide();
+
+ } else {
+
+ // Update the displayed rate data
+ $('#regRateName_' + rateEditId).html(data.name),
+ $('#regRateStartDays_' + rateEditId).html(data.start_days),
+ $('#regRateEndDays_' + rateEditId).html(data.end_days),
+ $('#regRateBaseRate_' + rateEditId).html('$' + data.base_rate.toFixed(2)),
+ $('#regRatePerRegistrant_' + rateEditId).html('$' + data.per_registrant.toFixed(2)),
+ $('#regRateRegistrantCredits_' + rateEditId).html(data.registrant_credits)
+
+ // Show display and hide edit
+ $('#regRateDisplayContainer_' + rateEditId).show();
+ $('#regRateEditContainer_' + rateEditId).hide();
+
+ }
+
+ rateEditId = false;
+ editActive = false;
+ newEdit = false;
+
+ enableSorting();
+
+ } else {
+ openMsgDialog(data.msg);
+ }
+ })
+ .fail( function() {
+ updatingDialogClose();
+ alert(failMsg);
+ });
+
+ break;
+
+ case 'cancelEditRate':
+
+ if (editActive && rateEditId) {
+
+ // If this is a new rate
+ if (editActive && rateEditId && newEdit) {
+ $('#regRateContainer_newId').remove();
+ } else {
+ $('#regRateDisplayContainer_' + rateEditId).show();
+ $('#regRateEditContainer_' + rateEditId).hide();
+ }
+ rateEditId = false;
+ editActive = false;
+
+ enableSorting();
+
+ }
+
+ break;
+
+ case 'deleteRate':
+
+ rateId = $(this).data('id');
+ if (!checkEditActive() && rateId && confirm('Are you sure you want to delete this rate?')) {
+
+ // Send delete request via AJAX
+ var formData = {
+ 'action': 'glm_members_admin_ajax',
+ 'glm_action': 'levelsAndRatesEdit',
+ 'option': 'deleteRate',
+ 'rateId': $(this).data('id')
+ };
+
+ updatingDialog();
+
+ $.ajax({
+ type: 'POST',
+ url: '{$ajaxUrl}',
+ data: formData,
+ encode: true,
+ dataType: 'JSON'
+ })
+ .done(function(data) {
+
+ updatingDialogClose();
+
+ // if success
+ if (data.status) {
+ var deleted = true;
+
+ if (deleted) {
+ $('#regRateContainer_' + rateId ).remove();
+ }
+ }
+ })
+ .fail( function() {
+ updatingDialogClose();
+ alert(failMsg);
+ });
+
+ }
+
+ break;
+
+ }
});
- </script>
-</div>
+ /*
+ * Operations not using delegated events
+ */
+
+ // Level dragable
+ $('#regLevelsContainer').sortable({
+ items: '.reg-level-container',
+ update: function(event, ui) {
+
+ // Create an array of the fields in the current order by field ID (field_{ id })
+ var sortedIds = $(this).sortable('toArray');
+
+ updatingDialog();
+
+ // Send new order via AJAX
+ var formData = {
+ 'action': 'glm_members_admin_ajax',
+ 'glm_action': 'levelsAndRatesEdit',
+ 'option': 'sortLevels',
+ 'sortedIds': sortedIds
+ };
+
+ updatingDialog();
+
+ $.ajax({
+ type: 'POST',
+ url: '{$ajaxUrl}',
+ data: formData,
+ encode: true,
+ dataType: 'json'
+ })
+ .done( function(data) {
+
+ updatingDialogClose();
+
+ if (data.status == false) {
+ var msg = 'An error occurred attempting to save the new level order.';
+ if (data.msg) {
+ msg += data.msg;
+ }
+ alert(msg);
+ }
+ })
+ .fail( function() {
+ updatingDialogClose();
+ alert(failMsg);
+ })
+ }
+
+ });
+
+ // Add Level
+ $('.reg-level-add-button').on('click', function() {
+
+ if (!checkEditActive()) {
+
+ levelEditId = 'newId';
+ editActive = true;
+ newEdit = true;
+
+ // Get level template
+ var levelTemplate = $('#regLevelTemplate').html();
+
+ // Replace the ID with 'newId'
+ levelTemplate = levelTemplate.replace(/{ id }/g, 'newId');
+
+ // Initialize all data fields
+ levelTemplate = levelTemplate.replace(/{ pendingName }/g, '');
+ levelTemplate = levelTemplate.replace(/{ pendingDescr }/g, '');
+
+ // Append to level
+ $('#regLevelsContainer').append(levelTemplate);
+
+ $('#regLevelDisplayContainer_newId').hide();
+ $('#regLevelEditContainer_newId').show();
+
+ disableSorting();
+ }
+// updatingDialogClose();
+ });
+
+ function disableSorting() {
+ $('#regLevelsContainer').sortable('disable');
+ $('.reg-level-container').css('cursor', 'default');
+ }
+ function enableSorting() {
+ $('#regLevelsContainer').sortable('enable');
+ $('.reg-level-container').css('cursor', 'pointer');
+ }
+
+ function checkEditActive() {
+ if (editActive) {
+ openMsgDialog('Please finish your current edit or update form first.');
+ }
+ return editActive;
+ }
+ function openMsgDialog(msg) {
+ $('#msgDialog').dialog({
+ modal: true,
+ resizable: false,
+ dragable: false,
+ closeOnEscape: true,
+ width: 'auto'
+ });
+ $('#msgDialog').html(msg);
+ }
+ function updatingDialog() {
+ openMsgDialog('UPDATING: Please wait!');
+ }
+ function updatingDialogClose() {
+ $('#msgDialog').dialog('close');
+ }
+
+ });
+</script>
{include file='admin/footer.html'}