Tailwind purges bg-orange-500 since it's not in the safelist. Use inline style to guarantee the orange button renders. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
622 lines
27 KiB
Text
622 lines
27 KiB
Text
---
|
|
import Base from "../../layouts/Base.astro";
|
|
---
|
|
|
|
<Base
|
|
title="FCC Compliance Check — Free Telecom Filing Status"
|
|
description="Enter your FCC Registration Number (FRN) to check your RMD, CPNI, 499-A, and STIR/SHAKEN compliance status instantly. Free tool from Performance West."
|
|
>
|
|
<main class="max-w-3xl mx-auto px-4 py-10">
|
|
<!-- Breadcrumb -->
|
|
<nav class="text-sm text-gray-500 mb-6" aria-label="Breadcrumb">
|
|
<a href="/" class="hover:text-pw-600">Home</a>
|
|
<span class="mx-1">/</span>
|
|
<a href="/tools" class="hover:text-pw-600">Free Tools</a>
|
|
<span class="mx-1">/</span>
|
|
<span class="text-gray-800 font-medium">FCC Compliance Check</span>
|
|
</nav>
|
|
|
|
<!-- Header -->
|
|
<h1 class="text-3xl font-bold text-gray-900 mb-2">FCC Compliance Check</h1>
|
|
<p class="text-gray-600 mb-6">
|
|
Enter a business name or FRN below to instantly check FCC filing and compliance status.
|
|
</p>
|
|
|
|
<!-- Disclaimer -->
|
|
<div class="bg-gray-100 border border-gray-200 rounded-lg p-4 text-sm text-gray-600 mb-8">
|
|
This tool queries publicly available FCC data and is for informational purposes only.
|
|
This is not legal or compliance advice.
|
|
</div>
|
|
|
|
<!-- Search Box -->
|
|
<div class="bg-white border border-gray-200 rounded-xl p-6 shadow-sm mb-8">
|
|
<!-- Business Name Search -->
|
|
<label for="name-input" class="block text-sm font-medium text-gray-700 mb-1">Business Name</label>
|
|
<div class="flex gap-2 mb-2">
|
|
<input
|
|
type="text"
|
|
id="name-input"
|
|
placeholder="e.g. Verizon"
|
|
class="flex-1 border border-gray-300 rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-pw-500"
|
|
/>
|
|
<button
|
|
id="name-search-btn"
|
|
class="bg-pw-600 hover:bg-pw-700 text-white font-semibold px-5 py-2 rounded-lg text-sm transition"
|
|
>
|
|
Search
|
|
</button>
|
|
</div>
|
|
<div id="name-results" class="hidden mt-3"></div>
|
|
|
|
<!-- Divider -->
|
|
<div class="flex items-center gap-3 my-5">
|
|
<div class="flex-1 border-t border-gray-200"></div>
|
|
<span class="text-sm text-gray-400">or enter FRN directly</span>
|
|
<div class="flex-1 border-t border-gray-200"></div>
|
|
</div>
|
|
|
|
<!-- FRN Search -->
|
|
<label for="frn-input" class="block text-sm font-medium text-gray-700 mb-1">FCC Registration Number (FRN)</label>
|
|
<div class="flex gap-2 mb-2">
|
|
<input
|
|
type="text"
|
|
id="frn-input"
|
|
placeholder="0012345678"
|
|
maxlength="10"
|
|
class="flex-1 border border-gray-300 rounded-lg px-4 py-2 font-mono text-lg focus:outline-none focus:ring-2 focus:ring-pw-500"
|
|
/>
|
|
<button
|
|
id="frn-check-btn"
|
|
class="bg-gray-700 hover:bg-gray-800 text-white font-semibold px-5 py-2 rounded-lg text-sm transition"
|
|
>
|
|
Check Compliance
|
|
</button>
|
|
</div>
|
|
<p class="text-xs text-gray-400">
|
|
Don't know your FRN?
|
|
<a href="https://apps.fcc.gov/cores/userLogin.do" target="_blank" rel="noopener" class="text-pw-600 hover:underline">Look it up on FCC CORES</a>
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Loading -->
|
|
<div id="loading" class="hidden text-center py-10">
|
|
<svg class="animate-spin h-8 w-8 text-pw-600 mx-auto mb-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
|
|
</svg>
|
|
<p class="text-gray-500 text-sm">Checking FCC databases…</p>
|
|
</div>
|
|
|
|
<!-- Error -->
|
|
<div id="error-box" class="hidden bg-red-50 border border-red-200 rounded-lg p-4 text-red-700 text-sm mb-6">
|
|
<p id="error-message"></p>
|
|
</div>
|
|
|
|
<!-- Results -->
|
|
<div id="results" class="hidden space-y-6">
|
|
<!-- Entity Header -->
|
|
<div class="bg-white border border-gray-200 rounded-xl p-6 shadow-sm">
|
|
<h2 id="entity-name" class="text-xl font-bold text-gray-900"></h2>
|
|
<p id="entity-dba" class="text-sm text-gray-500 hidden"></p>
|
|
<p id="entity-address" class="text-sm text-gray-500 mt-1"></p>
|
|
<p class="mt-2 text-sm text-gray-600">
|
|
FRN: <span id="entity-frn" class="font-mono font-semibold text-gray-800"></span>
|
|
</p>
|
|
<div id="entity-details" class="hidden mt-3 space-y-1 text-sm text-gray-600">
|
|
<p id="detail-filer-id"></p>
|
|
<p id="detail-comm-type"></p>
|
|
<p id="detail-rmd-number"></p>
|
|
<div id="detail-provider-types" class="flex flex-wrap gap-1 mt-1"></div>
|
|
<p id="detail-usf-contributor"></p>
|
|
<p id="detail-other-frns"></p>
|
|
<p id="detail-previous-names"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Checks -->
|
|
<div id="checks-container" class="space-y-4"></div>
|
|
|
|
<!-- Prior-year catch-up -->
|
|
<div id="prior-year" class="hidden bg-red-50 border border-red-200 rounded-xl p-5 text-sm text-red-800">
|
|
<p class="font-semibold mb-1">Prior-Year Catch-Up May Be Required</p>
|
|
<p>One or more filings appear overdue. In some cases prior-year filings must be completed before the current year can be filed. Contact us for a full assessment.</p>
|
|
</div>
|
|
|
|
<!-- CTA Section -->
|
|
<div id="cta-section" class="bg-white border border-gray-200 rounded-xl p-6 shadow-sm">
|
|
<div id="cta-content"></div>
|
|
|
|
<!-- Payment Icons -->
|
|
<div id="payment-icons" class="hidden mt-5 flex flex-wrap items-center gap-3 justify-center">
|
|
<img src="/images/cards/visa.png" alt="Visa" class="h-7 opacity-70" />
|
|
<img src="/images/cards/mastercard.svg" alt="Mastercard" class="h-7 opacity-70" />
|
|
<img src="/images/cards/amex.png" alt="Amex" class="h-7 opacity-70" />
|
|
<img src="/images/cards/discover.svg" alt="Discover" class="h-7 opacity-70" />
|
|
<img src="/images/cards/paypal.svg" alt="PayPal" class="h-6 opacity-70" />
|
|
<span class="text-gray-300 mx-1">|</span>
|
|
<img src="/images/cards/bitcoin.svg" alt="Bitcoin" class="h-6 opacity-60" />
|
|
<img src="/images/cards/ethereum.svg" alt="Ethereum" class="h-6 opacity-60" />
|
|
<img src="/images/cards/usdc.svg" alt="USDC" class="h-6 opacity-60" />
|
|
<img src="/images/cards/usdt.svg" alt="USDT" class="h-6 opacity-60" />
|
|
<img src="/images/cards/litecoin.svg" alt="Litecoin" class="h-6 opacity-60" />
|
|
</div>
|
|
|
|
<!-- Reminder CTA (shown when all green) -->
|
|
<div id="reminder-cta" class="hidden mt-5 text-center">
|
|
<p class="text-sm text-gray-600 mb-3">Want a reminder before your next filing deadline?</p>
|
|
<button
|
|
id="subscribe-btn-compliance"
|
|
class="bg-pw-600 hover:bg-pw-700 text-white font-semibold px-6 py-2 rounded-lg text-sm transition"
|
|
>
|
|
Join Reminder List
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Bottom row -->
|
|
<div class="mt-6 flex flex-wrap gap-3 justify-center text-sm">
|
|
<a href="/order/new-carrier" class="inline-flex items-center gap-1.5 bg-pw-600 hover:bg-pw-700 text-white font-semibold px-4 py-2 rounded-lg transition">
|
|
<img src="/images/flags/usa.png" alt="" class="h-4" />
|
|
Start a New US Carrier
|
|
</a>
|
|
<a href="/order/new-carrier-canada" class="inline-flex items-center gap-1.5 bg-red-600 hover:bg-red-700 text-white font-semibold px-4 py-2 rounded-lg transition">
|
|
<img src="/images/flags/canada.png" alt="" class="h-4" />
|
|
Start a New Canadian Carrier
|
|
</a>
|
|
<a href="/services" class="inline-flex items-center gap-1.5 border border-gray-300 text-gray-700 hover:bg-gray-50 font-semibold px-4 py-2 rounded-lg transition">
|
|
View All Telecom Services
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Timestamp -->
|
|
<p id="checked-at" class="text-xs text-gray-400 text-center"></p>
|
|
</div>
|
|
</main>
|
|
|
|
<script type="module" is:inline>
|
|
const API = window.__PW_API || "https://api.performancewest.net";
|
|
|
|
const nameInput = document.getElementById("name-input");
|
|
const nameSearchBtn = document.getElementById("name-search-btn");
|
|
const nameResults = document.getElementById("name-results");
|
|
const frnInput = document.getElementById("frn-input");
|
|
const frnCheckBtn = document.getElementById("frn-check-btn");
|
|
const loadingEl = document.getElementById("loading");
|
|
const errorBox = document.getElementById("error-box");
|
|
const errorMessage = document.getElementById("error-message");
|
|
const resultsEl = document.getElementById("results");
|
|
|
|
// --- Name search ---
|
|
nameSearchBtn.addEventListener("click", runNameSearch);
|
|
nameInput.addEventListener("keydown", (e) => { if (e.key === "Enter") runNameSearch(); });
|
|
|
|
async function runNameSearch() {
|
|
const name = nameInput.value.trim();
|
|
if (!name) return;
|
|
|
|
nameResults.classList.remove("hidden");
|
|
nameResults.innerHTML = '<p class="text-sm text-gray-500">Searching…</p>';
|
|
|
|
try {
|
|
const res = await fetch(`${API}/api/v1/fcc/cores-search?name=${encodeURIComponent(name)}`);
|
|
if (!res.ok) throw new Error("Search failed");
|
|
const data = await res.json();
|
|
const items = data.results || data;
|
|
|
|
if (!items || items.length === 0) {
|
|
nameResults.innerHTML = '<p class="text-sm text-gray-500">No results found.</p>';
|
|
return;
|
|
}
|
|
|
|
let html = `<p class="text-xs text-gray-400 mb-2">${items.length} result${items.length !== 1 ? "s" : ""}</p>`;
|
|
html += '<div class="space-y-1 max-h-60 overflow-y-auto">';
|
|
for (const item of items) {
|
|
const label = [
|
|
item.legal_name || "",
|
|
item.dba ? `DBA: ${item.dba}` : "",
|
|
item.frn ? `FRN: ${item.frn}` : "",
|
|
item.filer_id ? `Filer ID: ${item.filer_id}` : "",
|
|
].filter(Boolean).join(" — ");
|
|
|
|
html += `<button
|
|
data-frn="${item.frn || ""}"
|
|
class="name-result-btn block w-full text-left px-3 py-2 rounded-lg text-sm hover:bg-pw-50 border border-transparent hover:border-pw-200 transition"
|
|
>${label}</button>`;
|
|
}
|
|
html += "</div>";
|
|
nameResults.innerHTML = html;
|
|
|
|
nameResults.querySelectorAll(".name-result-btn").forEach((btn) => {
|
|
btn.addEventListener("click", () => {
|
|
const frn = btn.getAttribute("data-frn");
|
|
if (!frn) {
|
|
showError("No FRN available for this entity.");
|
|
return;
|
|
}
|
|
frnInput.value = frn;
|
|
runCheck();
|
|
});
|
|
});
|
|
} catch (err) {
|
|
nameResults.innerHTML = `<p class="text-sm text-red-600">Search error: ${err.message}</p>`;
|
|
}
|
|
}
|
|
|
|
// --- FRN compliance check ---
|
|
frnCheckBtn.addEventListener("click", runCheck);
|
|
frnInput.addEventListener("keydown", (e) => { if (e.key === "Enter") runCheck(); });
|
|
|
|
async function runCheck() {
|
|
const frn = frnInput.value.trim();
|
|
if (!frn) return;
|
|
|
|
// Update URL
|
|
const url = new URL(window.location);
|
|
url.searchParams.set("frn", frn);
|
|
history.replaceState(null, "", url);
|
|
|
|
// Reset UI
|
|
resultsEl.classList.add("hidden");
|
|
errorBox.classList.add("hidden");
|
|
loadingEl.classList.remove("hidden");
|
|
|
|
try {
|
|
const res = await fetch(`${API}/api/v1/fcc/lookup?frn=${frn}`);
|
|
if (!res.ok) {
|
|
const body = await res.json().catch(() => ({}));
|
|
throw new Error(body.detail || body.error || `Lookup failed (${res.status})`);
|
|
}
|
|
const data = await res.json();
|
|
renderResults(data);
|
|
} catch (err) {
|
|
showError(err.message);
|
|
} finally {
|
|
loadingEl.classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
function showError(msg) {
|
|
errorMessage.textContent = msg;
|
|
errorBox.classList.remove("hidden");
|
|
}
|
|
|
|
// --- Render results ---
|
|
let lastData = null;
|
|
|
|
function renderResults(data) {
|
|
lastData = data;
|
|
errorBox.classList.add("hidden");
|
|
|
|
// Entity name
|
|
document.getElementById("entity-name").textContent = data.entity_name || data.legal_name || "Unknown Entity";
|
|
document.getElementById("entity-frn").textContent = data.frn || frnInput.value.trim();
|
|
|
|
// DBA
|
|
const dbaEl = document.getElementById("entity-dba");
|
|
const dbaValues = [
|
|
data.filer_499?.trade_name,
|
|
...(data.rmd?.other_dba_names || []),
|
|
].filter((v) => v && v !== "None" && v.trim() !== "");
|
|
if (dbaValues.length > 0) {
|
|
dbaEl.textContent = "DBA: " + [...new Set(dbaValues)].join(", ");
|
|
dbaEl.classList.remove("hidden");
|
|
} else {
|
|
dbaEl.classList.add("hidden");
|
|
}
|
|
|
|
// Address
|
|
const addrEl = document.getElementById("entity-address");
|
|
const coresAddr = data.cores_address || data.address;
|
|
if (coresAddr) {
|
|
addrEl.textContent = coresAddr;
|
|
} else if (data.rmd?.business_address) {
|
|
addrEl.textContent = data.rmd.business_address;
|
|
} else if (data.filer_499?.state) {
|
|
addrEl.textContent = data.filer_499.state;
|
|
} else {
|
|
addrEl.textContent = "";
|
|
}
|
|
|
|
// Details
|
|
const detailsEl = document.getElementById("entity-details");
|
|
let hasDetails = false;
|
|
|
|
function setDetail(id, label, value) {
|
|
const el = document.getElementById(id);
|
|
if (value && value !== "None" && String(value).trim() !== "") {
|
|
el.innerHTML = `<span class="font-medium text-gray-700">${label}:</span> ${value}`;
|
|
el.classList.remove("hidden");
|
|
hasDetails = true;
|
|
} else {
|
|
el.classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
setDetail("detail-filer-id", "Filer ID", data.filer_499?.filer_id || data.filer_id);
|
|
setDetail("detail-comm-type", "Comm Type", data.filer_499?.comm_type || data.comm_type);
|
|
setDetail("detail-rmd-number", "RMD Number", data.rmd?.rmd_number);
|
|
|
|
// USF Contributor
|
|
const usfRaw = data.filer_499?.usf_contributor ?? data.usf_contributor ?? null;
|
|
const usfDisplay = usfRaw === true ? "Yes" : usfRaw === false ? "No" : null;
|
|
setDetail("detail-usf-contributor", "USF Contributor", usfDisplay);
|
|
|
|
// Provider types
|
|
const ptContainer = document.getElementById("detail-provider-types");
|
|
const providerTypes = data.rmd?.provider_types || [];
|
|
if (providerTypes.length > 0) {
|
|
ptContainer.innerHTML = '<span class="font-medium text-gray-700 mr-1">Provider Types:</span>' +
|
|
providerTypes.map((t) => `<span class="inline-block bg-pw-100 text-pw-800 text-xs font-medium px-2 py-0.5 rounded-full">${t}</span>`).join("");
|
|
ptContainer.classList.remove("hidden");
|
|
hasDetails = true;
|
|
} else {
|
|
ptContainer.classList.add("hidden");
|
|
}
|
|
|
|
setDetail("detail-other-frns", "Other FRNs", data.other_frns?.join(", "));
|
|
setDetail("detail-previous-names", "Previous Names", data.previous_names?.join(", "));
|
|
|
|
if (hasDetails) {
|
|
detailsEl.classList.remove("hidden");
|
|
} else {
|
|
detailsEl.classList.add("hidden");
|
|
}
|
|
|
|
// Checks
|
|
const checksContainer = document.getElementById("checks-container");
|
|
checksContainer.innerHTML = "";
|
|
const checks = data.checks || [];
|
|
|
|
const colorMap = {
|
|
green: { bg: "bg-green-50", border: "border-green-200", iconColor: "text-green-600", textColor: "text-green-800" },
|
|
yellow: { bg: "bg-amber-50", border: "border-amber-200", iconColor: "text-amber-600", textColor: "text-amber-800" },
|
|
red: { bg: "bg-red-50", border: "border-red-200", iconColor: "text-red-600", textColor: "text-red-800" },
|
|
unknown: { bg: "bg-gray-50", border: "border-gray-200", iconColor: "text-gray-500", textColor: "text-gray-700" },
|
|
};
|
|
|
|
const icons = {
|
|
green: `<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>`,
|
|
yellow: `<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01M10.29 3.86l-8.8 15.32A1 1 0 002.36 21h19.28a1 1 0 00.87-1.5l-9.64-16.64a1 1 0 00-1.74 0z"/></svg>`,
|
|
red: `<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>`,
|
|
unknown: `<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01"/></svg>`,
|
|
};
|
|
|
|
let hasRed = false;
|
|
|
|
checks.forEach((check) => {
|
|
const status = check.status || "unknown";
|
|
if (status === "red") hasRed = true;
|
|
const c = colorMap[status] || colorMap.unknown;
|
|
const icon = icons[status] || icons.unknown;
|
|
|
|
const card = document.createElement("div");
|
|
card.className = `${c.bg} ${c.border} border rounded-xl p-4 flex items-start gap-3`;
|
|
card.setAttribute("data-check-id", check.id);
|
|
|
|
let inner = `<div class="${c.iconColor} mt-0.5 flex-shrink-0">${icon}</div>`;
|
|
inner += `<div class="flex-1">`;
|
|
inner += `<p class="font-semibold ${c.textColor}">${check.label || check.id}</p>`;
|
|
if (check.due_date) inner += `<p class="text-xs ${c.textColor} opacity-75 mt-0.5">Due: ${check.due_date}</p>`;
|
|
if (check.detail) inner += `<p class="text-sm ${c.textColor} mt-1">${check.detail}</p>`;
|
|
|
|
// BDC special
|
|
if (check.id === "bdc_filing" && status === "unknown") {
|
|
inner += `<div class="mt-3">
|
|
<p class="text-sm font-medium ${c.textColor} mb-2">Do you provide broadband internet access?</p>
|
|
<div class="flex gap-2">
|
|
<button class="bdc-yes bg-amber-500 hover:bg-amber-600 text-white text-sm font-semibold px-4 py-1.5 rounded-lg transition">Yes</button>
|
|
<button class="bdc-no bg-green-600 hover:bg-green-700 text-white text-sm font-semibold px-4 py-1.5 rounded-lg transition">No</button>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
inner += `</div>`;
|
|
card.innerHTML = inner;
|
|
|
|
// BDC button handlers
|
|
if (check.id === "bdc_filing" && status === "unknown") {
|
|
card.querySelector(".bdc-yes")?.addEventListener("click", () => {
|
|
check.status = "yellow";
|
|
const cy = colorMap.yellow;
|
|
card.className = `${cy.bg} ${cy.border} border rounded-xl p-4 flex items-start gap-3`;
|
|
card.innerHTML = `<div class="${cy.iconColor} mt-0.5 flex-shrink-0">${icons.yellow}</div>
|
|
<div class="flex-1">
|
|
<p class="font-semibold ${cy.textColor}">${check.label || check.id}</p>
|
|
${check.due_date ? `<p class="text-xs ${cy.textColor} opacity-75 mt-0.5">Due: ${check.due_date}</p>` : ""}
|
|
${check.detail ? `<p class="text-sm ${cy.textColor} mt-1">${check.detail}</p>` : ""}
|
|
</div>`;
|
|
renderCta(lastData);
|
|
});
|
|
card.querySelector(".bdc-no")?.addEventListener("click", () => {
|
|
check.status = "green";
|
|
const cg = colorMap.green;
|
|
card.className = `${cg.bg} ${cg.border} border rounded-xl p-4 flex items-start gap-3`;
|
|
card.innerHTML = `<div class="${cg.iconColor} mt-0.5 flex-shrink-0">${icons.green}</div>
|
|
<div class="flex-1">
|
|
<p class="font-semibold ${cg.textColor}">${check.label || check.id}</p>
|
|
</div>`;
|
|
});
|
|
}
|
|
|
|
checksContainer.appendChild(card);
|
|
});
|
|
|
|
// Prior-year
|
|
document.getElementById("prior-year").classList.toggle("hidden", !hasRed);
|
|
|
|
// CTA
|
|
renderCta(data);
|
|
|
|
// Timestamp
|
|
document.getElementById("checked-at").textContent = "Checked at " + new Date().toLocaleString();
|
|
|
|
// Show results
|
|
resultsEl.classList.remove("hidden");
|
|
}
|
|
|
|
// --- Render CTA (separate function) ---
|
|
function renderCta(data) {
|
|
const checks = data.checks || [];
|
|
const frn = data.frn || frnInput.value.trim();
|
|
const services = [];
|
|
|
|
for (const check of checks) {
|
|
const s = check.status || "unknown";
|
|
if (s === "green") continue;
|
|
|
|
switch (check.id) {
|
|
case "rmd_filing":
|
|
services.push({ id: "rmd_filing", name: "RMD Registration", desc: "", price: 219 });
|
|
break;
|
|
case "stir_shaken":
|
|
services.push({ id: "stir_shaken", name: "STIR/SHAKEN Implementation", desc: "", price: 499 });
|
|
break;
|
|
case "form_499a":
|
|
services.push({ id: "form_499a", name: "Form 499-A Filing", desc: "", price: 499 });
|
|
if (s === "red") {
|
|
services.push({ id: "dc_agent", name: "D.C. Registered Agent", desc: "", price: 99, priceLabel: "$99/yr" });
|
|
}
|
|
break;
|
|
case "form_499q":
|
|
services.push({ id: "form_499q", name: "Form 499-Q Filing", desc: "included with 499-A", price: 0 });
|
|
break;
|
|
case "cpni_certification":
|
|
services.push({ id: "cpni_certification", name: "CPNI Certification", desc: "", price: 149 });
|
|
break;
|
|
case "cores_registration":
|
|
if (s === "red") {
|
|
services.push({ id: "cores_registration", name: "FCC CORES Registration", desc: "included", price: 0 });
|
|
}
|
|
break;
|
|
case "bdc_filing":
|
|
if (s === "yellow") {
|
|
services.push({ id: "bdc_filing", name: "BDC / Form 477 Filing", desc: "", price: 199 });
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
const ctaContent = document.getElementById("cta-content");
|
|
const paymentIcons = document.getElementById("payment-icons");
|
|
const reminderCta = document.getElementById("reminder-cta");
|
|
|
|
if (services.length > 0) {
|
|
let html = `<h3 class="text-lg font-bold text-gray-900 mb-4">We can help fix these items</h3>`;
|
|
html += `<div class="space-y-2" id="service-list">`;
|
|
|
|
for (const svc of services) {
|
|
const checked = svc.price > 0 && svc.id !== "stir_shaken" ? "checked" : "";
|
|
const priceLabel = svc.priceLabel || (svc.price > 0 ? `$${svc.price}` : svc.desc || "included");
|
|
html += `<label class="flex items-start gap-3 p-3 rounded-lg hover:bg-gray-50 cursor-pointer transition">
|
|
<input type="checkbox" class="svc-checkbox mt-1 accent-pw-600" data-id="${svc.id}" data-price="${svc.price}" ${checked} />
|
|
<div class="flex-1">
|
|
<span class="font-medium text-gray-900">${svc.name}</span>
|
|
${svc.desc && svc.price > 0 ? `<span class="text-xs text-gray-500 ml-1">${svc.desc}</span>` : ""}
|
|
${svc.price === 0 && svc.desc ? `<span class="text-xs text-gray-500 ml-1">(${svc.desc})</span>` : ""}
|
|
</div>
|
|
<span class="font-semibold text-gray-700 text-sm whitespace-nowrap">${priceLabel}</span>
|
|
</label>`;
|
|
}
|
|
|
|
html += `</div>`;
|
|
html += `<div id="total-row" class="mt-4 pt-4 border-t border-gray-200"></div>`;
|
|
html += `<div class="mt-4 text-center">
|
|
<a id="get-started-btn" href="#" style="background:#f97316;color:#fff;font-weight:700;padding:12px 32px;border-radius:8px;box-shadow:0 4px 6px rgba(0,0,0,0.1);display:inline-block;font-size:14px;text-decoration:none;">
|
|
Get Started →
|
|
</a>
|
|
</div>`;
|
|
|
|
ctaContent.innerHTML = html;
|
|
paymentIcons.classList.remove("hidden");
|
|
reminderCta.classList.add("hidden");
|
|
|
|
// Total calculation
|
|
function updateTotal() {
|
|
const boxes = ctaContent.querySelectorAll(".svc-checkbox");
|
|
let total = 0;
|
|
let pricedCount = 0;
|
|
const selectedIds = [];
|
|
|
|
boxes.forEach((cb) => {
|
|
if (cb.checked) {
|
|
const p = parseInt(cb.dataset.price, 10);
|
|
selectedIds.push(cb.dataset.id);
|
|
if (p > 0) {
|
|
// Exclude dc_agent from discount calc
|
|
if (cb.dataset.id !== "dc_agent") {
|
|
pricedCount++;
|
|
}
|
|
total += p;
|
|
}
|
|
}
|
|
});
|
|
|
|
const totalRow = document.getElementById("total-row");
|
|
let discountHtml = "";
|
|
|
|
if (pricedCount >= 2) {
|
|
const discount = Math.round(total * 0.15);
|
|
const final_ = total - discount;
|
|
discountHtml = `<div class="flex justify-between text-sm">
|
|
<span class="text-gray-600">Subtotal</span>
|
|
<span class="text-gray-600">$${total}</span>
|
|
</div>
|
|
<div class="flex justify-between text-sm text-green-600 font-medium">
|
|
<span>15% bundle discount</span>
|
|
<span>-$${discount}</span>
|
|
</div>
|
|
<div class="flex justify-between text-lg font-bold mt-1">
|
|
<span>Total</span>
|
|
<span>$${final_}</span>
|
|
</div>`;
|
|
} else if (pricedCount === 1) {
|
|
discountHtml = `<div class="flex justify-between text-sm">
|
|
<span class="text-gray-600">Total</span>
|
|
<span class="font-semibold">$${total}</span>
|
|
</div>
|
|
<p class="text-xs text-amber-600 mt-1">Add another service for 15% off</p>`;
|
|
} else {
|
|
discountHtml = `<div class="flex justify-between text-sm">
|
|
<span class="text-gray-600">Total</span>
|
|
<span class="font-semibold">$${total}</span>
|
|
</div>`;
|
|
}
|
|
|
|
totalRow.innerHTML = discountHtml;
|
|
|
|
// Update link
|
|
const btn = document.getElementById("get-started-btn");
|
|
if (btn) {
|
|
btn.href = `/order/fcc-compliance?services=${selectedIds.join(",")}&frn=${frn}`;
|
|
}
|
|
}
|
|
|
|
ctaContent.querySelectorAll(".svc-checkbox").forEach((cb) => {
|
|
cb.addEventListener("change", updateTotal);
|
|
});
|
|
|
|
updateTotal();
|
|
} else {
|
|
ctaContent.innerHTML = `<h3 class="text-lg font-bold text-green-800 mb-2">Looking good — all checks passed</h3>
|
|
<p class="text-sm text-gray-600">Your filings appear current. No action is needed at this time.</p>`;
|
|
paymentIcons.classList.add("hidden");
|
|
reminderCta.classList.remove("hidden");
|
|
}
|
|
}
|
|
|
|
// --- Auto-fill from URL ---
|
|
(function init() {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const frn = params.get("frn");
|
|
const entity = params.get("entity");
|
|
|
|
if (frn) {
|
|
frnInput.value = frn;
|
|
runCheck();
|
|
} else if (entity) {
|
|
nameInput.value = entity;
|
|
runNameSearch();
|
|
}
|
|
})();
|
|
</script>
|
|
</Base>
|