Skip to content

feat: add email field to transaction inputs and update related components.#398

Merged
onahprosper merged 4 commits intomainfrom
feature/transaction-email-field
Mar 9, 2026
Merged

feat: add email field to transaction inputs and update related components.#398
onahprosper merged 4 commits intomainfrom
feature/transaction-email-field

Conversation

@sundayonah
Copy link
Copy Markdown
Collaborator

@sundayonah sundayonah commented Mar 3, 2026

Description

This PR adds optional email support to transaction creation so that when a user completes a swap or transfer in Noblocks, their Privy email (when present) is stored on the transaction record. Downstream automation (e.g. Activepieces → Brevo) can then send transaction confirmation emails only to users who have an email, and use email_sent_at to avoid duplicate sends.

Background: The transactions table already had (or was extended with) an email column. The app was not sending the user's email when creating swap/transfer records, so automation could not target users by email. This change wires the existing Privy user email into the transaction payload for both flows.

Changes:

  • Types: TransactionCreateInput now includes optional email?: string.
  • API: POST /api/v1/transactions persists email (trimmed or null) on insert.
  • Swap: TransactionPreview.tsx passes user?.email?.address into the transaction object in saveTransactionData.
  • Transfer: useSmartWalletTransfer.ts passes user?.email?.address into the transaction object when calling saveTransaction.

Impacts: No breaking changes. Email is optional; existing callers and rows are unchanged. Rows without email continue to work; only users with a Privy email have it stored. Activepieces (or similar) can filter with email IS NOT NULL and email_sent_at IS NULL and set email_sent_at after sending to prevent duplicate emails.

Database: run this migration in Supabase SQL.

-- Add columns used by the app and by Activepieces
ALTER TABLE transactions
ADD COLUMN IF NOT EXISTS email TEXT,
ADD COLUMN IF NOT EXISTS order_id TEXT,
ADD COLUMN IF NOT EXISTS network TEXT,
ADD COLUMN IF NOT EXISTS email_sent_at TIMESTAMP WITH TIME ZONE;
ADD COLUMN IF NOT EXISTS explorer_link TEXT;

Checklist

  • I have added documentation and tests for new/changed functionality in this PR
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not main

By submitting a PR, I agree to Paycrest's Contributor Code of Conduct and Contribution Guide.

Summary by CodeRabbit

  • New Features
    • Transactions now optionally capture and store a user's email when available.
    • Transactions may include an optional explorer link derived from network and transaction hash.
    • Transaction records now include additional metadata (e.g., order/network fields and update/email timestamps).

…ents

* Introduced an email field in TransactionCreateInput to capture user email during transaction creation.
* Updated the transaction route to handle the new email field, ensuring it is trimmed and set to null if not provided.
* Modified useSmartWalletTransfer and TransactionPreview components to include the user's email address when saving transactions, enhancing user data capture.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

Adds optional email and explorer_link fields across types, frontend payloads, API create/update handlers, and the DB migration: frontend supplies user?.email?.address; APIs normalize email and derive explorer_link from network + txHash when present, persisting both on insert and update.

Changes

Cohort / File(s) Summary
Type definitions
app/types.ts
Added email?: string to TransactionCreateInput and explorer_link?: string to TransactionHistory.
Create transaction API
app/api/v1/transactions/route.ts
Normalize body.email to normalizedEmail, compute explorerLink from body.network + body.txHash, include email: normalizedEmail and conditionally explorer_link: explorerLink in the inserted payload.
Update transaction API
app/api/v1/transactions/[id]/route.ts
Compute explorerLink when txHash and existing network present and conditionally include explorer_link in the update payload.
Frontend payloads
app/hooks/useSmartWalletTransfer.ts, app/pages/TransactionPreview.tsx
Include optional email in transaction payloads, sourcing from user?.email?.address (falls back to undefined).
Database migration
supabase/migrations/create_transactions_table.sql
Schema expanded with new public columns: email, order_id, network, email_sent_at, explorer_link, and updated_at added to transactions table.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

