# 📖 Setters FAQ Modal — GHL Chrome Extension Script

A **GoHighLevel Chrome Extension script** that injects a **"FAQs"** button into the GHL conversation and contact detail pages. When clicked, it opens a draggable, resizable modal displaying a specific client's account information (pulled live from a remote database) alongside a comprehensive, accordion-style **Loan Types FAQ library** — designed to help setter and rover agents quickly reference client-specific details while on a call without switching contexts.

---

## 📁 Project Structure

```
extension/
└── setters_faq.js    # Self-contained script injected into the GHL web app
```

---

## ⚙️ How It Works — Overview

```
Page Load (2-second delay on startup)
         │
         ▼
appendFAQbutton()
         │
         ├─ Check URL: only runs on /conversations/ or /contacts/detail/
         ├─ Wait for #composer-textarea to exist (retries every 2.5s)
         ├─ Check Location ID against EXCLUDED_LOCATIONS
         │   Match → skip injection entirely
         │   No match → inject "FAQs" button above the composer
         │
         ▼
renderFAQHTMLModals() called once on startup
         │
         └─ Injects the full modal HTML into #app
              ├─ Client info panel (left)
              ├─ Loan details panel (right)
              ├─ Loan Types FAQ accordion (scrollable)
              ├─ Questions to ask (per loan type)
              └─ Draggable + resizable popup behavior

Agent clicks "FAQs"
         │
         ▼
modal_endchatFaqs()
         │
         ├─ GET /locations/{locationId}          → GHL location details
         ├─ POST kangaroo.growsimple.io/api.php  → Client FAQ data by GS Location ID
         ├─ GET GHL Surveys API                  → Onboarding checklist lookup by email
         │
         ├─ Populate modal fields (client info + FAQ fields)
         └─ Show modal
```

---

## 🧩 Features

### 1. Location-Scoped Button Injection

The script injects a `"FAQs"` button directly above the GHL conversation composer. Injection is **blocked** for specific excluded locations:

```javascript
const EXCLUDED_LOCATIONS = [
  "ynCWf3Y4AEJ7hfQ4lVWE",   // Media Simplified client success account
  "Yjkpt82b8Vqjm10Ir9tD",   // Sales account
];
```

**Injection behavior:**
- Only fires on `/conversations/conversations` and `/contacts/detail/` URLs
- Polls every 2.5 seconds for `#composer-textarea` to appear (handles GHL lazy rendering)
- Removes any existing `#endc-tabFaqs` element before re-injecting — prevents duplicates on route changes
- Listens to GHL's `routeChangeEvent` and re-runs `appendFAQbutton` after a 2-second delay
- Also fires once on initial script load after a 2-second startup delay

---

### 2. FAQ Modal — Client Info Panel (Left Side)

When the modal opens, `modal_endchatFaqs()` fetches GHL location details and then calls the remote API to load client-specific FAQ data. The left panel displays:

| Field | Element ID | Source |
|---|---|---|
| Client Name (avatar initials) | `client_name_custom_avtar` | Remote API → `faq_name` |
| Client Name (text) | `client_name_custom` | GHL location `business.name` |
| Office Location | `office_location__custom` | Remote API → `address` |
| Timezone | `timezone__custom` | Remote API → `timezone` |
| Office Hours | `office__custom` | Remote API → `office_hour` |
| Phone Number | `phone_no` | Remote API → `phone_no` |
| States Licensed In | `state_licensed` | Remote API → `state_licensed` |
| Spanish Speaking Rep? | `spanish_recps` | Remote API → `spanish_speaking` |

All fields support **double-click to edit inline** (`ondblclick="makeEditable('...')"`). If a field has no value in the remote database, it shows a `+` icon that opens an editable textarea on click.

---

### 3. FAQ Modal — Application/Loan Panel (Right Side)

The right panel shows:

