<?php
/*
 * Jetpack CRM
 * https://jetpackcrm.com
 * V1.20
 *
 * Copyright 2020 Automattic
 *
 * Date: 01/11/16
 */

defined( 'ZEROBSCRM_PATH' ) || exit( 0 );

/*
======================================================
	Contact
	====================================================== */

function zeroBSCRM_html_contactIntroSentence( $contact ) {

	// include 'contact since' when we have a valid date:
	if ( $contact['created'] > 0 ) {

		$c = '<i class="calendar alternate outline icon"></i>' . sprintf( __( 'Contact since %s', 'zero-bs-crm' ), $contact['created_date'] );

	}

	// in co? + check if B2B mode active
	$b2bMode = zeroBSCRM_getSetting( 'companylevelcustomers' );
	if ( $b2bMode == 1 ) {
		$possibleCo = zeroBS_getCustomerCompanyID( $contact['id'] );
		if ( ! empty( $possibleCo ) && $possibleCo > 0 ) {

			$co = zeroBS_getCompany( $possibleCo );

			if ( is_array( $co ) && isset( $co['name'] ) && ! empty( $co['name'] ) ) {

				$c .= '<br/><i class="building outline icon"></i>' . __( 'Works for', 'zero-bs-crm' ) . ' <a href="' . jpcrm_esc_link( 'view', $possibleCo, 'zerobs_company' ) . '" target="_blank">' . esc_html( $co['name'] ) . '</a>';
			}
		}
	}

		#} New 2.98+
		$contact_location = '';
	if ( ! empty( $contact['county'] ) && ! empty( $contact['country'] ) ) {
		$contact_location = $contact['county'] . ', ' . $contact['country'];
	} elseif ( ! empty( $contact['county'] ) && empty( $contact['country'] ) ) {
		$contact_location = $contact['county'];
	} elseif ( empty( $contact['county'] ) && ! empty( $contact['country'] ) ) {
		$contact_location = $contact['country'];
	}

	if ( $contact_location != '' ) {
		$c .= '<br/><i class="map marker alternate icon"></i>' . $contact_location;
	}

		// tags for easier viewing UI wise (2.98+)

	$customerTags = zeroBSCRM_getCustomerTagsByID( $contact['id'] );
	if ( ! is_array( $customerTags ) ) {
		$customerTags = array();
	}
	if ( count( $customerTags ) > 0 ) {
		$c .= '<br/>' . zeroBSCRM_html_linkedContactTags( $contact['id'], $customerTags, 'ui tag label zbs-mini-tag', false, true );
	}

	// assigned to?
	$usingOwnership = zeroBSCRM_getSetting( 'perusercustomers' );
	if ( $usingOwnership ) {
		$possibleOwner = zeroBS_getOwner( $contact['id'], true, 'zerobs_customer' );
		if ( is_array( $possibleOwner ) && isset( $possibleOwner['ID'] ) && ! empty( $possibleOwner['ID'] ) ) {

			if ( isset( $possibleOwner['OBJ'] ) && isset( $possibleOwner['OBJ']->user_nicename ) ) {
				$user_avatar = jpcrm_get_avatar( $possibleOwner['OBJ']->ID, 25 );
				$c          .= '<div class="zbs-contact-owner">' . __( 'Assigned to: ', 'zero-bs-crm' ) . ' <span class="ui image label">' . $user_avatar . ' ' . $possibleOwner['OBJ']->display_name . '</span></div>';
			}
		}
	}

	$c = apply_filters( 'zerobscrm_contactintro_filter', $c, $contact['id'] );

	return $c;
}
function zeroBSCRM_html_contactSince( $customer ) {
	echo "<i class='fa fa-calendar'></i>  ";
	esc_html_e( 'Contact since ', 'zero-bs-crm' );
	$d              = new DateTime( $customer['created'] );
	$formatted_date = $d->format( zeroBSCRM_getDateFormat() );
	return "<span class='zbs-action'><strong>" . $formatted_date . '</strong></span>';
}

function zeroBSCRM_html_sendemailto( $prefillID = -1, $emailAddress = '', $withIco = true ) {
	global $zbs;
	if ( $prefillID > 0 && ! empty( $emailAddress ) ) {
		if ( $withIco ) {
			echo "<i class='fa fa-envelope-o'></i>  ";
		}
		echo "<span class='zbs-action'><a href='" . esc_url( zeroBSCRM_getAdminURL( $zbs->slugs['emails'] ) . '&zbsprefill=' . $prefillID ) . "'>";
		echo esc_html( $emailAddress );
		echo '</a></span>';
	}
}

// added echo = true (i.e by default echo this, but need to return it in some cases)
function zeroBSCRM_html_linkedContactTags( $contactID = -1, $tags = false, $classStr = '', $echo = true, $trim = false, $limit = false ) {

	global $zbs;
	$res = '';

	// check if we have a way to pass a LIMIT to the below (cos tons of tags in the top box is bad)

	if ( $contactID > 0 && $tags == false ) {
		$tags = zeroBSCRM_getCustomerTagsByID( $contactID );
	}

	if ( count( $tags ) > 0 ) {
		foreach ( $tags as $tag ) {

			// DAL1/2 switch
			$tagName = '';
			$tagID   = -1;
			if ( is_array( $tag ) ) {
				$tagName = $tag['name'];
				$tagID   = $tag['id'];
			} else {
				$tagName = $tag->name;
				$tagID   = $tag->term_id;
			}

			$short_tag_name = $trim && strlen( $tagName ) > 50 ? substr( $tagName, 0, 10 ) . '...' : $tagName;

			$link = admin_url( 'admin.php?page=' . $zbs->slugs['managecontacts'] . '&zbs_tag=' . $tagID );
			$res .= '<a title="' . esc_attr( $tagName ) . '" class="' . $classStr . '" href="' . $link . '">' . esc_html( $short_tag_name ) . '</a>';

		}
	}

	if ( $echo ) {
		echo $res;
	} else {
		return $res;
	}
}

// builds the HTML for companies linked to a contact
// note can pass $companiesArray parameter optionally to avoid the need to retrieve companies (DAL3+ these are got with the getContact)
function zeroBSCRM_html_linkedContactCompanies( $contactID = -1, $companiesArray = false ) {

	global $zbs;

	#} Contacts' companies
	if ( ! is_array( $companiesArray ) ) {
		$companies = $zbs->DAL->contacts->getContactCompanies( $contactID );
	} else {
		$companies = $companiesArray;
	}

	$companiesStr = '';

	foreach ( $companies as $company ) {

		if ( is_array( $company ) && isset( $company['name'] ) && ! empty( $company['name'] ) ) {

			$companiesStr .= '<a href="' . jpcrm_esc_link( 'view', $company['id'], 'zerobs_company' ) . '" target="_blank">' . esc_html( $company['name'] ) . '</a>';

		}
	}

	return $companiesStr;
}