"I’m a rabbit with a pen so keen,
I tuck new fields where few have been,
An email here, a link to see,
Small hops that make the ledger free. 🐇✨"

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description comprehensively covers purpose, background, specific changes across all affected files, impacts (no breaking changes), and database migration. It includes context and rationale for downstream automation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title accurately describes the main changes: adding an email field to transaction inputs and updating related components across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/transaction-email-field

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/v1/transactions/route.ts`:
- Line 160: Guard against non-string email values before calling .trim() by
converting or checking the type like you do for walletAddress: replace direct
body.email?.trim() usage with a safe conversion/check (e.g., if (body.email ==
null) resultEmail = null else resultEmail = String(body.email).trim()) so that
email becomes null when absent and never throws when body.email is a
number/object; update the code that sets email to use this safe result
(reference body.email, .trim(), and the walletAddress String() conversion
approach).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a62cc0a and 9611a05.

📒 Files selected for processing (4)
  • app/api/v1/transactions/route.ts
  • app/hooks/useSmartWalletTransfer.ts
  • app/pages/TransactionPreview.tsx
  • app/types.ts

Comment thread app/api/v1/transactions/route.ts Outdated
* Added normalization for the email field in the transaction route to ensure it is trimmed and set to null if not provided, improving data integrity during transaction creation.
* Introduced an optional explorer_link field in the TransactionHistory interface to store links to transaction explorers.
* Updated the POST and PUT transaction routes to generate and include the explorer link based on the network and transaction hash, enhancing transaction visibility and user experience.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/api/v1/transactions/route.ts (1)

147-150: Minor inconsistency in default value between POST and PUT handlers.

Here the default is "" (empty string), while [id]/route.ts uses undefined. Both are falsy and work correctly with the conditional spread, but for consistency consider using the same default:

Optional: Align with PUT handler pattern
     const explorerLink =
       body.network && body.txHash
         ? getExplorerLink(body.network, body.txHash)
-        : "";
+        : undefined;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/v1/transactions/route.ts` around lines 147 - 150, The POST handler
sets explorerLink to an empty string while the PUT handler uses undefined;
change the POST assignment of explorerLink (where getExplorerLink(body.network,
body.txHash) is called) to use undefined as the default when body.network or
body.txHash are missing so it matches the PUT handler pattern (keep the same
conditional logic using body.network and body.txHash and the getExplorerLink
call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/v1/transactions/`[id]/route.ts:
- Line 80: The transactions table is missing columns referenced by the updater
(explorer_link via explorerLink, plus network, order_id, and email), which will
cause Supabase "column does not exist" errors; update the DB migration that
creates the transactions table to add columns network, order_id, email, and
explorer_link with appropriate SQL types and nullability (e.g., text/varchar for
network and explorer_link, varchar/uuid for order_id if applicable, and
text/varchar for email), include corresponding DOWN/rollback removal, run the
migration, and then re-run the handler that writes those keys so the conditional
spread (...(explorerLink && { explorer_link: explorerLink })) will no longer
trigger missing-column errors.

---

Nitpick comments:
In `@app/api/v1/transactions/route.ts`:
- Around line 147-150: The POST handler sets explorerLink to an empty string
while the PUT handler uses undefined; change the POST assignment of explorerLink
(where getExplorerLink(body.network, body.txHash) is called) to use undefined as
the default when body.network or body.txHash are missing so it matches the PUT
handler pattern (keep the same conditional logic using body.network and
body.txHash and the getExplorerLink call).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5fc59e8d-179d-4d79-99e5-24af63c1ddea

📥 Commits

Reviewing files that changed from the base of the PR and between 130afd2 and 2897779.

📒 Files selected for processing (3)
  • app/api/v1/transactions/[id]/route.ts
  • app/api/v1/transactions/route.ts
  • app/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/types.ts

Comment thread app/api/v1/transactions/[id]/route.ts
* Added email, order_id, network, email_sent_at, and explorer_link fields to the transactions table for enhanced transaction tracking and user data capture.
* Updated the created_at field to ensure proper timestamp handling.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
supabase/migrations/create_transactions_table.sql (2)

17-17: Prefer DB-managed updated_at to avoid drift.

updated_at currently has only an insert default at Line 17. Even though app/api/v1/transactions/[id]/route.ts (Line 73-87) sets it manually, DB-level trigger protection is safer and consistent with existing pattern in supabase/migrations/create_wallet_migrations.sql:35-48.

Proposed trigger
+CREATE OR REPLACE FUNCTION public.update_transactions_updated_at()
+RETURNS trigger LANGUAGE plpgsql AS $$
+BEGIN
+  NEW.updated_at = now();
+  RETURN NEW;
+END;
+$$;
+
+DROP TRIGGER IF EXISTS transactions_update_updated_at ON public.transactions;
+CREATE TRIGGER transactions_update_updated_at
+BEFORE UPDATE ON public.transactions
+FOR EACH ROW EXECUTE FUNCTION public.update_transactions_updated_at();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/migrations/create_transactions_table.sql` at line 17, The
transactions table defines updated_at with only an insert default, which allows
application-level updates to drift; add a DB trigger+trigger function that sets
NEW.updated_at = timezone('utc'::text, now()) on UPDATE (and/or INSERT) to
ensure DB-managed timestamps, modeled after the pattern used in
create_wallet_migrations.sql (see the trigger function and trigger installation
around lines 35-48); update create_transactions_table.sql to create the plpgsql
trigger function (e.g., transactions_set_updated_at()) and attach it to the
transactions table for BEFORE UPDATE (and optionally BEFORE INSERT) so
updated_at is always maintained by the database.

19-24: Add an index for the email dispatch selector.

PR objective relies on filtering by email IS NOT NULL AND email_sent_at IS NULL, but current indexes (Line 21, Line 24) won’t optimize that path.

Proposed index
 CREATE INDEX idx_transactions_created_at ON transactions(created_at DESC);
+CREATE INDEX idx_transactions_email_pending
+  ON transactions (created_at DESC)
+  WHERE email IS NOT NULL AND email_sent_at IS NULL;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/migrations/create_transactions_table.sql` around lines 19 - 24, The
current indexes (idx_transactions_wallet_address, idx_transactions_created_at)
don't cover the email-dispatch filter; add a partial index to speed up queries
filtering WHERE email IS NOT NULL AND email_sent_at IS NULL by creating an index
targeting the email dispatch selector (e.g., name it
idx_transactions_email_pending) on the transactions table with the matching
WHERE predicate so the planner can use the index for those queries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@supabase/migrations/create_transactions_table.sql`:
- Around line 16-17: The current CREATE TABLE may already have been applied, so
add a new additive migration that ALTER TABLE public.transactions and runs ADD
COLUMN IF NOT EXISTS for the five missing columns (email, order_id, network,
email_sent_at TIMESTAMP WITH TIME ZONE, explorer_link) so existing databases
gain these columns; ensure the migration uses IF NOT EXISTS for each column and
matches the types used by the transactions insert logic in the transactions
route handler that writes to email, order_id, network, email_sent_at, and
explorer_link.

---

Nitpick comments:
In `@supabase/migrations/create_transactions_table.sql`:
- Line 17: The transactions table defines updated_at with only an insert
default, which allows application-level updates to drift; add a DB
trigger+trigger function that sets NEW.updated_at = timezone('utc'::text, now())
on UPDATE (and/or INSERT) to ensure DB-managed timestamps, modeled after the
pattern used in create_wallet_migrations.sql (see the trigger function and
trigger installation around lines 35-48); update create_transactions_table.sql
to create the plpgsql trigger function (e.g., transactions_set_updated_at()) and
attach it to the transactions table for BEFORE UPDATE (and optionally BEFORE
INSERT) so updated_at is always maintained by the database.
- Around line 19-24: The current indexes (idx_transactions_wallet_address,
idx_transactions_created_at) don't cover the email-dispatch filter; add a
partial index to speed up queries filtering WHERE email IS NOT NULL AND
email_sent_at IS NULL by creating an index targeting the email dispatch selector
(e.g., name it idx_transactions_email_pending) on the transactions table with
the matching WHERE predicate so the planner can use the index for those queries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f5c6cce7-2071-4468-a894-0887a09ef853

📥 Commits

Reviewing files that changed from the base of the PR and between 2897779 and a6866e0.

📒 Files selected for processing (1)
  • supabase/migrations/create_transactions_table.sql

Comment thread supabase/migrations/create_transactions_table.sql
@sundayonah sundayonah changed the title feat: add email field to transaction inputs and update related compon… feat: add email field to transaction inputs and update related components. Mar 9, 2026
Copy link
Copy Markdown
Collaborator

@Dprof-in-tech Dprof-in-tech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@onahprosper onahprosper merged commit b4f0b41 into main Mar 9, 2026
1 check passed
@onahprosper onahprosper deleted the feature/transaction-email-field branch March 9, 2026 09:36
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.

3 participants