contact form working

This commit is contained in:
dimitar 2024-11-02 20:10:47 +01:00
parent 609475271e
commit 847ed031db
6 changed files with 176 additions and 124 deletions

View File

@ -17,3 +17,4 @@ SMTP_USER=mailer@imk.mk
SMTP_PASSWORD=76Avtostoperski76
SMTP_FROM=mailer@imk.mk
FRONTEND_URL=https://imk.mk
ADMIN_EMAIL=petrovskidimitar@yandex.com

View File

@ -49,7 +49,7 @@ export class AdminService {
data: {
...createUserDto,
password: hashedPassword,
isAdmin: true,
isAdmin: createUserDto.isAdmin,
},
});
}
@ -97,6 +97,7 @@ export class AdminService {
document.title,
document.uploadedBy.name,
);
console.log('Document shared with user:', sharedWithUser.email);
return document;
}

View File

@ -1,10 +1,15 @@
import { Controller, Post, Body } from '@nestjs/common';
import { EmailService } from './email.service';
import { MailerService } from '@nestjs-modules/mailer';
// import { MailerService } from '@nestjs-modules/mailer';
class ContactFormDto {
name: string;
email: string;
message: string;
}
@Controller('contact')
@Controller('email')
export class EmailController {
constructor(private emailService: MailerService) {}
constructor(private emailService: EmailService) {}
@Post()
async sendContactEmail(@Body() contactData: {
@ -12,17 +17,20 @@ export class EmailController {
email: string;
message: string;
}) {
await this.emailService.sendMail({
to: process.env.CONTACT_EMAIL,
subject: `Contact Form: ${contactData.name}`,
html: `
<h1>New Contact Form Submission</h1>
<p><strong>From:</strong> ${contactData.name}</p>
<p><strong>Email:</strong> ${contactData.email}</p>
<p><strong>Message:</strong></p>
<p>${contactData.message}</p>
`,
});
await this.emailService.sendContactEmail(
contactData.name,
contactData.email,
contactData.message
);
return { message: 'Contact form submitted successfully' };
}
@Post('contact')
async handleContactForm(@Body() contactData: ContactFormDto) {
await this.emailService.sendContactEmail(
contactData.name,
contactData.email,
contactData.message
);
return { message: 'Thank you for your message. We will contact you soon.' };
}
}

View File

@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
import { MailerModule } from '@nestjs-modules/mailer';
import { EmailService } from './email.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { EmailController } from './email.controller';
@Module({
imports: [
@ -24,6 +25,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
inject: [ConfigService],
}),
],
controllers: [EmailController],
providers: [EmailService],
exports: [EmailService],
})

View File

@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { Injectable, Post, Body } from '@nestjs/common';
import { MailerService } from '@nestjs-modules/mailer';
@Injectable()
@ -13,7 +13,10 @@ export class EmailService {
<h1>Welcome ${name}!</h1>
<p>Your account has been created successfully.</p>
<p>You can now login to access your documents.</p>
<p>Please use the following link to reset your password: </p>
<p>Best regards,<br>IMK Team</p>
`,
});
}
@ -42,4 +45,30 @@ export class EmailService {
`,
});
}
async sendContactEmail(name: string, email: string, message: string) {
// Send to admin
await this.mailerService.sendMail({
to: process.env.ADMIN_EMAIL,
subject: `New Contact Form Submission from ${name}`,
html: `
<h2>New Contact Form Submission</h2>
<p><strong>From:</strong> ${name}</p>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Message:</strong></p>
<p>${message}</p>
`,
});
await this.mailerService.sendMail({
to: email,
subject: 'Thank you for contacting us',
html: `
<h2>Thank you for contacting us</h2>
<p>Dear ${name},</p>
<p>We have received your message and will get back to you soon.</p>
<p>Your message:</p>
<blockquote>${message}</blockquote>
<p>Best regards,<br>IMK Team</p>
`,
});
}
}

View File

