fix: quality audit — memory leaks, dead prose classes, stale state scope
- safe-markdown: add `cancelled` flag to async useEffect; no more setState after unmount when component is destroyed mid-import - rich-editor: same cleanup for preview tab effect; also remove dead `prose prose-sm max-w-none` classes (Tailwind Typography not installed) and replace with explicit arbitrary-selector markdown styling that actually renders using existing design tokens - profile-certificate-slot: drop dead `ORDER_LABEL`, `order` variable, and `physicalOrder` from `MineCertificateResponse`; physical orders are disabled — these were leftover references causing lint noise - learning-panel: change `issuingCert: boolean` → `issuingCertFor: number | null` so only the targeted user's button shows a spinner; a boolean shared across all users caused the wrong row to animate when the admin switched selected users mid-request Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -65,7 +65,7 @@ export function LearningPanel() {
|
||||
const [sort, setSort] = useState<SortKey>("xp");
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null);
|
||||
const [unlocking, setUnlocking] = useState(false);
|
||||
const [issuingCert, setIssuingCert] = useState(false);
|
||||
const [issuingCertFor, setIssuingCertFor] = useState<number | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -117,7 +117,7 @@ export function LearningPanel() {
|
||||
};
|
||||
|
||||
const issueCertificate = async (id: number) => {
|
||||
setIssuingCert(true);
|
||||
setIssuingCertFor(id);
|
||||
try {
|
||||
await http.post(`/api/admin/users/${id}/certificate/issue`, {});
|
||||
toast.success("گواهینامه با موفقیت صادر شد");
|
||||
@@ -125,7 +125,7 @@ export function LearningPanel() {
|
||||
} catch (e) {
|
||||
toast.error(toUserError(e, "صدور گواهینامه ممکن نشد"));
|
||||
} finally {
|
||||
setIssuingCert(false);
|
||||
setIssuingCertFor(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -393,11 +393,15 @@ export function LearningPanel() {
|
||||
<Button
|
||||
size="sm"
|
||||
variant="default"
|
||||
disabled={issuingCert}
|
||||
disabled={issuingCertFor === detailQ.data.learning.user.id}
|
||||
onClick={() => issueCertificate(detailQ.data!.learning.user.id)}
|
||||
className="gap-1.5"
|
||||
>
|
||||
{issuingCert ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Award className="h-3.5 w-3.5" />}
|
||||
{issuingCertFor === detailQ.data.learning.user.id ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Award className="h-3.5 w-3.5" />
|
||||
)}
|
||||
صدور گواهینامه
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user