Form submissions updates

This commit is contained in:
Tanuja Pansare 2026-07-16 09:57:01 +05:30
parent bad7d38777
commit 31f5d80f41
3 changed files with 60 additions and 28 deletions

View File

@ -171,11 +171,18 @@ export function FormSubmissionsPanel({ formId, formName, onClose }: Props) {
setReplying(true); setReplying(true);
setReplyMessage(null); setReplyMessage(null);
try { try {
await formsApi.replyToSubmission(formId, { to, subject: replySubject, body: replyBody }); // Extend payload with submissionId; backend uses it to persist replied status.
await (formsApi as any).replyToSubmission(formId, {
submissionId: replyTarget._id,
to,
subject: replySubject,
body: replyBody,
});
setReplyMessage("Email sent successfully."); setReplyMessage("Email sent successfully.");
setReplyTarget(null); setReplyTarget(null);
setReplySubject(""); setReplySubject("");
setReplyBody(""); setReplyBody("");
await fetchPage();
} catch (e) { } catch (e) {
setReplyMessage(e instanceof Error ? e.message : "Failed to send reply."); setReplyMessage(e instanceof Error ? e.message : "Failed to send reply.");
} finally { } finally {
@ -456,32 +463,41 @@ export function FormSubmissionsPanel({ formId, formName, onClose }: Props) {
</thead> </thead>
<tbody> <tbody>
{rows.map((s) => { {rows.map((s) => {
const o = dataToObj(s.data); const o = dataToObj(s.data);
return ( const hasEmail = participantEmail(s.participant) !== "—";
<tr key={s._id} style={{ borderBottom: "1px solid var(--border)", verticalAlign: "top" }}>
<td style={{ padding: "10px 12px" }}> const isReplied = !!s.replied;
<button return (
type="button" <tr
onClick={() => openReply(s)} key={s._id}
style={{ style={{
display: "inline-flex", borderBottom: "1px solid var(--border)",
alignItems: "center", verticalAlign: "top",
gap: 6, background: isReplied ? "rgba(16, 185, 129, 0.08)" : undefined,
padding: "6px 10px", }}
borderRadius: "var(--radius-button)", >
border: "1px solid var(--border)", <td style={{ padding: "10px 12px" }}>
background: "var(--secondary)", <button
color: "var(--foreground)", type="button"
cursor: "pointer", onClick={() => hasEmail && !isReplied && openReply(s)}
fontSize: "var(--text-xs)", disabled={!hasEmail || isReplied}
fontFamily: "var(--font-noto-sans)", title={isReplied ? "Already replied" : !hasEmail ? "No email available" : "Reply"}
fontWeight: 600, style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "6px 10px", borderRadius: "var(--radius-button)",
}} border: "1px solid var(--border)",
> background: isReplied ? "rgba(16, 185, 129, 0.15)" : hasEmail ? "var(--secondary)" : "var(--background)",
<MailPlus size={14} /> color: isReplied ? "var(--foreground)" : hasEmail ? "var(--foreground)" : "var(--muted)",
Reply cursor: !hasEmail || isReplied ? "not-allowed" : "pointer",
</button> opacity: !hasEmail ? 0.5 : 1,
fontSize: "var(--text-xs)",
fontFamily: "var(--font-noto-sans)",
fontWeight: 600,
}}
>
<MailPlus size={14} />
{isReplied ? "Replied" : "Reply"}
</button>
</td> </td>
<td style={{ padding: "10px 12px", whiteSpace: "nowrap", color: "var(--foreground)" }}> <td style={{ padding: "10px 12px", whiteSpace: "nowrap", color: "var(--foreground)" }}>
{formatWhen(s.submittedAt)} {formatWhen(s.submittedAt)}
</td> </td>

View File

@ -200,7 +200,7 @@ export function ParticipantBulkDialogs({
}} }}
style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "none", background: "var(--primary)", color: "var(--primary-foreground)", cursor: "pointer", fontSize: "var(--text-sm)" }} style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "none", background: "var(--primary)", color: "var(--primary-foreground)", cursor: "pointer", fontSize: "var(--text-sm)" }}
> >
Apply {bulkDialog === "removeTags" ? "Remove" : "Apply"}
</button> </button>
)} )}
</> </>

View File

@ -610,8 +610,24 @@ export interface FormSubmissionRecord {
form?: string; form?: string;
submittedAt: string; submittedAt: string;
data?: Record<string, unknown>; data?: Record<string, unknown>;
participant?: { _id?: string; firstName?: string; lastName?: string; email?: string } | string; participant?: {
_id?: string;
firstName?: string;
lastName?: string;
email?: string;
} | string;
status?: string; status?: string;
replied?: boolean;
repliedAt?: string;
repliedBy?:
| string
| {
_id?: string;
firstName?: string;
lastName?: string;
email?: string;
};
} }
export interface SpeakerLogistics { export interface SpeakerLogistics {