feat(appointment): log cancellation events and show them in a Timeline

Introduce the first per-appointment event system. On cancel (via the status
or general update endpoints) an AppointmentEvent (type=cancelled, «نوبت لغو
شد») is recorded with the actor, cancel time, and an optional cancel_reason,
plus a warning-level app_log entry. New GET /appointment/{uuid}/events
returns the ordered event list. The admin appointment detail page renders a
Timeline section and the cancel dialog now collects an optional reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-17 11:13:23 +03:30
co-authored by Claude Fable 5
parent 36d7fe0303
commit 49b2ca60d7
8 changed files with 311 additions and 8 deletions
@@ -12,6 +12,8 @@ interface Props {
loading?: boolean;
onConfirm: () => void;
onCancel: () => void;
/** محتوای اضافه زیر پیام (مثلاً فیلد دلیل). */
children?: React.ReactNode;
}
export default function ConfirmDialog({
@@ -24,6 +26,7 @@ export default function ConfirmDialog({
loading = false,
onConfirm,
onCancel,
children,
}: Props) {
if (!open) return null;
@@ -48,6 +51,7 @@ export default function ConfirmDialog({
</div>
<div className="modal-body">
<p style={{ color: 'var(--text-2)', lineHeight: 1.75, margin: 0 }}>{message}</p>
{children}
</div>
<div className="modal-foot" style={{ justifyContent: 'flex-end' }}>
<button className="btn ghost sm" onClick={onCancel} disabled={loading}>