Form submissions updates
This commit is contained in:
parent
bad7d38777
commit
31f5d80f41
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue