diff --git a/client/src/lib/api.ts b/client/src/lib/api.ts
new file mode 100644
index 0000000..03300da
--- /dev/null
+++ b/client/src/lib/api.ts
@@ -0,0 +1,34 @@
+export async function sendAuthCode(payload: {
+ email?: string;
+ phoneNumber?: string;
+ firstName?: string;
+ lastName?: string;
+}) {
+ const res = await fetch("/api/auth/send-code", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+ if (!res.ok) {
+ const err = await res.json().catch(() => ({ message: "Failed to send code" }));
+ throw new Error(err.message || "Failed to send code");
+ }
+ return res.json();
+}
+
+export async function verifyAuthCode(payload: {
+ email?: string;
+ phoneNumber?: string;
+ code: string;
+}) {
+ const res = await fetch("/api/auth/verify-code", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+ if (!res.ok) {
+ const err = await res.json().catch(() => ({ message: "Failed to verify code" }));
+ throw new Error(err.message || "Failed to verify code");
+ }
+ return res.json();
+}
\ No newline at end of file
diff --git a/server/email-service.ts b/server/email-service.ts
index 2540559..8d825b0 100644
--- a/server/email-service.ts
+++ b/server/email-service.ts
@@ -1,120 +1,127 @@
-// SendGrid email service integration
-import sgMail from '@sendgrid/mail';
+import nodemailer from "nodemailer";
-class EmailService {
- private initialized = false;
+type SendResult = { success: boolean; info?: any };
- constructor() {
- this.initialize();
- }
+const SMTP_HOST = process.env.SMTP_HOST;
+const SMTP_PORT = process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT, 10) : undefined;
+const SMTP_USER = process.env.SMTP_USER;
+const SMTP_PASS = process.env.SMTP_PASS;
+const SMTP_SECURE = process.env.SMTP_SECURE === "true";
- private initialize() {
- try {
- const apiKey = process.env.SENDGRID_API_KEY;
-
- if (!apiKey) {
- console.log('SendGrid API key not found - email verification disabled');
- console.log('Set SENDGRID_API_KEY environment variable to enable email verification');
- return;
- }
+let transporter: nodemailer.Transporter | null = null;
- if (!apiKey.startsWith('SG.')) {
- console.warn('Warning: SendGrid API key format appears invalid (should start with "SG.")');
- }
+if (SMTP_HOST && SMTP_PORT && SMTP_USER && SMTP_PASS) {
+ transporter = nodemailer.createTransport({
+ host: SMTP_HOST,
+ port: SMTP_PORT,
+ secure: SMTP_SECURE || SMTP_PORT === 465,
+ auth: {
+ user: SMTP_USER,
+ pass: SMTP_PASS,
+ },
+ });
+}
- sgMail.setApiKey(apiKey);
- this.initialized = true;
- console.log('✓ SendGrid email service initialized successfully');
- } catch (error) {
- console.error('Failed to initialize SendGrid:', error);
- }
- }
+function verificationEmailHtml(code: string, firstName?: string) {
+ const name = firstName ? `Hi ${firstName},` : "Hello,";
+ return `
+
+
${name}
+
Your verification code for Instant Plumber Connect is:
+
${code}
+
This code expires in 10 minutes. If you did not request this, please ignore this email.
+
+
If you have trouble signing in, contact support.
+
+ `;
+}
- isReady(): boolean {
- return this.initialized;
- }
+function welcomeEmailHtml(firstName?: string) {
+ const name = firstName ? `Hi ${firstName},` : "Welcome,";
+ return `
+
+
${name}
+
Welcome to Instant Plumber Connect — glad to have you on board.
+
Start by updating your profile and verifying your contact details.
+
+
Thank you,
The Instant Plumber Connect Team
+
+ `;
+}
- async sendVerificationEmail(email: string, code: string, firstName?: string): Promise {
- if (!this.initialized) {
- console.log('Email service not initialized - cannot send verification email');
- return false;
- }
+export const emailService = {
+ isReady() {
+ return transporter !== null || process.env.NODE_ENV === "development";
+ },
+ async sendVerificationEmail(to: string, code: string, firstName?: string): Promise {
try {
- const msg = {
- to: email,
- from: 'noreply@instantplumberconnect.com', // Replace with your verified sender
- subject: 'Your Instant Plumber Connect Verification Code',
- text: `Your verification code is: ${code}`,
- html: `
-
-
Instant Plumber Connect
-
Hello ${firstName || 'there'},
-
Your verification code is:
-
-
${code}
-
-
This code will expire in 10 minutes.
-
If you didn't request this verification, please ignore this email.
-
-
- Instant Plumber Connect - Professional plumbing services made simple
-
-
- `,
- };
-
- await sgMail.send(msg);
- console.log(`Verification email sent successfully to ${email}`);
- return true;
- } catch (error: any) {
- console.error('SendGrid email error:', error);
-
- // Handle specific SendGrid errors
- if (error.response) {
- console.error('SendGrid response error:', {
- status: error.response.status,
- body: error.response.body
+ const subject = "Your Instant Plumber Connect verification code";
+ const html = verificationEmailHtml(code, firstName);
+ if (transporter) {
+ const info = await transporter.sendMail({
+ from: process.env.EMAIL_FROM || `"Instant Plumber Connect" `,
+ to,
+ subject,
+ html,
+ text: `Your verification code is ${code}`,
});
+ console.log("Verification email sent:", info.messageId);
+ return true;
+ } else {
+ // Development fallback: log code so you can test without SMTP configured
+ console.log(`[DEV EMAIL] To: ${to} Subject: ${subject} Code: ${code}`);
+ return true;
}
-
+ } catch (err) {
+ console.error("Error sending verification email:", err);
return false;
}
- }
+ },
- async sendWelcomeEmail(email: string, firstName: string): Promise {
- if (!this.initialized) {
+ async sendWelcomeEmail(to: string, firstName?: string): Promise {
+ try {
+ const subject = "Welcome to Instant Plumber Connect";
+ const html = welcomeEmailHtml(firstName);
+ if (transporter) {
+ const info = await transporter.sendMail({
+ from: process.env.EMAIL_FROM || `"Instant Plumber Connect" `,
+ to,
+ subject,
+ html,
+ text: `Welcome to Instant Plumber Connect.`,
+ });
+ console.log("Welcome email sent:", info.messageId);
+ return true;
+ } else {
+ console.log(`[DEV EMAIL] To: ${to} Subject: ${subject}`);
+ return true;
+ }
+ } catch (err) {
+ console.error("Error sending welcome email:", err);
return false;
}
+ },
+ async sendGenericEmail(to: string, subject: string, html: string): Promise {
try {
- const msg = {
- to: email,
- from: 'noreply@instantplumberconnect.com',
- subject: 'Welcome to Instant Plumber Connect!',
- html: `
-
-
Welcome to Instant Plumber Connect!
-
Hello ${firstName},
-
Your plumber account has been successfully created. You can now:
-
- - Receive instant video call requests from customers
- - Manage your availability status
- - Track your earnings and call history
-
-
Start receiving calls by setting yourself as available in your dashboard!
-
- `,
- };
-
- await sgMail.send(msg);
- console.log(`Welcome email sent to ${email}`);
- return true;
- } catch (error) {
- console.error('Error sending welcome email:', error);
- return false;
+ if (transporter) {
+ const info = await transporter.sendMail({
+ from: process.env.EMAIL_FROM || `"Instant Plumber Connect" `,
+ to,
+ subject,
+ html,
+ });
+ return { success: true, info };
+ } else {
+ console.log(`[DEV EMAIL] To: ${to} Subject: ${subject} HTML: ${html}`);
+ return { success: true, info: "dev-fallback" };
+ }
+ } catch (err) {
+ console.error("Error sending email:", err);
+ return { success: false, info: err };
}
- }
-}
+ },
+};
-export const emailService = new EmailService();
\ No newline at end of file
+export default emailService;
\ No newline at end of file