Files
moreminimore-chat/app/javascript/entrypoints/superadmin.js
Sony Mathew 7c1711170b feat: Add account suspension metadata in Super Admin (#15158)
## Description

Super Admins can now record a category and reason when suspending an
account, review the complete suspension history on the account details
page, and correct the latest suspension metadata without losing its
original timestamp. Suspension events are stored internally on the
account without changing customer-facing account API payloads.

## Closes

-
[CW-7653](https://linear.app/chatwoot/issue/CW-7653/ability-to-add-notes-while-suspending-an-acocunt)
- [Implementation
plan](https://linear.app/chatwoot/document/super-admin-account-suspension-metadata-implementation-plan-e7e4eb79d078)

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## What changed

- Require a suspension category and a reason of up to 256 characters
when an active account is suspended.
- Store append-only suspension events in `accounts.internal_attributes`,
while preserving unrelated internal metadata.
- Allow corrections to the latest event for an already suspended account
without changing its timestamp.
- Show the full suspension history, newest first, on the Super Admin
account details page.
- Add visual dividers between top-level sections on the Super Admin
account edit page.
- Keep legacy suspended-account edits and new-account creation behavior
unchanged.

## How to test

1. Open an active account in Super Admin and choose **Suspended**.
2. Confirm the category and reason controls appear, reject incomplete or
invalid values, and enforce the 256-character reason limit.
3. Suspend the account with each supported category and confirm the
event appears on the details page.
4. Reactivate and suspend the account again; confirm prior history is
retained and a new event is added.
5. Edit a suspended account's latest category or reason; confirm its
original timestamp is preserved.
6. Confirm a legacy suspended account without history can still be
edited without supplying suspension metadata.

## Checklist

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2026-07-24 14:48:14 +05:30

39 lines
1.4 KiB
JavaScript

import '../dashboard/assets/scss/super_admin/index.scss';
const initializeAccountSuspensionForm = () => {
const form = document.querySelector('[data-account-suspension-form]');
if (!form) return;
const status = form.querySelector('[data-account-status-select]');
const fields = form.querySelector('[data-account-suspension-fields]');
if (!status || !fields) return;
const category = fields.querySelector('[data-suspension-category]');
const reason = fields.querySelector('[data-suspension-reason]');
const controls = [category, reason];
const originalStatus = form.dataset.originalStatus;
const hasHistory = form.dataset.hasSuspensionHistory === 'true';
const updateFields = () => {
const isSuspended = status.value === 'suspended';
const hasEnteredDetails = controls.some(
control => control.value.trim().length > 0
);
const detailsRequired =
isSuspended &&
(originalStatus === 'active' || hasHistory || hasEnteredDetails);
fields.classList.toggle('hidden', !isSuspended);
controls.forEach(control => {
control.disabled = !isSuspended;
control.required = detailsRequired;
});
};
status.addEventListener('change', updateFields);
controls.forEach(control => control.addEventListener('input', updateFields));
updateFields();
};
document.addEventListener('DOMContentLoaded', initializeAccountSuspensionForm);