Browse Source

contactform added

dev
khang 6 months ago
parent
commit
136274aa4e
6 changed files with 169 additions and 17 deletions
  1. +2
    -1
      .gitignore
  2. +15
    -0
      package-lock.json
  3. +1
    -0
      package.json
  4. +25
    -0
      src/App.css
  5. +104
    -0
      src/components/ContactForm.js
  6. +22
    -16
      src/components/Navbar.js

+ 2
- 1
.gitignore View File

@ -10,7 +10,8 @@
# production # production
/build /build
# sensitive files
/src/components/apikey.js
# misc # misc
.DS_Store .DS_Store
.env.local .env.local


+ 15
- 0
package-lock.json View File

@ -12,6 +12,7 @@
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"emailjs-com": "^3.2.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-bootstrap": "^2.10.4", "react-bootstrap": "^2.10.4",
"react-bootstrap-icons": "^1.11.4", "react-bootstrap-icons": "^1.11.4",
@ -7299,6 +7300,15 @@
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.822.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.822.tgz",
"integrity": "sha512-qJzHIt4dRRFKjHHvaExCrG95F65kUP3xysaEZ4I2+/R/uIyr5Ar5g/rkAnrRz0parRUYwzpqN8Pz1HgoiYQPpg==" "integrity": "sha512-qJzHIt4dRRFKjHHvaExCrG95F65kUP3xysaEZ4I2+/R/uIyr5Ar5g/rkAnrRz0parRUYwzpqN8Pz1HgoiYQPpg=="
}, },
"node_modules/emailjs-com": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/emailjs-com/-/emailjs-com-3.2.0.tgz",
"integrity": "sha512-Prbz3E1usiAwGjMNYRv6EsJ5c373cX7/AGnZQwOfrpNJrygQJ15+E9OOq4pU8yC977Z5xMetRfc3WmDX6RcjAA==",
"deprecated": "The SDK name changed to @emailjs/browser",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/emittery": { "node_modules/emittery": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
@ -23616,6 +23626,11 @@
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.822.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.822.tgz",
"integrity": "sha512-qJzHIt4dRRFKjHHvaExCrG95F65kUP3xysaEZ4I2+/R/uIyr5Ar5g/rkAnrRz0parRUYwzpqN8Pz1HgoiYQPpg==" "integrity": "sha512-qJzHIt4dRRFKjHHvaExCrG95F65kUP3xysaEZ4I2+/R/uIyr5Ar5g/rkAnrRz0parRUYwzpqN8Pz1HgoiYQPpg=="
}, },
"emailjs-com": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/emailjs-com/-/emailjs-com-3.2.0.tgz",
"integrity": "sha512-Prbz3E1usiAwGjMNYRv6EsJ5c373cX7/AGnZQwOfrpNJrygQJ15+E9OOq4pU8yC977Z5xMetRfc3WmDX6RcjAA=="
},
"emittery": { "emittery": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",


+ 1
- 0
package.json View File

@ -7,6 +7,7 @@
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"emailjs-com": "^3.2.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-bootstrap": "^2.10.4", "react-bootstrap": "^2.10.4",
"react-bootstrap-icons": "^1.11.4", "react-bootstrap-icons": "^1.11.4",


+ 25
- 0
src/App.css View File

@ -358,3 +358,28 @@ nav.navbar .navbar-toggler[aria-expanded="true"] .navbar-toggler-icon {
background-size: cover; background-size: cover;
padding-top: 150px; /* Same as the padding top of the banner */ padding-top: 150px; /* Same as the padding top of the banner */
} }
/* contactform */
.modal-header {
background-color: #121212;
color: white;
}
.modal-body {
background-color: #f8f9fa;
}
.modal-footer {
background-color: #121212;
}
.btn-primary {
background-color: #007bff;
border-color: #007bff;
}
.btn-primary:hover {
background-color: #0056b3;
border-color: #0056b3;
}

+ 104
- 0
src/components/ContactForm.js View File