function zeroBSCRM_html_contactTimeline( $contactID = -1, $logs = false, $contactObj = false ) {

	global $zeroBSCRM_logTypes, $zbs;

	if ( isset( $contactID ) && $contactID > 0 && $logs === false ) {

		// get logs
		$logs = zeroBSCRM_getContactLogs( $contactID, true, 100, 0, '', false );

	}

	// Compile a list of actions to show
	// - if under 10, show them all
	// - if over 10, show creation, and 'higher level' logs, then latest
	// - 7/2/19 WH modified this to catch "creation" logs properly, and always put them at the end
	// ... (we were getting instances where transaction + contact created in same second, which caused the order to be off)
	$logsToShow  = array();
	$creationLog = false;

	if ( count( $logs ) <= 10 ) {

		$logsToShow = $logs;

		$logsF       = array();
		$creationLog = false;
		// here we have to just do a re-order to make sure created is last :)
		foreach ( $logsToShow as $l ) {

			if ( $l['type'] == 'created' ) {
				$creationLog = $l;
			} else {
				$logsF[] = $l;
			}
		}

		// add it
		if ( is_array( $creationLog ) ) {
			$logsF[] = $creationLog;
		}

		// tidy
		$logsToShow = $logsF;
		unset( $logsF );
		unset( $creationLog );

	} else {

		// cherry pick 9 logs

		// 1) latest
		$logsToShow[] = current( $logs );

		// 2) cherry pick 8 middle events
		$logTypesToPrioritise = array(
			'Quote: Accepted',
			'Quote: Refused',
			'Invoice: Sent',
			'Invoice: Part Paid',
			'Invoice: Paid',
			'Invoice: Refunded',
			'Transaction',
			'Feedback',
			'Status Change',
			'Client Portal User Created',
			'Call',
			'Email',
			'Note',
		);

		// convert to type stored in db
		$x = array();
		foreach ( $logTypesToPrioritise as $lt ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
			$x[] = $zbs->DAL->logs->logTypeIn( $lt ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
		}
			$logTypesToPrioritise = $x;
		unset( $x );

			// for now, abbreviated, just cycle through + pick any in prioritised group... could do this staggered by type/time later
			// skip first item, as we've already added it earlier
		foreach ( array_slice( $logs, 1 ) as $l ) {
			if ( $l['type'] == 'created' ) {

				// add to this var
				$creationLog = $l;

			} else {

				// normal pickery
				if ( count( $logsToShow ) < 9 ) {
					if ( in_array( $l['type'], $logTypesToPrioritise ) ) {
						$logsToShow[] = $l;
					}
				} else {
					break;
				}
			}
		}

		// 3) created
		// for now, assume first log is created, if it's not, add one with date
		// ... this'll cover 100+ logs situ
		// WH changed 7/2/18 to remove issue mentioned above
			// $creationLog = end($logs);
		if ( $creationLog == false ) {

			// retrieve it
			$creationLog = zeroBSCRM_getObjCreationLog( $contactID, 1 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

		}
		if ( is_array( $creationLog ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

			$logsToShow[] = $creationLog;

		} else {

			// if has creation date (contactObj)
			if ( $contactObj != false ) {

				// manufacture a created log
				$logsToShow[] = array(

					'id'        => -1,
					'created'   => $contactObj['created'],
					'name'      => '',

					// also add DAL2 support:
					'type'      => __( 'Created', 'zero-bs-crm' ),
					'shortdesc' => __( 'Contact Created', 'zero-bs-crm' ),
					'longdesc'  => __( 'Contact was created', 'zero-bs-crm' ),

					'meta'      => array(
						'type'      => __( 'Created', 'zero-bs-crm' ),
						'shortdesc' => __( 'Contact Created', 'zero-bs-crm' ),
						'longdesc'  => __( 'Contact was created', 'zero-bs-crm' ),
					),
					'owner'     => -1,
					// nicetime

				);

			}
		}
	}

	if ( count( $logsToShow ) > 0 ) {
		?>
		<ul class="zbs-timeline">
			<?php
			$prevDate = '';
			$i        = 0;
			foreach ( $logsToShow as $log ) {

				if ( ! is_array( $log ) || ! isset( $log['created'] ) ) {
					continue;
				}

				// format date
				$d              = new DateTime( $log['created'] );
				$formatted_date = $d->format( zeroBSCRM_getDateFormat() );

				// check if same day as prev log
				$sameDate = false;
				if ( $formatted_date == $prevDate ) {
					$sameDate = true;
				}
				$prevDate = $formatted_date;

				// ico?
				$ico    = '';
				$logKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $log['type'] ) ) );
				if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) {
					$ico = $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['ico'];
				}
				// these are FA ico's at this point

				// fill in nicetime if using :)
				// use a setting to turn on off?
				if ( ! empty( $log['createduts'] ) && $log['createduts'] > 0 ) {
					// get H:i in local timezone
					$log['nicetime'] = zeroBSCRM_date_i18n( 'H:i', $log['createduts'], true, false );
				}

				// if it's last one, make sure it has class:
				$notLast = true;
				if ( count( $logsToShow ) == $i + 1 ) {
					$notLast = false;
				}

				// compile this first, so can catch default (empty types)
				$logTitle = '';
				if ( ! empty( $ico ) ) {
					$logTitle .= '<i class="fa ' . $ico . '"></i> ';
				}

				if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) {
					$logTitle .= __( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['label'], 'zero-bs-crm' );
				}

				$timeline_item_classes = '';
				if ( $sameDate && $notLast ) {
					$timeline_item_classes .= '-contd';
				}
				if ( empty( $logTitle ) ) {
					$timeline_item_classes .= ' zbs-timeline-item-notitle';
				}
				if ( ! $notLast ) {
					$timeline_item_classes .= ' zbs-last-item'; // last item (stop rolling padding)
				}

				$timeline_item_id_attr = '';
				if ( isset( $log['id'] ) && $log['id'] !== -1 ) {
					$timeline_item_id_attr = ' id="zbs-contact-log-' . $log['id'] . '"';
				}

				?>
				<li class="zbs-timeline-item<?php echo esc_attr( $timeline_item_classes ); ?> zbs-single-log"<?php $timeline_item_id_attr; ?>>
					<?php
					if ( ! $sameDate ) {
						?>
						<div class="zbs-timeline-info">
							<span><?php echo esc_html( $formatted_date ); ?></span>
						</div>
						<?php
					}
					?>
					<div class="zbs-timeline-marker"></div>
					<div class="zbs-timeline-content">

						<h3 class="zbs-timeline-title">
							<?php
							if ( ! empty( $ico ) ) {
								echo '<i class="fa ' . esc_attr( $ico ) . '"></i> ';
							}

							if ( isset( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ] ) ) {
								echo esc_html__( $zeroBSCRM_logTypes['zerobs_customer'][ $logKey ]['label'], 'zero-bs-crm' );
							}
							?>
						</h3>
						<div>
							<?php
							if ( isset( $log['shortdesc'] ) ) {
								echo wp_kses( $log['shortdesc'], array( 'i' => array( 'class' => true ) ) );
							}
							if ( ! empty( $log['author'] ) ) {
								echo ' &mdash; ' . esc_html( $log['author'] );
							}
							if ( isset( $log['nicetime'] ) ) {
								echo ' &mdash; <i class="clock icon"></i>' . esc_html( $log['nicetime'] );
							}
							// if has long desc, show/hide
							if ( ! empty( $log['longdesc'] ) ) {
								?>
								<i class="angle down icon zbs-show-longdesc"></i><i class="angle up icon zbs-hide-longdesc"></i>
								<div class="zbs-long-desc">
									<?php echo wp_kses( html_entity_decode( $log['longdesc'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ), $zbs->acceptable_restricted_html ); ?>
								</div>
								<?php
							}
							?>
						</div>
					</div>
				</li>
				<?php
				++$i;
			} // / per log
			?>
		</ul>
		<?php
	}
}

/**
 * Builds HTML table of custom tables & values for (any object type)
 *
 * @return string HTML table
 */
function zeroBSCRM_pages_admin_display_custom_fields_table( $id = -1, $objectType = ZBS_TYPE_CONTACT ) {

	global $zbs;

	// retrieve custom fields (including value)
	$custom_fields = $zbs->DAL->getObjectLayerByType( $objectType )->getSingleCustomFields( $id, false );

	// Build HTML
	if ( is_array( $custom_fields ) && count( $custom_fields ) > 0 ) {

		$html = '<table class="ui fixed single line celled table zbs-view-vital-customfields"><tbody>';

		foreach ( $custom_fields as $k => $v ) {

			$html .= '<tr id="zbs-view-vital-customfield-' . esc_attr( $v['id'] ) . '" class="wraplines">';
			$html .= '<td class="zbs-view-vital-customfields-label">' . esc_html( $v['name'] ) . '</td>';
			switch ( $v['type'] ) {

				case 'text':
						$value = nl2br( esc_html( $v['value'] ) );
						// if url, build link, prefixed with 'https://' if needed
					if ( jpcrm_is_url( $value ) ) {
						$value = '<a href="' . jpcrm_url_with_scheme( $value ) . '" target="_blank">' . $value . '</a>';
					}
					$html .= '<td class="zbs-view-vital-customfields-' . esc_attr( $v['type'] ) . '">' . $value . '</td>';
					break;

				case 'date':
						$html .= '<td class="zbs-view-vital-customfields-' . esc_attr( $v['type'] ) . '">' . ( $v['value'] !== '' ? jpcrm_uts_to_date_str( $v['value'], false, true ) : '' ) . '</td>';
					break;

				case 'checkbox':
					// pad , out
					$html .= '<td class="zbs-view-vital-customfields-' . esc_attr( $v['type'] ) . '">' . str_replace( ',', ', ', esc_html( $v['value'] ) ) . '</td>';
					break;

				default:
					$html .= '<td class="zbs-view-vital-customfields-' . esc_attr( $v['type'] ) . '">' . nl2br( esc_html( $v['value'] ) ) . '</td>';
					break;

			}

			$html .= '</tr>';

		}

		$html .= '</tbody></table>';

	} else {

		$html = __( 'No custom fields have been set up yet.', 'zero-bs-crm' );
		if ( zeroBSCRM_isZBSAdminOrAdmin() ) {

			$customFieldsUrl = esc_url( admin_url( 'admin.php?page=' . $zbs->slugs['settings'] ) . '&tab=customfields' );
			$html           .= ' <a href="' . $customFieldsUrl . '" target="_blank">' . __( 'Click here to manage custom fields', 'zero-bs-crm' ) . '</a>';

		}
	}

	return $html;
}

/*
======================================================
	/ Contact
	====================================================== */

/*
======================================================
	Company
	====================================================== */

/*
* Returns company introduction sentence
* e.g. Email: alessandra.koepp@example.com, Added 01/01/2022
*/
function zeroBSCRM_html_companyIntroSentence( $company ) {

	$return = '';
	if ( isset( $company['email'] ) && ! empty( $company['email'] ) ) {
		$return .= __( 'Email:', 'zero-bs-crm' );
		$return .= '<a href="mailto:' . $company['email'] . '" class="coemail"> ' . $company['email'] . '</a><br/>';
	}

	if ( is_array( $company ) && $company['created'] > 0 && isset( $company['created_date'] ) ) {
		$formatted_date = $company['created_date'];
		$return        .= __( 'Added', 'zero-bs-crm' ) . ' ' . $formatted_date;
	}

	// filter
	$return = apply_filters( 'zerobscrm_companyintro_filter', $return, $company['id'] );

	return $return;
}

function zeroBSCRM_html_linkedCompanyTags( $contactID = -1, $tags = false, $classStr = '' ) {

	global $zbs;

	if ( $contactID > 0 && $tags == false ) {
		$tags = zeroBSCRM_getCustomerTagsByID( $contactID );
	}
	if ( count( $tags ) > 0 ) {
		foreach ( $tags as $tag ) {

			// DAL1/2 switch
			$tagName = '';
			$tagID   = -1;
			if ( is_array( $tag ) ) {
				$tagName = $tag['name'];
				$tagID   = $tag['id'];
			} else {
				$tagName = $tag->name;
				$tagID   = $tag->term_id;
			}

			?>
		<a class="<?php echo esc_attr( $classStr ); ?>" href="<?php echo jpcrm_esc_link( $zbs->slugs['managecompanies'] ) . '&zbs_tag=' . $tagID; ?>"><?php echo esc_html( $tagName ); ?></a>
			<?php
		}
	}
}

// builds the HTML for contacts linked to a company
// note can pass $contactsArray parameter optionally to avoid the need to retrieve contacts (DAL3+ these are got with the getCompany)
function zeroBSCRM_html_linkedCompanyContacts( $companyID = -1, $contactsArray = false ) {

	// avatar mode
	$avatarMode = zeroBSCRM_getSetting( 'avatarmode' );

	// Contacts at company
	if ( ! is_array( $contactsArray ) ) {
		$contactsAtCo = zeroBS_getCustomers( true, 1000, 0, false, false, '', false, false, $companyID );
	} else {
		$contactsAtCo = $contactsArray;
	}

	$contactStr = '';
	foreach ( $contactsAtCo as $contact ) {

		if ( $avatarMode !== 3 ) {
			$contactStr .= zeroBS_getCustomerIcoLinkedLabel( $contact['id'] ); // or zeroBS_getCustomerIcoLinkedLabel?
		} else {
			// no avatars, use labels
			$contactStr .= zeroBS_getCustomerLinkedLabel( $contact['id'] );
		}
	}

	return $contactStr;
}

