import {PowerOff, RefreshCcw, Save} from 'lucide-react'; import {FormEvent, useEffect, useState} from 'react'; import { disableProfileRedeemCode, listProfileRedeemCodes, upsertProfileRedeemCode, } from '../api/adminApiClient'; import type { ProfileRedeemCodeAdminResponse, ProfileRedeemCodeMode, } from '../api/adminApiTypes'; import {useAdminWriteConfirm} from '../components/useAdminWriteConfirm'; import {handlePageError, splitLines} from './pageUtils'; interface AdminRedeemCodePageProps { token: string; result: ProfileRedeemCodeAdminResponse | null; onUnauthorized: (message?: string) => void; onResultChange: (result: ProfileRedeemCodeAdminResponse) => void; } const redeemModes: Array<{value: ProfileRedeemCodeMode; label: string}> = [ {value: 'public', label: '公共码'}, {value: 'unique', label: '唯一码'}, {value: 'private', label: '私有码'}, ]; export function AdminRedeemCodePage({ token, result, onUnauthorized, onResultChange, }: AdminRedeemCodePageProps) { const [code, setCode] = useState(''); const [mode, setMode] = useState('public'); const [rewardPoints, setRewardPoints] = useState('100'); const [maxUses, setMaxUses] = useState('1'); const [enabled, setEnabled] = useState(true); const [allowedUserIds, setAllowedUserIds] = useState(''); const [allowedPublicUserCodes, setAllowedPublicUserCodes] = useState(''); const [disableCode, setDisableCode] = useState(''); const [errorMessage, setErrorMessage] = useState(''); const [disableErrorMessage, setDisableErrorMessage] = useState(''); const [listErrorMessage, setListErrorMessage] = useState(''); const [entries, setEntries] = useState([]); const [isSaving, setIsSaving] = useState(false); const [isDisabling, setIsDisabling] = useState(false); const [isLoading, setIsLoading] = useState(false); const {confirmWrite, confirmDialog} = useAdminWriteConfirm(); useEffect(() => { void refreshRedeemCodes(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [token]); async function refreshRedeemCodes() { setIsLoading(true); setListErrorMessage(''); try { const response = await listProfileRedeemCodes(token); setEntries(response.entries); } catch (error: unknown) { handlePageError(error, onUnauthorized, setListErrorMessage); } finally { setIsLoading(false); } } async function handleSave(event: FormEvent) { event.preventDefault(); if (isSaving) { return; } setErrorMessage(''); const confirmed = await confirmWrite({ action: '保存兑换码', target: code.trim(), }); if (!confirmed) { return; } setIsSaving(true); try { const response = await upsertProfileRedeemCode(token, { code: code.trim(), mode, rewardPoints: parsePositiveInteger(rewardPoints), maxUses: parsePositiveInteger(maxUses), enabled, allowedUserIds: mode === 'private' ? splitLines(allowedUserIds) : [], allowedPublicUserCodes: mode === 'private' ? splitLines(allowedPublicUserCodes) : [], }); onResultChange(response); upsertEntry(response); fillForm(response); } catch (error: unknown) { handlePageError(error, onUnauthorized, setErrorMessage); } finally { setIsSaving(false); } } async function handleDisable(event: FormEvent) { event.preventDefault(); if (isDisabling) { return; } setDisableErrorMessage(''); const confirmed = await confirmWrite({ action: '停用兑换码', target: disableCode.trim(), }); if (!confirmed) { return; } setIsDisabling(true); try { const response = await disableProfileRedeemCode(token, { code: disableCode.trim(), }); onResultChange(response); upsertEntry(response); fillForm(response); } catch (error: unknown) { handlePageError(error, onUnauthorized, setDisableErrorMessage); } finally { setIsDisabling(false); } } function upsertEntry(next: ProfileRedeemCodeAdminResponse) { setEntries((current) => { const rest = current.filter((entry) => entry.code !== next.code); return [...rest, next].sort((left, right) => { const leftUpdatedAt = Date.parse(left.updatedAt); const rightUpdatedAt = Date.parse(right.updatedAt); if (Number.isFinite(leftUpdatedAt) && Number.isFinite(rightUpdatedAt)) { const updatedCompare = rightUpdatedAt - leftUpdatedAt; if (updatedCompare !== 0) { return updatedCompare; } } return left.code.localeCompare(right.code); }); }); } function fillForm(entry: ProfileRedeemCodeAdminResponse) { setCode(entry.code); setMode(entry.mode); setRewardPoints(String(entry.rewardPoints)); setMaxUses(String(entry.maxUses)); setEnabled(entry.enabled); setAllowedUserIds(entry.allowedUserIds.join('\n')); setAllowedPublicUserCodes(''); setDisableCode(entry.code); } return (

兑换码

创建、更新与停用

{listErrorMessage ? (
{listErrorMessage}
) : null}
{redeemModes.map((item) => ( ))}
{mode === 'private' ? (