Pull groups from WhatsApp
This commit is contained in:
84
core/templates/pages/whatsapp-chat-link.html
Normal file
84
core/templates/pages/whatsapp-chat-link.html
Normal file
@@ -0,0 +1,84 @@
|
||||
{% extends "index.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container" style="max-width: 44rem;">
|
||||
<div class="level" style="margin-bottom: 0.75rem;">
|
||||
<div class="level-left">
|
||||
<div>
|
||||
<h1 class="title is-4" style="margin-bottom: 0.2rem;">WhatsApp Chat Link</h1>
|
||||
<p class="is-size-7 has-text-grey">Link a WhatsApp chat identifier to a person. This link is WhatsApp-only.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<a class="button is-light" href="{% url 'whatsapp' %}">
|
||||
<span class="icon is-small"><i class="fa-solid fa-arrow-left"></i></span>
|
||||
<span>Back To WhatsApp</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if notice_message %}
|
||||
<article class="notification is-{{ notice_level|default:'info' }} is-light">
|
||||
{{ notice_message }}
|
||||
</article>
|
||||
{% endif %}
|
||||
|
||||
<article class="box">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="field">
|
||||
<label class="label is-small">Chat Identifier</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text" name="identifier" value="{{ identifier }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-small">Existing Person</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select name="person_id">
|
||||
<option value="">- Select person -</option>
|
||||
{% for person in people %}
|
||||
<option value="{{ person.id }}" {% if existing and existing.person_id == person.id %}selected{% endif %}>{{ person.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-small">Or Create Person</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text" name="person_name" placeholder="New person name">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-small">Chat JID (optional)</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text" name="chat_jid" value="{% if existing %}{{ existing.chat_jid|default:'' }}{% endif %}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-small">Display Name (optional)</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text" name="chat_name" value="{% if existing %}{{ existing.chat_name|default:'' }}{% endif %}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="button is-link" type="submit">
|
||||
<span class="icon is-small"><i class="fa-solid fa-link"></i></span>
|
||||
<span>Save WhatsApp Chat Link</span>
|
||||
</button>
|
||||
</form>
|
||||
</article>
|
||||
|
||||
{% if existing %}
|
||||
<article class="notification is-light" style="margin-top: 0.8rem;">
|
||||
Current link: <strong>{{ existing.person.name }}</strong> ← <code>{{ existing.chat_identifier }}</code>
|
||||
</article>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -2545,18 +2545,6 @@
|
||||
return response.json();
|
||||
};
|
||||
|
||||
const getJson = async function (url) {
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" }
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error("Request failed");
|
||||
}
|
||||
return response.json();
|
||||
};
|
||||
|
||||
const titleCase = function (value) {
|
||||
const raw = String(value || "").trim().toLowerCase();
|
||||
if (!raw) {
|
||||
@@ -2639,17 +2627,6 @@
|
||||
}
|
||||
};
|
||||
|
||||
const cardContentNode = function (card) {
|
||||
return card ? card.querySelector(".compose-ai-content") : null;
|
||||
};
|
||||
|
||||
const setCardMessage = function (card, message) {
|
||||
const node = cardContentNode(card);
|
||||
if (node) {
|
||||
node.textContent = String(message || "");
|
||||
}
|
||||
};
|
||||
|
||||
const openEngage = function (sourceRef) {
|
||||
const engageCard = showCard("engage");
|
||||
if (!engageCard) {
|
||||
@@ -2669,19 +2646,19 @@
|
||||
}
|
||||
setCardLoading(card, true);
|
||||
try {
|
||||
const payload = await getJson(
|
||||
thread.dataset.draftsUrl + "?" + queryParams().toString()
|
||||
);
|
||||
const response = await fetch(thread.dataset.draftsUrl + "?" + queryParams().toString(), {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" }
|
||||
});
|
||||
const payload = await response.json();
|
||||
setCardLoading(card, false);
|
||||
if (!payload.ok) {
|
||||
setCardMessage(card, payload.error || "Failed to load drafts.");
|
||||
card.querySelector(".compose-ai-content").textContent = payload.error || "Failed to load drafts.";
|
||||
return;
|
||||
}
|
||||
const drafts = Array.isArray(payload.drafts) ? payload.drafts : [];
|
||||
const container = cardContentNode(card);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const container = card.querySelector(".compose-ai-content");
|
||||
container.innerHTML = "";
|
||||
const engageButton = document.createElement("button");
|
||||
engageButton.type = "button";
|
||||
@@ -2720,7 +2697,7 @@
|
||||
});
|
||||
} catch (err) {
|
||||
setCardLoading(card, false);
|
||||
setCardMessage(card, "Failed to load drafts.");
|
||||
card.querySelector(".compose-ai-content").textContent = "Failed to load drafts.";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2731,18 +2708,21 @@
|
||||
}
|
||||
setCardLoading(card, true);
|
||||
try {
|
||||
const payload = await getJson(
|
||||
thread.dataset.summaryUrl + "?" + queryParams().toString()
|
||||
);
|
||||
const response = await fetch(thread.dataset.summaryUrl + "?" + queryParams().toString(), {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" }
|
||||
});
|
||||
const payload = await response.json();
|
||||
setCardLoading(card, false);
|
||||
if (!payload.ok) {
|
||||
setCardMessage(card, payload.error || "Failed to load summary.");
|
||||
card.querySelector(".compose-ai-content").textContent = payload.error || "Failed to load summary.";
|
||||
return;
|
||||
}
|
||||
setCardMessage(card, String(payload.summary || ""));
|
||||
card.querySelector(".compose-ai-content").textContent = String(payload.summary || "");
|
||||
} catch (err) {
|
||||
setCardLoading(card, false);
|
||||
setCardMessage(card, "Failed to load summary.");
|
||||
card.querySelector(".compose-ai-content").textContent = "Failed to load summary.";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2753,14 +2733,17 @@
|
||||
}
|
||||
setCardLoading(card, true);
|
||||
try {
|
||||
const payload = await getJson(
|
||||
thread.dataset.quickInsightsUrl + "?" + queryParams().toString()
|
||||
const response = await fetch(
|
||||
thread.dataset.quickInsightsUrl + "?" + queryParams().toString(),
|
||||
{
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" }
|
||||
}
|
||||
);
|
||||
const payload = await response.json();
|
||||
setCardLoading(card, false);
|
||||
const container = cardContentNode(card);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const container = card.querySelector(".compose-ai-content");
|
||||
if (!payload.ok) {
|
||||
container.textContent = payload.error || "Failed to load quick insights.";
|
||||
return;
|
||||
@@ -3013,7 +2996,8 @@
|
||||
}
|
||||
} catch (err) {
|
||||
setCardLoading(card, false);
|
||||
setCardMessage(card, "Failed to load quick insights.");
|
||||
card.querySelector(".compose-ai-content").textContent =
|
||||
"Failed to load quick insights.";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3053,12 +3037,18 @@
|
||||
if (showCustom && customValue) {
|
||||
params.set("custom_text", customValue);
|
||||
}
|
||||
const payload = await getJson(
|
||||
thread.dataset.engagePreviewUrl + "?" + params.toString()
|
||||
const response = await fetch(
|
||||
thread.dataset.engagePreviewUrl + "?" + params.toString(),
|
||||
{
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" }
|
||||
}
|
||||
);
|
||||
const payload = await response.json();
|
||||
setCardLoading(card, false);
|
||||
if (!payload.ok) {
|
||||
setCardMessage(card, payload.error || "Failed to load engage preview.");
|
||||
card.querySelector(".compose-ai-content").textContent = payload.error || "Failed to load engage preview.";
|
||||
panelState.engageToken = "";
|
||||
return;
|
||||
}
|
||||
@@ -3093,11 +3083,11 @@
|
||||
if (payload.artifact) {
|
||||
text = text + "\n\nSource: " + String(payload.artifact);
|
||||
}
|
||||
setCardMessage(card, text);
|
||||
card.querySelector(".compose-ai-content").textContent = text;
|
||||
sendBtn.disabled = !(confirm.checked && panelState.engageToken);
|
||||
} catch (err) {
|
||||
setCardLoading(card, false);
|
||||
setCardMessage(card, "Failed to load engage preview.");
|
||||
card.querySelector(".compose-ai-content").textContent = "Failed to load engage preview.";
|
||||
panelState.engageToken = "";
|
||||
} finally {
|
||||
if (refreshBtn) {
|
||||
|
||||
Reference in New Issue
Block a user