function zeroBSCRM_html_companyTimeline( $companyID = -1, $logs = false, $companyObj = false ) {

	global $zeroBSCRM_logTypes, $zbs;

	if ( isset( $companyID ) && $companyID > 0 && $logs === false ) {

		// get logs
		$logs = zeroBSCRM_getCompanyLogs( $companyID, true, 100, 0, '', false );

	}

	// Compile a list of actions to show
	// - if under 10, show them all
	// - if over 10, show creation, and 'higher level' logs, then latest
	// - 7/2/19 WH modified this to catch "creation" logs properly, and always put them at the end
	// ... (we were getting instances where transaction + contact created in same second, which caused the order to be off)
	$logsToShow  = array();
	$creationLog = false;

	if ( count( $logs ) <= 10 ) {

		$logsToShow = $logs;

		$logsF       = array();
		$creationLog = false;
		// here we have to just do a re-order to make sure created is last :)
		foreach ( $logsToShow as $l ) {

			if ( $l['type'] == 'created' ) {
				$creationLog = $l;
			} else {
				$logsF[] = $l;
			}
		}

		// add it
		if ( is_array( $creationLog ) ) {
			$logsF[] = $creationLog;
		}

		// tidy
		$logsToShow = $logsF;
		unset( $logsF );
		unset( $creationLog );

	} else {

		// cherry pick 9 logs

		// 1) latest
		$logsToShow[] = current( $logs );

		// 2) cherry pick 8 middle events
		$logTypesToPrioritise = array(
			'Call',
			'Email',
			'Note',
		);

		// convert to type stored in db
		$x = array();
		foreach ( $logTypesToPrioritise as $lt ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
			$x[] = $zbs->DAL->logs->logTypeIn( $lt ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
		}
			$logTypesToPrioritise = $x;
		unset( $x );

			// for now, abbreviated, just cycle through + pick any in prioritised group... could do this staggered by type/time later
		foreach ( $logs as $l ) {
			if ( $l['type'] == 'created' ) {

				// add to this var
				$creationLog = $l;

			} else {

				// normal pickery
				if ( count( $logsToShow ) < 9 ) {
					if ( in_array( $l['type'], $logTypesToPrioritise ) ) {
						$logsToShow[] = $l;
					}
				} else {
					break;
				}
			}
		}

		// 3) created
		// for now, assume first log is created, if it's not, add one with date
		// ... this'll cover 100+ logs situ
		// WH changed 7/2/18 to remove issue mentioned above
			// $creationLog = end($logs);
		if ( $creationLog == false ) {

			// retrieve it
			$creationLog = zeroBSCRM_getObjCreationLog( $companyID, 1 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
		}
		if ( is_array( $creationLog ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

			$logsToShow[] = $creationLog;

		} else {

			// if has creation date (companyObj)
			if ( $companyObj != false ) {

				// manufacture a created log
				$logsToShow[] = array(

					'id'        => -1,
					'created'   => $companyObj['created'],
					'name'      => '',

					// also add DAL2 support:
					'type'      => __( 'Created', 'zero-bs-crm' ),
					'shortdesc' => __( jpcrm_label_company() . 'Created', 'zero-bs-crm' ),
					'longdesc'  => __( jpcrm_label_company() . ' was created', 'zero-bs-crm' ),

					'meta'      => array(
						'type'      => __( 'Created', 'zero-bs-crm' ),
						'shortdesc' => __( jpcrm_label_company() . ' Created', 'zero-bs-crm' ),
						'longdesc'  => __( jpcrm_label_company() . ' was created', 'zero-bs-crm' ),
					),
					'owner'     => -1,
					// nicetime

				);

			}
		}
	}

	if ( count( $logsToShow ) > 0 ) {
		?>
	<ul class="zbs-timeline">
				<?php
				$prevDate = '';
				$i        = 0; foreach ( $logsToShow as $log ) {

					// format date
					$d              = new DateTime( $log['created'] );
					$formatted_date = $d->format( zeroBSCRM_getDateFormat() );

					// check if same day as prev log
					$sameDate = false;
					if ( $formatted_date == $prevDate ) {
						$sameDate = true;
					}
					$prevDate = $formatted_date;

					// ico?
					$ico    = '';
					$logKey = strtolower( str_replace( ' ', '_', str_replace( ':', '_', $log['type'] ) ) );
					if ( isset( $zeroBSCRM_logTypes['zerobs_company'][ $logKey ] ) ) {
						$ico = $zeroBSCRM_logTypes['zerobs_company'][ $logKey ]['ico'];
					}
					// these are FA ico's at this point

					// fill in nicetime if using :)
					// use a setting to turn on off?
					if ( isset( $log['createduts'] ) && ! empty( $log['createduts'] ) && $log['createduts'] > 0 ) {
						// $log['nicetime'] = date('H:i',$log['createduts']);
						$log['nicetime'] = zeroBSCRM_date_i18n( 'H:i', $log['createduts'], true, false );
					}

					// if it's last one, make sure it has class:
					$notLast = true;
					if ( count( $logsToShow ) == $i + 1 ) {
						$notLast = false;
					}

					?>
				<li class="zbs-timeline-item
					<?php
					if ( $sameDate && $notLast ) {
						echo '-contd';
					}
					if ( empty( $logTitle ) ) {
						echo ' zbs-timeline-item-notitle';
					}
					if ( ! $notLast ) {
						echo ' zbs-last-item'; // last item (stop rolling padding)
					}
					?>
				zbs-single-log" 
					<?php
					if ( isset( $log['id'] ) && $log['id'] !== -1 ) {
						echo 'id="zbs-company-log-' . esc_attr( $log['id'] ) . '"';
					}
					?>
				>
					<?php
					if ( ! $sameDate ) {
						?>
						<div class="zbs-timeline-info">
						<span><?php echo esc_html( $formatted_date ); ?></span>
					</div><?php } ?>
					<div class="zbs-timeline-marker"></div>
					<div class="zbs-timeline-content">
					<?php

							// if multiple owners
							/*
							show "team member who enacted"?
							similar to https://semantic-ui.com/views/feed.html
							<div class="label">
								<img src="/images/avatar/small/elliot.jpg">
							</div> */

					?>
						<h3 class="zbs-timeline-title">
						<?php
						if ( ! empty( $ico ) ) {
							echo '<i class="fa ' . esc_attr( $ico ) . '"></i> ';
						}
						if ( isset( $zeroBSCRM_logTypes['zerobs_company'][ $logKey ] ) ) {
							echo esc_html( $zeroBSCRM_logTypes['zerobs_company'][ $logKey ]['label'] );
						}
						?>
						</h3>
						<p>
						<?php
						if ( isset( $log['shortdesc'] ) ) {
							echo wp_kses( $log['shortdesc'], array( 'i' => array( 'class' => true ) ) );
							if ( isset( $log['author'] ) ) {
								echo ' &mdash; ' . esc_html( $log['author'] );
							}
							if ( isset( $log['nicetime'] ) ) {
								echo ' &mdash; <i class="clock icon"></i>' . esc_html( $log['nicetime'] );
							}
						}
						?>
						</p>
					</div>
				</li>
								<?php ++$i; } ?>
			</ul>
			<?php

	}
}

/*
======================================================
	/ Company
	====================================================== */

/*
======================================================
	Quotes
	====================================================== */

function zeroBSCRM_html_quoteStatusLabel( $quote = array() ) {

	$statusInt = zeroBS_getQuoteStatus( $quote, true );

	switch ( $statusInt ) {
		case -2: // published not accepted
			return 'ui orange label';
			break;
		case -1: // draft
			return 'ui grey label';
			break;
	}

	// accepted
	return 'ui green label';
}

/**
 * Return an updated HTML string, replacing date placeholders with correct date strings based on site settings.
 *
 * @param  string $value                 The value of the date variable to be replaced.
 * @param  string $key                   The key of the date variable to be replaced.
 * @param  string $working_html          The HTML string to be updated.
 * @param  string $placeholder_str_start The string to add to the beginning of the placeholder string (eg. ##QUOTE-).
 *
 * @return string                The updated HTML string.
 */
function jpcrm_process_date_variables( $value, $key, $working_html, $placeholder_str_start = '##' ) {

	$base_date_key        = $key;
	$date_to_uts          = jpcrm_date_str_to_uts( $value );
	$datetime_key         = $key . '_datetime_str';
	$date_uts_to_datetime = jpcrm_uts_to_datetime_str( $date_to_uts );
	$date_key             = $key . '_date_str';
	$date_uts__to_date    = jpcrm_uts_to_date_str( $date_to_uts );

	$search_replace_pairs = array(
		$placeholder_str_start . strtoupper( $base_date_key ) . '##' => $date_to_uts,
		$placeholder_str_start . strtoupper( $datetime_key ) . '##' => $date_uts_to_datetime,
		$placeholder_str_start . strtoupper( $date_key ) . '##' => $date_uts__to_date,

	);

	$working_html = str_replace( array_keys( $search_replace_pairs ), $search_replace_pairs, $working_html );

	return $working_html;
}

/*
======================================================
	/ Quotes
	====================================================== */

/*
======================================================
	Invoices
	====================================================== */

function zeroBSCRM_html_invoiceStatusLabel( $inv = array() ) {

	$status = '';

	// <3.0
	if ( isset( $inv['meta'] ) && isset( $inv['meta']['status'] ) ) {
		$status = $inv['meta']['status'];
	}
	// 3.0
	if ( isset( $inv['status'] ) ) {
		$status = $inv['status'];
	}

	switch ( $status ) {
		case __( 'Draft', 'zero-bs-crm' ):
			return 'ui teal label';
			break;
		case __( 'Unpaid', 'zero-bs-crm' ):
			return 'ui orange label';
			break;
		case __( 'Paid', 'zero-bs-crm' ):
			return 'ui green label';
			break;
		case __( 'Overdue', 'zero-bs-crm' ):
			return 'ui red label';
			break;
		case __( 'Deleted', 'zero-bs-crm' ):
			return 'ui red label';
			break;
	}

	return 'ui grey label';
}

/*
======================================================
	/ Invoices
	====================================================== */

/*
======================================================
	Transactions
	====================================================== */

function zeroBSCRM_html_transactionStatusLabel( $trans = array() ) {

	$status = '';

	if ( isset( $trans['status'] ) ) {
		$status = $trans['status'];
	}

	switch ( $status ) {
		case __( 'failed', 'zero-bs-crm' ):
			return 'ui orange label';
			break;
		case __( 'refunded', 'zero-bs-crm' ):
			return 'ui red label';
			break;
		case __( 'succeeded', 'zero-bs-crm' ):
			return 'ui green label';
			break;
		case __( 'completed', 'zero-bs-crm' ):
			return 'ui green label';
			break;

	}

	return 'ui grey label';
}

/*
======================================================
	/ Transactions
	====================================================== */

/*
======================================================
	Object Nav
	====================================================== */

// Navigation block (usually wrapped in smt like:)
// $filterStr = '<div class="ui items right floated" style="margin:0">'.zeroBSCRM_getObjNav($zbsid,'edit','CONTACT').'</div>';
function zeroBSCRM_getObjNav( $id = -1, $key = '', $type = ZBS_TYPE_CONTACT ) {

	global $zbs;

	$html            = '';
	$navigation_mode = $zbs->settings->get( 'objnav' );

	// The first addition of a contact is actually 'edit' but gives the option to view.
	$id = ( empty( $_GET['zbsid'] ) ? -1 : (int) $_GET['zbsid'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

	$html = '';

	switch ( $type ) {

		case ZBS_TYPE_CONTACT:
			// contact nav
			$navigation = $zbs->DAL->contacts->getContactPrevNext( $id );

			// PREV
			if ( $navigation_mode === 1 && ! empty( $navigation['prev'] ) ) {
				$html .= '<a href="' . jpcrm_esc_link( $key, $navigation['prev'], 'zerobs_customer', false ) . '" class="jpcrm-button transparent-bg font-14px"><i class="fa fa-chevron-left"></i>&nbsp;&nbsp;' . esc_html( __( 'Prev', 'zero-bs-crm' ) ) . '</a>';
			}
			// If in edit mode, show view link
			if ( $key === 'edit' && $id > 0 ) {
				$html .= '<a class="jpcrm-button transparent-bg font-14px" href="' . jpcrm_esc_link( 'view', $id, 'zerobs_customer' ) . '">' . esc_html( __( 'View contact', 'zero-bs-crm' ) ) . '</a>';
			}
			if ( $navigation_mode === 1 && ! empty( $navigation['next'] ) ) {
				$html .= '<a href="' . jpcrm_esc_link( $key, $navigation['next'], 'zerobs_customer', false ) . '" class="jpcrm-button transparent-bg font-14px">' . esc_html( __( 'Next', 'zero-bs-crm' ) ) . '&nbsp;&nbsp;<i class="fa fa-chevron-right"></i></a>';
			}

			break;

		case ZBS_TYPE_COMPANY:
			// company nav
			$navigation = $zbs->DAL->companies->getCompanyPrevNext( $id );

			// PREV
			if ( $navigation_mode === 1 && ! empty( $navigation['prev'] ) ) {
				$html .= '<a href="' . jpcrm_esc_link( $key, $navigation['prev'], 'zerobs_company', false ) . '" class="jpcrm-button transparent-bg font-14px"><i class="fa fa-chevron-left"></i>&nbsp;&nbsp;' . esc_html( __( 'Prev', 'zero-bs-crm' ) ) . '</a>';
			}
			// If in edit mode, show view link
			if ( $key === 'edit' && $id > 0 ) {
				$html .= '<a style="margin: 0 5px;" class="jpcrm-button transparent-bg font-14px" href="' . jpcrm_esc_link( 'view', $id, ZBS_TYPE_COMPANY ) . '">' . esc_html( __( 'View company', 'zero-bs-crm' ) ) . '</a>';
			}
			if ( $navigation_mode === 1 && ! empty( $navigation['next'] ) ) {
				$html .= '<a href="' . jpcrm_esc_link( $key, $navigation['next'], 'zerobs_company', false ) . '" class="jpcrm-button transparent-bg font-14px">' . esc_html( __( 'Next', 'zero-bs-crm' ) ) . '&nbsp;&nbsp;<i class="fa fa-chevron-right"></i></a>';
			}

			break;

		case ZBS_TYPE_QUOTE:
		case ZBS_TYPE_INVOICE:
		case ZBS_TYPE_TRANSACTION:
			break;
	}

	return $html;
}

/*
======================================================
	/ Object Nav
	====================================================== */

/**
 * Return table options button
 */
function get_jpcrm_table_options_button() {
	return '<button class="jpcrm-button transparent-bg font-14px" type="button" id="jpcrm_table_options">' . esc_html__( 'Table options', 'zero-bs-crm' ) . '&nbsp;<i class="fa fa-cog"></i></button>';
}

/*
======================================================
	Tasks
	====================================================== */

function zeroBSCRM_html_taskStatusLabel( $task = array() ) {

	if ( isset( $task['complete'] ) && $task['complete'] === 1 ) {
		return 'ui green label';
	}

	return 'ui grey label';
}

/**
 * Returns a task datetime range string
 *
 * @param array $task Task array.
 *
 * @return string datetime range string
 */
function zeroBSCRM_html_taskDate( $task = array() ) {

	if ( ! isset( $task['start'] ) ) {

		// task doesn't have start date...not sure why this would ever happen
		$task_start = jpcrm_uts_to_datetime_str( time() + 3600 );
		$task_end   = jpcrm_uts_to_datetime_str( $task_start + 3600 );

	} else {

		$task_start = jpcrm_uts_to_datetime_str( $task['start'] );
		$task_end   = jpcrm_uts_to_datetime_str( $task['end'] );

	}

	return $task_start . ' - ' . $task_end;
}

/*
======================================================
	/ Tasks
	====================================================== */

/*
======================================================
	Email History
	====================================================== */

function zeroBSCRM_outputEmailHistory( $user_id = -1 ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid,Squiz.Commenting.FunctionComment.Missing,Squiz.Commenting.FunctionComment.WrongStyle

	global $zbs;

	// get the last 50 (can add pagination later...)
	$email_hist = zeroBSCRM_get_email_history( 0, 50, $user_id );
	?>
	<style>
		.zbs-email-sending-record {
			margin-bottom:0.8em;
		}
		.zbs-email-sending-record .avatar{
			margin-left: 5px;
			border-radius: 50%;
		}
		.zbs-email-detail {
			width: 80%;
			display: inline-block;
		}
	</style>
	<?php

	if ( count( $email_hist ) === 0 ) {
		echo '<div class="ui message"><i class="icon envelope outline"></i>' . esc_html( __( 'No Recent Emails', 'zero-bs-crm' ) ) . '</div>';
	}

	foreach ( $email_hist as $em_hist ) {

		$email_details_html = '';

		$email_subject = zeroBSCRM_mailTemplate_getSubject( $em_hist->zbsmail_type );
		$emoji         = '🤖';

		if ( $email_subject === '' ) {
			// then this is a custom email
			$email_subject = $em_hist->zbsmail_subject;
			$emoji         = '😀';
		}

		// if still empty
		if ( empty( $email_subject ) ) {
			$email_subject = esc_html__( 'Untitled', 'zero-bs-crm' );
		}
		$email_details_html .= '<div class="zbs-email-sending-record">';
		$email_details_html .= '<span class="label blue ui tiny hist-label" style="float:left"> ' . esc_html( __( 'sent', 'zero-bs-crm' ) ) . ' </span>';
		$email_details_html .= '<div class="zbs-email-detail">' . esc_html( $emoji );
		$email_details_html .= ' <strong>' . esc_html( $email_subject ) . '</strong><br />';
		$email_details_html .= '<span class="sent-to">' . esc_html( __( ' sent to ', 'zero-bs-crm' ) ) . '</span>';

		// -10 are the system emails sent to CUSTOMERS
		if ( $em_hist->zbsmail_sender_wpid === '-10' ) {
			$customer = zeroBS_getCustomerMeta( $em_hist->zbsmail_target_objid );
			if ( ! $customer ) {
				continue;
			}

			$link = admin_url( 'admin.php?page=' . $zbs->slugs['addedit'] . '&action=view&zbsid=' . $em_hist->zbsmail_target_objid );
			if ( $customer['fname'] === '' && $customer['lname'] === '' ) {
				$email_details_html .= '<a href="' . esc_url( $link ) . '">' . esc_html( $customer['email'] ) . '</a>';
			} else {
				$email_details_html .= '<a href="' . esc_url( $link ) . '">' . esc_html( $customer['fname'] . ' ' . $customer['lname'] ) . '</a>';
			}
		} elseif ( $em_hist->zbsmail_sender_wpid === '-11' ) {
			// quote proposal accepted (sent to admin...)
			$user_obj = get_user_by( 'ID', $em_hist->zbsmail_target_objid );
			if ( ! $user_obj ) {
				continue;
			}

			$email_details_html .= esc_html( $user_obj->data->display_name );
			$email_details_html .= jpcrm_get_avatar( $em_hist->zbsmail_target_objid, 20 );
		} elseif ( $em_hist->zbsmail_sender_wpid === '-12' ) {
			// quote proposal accepted (sent to admin...) -12 is the you have a new quote...
			$customer = zeroBS_getCustomerMeta( $em_hist->zbsmail_target_objid );
			if ( ! $customer ) {
				continue;
			}

			$link = admin_url( 'admin.php?page=' . $zbs->slugs['addedit'] . '&action=view&zbsid=' . $em_hist->zbsmail_target_objid );
			if ( $customer['fname'] === '' && $customer['lname'] === '' ) {
				$email_details_html .= '<a href="' . esc_url( $link ) . '">' . esc_html( $customer['email'] ) . '</a>';
			} else {
				$email_details_html .= '<a href="' . esc_url( $link ) . '">' . esc_html( $customer['fname'] . ' ' . $customer['lname'] ) . '</a>';
			}
		} elseif ( $em_hist->zbsmail_sender_wpid === '-13' ) {
			// -13 is the task notification (sent to the OWNER of the task) so a WP user (not ZBS contact)...
			$user_obj = get_user_by( 'ID', $em_hist->zbsmail_target_objid );
			if ( ! $user_obj ) {
				continue;
			}

			$email_details_html .= esc_html( $user_obj->data->display_name );
			$email_details_html .= jpcrm_get_avatar( $em_hist->zbsmail_target_objid, 20 );
		} else {
			$customer = zeroBS_getCustomerMeta( $em_hist->zbsmail_target_objid );
			if ( ! $customer ) {
				continue;
			}

			// then it is a CRM team member [team member is quote accept]....
			$link = admin_url( 'admin.php?page=' . $zbs->slugs['addedit'] . '&action=view&zbsid=' . $em_hist->zbsmail_target_objid );
			if ( $customer['fname'] === '' && $customer['lname'] === '' ) {
				$email_details_html .= '<a href="' . esc_url( $link ) . '">' . esc_html( $customer['email'] ) . '</a>';
			} else {
				$email_details_html .= '<a href="' . esc_url( $link ) . '">' . esc_html( $customer['fname'] . ' ' . $customer['lname'] ) . '</a>';
			}

			$user_obj = get_user_by( 'ID', $em_hist->zbsmail_sender_wpid );
			if ( ! $user_obj ) {
				continue;
			}

			$email_details_html .= esc_html( __( ' by ', 'zero-bs-crm' ) . $user_obj->data->display_name );
			$email_details_html .= jpcrm_get_avatar( $em_hist->zbsmail_sender_wpid, 20 );
		}
		$unixts = gmdate( 'U', $em_hist->zbsmail_created );
		$diff   = human_time_diff( $unixts, time() );

		$email_details_html .= '<time>' . esc_html( $diff . __( ' ago', 'zero-bs-crm' ) ) . '</time>';
		if ( $em_hist->zbsmail_opened === '1' ) {
			$email_details_html .= '<span class="ui green basic label mini" style="margin-left:7px;"><i class="icon check"></i> ' . esc_html( __( 'opened', 'zero-bs-crm' ) ) . '</span>';
		}
		$email_details_html .= '</div></div>';

		echo $email_details_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}
}

/*
======================================================
	/ Email History
	====================================================== */

/*
======================================================
	Edit Pages Field outputter
	====================================================== */

	// puts out edit fields for an object (e.g. quotes)
	// centralisd/genericified 20/7/18 wh 2.91+
function zeroBSCRM_html_editFields( $objArr = false, $fields = false, $postPrefix = 'zbs_', $skipFields = array() ) {

	if ( is_array( $fields ) ) {

		foreach ( $fields as $fieldK => $fieldV ) {

			// we skip some when we put them out specifically/manually in the metabox/ui
			if ( ! in_array( $fieldK, $skipFields ) ) {
				zeroBSCRM_html_editField( $objArr, $fieldK, $fieldV, $postPrefix );
			}
		}
	}
}

	// puts out edit field for an object (e.g. quotes)
	// centralisd/genericified 20/7/18 wh 2.91+
function zeroBSCRM_html_editField( $dataArr = array(), $fieldKey = false, $fieldVal = false, $postPrefix = 'zbs_' ) {
	 // phpcs:disable
   	/* debug
   	if ($fieldKey == 'house-type') {
	 echo '<tr><td colspan="2">'.$fieldKey.'<pre>'.print_r(array($fieldVal,$dataArr),1).'</pre></td></tr>';
   	} */

	 if (!empty($fieldKey) && is_array($fieldVal)){

		// infer a default (Added post objmodels v3.0 as a potential.)
		$default = ''; if (is_array($fieldVal) && isset($fieldVal['default'])) $default = $fieldVal['default'];

		// get a value (this allows field-irrelevant global tweaks, like the addr catch below...)
		// -99 = notset
		$value = -99; if (isset($dataArr[$fieldKey])) $value = $dataArr[$fieldKey];

		// custom classes for inputs
		$inputClasses = isset($fieldVal['custom-field']) ? ' zbs-custom-field' : '';

		// contacts got stuck in limbo as we upgraded db in 2 phases. 
		// following catches old str and modernises to v3.0
		// make addresses their own objs 3.0+ and do away with this.
		// ... hard typed to avoid custom field collisions, hacky at best.
		switch ($fieldKey){

	   case 'secaddr1':
						if (isset($dataArr['secaddr_addr1'])) $value = $dataArr['secaddr_addr1'];
			break;

		case 'secaddr2':
	   					 if (isset($dataArr['secaddr_addr2'])) $value = $dataArr['secaddr_addr2'];
			 break;

		  case 'seccity':
							   if (isset($dataArr['secaddr_city'])) $value = $dataArr['secaddr_city'];
			   break;

			case 'seccounty':
							if (isset($dataArr['secaddr_county'])) $value = $dataArr['secaddr_county'];
			   break;

		   case 'seccountry':
						  if (isset($dataArr['secaddr_country'])) $value = $dataArr['secaddr_country'];
				break;

			case 'secpostcode':
						  if (isset($dataArr['secaddr_postcode'])) $value = $dataArr['secaddr_postcode'];
				break;
			}

		global $zbs;

		switch ( $fieldVal[0] ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
			 case 'text':
				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<div class="zbs-text-input <?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>">
								<input
									type="text"
									name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									id="<?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									class="form-control widetext zbs-dc<?php echo esc_attr( $inputClasses ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									placeholder="<?php if ( isset( $fieldVal[2] ) ) echo esc_attr__( $fieldVal[2], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>"
									value="<?php if ( $value !== -99 ) echo esc_attr( $value ); else echo esc_attr( $default ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, Squiz.PHP.EmbeddedPhp.MultipleStatements ?>"
									autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>"
								/>
						</div>
						</div>
				<?php

					break;

				case 'price':

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<div class="jpcrm-form-input-group">
			  <?php echo esc_html( zeroBSCRM_getCurrencyChr() ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>
								<input
									type="text"
									name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									id="<?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									class="form-control numbersOnly zbs-dc<?php echo esc_attr( $inputClasses ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									placeholder="<?php if ( isset( $fieldVal[2] ) ) echo esc_attr__( $fieldVal[2], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>"
									value="<?php if ( $value !== -99 ) echo esc_attr( $value ); else echo esc_attr( $default ); // phpcs:ignore Squiz.PHP.EmbeddedPhp.MultipleStatements ?>"
									autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>"
								/>
						</div>
					</div>
				<?php

					break;

				case 'numberfloat':

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<input
							type="text"
							name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
							id="<?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
							class="form-control numbersOnly zbs-dc<?php echo esc_attr( $inputClasses ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
							placeholder="<?php if ( isset( $fieldVal[2] ) ) echo esc_attr__( $fieldVal[2], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>"
							value="<?php if ( $value !== -99 ) echo esc_attr( $value ); else echo esc_attr( $default ); // phpcs:ignore Squiz.PHP.EmbeddedPhp.MultipleStatements ?>"
							autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>"
						/>
						</div>
			   <?php

					 break;

				case 'numberint':

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
								<input
									type="text"
									name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									id="<?php echo esc_attr( $fieldKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									class="form-control intOnly zbs-dc<?php echo esc_attr( $inputClasses ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"
									placeholder="<?php if ( isset( $fieldVal[2] ) ) echo esc_attr__( $fieldVal[2], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>"
									value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); // phpcs:ignore Squiz.PHP.EmbeddedPhp.MultipleStatements ?>"
									autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>"
								/>
						</div>
				<?php
					break;

			 case 'date':
				$datevalue = '';
				if ( $value !== -99 ) {
					$datevalue = jpcrm_uts_to_date_str( $value, 'Y-m-d', true );
				 }

				// if this is a custom field, and is unset, we let it get passed as empty (gh-56)
				if ( isset( $fieldVal['custom-field'] ) && ( $value === -99 || $value === '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
					$datevalue = '';
				 }
				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
							<input type="date" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" placeholder="yyyy-mm-dd" value="<?php echo esc_attr( $datevalue ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase ?>"/>
						</div>
				<?php

					   break;


				case 'datetime':

			 $datevalue = ''; if ($value !== -99) $datevalue = $value; 

			 $datevalue = zeroBSCRM_date_i18n_plusTime(-1,$datevalue,true);

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control jpcrm-date-time zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php echo esc_attr( $datevalue ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />
						</div>
			   <?php

					 break;

				case 'select':
			   //don't load prefix select if prefix is hidden in settings
			   if ($zbs->settings->get('showprefix') == 0 && $fieldKey == 'prefix') {
					break;
				 }

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<select name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-watch-input zbs-dc<?php echo esc_attr( $inputClasses ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>">
				<?php
				// pre DAL 2 = $fieldV[3], DAL2 = $fieldV[2]
				$options = false; 
				if (isset($fieldVal[3]) && is_array($fieldVal[3])) {
					   $options = $fieldVal[3];
				   } else {
				  // DAL2 these don't seem to be auto-decompiled?
				  // doing here for quick fix, maybe fix up the chain later.
				  if (isset($fieldVal[2])) $options = explode(',', $fieldVal[2]);
				   }

				//if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
				if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){

					   // if $default, use that
					   $selectVal = '';
					   if ($value !== -99 && !empty($value)){
					  $selectVal = $value;
						 } elseif (!empty($default))
						   $selectVal = $default;

					   //catcher
													   echo '<option value=""' . ($fieldKey == 'prefix' ? '' :' disabled="disabled"');
					   if (empty($default) && ($value == -99 || ($value !== -99 && empty($value)))) echo ' selected="selected"';
					   echo '>'. esc_html__('Select','zero-bs-crm').'</option>';

					   foreach ($options as $opt){

					  echo '<option value="' . esc_attr( $opt ) . '"';

					  if ($selectVal == $opt) echo ' selected="selected"'; 
					  echo '>' . esc_html( $opt ) . '</option>';

						 }

				   } else echo '<option value="">'. esc_html__('No Options','zero-bs-crm').'!</option>';

			   ?>
						</select>
						<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
						</div>
			  <?php

						break;

				case 'tel':

			 // Click 2 call?
			 $click2call = $zbs->settings->get('clicktocall');

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<span class="zbs-tel-wrap">

						<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-tel zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />
				<?php if ($click2call == "1" && $value !== -99 && !empty($value)) echo '<a href="' . esc_attr( zeroBSCRM_clickToCallPrefix() . $value ) . '" class="button"><i class="fa fa-phone"></i> ' . esc_html( $value ) . '</a>'; ?>

			   <?php 

			   if ($fieldKey == 'mobtel'){

								$sms_class = 'send-sms-none';
								$sms_class = apply_filters('zbs_twilio_sms', $sms_class); 
								do_action('zbs_twilio_nonce');

								$customerMob = ''; 
								// wh genericified 
								//if (is_array($dataArr) && isset($dataArr[$fieldKey]) && isset($dataArr['id'])) $customerMob = zeroBS_customerMobile($dataArr['id'],$dataArr);
								if ($value !== -99) $customerMob = $value;
												
								if (!empty($customerMob)) echo '<a class="' . esc_attr( $sms_class ) . ' button" data-smsnum="' . esc_attr( $customerMob ) .'"><i class="mobile alternate icon"></i> '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . '</a>';

				  }

			   ?>
						</span>
						</div>
				<?php

						break;

				case 'email':

			 // added zbs-text-input class 5/1/18 - this allows "linkify" automatic linking
			 // ... via js <div class="zbs-text-input">
			 // removed from email for now zbs-text-input

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<div class="<?php echo esc_attr( $fieldKey ); ?>">

							<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-email zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

						</div>
						</div>
			   <?php

					 break;

				case 'textarea':

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2 jpcrm-form-group jpcrm-form-group-span-2-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<textarea name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>"><?php if ($value !== -99) echo esc_textarea( $value ); else echo esc_textarea( $default ); ?></textarea>
						</div>
			   <?php

					 break;

				#} Added 1.1.19 
				case 'selectcountry':

			 $countries = zeroBSCRM_loadCountryList();

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
						<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<select name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-dc<?php echo esc_attr( $inputClasses ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>">
				<?php

				#if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
				if (isset($countries) && count($countries) > 0){

					   //catcher
					   echo '<option value=""';
					   if (empty($default) && ($value == -99 || ($value !== -99 && empty($value)))) echo ' selected="selected"';
					   echo '>'. esc_html__('Select','zero-bs-crm').'</option>';

					   foreach ($countries as $countryKey => $country){

						// temporary fix for people storing "United States" but also "US"
						// needs a migration to iso country code, for now, catch the latter (only 1 user via api)


					   echo '<option value="' . esc_attr( $country ) . '"';
					   if ($value !== -99 && (
					   strtolower($value) == strtolower($country)
					   ||
					   strtolower($value) == strtolower($countryKey)
					  )) echo ' selected="selected"'; 
					   echo '>' . esc_html( $country ) . '</option>';

						   }
									

				   } else echo '<option value="">'. esc_html__('No Countries Loaded','zero-bs-crm').'</option>';

			   ?>
						</select>
						</div>
			  <?php

						break;


					// 2.98.5 added autonumber, checkbox, radio

					// auto number - can't actually edit autonumbers, so its just outputting :)
					case 'autonumber':

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
								<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
								<span class="zbs-field-id">
			  <?php

		  // output any saved autonumber for this obj
		  $str = ''; if ($value !== -99) $str = $value;

		  // we strip the hashes saved in db for easy separation later
		  $str = str_replace('#','',$str);

		  // then output...
		  if (empty($str)) 
			   echo '~';
		  else
			   echo esc_html( $str );

		  // we also output as input, which stops any overwriting + makes new ones for new records
		  echo '<input type="hidden" value="' . esc_attr( $str ) . '" name="'. esc_attr( $postPrefix.$fieldKey ) .'" />';

			  ?>
							</span>							
							</div>
		 <?php

						break;

					// radio
					case 'radio':

				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
								<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
							<div class="zbs-field-radio-wrap">
		   <?php

			   // pre DAL 2 = $fieldV[3], DAL2 = $fieldV[2]
			   $options = false; 
			   if (isset($fieldVal[3]) && is_array($fieldVal[3])) {
									 $options = $fieldVal[3];
			  } else {
								  // DAL2 these don't seem to be auto-decompiled?
								  // doing here for quick fix, maybe fix up the chain later.
								  if (isset($fieldVal[2])) $options = explode(',', $fieldVal[2]);
			  }

			   //if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
			   if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){

											  $optIndex = 0;

											  foreach ($options as $opt){

						echo '<div class="zbs-radio"><input type="radio" name="'. esc_attr( $postPrefix.$fieldKey ) .'" id="'. esc_attr( $fieldKey.'-'.$optIndex ) .'" value="' . esc_attr( $opt ) . '"';

						if ($value !== -99 && $value == $opt) echo ' checked="checked"'; 
		echo ' /> <label class="jpcrm-form-label" for="' . esc_attr( $fieldKey . '-' . $optIndex ) . '">' . esc_html( $opt ) . '</label></div>'; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

						$optIndex++;

											  }

				} else {
								echo '<label class="jpcrm-form-label" for="' . esc_attr( $fieldKey ) . '-0">' . esc_attr__( 'No Options', 'zero-bs-crm' ) . '!</label>'; //phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
				}
			?>
							</div>
							<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
								</div>
			<?php

							break;

					// checkbox
					case 'checkbox':
				?>
						<div class="jpcrm-form-group jpcrm-form-group-span-2">
							<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>">
								<?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:
							</label>
						<div class="zbs-field-checkbox-wrap">
			<?php

				// pre DAL 2 = $fieldV[3], DAL2 = $fieldV[2]
				$options = false; 
				if (isset($fieldVal[3]) && is_array($fieldVal[3])) {
					$options = $fieldVal[3];
				} else {
					// DAL2 these don't seem to be auto-decompiled?
					// doing here for quick fix, maybe fix up the chain later.
					if (isset($fieldVal[2])) $options = explode(',', $fieldVal[2]);
				}	
										
				// split fields (multi select)
				$dataOpts = array();
				if ($value !== -99 && !empty($value)){
					$dataOpts = explode(',', $value);
				}

				//if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
				if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){

					$optIndex = 0;

					foreach ($options as $opt){

						echo '<div class="ui checkbox"><input type="checkbox" name="'. esc_attr( $postPrefix.$fieldKey.'-'.$optIndex ).'" id="'. esc_attr( $fieldKey.'-'.$optIndex ) .'" value="' . esc_attr( $opt ) . '"';
						if (in_array($opt, $dataOpts)) echo ' checked="checked"'; 
						echo ' /><label class="jpcrm-form-label" for="' . esc_attr( $fieldKey . '-' . $optIndex ) . '">' . esc_html( $opt ) . '</label></div>'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase

						$optIndex++;

					}

				} else {
					echo '<label class="jpcrm-form-label" for="' . esc_attr( $fieldKey ) . '-0">' . esc_html__( 'No Options', 'zero-bs-crm' ) . '!</label>'; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
				}

				?>
						</div>
						<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
					</div>
		 		<?php

						break;

					// tax
					case 'tax':
				?>
							<div class="jpcrm-form-group jpcrm-form-group-span-2">
							<label class="jpcrm-form-label" for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.WP.I18n.NonSingularStringLiteralText ?>:</label>
						<select name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-watch-input zbs-dc<?php echo esc_attr( $inputClasses ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>">
			  <?php

		  // retrieve tax rates + cache
		  global $zbsTaxRateTable; if (!isset($zbsTaxRateTable)) $zbsTaxRateTable = zeroBSCRM_taxRates_getTaxTableArr();

		  // if got em
		  if (isset($zbsTaxRateTable) && is_array($zbsTaxRateTable) && count($zbsTaxRateTable) > 0){

								   // if $default, use that
								   $selectVal = '';
								   if ($value !== -99 && !empty($value)){
		   $selectVal = $value;
								   } elseif (!empty($default))
									   $selectVal = $default;

								   //catcher
								   echo '<option value=""';
								   if (empty($default) && ($value == -99 || ($value !== -99 && empty($value)))) echo ' selected="selected"';
								   echo '>' . esc_html( __( 'None', 'zero-bs-crm' ) ) . '</option>';

								   foreach ($zbsTaxRateTable as $taxRate){

			echo '<option value="'. esc_attr( $taxRate['id'] ) .'"';
			if ($selectVal == $taxRate['id']) echo ' selected="selected"'; 
			echo '>' . esc_html( $taxRate['name'] . ' (' . $taxRate['rate'] . '%)' ) . '</option>';

								   }

				  } else echo '<option value="">'. esc_html__('No Tax Rates Defined','zero-bs-crm').'!</option>';

			  ?>
						</select>
						<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
						</div>
		  <?php

						break;

			} // switch

		} // if is legit params
	 // phpcs:enable
}

	// TODO: Refactor invoice edit fields.
	// phpcs:disable
   function zeroBSCRM_html_editField_for_invoices($dataArr=array(), $fieldKey = false, $fieldVal = false, $postPrefix = 'zbs_') {

   	/* debug
   	if ($fieldKey == 'house-type') {
echo '<tr><td colspan="2">'.$fieldKey.'<pre>'.print_r(array($fieldVal,$dataArr),1).'</pre></td></tr>';
   	} */

if (!empty($fieldKey) && is_array($fieldVal)){

		   // infer a default (Added post objmodels v3.0 as a potential.)
		   $default = ''; if (is_array($fieldVal) && isset($fieldVal['default'])) $default = $fieldVal['default'];

		   // get a value (this allows field-irrelevant global tweaks, like the addr catch below...)
		   // -99 = notset
		   $value = -99; if (isset($dataArr[$fieldKey])) $value = $dataArr[$fieldKey];

		   // custom classes for inputs
		   $inputClasses = isset($fieldVal['custom-field']) ? ' zbs-custom-field' : '';

			   // contacts got stuck in limbo as we upgraded db in 2 phases. 
			   // following catches old str and modernises to v3.0
			   // make addresses their own objs 3.0+ and do away with this.
			   // ... hard typed to avoid custom field collisions, hacky at best.
			   switch ($fieldKey){

	  case 'secaddr1':
						if (isset($dataArr['secaddr_addr1'])) $value = $dataArr['secaddr_addr1'];
		   break;

	  case 'secaddr2':
	   					 if (isset($dataArr['secaddr_addr2'])) $value = $dataArr['secaddr_addr2'];
		   break;

	  case 'seccity':
							   if (isset($dataArr['secaddr_city'])) $value = $dataArr['secaddr_city'];
		   break;

	  case 'seccounty':
							   if (isset($dataArr['secaddr_county'])) $value = $dataArr['secaddr_county'];
		   break;

	  case 'seccountry':
							   if (isset($dataArr['secaddr_country'])) $value = $dataArr['secaddr_country'];
		   break;

	  case 'secpostcode':
							   if (isset($dataArr['secaddr_postcode'])) $value = $dataArr['secaddr_postcode'];
		   break;
						  }
		   global $zbs;

		   switch ($fieldVal[0]){

		   case 'text':

				   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>
						<div class="zbs-text-input <?php echo esc_attr( $fieldKey ); ?>">

							<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control widetext zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

						</div>
					</td></tr><?php

					break;

		   case 'price':

					?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>

						<?php echo esc_html( zeroBSCRM_getCurrencyChr() ); ?> <input style="width: 130px;display: inline-block;" type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control numbersOnly zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default );  ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

					</td></tr><?php

					break;

		  case 'numberfloat':

					 ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>

						<input style="width: 130px;display: inline-block;" type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control numbersOnly zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

					</td></tr><?php

					break;

		  case 'numberint':

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>

						<input style="width: 130px;display: inline-block;" type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control intOnly zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

					</td></tr><?php

					break;


			case 'date':
						   $datevalue = '';

						   if ( $value !== -99 ) {
				 $datevalue = jpcrm_uts_to_date_str( $value, 'Y-m-d', true );
						   }

						   // if this is a custom field, and is unset, we let it get passed as empty (gh-56)
						   if ( isset( $fieldVal['custom-field'] ) && ( $value === -99 || $value === '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
					$datevalue = '';
						   }
					 ?>
				<tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e( $fieldVal[1], 'zero-bs-crm' ); ?>:</label></th>
				<td>
				<input type="date" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" placeholder="yyyy-mm-dd" value="<?php echo esc_attr( $datevalue ); ?>"/>
				</td></tr>
							<?php
				break;


		  case 'datetime':

					   $datevalue = ''; if ($value !== -99) $datevalue = $value; 

					   $datevalue = zeroBSCRM_date_i18n_plusTime(-1,$datevalue,true);

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>

						<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control jpcrm-date-time zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php echo esc_attr( $datevalue ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

					</td></tr><?php

					break;

		  case 'select':
									//don't load prefix select if prefix is hidden in settings
									if ($zbs->settings->get('showprefix') == 0 && $fieldKey == 'prefix') {
		break;
									}

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>
						<select name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-watch-input zbs-dc<?php echo esc_attr( $inputClasses ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>">
							<?php
								// pre DAL 2 = $fieldV[3], DAL2 = $fieldV[2]
								$options = false; 
								if (isset($fieldVal[3]) && is_array($fieldVal[3])) {
								$options = $fieldVal[3];
								} else {
								// DAL2 these don't seem to be auto-decompiled?
								// doing here for quick fix, maybe fix up the chain later.
								if (isset($fieldVal[2])) $options = explode(',', $fieldVal[2]);
								}

								//if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
								if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){

								// if $default, use that
								$selectVal = '';
								if ($value !== -99 && !empty($value)){
									$selectVal = $value;
									} elseif (!empty($default))
								$selectVal = $default;

								//catcher
								echo '<option value=""' . ($fieldKey == 'prefix' ? '' :' disabled="disabled"');
								if (empty($default) && ($value == -99 || ($value !== -99 && empty($value)))) echo ' selected="selected"';
								echo '>'. esc_html__('Select','zero-bs-crm').'</option>';

								foreach ($options as $opt){

									echo '<option value="' . esc_attr( $opt ) . '"';

									if ($selectVal == $opt) echo ' selected="selected"'; 
									echo '>' . esc_html( $opt ) . '</option>';

									}

								} else echo '<option value="">'. esc_html__('No Options','zero-bs-crm').'!</option>';

							?>
						</select>
						<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
					</td></tr><?php

					break;

		  case 'tel':

					   // Click 2 call?
					   $click2call = $zbs->settings->get('clicktocall');

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td class="zbs-tel-wrap">

						<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-tel zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />
						 <?php if ($click2call == "1" && $value !== -99 && !empty($value)) echo '<a href="' . esc_attr( zeroBSCRM_clickToCallPrefix() . $value ) . '" class="button"><i class="fa fa-phone"></i> ' . esc_html( $value ) . '</a>'; ?>

										<?php 

											if ($fieldKey == 'mobtel'){

											$sms_class = 'send-sms-none';
											$sms_class = apply_filters('zbs_twilio_sms', $sms_class); 
											do_action('zbs_twilio_nonce');

											$customerMob = ''; 
											// wh genericified 
											//if (is_array($dataArr) && isset($dataArr[$fieldKey]) && isset($dataArr['id'])) $customerMob = zeroBS_customerMobile($dataArr['id'],$dataArr);
											if ($value !== -99) $customerMob = $value;
												
											if (!empty($customerMob)) echo '<a class="' . esc_attr( $sms_class ) . ' button" data-smsnum="' . esc_attr( $customerMob ) .'"><i class="mobile alternate icon"></i> '. esc_html__('SMS','zero-bs-crm').': ' . esc_html( $customerMob ) . '</a>';

											}

											?>
					</td></tr><?php

					break;

		  case 'email':

					   // added zbs-text-input class 5/1/18 - this allows "linkify" automatic linking
					   // ... via js <div class="zbs-text-input">
					   // removed from email for now zbs-text-input

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>
						<div class="<?php echo esc_attr( $fieldKey ); ?>">

							<input type="text" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-email zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" value="<?php if ($value !== -99) echo esc_attr( $value ); else echo esc_attr( $default ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>" />

						</div>
					</td></tr><?php

					break;

		  case 'textarea':

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>
						<textarea name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-dc<?php echo esc_attr( $inputClasses ); ?>" placeholder="<?php if (isset($fieldVal[2])) echo esc_attr__($fieldVal[2],'zero-bs-crm'); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>"><?php if ($value !== -99) echo esc_textarea( $value ); else echo esc_textarea( $default ); ?></textarea>
					</td></tr><?php

					break;

		  #} Added 1.1.19 
		  case 'selectcountry':

					   $countries = zeroBSCRM_loadCountryList();

					   ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>
						<select name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-dc<?php echo esc_attr( $inputClasses ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>">
							<?php

								#if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
								if (isset($countries) && count($countries) > 0){

								//catcher
								echo '<option value=""';
								if (empty($default) && ($value == -99 || ($value !== -99 && empty($value)))) echo ' selected="selected"';
								echo '>'. esc_html__('Select','zero-bs-crm').'</option>';

								foreach ($countries as $countryKey => $country){

										// temporary fix for people storing "United States" but also "US"
										// needs a migration to iso country code, for now, catch the latter (only 1 user via api)


									echo '<option value="' . esc_attr( $country ) . '"';
									if ($value !== -99 && (
												strtolower($value) == strtolower($country)
												||
												strtolower($value) == strtolower($countryKey)
											)) echo ' selected="selected"'; 
									echo '>' . esc_html( $country ) . '</option>';

									}
									

								} else echo '<option value="">'. esc_html__('No Countries Loaded','zero-bs-crm').'</option>';

							?>
						</select>
					</td></tr><?php

					break;


			// 2.98.5 added autonumber, checkbox, radio

			// auto number - can't actually edit autonumbers, so its just outputting :)
			case 'autonumber':

				 ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
						<td class="zbs-field-id">
					 <?php

						 // output any saved autonumber for this obj
						 $str = ''; if ($value !== -99) $str = $value;

						 // we strip the hashes saved in db for easy separation later
						 $str = str_replace('#','',$str);

						 // then output...
						 if (empty($str)) 
							 echo '~';
						 else
							 echo esc_html( $str );

						 // we also output as input, which stops any overwriting + makes new ones for new records
						 echo '<input type="hidden" value="' . esc_attr( $str ) . '" name="'. esc_attr( $postPrefix.$fieldKey ) .'" />';

					  ?>
						</td></tr><?php

						break;

			// radio
			case 'radio':

				  ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
						<td>
							<div class="zbs-field-radio-wrap">
						  <?php

							  // pre DAL 2 = $fieldV[3], DAL2 = $fieldV[2]
							  $options = false; 
							  if (isset($fieldVal[3]) && is_array($fieldVal[3])) {
								$options = $fieldVal[3];
								 } else {
							 // DAL2 these don't seem to be auto-decompiled?
							 // doing here for quick fix, maybe fix up the chain later.
							 if (isset($fieldVal[2])) $options = explode(',', $fieldVal[2]);
								 }

								 //if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
								 if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){

								$optIndex = 0;

								foreach ($options as $opt){

								   echo '<div class="zbs-radio"><input type="radio" name="'. esc_attr( $postPrefix.$fieldKey ) .'" id="'. esc_attr( $fieldKey.'-'.$optIndex ) .'" value="' . esc_attr( $opt ) . '"';

									if ($value !== -99 && $value == $opt) echo ' checked="checked"'; 
									echo ' /> <label for="'. esc_attr( $fieldKey.'-'.$optIndex ) .'">' . esc_html( $opt ) . '</label></div>';

									$optIndex++;

								}

									} else echo '<label for="'. esc_attr( $fieldKey ) .'-0">'. esc_attr__('No Options','zero-bs-crm').'!</label>'; //<input type="radio" name="'.$postPrefix.$fieldKey.'" id="'.$fieldKey.'-0" value="" checked="checked" /> 

								?>
							</div>
							<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
						</td></tr><?php

						break;

		   // checkbox
		   case 'checkbox':

						 ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
						<td>
							<div class="zbs-field-checkbox-wrap">
								<?php

									// pre DAL 2 = $fieldV[3], DAL2 = $fieldV[2]
									$options = false; 
									if (isset($fieldVal[3]) && is_array($fieldVal[3])) {
									$options = $fieldVal[3];
									} else {
									// DAL2 these don't seem to be auto-decompiled?
									// doing here for quick fix, maybe fix up the chain later.
									if (isset($fieldVal[2])) $options = explode(',', $fieldVal[2]);
									}	
									
									// split fields (multi select)
									$dataOpts = array();
									if ($value !== -99 && !empty($value)){
									$dataOpts = explode(',', $value);
									}

									//if (isset($fieldVal[3]) && count($fieldVal[3]) > 0){
									if (isset($options) && is_array($options) && count($options) > 0 && $options[0] != ''){

									$optIndex = 0;

									foreach ($options as $opt){

										echo '<div class="ui checkbox"><input type="checkbox" name="'. esc_attr( $postPrefix.$fieldKey.'-'.$optIndex ).'" id="'. esc_attr( $fieldKey.'-'.$optIndex ) .'" value="' . esc_attr( $opt ) . '"';
										if (in_array($opt, $dataOpts)) echo ' checked="checked"'; 
										echo ' /><label for="'. esc_attr( $fieldKey.'-'.$optIndex ) .'">' . esc_html( $opt ) . '</label></div>';

										$optIndex++;

										}

									} else echo '<label for="'. esc_attr( $fieldKey ).'-0">'. esc_html__('No Options','zero-bs-crm').'!</label>';

								?>
							</div>
							<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
						</td></tr><?php

						break;

		   // tax
		   case 'tax':

					  ?><tr class="wh-large"><th><label for="<?php echo esc_attr( $fieldKey ); ?>"><?php esc_html_e($fieldVal[1],"zero-bs-crm"); ?>:</label></th>
					<td>
						<select name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>" id="<?php echo esc_attr( $fieldKey ); ?>" class="form-control zbs-watch-input zbs-dc<?php echo esc_attr( $inputClasses ); ?>" autocomplete="<?php echo esc_attr( jpcrm_disable_browser_autocomplete() ); ?>">
							<?php

								// retrieve tax rates + cache
								global $zbsTaxRateTable; if (!isset($zbsTaxRateTable)) $zbsTaxRateTable = zeroBSCRM_taxRates_getTaxTableArr();

								// if got em
								if (isset($zbsTaxRateTable) && is_array($zbsTaxRateTable) && count($zbsTaxRateTable) > 0){

								// if $default, use that
								$selectVal = '';
								if ($value !== -99 && !empty($value)){
									$selectVal = $value;
									} elseif (!empty($default))
								$selectVal = $default;

								//catcher
								echo '<option value=""';
								if (empty($default) && ($value == -99 || ($value !== -99 && empty($value)))) echo ' selected="selected"';
								echo '>' . esc_html( __( 'None', 'zero-bs-crm' ) ) . '</option>';

								foreach ($zbsTaxRateTable as $taxRate){

									echo '<option value="'. esc_attr( $taxRate['id'] ) .'"';
									if ($selectVal == $taxRate['id']) echo ' selected="selected"'; 
									echo '>' . esc_html( $taxRate['name'] . ' (' . $taxRate['rate'] . '%)' ) . '</option>';

									}

								} else echo '<option value="">'. esc_html__('No Tax Rates Defined','zero-bs-crm').'!</option>';

							?>
						</select>
						<input type="hidden" name="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" id="<?php echo esc_attr( $postPrefix ); ?><?php echo esc_attr( $fieldKey ); ?>_dirtyflag" value="0" />
					</td></tr><?php

					break;

				  } // switch

		} // if is legit params

   }
	// phpcs:enable

/*
======================================================
	/ Edit Pages Field outputter
	====================================================== */

/*
======================================================
	Table Views (temporary)
	(These need moving into JS globals - something like bringing the listview js into 1 model js/php obj outputter)
	====================================================== */

	// Temp here - takes a potential transaction column header
	// (can be a field key or a column key) and finds a str for title
function zeroBS_objDraw_transactionColumnHeader( $colKey = '' ) {

		global $zbsTransactionFields, $zeroBSCRM_columns_transaction;

		$ret = ucwords( str_replace( '_', ' ', $colKey ) );

		// all fields (inc custom:)
	if ( isset( $zbsTransactionFields ) && is_array( $zbsTransactionFields ) && isset( $zbsTransactionFields[ $colKey ] ) ) {

		// key => name
		$ret = $zbsTransactionFields[ $colKey ][1];

	}
		// all columns (any with same key will override)
	if ( isset( $zeroBSCRM_columns_transaction['all'] ) && is_array( $zeroBSCRM_columns_transaction['all'] ) && isset( $zeroBSCRM_columns_transaction['all'][ $colKey ] ) ) {

		// key => name
		$ret = $zeroBSCRM_columns_transaction['all'][ $colKey ][0];

	}

		return $ret;
}

	// Temp here - takes a potential transaction column + returns html
	// these are mimics of js draw funcs, move into globals (eventually)
	// hacky at best... (WH wrote to quickly satisfy Borge freelance)
function zeroBS_objDraw_transactionColumnTD( $colKey = '', $obj = false ) {

		$ret = '';

	if ( ! empty( $colKey ) && is_array( $obj ) ) {

		$linkOpen = jpcrm_esc_link( 'edit', $obj['id'], ZBS_TYPE_TRANSACTION );

		switch ( $colKey ) {

			case 'id':
				$idRef = zeroBS_objDraw_generic_id( $obj );
				if ( isset( $obj['ref'] ) ) {
					if ( ! empty( $idRef ) ) {
						$idRef .= ' - ';
					}
					$idRef .= $obj['ref'];
				}
				$ret  = '<a href="' . $linkOpen . '">' . $idRef . '</a>';
				$ret .= ! empty( $obj['title'] ) ? '<br>' . $obj['title'] : '';
				break;
			case 'editlink':
				$ret = '<a href="' . $linkOpen . '" class="ui button basic small">' . __( 'Edit', 'zero-bs-crm' ) . '</a>';
				break;
			case 'date':
				if ( isset( $obj['date_date'] ) ) {
					$ret = $obj['date_date'];
				}
				break;
			case 'item':
				$itemStr = '';
				if ( isset( $obj['meta'] ) ) {
					$itemStr = $obj['meta']['item']; // <3.0
				}
				if ( isset( $obj['title'] ) ) {
					$itemStr = $obj['title']; // 3.0
				}
				$ret = '<a href="' . $linkOpen . '">' . $itemStr . '</a>';
				break;
			case 'total':
				$total = 0;
				if ( isset( $obj['meta'] ) ) {
					$total = $obj['meta']['total']; // <3.0
				}
				if ( isset( $obj['total'] ) ) {
					$total = $obj['total']; // 3.0
				}
				$ret = zeroBSCRM_formatCurrency( $total );
				break;
			case 'status':
				$status = '';
				if ( isset( $obj['meta'] ) ) {
					$status = $obj['meta']['status']; // <3.0
				}
				if ( isset( $obj['status'] ) ) {
					$status = $obj['status']; // 3.0
				}
				$ret = "<span class='" . zeroBSCRM_html_transactionStatusLabel( $obj ) . "'>" . ucfirst( $status ) . '</span>';
				break;

		}

		// if still empty, let's try generic text
		if ( empty( $ret ) ) {
			$ret = zeroBS_objDraw_generic_text( $colKey, $obj );
		}
	}

		return $ret;
}

	// Temp here
	// these are mimics of js draw funcs, move into globals (eventually)
function zeroBS_objDraw_generic_id( $obj = false ) {

		$ret = '';

	if ( is_array( $obj ) ) {

		if ( isset( $obj['id'] ) ) {
			$ret = '#' . $obj['id'];
		}
		if ( isset( $obj['zbsid'] ) ) {
			$ret = '#' . $obj['zbsid'];
		}
	}

		return $ret;
}
function zeroBS_objDraw_generic_text( $key = '', $obj = false ) {

		$ret = '';

	if ( ! empty( $key ) && is_array( $obj ) ) {

		if ( isset( $obj[ $key ] ) ) {
			$ret = $obj[ $key ];
		}
		if ( isset( $obj['meta'] ) && is_array( $obj['meta'] ) && isset( $obj['meta'][ $key ] ) ) {
			$ret = $obj['meta'][ $key ];
		}
	}

		return $ret;
}

/*
======================================================
	/ Table Views (temporary)
	====================================================== */

	// quick workaround to turn 29999 into 2.99.99
	// noting that the real issue here is our non delimited migration numbers :facepalm:
function zeroBSCRM_format_migrationVersion( $ver = '' ) {

	// catch 3000
	$ver = str_replace( '000', '0', $ver );

	switch ( strlen( $ver ) ) {

			// catch x.x
		case 2:
			$migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 1 );
			break;
			// catch x.x.x
		case 3:
			$migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 1 ) . '.' . substr( $ver, 2 );
			break;
		case 4:
			// if second char is 0
			if ( substr( $ver, 1, 1 ) == 0 ) {

				// e.g. 3010 = 3.0.10
				$migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 1 ) . '.' . substr( $ver, 2 );

			} else {

				// e.g. 3111 = 3.11.1
				$migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 2 ) . '.' . substr( $ver, 3 );

			}

			break;

			// catch edge case 29999
		case 5:
			// e.g. 29999 = 2.99
			$migrationName = substr( $ver, 0, 1 ) . '.' . substr( $ver, 1, 2 );

			break;

		default:
			$migrationName = $ver;
			break;

	}

	return $migrationName;
}
