improvement: loading state added to buttons who interact with backend.
This commit is contained in:
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useState, type KeyboardEvent } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Eye, EyeOff, Send } from 'lucide-react';
|
||||
import { getUserFacingError } from '@/components/shared/formatApiError';
|
||||
import { useAsyncActionById } from '@/lib/hooks/useAsyncAction';
|
||||
import type { LabCaseComment } from '@/types/cases';
|
||||
|
||||
interface LabCaseCommentsPanelProps {
|
||||
@@ -42,6 +43,7 @@ export function LabCaseCommentsPanel({
|
||||
const [posting, setPosting] = useState(false);
|
||||
const [body, setBody] = useState('');
|
||||
const [visibleToClinic, setVisibleToClinic] = useState(false);
|
||||
const toggleBusy = useAsyncActionById();
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -84,12 +86,14 @@ export function LabCaseCommentsPanel({
|
||||
|
||||
async function handleToggle(comment: LabCaseComment) {
|
||||
if (!onToggleVisibility || !canToggleVisibility) return;
|
||||
try {
|
||||
const updated = await onToggleVisibility(comment.id, !comment.visibleToClinic);
|
||||
setComments((prev) => prev.map((c) => (c.id === updated.id ? updated : c)));
|
||||
} catch (error: unknown) {
|
||||
onError?.(getUserFacingError(error, tErrors, t('errorToggle')));
|
||||
}
|
||||
await toggleBusy.run(comment.id, async () => {
|
||||
try {
|
||||
const updated = await onToggleVisibility(comment.id, !comment.visibleToClinic);
|
||||
setComments((prev) => prev.map((c) => (c.id === updated.id ? updated : c)));
|
||||
} catch (error: unknown) {
|
||||
onError?.(getUserFacingError(error, tErrors, t('errorToggle')));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -127,10 +131,14 @@ export function LabCaseCommentsPanel({
|
||||
{canToggleVisibility && comment.canToggleVisibility && onToggleVisibility ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void handleToggle(comment)}
|
||||
className="shrink-0 p-1 rounded hover:bg-border text-text-muted"
|
||||
onClick={() => handleToggle(comment)}
|
||||
disabled={toggleBusy.pendingId !== null}
|
||||
className={`shrink-0 p-1 rounded hover:bg-border text-text-muted disabled:opacity-40 disabled:cursor-not-allowed ${
|
||||
toggleBusy.pendingId === comment.id ? 'animate-pulse' : ''
|
||||
}`}
|
||||
title={comment.visibleToClinic ? t('makeHidden') : t('makeVisible')}
|
||||
aria-label={comment.visibleToClinic ? t('makeHidden') : t('makeVisible')}
|
||||
aria-busy={toggleBusy.pendingId === comment.id || undefined}
|
||||
>
|
||||
{comment.visibleToClinic ? (
|
||||
<Eye className="h-4 w-4" />
|
||||
@@ -184,7 +192,7 @@ export function LabCaseCommentsPanel({
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void handlePost()}
|
||||
onClick={() => handlePost()}
|
||||
disabled={posting || !body.trim()}
|
||||
className="shrink-0 p-2 rounded-md bg-primary text-white transition-colors hover:opacity-90 disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
title={t('send')}
|
||||
|
||||
Reference in New Issue
Block a user