fix(exam,result): collapse row actions into a dropdown menu everywhere

Same treatment as the questions table, applied consistently: exams list,
exam results list, and the exam-detail candidates panel all now show a
single Actions button opening a dropdown instead of a row of inline
buttons/icons. Also fixes the exams list's action column header, which was
rendering the literal untranslated key ('exam.columns.actions') — missing
a fallback string, same pattern already used elsewhere in this file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
mihretue
2026-08-18 11:40:13 +00:00
parent 896a19bd5d
commit 80db201676
3 changed files with 145 additions and 136 deletions

View File

@@ -1,5 +1,5 @@
import { Button, Group } from '@mantine/core';
import { IconEye, IconSend, IconTrash } from '@tabler/icons-react';
import { Button, Menu } from '@mantine/core';
import { IconChevronDown, IconEye, IconSend, IconTrash } from '@tabler/icons-react';
import type { TFunction } from 'i18next';
import type { AdvancedColumn } from '@ema-platform/ui';
import { LICENSE_PERMISSIONS, RequirePermission } from '@ema-platform/auth';
@@ -22,62 +22,66 @@ export function resultActionsColumn(
cell: ({ row }) => {
const r = row.original;
return (
<Group gap="xs">
{(r.reviewStatus === 'MARKED' || r.reviewStatus === 'MODERATED') && (
<>
<RequirePermission anyOf={[LICENSE_PERMISSIONS.MODERATE_EXAM_RESULT]} hideOnly>
<Button size="compact-xs" variant="light" color="yellow" onClick={() => handlers.onQc(r, 'moderate')}>
{t('result.review.moderate')}
</Button>
</RequirePermission>
<RequirePermission anyOf={[LICENSE_PERMISSIONS.APPROVE_EXAM_RESULT]} hideOnly>
<Button size="compact-xs" variant="light" color="blue" onClick={() => handlers.onQc(r, 'approve')}>
{t('result.review.approve')}
</Button>
</RequirePermission>
</>
)}
{(r.reviewStatus === 'APPROVED' || r.reviewStatus === 'MODERATED') && (
<RequirePermission
anyOf={[
LICENSE_PERMISSIONS.MODERATE_EXAM_RESULT,
LICENSE_PERMISSIONS.APPROVE_EXAM_RESULT,
]}
hideOnly
>
<Button size="compact-xs" variant="subtle" color="orange" onClick={() => handlers.onQc(r, 'return')}>
{t('result.review.return')}
</Button>
</RequirePermission>
)}
{r.reviewStatus === 'APPROVED' && (
<RequirePermission anyOf={[LICENSE_PERMISSIONS.PUBLISH_EXAM_RESULT]} hideOnly>
<Button
size="compact-xs"
variant="light"
color="teal"
leftSection={<IconSend size={13} />}
onClick={() => handlers.onPublish(r)}
>
{t('result.review.publish')}
</Button>
</RequirePermission>
)}
<Button size="xs" variant="subtle" leftSection={<IconEye size={13} />} onClick={() => handlers.onViewDetail(r)}>
{t('result.action.viewEdit')}
</Button>
<RequirePermission anyOf={[LICENSE_PERMISSIONS.APPROVE_EXAM_RESULT]} hideOnly>
<Button
size="xs"
variant="subtle"
color="red"
leftSection={<IconTrash size={13} />}
onClick={() => handlers.onDelete(r)}
>
{t('result.action.delete')}
<Menu shadow="md" width={180} position="bottom-end">
<Menu.Target>
<Button size="compact-xs" variant="light" rightSection={<IconChevronDown size={12} />}>
{t('result.columns.actions', 'Actions')}
</Button>
</RequirePermission>
</Group>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item leftSection={<IconEye size={14} />} onClick={() => handlers.onViewDetail(r)}>
{t('result.action.viewEdit')}
</Menu.Item>
{(r.reviewStatus === 'MARKED' || r.reviewStatus === 'MODERATED') && (
<>
<RequirePermission anyOf={[LICENSE_PERMISSIONS.MODERATE_EXAM_RESULT]} hideOnly>
<Menu.Item color="yellow" onClick={() => handlers.onQc(r, 'moderate')}>
{t('result.review.moderate')}
</Menu.Item>
</RequirePermission>
<RequirePermission anyOf={[LICENSE_PERMISSIONS.APPROVE_EXAM_RESULT]} hideOnly>
<Menu.Item color="blue" onClick={() => handlers.onQc(r, 'approve')}>
{t('result.review.approve')}
</Menu.Item>
</RequirePermission>
</>
)}
{(r.reviewStatus === 'APPROVED' || r.reviewStatus === 'MODERATED') && (
<RequirePermission
anyOf={[
LICENSE_PERMISSIONS.MODERATE_EXAM_RESULT,
LICENSE_PERMISSIONS.APPROVE_EXAM_RESULT,
]}
hideOnly
>
<Menu.Item color="orange" onClick={() => handlers.onQc(r, 'return')}>
{t('result.review.return')}
</Menu.Item>
</RequirePermission>
)}
{r.reviewStatus === 'APPROVED' && (
<RequirePermission anyOf={[LICENSE_PERMISSIONS.PUBLISH_EXAM_RESULT]} hideOnly>
<Menu.Item
color="teal"
leftSection={<IconSend size={14} />}
onClick={() => handlers.onPublish(r)}
>
{t('result.review.publish')}
</Menu.Item>
</RequirePermission>
)}
<RequirePermission anyOf={[LICENSE_PERMISSIONS.APPROVE_EXAM_RESULT]} hideOnly>
<Menu.Divider />
<Menu.Item
color="red"
leftSection={<IconTrash size={14} />}
onClick={() => handlers.onDelete(r)}
>
{t('result.action.delete')}
</Menu.Item>
</RequirePermission>
</Menu.Dropdown>
</Menu>
);
},
};