text changes and remove infra folder

This commit is contained in:
jackiettran
2026-01-21 19:00:55 -05:00
parent 23ca97cea9
commit 420e0efeb4
39 changed files with 1170 additions and 3640 deletions

View File

@@ -42,7 +42,7 @@ class AlphaInvitationEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const variables = {
code: code,
@@ -54,13 +54,13 @@ class AlphaInvitationEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"alphaInvitationToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
email,
"Your Alpha Access Code - Village Share",
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send alpha invitation email", { error });

View File

@@ -44,7 +44,7 @@ class AuthEmailService {
await this.initialize();
}
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const verificationUrl = `${frontendUrl}/verify-email?token=${verificationToken}`;
const variables = {
@@ -55,13 +55,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"emailVerificationToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Verify Your Email - Village Share",
htmlContent
htmlContent,
);
}
@@ -78,7 +78,7 @@ class AuthEmailService {
await this.initialize();
}
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const resetUrl = `${frontendUrl}/reset-password?token=${resetToken}`;
const variables = {
@@ -88,13 +88,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"passwordResetToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Reset Your Password - Village Share",
htmlContent
htmlContent,
);
}
@@ -123,13 +123,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"passwordChangedToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Password Changed Successfully - Village Share",
htmlContent
htmlContent,
);
}
@@ -158,13 +158,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"personalInfoChangedToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Personal Information Updated - Village Share",
htmlContent
htmlContent,
);
}
@@ -188,13 +188,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"twoFactorOtpToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Your Verification Code - Village Share",
htmlContent
htmlContent,
);
}
@@ -222,13 +222,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"twoFactorEnabledToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Multi-Factor Authentication Enabled - Village Share",
htmlContent
htmlContent,
);
}
@@ -256,13 +256,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"twoFactorDisabledToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Multi-Factor Authentication Disabled - Village Share",
htmlContent
htmlContent,
);
}
@@ -302,13 +302,13 @@ class AuthEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"recoveryCodeUsedToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Recovery Code Used - Village Share",
htmlContent
htmlContent,
);
}
}

View File

@@ -60,13 +60,13 @@ class FeedbackEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"feedbackConfirmationToUser",
variables
variables,
);
return await this.emailClient.sendEmail(
user.email,
"Thank You for Your Feedback - Village Share",
htmlContent
htmlContent,
);
}
@@ -90,8 +90,7 @@ class FeedbackEmailService {
await this.initialize();
}
const adminEmail =
process.env.FEEDBACK_EMAIL || process.env.CUSTOMER_SUPPORT_EMAIL;
const adminEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
if (!adminEmail) {
console.warn("No admin email configured for feedback notifications");
@@ -117,13 +116,13 @@ class FeedbackEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"feedbackNotificationToAdmin",
variables
variables,
);
return await this.emailClient.sendEmail(
adminEmail,
`New Feedback from ${user.firstName} ${user.lastName}`,
htmlContent
htmlContent,
);
}
}

View File

