From a6413da67a4579866f0fd0323ddb23a7b6b9654a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 18 Sep 2026 17:00:53 +0000
Subject: [PATCH] =Cleaning up the Integrations setup a bit, started the Helcim integration work too

---
 inc/integrations/Admin.php |  140 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 107 insertions(+), 33 deletions(-)

diff --git a/inc/integrations/Admin.php b/inc/integrations/Admin.php
index 122a459..cb9efdf 100644
--- a/inc/integrations/Admin.php
+++ b/inc/integrations/Admin.php
@@ -9,6 +9,7 @@
 
 trait Admin {
 	use _Base;
+	protected bool $canTest = false;
 	//An array of AdminAction objects
 	protected array $actions = [];
 	protected array $instructions = [];
@@ -22,18 +23,33 @@
 				'label'		=> 'Save Changes',
 				'icon'		=> 'floppy-disk',
 				'action'	=> [$this, 'saveCredentials']
-			],
-			[
-				'name'		=> 'Clear Credentials',
-				'icon'		=> 'broom',
-				'action'	=> [$this, 'clearCredentials']
-			],
+			]
 		];
+		if ($this->isSetUp()) {
+			$actions[] = [
+				'name'		=> 'Clear Credentials',
+				'label'		=> 'Clear Credentials',
+				'icon'		=> 'broom',
+				'action'	=> [$this, 'deleteCredentials']
+			];
+		}
+		if ($this->canTest) {
+			$actions[] = [
+				'name'	=> 'Test Connection',
+				'label'	=> 'Test Connection',
+				'icon'	=> 'plugs-connected',
+				'action'	=> [$this, 'testConnectionAction']
+			];
+		}
 		foreach ($actions as $a) {
 			$this->addAction($a['name'], $a['action'], $a['slug']??null, $a['icon']??null, $a['label']??null);
 		}
+
+		$this->defineActions();
 	}
 
+	abstract protected function defineActions():void;
+
 	public function addAction(string $name, callable $callback, ?string $slug = null, ?string $icon = null, ?string $label = null):void
 	{
 		$action = new AdminActions($name, $callback);
@@ -78,17 +94,10 @@
 		return $result;
 	}
 
-	public function response(bool $success, string $message):array
-	{
-		return [
-			'success'	=> $success,
-			'message'	=> $message
-		];
-	}
 