| Field | Element ID | Source |
|---|---|---|
| Application Link | `application_link__custom` | Remote API → `application_link` |
| Minimum Requirements | `faq_minimum_requirements` | Remote API |
| Loan Types | `faq_loan_types` | Remote API |
| LG Sources | `faq_lg_source` | Remote API |
| Campaigns Live | `faq_campaign_live` | Remote API |
| Tempo | `faq_tempo` | Remote API |
| Additional Notes | `faq_additional_notes` | Remote API |

All fields are double-click editable with the same `makeEditable()` inline editing system.

---

### 4. Remote API Data Loading

The modal calls `kangaroo.growsimple.io/api.php` with action `get_app_link_by_location_id` and the current GHL location's internal ID (not the URL location ID — the actual `userData.location.id`):

```javascript
$.ajax({
  url: "https://kangaroo.growsimple.io/api.php",
  method: "POST",
  data: {
    action: "get_app_link_by_location_id",
    gslocationId: GSLocationId,
  },
  success: function (response) { /* populate fields */ }
});
```

The response is a JSON object containing all client FAQ configuration data stored in the Media Simplified backend database.

---

### 5. Inline Field Editing (`makeEditable`)

Any field can be edited inline by double-clicking it. When double-clicked:
1. The element's text content is replaced with a `<textarea>`
2. The textarea auto-resizes to fit its content
3. On `change` → `UpdateClientInformation(id, value)` is called immediately
4. On `blur` → if empty, shows the `+` icon again; if not empty, restores plain text

`UpdateClientInformation()` maps each element ID to a specific column name in the remote database and calls `kangaroo.growsimple.io/api.php` with action `get_live_billing_data`:

| Element ID | Database Column Updated |
|---|---|
| `client_name_custom` | Name |
| `application_link__custom` | Application Link |
| `office_location__custom` | Address |
| `timezone__custom` | Timezone |
| `office__custom` | Hours |
| `phone_no` | Phone |
| `state_licensed` | State licensed in |
| `spanish_recps` | Spanish Speaking Rep? |
| `faq_minimum_requirements` | Minimum Requirements (onboarding) |
| `faq_loan_types` | Loan Type (onboarding) |
| `faq_lg_source` | Lead Gen Sources (LG Board) |
| `faq_campaign_live` | Campaigns Live? (LG Board) |
| `faq_tempo` | Tempo (Monday Setters) |
| `faq_additional_notes` | Any other Client Notes or Details (Setters board) |

---

### 6. Loan Types FAQ Accordion

Below the client info panels, a **scrollable accordion** lists 13 mortgage/loan product types. Each accordion item shows:
- Loan type name (clickable to expand)
- **What it is** — plain-language description
- **Best for** — ideal borrower profile
- **Requirements** — qualification criteria
- A chevron toggle button (rotates when active, turns blue)

**Loan types included:**

| # | Loan Type |
|---|---|
| 1 | FHA First-Time Homebuyer Loan |
| 2 | DSCR Loan |
| 3 | Cash-Out Refinance Loan |
| 4 | Homes for Heroes |
| 5 | VA Loan |
| 6 | Hard Money Loan |
| 7 | Bridge Loan |
| 8 | HELOC (Home Equity Line of Credit) |
| 9 | Private Money Loan |
| 10 | Fix and Flip Loan |
| 11 | NOD Loans (Notice of Default) |
| 12 | First-Time Construction Loan |
| 13 | VA Refinance Loan (IRRRL) |

**Contextual question sets** appear at the bottom based on which loan type is selected:

| Loan Type Selected | Questions Shown |
|---|---|
| Cash-Out Refinance, HELOC, NOD Loans, VA Refinance | **"Questions to ask: Refi/HELOC/PNOD"** — credit score, home ownership duration, late payments, application link |
| All other loan types | **"Questions to ask: Purchase"** — credit score, annual income, down payment, realtor status, application link |

Only one question set is visible at a time. Switching loan types automatically hides/shows the appropriate set.

---

### 7. Draggable & Resizable Modal

