# `MishkaDocumentWeb.Templates.IssueCard`
[🔗](https://github.com/mishka-group/mishka_document/blob/v0.0.1/lib/mishka_document_web/templates/issue_card.ex#L5)

The issues list: full-width cards, each one able to open a comments panel underneath itself.

Declared only by `MishkaDocument.Issue`, and it reads that record directly rather than by column
position — a card is a specific shape (title over a type and a status badge, a description, a meta
line, and an actions cluster) that a generic position mapping cannot describe. The resource's columns
stay the field-selection contract and the sort menu's vocabulary; nothing here renders through them.

A card wears two badges — what kind of issue it is (`type_badge/1`) and where it stands
(`status_badge/1`) — and their colours are the ones the Documents dashboard's issue panel already
uses, so an issue reads the same on both pages.

## The expanded panel

`:expand` is what separates this from the other card templates. The Comment button pushes
`expand_row`, Gervaz answers by putting `AsyncResult.loading()` on `state.expanded_data` and asking
the page for the viewer, and the page hands back a `current_user`/`master_user?` pair the panel
mounts `MishkaDocumentWeb.Live.Admin.Dashboard.Issue.IssueCommentsLive` from. One row is open at a
time — that is Gervaz's rule, not ours.

The panel also carries the status machine. Which transitions an issue offers is decided by
`transitions/1` here, not by the resource: the actions themselves accept any status, so this is the
only thing standing between `:closed` and a "Mark In Progress" button.

## Features
- `:filter` - the toolbar: search, the archive switch, and an Advanced panel holding the rest
- `:select` - per-card selection for bulk operations, with a Select all row over the list
- `:bulk_actions` - bulk actions on the selected cards
- `:paginate` - the page-size picker and numbered pages under the list
- `:expand` - the comments and actions panel

Pairs with `MishkaCmsCoreWeb.UIAdapters.Admin`, which draws the archive switch and the row
actions. The furniture around the cards — the toolbar, the count row, the loading veils, the
pagination — comes from `MishkaCmsCoreWeb.Templates.CardChrome`. See
`MishkaDocumentWeb.Templates.DocumentCard`, the same idea for workspaces.

# `render_bulk_actions`

# `render_empty`

# `render_error`

# `render_filters`

# `render_header`

# `render_item`

One issue card, and the comments panel underneath it while it is the open one.

Reads the record directly rather than by column position — the resource declares this template, and
a card's shape (badges beside a title, a meta line, an actions cluster) is not a column order.

# `render_pagination`

The page-size picker on the left, the numbered pages on the right, under the list.

`change_page_size`, `prev_page` / `next_page` / `go_to_page` and every figure here are Gervaz's —
only the look is ours. A resource that asked for `:load_more` or `:infinite` instead keeps the
shared pagination, which is the only thing that knows how to draw those.

# `render_template_switcher`

# `reporter`

```elixir
@spec reporter(map()) :: String.t()
```

Who reported `issue`, for the reader whose read loaded its `:reporter` and `:reporter_master?`.

The email the reader may see, "Master" for a master, else "Unknown".

# `status_badge`

```elixir
@spec status_badge(map()) :: %{label: String.t(), chip: String.t()}
```

How an issue's status badge reads and what colour it wears — flat and uppercase, no dot.

These are the four the Documents dashboard's issue rows already use, so an issue keeps its colour
between the two pages. Falls back to `:open`, which is the attribute's own default.

# `status_label`

```elixir
@spec status_label(map()) :: String.t()
```

The words an issue's status badge reads, in the viewer's language.

# `transitions`

```elixir
@spec transitions(map()) :: [{String.t(), String.t(), String.t()}]
```

Which status changes an issue offers, in the order the panel shows them.

The resource's transition actions accept any status — they only set one — so this is the whole state
machine. An issue never offers the state it is already in, and `:closed` is a terminal state you
leave only by reopening.

# `type_badge`

```elixir
@spec type_badge(map()) :: %{label: String.t(), chip: String.t(), dot: String.t()}
```

How an issue's type badge reads and what colour it wears.

One entry per `Issue.issue_type`, and the design names five of the six — `:review_feedback` is ours
and takes the one hue the others leave free, so no two types read as each other. `issue_type` has a
default on the resource, but a record read with a narrowed field set can still arrive without it: an
issue whose type nobody chose reads as `:other` rather than taking the card down.

# `type_label`

```elixir
@spec type_label(map()) :: String.t()
```

The words an issue's type badge reads, in the viewer's language.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