@ -1,115 +1,126 @@
import { useState } from 'react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import { Switch } from '@headlessui/react'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
import { useState, useEffect } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
export default function Contact() {
const [agreed, setAgreed] = useState(false)
const navigate = useNavigate();
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const [status, setStatus] = useState({ type: '', message: '' });
return (
<div className="isolate bg-gray px-6 bg-gradient-to-b from-cyan-900 to-cyan-800 sm:py-32 lg:px-8">
<div
aria-hidden="true"
>
useEffect(() => {
window.scrollTo({ top: 0, behavior: "smooth" });
}, []);
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
});
};
const handleSubmit = async (e) => {
e.preventDefault();
setStatus({ type: 'loading', message: 'Sending...' });
try {
await axios.post(`http://localhost:3000/email/contact`, formData);
setStatus({
type: 'success',
message: 'Thank you for your message. We will contact you soon.'
});
setFormData({ name: '', email: '', message: '' });
// Redirect to home page after 2 seconds
setTimeout(() => {
navigate('/');
}, 2000);
} catch (error) {
setStatus({
type: 'error',
message: 'There was an error sending your message. Please try again.'
});
}
};
return (
<div className="isolate bg-gray-900 px-6 py-24 sm:py-32 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-3xl font-bold tracking-tight text-white sm:text-4xl">Контактирајте нѐ</h2>
<p className="mt-2 text-lg leading-8 text-gray-300">
Имате прашања? Ние сме тука да помогнеме.
</p>
</div>
<form onSubmit={handleSubmit} className="mx-auto mt-16 max-w-xl sm:mt-20">
<div className="grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2">
<div className="sm:col-span-2">
<label htmlFor="name" className="block text-sm font-semibold leading-6 text-white">
Име и Презиме
</label>
<div className="mt-2.5">
<input
type="text"
name="name"
id="name"
value={formData.name}
onChange={handleChange}
required
className="block w-full rounded-md border-0 bg-white/5 px-3.5 py-2 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6"
/>
</div>
<div className="mx-auto max-w-2xl text-center mt-10">
<h2 className="text-3xl font-bold tracking-tight text-gray-900 sm:text-3xl">Пишете ни порака | Закажете средба</h2>
{/* <p className="mt-2 text-lg leading-8 text-gray-600">
take a wheel or let it slide
</p> */}
</div>
<div className="sm:col-span-2">
<label htmlFor="email" className="block text-sm font-semibold leading-6 text-white">
Емаил
</label>
<div className="mt-2.5">
<input
type="email"
name="email"
id="email"
value={formData.email}
onChange={handleChange}
required
className="block w-full rounded-md border-0 bg-white/5 px-3.5 py-2 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6"
/>
</div>
<form action="https://formsubmit.co/taratur@gmail.com" method="POST" className="mx-auto mt-16 max-w-xl sm:mt-20">
<div className="grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2">
<div>
<label htmlFor="first-name" className="block text-sm font-semibold leading-6 text-white">
Име
</label>
<div className="mt-2.5">
<input
type="text"
name="first-name"
id="first-name"
autoComplete="given-name"
className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div>
<label htmlFor="last-name" className="block text-sm font-semibold leading-6 text-white">
Презиме
</label>
<div className="mt-2.5">
<input
type="text"
name="last-name"
id="last-name"
autoComplete="family-name"
className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div className="sm:col-span-2">
<label htmlFor="company" className="block text-sm font-semibold leading-6 text-white">
Компанија
</label>
<div className="mt-2.5">
<input
type="text"
name="company"
id="company"
autoComplete="organization"
className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div className="sm:col-span-2">
<label htmlFor="email" className="block text-sm font-semibold leading-6 text-white">
Мејл
</label>
<div className="mt-2.5">
<input
type="email"
name="email"
id="email"
autoComplete="email"
className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div className="sm:col-span-2">
<label htmlFor="message" className="block text-sm font-semibold leading-6 text-white">
Порака
</label>
<div className="mt-2.5">
<textarea
name="message"
id="message"
rows={4}
className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
defaultValue={''}
/>
</div>
</div>
<Switch.Group as="div" className="flex gap-x-4 sm:col-span-2">
</Switch.Group>
</div>
<input type="hidden" name="_next" value="https://imk.mk/"></input>
<div className="mt-10">
<button
type="submit"
className="block w-full rounded-md bg-gray-500 px-3.5 py-2.5 text-center text-sm font-semibold text-white shadow-sm hover:bg-gray-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500"
>
Испрати
</button>
</div>
</form>
</div>
<div className="sm:col-span-2">
<label htmlFor="message" className="block text-sm font-semibold leading-6 text-white">
Порака
</label>
<div className="mt-2.5">
<textarea
name="message"
id="message"
rows={4}
value={formData.message}
onChange={handleChange}
required
className="block w-full rounded-md border-0 bg-white/5 px-3.5 py-2 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6"
/>
</div>
</div>
</div>
)
{status.message && (
<div className={`mt-4 text-center ${status.type === 'error' ? 'text-red-500' : 'text-green-500'}`}>
{status.message}
</div>
)}
<div className="mt-10">
<button
type="submit"
disabled={status.type === 'loading'}
className="block w-full rounded-md bg-indigo-600 px-3.5 py-2.5 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
{status.type === 'loading' ? 'Испраќање...' : 'Испрати Порака'}
</button>
</div>
</form>
</div>
);
}