@@ -57,7 +57,7 @@ class ForumEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const timestamp = new Date(comment.createdAt).toLocaleString("en-US", {
@@ -77,7 +77,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumCommentToPostAuthor",
variables
variables,
);
const subject = `${commenter.firstName} ${commenter.lastName} commented on your post`;
@@ -85,12 +85,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
postAuthor.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum comment notification email sent to ${postAuthor.email}`
`Forum comment notification email sent to ${postAuthor.email}`,
);
}
@@ -124,14 +124,14 @@ class ForumEmailService {
replier,
post,
reply,
parentComment
parentComment,
) {
if (!this.initialized) {
await this.initialize();
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const timestamp = new Date(reply.createdAt).toLocaleString("en-US", {
@@ -152,7 +152,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumReplyToCommentAuthor",
variables
variables,
);
const subject = `${replier.firstName} ${replier.lastName} replied to your comment`;
@@ -160,12 +160,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
commentAuthor.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum reply notification email sent to ${commentAuthor.email}`
`Forum reply notification email sent to ${commentAuthor.email}`,
);
}
@@ -195,14 +195,14 @@ class ForumEmailService {
commentAuthor,
postAuthor,
post,
comment
comment,
) {
if (!this.initialized) {
await this.initialize();
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const variables = {
@@ -216,7 +216,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumAnswerAcceptedToCommentAuthor",
variables
variables,
);
const subject = `Your comment was marked as the accepted answer!`;
@@ -224,12 +224,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
commentAuthor.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum answer accepted notification email sent to ${commentAuthor.email}`
`Forum answer accepted notification email sent to ${commentAuthor.email}`,
);
}
@@ -237,7 +237,7 @@ class ForumEmailService {
} catch (error) {
logger.error(
"Failed to send forum answer accepted notification email:",
error
error,
);
return { success: false, error: error.message };
}
@@ -263,14 +263,14 @@ class ForumEmailService {
participant,
commenter,
post,
comment
comment,
) {
if (!this.initialized) {
await this.initialize();
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const timestamp = new Date(comment.createdAt).toLocaleString("en-US", {
@@ -290,7 +290,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumThreadActivityToParticipant",
variables
variables,
);
const subject = `New activity on a post you're following`;
@@ -298,12 +298,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
participant.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum thread activity notification email sent to ${participant.email}`
`Forum thread activity notification email sent to ${participant.email}`,
);
}
@@ -311,7 +311,7 @@ class ForumEmailService {
} catch (error) {
logger.error(
"Failed to send forum thread activity notification email:",
error
error,
);
return { success: false, error: error.message };
}
@@ -331,18 +331,13 @@ class ForumEmailService {
* @param {Date} closedAt - Timestamp when discussion was closed
* @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
*/
async sendForumPostClosedNotification(
recipient,
closer,
post,
closedAt
) {
async sendForumPostClosedNotification(recipient, closer, post, closedAt) {
if (!this.initialized) {
await this.initialize();
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const timestamp = new Date(closedAt).toLocaleString("en-US", {
@@ -352,8 +347,7 @@ class ForumEmailService {
const variables = {
recipientName: recipient.firstName || "there",
adminName:
`${closer.firstName} ${closer.lastName}`.trim() || "A user",
adminName: `${closer.firstName} ${closer.lastName}`.trim() || "A user",
postTitle: post.title,
postUrl: postUrl,
timestamp: timestamp,
@@ -361,7 +355,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumPostClosed",
variables
variables,
);
const subject = `Discussion closed: ${post.title}`;
@@ -369,12 +363,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
recipient.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum post closed notification email sent to ${recipient.email}`
`Forum post closed notification email sent to ${recipient.email}`,
);
}
@@ -382,7 +376,7 @@ class ForumEmailService {
} catch (error) {
logger.error(
"Failed to send forum post closed notification email:",
error
error,
);
return { success: false, error: error.message };
}
@@ -401,18 +395,24 @@ class ForumEmailService {
* @param {string} deletionReason - Reason for deletion
* @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
*/
async sendForumPostDeletionNotification(postAuthor, admin, post, deletionReason) {
async sendForumPostDeletionNotification(
postAuthor,
admin,
post,
deletionReason,
) {
if (!this.initialized) {
await this.initialize();
}
try {
const supportEmail = process.env.SUPPORT_EMAIL;
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const supportEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
const frontendUrl = process.env.FRONTEND_URL;
const variables = {
postAuthorName: postAuthor.firstName || "there",
adminName: `${admin.firstName} ${admin.lastName}`.trim() || "An administrator",
adminName:
`${admin.firstName} ${admin.lastName}`.trim() || "An administrator",
postTitle: post.title,
deletionReason,
supportEmail,
@@ -421,7 +421,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumPostDeletionToAuthor",
variables
variables,
);
const subject = `Important: Your forum post "${post.title}" has been removed`;
@@ -429,12 +429,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
postAuthor.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum post deletion notification email sent to ${postAuthor.email}`
`Forum post deletion notification email sent to ${postAuthor.email}`,
);
}
@@ -442,7 +442,7 @@ class ForumEmailService {
} catch (error) {
logger.error(
"Failed to send forum post deletion notification email:",
error
error,
);
return { success: false, error: error.message };
}
@@ -462,19 +462,25 @@ class ForumEmailService {
* @param {string} deletionReason - Reason for deletion
* @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
*/
async sendForumCommentDeletionNotification(commentAuthor, admin, post, deletionReason) {
async sendForumCommentDeletionNotification(
commentAuthor,
admin,
post,
deletionReason,
) {
if (!this.initialized) {
await this.initialize();
}
try {
const supportEmail = process.env.SUPPORT_EMAIL;
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const supportEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const variables = {
commentAuthorName: commentAuthor.firstName || "there",
adminName: `${admin.firstName} ${admin.lastName}`.trim() || "An administrator",
adminName:
`${admin.firstName} ${admin.lastName}`.trim() || "An administrator",
postTitle: post.title,
postUrl,
deletionReason,
@@ -483,7 +489,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumCommentDeletionToAuthor",
variables
variables,
);
const subject = `Your comment on "${post.title}" has been removed`;
@@ -491,12 +497,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
commentAuthor.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Forum comment deletion notification email sent to ${commentAuthor.email}`
`Forum comment deletion notification email sent to ${commentAuthor.email}`,
);
}
@@ -504,7 +510,7 @@ class ForumEmailService {
} catch (error) {
logger.error(
"Failed to send forum comment deletion notification email:",
error
error,
);
return { success: false, error: error.message };
}
@@ -531,7 +537,7 @@ class ForumEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const postUrl = `${frontendUrl}/forum/posts/${post.id}`;
const variables = {
@@ -546,7 +552,7 @@ class ForumEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"forumItemRequestNotification",
variables
variables,
);
const subject = `Someone nearby is looking for: ${post.title}`;
@@ -554,12 +560,12 @@ class ForumEmailService {
const result = await this.emailClient.sendEmail(
recipient.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Item request notification email sent to ${recipient.email}`
`Item request notification email sent to ${recipient.email}`,
);
}

View File

@@ -50,7 +50,7 @@ class MessagingEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const conversationUrl = `${frontendUrl}/messages/conversations/${sender.id}`;
const timestamp = new Date(message.createdAt).toLocaleString("en-US", {
@@ -68,7 +68,7 @@ class MessagingEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"newMessageToUser",
variables
variables,
);
const subject = `New message from ${sender.firstName} ${sender.lastName}`;
@@ -76,12 +76,12 @@ class MessagingEmailService {
const result = await this.emailClient.sendEmail(
receiver.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {
logger.info(
`Message notification email sent to ${receiver.email} from ${sender.firstName} ${sender.lastName}`
`Message notification email sent to ${receiver.email} from ${sender.firstName} ${sender.lastName}`,
);
}

View File

@@ -49,12 +49,8 @@ class PaymentEmailService {
}
try {
const {
renterFirstName,
itemName,
declineReason,
updatePaymentUrl,
} = params;
const { renterFirstName, itemName, declineReason, updatePaymentUrl } =
params;
const variables = {
renterFirstName: renterFirstName || "there",
@@ -65,13 +61,13 @@ class PaymentEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"paymentDeclinedToRenter",
variables
variables,
);
return await this.emailClient.sendEmail(
renterEmail,
`Action Required: Payment Issue - ${itemName || "Your Rental"}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send payment declined notification", { error });
@@ -105,16 +101,18 @@ class PaymentEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"paymentMethodUpdatedToOwner",
variables
variables,
);
return await this.emailClient.sendEmail(
ownerEmail,
`Payment Method Updated - ${itemName || "Your Item"}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send payment method updated notification", { error });
logger.error("Failed to send payment method updated notification", {
error,
});
return { success: false, error: error.message };
}
}
@@ -151,22 +149,25 @@ class PaymentEmailService {
const variables = {
ownerName: ownerName || "there",
payoutAmount: payoutAmount?.toFixed(2) || "0.00",
failureMessage: failureMessage || "There was an issue with your payout.",
actionRequired: actionRequired || "Please check your bank account details.",
failureMessage:
failureMessage || "There was an issue with your payout.",
actionRequired:
actionRequired || "Please check your bank account details.",
failureCode: failureCode || "unknown",
requiresBankUpdate: requiresBankUpdate || false,
payoutSettingsUrl: payoutSettingsUrl || process.env.FRONTEND_URL + "/settings/payouts",
payoutSettingsUrl:
payoutSettingsUrl || process.env.FRONTEND_URL + "/settings/payouts",
};
const htmlContent = await this.templateManager.renderTemplate(
"payoutFailedToOwner",
variables
variables,
);
return await this.emailClient.sendEmail(
ownerEmail,
"Action Required: Payout Issue - Village Share",
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send payout failed notification", { error });
@@ -200,13 +201,13 @@ class PaymentEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"accountDisconnectedToOwner",
variables
variables,
);
return await this.emailClient.sendEmail(
ownerEmail,
"Your payout account has been disconnected - Village Share",
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send account disconnected email", { error });
@@ -240,13 +241,13 @@ class PaymentEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"payoutsDisabledToOwner",
variables
variables,
);
return await this.emailClient.sendEmail(
ownerEmail,
"Action Required: Your payouts have been paused - Village Share",
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send payouts disabled email", { error });
@@ -289,16 +290,16 @@ class PaymentEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"disputeAlertToAdmin",
variables
variables,
);
// Send to admin email (configure in env)
const adminEmail = process.env.ADMIN_EMAIL || process.env.SES_FROM_EMAIL;
const adminEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
return await this.emailClient.sendEmail(
adminEmail,
`URGENT: Payment Dispute - Rental #${disputeData.rentalId}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send dispute alert email", { error });
@@ -326,22 +327,24 @@ class PaymentEmailService {
const variables = {
rentalId: disputeData.rentalId,
amount: disputeData.amount.toFixed(2),
ownerPayoutAmount: parseFloat(disputeData.ownerPayoutAmount || 0).toFixed(2),
ownerPayoutAmount: parseFloat(
disputeData.ownerPayoutAmount || 0,
).toFixed(2),
ownerName: disputeData.ownerName || "Unknown",
ownerEmail: disputeData.ownerEmail || "Unknown",
};
const htmlContent = await this.templateManager.renderTemplate(
"disputeLostAlertToAdmin",
variables
variables,
);
const adminEmail = process.env.ADMIN_EMAIL || process.env.SES_FROM_EMAIL;
const adminEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
return await this.emailClient.sendEmail(
adminEmail,
`ACTION REQUIRED: Dispute Lost - Owner Already Paid - Rental #${disputeData.rentalId}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send dispute lost alert email", { error });

View File

@@ -62,7 +62,7 @@ class RentalFlowEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const approveUrl = `${frontendUrl}/owning?rentalId=${rental.id}`;
const variables = {
@@ -95,13 +95,13 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"rentalRequestToOwner",
variables
variables,
);
return await this.emailClient.sendEmail(
owner.email,
`Rental Request for ${rental.item?.name || "Your Item"}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send rental request email", { error });
@@ -129,7 +129,7 @@ class RentalFlowEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const viewRentalsUrl = `${frontendUrl}/renting`;
// Determine payment message based on rental amount
@@ -162,16 +162,18 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"rentalRequestConfirmationToRenter",
variables
variables,
);
return await this.emailClient.sendEmail(
renter.email,
`Rental Request Submitted - ${rental.item?.name || "Item"}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send rental request confirmation email", { error });
logger.error("Failed to send rental request confirmation email", {
error,
});
return { success: false, error: error.message };
}
}
@@ -203,7 +205,7 @@ class RentalFlowEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
// Determine if Stripe setup is needed
const hasStripeAccount = !!owner.stripeConnectedAccountId;
@@ -250,7 +252,7 @@ class RentalFlowEmailService {
<div class="warning-box">
<p><strong>⚠️ Action Required: Set Up Your Earnings Account</strong></p>
<p>To receive your payout of <strong>$${payoutAmount.toFixed(
2
2,
)}</strong> when this rental completes, you need to set up your earnings account.</p>
</div>
<h2>Set Up Earnings to Get Paid</h2>
@@ -276,7 +278,7 @@ class RentalFlowEmailService {
<div class="success-box">
<p><strong>✓ Earnings Account Active</strong></p>
<p>Your earnings account is set up. You'll automatically receive $${payoutAmount.toFixed(
2
2,
)} when this rental completes.</p>
<p><a href="${frontendUrl}/earnings" style="color: #155724; text-decoration: underline;">View your earnings dashboard →</a></p>
</div>
@@ -313,7 +315,7 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"rentalApprovalConfirmationToOwner",
variables
variables,
);
const subject = `Rental Approved - ${rental.item?.name || "Your Item"}`;
@@ -321,10 +323,12 @@ class RentalFlowEmailService {
return await this.emailClient.sendEmail(
owner.email,
subject,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send rental approval confirmation email", { error });
logger.error("Failed to send rental approval confirmation email", {
error,
});
return { success: false, error: error.message };
}
}
@@ -351,7 +355,7 @@ class RentalFlowEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const browseItemsUrl = `${frontendUrl}/`;
// Determine payment message based on rental amount
@@ -398,13 +402,13 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"rentalDeclinedToRenter",
variables
variables,
);
return await this.emailClient.sendEmail(
renter.email,
`Rental Request Declined - ${rental.item?.name || "Item"}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send rental declined email", { error });
@@ -438,7 +442,7 @@ class RentalFlowEmailService {
notification,
rental,
recipientName = null,
isRenter = false
isRenter = false,
) {
if (!this.initialized) {
await this.initialize();
@@ -533,7 +537,7 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"rentalConfirmationToUser",
variables
variables,
);
// Use clear, transactional subject line with item name
@@ -602,10 +606,12 @@ class RentalFlowEmailService {
ownerNotification,
rental,
owner.firstName,
false // isRenter = false for owner
false, // isRenter = false for owner
);
if (ownerResult.success) {
logger.info("Rental confirmation email sent to owner", { email: owner.email });
logger.info("Rental confirmation email sent to owner", {
email: owner.email,
});
results.ownerEmailSent = true;
} else {
logger.error("Failed to send rental confirmation email to owner", {
@@ -629,10 +635,12 @@ class RentalFlowEmailService {
renterNotification,
rental,
renter.firstName,
true // isRenter = true for renter (enables payment receipt)
true, // isRenter = true for renter (enables payment receipt)
);
if (renterResult.success) {
logger.info("Rental confirmation email sent to renter", { email: renter.email });
logger.info("Rental confirmation email sent to renter", {
email: renter.email,
});
results.renterEmailSent = true;
} else {
logger.error("Failed to send rental confirmation email to renter", {
@@ -648,7 +656,9 @@ class RentalFlowEmailService {
}
}
} catch (error) {
logger.error("Error fetching user data for rental confirmation emails", { error });
logger.error("Error fetching user data for rental confirmation emails", {
error,
});
}
return results;
@@ -687,7 +697,7 @@ class RentalFlowEmailService {
};
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const browseUrl = `${frontendUrl}/`;
const cancelledBy = rental.cancelledBy;
@@ -731,7 +741,7 @@ class RentalFlowEmailService {
<div class="info-box">
<p><strong>Full Refund Processed</strong></p>
<p>You will receive a full refund of $${refundInfo.amount.toFixed(
2
2,
)}. The refund will appear in your account within 5-10 business days.</p>
</div>
<div style="text-align: center">
@@ -774,7 +784,7 @@ class RentalFlowEmailService {
<div class="refund-amount">$${refundInfo.amount.toFixed(2)}</div>
<div class="info-box">
<p><strong>Refund Amount:</strong> $${refundInfo.amount.toFixed(
2
2,
)} (${refundPercentage}% of total)</p>
<p><strong>Reason:</strong> ${refundInfo.reason}</p>
<p><strong>Processing Time:</strong> Refunds typically appear within 5-10 business days.</p>
@@ -804,13 +814,13 @@ class RentalFlowEmailService {
const confirmationHtml = await this.templateManager.renderTemplate(
"rentalCancellationConfirmationToUser",
confirmationVariables
confirmationVariables,
);
const confirmationResult = await this.emailClient.sendEmail(
confirmationRecipient,
`Cancellation Confirmed - ${itemName}`,
confirmationHtml
confirmationHtml,
);
if (confirmationResult.success) {
@@ -841,13 +851,13 @@ class RentalFlowEmailService {
const notificationHtml = await this.templateManager.renderTemplate(
"rentalCancellationNotificationToUser",
notificationVariables
notificationVariables,
);
const notificationResult = await this.emailClient.sendEmail(
notificationRecipient,
`Rental Cancelled - ${itemName}`,
notificationHtml
notificationHtml,
);
if (notificationResult.success) {
@@ -858,7 +868,9 @@ class RentalFlowEmailService {
results.notificationEmailSent = true;
}
} catch (error) {
logger.error("Failed to send cancellation notification email", { error });
logger.error("Failed to send cancellation notification email", {
error,
});
}
} catch (error) {
logger.error("Error sending cancellation emails", { error });
@@ -896,7 +908,7 @@ class RentalFlowEmailService {
await this.initialize();
}
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const results = {
renterEmailSent: false,
ownerEmailSent: false,
@@ -968,17 +980,19 @@ class RentalFlowEmailService {
const renterHtmlContent = await this.templateManager.renderTemplate(
"rentalCompletionThankYouToRenter",
renterVariables
renterVariables,
);
const renterResult = await this.emailClient.sendEmail(
renter.email,
`Thank You for Returning "${rental.item?.name || "Item"}" On Time!`,
renterHtmlContent
renterHtmlContent,
);
if (renterResult.success) {
logger.info("Rental completion thank you email sent to renter", { email: renter.email });
logger.info("Rental completion thank you email sent to renter", {
email: renter.email,
});
results.renterEmailSent = true;
} else {
logger.error("Failed to send rental completion email to renter", {
@@ -1035,7 +1049,7 @@ class RentalFlowEmailService {
<div class="warning-box">
<p><strong>⚠️ Action Required: Set Up Your Earnings Account</strong></p>
<p>To receive your payout of <strong>$${payoutAmount.toFixed(
2
2,
)}</strong>, you need to set up your earnings account.</p>
</div>
<h2>Set Up Earnings to Get Paid</h2>
@@ -1061,7 +1075,7 @@ class RentalFlowEmailService {
<div class="success-box">
<p><strong>✓ Payout Initiated</strong></p>
<p>Your earnings of <strong>$${payoutAmount.toFixed(
2
2,
)}</strong> have been transferred to your Stripe account.</p>
<p style="font-size: 14px; margin-top: 10px;">Funds typically reach your bank within 2-7 business days.</p>
<p><a href="${frontendUrl}/earnings" style="color: #155724; text-decoration: underline;">View your earnings dashboard →</a></p>
@@ -1086,17 +1100,19 @@ class RentalFlowEmailService {
const ownerHtmlContent = await this.templateManager.renderTemplate(
"rentalCompletionCongratsToOwner",
ownerVariables
ownerVariables,
);
const ownerResult = await this.emailClient.sendEmail(
owner.email,
`Rental Complete - ${rental.item?.name || "Your Item"}`,
ownerHtmlContent
ownerHtmlContent,
);
if (ownerResult.success) {
logger.info("Rental completion congratulations email sent to owner", { email: owner.email });
logger.info("Rental completion congratulations email sent to owner", {
email: owner.email,
});
results.ownerEmailSent = true;
} else {
logger.error("Failed to send rental completion email to owner", {
@@ -1145,7 +1161,7 @@ class RentalFlowEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const earningsDashboardUrl = `${frontendUrl}/earnings`;
// Format currency values
@@ -1177,7 +1193,7 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"payoutReceivedToOwner",
variables
variables,
);
return await this.emailClient.sendEmail(
@@ -1185,7 +1201,7 @@ class RentalFlowEmailService {
`Earnings Received - $${payoutAmount.toFixed(2)} for ${
rental.item?.name || "Your Item"
}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send payout received email", { error });
@@ -1223,13 +1239,13 @@ class RentalFlowEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"authenticationRequiredToRenter",
variables
variables,
);
return await this.emailClient.sendEmail(
email,
`Action Required: Complete payment for ${itemName}`,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send authentication required email", { error });

View File

@@ -47,7 +47,7 @@ class UserEngagementEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const frontendUrl = process.env.FRONTEND_URL;
const variables = {
ownerName: owner.firstName || "there",
@@ -58,7 +58,7 @@ class UserEngagementEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"firstListingCelebrationToOwner",
variables
variables,
);
const subject = `Congratulations! Your first item is live on Village Share`;
@@ -66,7 +66,7 @@ class UserEngagementEmailService {
return await this.emailClient.sendEmail(
owner.email,
subject,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send first listing celebration email", { error });
@@ -91,8 +91,8 @@ class UserEngagementEmailService {
}
try {
const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const supportEmail = process.env.SUPPORT_EMAIL;
const frontendUrl = process.env.FRONTEND_URL;
const supportEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
const variables = {
ownerName: owner.firstName || "there",
@@ -104,7 +104,7 @@ class UserEngagementEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"itemDeletionToOwner",
variables
variables,
);
const subject = `Important: Your listing "${item.name}" has been removed`;
@@ -112,10 +112,12 @@ class UserEngagementEmailService {
return await this.emailClient.sendEmail(
owner.email,
subject,
htmlContent
htmlContent,
);
} catch (error) {
logger.error("Failed to send item deletion notification email", { error });
logger.error("Failed to send item deletion notification email", {
error,
});
return { success: false, error: error.message };
}
}
@@ -137,7 +139,7 @@ class UserEngagementEmailService {
}
try {
const supportEmail = process.env.SUPPORT_EMAIL;
const supportEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
const variables = {
userName: bannedUser.firstName || "there",
@@ -147,15 +149,16 @@ class UserEngagementEmailService {
const htmlContent = await this.templateManager.renderTemplate(
"userBannedNotification",
variables
variables,
);
const subject = "Important: Your Village Share Account Has Been Suspended";
const subject =
"Important: Your Village Share Account Has Been Suspended";
const result = await this.emailClient.sendEmail(
bannedUser.email,
subject,
htmlContent
htmlContent,
);
if (result.success) {