Skip to content

feat: Implement email templates#669

Open
rajat1saxena wants to merge 3 commits intomainfrom
feature-email-templates-2
Open

feat: Implement email templates#669
rajat1saxena wants to merge 3 commits intomainfrom
feature-email-templates-2

Conversation

@rajat1saxena
Copy link
Copy Markdown
Member

This commit introduces the email templates feature, allowing you to create reusable templates for broadcast and sequence emails.

Backend:

  • Added EmailTemplate model.
  • Implemented GraphQL queries (getEmailTemplate, getEmailTemplates) and mutations (createEmailTemplate, updateEmailTemplate, deleteEmailTemplate) for email templates.
  • Added logic for the new GraphQL operations.

Frontend:

  • Added a 'Templates' tab to the /dashboard/mails page.
  • Created a TemplatesList component to display email templates.
  • Created an email template editor page.
  • Created a new page for selecting a template when creating a new broadcast or sequence.
  • Updated the createSequence mutation to accept title and content from a template.

This commit introduces the email templates feature, allowing you to create reusable templates for broadcast and sequence emails.

Backend:
- Added `EmailTemplate` model.
- Implemented GraphQL queries (`getEmailTemplate`, `getEmailTemplates`) and mutations (`createEmailTemplate`, `updateEmailTemplate`, `deleteEmailTemplate`) for email templates.
- Added logic for the new GraphQL operations.

Frontend:
- Added a 'Templates' tab to the `/dashboard/mails` page.
- Created a `TemplatesList` component to display email templates.
- Created an email template editor page.
- Created a new page for selecting a template when creating a new broadcast or sequence.
- Updated the `createSequence` mutation to accept `title` and `content` from a template.
@vercel
Copy link
Copy Markdown

vercel bot commented Nov 16, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
courselit-docs Ready Ready Preview, Comment Mar 28, 2026 11:59am

Request Review

.build();

