ui phase 11
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
import { useState } from 'react';
|
||||
import { Suspense, useState } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { Box, Chip, MenuItem, Paper, Skeleton, Stack, TextField, Typography } from '@mui/material';
|
||||
import { AppButton, RatingInput } from '@/components';
|
||||
import { AppButton, AppLoading, RatingInput } from '@/components';
|
||||
import { AdminEmptyState, AdminErrorState, AdminPageHeader, AdminPager, ConfirmDialog } from '@/components/admin';
|
||||
import { useAdminCapabilities } from '@/hooks';
|
||||
import { useAdminCapabilities, useAdminListState } from '@/hooks';
|
||||
import { REVIEWS_PAGE_SIZE } from '@/services/reviews/constants';
|
||||
import type { ModerationAction, ModerationQueueItem, ModerationStatus } from '@/services/reviews/types';
|
||||
import { useModerationQueue, useModerateReview } from '@/services/reviews';
|
||||
@@ -29,13 +29,33 @@ const STATUS_CHIP_COLOR: Record<ModerationStatus, 'default' | 'success' | 'warni
|
||||
* Publishing recomputes the nurse aggregate **server-side**; the mutation invalidates the queue so the row
|
||||
* leaves on success. `canModerate` only hides the controls — the server enforces the role scope.
|
||||
*/
|
||||
const DEFAULT_STATUS: ModerationStatus = 'pending_moderation';
|
||||
|
||||
function parseFilters(params: URLSearchParams): { status: ModerationStatus } {
|
||||
const status = params.get('status') as ModerationStatus | null;
|
||||
return { status: status && MODERATION_STATUSES.includes(status) ? status : DEFAULT_STATUS };
|
||||
}
|
||||
|
||||
export default function AdminReviewsPage() {
|
||||
return (
|
||||
<Suspense fallback={<AppLoading />}>
|
||||
<AdminReviewsPageInner />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
function AdminReviewsPageInner() {
|
||||
const t = useTranslations('admin');
|
||||
const caps = useAdminCapabilities();
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const [status, setStatus] = useState<ModerationStatus>('pending_moderation');
|
||||
const [page, setPage] = useState(1);
|
||||
const listState = useAdminListState<{ status: ModerationStatus }>({
|
||||
parse: parseFilters,
|
||||
serialize: (f): Record<string, string> => (f.status !== DEFAULT_STATUS ? { status: f.status } : {}),
|
||||
empty: { status: DEFAULT_STATUS },
|
||||
});
|
||||
const status = listState.applied.status;
|
||||
const page = listState.page;
|
||||
const [pending, setPending] = useState<{ item: ModerationQueueItem; action: ModerationAction } | null>(null);
|
||||
|
||||
const queue = useModerationQueue({ status }, page);
|
||||
@@ -44,6 +64,8 @@ export default function AdminReviewsPage() {
|
||||
const items = queue.data?.items ?? [];
|
||||
const pageCount = Math.max(1, Math.ceil((queue.data?.total ?? 0) / REVIEWS_PAGE_SIZE));
|
||||
|
||||
const setStatus = (next: ModerationStatus) => listState.applyFilters({ status: next });
|
||||
|
||||
const requireReason = pending?.action === 'hide' || pending?.action === 'reject';
|
||||
|
||||
const onConfirm = (reason?: string) => {
|
||||
@@ -70,10 +92,7 @@ export default function AdminReviewsPage() {
|
||||
size="small"
|
||||
label={t('filter_label')}
|
||||
value={status}
|
||||
onChange={(e) => {
|
||||
setStatus(e.target.value as ModerationStatus);
|
||||
setPage(1);
|
||||
}}
|
||||
onChange={(e) => setStatus(e.target.value as ModerationStatus)}
|
||||
sx={{ minWidth: 180 }}
|
||||
>
|
||||
{MODERATION_STATUSES.map((s) => (
|
||||
@@ -107,11 +126,11 @@ export default function AdminReviewsPage() {
|
||||
<AdminPager
|
||||
page={page}
|
||||
pageCount={pageCount}
|
||||
onPrev={() => setPage((p) => Math.max(1, p - 1))}
|
||||
onNext={() => setPage((p) => Math.min(pageCount, p + 1))}
|
||||
onPrev={() => listState.goToPage(Math.max(1, page - 1))}
|
||||
onNext={() => listState.goToPage(Math.min(pageCount, page + 1))}
|
||||
prevLabel={t('prev_page')}
|
||||
nextLabel={t('next_page')}
|
||||
indicator={t('page_indicator', { page })}
|
||||
indicator={t('page_indicator', { page, total: pageCount })}
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
|
||||
Reference in New Issue
Block a user