The FAQ modal (`#popup1`) is fully **draggable** via its header bar and **resizable** via CSS `resize: both`. Dragging is implemented with native `mousedown` / `mousemove` / `mouseup` events:

- `mousedown` on `.popup-header` → starts drag, records offset from popup corner
- `mousemove` → repositions popup using `style.left` and `style.top`
- `mouseup` → cleans up event listeners, removes dragging class
- `popup.style.margin = "unset"` is called on first drag to allow absolute positioning

---

### 8. Email Iframe Scroll Fix (`addScrolling`)

A secondary utility function `addScrolling()` runs 10 seconds after startup. It:
- Observes `document.body` with a `MutationObserver` to detect when the active conversation ID changes in the URL
- On conversation change, starts polling every 3 seconds for `.new-email-thread-view` elements (GHL email thread previews)
- When an email preview is clicked, waits 2 seconds, then finds all iframes and forces `height: 100vh` if the iframe contains a `.ProseMirror` editor
- Auto-stops polling after 15 seconds or after 15 empty checks
- Fixes a GHL bug where email content iframes are too short to scroll

---

### 9. Onboarding Checklist Lookup

On modal open, `getoOnboardingChecklist(email, email_2)` calls the GHL v1 Surveys API to look up the client's onboarding survey submission by email address:

```
GET https://rest.gohighlevel.com/v1/surveys/submissions
    ?surveyId=IMbFK80bwkdXuWmcXWb1
    &q={email}
    &startAt=2020-11-14
    &endAt={today}
```

If the primary email returns zero results, it retries with the secondary email (`email_2` from `prospectInfo.email`). The result is used by `appendClientInfo()` but the data is not currently rendered into the modal UI — it is available for future use.

---

## 🔌 API Calls Summary

| Function | Endpoint | Auth | Purpose |
|---|---|---|---|
| `getuserdetails()` | `GET /locations/{locationId}` | GHL token | Fetch location name, email, business info |
| `modal_endchatFaqs()` | `POST kangaroo.growsimple.io/api.php` | None (server-side) | Load client FAQ data by GS Location ID |
| `UpdateClientInformation()` | `POST kangaroo.growsimple.io/api.php` | None (server-side) | Save edited field value to remote database |
| `getoOnboardingChecklist()` | `GET rest.gohighlevel.com/v1/surveys/...` | Bearer JWT (hardcoded) | Look up onboarding survey submission by email |

---

## 🗂️ Helper Functions

| Function | Description |
|---|---|
| `getLocationId()` | Extracts Location ID from GHL URL path (`/location/{id}/`) |
| `getInitials(name)` | Returns two-character uppercase initials from a full name (e.g., "John Doe" → "JD") |
| `setTextOrAddIcon(id, value)` | Sets element text if value exists; shows a clickable `+` icon if empty |
| `showAddIcon(id)` | Renders a blue `+` icon that triggers `makeEditable()` on click |
| `makeEditable(id)` | Replaces element content with an auto-resizing textarea; saves on change, restores on blur |
| `formatDate(dateStr)` | *(imported from shared script)* — not defined in this file but used via global scope |
| `renderFAQHTMLModals()` | Returns the complete modal HTML string (client panels + loan FAQ accordion + styles) |

---


## ⚡ Initialization Sequence

```javascript
// 1. After 2 seconds on script load:
setTimeout(() => {

  // Inject FAQ button into GHL header
  appendFAQbutton();

  // Render modal HTML into #app (only once — guard check prevents duplicates)
  if (no modal exists) {
    document.querySelector("#app").insertAdjacentHTML("beforeend", renderFAQHTMLModals());

    // Attach accordion click handlers to all .faq elements
    // Attach toggle handlers to all .faq-toggle buttons
    // Initialize draggable popup behavior on .popup-header
    // Schedule addScrolling() to run after 10 more seconds
  }

}, 2000);

// 2. On every GHL SPA route change (with 2s delay):
window.addEventListener("routeChangeEvent", () => {
  setTimeout(appendFAQbutton, 2000);
});
```
