├── api ├── index.php └── contact │ ├── config.php │ ├── index.php │ └── classes │ └── sendmail.php ├── app ├── .env ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── Dockerfile ├── .gitignore ├── package.json └── src │ ├── index.js │ └── components │ └── Form │ ├── styles.css │ └── index.js ├── config-obj.png ├── screenshot.png ├── .travis.yml ├── site.conf ├── .github └── FUNDING.yml ├── docker-compose.yml ├── .all-contributorsrc ├── README.md └── LICENSE /api/index.php: -------------------------------------------------------------------------------- 1 | 0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /api/contact/index.php: -------------------------------------------------------------------------------- 1 | false, 14 | "message" => $SendMailEmptyerrorMessage 15 | ] 16 | ); 17 | exit(); 18 | } 19 | 20 | if ($_POST){ 21 | //@important: Please change this before using 22 | http_response_code(200); 23 | $subject = 'Contact from: ' . $_POST['firstName']; 24 | $from = $_POST['email']; 25 | $message = $_POST['msg']; 26 | //Actual sending email 27 | $sendEmail = new Sender($adminEmail, $from, $subject, $message); 28 | $sendEmail->send(); 29 | } else { 30 | // tell the user about error 31 | echo json_encode( 32 | [ 33 | "sent" => false, 34 | "message" => $SendMailFailederrorMessage 35 | ] 36 | ); 37 | } -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "malithmcr", 10 | "name": "Malith Priyashan", 11 | "avatar_url": "https://avatars3.githubusercontent.com/u/4549859?v=4", 12 | "profile": "https://craftcode.design/", 13 | "contributions": [ 14 | "infra", 15 | "test", 16 | "code" 17 | ] 18 | }, 19 | { 20 | "login": "bretwadleigh", 21 | "name": "Bret Wadleigh", 22 | "avatar_url": "https://avatars3.githubusercontent.com/u/923404?v=4", 23 | "profile": "http://bretwadleigh.net", 24 | "contributions": [ 25 | "maintenance" 26 | ] 27 | }, 28 | { 29 | "login": "hans2103", 30 | "name": "Hans Kuijpers", 31 | "avatar_url": "https://avatars2.githubusercontent.com/u/639822?v=4", 32 | "profile": "https://hkweb.nl", 33 | "contributions": [ 34 | "code" 35 | ] 36 | }, 37 | { 38 | "login": "cscheerio", 39 | "name": "cscheerio", 40 | "avatar_url": "https://avatars.githubusercontent.com/u/49214389?v=4", 41 | "profile": "https://github.com/cscheerio", 42 | "contributions": [ 43 | "maintenance" 44 | ] 45 | } 46 | ], 47 | "contributorsPerLine": 7, 48 | "projectName": "react-php-contact-form", 49 | "projectOwner": "malithmcr", 50 | "repoType": "github", 51 | "repoHost": "https://github.com", 52 | "skipCi": true 53 | } 54 | -------------------------------------------------------------------------------- /app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Form from '../src/components/Form'; 4 | 5 | /** 6 | * @config preparing config prop. 7 | * api: url for the server endpoint 8 | * title: form title 9 | * successMessage: message will show in the UI when mail is successfully sent. 10 | * errorMessage: message will show in the UI when mail is not sent. 11 | * fields: this is the name of each field. This should be exact order of the fieldsConfig and fieldsConfig.fieldName should be the same 12 | * fieldsConfig = settings for each input/textarea field 13 | */ 14 | const config = { 15 | api: `${process.env.REACT_APP_API}`, 16 | title: 'Contact Me', 17 | description: 'Write us about your request, We\'ll get back to you within 24 hours.', 18 | successMessage: 'Thank you for contacting me.', 19 | errorMessage: 'Please fill the complete form', 20 | fields:{ 21 | firstName: '', 22 | lastName: '', 23 | email: '', 24 | msg: '' 25 | }, 26 | fieldsConfig: [ 27 | { id: 1, label: 'First Name', fieldName: 'firstName', type: 'text',placeholder:'Your First Name', isRequired: true , klassName:'first-name-field'}, 28 | { id: 2, label: 'Last Name', fieldName: 'lastName', type: 'text', placeholder: 'Your Last Name', isRequired: true , klassName:'last-name-field'}, 29 | { id: 3, label: 'Email', fieldName: 'email', type: 'email', placeholder: ' Your Email', isRequired: true , klassName:'email-field'}, 30 | { id: 4, label: 'Message', fieldName: 'msg', type: 'textarea',placeholder:'Write something.....', isRequired: true , klassName:'message-field'} 31 | ] 32 | } 33 | ReactDOM.render(
, document.getElementById('root')); 34 | -------------------------------------------------------------------------------- /app/src/components/Form/styles.css: -------------------------------------------------------------------------------- 1 | * {box-sizing: border-box;} 2 | 3 | .contact-form { 4 | max-width: 510px; 5 | margin: 30px auto; 6 | } 7 | 8 | .contact-form__container { 9 | border: 1px solid #f5f5f5; 10 | padding: 35px; 11 | box-shadow: 2px 2px 10px 0 #f5f5f5; 12 | } 13 | .contact-form__container p{ 14 | margin: 0; 15 | text-align: left; 16 | } 17 | .contact-form__header h2{ 18 | color: #4a4a4a; 19 | } 20 | .contact-form__header p{ 21 | margin-bottom: 0; 22 | color: #4a4a4a; 23 | color: #311c56; 24 | } 25 | .contact-form__header{ 26 | background: #f7f7f7; 27 | padding: 2px 35px 31px; 28 | margin: 0; 29 | border-top-left-radius: 5px; 30 | border-top-right-radius: 5px; 31 | } 32 | p { 33 | text-align: center; 34 | font-weight: 500; 35 | } 36 | 37 | input[type=text],input[type=email], select, textarea { 38 | width: 100%; 39 | padding: 12px; 40 | border: 1px solid #ccc; 41 | border-radius: 4px; 42 | box-sizing: border-box; 43 | margin-top: 6px; 44 | margin-bottom: 16px; 45 | resize: vertical; 46 | } 47 | 48 | input[type=submit] { 49 | background-color: #311c56; 50 | color: white; 51 | padding: 12px 20px; 52 | border: none; 53 | border-radius: 4px; 54 | cursor: pointer; 55 | width: 100%; 56 | } 57 | textarea{ 58 | height: 140px; 59 | } 60 | input[type=submit]:hover { 61 | background-color: #140c23; 62 | } 63 | 64 | .container { 65 | border-radius: 5px; 66 | background-color: #f2f2f2; 67 | padding: 20px; 68 | } 69 | .sucsess { 70 | margin: 20px 0; 71 | border: 1px solid green; 72 | padding: 7px; 73 | font-weight: bold; 74 | } 75 | 76 | .error { 77 | margin: 20px 0; 78 | border: 1px solid red; 79 | padding: 7px; 80 | font-weight: bold; 81 | } -------------------------------------------------------------------------------- /app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React PHP Contact form | Tutorial 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /api/contact/classes/sendmail.php: -------------------------------------------------------------------------------- 1 | sendTo = $sendTo; 18 | $this->sendFrom = ($sendFrom) ? $sendFrom : 'hey@malith.dev'; 19 | $this->subject = $subject; 20 | $this->message = $message; 21 | } 22 | 23 | public function setTo($email, $name) { 24 | return $this->sendTo = $email; 25 | } 26 | 27 | public function getTo() { 28 | return $this->sendTo; 29 | } 30 | 31 | public function setFrom($email, $name) { 32 | return $this->sendFrom = $email; 33 | } 34 | 35 | public function setSubject($subject) { 36 | return $this->subject = $subject; 37 | } 38 | 39 | public function getSubject() { 40 | return $this->subject; 41 | } 42 | 43 | public function setMessage($message) { 44 | $this->message = $message; 45 | return $this; 46 | } 47 | 48 | public function getMessage() { 49 | return $this->message; 50 | } 51 | 52 | public function setHeader() { 53 | $headers = 'From: '.$this->getFrom() . "\r\n" . 54 | 'Reply-To: '.$this->getFrom() . "\r\n" . 55 | 'X-Mailer: PHP/' . phpversion(); 56 | 57 | $this->headers = $headers; 58 | return $this; 59 | } 60 | 61 | public function getFrom() { 62 | return $this->sendFrom; 63 | } 64 | 65 | public function send() { 66 | $to = $this->sendTo; 67 | $from = $this->sendFrom; 68 | $subject = $this->subject; 69 | $message = $this->message; 70 | //$headers = $this->headers; 71 | $headers = 'From: '.$this->getFrom() . "\r\n" . 72 | 'Reply-To: '.$this->getFrom() . "\r\n" . 73 | 'X-Mailer: PHP/' . phpversion(); 74 | 75 | mail($to, $subject, $message, $headers); 76 | echo json_encode(array("sent" => true)); 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/components/Form/index.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from "react"; 2 | import PropTypes from "prop-types"; 3 | import axios from "axios"; 4 | import "./styles.css"; 5 | 6 | /** 7 | * @component Form 8 | * @props - { object } - config 9 | */ 10 | const Form = (props) => { 11 | const [mailSent, setmailSent] = useState(false); 12 | const [error, setError] = useState(null); 13 | const [formData, setFormData] = useState({}); 14 | 15 | /** 16 | * @function handleFormSubmit 17 | * @param e { obj } - form event 18 | * @return void 19 | */ 20 | const handleFormSubmit = e => { 21 | e.preventDefault(); 22 | axios({ 23 | method: "post", 24 | url: `${process.env.REACT_APP_API}`, 25 | headers: { "content-type": "application/json" }, 26 | data: formData 27 | }) 28 | .then(result => { 29 | if (result.data.sent) { 30 | setmailSent(result.data.sent) 31 | setError(false) 32 | } else { 33 | setError(true) 34 | } 35 | }) 36 | .catch(error => setError( error.message )); 37 | }; 38 | /** 39 | * @function handleChange 40 | * @param e { obj } - change event 41 | * @param field { string } - namve of the field 42 | * @return void 43 | */ 44 | const handleChange = (e, field) => { 45 | let value = e.target.value; 46 | setFormData({ 47 | ...formData, 48 | [field]: value, 49 | }); 50 | }; 51 | 52 | const { title,description, successMessage, errorMessage, fieldsConfig } = props.config; 53 | return ( 54 |
55 |
56 |

{title}

57 |

{description}

58 |
59 |
60 |
61 | 62 | {fieldsConfig && 63 | fieldsConfig.map(field => { 64 | return ( 65 | 66 | {field.type !== "textarea" ? ( 67 | 68 | 69 | handleChange(e, field.fieldName)} 75 | /> 76 | 77 | ) : ( 78 | 79 | 80 |