try {
dispatch && dispatch(networkAction(true));

Check warning

Code scanning / CodeQL

Superfluous trailing arguments Warning

Superfluous argument passed to
function dispatch
.

Copilot Autofix

AI 1 day ago

In general, to fix a “superfluous trailing arguments” issue, either remove the unused arguments or ensure the callee’s signature and implementation actually make use of them. In this case, the argument to dispatch is semantically important (it is an action from networkAction(true/false)), so the correct fix is to make dispatch accept and use that argument instead of being a no-op function.

Concretely, in apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx, replace the stub const dispatch = () => {}; with a proper Redux dispatch obtained from the store or from a hook. Since we already import AppState, ThunkDispatch, and AnyAction, the most minimal, functionality-preserving change within this file is to import useDispatch from react-redux and use it to get a correctly typed dispatch function:

  • Add import { useDispatch } from "react-redux"; alongside the other imports.
  • Change line 28 from const dispatch = () => {}; to:
const dispatch: ThunkDispatch<AppState, unknown, AnyAction> = useDispatch();

This way, dispatch(networkAction(true)) and dispatch(networkAction(false)) become meaningful calls to the Redux dispatch function, the argument is no longer superfluous, and existing behavior (intended network action toggling) is preserved rather than removed.

Suggested changeset 2
apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
--- a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
+++ b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
@@ -13,6 +13,7 @@
 import { AnyAction } from "redux";
 import { AddressContext } from "@components/contexts";
 import { useContext } from "react";
+import { useDispatch } from "react-redux";
 
 interface NewMailPageClientProps {
     systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
     const { toast } = useToast();
     const router = useRouter();
     const searchParams = useSearchParams();
-    const dispatch = () => {};
+    const dispatch: ThunkDispatch<AppState, unknown, AnyAction> = useDispatch();
 
     const type = searchParams?.get("type") as SequenceType;
 
EOF
@@ -13,6 +13,7 @@
import { AnyAction } from "redux";
import { AddressContext } from "@components/contexts";
import { useContext } from "react";
import { useDispatch } from "react-redux";

interface NewMailPageClientProps {
systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
const { toast } = useToast();
const router = useRouter();
const searchParams = useSearchParams();
const dispatch = () => {};
const dispatch: ThunkDispatch<AppState, unknown, AnyAction> = useDispatch();

const type = searchParams?.get("type") as SequenceType;

apps/web/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/package.json b/apps/web/package.json
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -102,7 +102,8 @@
         "tailwind-merge": "^2.5.4",
         "tailwindcss-animate": "^1.0.7",
         "xml2js": "^0.6.2",
-        "zod": "^3.24.1"
+        "zod": "^3.24.1",
+        "react-redux": "^9.2.0"
     },
     "devDependencies": {
         "@eslint/eslintrc": "^3.3.1",
EOF
@@ -102,7 +102,8 @@
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
"xml2js": "^0.6.2",
"zod": "^3.24.1"
"zod": "^3.24.1",
"react-redux": "^9.2.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
This fix introduces these dependencies
Package Version Security advisories
react-redux (npm) 9.2.0 None
Copilot is powered by AI and may make mistakes. Always verify output.
variant: "destructive",
});
} finally {
dispatch && dispatch(networkAction(false));

Check warning

Code scanning / CodeQL

Superfluous trailing arguments Warning

Superfluous argument passed to
function dispatch
.

Copilot Autofix

AI 1 day ago

In general, to fix superfluous trailing arguments, either (a) remove the extra arguments if they truly are not needed, or (b) update the function so it correctly accepts and uses those arguments. Here, calls like dispatch(networkAction(true)) are intended to dispatch Redux actions; the problem is that dispatch is currently a zero-argument no-op. Removing the argument would only hide the intent and keep the code from dispatching anything, so the correct fix is to replace the stub with a real dispatch that accepts an action argument.

The best fix with minimal functional change is to obtain a proper Redux dispatch from the Redux store using the useDispatch hook from react-redux, typed as ThunkDispatch<AppState, null, AnyAction> to match the existing imports. Then replace const dispatch = () => {}; with const dispatch = useDispatch<ThunkDispatch<AppState, null, AnyAction>>();. This makes dispatch a function that expects an action (or thunk) argument, so the existing calls with networkAction(true/false) become meaningful and no longer have superfluous arguments.

Concretely:

  • In apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx, add an import for useDispatch from react-redux alongside the other imports.
  • Replace the line const dispatch = () => {}; with a typed useDispatch call, e.g. const dispatch = useDispatch<ThunkDispatch<AppState, null, AnyAction>>();.
    No other changes are required in the shown snippet.
Suggested changeset 1
apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
--- a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
+++ b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
@@ -13,6 +13,7 @@
 import { AnyAction } from "redux";
 import { AddressContext } from "@components/contexts";
 import { useContext } from "react";
+import { useDispatch } from "react-redux";
 
 interface NewMailPageClientProps {
     systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
     const { toast } = useToast();
     const router = useRouter();
     const searchParams = useSearchParams();
-    const dispatch = () => {};
+    const dispatch = useDispatch<ThunkDispatch<AppState, null, AnyAction>>();
 
     const type = searchParams?.get("type") as SequenceType;
 
EOF
@@ -13,6 +13,7 @@
import { AnyAction } from "redux";
import { AddressContext } from "@components/contexts";
import { useContext } from "react";
import { useDispatch } from "react-redux";

interface NewMailPageClientProps {
systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
const { toast } = useToast();
const router = useRouter();
const searchParams = useSearchParams();
const dispatch = () => {};
const dispatch = useDispatch<ThunkDispatch<AppState, null, AnyAction>>();

const type = searchParams?.get("type") as SequenceType;

Copilot is powered by AI and may make mistakes. Always verify output.
try {
dispatch &&
(dispatch as ThunkDispatch<AppState, null, AnyAction>)(
networkAction(true),

Check warning

Code scanning / CodeQL

Superfluous trailing arguments Warning

Superfluous argument passed to
function dispatch
.

Copilot Autofix

AI 1 day ago

To fix this, we should ensure that dispatch is actually a Redux Thunk dispatch function rather than a no-op. That way, calling dispatch(networkAction(true)) and dispatch(networkAction(false)) is both type-correct and functionally meaningful, and the argument to networkAction is no longer “superfluous” in practice.

Concretely, in apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx:

  1. Replace the placeholder const dispatch = () => {}; with a real dispatch obtained from the Redux store, using useDispatch from react-redux and typing it as ThunkDispatch<AppState, null, AnyAction>.
  2. Add the necessary import for useDispatch from react-redux.

This preserves the existing behavior intent (toggling network state before/after the async call) without changing other logic.

Suggested changeset 1
apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
--- a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
+++ b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
@@ -13,6 +13,7 @@
 import { AnyAction } from "redux";
 import { AddressContext } from "@components/contexts";
 import { useContext } from "react";
+import { useDispatch } from "react-redux";
 
 interface NewMailPageClientProps {
     systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
     const { toast } = useToast();
     const router = useRouter();
     const searchParams = useSearchParams();
-    const dispatch = () => {};
+    const dispatch = useDispatch<ThunkDispatch<AppState, null, AnyAction>>();
 
     const type = searchParams?.get("type") as SequenceType;
 
EOF
@@ -13,6 +13,7 @@
import { AnyAction } from "redux";
import { AddressContext } from "@components/contexts";
import { useContext } from "react";
import { useDispatch } from "react-redux";

interface NewMailPageClientProps {
systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
const { toast } = useToast();
const router = useRouter();
const searchParams = useSearchParams();
const dispatch = () => {};
const dispatch = useDispatch<ThunkDispatch<AppState, null, AnyAction>>();

const type = searchParams?.get("type") as SequenceType;

Copilot is powered by AI and may make mistakes. Always verify output.
} finally {
dispatch &&
(dispatch as ThunkDispatch<AppState, null, AnyAction>)(
networkAction(false),

Check warning

Code scanning / CodeQL

Superfluous trailing arguments Warning

Superfluous argument passed to
function dispatch
.

Copilot Autofix

AI 1 day ago

In general, to fix “superfluous trailing arguments” you either (a) remove the unused arguments from the call site, or (b) update the function so it actually accepts and uses those arguments. Here, dispatch is clearly intended to receive actions created by networkAction, matching Redux usage already present elsewhere in the codebase (as suggested by the imports from @courselit/state-management and use of ThunkDispatch). Removing the arguments would hide the underlying bug (that network actions are never dispatched). The best fix is to replace the dummy dispatch implementation with a proper one retrieved from Redux.

Concretely, in apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx, replace const dispatch = () => {}; with a typed Redux dispatch from useDispatch (from react-redux), using the existing ThunkDispatch<AppState, null, AnyAction> type. This way, dispatch(networkAction(true)) and dispatch(networkAction(false)) become valid calls whose argument is actually consumed, eliminating the “superfluous argument” condition and restoring the intended behavior. To implement this, add an import for useDispatch from react-redux, then define const dispatch: ThunkDispatch<AppState, null, AnyAction> = useDispatch(); (or similar) in place of the stub. No other call sites need to change.

Suggested changeset 2
apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
--- a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
+++ b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
@@ -13,6 +13,7 @@
 import { AnyAction } from "redux";
 import { AddressContext } from "@components/contexts";
 import { useContext } from "react";
+import { useDispatch } from "react-redux";
 
 interface NewMailPageClientProps {
     systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
     const { toast } = useToast();
     const router = useRouter();
     const searchParams = useSearchParams();
-    const dispatch = () => {};
+    const dispatch: ThunkDispatch<AppState, null, AnyAction> = useDispatch();
 
     const type = searchParams?.get("type") as SequenceType;
 
EOF
@@ -13,6 +13,7 @@
import { AnyAction } from "redux";
import { AddressContext } from "@components/contexts";
import { useContext } from "react";
import { useDispatch } from "react-redux";

interface NewMailPageClientProps {
systemTemplates: EmailTemplate[];
@@ -25,7 +26,7 @@
const { toast } = useToast();
const router = useRouter();
const searchParams = useSearchParams();
const dispatch = () => {};
const dispatch: ThunkDispatch<AppState, null, AnyAction> = useDispatch();

const type = searchParams?.get("type") as SequenceType;

apps/web/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/package.json b/apps/web/package.json
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -102,7 +102,8 @@
         "tailwind-merge": "^2.5.4",
         "tailwindcss-animate": "^1.0.7",
         "xml2js": "^0.6.2",
-        "zod": "^3.24.1"
+        "zod": "^3.24.1",
+        "react-redux": "^9.2.0"
     },
     "devDependencies": {
         "@eslint/eslintrc": "^3.3.1",
EOF
@@ -102,7 +102,8 @@
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
"xml2js": "^0.6.2",
"zod": "^3.24.1"
"zod": "^3.24.1",
"react-redux": "^9.2.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
This fix introduces these dependencies
Package Version Security advisories
react-redux (npm) 9.2.0 None
Copilot is powered by AI and may make mistakes. Always verify output.
const NewMailPageClient = ({ systemTemplates }: NewMailPageClientProps) => {
const address = useContext(AddressContext);
const [templates, setTemplates] = useState<EmailTemplate[]>([]);
const [isLoading, setIsLoading] = useState(false);

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable isLoading.

Copilot Autofix

AI 1 day ago

To fix the problem, remove the unused isLoading state variable and its setter calls, since no rendering or logic depends on it. This avoids maintaining redundant state and eliminates the CodeQL warning.

Concretely, in apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx:

  1. Change the useState declaration on line 24 so that it no longer creates isLoading/setIsLoading. Since neither is used elsewhere, simply remove that line entirely.
  2. In loadTemplates, remove the calls to setIsLoading(true); (line 41) and setIsLoading(false); (line 78 or 79, depending on numbering after edits), as these will no longer be defined and serve no purpose.

No new methods, imports, or definitions are needed. Functionality is unchanged, because nothing depended on isLoading before.

Suggested changeset 1
apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
--- a/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
+++ b/apps/web/app/(with-contexts)/dashboard/mails/new/new-mail-page-client.tsx
@@ -21,7 +21,6 @@
 const NewMailPageClient = ({ systemTemplates }: NewMailPageClientProps) => {
     const address = useContext(AddressContext);
     const [templates, setTemplates] = useState<EmailTemplate[]>([]);
-    const [isLoading, setIsLoading] = useState(false);
     const { toast } = useToast();
     const router = useRouter();
     const searchParams = useSearchParams();
@@ -38,7 +37,6 @@
     }, []);
 
     const loadTemplates = async () => {
-        setIsLoading(true);
         const query = `
             query GetEmailTemplates {
                 templates: getEmailTemplates {
@@ -75,7 +73,6 @@
             });
         } finally {
             dispatch && dispatch(networkAction(false));
-            setIsLoading(false);
         }
     };
 
EOF
@@ -21,7 +21,6 @@
const NewMailPageClient = ({ systemTemplates }: NewMailPageClientProps) => {
const address = useContext(AddressContext);
const [templates, setTemplates] = useState<EmailTemplate[]>([]);
const [isLoading, setIsLoading] = useState(false);
const { toast } = useToast();
const router = useRouter();
const searchParams = useSearchParams();
@@ -38,7 +37,6 @@
}, []);

const loadTemplates = async () => {
setIsLoading(true);
const query = `
query GetEmailTemplates {
templates: getEmailTemplates {
@@ -75,7 +73,6 @@
});
} finally {
dispatch && dispatch(networkAction(false));
setIsLoading(false);
}
};

Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant