| {% comment %} Selects this page, not the whole filter. A "select every matching contact" affordance would promise a bulk action over a set the endpoint caps at 500 — targeting a whole segment is a broadcast's shape (issue #23), not a checkbox on a list. {% endcomment %} | Contact | Channels | Tags | Last active | Status |
|---|---|---|---|---|---|
| {% comment %} A round initial rather than the 4px platform square the row used to lead with: the channel belongs in the Channels column, and what a reader scans a contact list for is people. {% endcomment %} {{ contact.display_name|make_list|first|upper }} {{ contact.display_name }} {% if contact.email %} {% elif contact.phone %} {% else %}{% endif %} | {% for platform in contact.channel_platforms %} {% include "partials/_platform_icon.html" with platform=platform size="sm" %} {% empty %} None {% endfor %} | {% for tag in contact.tags.all %}{{ tag.name }}{% empty %}None{% endfor %} | {% if contact.last_interaction_at %}{{ contact.last_interaction_at|timesince }} ago{% else %}Never{% endif %} | {% comment %} Whether they may be messaged, as a status pill (HANDOFF §3, Contacts) — the same words the Filter popover's Status group uses. The column used to be headed "Opt-in" and then "Contactable"; what a reader wants to know is whether they may message this person. Still two independent facts, never an if/elif chain. `has_opt_in` and `has_opted_out` can both be true — a contact can have consented on Telegram and opted out on SMS — and `annotate_reachability`'s docstring says collapsing them "would have to pick which one to lie about". An elif did exactly that: it hid a still-reachable channel behind the opt-out and read as though the contact were unreachable. The mixed case gets its own sentence instead. {% endcomment %} {% if contact.has_opt_in and contact.has_opted_out %} On some channels {% elif contact.has_opt_in %} Subscribed {% elif contact.has_opted_out %} Opted out {% else %} Not yet {% endif %} |
Page {{ page.number }} of {{ page.paginator.num_pages }}. {{ page.paginator.count }} contact{{ page.paginator.count|pluralize }} in all. {% if page.has_previous %} Previous {% endif %} {% if page.has_next %} Next {% endif %}
{% else %} {% if query.is_filtered or query.segment %} {% url 'contacts:list' workspace_id=request.workspace.id as everyone_url %} {% include "components/empty_state.html" with icon="search" title="No contacts match this filter." body="Try a different word, or clear the filters." action_label="Clear filters" action_url=everyone_url %} {% else %} {% include "components/empty_state.html" with icon="contacts" title="No contacts yet" body="They arrive when someone messages a connected channel, or when you import a CSV." %} {% endif %} {% endif %}