From 73d453d78a71772af926a61979e27ee7ea806912 Mon Sep 17 00:00:00 2001 From: Samir Boulahtit Date: Thu, 2 Apr 2026 23:14:47 +0200 Subject: [PATCH] feat(hosting): prospect search dropdown on site creation form - Replace raw ID inputs with a live search dropdown that queries /admin/prospecting/prospects?search= as you type - Shows matching prospects with business name, domain, and ID - Clicking a prospect auto-fills business name, email, phone - Selected prospect shown as badge with clear button - Optional merchant ID field for existing merchants - Remove stale "Create from Prospect" link on sites list (was just a link to the prospects page) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../templates/hosting/admin/site-new.html | 99 +++++++++++++++---- .../templates/hosting/admin/sites.html | 5 - 2 files changed, 82 insertions(+), 22 deletions(-) diff --git a/app/modules/hosting/templates/hosting/admin/site-new.html b/app/modules/hosting/templates/hosting/admin/site-new.html index affc62c9..7949150e 100644 --- a/app/modules/hosting/templates/hosting/admin/site-new.html +++ b/app/modules/hosting/templates/hosting/admin/site-new.html @@ -44,25 +44,48 @@ class="w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-lg focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:focus:shadow-outline-gray dark:bg-gray-700 dark:text-gray-300"> - +
-
-
- - + +
+ + +
+ + + +
-
- - + +
+
-

At least one is required. Prospect ID auto-creates a merchant from prospect data.

+

A merchant will be auto-created from the prospect's contact data.

+
+ + +
+ +
@@ -101,20 +124,62 @@ function hostingSiteNew() { contact_phone: '', internal_notes: '', }, + // Prospect search + prospectSearch: '', + prospectResults: [], + selectedProspect: null, + showProspectDropdown: false, + creating: false, errorMsg: '', + get canCreate() { return this.form.business_name && (this.form.prospect_id || this.form.merchant_id); }, + + async searchProspects() { + if (this.prospectSearch.length < 2) { this.prospectResults = []; return; } + try { + var resp = await apiClient.get('/admin/prospecting/prospects?search=' + encodeURIComponent(this.prospectSearch) + '&per_page=10'); + this.prospectResults = resp.items || []; + this.showProspectDropdown = true; + } catch (e) { + this.prospectResults = []; + } + }, + + selectProspect(prospect) { + this.selectedProspect = prospect; + this.form.prospect_id = prospect.id; + this.prospectSearch = prospect.business_name || prospect.domain_name; + this.showProspectDropdown = false; + // Auto-fill form from prospect + if (!this.form.business_name) { + this.form.business_name = prospect.business_name || prospect.domain_name || ''; + } + if (!this.form.contact_email && prospect.primary_email) { + this.form.contact_email = prospect.primary_email; + } + if (!this.form.contact_phone && prospect.primary_phone) { + this.form.contact_phone = prospect.primary_phone; + } + }, + + clearProspect() { + this.selectedProspect = null; + this.form.prospect_id = null; + this.prospectSearch = ''; + this.prospectResults = []; + }, + async createSite() { if (!this.canCreate) { - this.errorMsg = 'Business name and at least one of Prospect ID or Merchant ID required'; + this.errorMsg = 'Business name and a linked prospect or merchant are required'; return; } this.creating = true; this.errorMsg = ''; try { - // Clean nulls var payload = {}; for (var k in this.form) { if (this.form[k] !== null && this.form[k] !== '') payload[k] = this.form[k]; diff --git a/app/modules/hosting/templates/hosting/admin/sites.html b/app/modules/hosting/templates/hosting/admin/sites.html index 0606902c..5e14cde3 100644 --- a/app/modules/hosting/templates/hosting/admin/sites.html +++ b/app/modules/hosting/templates/hosting/admin/sites.html @@ -40,11 +40,6 @@ - - - Create from Prospect -