# `PhoenixKitComments`
[🔗](https://github.com/BeamLabEU/phoenix_kit_comments/blob/v0.1.3/lib/phoenix_kit_comments.ex#L1)

Standalone, resource-agnostic comments module.

Provides polymorphic commenting for any resource type (posts, entities, tickets, etc.)
with unlimited threading, likes/dislikes, and moderation support.

## Architecture

Comments are linked to resources via `resource_type` (string) + `resource_uuid` (UUID).
No foreign key constraints on the resource side — any module can use comments.

## Resource Handler Callbacks

Modules that consume comments can register handlers to receive notifications
when comments are created or deleted. Configure in your app:

    config :phoenix_kit, :comment_resource_handlers, %{
      "post" => PhoenixKitPosts
    }

Handler modules should implement `on_comment_created/3` and `on_comment_deleted/3`.

## Core Functions

### System Management
- `enabled?/0` - Check if Comments module is enabled
- `enable_system/0` - Enable the Comments module
- `disable_system/0` - Disable the Comments module
- `get_config/0` - Get module configuration with statistics

### Comment CRUD
- `create_comment/4` - Create a comment on a resource
- `update_comment/2` - Update a comment
- `delete_comment/1` - Delete a comment
- `get_comment/2`, `get_comment!/2` - Get by ID
- `list_comments/3` - Flat list for a resource
- `get_comment_tree/2` - Nested tree for a resource
- `count_comments/3` - Count comments for a resource

### Moderation
- `approve_comment/1` - Set status to published
- `hide_comment/1` - Set status to hidden
- `bulk_update_status/2` - Bulk status changes
- `list_all_comments/1` - Cross-resource listing with filters
- `comment_stats/0` - Aggregate statistics

### Like/Dislike
- `like_comment/2`, `unlike_comment/2`, `comment_liked_by?/2`
- `dislike_comment/2`, `undislike_comment/2`, `comment_disliked_by?/2`

# `approve_comment`

Sets a comment's status to published.

# `bulk_update_status`

Bulk-updates status for multiple comment UUIDs.

# `comment_disliked_by?`

Checks if a user has disliked a comment.

# `comment_liked_by?`

Checks if a user has liked a comment.

# `comment_stats`

Returns aggregate statistics for all comments.

# `count_comments`

Counts comments for a resource.

# `count_comments_by_type`

Returns comment counts grouped by resource type.

# `create_comment`

Creates a comment on a resource.

Automatically calculates depth from parent. Invokes resource handler callback
if configured.

## Parameters

- `resource_type` - Type of resource (e.g., "post")
- `resource_uuid` - UUID of the resource
- `user_uuid` - UUID of commenter
- `attrs` - Comment attributes (content, parent_uuid, etc.)

# `delete_comment`

Soft-deletes a comment by setting its status to "deleted".

Invokes resource handler callback if configured.

# `disable_system`

Disables the Comments module.

# `dislike_comment`

User dislikes a comment. Removes any existing like first.

# `enable_system`

Enables the Comments module.

# `enabled?`

Checks if the Comments module is enabled.

# `get_comment`

Gets a single comment by ID with optional preloads.

Returns `nil` if not found.

# `get_comment!`

Gets a single comment by ID with optional preloads.

Raises `Ecto.NoResultsError` if not found.

# `get_comment_tree`

Gets nested comment tree for a resource.

Returns all published comments organized in a tree structure.

# `get_config`

Gets the Comments module configuration with statistics.

# `get_max_depth`

Returns the configured maximum comment depth.

# `get_max_length`

Returns the configured maximum comment length.

# `get_resource_path_templates`

Gets configured resource templates (path + optional display title).

Returns a map of `resource_type => config`, where config is either:
- A plain string (legacy path-only format)
- A map with `"path"` and optional `"title"` keys

## Examples

    %{"shoes" => "/order/shoes/:uuid"}
    %{"shoes" => %{"path" => "/order/shoes/:uuid", "title" => ":metadata.name"}}

# `hide_comment`

Sets a comment's status to hidden.

# `like_comment`

User likes a comment. Removes any existing dislike first.

# `list_all_comments`

Lists all comments across all resource types with filters.

## Options

- `:resource_type` - Filter by resource type
- `:status` - Filter by status
- `:user_uuid` - Filter by user
- `:search` - Search in content
- `:page` - Page number (default: 1)
- `:per_page` - Items per page (default: 20)

# `list_comment_dislikes`

Lists all dislikes for a comment.

# `list_comment_likes`

Lists all likes for a comment.

# `list_comments`

Lists comments for a resource (flat list).

## Options

- `:preload` - Associations to preload
- `:status` - Filter by status

# `list_metadata_keys_by_type`

Returns distinct metadata keys grouped by resource type.

Queries the JSONB `metadata` column for all keys in use, e.g.:

    %{"manga_annotation" => ["chapter", "page", "slug", "source"],
      "post" => ["category"]}

# `list_resource_types`

Returns distinct resource types that have comments.

# `resolve_resource_context`

Resolves resource context (title and admin path) for a list of comments.

Returns a map of `{resource_type, resource_uuid} => %{title: ..., path: ...}`
by delegating to registered `comment_resource_handlers` that implement
`resolve_comment_resources/1`.

# `undislike_comment`

User removes dislike from a comment. Deletes dislike record and decrements counter.

# `unlike_comment`

User unlikes a comment. Deletes like record and decrements counter.

# `update_comment`

Updates a comment.

## Parameters

- `comment` - Comment to update
- `attrs` - Attributes to update (content, status)

# `update_resource_path_templates`

Updates resource templates for resource types.

Accepts both legacy string values and new map values with `"path"` and `"title"` keys.

---

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