diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2199c54e --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +run-dev: + docker-compose up \ No newline at end of file diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 00000000..c4ad5211 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,20 @@ +# Dockerfile for Node Express Backend + +FROM node:14-alpine + +# Create App Directory +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +# Install Dependencies +COPY package*.json ./ + +RUN npm install + +# Copy app source code +COPY . . + +# Exports +EXPOSE 3500 + +CMD ["npm","start"] \ No newline at end of file diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 00000000..69e0fedd --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,5 @@ +# "make build" will give us the backend image +build: + docker build -t api-server . + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..f31ea9f4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,58 @@ +version: "3.7" + +services: + api-server: + build: + context: ./backend/ + dockerfile: Dockerfile + image: api-server + container_name: myapp-node-server + command: /usr/src/app/node_modules/.bin/nodemon index.js + volumes: + - ./backend/:/usr/src/app + - /usr/src/app/node_modules + ports: + - "3500:3500" + depends_on: + - mongo + env_file: ./backend/.env + environment: + - NODE_ENV=development + networks: + - community-app + mongo: + image: mongo:4.4-bionic + volumes: + - mongo-data:/data/db + ports: + - "27017:27017" + networks: + - community-app + react-app: + build: + context: ./frontend/ + dockerfile: Dockerfile + image: react-app + stdin_open: true + container_name: myapp-react-frontend + command: npm start + volumes: + - ./frontend/:/usr/src/app + - /usr/src/app/node_modules + depends_on: + - api-server + ports: + - "3000:3000" + networks: + - community-app + +networks: + community-app: + driver: bridge + +volumes: + mongo-data: + driver: local + node_modules: + web-root: + driver: local diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 00000000..154e9cd1 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,20 @@ +# Dockerfile for React client + +# Build react client +FROM node:14-alpine + +# Working directory be app +WORKDIR /usr/src/app + +COPY package*.json ./ + +### Installing dependencies + +RUN npm install + +# copy local files to app folder +COPY . . + +EXPOSE 3000 + +CMD ["npm","start"] \ No newline at end of file diff --git a/frontend/Makefile b/frontend/Makefile new file mode 100644 index 00000000..d908ff7c --- /dev/null +++ b/frontend/Makefile @@ -0,0 +1,5 @@ +# "make build" will give us the frontend image +build: + docker build -t react-app . + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a8093325..a8f2325f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2019,6 +2019,31 @@ "prop-types": "^15.6.2" } }, + "@sideway/address": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", + "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "requires": { + "@hapi/hoek": "^9.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", + "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + } + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, "@sinonjs/commons": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", @@ -7761,6 +7786,11 @@ "resolved": "https://registry.npmjs.org/goober/-/goober-2.0.33.tgz", "integrity": "sha512-Wy9HYzmmqmB1PTMQCY3+hlREZ4Lk7kaac6PZeWlJxOM6lIO9lsrU2yBu33TiougO0AC6bBxxIVueDP+nEGNWJw==" }, + "google-libphonenumber": { + "version": "3.2.17", + "resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.17.tgz", + "integrity": "sha512-T1fBQ3ujlpo4VUe0palZVHxBkY1zsfCShkS3l1rNq/d5C6C1SIijo8aXzgpJeGQFB8Bk+C36o6jhLl05NtfQ3w==" + }, "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", @@ -10322,11 +10352,46 @@ "supports-color": "^7.0.0" } }, + "joi": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.0.tgz", + "integrity": "sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + }, + "dependencies": { + "@hapi/hoek": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", + "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + }, + "@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + } + } + }, "joi-browser": { "version": "13.4.0", "resolved": "https://registry.npmjs.org/joi-browser/-/joi-browser-13.4.0.tgz", "integrity": "sha512-TfzJd2JaJ/lg/gU+q5j9rLAjnfUNF9DUmXTP9w+GfmG79LjFOXFeM7hIFuXCBcZCivUDFwd9l1btTV9rhHumtQ==" }, + "joi-phone-number": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/joi-phone-number/-/joi-phone-number-5.0.1.tgz", + "integrity": "sha512-gVzKD2WETDxAONmdt79tF9LHEfr2M6AtSyZ8/FnkQkF9qln6PF5wuzjrr9555uB7R+LbAQdFNgYN2UETzPn5ew==", + "requires": { + "google-libphonenumber": "3.2.17" + } + }, "jquery": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 2a087416..fed59d67 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,7 +12,9 @@ "bootstrap": "^4.5.3", "bootstrap-social": "^5.1.1", "font-awesome": "^4.7.0", + "joi": "^17.4.0", "joi-browser": "^13.4.0", + "joi-phone-number": "^5.0.1", "jwt-decode": "^3.1.2", "mdbreact": "^5.0.1", "node-sass": "^4.14.1", diff --git a/frontend/src/pages/Home/components/JoinUsForm/Form.jsx b/frontend/src/pages/Home/components/JoinUsForm/Form.jsx index 78e724c3..fbaf4942 100644 --- a/frontend/src/pages/Home/components/JoinUsForm/Form.jsx +++ b/frontend/src/pages/Home/components/JoinUsForm/Form.jsx @@ -1,12 +1,37 @@ import React, { useState } from "react"; import Joi from "joi-browser"; +<<<<<<< HEAD +======= import MultiSelect from "react-multi-select-component"; +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 import styles from "./form.module.scss"; import { Button2 } from "../../../../components/util/Button/index"; + export const JoinUsForm = (props) => { let dark = props.theme; +<<<<<<< HEAD + const [formData, setFormData] = useState({ + name: "", + email: "", + link: "", + desc: "", + dept: null, + college: "", + }); + + const [formerrors, setFormErrors] = useState({}); + + const schema = { + name: Joi.string().min(3).required(), + email: Joi.string() + .email({ tlds: { allow: false } }) + .required(), + link: Joi.string().uri().required(), + desc: Joi.string().required(), + dept: Joi.required(), +======= const [formdata, setFormData] = useState({ name: "", phone: "", @@ -46,11 +71,16 @@ export const JoinUsForm = (props) => { other: Joi.string().allow(""), dept: Joi.string().allow(""), year: Joi.number().required(), +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 college: Joi.string().required(), }; const validate = () => { +<<<<<<< HEAD + const result = Joi.validate(formData, schema, { abortEarly: false }); +======= const result = Joi.validate(formdata, schema, { abortEarly: false }); +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 if (!result.error) return null; const errors = {}; for (let item of result.error.details) { @@ -67,6 +97,32 @@ export const JoinUsForm = (props) => { return result.error ? result.error.details[0].message : null; }; +<<<<<<< HEAD + const handleSubmit = (e) => { + e.preventDefault(); + const errors = validate(); + Object.keys(formData).map((key) => { + if (formData[key] === "" || formData[key] === null) { + errors[key] = `${key} is not allowed to be empty`; + } + return 0; + }); + if (errors["info"]) { + delete errors["info"]; + } + if (Object.keys(errors).length !== 0) { + setFormErrors(errors); + } + if (Object.keys(errors).length !== 0) { + console.log(errors); + } else { + //Call the Server + console.log("Submitted"); + } + }; + +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 const handleChange = (e) => { const { currentTarget: input } = e; const errors = { ...formerrors }; @@ -74,12 +130,18 @@ export const JoinUsForm = (props) => { if (errorMessage) errors[input.name] = errorMessage; else delete errors[input.name]; +<<<<<<< HEAD + const data = { ...formData }; +======= const data = { ...formdata }; +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 data[input.name] = input.value; setFormData({ ...data, [input.name]: input.value }); setFormErrors(errors); }; +<<<<<<< HEAD +======= const handleSubmit = (e) => { e.preventDefault(); const errors = validate(); @@ -100,6 +162,7 @@ export const JoinUsForm = (props) => { console.log("form error: ", formerrors); console.log("form data: ", formdata, domains); +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 return (
{ > Join Us Form +<<<<<<< HEAD + +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0
@@ -149,6 +216,10 @@ export const JoinUsForm = (props) => { placeholder="Name" id="txt_name" type="text" +<<<<<<< HEAD + required="required" +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 name="name" onChange={handleChange} /> @@ -156,10 +227,15 @@ export const JoinUsForm = (props) => {
+<<<<<<< HEAD + {formerrors["name"] && ( +
{formerrors["name"]}
+======= {formerrors["name"] ? (
* {formerrors["name"]}
) : (
   
+>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 )}
@@ -176,6 +252,12 @@ export const JoinUsForm = (props) => { placeholder="Contact No." id="phone" type="tel" +<<<<<<< HEAD + required="required" + name="phone" + /> + +======= name="phone" onChange={handleChange} /> @@ -189,6 +271,7 @@ export const JoinUsForm = (props) => {
   
)}
+>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0
@@ -204,6 +287,10 @@ export const JoinUsForm = (props) => { placeholder="Email ID" id="txt_email" type="text" +<<<<<<< HEAD + required="required" +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 name="email" onChange={handleChange} /> @@ -213,7 +300,13 @@ export const JoinUsForm = (props) => {
+<<<<<<< HEAD + {formerrors["email"] && ( +
{formerrors["email"]}
+ )} +======= {formerrors["email"] &&
* {formerrors["email"]}
} +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0
@@ -229,6 +322,10 @@ export const JoinUsForm = (props) => { placeholder="Linkedin Profile URL" id="txt_link" type="text" +<<<<<<< HEAD + required="required" +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 name="link" onChange={handleChange} /> @@ -236,10 +333,15 @@ export const JoinUsForm = (props) => {
+<<<<<<< HEAD + {formerrors["link"] && ( +
{formerrors["link"]}
+======= {formerrors["link"] ? (
* {formerrors["link"]}
) : (
   
+>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 )}
@@ -257,16 +359,25 @@ export const JoinUsForm = (props) => { rows="2" cols="20" name="desc" +<<<<<<< HEAD + required="required" +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 onChange={handleChange} >
+<<<<<<< HEAD + {formerrors["desc"] && ( +
{formerrors["desc"]}
+======= {formerrors["desc"] ? (
* {formerrors["desc"]}
) : (
   
+>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 )}
@@ -280,6 +391,227 @@ export const JoinUsForm = (props) => { +<<<<<<< HEAD +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+======= { ) : (
   
)} +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0
@@ -430,6 +763,10 @@ export const JoinUsForm = (props) => { placeholder="College Name" id="txt_college" type="text" +<<<<<<< HEAD + required="required" +======= +>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 name="college" onChange={handleChange} /> @@ -439,10 +776,17 @@ export const JoinUsForm = (props) => {
+<<<<<<< HEAD + {formerrors["college"] && ( +
+ {formerrors["college"]} +
+======= {formerrors["college"] ? (
* {formerrors["college"]}
) : (
   
+>>>>>>> dc1fd2dcc269733b2aacb998fc61a9a99de38cc0 )}