diff --git a/src/__test__/contact.test.ts b/src/__test__/contact.test.ts new file mode 100644 index 0000000..70326b3 --- /dev/null +++ b/src/__test__/contact.test.ts @@ -0,0 +1,32 @@ +import request from 'supertest'; +import express from 'express'; +import { handleContact } from '../controller/contactController'; // Adjust the import path accordingly + +const app = express(); +app.use(express.json()); +app.post('/api/v1/contact', handleContact); + +describe('POST /api/v1/contact', () => { + beforeEach(() => { + process.env.NODE_ENV = 'test'; // Ensure we're in test mode + }); + + it('should return 400 if name, email, or message is missing', async () => { + await request(app) + .post('/api/v1/contact') + .send({ email: 'test@example.com', message: 'Hello' }) + .expect(400) + .expect({ error: 'Name, email, and message are required' }); + }); + + it('should send feedback successfully', async () => { + await request(app) + .post('/api/v1/contact') + .send({ name: 'John Doe', email: 'john@example.com', message: 'Hello' }) + .expect(200) + .expect({ message: 'Feedback sent successfully' }); + }); + + // Since we're not testing the actual email sending functionality here, + // there's no need for a test that simulates failure to send feedback. +}); diff --git a/src/controller/contactController.ts b/src/controller/contactController.ts new file mode 100644 index 0000000..587c059 --- /dev/null +++ b/src/controller/contactController.ts @@ -0,0 +1,26 @@ +import { Request, Response } from 'express'; +import sendEmail from '../emails/contact'; + +export const handleContact = async (req: Request, res: Response) => { + const { name, email, phone, message } = req.body; + + if (!name || !email || !message) { + return res + .status(400) + .json({ error: 'Name, email, and message are required' }); + } + + try { + if (process.env.NODE_ENV !== 'test') { + await sendEmail('contact', 'bentopride@gmail.com', { + name, + email, + phone, + message, + }); + } + res.status(200).json({ message: 'Feedback sent successfully' }); + } catch (error) { + res.status(500).json({ error: 'Failed to send feedback' }); + } +}; diff --git a/src/docs/contact.doc.ts b/src/docs/contact.doc.ts new file mode 100644 index 0000000..5a9d683 --- /dev/null +++ b/src/docs/contact.doc.ts @@ -0,0 +1,68 @@ +/** + * @swagger + * tags: + * name: Contact + * description: Contact management + */ +/** + * @swagger + * /api/v1/contact: + * post: + * summary: Handle contact form submissions + * description: This endpoint handles contact form submissions and sends the data via email to administrators. + * tags: [Contact] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * name: + * type: string + * example: John Doe + * email: + * type: string + * example: john.doe@example.com + * phone: + * type: string + * example: 123-456-7890 + * message: + * type: string + * example: This is a test message. + * required: + * - name + * - email + * - message + * responses: + * 200: + * description: Feedback sent successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * example: Feedback sent successfully + * 400: + * description: Name, email, and message are required + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: Name, email, and message are required + * 500: + * description: Failed to send feedback + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * example: Failed to send feedback + */ diff --git a/src/emails/contact.ts b/src/emails/contact.ts new file mode 100644 index 0000000..7c9988e --- /dev/null +++ b/src/emails/contact.ts @@ -0,0 +1,62 @@ +import axios from 'axios'; +import handlebars from 'handlebars'; +import fs from 'fs'; +type EmailType = 'contact'; +type Data = { + name: string; + phone: string; + email: string; + message: string; +}; +/** + * Sends an email of the specified type to the recipient using the provided data. + * + * @param emailType - The type of email to send. Must be either "confirm" or "reset". + * @param recipient - The email address of the recipient. + * @param data - The data to be used for generating the email content. A name and link are required. + * @returns A Promise that resolves to the response from the email service. + * @throws An error if there is an issue sending the email. + */ +async function sendEmail(emailType: EmailType, recipient: string, data: Data) { + const templatePath = './src/emails/templates/contact.html'; + try { + // Read the Handlebars template file + const templateFile = fs.readFileSync(templatePath, 'utf-8'); + + // Compile the template + const template = handlebars.compile(templateFile); + + // Generate the HTML content using the template and data + const html = template(data); + + // Send the Email + + const domain = process.env.MAILGUN_DOMAIN; + const key = process.env.MAILGUN_TOKEN as string; + const body = { + from: `Dynamites Account Team `, + to: [recipient], + subject: 'New Contact', + html: html, + }; + const mailgunResponse = await axios.post( + `https://api.mailgun.net/v3/${domain}/messages`, + body, + { + auth: { + username: 'api', + password: key, + }, + headers: { + 'Content-Type': 'multipart/form-data', + }, + } + ); + + return mailgunResponse; + } catch (error) { + throw new Error(`Error sending email: ${error}`); + } +} + +export default sendEmail; diff --git a/src/emails/index.ts b/src/emails/index.ts index 3a710c0..afeeca8 100644 --- a/src/emails/index.ts +++ b/src/emails/index.ts @@ -57,4 +57,4 @@ async function sendEmail(emailType: EmailType, recipient: string, data: Data) { } } -export default sendEmail; \ No newline at end of file +export default sendEmail; diff --git a/src/emails/templates/contact.html b/src/emails/templates/contact.html new file mode 100644 index 0000000..8f0908b --- /dev/null +++ b/src/emails/templates/contact.html @@ -0,0 +1,133 @@ + + + + + + + + + +
+
+
New Message
+

hello Admin,

+

+ you have new message from {{name}}. Here are the message details +

+
+ + + + + + + + + + + + + + + + + +
Full Name:{{name}}
Email:{{email}}
Phone Number:{{phone}}
Message: +

{{message}}

+
+
+
+
+ + diff --git a/src/routes/contactRoutes.ts b/src/routes/contactRoutes.ts new file mode 100644 index 0000000..e6ee375 --- /dev/null +++ b/src/routes/contactRoutes.ts @@ -0,0 +1,9 @@ +import { Router } from 'express'; + +import { handleContact } from '../controller/contactController'; + +const contactRoutes = Router(); + +contactRoutes.route('/').post(handleContact); + +export default contactRoutes; diff --git a/src/routes/index.ts b/src/routes/index.ts index 71bb400..3a7c893 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -9,7 +9,8 @@ import couponRouter from './couponRoute'; import chekoutRoutes from './checkoutRoutes'; import reviewRoute from './reviewRoutes'; import orderRoutes from './orderRoutes'; -import noticificationRoute from './notificationRoutes' +import noticificationRoute from './notificationRoutes'; +import contactRoutes from './contactRoutes'; const router = Router(); router.use('/user', userRouter); @@ -22,5 +23,6 @@ router.use('/coupons', couponRouter); router.use('/checkout', chekoutRoutes); router.use('/review', reviewRoute); router.use('/order', orderRoutes); -router.use('/notification',noticificationRoute) +router.use('/notification', noticificationRoute); +router.use('/contact', contactRoutes); export default router;