-	public function renderConnection():string
+	public function renderConnection(bool $return = false):string
 	{
-		if ($this->userID && !JVB()->userCanConnect($this->service_name, $this->userID)) {
+		if ($this->userID && !$this->userCanConnect($this->userID)) {
 			return '';
 		}
 
@@ -96,13 +105,28 @@
 		$isConnected = !empty($credentials);
 
 		$meta = '';
-		if ($isConnected && array_key_exists('updated_at', $credentials) && $credentials['updated_at'] > 0) {
-			$meta = sprintf(
-			'<div class="meta">
-					<small>Last updated: %s ago</small>
-				</div>',
-				human_time_diff($credentials['updated_at'])
-			);
+		if ($isConnected) {
+			$updated = Auth::getInstance()->getLastUpdated($this->service_name, $this->userID);
+			$meta = [];
+			if ($updated) {
+				$meta[] = sprintf(
+				'<small>Last updated: %s ago</small>',
+					human_time_diff(strtotime($updated))
+				);
+			}
+			$tested = Auth::getInstance()->getLastTested($this->service_name, $this->userID);
+			if ($tested && $tested !== '0000-00-00 00:00:00') {
+				$meta[] = sprintf(
+					'<small>Last tested: %s ago</small>',
+					human_time_diff(strtotime($tested))
+				);
+			}
+			if (!empty($meta)) {
+				$meta = sprintf(
+					'<div class="meta">%s</div>',
+					implode('<br>', $meta)
+				);
+			}
 		}
 
 		$form = sprintf(
@@ -124,7 +148,7 @@
 			$meta,
 		);
 
-		if (!empty($this->instructions)) {
+		if (!$this->isSetUp() && !empty($this->instructions)) {
 			$form .= sprintf(
 				'<details%s>
 					<summary>Instructions</summary>
@@ -132,13 +156,22 @@
 				</details>',
 				$isConnected ? '' : ' open',
 				implode('',array_map(function($el) {
+					if (is_array($el)) {
+						$bits = implode('', array_map(function ($b) {
+							return sprintf('<li>%s</li>', $b);
+						}, $el));
+						return sprintf('<ol>%s</ol>', $bits);
+					}
 					return sprintf('<li>%s</li>', $el);
 				}, $this->instructions))
 			);
 		}
 
+		$setupFields = array_filter($this->fields, function($field) {
+			return $field->isSetupField();
+		});
 
-		if (current_user_can('manage_options')) {
+		if ((method_exists($this, 'userCanConnect') && $this->userCanConnect(get_current_user_id())) || current_user_can('manage_options')) {
 			$form .= sprintf(
 				'<details class="initial-setup"%s>
 				<summary>Setup</summary>
@@ -146,7 +179,7 @@
 				%s
 			</details>',
 				$isConnected ? '' : ' open',
-				$this->outputFields($this->credentialFields),
+				$this->outputFields($setupFields),
 				method_exists($this, 'renderWebhookUrl') ? $this->renderWebhookUrl() : ''
 			);
 		}
@@ -155,16 +188,35 @@
 			$form .= $this->renderOAuthConnectionForm();
 		}
 
-		if (!empty($this->optionalFields) || $this->hasExtraOptions) {
-			$form .= '<div class="integration-content">';
-			if (!empty($this->optionalFields)) {
-				$form .= sprintf(
+		$advancedFields = array_filter($this->fields, function($field) {
+			return $field->isAdvancedField();
+		});
+
+		if (!empty($advancedFields) && $this->isSetUp()) {
+			$form .= sprintf(
 				'<details class="advanced">
-						<summary>Advanced Settings</summary>%s</details>',
-					$this->outputFields($this->optionalFields)
+				<summary>Advanced Options</summary>
+				%s
+			</details>',
+				$this->outputFields($advancedFields),
+			);
+		}
+
+		$optionalFields = array_filter($this->fields, function($field) {
+			return $field->isAdditionalField();
+		});
+
+		if ($this->isSetUp() && (!empty($optionalFields) || $this->hasExtraOptions())) {
+			$form .= '<div class="integration-content">';
+			if (!empty($optionalFields)) {
+				$form .= sprintf(
+				'<details class="advanced"%s>
+						<summary>Optional Settings</summary>%s</details>',
+					$this->isSetUp() ? ' open' : '',
+					$this->outputFields($optionalFields)
 				);
 			}
-			if ($this->hasExtraOptions) {
+			if ($this->hasExtraOptions()) {
 				$form .= sprintf(
 					'<a href="%s" class="btn">More Settings</a>',
 					$this->determineOptionPage()
@@ -176,6 +228,10 @@
 		$form .= $this->outputActionButtons();
 		$form .= '</form>';
 
+		if (!$return) {
+			echo $form;
+		}
+
 		return $form;
 	}
 		protected function outputActionButtons():string
@@ -188,7 +244,7 @@
 				$label .= $action->getLabel();
 				return sprintf(
 					'<button type="button" data-action="%s"%s%s>%s</button>',
-					$action->getSlug,
+					$action->getSlug(),
 					$action->getName(),
 					empty($action->getConfirm()) ? '' : ' data-confirm="'.$action->getConfirm().'"',
 					$label
@@ -210,6 +266,13 @@
 			if (!empty($value)) {
 				$config['readonly'] = true;
 			}
+			if (!empty($value) && $f->isHideStored()) {
+				return sprintf(
+					'<span class="label">%s</span><code>%s</code>',
+					$config['label'],
+					preg_replace('/.(?=.{4})/', '*', $value)
+				);
+			}
 			$config['base'] = $this->service_name.'_';
 			return Form::render($f->name, $value, $f->getConfig());
 		}, $fields));
@@ -229,5 +292,16 @@
 			$this->fields[$name]->setRequired();
 			return true;
 		}
+		public function updateField(string $name, Field $field):void
+		{
+			$this->fields[$name] = $field;
+		}
+
+	public function testConnectionAction(?array $data = null):array
+	{
+		$success = $this->testConnection();
+		$message = $success ? 'Successfully tested connection' : 'Could not test connection';
+		return $this->response($success, $message);
+	}
 
 }

--
Gitblit v1.10.0