@ -0,0 +1,104 @@
// src/components/ContactForm.js
import React, { useState } from 'react';
import { Modal, Button, Form } from 'react-bootstrap';
import emailjs from 'emailjs-com';
import emailConfig from './apikey';
const ContactForm = ({ show, handleClose }) => {
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
message: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value
});
};
const handleSubmit = (e) => {
e.preventDefault();
emailjs.send(
emailConfig.serviceId, // EmailJS service ID
emailConfig.templateId, // EmailJS template ID
formData,
emailConfig.userId // EmailJS user ID
)
.then((result) => {
alert('Message sent successfully!');
handleClose();
}, (error) => {
alert('Failed to send message, please try again.');
});
};
return (
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Contact Me</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Form.Group controlId="formFirstName">
<Form.Label>First Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter your first name"
name="firstName"
value={formData.firstName}
onChange={handleChange}
required
/>
</Form.Group>
<Form.Group controlId="formLastName">
<Form.Label>Last Name</Form.Label>
<Form.Control
type="text"
placeholder="Enter your last name"
name="lastName"
value={formData.lastName}
onChange={handleChange}
required
/>
</Form.Group>
<Form.Group controlId="formEmail">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
placeholder="Enter your email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
</Form.Group>
<Form.Group controlId="formMessage">
<Form.Label>Message</Form.Label>
<Form.Control
as="textarea"
rows={3}
placeholder="Enter your message"
name="message"
value={formData.message}
onChange={handleChange}
required
/>
</Form.Group>
<Button variant="primary" type="submit">
Send Message
</Button>
</Form>
</Modal.Body>
</Modal>
);
};
export default ContactForm;

+ 22
- 16
src/components/Navbar.js View File

@ -1,13 +1,19 @@
import React, { useState, useEffect } from "react";
import { Container, Nav, Navbar } from "react-bootstrap";
import logo from "../assets/img/logo.svg";
import navIcon from "../assets/img/github.svg";
import linkedin from "../assets/img/linkedln.svg"
// src/components/NavBar.js
import React, { useState, useEffect } from 'react';
import { Container, Nav, Navbar } from 'react-bootstrap';
import logo from '../assets/img/logo.svg';
import navIcon from '../assets/img/github.svg';
import linkedin from '../assets/img/linkedln.svg';
import ContactForm from './ContactForm';
const NavBar = () => { const NavBar = () => {
const [activeLink, setActiveLink] = useState("home");
const [activeLink, setActiveLink] = useState('home');
const [scrolled, setScrolled] = useState(false); const [scrolled, setScrolled] = useState(false);
const [showContactForm, setShowContactForm] = useState(false);
const handleShowContactForm = () => setShowContactForm(true);
const handleCloseContactForm = () => setShowContactForm(false);
// Check for scrolling
useEffect(() => { useEffect(() => {
const onScroll = () => { const onScroll = () => {
if (window.scrollY > 50) { if (window.scrollY > 50) {
@ -17,10 +23,9 @@ const NavBar = () => {
} }
}; };
window.addEventListener("scroll", onScroll);
window.addEventListener('scroll', onScroll);
// Remove event listener when component unmounts
return () => window.removeEventListener("scroll", onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []); }, []);
const onUpdateLink = (value) => { const onUpdateLink = (value) => {
@ -28,7 +33,7 @@ const NavBar = () => {
}; };
return ( return (
<Navbar expand="lg" className={scrolled ? "scrolled" : ""}>
<Navbar expand="lg" className={scrolled ? 'scrolled' : ''}>
<Container> <Container>
<Navbar.Brand href="#home"> <Navbar.Brand href="#home">
<img src={logo} alt="Logo" /> <img src={logo} alt="Logo" />
@ -39,18 +44,18 @@ const NavBar = () => {
<Nav.Link <Nav.Link
href="#home" href="#home"
className={ className={
activeLink === "home" ? "active navbar-link" : "navbar-link"
activeLink === 'home' ? 'active navbar-link' : 'navbar-link'
} }
onClick={() => onUpdateLink("home")}
onClick={() => onUpdateLink('home')}
> >
Home Home
</Nav.Link> </Nav.Link>
<Nav.Link <Nav.Link
href="#projects" href="#projects"
className={ className={
activeLink === "projects" ? "active navbar-link" : "navbar-link"
activeLink === 'projects' ? 'active navbar-link' : 'navbar-link'
} }
onClick={() => onUpdateLink("projects")}
onClick={() => onUpdateLink('projects')}
> >
Projects Projects
</Nav.Link> </Nav.Link>
@ -64,12 +69,13 @@ const NavBar = () => {
<img src={linkedin} alt="linkedin Icon" /> <img src={linkedin} alt="linkedin Icon" />
</a> </a>
</div> </div>
<button className="vvd" onClick={() => console.log("connect")}>
<button className="vvd" onClick={handleShowContactForm}>
<span>Let's connect!</span> <span>Let's connect!</span>
</button> </button>
</span> </span>
</Navbar.Collapse> </Navbar.Collapse>
</Container> </Container>
<ContactForm show={showContactForm} handleClose={handleCloseContactForm} />
</Navbar> </Navbar>
); );
}; };


Loading…
Cancel
Save