diff --git a/src/app/auth/callback/route.ts b/src/app/auth/callback/route.ts index 49c2a468..207dd814 100644 --- a/src/app/auth/callback/route.ts +++ b/src/app/auth/callback/route.ts @@ -8,8 +8,6 @@ export async function GET(request: Request) { // if "next" is in param, use it as the redirect URL const next = searchParams.get("redirect") ?? "/"; - console.log("next", next); - if (code) { const supabase = createClient(); const { error } = await supabase.auth.exchangeCodeForSession(code); diff --git a/src/app/portal/admin/forms/[id]/settings/formSettings.tsx b/src/app/portal/admin/forms/[id]/settings/formSettings.tsx new file mode 100644 index 00000000..2d20f1d5 --- /dev/null +++ b/src/app/portal/admin/forms/[id]/settings/formSettings.tsx @@ -0,0 +1,477 @@ +"use client"; +import { useState, useMemo } from "react"; +import { marked } from "marked"; +import Input from "@/components/general/input"; +import { formContext } from "@/components/layouts/formTabView"; +import { Textarea } from "@/components/primitives/textArea"; +import { useContext } from "react"; +import { Button } from "@/components/primitives/button"; +import MultiSelect from "@/components/general/multiSelect"; +import { FormStep } from "@/lib/types/questions"; +import { updateOrCreateEmailTemplate } from "./actions"; +import { toast } from "sonner"; +import { Dialog } from "@/components/primitives/dialog"; +import { number } from "zod"; + +// Helper function to extract template tags +const extractTemplateTags = (content: string): string[] => { + const regex = /{{([^{}]+)}}/g; + const matches = content.match(regex); + if (!matches) return []; + return matches.map((match) => match.slice(2, -2)); +}; + +// Helper to find unclosed tags +const findInvalidTags = (content: string): string[] => { + const regex = /{{([^{}]*$)|{{([^{}]*)}(?!})/g; + const matches = content.match(regex); + return matches || []; +}; + +export default function FormSettingsPage() { + const { rawForm: form, submissions } = useContext(formContext); + const emailStatuses = form?.config.application?.emails?.status || {}; + const statusOptions = form?.config.application?.status || []; + const [editingStatus, setEditingStatus] = useState(null); + const [showNewTemplate, setShowNewTemplate] = useState(false); + const [selectedStatus, setSelectedStatus] = useState(""); + const [showPreview, setShowPreview] = useState(false); + + const [title, setTitle] = useState(""); + const [content, setContent] = useState(""); + const [openTemplates, setOpenTemplates] = useState([]); + + async function applyTemplateChange(templateData: { + status: string; + title: string; + content: string; + }) { + try { + await updateOrCreateEmailTemplate(form.id, templateData.status, { + title: templateData.title, + content: templateData.content, + }); + toast.success("Template updated successfully", { + action: { + label: "Refresh", + onClick: () => window.location.reload(), + }, + }); + return true; + } catch (error) { + toast.error("Error updating template"); + console.error("Error updating template:", error); + return false; + } + } + + const templateFields = useMemo(() => { + const fields: Record = {}; + form.questions.forEach((fStep: FormStep) => { + fStep.questions.forEach((question) => { + fields[question.id] = question.label; + }); + }); + form.config.application?.subfields?.forEach( + (field: { id: string; label: string }) => { + fields[field.id] = field.label; + }, + ); + return fields; + }, [form]); + + const handleSave = async (templateData) => { + await applyTemplateChange(templateData); + setEditingStatus(null); + }; + + const handleCreateNew = async (templateData) => { + await applyTemplateChange(templateData); + setShowNewTemplate(false); + setSelectedStatus(""); + setTitle(""); + setContent(""); + }; + + const availableStatuses = statusOptions + .filter( + (status) => + !emailStatuses[status.id] || !emailStatuses[status.id.toString()], + ) + .map((status) => ({ + id: status.id, + label: status.label, + })); + + return ( +
+
+

Email Settings

+ {availableStatuses.length > 0 && ( + + )} +
+
+
+
+ + Important Information About Email Templates + +
+
+

Email Sending Limits

+

+ Due to email service provider restrictions, we can only send + up to 100 automated emails per day. Please plan your bulk + notifications accordingly. +

+
+
+

Available Template Tags

+
+ {Object.entries(templateFields).map(([key, value]) => ( + + {`{{${key}}}`} + : {value} + + ))} +
+
+
+
+ +
+ ({ + value: status, + label: ( +
+ + {status} + + + {emailConfig.title} + +
+ ), + }), + )} + value={openTemplates} + onChange={setOpenTemplates} + allowMultiple={true} + className="w-full" + emptyText="Select templates to view..." + /> + {showNewTemplate && ( +
+

Create New Template

+
+
+

Status

+ +
+ +
+

Subject Line

+ setTitle(e.target.value)} + placeholder="Enter email subject" + className="w-full p-2 border rounded-md bg-background-600" + /> +
+ +
+

Email Content

+