Files
heygo/src/components/ResubmitDialog.tsx
T

105 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import type { PromotionSubmission } from '../lib/api';
interface ResubmitDialogProps {
readonly submission: PromotionSubmission;
readonly onSubmit: (input: { privateLinkId: string; proposedAlias: string; note?: string }) => Promise<void>;
readonly onClose: () => void;
}
export default function ResubmitDialog({ submission, onSubmit, onClose }: ResubmitDialogProps) {
const { t } = useTranslation();
const [proposedAlias, setProposedAlias] = useState<string>(submission.proposedAlias);
const [note, setNote] = useState<string>(submission.note ?? '');
const [error, setError] = useState<string | null>(null);
const [submitting, setSubmitting] = useState(false);
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
if (submitting) {
return;
}
setError(null);
setSubmitting(true);
try {
await onSubmit({
privateLinkId: submission.privateLinkId,
proposedAlias: proposedAlias.trim(),
note: note.trim() ? note.trim() : undefined,
});
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to resubmit promotion');
} finally {
setSubmitting(false);
}
}
return (
<div className="dialog-backdrop" role="dialog" aria-modal="true" aria-label={t('resubmitDialog.dialogLabel')}>
<form className="dialog-card link-form" onSubmit={handleSubmit}>
<div className="dialog-header">
<h2>{t('resubmitDialog.title')}</h2>
<button type="button" className="dialog-close" aria-label={t('resubmitDialog.closeLabel')} onClick={onClose} disabled={submitting}>×</button>
</div>
<p className="muted">
Resubmitting <span className="alias-pill">#{submission.privateLinkAlias ?? submission.privateLinkId}</span>
{submission.privateLinkTargetUrl ? <> <span className="truncate">{submission.privateLinkTargetUrl}</span></> : null}
</p>
{submission.rejectionReason ? (
<div className="resubmit-reason" role="note">
<strong>{t('resubmitDialog.requestedChanges')}</strong>
<p>{submission.rejectionReason}</p>
</div>
) : null}
<div className="field">
<label htmlFor="resubmit-alias">{t('resubmitDialog.fieldAlias')}</label>
<div className="alias-input">
<span className="alias-input__prefix" aria-hidden="true">#</span>
<input
id="resubmit-alias"
name="proposedAlias"
value={proposedAlias}
onChange={(e) => setProposedAlias(e.target.value)}
required
maxLength={100}
autoComplete="off"
placeholder={t('resubmitDialog.aliasPlaceholder')}
disabled={submitting}
/>
</div>
<small className="hint alias-preview">
<span>{t('resubmitDialog.aliasHint')}</span>
{proposedAlias.trim() ? <span className="alias-pill">#{proposedAlias.trim()}</span> : null}
</small>
</div>
<div className="field">
<label htmlFor="resubmit-note">{t('resubmitDialog.fieldNote')}</label>
<textarea
id="resubmit-note"
name="note"
value={note}
onChange={(e) => setNote(e.target.value)}
rows={3}
maxLength={1000}
placeholder={t('resubmitDialog.notePlaceholder')}
disabled={submitting}
/>
</div>
{error ? <p className="form-error" role="alert">{error}</p> : null}
<div className="form-actions">
<button type="submit" disabled={submitting || !proposedAlias.trim()}>
{submitting ? t('resubmitDialog.submitting') : t('resubmitDialog.resubmitForReview')}
</button>
<button type="button" onClick={onClose} disabled={submitting}>{t('resubmitDialog.cancel')}</button>
</div>
</form>
</div>
);
}