feat: Leads — Button zur erstellten Vorschau-Website
- Vorschau-Button (Auge, primary) je Lead -> previewUrl der deployten Website - previewUrl live gejoint (Lead->Kunde per E-Mail->websiteProjects status deployed/ready); Preview haengt an anderem Repo als lead.repoUrl -> Kunden-Join - attachWoids -> attachLeadLinks (haengt jetzt woid + previewUrl an) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -19,10 +19,12 @@ async function listAll(collection, queries = []) {
|
||||
return out
|
||||
}
|
||||
|
||||
/** Haengt an jeden Lead die WOID seines Akquise-Tickets:
|
||||
* Lead -> Kunde (per E-Mail) -> Akquise-Workorder -> woid. Best effort;
|
||||
* am Lead selbst ist keine WOID gespeichert, daher live gejoint. */
|
||||
async function attachWoids(leads) {
|
||||
/** Haengt an jeden Lead Verweise, die nicht am Lead selbst gespeichert sind,
|
||||
* sondern ueber den Kunden verknuepft werden — via Lead -> Kunde (per E-Mail):
|
||||
* - woid: WOID des Akquise-Tickets (workorders type=Akquise)
|
||||
* - previewUrl: URL der erstellten, deployten Website (websiteProjects)
|
||||
* Best effort; Fehler brechen die Lead-Liste nicht. */
|
||||
async function attachLeadLinks(leads) {
|
||||
const norm = (l) => (l.email || l.portalLogin || '').trim().toLowerCase()
|
||||
const emails = [...new Set(leads.map(norm).filter(Boolean))]
|
||||
if (!emails.length) return leads
|
||||
@@ -57,10 +59,29 @@ async function attachWoids(leads) {
|
||||
}
|
||||
}
|
||||
|
||||
// 3) an die Leads haengen
|
||||
// 3) deployte Preview je Kunde -> URL der erstellten Website.
|
||||
// Die websiteProjects-Collection ist klein -> komplett laden + lokal zuordnen
|
||||
// (die Preview haengt am selben Kunden, aber an einem anderen Repo als lead.repoUrl).
|
||||
const customerToPreview = {}
|
||||
const idSet = new Set(customerIds)
|
||||
for (const p of await listAll(COLLECTIONS.WEBSITE_PROJECTS)) {
|
||||
if (!idSet.has(p.customerId) || customerToPreview[p.customerId]) continue
|
||||
const ready = p.status === 'deployed' || p.status === 'ready' || p.provisioningStatus === 'ready'
|
||||
const url = p.previewUrl || (p.subdomain ? `https://${p.subdomain}.project.webklar.com` : '')
|
||||
if (ready && url) customerToPreview[p.customerId] = url
|
||||
}
|
||||
|
||||
// 4) an die Leads haengen
|
||||
return leads.map((l) => {
|
||||
const hit = customerToWoid[emailToCustomer[norm(l)]]
|
||||
return hit ? { ...l, woid: hit.woid, ticketId: hit.ticketId } : l
|
||||
const cid = emailToCustomer[norm(l)]
|
||||
const t = customerToWoid[cid]
|
||||
const previewUrl = customerToPreview[cid]
|
||||
if (!t && !previewUrl) return l
|
||||
return {
|
||||
...l,
|
||||
...(t ? { woid: t.woid, ticketId: t.ticketId } : {}),
|
||||
...(previewUrl ? { previewUrl } : {}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,7 +98,7 @@ export function useLeads() {
|
||||
try {
|
||||
const out = await listAll(COLLECTIONS.LEADS, [Query.orderDesc('leadScore')])
|
||||
let enriched = out
|
||||
try { enriched = await attachWoids(out) } catch { /* WOID-Join best effort */ }
|
||||
try { enriched = await attachLeadLinks(out) } catch { /* Live-Join best effort */ }
|
||||
setLeads(enriched)
|
||||
setError(null)
|
||||
} catch (err) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
FaArrowsRotate,
|
||||
FaCheck,
|
||||
FaCopy,
|
||||
FaEye,
|
||||
FaHashtag,
|
||||
FaTriangleExclamation,
|
||||
} from 'react-icons/fa6'
|
||||
@@ -428,6 +429,11 @@ function LeadCard({ lead, pipeline, onUpdate }) {
|
||||
<FaGitAlt />
|
||||
</Button>
|
||||
)}
|
||||
{lead.previewUrl && (
|
||||
<Button size="sm" variant="primary" as="a" href={lead.previewUrl} target="_blank" rel="noreferrer" title="Erstellte Vorschau-Website öffnen (Login-geschützt)" aria-label="Vorschau öffnen">
|
||||
<FaEye />
|
||||
</Button>
|
||||
)}
|
||||
{lead.woid && (
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user