├── .github
└── workflows
│ └── codesee-arch-diagram.yml
├── .gitignore
├── LICENSE
├── MeowForm Badge Final.svg
├── README.md
├── backend
├── Modles
│ ├── forms.js
│ └── user.js
├── connectDb.js
├── index.js
├── package-lock.json
├── package.json
├── router
│ ├── Respond.js
│ ├── Response.js
│ ├── addForm.js
│ ├── addUrl.js
│ ├── index.html
│ ├── user.js
│ └── views
│ │ └── submited.html
└── utility
│ ├── addForm.js
│ ├── createUser.js
│ ├── searchUser.js
│ ├── sendMail.js
│ ├── updateUrl.js
│ └── updateUser.js
├── package-lock.json
├── package.json
├── public
├── MeowForm Icon.svg
├── favicon.png
├── index.html
├── manifest.json
├── review_avtar.jpeg
└── robots.txt
├── src
├── App.css
├── App.js
├── App.test.js
├── Util
│ └── AuthWithHistory.js
├── comp
│ ├── Comp
│ │ ├── Faq.js
│ │ ├── Footer.js
│ │ ├── FormCard.js
│ │ ├── FormData.js
│ │ ├── FormHeading.js
│ │ ├── MenuButtons.js
│ │ ├── MenuItems.js
│ │ ├── NavBar.js
│ │ └── Review.js
│ └── Skeletons
│ │ └── FullPage.js
├── data
│ └── faq.js
├── index.css
├── index.js
├── logo.svg
├── pages
│ ├── Dashboard
│ │ └── Dashboard.js
│ ├── Home
│ │ └── Home.js
│ └── Index.js
├── reportWebVitals.js
├── setupTests.js
└── styles
│ └── faq.css
└── yarn.lock
/.github/workflows/codesee-arch-diagram.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | pull_request_target:
6 | types: [opened, synchronize, reopened]
7 |
8 | name: CodeSee Map
9 |
10 | jobs:
11 | test_map_action:
12 | runs-on: ubuntu-latest
13 | continue-on-error: true
14 | name: Run CodeSee Map Analysis
15 | steps:
16 | - name: checkout
17 | id: checkout
18 | uses: actions/checkout@v2
19 | with:
20 | repository: ${{ github.event.pull_request.head.repo.full_name }}
21 | ref: ${{ github.event.pull_request.head.ref }}
22 | fetch-depth: 0
23 |
24 | # codesee-detect-languages has an output with id languages.
25 | - name: Detect Languages
26 | id: detect-languages
27 | uses: Codesee-io/codesee-detect-languages-action@latest
28 |
29 | - name: Configure JDK 16
30 | uses: actions/setup-java@v2
31 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }}
32 | with:
33 | java-version: '16'
34 | distribution: 'zulu'
35 |
36 | # CodeSee Maps Go support uses a static binary so there's no setup step required.
37 |
38 | - name: Configure Node.js 14
39 | uses: actions/setup-node@v2
40 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }}
41 | with:
42 | node-version: '14'
43 |
44 | - name: Configure Python 3.x
45 | uses: actions/setup-python@v2
46 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }}
47 | with:
48 | python-version: '3.x'
49 | architecture: 'x64'
50 |
51 | - name: Configure Ruby '3.x'
52 | uses: ruby/setup-ruby@v1
53 | if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }}
54 | with:
55 | ruby-version: '3.0'
56 |
57 | # CodeSee Maps Rust support uses a static binary so there's no setup step required.
58 |
59 | - name: Generate Map
60 | id: generate-map
61 | uses: Codesee-io/codesee-map-action@latest
62 | with:
63 | step: map
64 | github_ref: ${{ github.ref }}
65 | languages: ${{ steps.detect-languages.outputs.languages }}
66 |
67 | - name: Upload Map
68 | id: upload-map
69 | uses: Codesee-io/codesee-map-action@latest
70 | with:
71 | step: mapUpload
72 | api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
73 | github_ref: ${{ github.ref }}
74 |
75 | - name: Insights
76 | id: insights
77 | uses: Codesee-io/codesee-map-action@latest
78 | with:
79 | step: insights
80 | api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
81 | github_ref: ${{ github.ref }}
82 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # drepndencies
3 |
4 | /backend/node_modules
5 | /backend/node_modules/
6 | /.pnp
7 | .pnp.js
8 |
9 | /node_modules
10 | # testing
11 | /coverage
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 | .env
23 | .ejnfdjknv
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Gaurav Tewari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MeowForm Badge Final.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
${title[i]} : ${entry[i]}
`
51 | }
52 | // console.log(mailBody);
53 | let data = JSON.stringify(req.body);
54 |
55 |
56 | let meow = await updateUser(userData[0]._id,formName, title,entry,formData);
57 | res.status(200).json({msg : 'Response Saved'});
58 |
59 | mg.messages().send( {
60 | from: 'Cheese 🐱',
61 | to: email,
62 | subject: `You have got a new Response in ${formName} Meow! UvU `,
63 | html: `${mailBody} buy Cheese some cat food 🐟 `
64 | } , function (error, body) {
65 |
66 | if(error){
67 | console.log(error);
68 | }else{
69 | console.log(body);
70 | }
71 | });
72 |
73 |
74 |
75 |
76 | });
77 | module.exports = router;
--------------------------------------------------------------------------------
/backend/router/Response.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | var axios = require("axios").default;
4 | const searchUser = require("../utility/searchUser");
5 | const updateUser = require("../utility/updateUser");
6 | const mailgun = require("mailgun-js");
7 | const DOMAIN = process.env.Domain ;
8 | const api_key = process.env.API_MONEY;
9 | const mg = mailgun({apiKey: api_key, domain: DOMAIN});
10 |
11 | const app = express();
12 |
13 | app.set('view engine','ejs');
14 | app.set('views', './views');
15 |
16 |
17 | router.post("/:email&:formName",async(req,res)=>{
18 |
19 |
20 |
21 |
22 | let email = req.params.email ;
23 | let userData = await searchUser(email) ;
24 | if(userData == ""){
25 | res.send("You must signUp with that email to use MeowFroms");
26 | return;
27 | }
28 |
29 | // console.log(userData[0].forms.length);
30 | let formName = req.params.formName;
31 | let temp = req.body;
32 |
33 | let formData = JSON.stringify(temp);
34 | temp = JSON.stringify(temp);
35 | temp = temp.replace(/{/g," ");
36 | temp = temp.replace(/}/g," ");
37 | temp = temp.split(",");
38 | let title = [];
39 | let entry = [];
40 | for(let i=0;i${title[i]} : ${entry[i]}
`
51 | }
52 | // console.log(mailBody);
53 | let data = JSON.stringify(req.body);
54 |
55 |
56 | let meow = await updateUser(userData[0]._id,formName, title,entry,formData);
57 | res.sendFile("./views/submited.html" ,{root :__dirname });
58 |
59 | mg.messages().send( {
60 | from: 'Cheese 🐱',
61 | to: email,
62 | subject: `You have got a new Response in ${formName} Meow! UvU `,
63 | html: `${mailBody} buy Cheese some cat food 🐟 `
64 | } , function (error, body) {
65 |
66 | if(error){
67 | console.log(error);
68 | }else{
69 | console.log(body);
70 | }
71 | });
72 |
73 |
74 |
75 |
76 | });
77 | module.exports = router;
--------------------------------------------------------------------------------
/backend/router/addForm.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const addFrom = require("../utility/addForm");
4 |
5 |
6 | router.post("/:authKey",async(req,res)=>{
7 | let authKey = req.params.authKey;
8 | if(authKey === process.env.authKey){
9 | let email = req.body.email;
10 | let formName = req.body.formName;
11 | let url = req.body.url || "";
12 | addFrom(email,formName ,url);
13 | }else{
14 | res.send("AuthKey does not match");
15 | }
16 |
17 | });
18 |
19 | module.exports = router;
--------------------------------------------------------------------------------
/backend/router/addUrl.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const User = require("../Modles/user");
4 | const updateUrl = require("../utility/updateUrl");
5 |
6 |
7 |
8 | router.post("/:mail&:authKey",async(req,res)=>{
9 |
10 | let authKey = req.params.authKey;
11 | if(authKey === process.env.authKey){
12 |
13 |
14 | let url = req.body.url;
15 | let formName = req.body.formName;
16 |
17 |
18 | let email = req.params.mail;
19 | updateUrl(email,url, formName);
20 |
21 | res.send("yo");
22 |
23 |
24 | }else{
25 | res.status(401).send("Auth Key does not match");
26 | }
27 |
28 |
29 |
30 | });
31 |
32 | module.exports = router;
--------------------------------------------------------------------------------
/backend/router/index.html:
--------------------------------------------------------------------------------
1 | !
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/backend/router/user.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const Search = require("../utility/searchUser");
4 | const createUser = require("../utility/createUser");
5 |
6 | router.get("/:mail&:authKey",async(req,res)=>{
7 | let authKey = req.params.authKey;
8 | if(authKey === process.env.authKey){
9 | let email = req.params.mail;
10 |
11 | let result ;
12 | result = await Search(email);
13 |
14 | if(typeof result !== 'undefined' && result.length === 0){
15 | let user = await createUser(email);
16 | res.json(user);
17 |
18 | }else{
19 |
20 | res.json(result);
21 | }
22 | }else{
23 | res.status(401).send("Auth Key does not match");
24 | }
25 |
26 |
27 |
28 | });
29 |
30 | module.exports = router;
--------------------------------------------------------------------------------
/backend/router/views/submited.html:
--------------------------------------------------------------------------------
1 | .
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | MeowFroms
11 |
12 |
13 |
14 |
15 |
52 |
53 |
54 |
55 |
56 |
Meow!
57 |
58 |
59 |
60 | Your Form has been submited
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
73 |
74 |
--------------------------------------------------------------------------------
/backend/utility/addForm.js:
--------------------------------------------------------------------------------
1 | const User = require("../Modles/user");
2 |
3 |
4 |
5 |
6 | let addForm = async(email,formName,url) => {
7 |
8 | let index = 0;
9 | let result = await User.find({email});
10 | let temp = result[0]._id;
11 | result = await User.findById(temp);
12 | let newForm = {};
13 | newForm["formData"] = [];
14 | console.log(url);
15 | newForm["redirectUrl"] = url;
16 | newForm["formName"] = formName;
17 | result.forms.push(newForm);
18 | let finalForm = result.save();
19 | console.log(result);
20 | }
21 |
22 |
23 |
24 | module.exports = addForm;
--------------------------------------------------------------------------------
/backend/utility/createUser.js:
--------------------------------------------------------------------------------
1 | const User = require("../Modles/user");
2 |
3 | const log = async(email) => {
4 |
5 | const newUser = new User({
6 | email,
7 | })
8 | try{
9 | const a1 = await newUser.save();
10 | return a1;
11 | }catch(error){
12 | console.log(error);
13 | }
14 | }
15 | module.exports = log;
--------------------------------------------------------------------------------
/backend/utility/searchUser.js:
--------------------------------------------------------------------------------
1 | const User = require("../Modles/user");
2 |
3 | let result ;
4 | const search = async(email) => {
5 |
6 | let temp = await User.find({email});
7 | return temp;
8 |
9 | }
10 | module.exports = search;
--------------------------------------------------------------------------------
/backend/utility/sendMail.js:
--------------------------------------------------------------------------------
1 | const nodemailer = require("nodemailer");
2 |
3 | async function main() {
4 | // Generate test SMTP service account from ethereal.email
5 | // Only needed if you don't have a real mail account for testing
6 |
7 |
8 | let testAccount = await nodemailer.createTestAccount();
9 |
10 | // create reusable transporter object using the default SMTP transport
11 | let transporter = nodemailer.createTransport({
12 | host: "smtp.ethereal.email",
13 | port: 587,
14 | secure: false, // true for 465, false for other ports
15 | auth: {
16 | user: testAccount.user, // generated ethereal user
17 | pass: testAccount.pass, // generated ethereal password
18 | },
19 | });
20 |
21 | // send mail with defined transport object
22 | let info = await transporter.sendMail({
23 | from: '"Fred Foo 👻" ', // sender address
24 | to: "bar@example.com, baz@example.com", // list of receivers
25 | subject: "Hello ✔", // Subject line
26 | text: "Hello world?", // plain text body
27 | html: "Hello world? ", // html body
28 | });
29 |
30 | console.log("Message sent: %s", info.messageId);
31 | // Message sent:
32 |
33 | // Preview only available when sending through an Ethereal account
34 | console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
35 | // Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
36 | }
37 |
38 | main().catch(console.error);
39 |
40 |
41 | module.exports = main;
--------------------------------------------------------------------------------
/backend/utility/updateUrl.js:
--------------------------------------------------------------------------------
1 | const User = require("../Modles/user");
2 |
3 |
4 | const updateUrl = async(email,url,formName) => {
5 | let index = 0;
6 | let result = await User.find({email});
7 | let temp = result[0]._id;
8 | result = await User.findById(temp);
9 |
10 |
11 | for(let i=0;i{
4 | formData = JSON.parse(formData);
5 | let date = new Date();
6 | formData["_date"] = date;
7 |
8 | let newUserData = await User.findById(id);
9 | if(newUserData["forms"].length === 0){
10 | const newForm = {};
11 | newForm["formName"] = formName ;
12 | newForm["formData"] = [];
13 | newForm["formData"].push(formData);
14 | newForm["redirectUrl"] = "";
15 | newUserData["forms"].push(newForm);
16 | let final = await newUserData.save();
17 |
18 | }else{
19 | let index = -1;
20 | for(let i=0;i0.2%",
44 | "not dead",
45 | "not op_mini all"
46 | ],
47 | "development": [
48 | "last 1 chrome version",
49 | "last 1 firefox version",
50 | "last 1 safari version"
51 | ]
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/public/MeowForm Icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tewarig/MeowForm/a2064567b486219ef85141be752d786173ad83ac/public/favicon.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 |
28 | MeowForms
29 |
30 |
31 | Best way to create your forms
32 |
33 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Meow Form",
3 | "name": "Meow Form",
4 | "icons": [
5 | {
6 | "src": "favicon.png",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/review_avtar.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tewarig/MeowForm/a2064567b486219ef85141be752d786173ad83ac/public/review_avtar.jpeg
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | /* .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | } */
30 |
31 | .react-reveal {
32 | animation-fill-mode: backwards !important;
33 | }
34 |
35 | /* @keyframes App-logo-spin {
36 | from {
37 | transform: rotate(0deg);
38 | }
39 | to {
40 | transform: rotate(360deg);
41 | }
42 | } */
43 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ChakraProvider } from "@chakra-ui/react";
3 | import Index from "./pages/Index";
4 | import "./App.css";
5 |
6 | function App() {
7 | return (
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/Util/AuthWithHistory.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useHistory } from "react-router-dom";
3 | import { Auth0Provider } from "@auth0/auth0-react";
4 |
5 | const Auth0ProviderWithHistory = ({ children }) => {
6 |
7 | const history = useHistory();
8 |
9 | const onRedirectCallback = (appState) => {
10 | history.push(appState?.returnTo || window.location.pathname);
11 | };
12 |
13 | return (
14 |
23 | {children}
24 |
25 | );
26 | };
27 |
28 | export default Auth0ProviderWithHistory;
--------------------------------------------------------------------------------
/src/comp/Comp/Faq.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import { FAQ_Data } from '../../data/faq'
3 | import '../../styles/faq.css'
4 |
5 | import {
6 | Text,
7 | Box,
8 | useColorModeValue,
9 | useMediaQuery,
10 | Image,
11 | Flex,
12 | Button,
13 | } from "@chakra-ui/react";
14 |
15 | function Faq() {
16 |
17 | const textColor = useColorModeValue("gray.700", "gray.100");
18 | const [check] = useMediaQuery("(min-width: 1025px)");
19 |
20 | return (
21 |
22 |
23 |
24 |
30 | Frequently Asked Questions (FAQ)
31 |
32 |
33 |
34 | {
35 | FAQ_Data.map((data) => (
36 |
37 |
38 |
Q . {data.question}
39 |
40 |
41 |
A . {data.answer}
42 |
43 |
44 | ))
45 | }
46 |
47 |
48 |
49 | );
50 | }
51 |
52 | export default Faq
53 |
--------------------------------------------------------------------------------
/src/comp/Comp/Footer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Box, Text, Flex, useMediaQuery } from "@chakra-ui/react";
3 |
4 | function Footer(props) {
5 | const [check] = useMediaQuery("(min-width: 1025px)");
6 | return (
7 |
8 |
9 |
10 |
16 | Meow Forms 🐱
17 |
18 |
23 |
24 |
28 | Help me keep Meow Form Free ☕
29 |
30 |
31 |
32 |
37 |
41 | Icons by Icons8
42 |
43 |
44 |
48 | 🐦 @oyeTewari
49 |
50 |
51 |
52 | All mails are delivered by 🧀 the 🐈
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | );
64 | }
65 |
66 | export default Footer;
67 |
--------------------------------------------------------------------------------
/src/comp/Comp/FormCard.js:
--------------------------------------------------------------------------------
1 | import { Box , Text } from '@chakra-ui/layout';
2 | import { Image , Button ,useColorModeValue ,Badge ,useMediaQuery ,Flex ,Input} from "@chakra-ui/react";
3 | import FormData from './FormData';
4 | import FormHeading from './FormHeading';
5 | import { AspectRatio } from "@chakra-ui/react"
6 |
7 | import {
8 | Drawer,
9 | DrawerBody,
10 | DrawerFooter,
11 | DrawerHeader,
12 | DrawerOverlay,
13 | DrawerContent,
14 | DrawerCloseButton,
15 | useDisclosure
16 | } from "@chakra-ui/react";
17 | import {Link} from "react-router-dom";
18 | import React from 'react';
19 | import axios from 'axios';
20 | import toast ,{Toaster} from "react-hot-toast";
21 |
22 |
23 | function FormCard({formName , responses ,formData ,redirectUrl ,email }) {
24 | const formBackground = useColorModeValue("gray.100","gray.700");
25 | const [check] = useMediaQuery("(min-width: 1025px)")
26 | const { isOpen, onOpen, onClose } = useDisclosure()
27 | const [size, setSize] = React.useState("md")
28 | const [url, setUrl] = React.useState();
29 | const [edit , setEdit] = React.useState(false);
30 | let apiKey = process.env.REACT_APP_APIKEY ;
31 | let apiUrl = process.env.REACT_APP_HOSTURL ;
32 |
33 | function isValidURL(string) {
34 | var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
35 | return (res !== null)
36 | };
37 | const sendResponse = async(serverUrl)=> {
38 | let meow = await axios({
39 | method: 'post',
40 | url: serverUrl,
41 | data: {
42 | url: url,
43 | formName: formName
44 | }
45 | });
46 |
47 | }
48 | const checkUrl = () => {
49 | if(url === "" || url === undefined){
50 | toast.error(' Url not saved');
51 | setEdit(!edit)
52 |
53 |
54 | }else if(isValidURL(url)){
55 | let serverUrl = apiUrl + 'url/' + email + '&' + apiKey;
56 | sendResponse(serverUrl);
57 |
58 | toast.success('Url is saved, it will some time to reflect');
59 |
60 | setEdit(!edit)
61 | }else{
62 | toast.error('The url is not valid :( ');
63 |
64 |
65 | }
66 |
67 | }
68 |
69 |
70 | return (
71 |
72 |
73 |
74 |
75 | {formName}
76 | {responses} Responses
77 | View
78 |
79 |
80 | {/* {console.log(formData)} */}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
94 |
95 | {formName}
96 |
97 |
100 | {responses} Responses
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | {formData.length > 0 &&
110 | <>
111 |
112 |
113 | {
114 | formData.map(x=>
115 |
116 | )
117 | }
118 |
119 | >
120 | }
121 | {/*
122 | Redirect Url
123 | { redirectUrl }
124 | */}
125 | {/* { edit && */}
126 | {/*
127 | (setUrl(e.target.value))}
128 | />
129 | {edit === false ?
130 | {setEdit(!edit)}}>
131 | edit
132 |
133 | :
134 | (checkUrl())}> Save
135 | }
136 | */}
137 | {/* } */}
138 | {/* * you one need Redirect url if you are just using html css , check docs here */}
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | );
152 | }
153 |
154 | export default FormCard;
--------------------------------------------------------------------------------
/src/comp/Comp/FormData.js:
--------------------------------------------------------------------------------
1 | import { Spacer, Text } from '@chakra-ui/layout';
2 | import {Flex , Divider} from '@chakra-ui/react';
3 | import React from 'react';
4 |
5 | function FormData({obj}) {
6 | let arr = [];
7 |
8 | Object.values(obj).forEach(values => (
9 | arr.push(values)
10 | )
11 | )
12 |
13 |
14 | return (
15 |
16 |
17 |
18 | {
19 | arr.map(x=>
20 | <>
21 |
22 | {x}
23 |
24 |
25 | >)
26 | }
27 |
28 |
29 |
30 | );
31 | }
32 |
33 | export default FormData;
--------------------------------------------------------------------------------
/src/comp/Comp/FormHeading.js:
--------------------------------------------------------------------------------
1 | import { Spacer, Text } from '@chakra-ui/layout';
2 | import {Flex , Divider} from '@chakra-ui/react';
3 | import React from 'react';
4 |
5 | function FormHeading({obj}) {
6 | let arr = [];
7 | let temp = obj;
8 | const objectArray = Object.entries(temp);
9 | objectArray.forEach(([key, value]) => arr.push(key));
10 |
11 |
12 |
13 |
14 |
15 | return (
16 |
17 |
18 | {
19 | arr.map(key =>
20 | <>
21 |
25 | {key}
26 |
27 |
28 |
29 | > )
30 | }
31 |
32 | {/* {
33 | objectArray.map(x=>
34 | <>
35 |
36 | {x}
37 |
38 |
39 | >)
40 | } */}
41 |
42 |
43 |
44 | );
45 | }
46 |
47 | export default FormHeading;
--------------------------------------------------------------------------------
/src/comp/Comp/MenuButtons.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Link} from 'react-router-dom';
3 | import {Button ,Text} from '@chakra-ui/react';
4 |
5 | function MenuButtons({link,icon,Tittle,click ,nextPage}) {
6 | return (
7 |
22 | );
23 | }
24 |
25 | export default MenuButtons;
--------------------------------------------------------------------------------
/src/comp/Comp/MenuItems.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import MenuButtons from './MenuButtons';
3 | import {Button, IconButton} from "@chakra-ui/button";
4 | import { VStack,Flex ,Heading, Spacer , Box , Text , Divider} from "@chakra-ui/layout";
5 | import {useMediaQuery} from "@chakra-ui/react";
6 | import {Tooltip } from "@chakra-ui/react";
7 | import { FaSun , FaMoon, FaGithub, FaUser} from "react-icons/fa";
8 | import { FcList, FcSearch } from "react-icons/fc";
9 | import {BsSearch ,BsCalendarFill, BsPeopleFill, BsPerson, BsFillExclamationCircleFill, BsStar ,BsMenu} from "react-icons/bs";
10 | import { useColorMode ,useColorModeValue } from '@chakra-ui/color-mode';
11 | import {Link} from "react-router-dom";
12 | import {MdRemoveFromQueue , MdFindInPage , MdStar, MdPeople} from "react-icons/md";
13 |
14 | import {
15 | Drawer,
16 | DrawerBody,
17 | DrawerFooter,
18 | DrawerHeader,
19 | DrawerOverlay,
20 | DrawerContent,
21 | DrawerCloseButton,
22 | useDisclosure
23 | } from "@chakra-ui/react";
24 |
25 | function MenuItems({onClose}) {
26 | return (
27 |
60 | );
61 | }
62 |
63 | export default MenuItems;
--------------------------------------------------------------------------------
/src/comp/Comp/NavBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button, IconButton} from "@chakra-ui/button";
3 | import {Avatar }from '@chakra-ui/react';
4 | import { VStack,Flex, Spacer , Box , Text , Divider} from "@chakra-ui/layout";
5 | import {useMediaQuery} from "@chakra-ui/react";
6 | import {Tooltip } from "@chakra-ui/react";
7 | import { FaSun , FaMoon, FaGithub, FaList} from "react-icons/fa";
8 | import { useColorMode ,useColorModeValue } from '@chakra-ui/color-mode';
9 | import {Link} from "react-router-dom";
10 | import { useAuth0 } from "@auth0/auth0-react";
11 |
12 |
13 | import {
14 | Drawer,
15 | DrawerBody,
16 | DrawerHeader,
17 | DrawerOverlay,
18 | DrawerContent,
19 | useDisclosure,
20 | Menu,
21 | MenuButton,
22 | MenuList,
23 | MenuItem
24 |
25 | } from "@chakra-ui/react";
26 | import MenuItems from './MenuItems';
27 |
28 |
29 | function Navbar(props) {
30 | const {colorMode , toggleColorMode }= useColorMode();
31 | const isDark = colorMode === 'dark';
32 | const { isOpen, onOpen, onClose } = useDisclosure()
33 | const [size, setSize] = React.useState("md")
34 | const [check] = useMediaQuery("(min-width: 1025px)")
35 | const [meow ,setMeow] = React.useState(false);
36 | const [signIn,setSignIn] = React.useState(false);
37 | const formBackground = useColorModeValue("white.100","gray.900");
38 | const { loginWithRedirect , logout , isAuthenticated , user} = useAuth0();
39 |
40 |
41 | let flag = false;
42 | var setFlag = () =>{
43 | setMeow(!meow);
44 | onClose();
45 | }
46 |
47 | return (
48 | <>
49 |
50 |
51 |
52 |
53 |
54 |
55 |
60 | MeowForm
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | } isRound="true">
70 |
71 | {check &&
72 |
73 | } isRound="true">
74 |
75 | }
76 | { check &&
77 |
78 | : } isRound="true" onClick={toggleColorMode}>
79 |
80 |
81 | }
82 |
83 |
84 |
85 |
86 |
87 | { user &&
88 |
89 | {({ isOpen }) => (
90 | <>
91 |
92 |
93 |
94 |
95 | Hi , {user.name}
96 |
97 | Dashboard
98 |
99 |
100 | logout()}>Logout
101 |
102 | >
103 | )}
104 |
105 | }
106 | { !isAuthenticated &&
107 |
108 |
109 | {({ isOpen }) => (
110 | <>
111 |
112 |
113 |
114 |
115 |
116 | (loginWithRedirect()) }>Sign In/Sign Up
117 |
118 | >
119 | )}
120 |
121 | {/* } isRound="true" onClick={()=>(loginWithRedirect())}>
122 | */}
123 |
124 | }
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
140 | MeowForm
141 |
142 |
143 |
144 |
145 |
146 | {!check &&
147 |
148 | {isDark ? : }
149 |
150 |
151 | {isDark ? "Light Mode" : "Dark Mode"}
152 |
153 |
154 | }
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 | >
180 | );
181 | }
182 |
183 | export default Navbar;
184 |
--------------------------------------------------------------------------------
/src/comp/Comp/Review.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import "react-responsive-carousel/lib/styles/carousel.min.css";
3 | import { Carousel } from "react-responsive-carousel";
4 |
5 | export default class Reviews extends Component {
6 | render() {
7 | return (
8 |
16 |
17 |
21 |
22 |
Anmol Malik
23 |
24 | Amazing Project Gaurav Tewari, I had used this in my portfolio,
25 | its very easy to use, literally I don't have to write any
26 | back-end. And specially that mail feature, I really liked it. Keep
27 | it up Bro 🙌🏻
28 |
29 |
30 |
31 |
32 |
36 |
37 |
Savio Martin
38 |
39 | Great App Gaurav Tewari, Very helpful. This will help me a lot
40 | when form submitting. Kudos 👏 I really like the idea and the
41 | implementation is also so good. Keep up the good work bro! 🚀
42 |
43 |
44 |
45 |
46 |
50 |
51 |
Devansh Dubey
52 |
53 | Amazing idea bro, this will help a ton of developers in their projects. Kudos, great work 🔥
54 |
55 |
56 |
57 |
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/comp/Skeletons/FullPage.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Box ,SkeletonText , SkeletonCircle ,Flex} from "@chakra-ui/react";
4 | function FullPage(props) {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | < Box padding="6" boxShadow="lg" >
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | );
29 | }
30 |
31 | export default FullPage;
--------------------------------------------------------------------------------
/src/data/faq.js:
--------------------------------------------------------------------------------
1 | export const FAQ_Data = [{
2 | 'id': 1,
3 | 'question': 'How you are able to keep Meow Form Completely free?',
4 | 'answer': `Currently MeowForm's is costing me around $5 a month I am able to cover this cost.`
5 | },
6 | {
7 | 'id': 2,
8 | 'question': 'What if i do if a not receive email responses ?',
9 | 'answer': ' Currenlty due to bugeting Meowform has a cap of 30,000 emails a month . so if this limit is cross you would not receive any of the email. but still you can check you dashboard for new responses'
10 | },
11 | {
12 | 'id': 3,
13 | 'question': 'How can i support Meowforms ? ',
14 | 'answer': 'You can support it by contributing to meowform in github or by telling the whole world about Meowforms or by buying me a coffe or Ice Tea'
15 | },
16 | {
17 | 'id': 4,
18 | 'question': 'What if you stop Mainting MeowForms or Paying for the Services ',
19 | 'answer': `Surely MeowForms will go offline but the Code is open sourced so you can deploy a the code youself if you are heavly deponded on Meowform`
20 | },
21 | ]
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
15 | /* reviews */
16 | .carousel-root {
17 | width: 64% !important;
18 | margin: auto !important;
19 | margin-top: 3% !important;
20 | }
21 |
22 | .carousel .slide {
23 | background: #fff !important;
24 | color: black;
25 | height: 100%;
26 | }
27 |
28 | .carousel .slide img {
29 | width: 100px !important;
30 | border-radius: 50%;
31 | }
32 |
33 | .myCarousel {
34 | background: #fafafa;
35 | margin-top: -6%;
36 | width: 75%;
37 | margin-left: auto;
38 | margin-right: auto;
39 | padding-top: 6%;
40 | padding-bottom: 20%;
41 | padding-left: 5%;
42 | padding-right: 5%;
43 | border: 1px solid #ddd;
44 | height: 286px;
45 | }
46 |
47 | .carousel .control-dots {
48 | padding-left: 5px !important;
49 | outline: 0;
50 | bottom: 5% !important;
51 | }
52 |
53 | .myCarousel h3 {
54 | color: #222;
55 | font-weight: 100;
56 | letter-spacing: 0.2px;
57 | margin-bottom: 10px;
58 | font-weight: 600;
59 | /* text-transform: uppercase; */
60 | font-size: 22px;
61 | }
62 |
63 | .myCarousel p {
64 | font-weight: 140 !important;
65 | line-height: 29px !important;
66 | color: #222;
67 | font-size: 17px;
68 | font-family: sans-serif;
69 | max-height: 67px;
70 | }
71 |
72 | .myCarousel p:before {
73 | content: "“";
74 | color: rgb(192, 129, 46);;
75 | font-size: 26px;
76 | font-family: monospace;
77 | font-weight: 100;
78 | }
79 |
80 | .myCarousel p:after {
81 | content: "”";
82 | color: rgb(192, 129, 46);
83 | font-size: 26px;
84 | font-family: monospace;
85 | font-weight: 100;
86 | line-height: 0;
87 | }
88 |
89 | .carousel .control-dots .dot {
90 | box-shadow: none !important;
91 | background: orange !important;
92 | outline: 0;
93 | }
94 |
95 | .carousel.carousel-slider .control-arrow {
96 | background:orangered !important;
97 | height: 50px !important;
98 | position: absolute;
99 | top: 35% !important;
100 | }
101 |
102 | @media only screen and (max-width: 934px) {
103 | .carousel-root {
104 | outline: 0;
105 | width: 93% !important;
106 | margin: auto !important;
107 | }
108 |
109 | .carousel.carousel-slider .control-arrow {
110 | display: none !important;
111 | }
112 | .myCarousel {
113 | background: #fafafa;
114 | margin-top: -9%;
115 | width: 88%;
116 | margin-left: auto;
117 | margin-right: auto;
118 | padding-top: 8%;
119 | padding-bottom: 12.5%;
120 | padding-left: 5%;
121 | padding-right: 5%;
122 | border: 1px solid #ddd;
123 | height: 269px;
124 | }
125 |
126 | .carousel .slide img {
127 | width: 24% !important;
128 | border-radius: 50%;
129 | }
130 | }
131 |
132 | .Reviews{
133 | padding: 30px 10px 170px 10px ;
134 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/Dashboard/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import {
3 | Box,
4 | Text,
5 | Flex,
6 | Image,
7 | useMediaQuery,
8 | Divider,
9 | SkeletonText,
10 | Button,
11 | Input,
12 | } from "@chakra-ui/react";
13 | import { useAuth0, withAuthenticationRequired } from "@auth0/auth0-react";
14 | import FullPage from "../../comp/Skeletons/FullPage";
15 | import axios from "axios";
16 | import FormCard from "../../comp/Comp/FormCard";
17 | import {
18 | Drawer,
19 | DrawerBody,
20 | DrawerHeader,
21 | DrawerOverlay,
22 | DrawerContent,
23 | useDisclosure,
24 | } from "@chakra-ui/react";
25 | import toast, { Toaster } from "react-hot-toast";
26 |
27 | const Dashboard = () => {
28 | const { isLoading, user } = useAuth0();
29 | const [check] = useMediaQuery("(min-width: 1025px)");
30 | const { isOpen, onOpen, onClose } = useDisclosure();
31 | const [formName, setFormName] = React.useState();
32 | let userEmail = user.email;
33 | let apiKey = process.env.REACT_APP_APIKEY;
34 | let apiUrl = process.env.REACT_APP_HOSTURL;
35 | const [data, setData] = React.useState();
36 | const getData = async () => {
37 | let temp = await axios.get(apiUrl + "user/" + userEmail + "&" + apiKey);
38 | setData(temp.data[0]);
39 | console.log(data);
40 | };
41 | useEffect(() => {
42 | getData();
43 | if (data === undefined) {
44 | setTimeout(() => getData(), 2500);
45 | }
46 | }, []);
47 | let responses = 0;
48 | if (data) {
49 | for (let i = 0; i < data.forms.length; i++) {
50 | responses += data.forms[i].formData.length;
51 | }
52 | }
53 |
54 | const postApiData = async () => {
55 | let temp = await axios.post(apiUrl + "addForm/" + apiKey, {
56 | email: user.email,
57 | formName: formName,
58 | url: "",
59 | });
60 | getData();
61 | };
62 | const addNewForm = () => {
63 | if (formName === "") {
64 | toast.error("Form is empty😉");
65 | } else {
66 | // console.log(data.forms[0].formName);
67 | let isCopy = false;
68 | for (let i = 0; i < data.forms.length; i++) {
69 | if (data.forms[i].formName === formName) {
70 | isCopy = true;
71 | }
72 | }
73 | if (isCopy) {
74 | toast.error("form with such name already exits ");
75 | } else {
76 | postApiData();
77 | setTimeout(() => getData(), 2000);
78 | onClose();
79 | setTimeout(
80 | () => toast.success("Form Have beeen added 😉"),
81 | 2000
82 | );
83 | }
84 | }
85 | };
86 |
87 | return (
88 |
89 |
95 |
96 |
97 |
98 |
104 | {user.name}
105 |
106 |
107 |
108 |
109 |
110 |
114 | {data ? (
115 | responses
116 | ) : (
117 |
118 | )}
119 |
120 | Responses
121 |
122 |
123 |
127 | {data ? (
128 | data.forms.length
129 | ) : (
130 |
131 | )}
132 |
133 |
134 | Forms
135 |
136 |
137 |
138 |
139 |
140 |
145 |
146 |
151 | Forms
152 |
153 |
154 | New form
155 |
156 |
157 |
158 | {data ? (
159 | data.forms.map((x) => (
160 |
166 | ))
167 | ) : (
168 | <>
169 |
170 |
171 | >
172 | )}
173 |
174 | {data && data.forms.length === 0 ? (
175 | <>
176 |
182 |
183 | You haven't created a form Yet{" "}
184 |
185 | >
186 | ) : (
187 | <> >
188 | )}
189 |
190 |
194 |
195 |
196 |
197 |
203 | Add Form
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
213 | setFormName(e.target.value)
214 | }
215 | placeholder='Form Name'
216 | />
217 |
221 | {" "}
222 | >{" "}
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 | );
234 | };
235 | export default withAuthenticationRequired(Dashboard, {
236 | onRedirecting: () => ,
237 | });
238 |
--------------------------------------------------------------------------------
/src/pages/Home/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import Bounce from "react-reveal/Bounce";
4 | import Flip from "react-reveal/Flip";
5 | import Fade from "react-reveal/Fade";
6 | import Reviews from "../../comp/Comp/Review";
7 | import Faq from "../../comp/Comp/Faq";
8 |
9 | import {
10 | Text,
11 | Box,
12 | useColorModeValue,
13 | useMediaQuery,
14 | Image,
15 | Flex,
16 | Button,
17 | } from "@chakra-ui/react";
18 | import Typewriter from "typewriter-effect";
19 |
20 | function Home(props) {
21 | const textColor = useColorModeValue("gray.700", "gray.100");
22 | const [check] = useMediaQuery("(min-width: 1025px)");
23 |
24 | return (
25 | <>
26 |
27 |
28 |
29 |
35 | Functional Forms Solution for
36 |
37 |
44 |
58 |
59 |
60 |
61 |
67 |
68 |
77 |
78 |
79 |
80 |
81 |
85 | View docs
86 |
87 |
88 |
89 |
90 |
91 | {" "}
92 | Try it
93 |
94 |
95 |
96 |
97 |
98 |
108 |
109 |
110 |
111 |
.
112 |
113 |
114 |
115 | .
116 |
117 |
118 |
119 |
120 |
126 |
127 |
134 | Make backend-less forms with MeowForm and get
135 |
138 | Unlimited Responses{" "}
139 | {" "}
140 | in your inbox .
141 |
142 |
143 |
144 |
145 |
146 |
153 | Choose your fontend , Use our API to handle things
154 | for
155 |
158 | {" "}
159 | Free{" "}
160 |
161 |
162 |
163 |
169 |
170 |
171 |
172 |
179 | Missed a response ? don't worry view all responses
180 | in out dashboard
181 |
184 | {" "}
185 |
186 |
187 |
188 |
194 |
195 |
196 |
197 |
202 |
203 |
213 |
214 | Meow Form in action
215 |
216 |
217 | {/* */}
218 |
219 |
220 |
221 |
222 | >
223 | );
224 | }
225 |
226 | export default Home;
227 |
--------------------------------------------------------------------------------
/src/pages/Index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Fade from "react-reveal/Fade";
3 | import { BrowserRouter as Router, Route } from "react-router-dom";
4 |
5 | import Navbar from "../comp/Comp/NavBar";
6 | import Home from "./Home/Home";
7 | import Dashboard from "./Dashboard/Dashboard";
8 | import Auth0ProviderWithHistory from "../Util/AuthWithHistory";
9 | import Footer from "../comp/Comp/Footer";
10 |
11 | function Index(props) {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 |
32 | export default Index;
33 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/styles/faq.css:
--------------------------------------------------------------------------------
1 | .faq-div {
2 | width: 100%;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | margin-bottom: 40px;
7 | }
8 |
9 | .faq-main {
10 | max-width: 900px;
11 | width: 100%;
12 | margin: 0px;
13 | padding: 0px;
14 | display: flex;
15 | align-items: center;
16 | justify-content: center;
17 | flex-direction: column;
18 | }
19 |
20 | .faq-data {
21 | max-width: 800px;
22 | width: 100%;
23 | margin: 80px 0px;
24 | display: flex;
25 | flex-direction: column;
26 | border-radius: 6px;
27 | border: 2px solid #bebebe;
28 | padding: 0px 20px;
29 | }
30 |
31 | .singleFaq {
32 | width: 100%;
33 | padding: 32px 20px;
34 | font-size: 18px;
35 | border-bottom: 2px solid #807878;
36 | }
37 |
38 | .singleFaq:nth-last-child(1) {
39 | border: none;
40 | }
41 |
42 | .faq-question {
43 | font-weight: 500;
44 | margin-bottom: 4px;
45 | }
46 |
47 | .faq-question span,
48 | .faq-answer span {
49 | font-weight: 500;
50 | margin-right: 4px;
51 | }
--------------------------------------------------------------------------------