Compare commits

..

23 Commits
server ... main

Author SHA1 Message Date
Priyatham Sai Chand e736aa99fb adding modal 2021-04-19 23:35:04 +05:30
Priyatham Sai Chand 508cbf5d63 house card hover fix 2021-04-18 22:25:21 +05:30
Priyatham Sai Chand 521219bbbb house card overlay add 2021-04-18 16:40:01 +05:30
Priyatham Sai Chand bd8c1d25a8 card placement 2021-04-17 22:25:54 +05:30
Priyatham Sai Chand 1f8b82a3ea house card start 2021-04-16 23:52:54 +05:30
Priyatham-sai-chand 5cc119b916 http to https fix 2021-04-15 21:55:00 +05:30
Priyatham-sai-chand ed392ef98d google meta tag 2021-04-15 21:47:31 +05:30
Priyatham Sai Chand 3d688dfbc8 log in responsive fix 2021-04-13 18:30:37 +05:30
Priyatham Sai Chand 01a1e2ceea google auth fix 2021-04-13 18:12:40 +05:30
Priyatham Sai Chand 6099c144b3 Merge branch 'client' into main 2021-04-12 10:23:48 +05:30
Priyatham Sai Chand bc5052ba85 modules reinstalled 2021-04-11 21:37:37 +05:30
Priyatham Sai Chand f8f8ef9327 add after log in 2021-04-05 16:11:07 +05:30
Priyatham-sai-chand 80db290d4d error notice modify 2021-03-31 23:54:24 +05:30
Priyatham Sai Chand 63a68d51e7 Added Jest mock package 2021-03-30 23:49:23 +05:30
Priyatham Sai Chand 950d4a9072 modify sidebar 2021-03-29 18:17:28 +05:30
Priyatham Sai Chand 8408889432 Merge branch 'client' of github.com:Priyatham-sai-chand/locaft into client 2021-03-29 15:51:53 +05:30
Priyatham Sai Chand 54295a18f6 web bootstrap reset 2021-03-29 15:51:01 +05:30
Priyatham Sai Chand 3c360a9276 remove web bootstrap 2021-03-29 15:23:01 +05:30
Priyatham Sai Chand 7e7fb6d46a finish log in styled 2021-03-28 23:54:40 +05:30
Priyatham Sai Chand 235711d3d6 finish pricing styled 2021-03-28 23:54:21 +05:30
Priyatham Sai Chand 88f2d51a33 Button styled export 2021-03-28 18:38:40 +05:30
Priyatham Sai Chand 66e24f5d3c log in styled change 2021-03-27 23:52:22 +05:30
Priyatham Sai Chand a818be5766 start styled log in migration 2021-03-26 23:54:56 +05:30
63 changed files with 20249 additions and 970 deletions

5
.gitignore vendored
View File

@ -1,3 +1,4 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
client/node_modules
@ -6,7 +7,6 @@ client/.env
/client.pnp.js
server/node_modules
node_modules
# testing
/coverage
@ -14,12 +14,13 @@ node_modules
/build
# misc
.env
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
.env
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -1 +0,0 @@
web: node server.js

View File

@ -1,24 +0,0 @@
const jwt = require("jsonwebtoken");
const auth = (req, res, next) => {
try {
const token = req.header("x-auth-token");
if (!token)
return res
.status(401)
.json({ msg: "No authentication token, authorization denied." });
const verified = jwt.verify(token, process.env.jwtSecret);
if (!verified)
return res
.status(401)
.json({ msg: "Token verification failed, authorization denied." });
req.user = verified.id;
next();
} catch (err) {
res.status(500).json({ error: err.message });
}
};
module.exports = auth;

18371
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,52 @@
{
"name": "auth",
"version": "1.0.0",
"description": "sign up and sign in auth",
"main": "server.js",
"scripts": {
"start": "node server.js",
"app": "nodemon server.js"
},
"author": "B. Priyatham Sai chand",
"license": "ISC",
"name": "locaft",
"version": "0.1.0",
"private": true,
"dependencies": {
"bcryptjs": "^2.4.3",
"config": "^3.3.2",
"context": "^1.1.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-validator": "^6.6.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.10.13",
"nodemon": "^2.0.7"
"@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-brands-svg-icons": "^5.15.1",
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"@fortawesome/react-fontawesome": "^0.1.13",
"@testing-library/jest-dom": "^5.11.5",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"axios": "^0.21.1",
"bootstrap": "^4.6.0",
"install": "^0.13.0",
"react": "^17.0.1",
"react-bootstrap": "^1.5.2",
"react-dom": "^17.0.1",
"react-google-login": "^5.2.2",
"react-lottie": "^1.2.3",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3",
"styled-components": "^5.2.1",
"styled-icons": "^10.22.0",
"web-vitals": "^0.2.4"
},
"engines": {
"node": "14.x",
"npm": "6.14.8"
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev": "npm run start && nodemon index.js"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

1
public/_redirects Normal file
View File

@ -0,0 +1 @@
/* /index.html 200

46
public/apple_badge.svg Normal file
View File

@ -0,0 +1,46 @@
<svg id="livetype" xmlns="http://www.w3.org/2000/svg" width="119.66407" height="40" viewBox="0 0 119.66407 40">
<title>Download_on_the_App_Store_Badge_US-UK_RGB_blk_4SVG_092917</title>
<g>
<g>
<g>
<path d="M110.13477,0H9.53468c-.3667,0-.729,0-1.09473.002-.30615.002-.60986.00781-.91895.0127A13.21476,13.21476,0,0,0,5.5171.19141a6.66509,6.66509,0,0,0-1.90088.627A6.43779,6.43779,0,0,0,1.99757,1.99707,6.25844,6.25844,0,0,0,.81935,3.61816a6.60119,6.60119,0,0,0-.625,1.90332,12.993,12.993,0,0,0-.1792,2.002C.00587,7.83008.00489,8.1377,0,8.44434V31.5586c.00489.3105.00587.6113.01515.9219a12.99232,12.99232,0,0,0,.1792,2.0019,6.58756,6.58756,0,0,0,.625,1.9043A6.20778,6.20778,0,0,0,1.99757,38.001a6.27445,6.27445,0,0,0,1.61865,1.1787,6.70082,6.70082,0,0,0,1.90088.6308,13.45514,13.45514,0,0,0,2.0039.1768c.30909.0068.6128.0107.91895.0107C8.80567,40,9.168,40,9.53468,40H110.13477c.3594,0,.7246,0,1.084-.002.3047,0,.6172-.0039.9219-.0107a13.279,13.279,0,0,0,2-.1768,6.80432,6.80432,0,0,0,1.9082-.6308,6.27742,6.27742,0,0,0,1.6172-1.1787,6.39482,6.39482,0,0,0,1.1816-1.6143,6.60413,6.60413,0,0,0,.6191-1.9043,13.50643,13.50643,0,0,0,.1856-2.0019c.0039-.3106.0039-.6114.0039-.9219.0078-.3633.0078-.7246.0078-1.0938V9.53613c0-.36621,0-.72949-.0078-1.09179,0-.30664,0-.61426-.0039-.9209a13.5071,13.5071,0,0,0-.1856-2.002,6.6177,6.6177,0,0,0-.6191-1.90332,6.46619,6.46619,0,0,0-2.7988-2.7998,6.76754,6.76754,0,0,0-1.9082-.627,13.04394,13.04394,0,0,0-2-.17676c-.3047-.00488-.6172-.01074-.9219-.01269-.3594-.002-.7246-.002-1.084-.002Z" style="fill: #a6a6a6"/>
<path d="M8.44483,39.125c-.30468,0-.602-.0039-.90429-.0107a12.68714,12.68714,0,0,1-1.86914-.1631,5.88381,5.88381,0,0,1-1.65674-.5479,5.40573,5.40573,0,0,1-1.397-1.0166,5.32082,5.32082,0,0,1-1.02051-1.3965,5.72186,5.72186,0,0,1-.543-1.6572,12.41351,12.41351,0,0,1-.1665-1.875c-.00634-.2109-.01464-.9131-.01464-.9131V8.44434S.88185,7.75293.8877,7.5498a12.37039,12.37039,0,0,1,.16553-1.87207,5.7555,5.7555,0,0,1,.54346-1.6621A5.37349,5.37349,0,0,1,2.61183,2.61768,5.56543,5.56543,0,0,1,4.01417,1.59521a5.82309,5.82309,0,0,1,1.65332-.54394A12.58589,12.58589,0,0,1,7.543.88721L8.44532.875H111.21387l.9131.0127a12.38493,12.38493,0,0,1,1.8584.16259,5.93833,5.93833,0,0,1,1.6709.54785,5.59374,5.59374,0,0,1,2.415,2.41993,5.76267,5.76267,0,0,1,.5352,1.64892,12.995,12.995,0,0,1,.1738,1.88721c.0029.2832.0029.5874.0029.89014.0079.375.0079.73193.0079,1.09179V30.4648c0,.3633,0,.7178-.0079,1.0752,0,.3252,0,.6231-.0039.9297a12.73126,12.73126,0,0,1-.1709,1.8535,5.739,5.739,0,0,1-.54,1.67,5.48029,5.48029,0,0,1-1.0156,1.3857,5.4129,5.4129,0,0,1-1.3994,1.0225,5.86168,5.86168,0,0,1-1.668.5498,12.54218,12.54218,0,0,1-1.8692.1631c-.2929.0068-.5996.0107-.8974.0107l-1.084.002Z"/>
</g>
<g id="_Group_" data-name="&lt;Group&gt;">
<g id="_Group_2" data-name="&lt;Group&gt;">
<g id="_Group_3" data-name="&lt;Group&gt;">
<path id="_Path_" data-name="&lt;Path&gt;" d="M24.76888,20.30068a4.94881,4.94881,0,0,1,2.35656-4.15206,5.06566,5.06566,0,0,0-3.99116-2.15768c-1.67924-.17626-3.30719,1.00483-4.1629,1.00483-.87227,0-2.18977-.98733-3.6085-.95814a5.31529,5.31529,0,0,0-4.47292,2.72787c-1.934,3.34842-.49141,8.26947,1.3612,10.97608.9269,1.32535,2.01018,2.8058,3.42763,2.7533,1.38706-.05753,1.9051-.88448,3.5794-.88448,1.65876,0,2.14479.88448,3.591.8511,1.48838-.02416,2.42613-1.33124,3.32051-2.66914a10.962,10.962,0,0,0,1.51842-3.09251A4.78205,4.78205,0,0,1,24.76888,20.30068Z" style="fill: #fff"/>
<path id="_Path_2" data-name="&lt;Path&gt;" d="M22.03725,12.21089a4.87248,4.87248,0,0,0,1.11452-3.49062,4.95746,4.95746,0,0,0-3.20758,1.65961,4.63634,4.63634,0,0,0-1.14371,3.36139A4.09905,4.09905,0,0,0,22.03725,12.21089Z" style="fill: #fff"/>
</g>
</g>
<g>
<path d="M42.30227,27.13965h-4.7334l-1.13672,3.35645H34.42727l4.4834-12.418h2.083l4.4834,12.418H43.438ZM38.0591,25.59082h3.752l-1.84961-5.44727h-.05176Z" style="fill: #fff"/>
<path d="M55.15969,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H48.4302v1.50586h.03418a3.21162,3.21162,0,0,1,2.88281-1.60059C53.645,21.34766,55.15969,23.16406,55.15969,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C52.30227,29.01563,53.24953,27.81934,53.24953,25.96973Z" style="fill: #fff"/>
<path d="M65.12453,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H58.395v1.50586h.03418A3.21162,3.21162,0,0,1,61.312,21.34766C63.60988,21.34766,65.12453,23.16406,65.12453,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C62.26711,29.01563,63.21438,27.81934,63.21438,25.96973Z" style="fill: #fff"/>
<path d="M71.71047,27.03613c.1377,1.23145,1.334,2.04,2.96875,2.04,1.56641,0,2.69336-.80859,2.69336-1.91895,0-.96387-.67969-1.541-2.28906-1.93652l-1.60937-.3877c-2.28027-.55078-3.33887-1.61719-3.33887-3.34766,0-2.14258,1.86719-3.61426,4.51855-3.61426,2.624,0,4.42285,1.47168,4.4834,3.61426h-1.876c-.1123-1.23926-1.13672-1.9873-2.63379-1.9873s-2.52148.75684-2.52148,1.8584c0,.87793.6543,1.39453,2.25488,1.79l1.36816.33594c2.54785.60254,3.60645,1.626,3.60645,3.44238,0,2.32324-1.85059,3.77832-4.79395,3.77832-2.75391,0-4.61328-1.4209-4.7334-3.667Z" style="fill: #fff"/>
<path d="M83.34621,19.2998v2.14258h1.72168v1.47168H83.34621v4.99121c0,.77539.34473,1.13672,1.10156,1.13672a5.80752,5.80752,0,0,0,.61133-.043v1.46289a5.10351,5.10351,0,0,1-1.03223.08594c-1.833,0-2.54785-.68848-2.54785-2.44434V22.91406H80.16262V21.44238H81.479V19.2998Z" style="fill: #fff"/>
<path d="M86.065,25.96973c0-2.84863,1.67773-4.63867,4.29395-4.63867,2.625,0,4.29492,1.79,4.29492,4.63867,0,2.85645-1.66113,4.63867-4.29492,4.63867C87.72609,30.6084,86.065,28.82617,86.065,25.96973Zm6.69531,0c0-1.9541-.89551-3.10742-2.40137-3.10742s-2.40039,1.16211-2.40039,3.10742c0,1.96191.89453,3.10645,2.40039,3.10645S92.76027,27.93164,92.76027,25.96973Z" style="fill: #fff"/>
<path d="M96.18606,21.44238h1.77246v1.541h.043a2.1594,2.1594,0,0,1,2.17773-1.63574,2.86616,2.86616,0,0,1,.63672.06934v1.73828a2.59794,2.59794,0,0,0-.835-.1123,1.87264,1.87264,0,0,0-1.93652,2.083v5.37012h-1.8584Z" style="fill: #fff"/>
<path d="M109.3843,27.83691c-.25,1.64355-1.85059,2.77148-3.89844,2.77148-2.63379,0-4.26855-1.76465-4.26855-4.5957,0-2.83984,1.64355-4.68164,4.19043-4.68164,2.50488,0,4.08008,1.7207,4.08008,4.46582v.63672h-6.39453v.1123a2.358,2.358,0,0,0,2.43555,2.56445,2.04834,2.04834,0,0,0,2.09082-1.27344Zm-6.28223-2.70215h4.52637a2.1773,2.1773,0,0,0-2.2207-2.29785A2.292,2.292,0,0,0,103.10207,25.13477Z" style="fill: #fff"/>
</g>
</g>
</g>
<g id="_Group_4" data-name="&lt;Group&gt;">
<g>
<path d="M37.82619,8.731a2.63964,2.63964,0,0,1,2.80762,2.96484c0,1.90625-1.03027,3.002-2.80762,3.002H35.67092V8.731Zm-1.22852,5.123h1.125a1.87588,1.87588,0,0,0,1.96777-2.146,1.881,1.881,0,0,0-1.96777-2.13379h-1.125Z" style="fill: #fff"/>
<path d="M41.68068,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C44.57522,13.99463,45.01369,13.42432,45.01369,12.44434Z" style="fill: #fff"/>
<path d="M51.57326,14.69775h-.92187l-.93066-3.31641h-.07031l-.92676,3.31641h-.91309l-1.24121-4.50293h.90137l.80664,3.436h.06641l.92578-3.436h.85254l.92578,3.436h.07031l.80273-3.436h.88867Z" style="fill: #fff"/>
<path d="M53.85354,10.19482H54.709v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915h-.88867V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M59.09377,8.437h.88867v6.26074h-.88867Z" style="fill: #fff"/>
<path d="M61.21779,12.44434a2.13346,2.13346,0,1,1,4.24756,0,2.1338,2.1338,0,1,1-4.24756,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C64.11232,13.99463,64.5508,13.42432,64.5508,12.44434Z" style="fill: #fff"/>
<path d="M66.4009,13.42432c0-.81055.60352-1.27783,1.6748-1.34424l1.21973-.07031v-.38867c0-.47559-.31445-.74414-.92187-.74414-.49609,0-.83984.18213-.93848.50049h-.86035c.09082-.77344.81836-1.26953,1.83984-1.26953,1.12891,0,1.76563.562,1.76563,1.51318v3.07666h-.85547v-.63281h-.07031a1.515,1.515,0,0,1-1.35254.707A1.36026,1.36026,0,0,1,66.4009,13.42432Zm2.89453-.38477v-.37646l-1.09961.07031c-.62012.0415-.90137.25244-.90137.64941,0,.40527.35156.64111.835.64111A1.0615,1.0615,0,0,0,69.29543,13.03955Z" style="fill: #fff"/>
<path d="M71.34816,12.44434c0-1.42285.73145-2.32422,1.86914-2.32422a1.484,1.484,0,0,1,1.38086.79h.06641V8.437h.88867v6.26074h-.85156v-.71143h-.07031a1.56284,1.56284,0,0,1-1.41406.78564C72.0718,14.772,71.34816,13.87061,71.34816,12.44434Zm.918,0c0,.95508.4502,1.52979,1.20313,1.52979.749,0,1.21191-.583,1.21191-1.52588,0-.93848-.46777-1.52979-1.21191-1.52979C72.72121,10.91846,72.26613,11.49707,72.26613,12.44434Z" style="fill: #fff"/>
<path d="M79.23,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C82.12453,13.99463,82.563,13.42432,82.563,12.44434Z" style="fill: #fff"/>
<path d="M84.66945,10.19482h.85547v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915H87.605V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M93.51516,9.07373v1.1416h.97559v.74854h-.97559V13.2793c0,.47168.19434.67822.63672.67822a2.96657,2.96657,0,0,0,.33887-.02051v.74023a2.9155,2.9155,0,0,1-.4834.04541c-.98828,0-1.38184-.34766-1.38184-1.21582v-2.543h-.71484v-.74854h.71484V9.07373Z" style="fill: #fff"/>
<path d="M95.70461,8.437h.88086v2.48145h.07031a1.3856,1.3856,0,0,1,1.373-.80664,1.48339,1.48339,0,0,1,1.55078,1.67871v2.90723H98.69v-2.688c0-.71924-.335-1.0835-.96289-1.0835a1.05194,1.05194,0,0,0-1.13379,1.1416v2.62988h-.88867Z" style="fill: #fff"/>
<path d="M104.76125,13.48193a1.828,1.828,0,0,1-1.95117,1.30273A2.04531,2.04531,0,0,1,100.73,12.46045a2.07685,2.07685,0,0,1,2.07617-2.35254c1.25293,0,2.00879.856,2.00879,2.27V12.688h-3.17969v.0498a1.1902,1.1902,0,0,0,1.19922,1.29,1.07934,1.07934,0,0,0,1.07129-.5459Zm-3.126-1.45117h2.27441a1.08647,1.08647,0,0,0-1.1084-1.1665A1.15162,1.15162,0,0,0,101.63527,12.03076Z" style="fill: #fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/avasa.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/avasa_optmized.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

51
public/index.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link href="../src/index.css" rel="stylesheet"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.jpg" />
<script src="https://apis.google.com/js/platform.js" async defer></script>
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSS Styles-->
<title>Locaft</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
public/indigo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
public/indigo_optimized.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/locaft.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
public/locaft.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
public/locaft_optmized.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
public/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

15
public/manifest.json Normal file
View File

@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

BIN
public/nobroker.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
public/nobroker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

BIN
public/skyscraper.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
public/skyscraper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

BIN
public/skyscraper1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
public/vrl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
public/vrl_optmized.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,130 +0,0 @@
const router = require("express").Router();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const auth = require("../middleware/auth");
const User = require("../schemas/User");
const config = require("config");
router.post("/register", async (req, res) => {
try {
let { username,email,phonenumber,password} = req.body;
if (!email || !password )
return res.status(400).json({ msg: "Not all fields have been entered." });
if (password.length < 5)
return res
.status(400)
.json({ msg: "The password needs to be at least 5 characters long." });
const existingUser = await User.findOne({ email: email });
if (existingUser)
return res
.status(400)
.json({ msg: "An account with this email already exists." });
if (!username) username = email;
const salt = await bcrypt.genSalt();
const passwordHash = await bcrypt.hash(password, salt);
const newUser = new User({
username,
email,
phonenumber,
password: passwordHash,
});
const savedUser = await newUser.save();
res.json(savedUser);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
// validate
if (!email || !password)
return res.status(400).json({ msg: "Not all fields have been entered." });
const user = await User.findOne({ email: email });
if (!user)
return res
.status(400)
.json({ msg: "No account with this email has been registered." });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ msg: "Invalid credentials." });
const token = jwt.sign({ id: user._id },process.env.jwtSecret);
if(token) return res
.json({
token,
user: {
id: user._id,
username: user.username,
pricing: user.pricing
},
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.delete("/delete", auth, async (req, res) => {
try {
const deletedUser = await User.findByIdAndDelete(req.user);
res.json(deletedUser);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post("/tokenIsValid", async (req, res) => {
try {
const token = req.header("x-auth-token");
if (!token) return res.json({error: message});
const verified = jwt.verify(token,process.env.jwtSecret);
if (!verified) return res.json({error: message});
const user = await User.findById(verified.id);
if (!user) return res.json({error: message});
return res.json(true);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.get("/", auth, async (req, res) => {
const user = await User.findById(req.user);
console.log(user);
res.json({
username: user.username,
id: user._id,
});
});
router.put("/update", async (req, res) => {
const { id,pricing } = req.body;
if (!id) {
return res.status(400).json({ Msg: "Not all fields have been entered." });
}
User.findByIdAndUpdate(id, { pricing: pricing }).then(() => {
User.findOne({ _id: id }).then((user) => {
res.send(user);
console.log(user)
})
})
})
;
module.exports = router;

View File

@ -1,33 +0,0 @@
const mongoose = require('mongoose');
const UserSchema = mongoose.Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required:true,
unique: true
},
phonenumber: {
type: Number,
required: true
},
password: {
type:String,
required:true,
minlength: 5
},
pricing: {
type:String,
enum: ['free','basic','intermediate','luxury'],
default:'free',
required:false
}
});
module.exports = User = mongoose.model('user',UserSchema);

View File

@ -1,34 +0,0 @@
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
require('dotenv').config()
// set up express
const app = express();
app.use(express.json());
app.use(cors());
app.get('/', (req, res) => { res.send('Hello from Express!')});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`The server has started on port: ${PORT}`));
// set up mongoose
mongoose.connect(
process.env.mongoURI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
},
(err) => {
if (err) throw err;
console.log("MongoDB connection established");
}
);
// set up routes
app.use("/users", require("./routes/users"));

77
src/App.js Normal file
View File

@ -0,0 +1,77 @@
import React, { useEffect, useState } from 'react';
import Axios from 'axios';
import HomePage from "./components/HomePage";
import PricingPlan from "./components/PricingPlan";
import LogInContainer from "./components/LogInContainer";
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import UserContext from "./context/UserContext";
import Options from "./components/Options";
import Stepper from './components/Stepper';
import NavBar from "./components/NavBar";
import FillingDetails from "./components/FillingDetails";
import Error404 from './components/Error404';
import Payment from './components/Payment'
import 'bootstrap/dist/css/bootstrap.min.css';
export default function App() {
const [userData, setUserData ] = useState({
token: undefined,
user: undefined
});
useEffect(() => {
const checkLoggedIn = async () => {
let token = localStorage.getItem("auth-token");
console.log("app js " + token);
if (token == null) {
localStorage.setItem("auth-token","");
token ="";
}
const tokenRes = await Axios.post(
"https://server-locaft.herokuapp.com/users/tokenIsValid",
null,
{headers: {"x-auth-token": token }}
);
if (tokenRes.data) {
const userRes = await Axios.get("https://server-locaft.herokuapp.com/users/",
{headers:{"x-auth-token":token},
});
setUserData({
token,
user: userRes.data,
});
}
};
checkLoggedIn();
},[])
return (
<>
<div className="App">
<BrowserRouter>
<UserContext.Provider value= {{userData, setUserData}}>
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="asdf" component={NavBar} />
<Route path="/user" component={LogInContainer} />
<Route path="/pricing" component={PricingPlan} />
<Route path="/track" component={Stepper} />
<Route path="/options" component={Options} />
<Route path="/details" component={FillingDetails} />
<Route path="/payment" component={Payment} />
<Route path="/" component={Error404} />
</Switch>
</UserContext.Provider>
</BrowserRouter>
</div>
</>
);
}

8
src/App.test.js Normal file
View File

@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -0,0 +1,58 @@
import React from 'react';
import styled from 'styled-components';
import Lottie from 'react-lottie';
import animationData from '../lottie/box_error';
const Body = styled.div`
@import url('https://fonts.googleapis.com/css?family=Roboto:400,100,300,500');
font-size: 100%;
line-height: 1.5;
font-family: "Roboto", sans-serif;
display:flex;
justify-content: center;
align-items: center;
`;
const Container = styled.div`
position: relative;
background-color: #66bfbf;
text-align: center;
`;
const Heading = styled.h1`
padding-top: 15%;
color: white;
font-size: 4rem;
margin: 0px;
`;
const defaultOptions = {
loop: true,
autoplay: true,
animationData: animationData,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice"
}
};
const Error404 = () => {
return (
<Body>
<Container>
<Heading>Error </Heading>
<br />
<Lottie height={500} width={500} options={defaultOptions} />
</Container>
</Body>
);
}
export default Error404;

View File

@ -0,0 +1,53 @@
import React from "react";
import styled from 'styled-components';
export default function ErrorNotice(props) {
const ErrorNotice = styled.div`
margin: 1rem 0;
border: 1px solid #e07c7c;
border-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #f8d6d6;
padding: 10px;
`;
const ErrorMessage = styled.div`
color: #000000;
`;
const ErrorButton = styled.a
`
color: red;
position: relative;
width: 20px;
height: 20px;
opacity: 0.3;
&:hover {
opacity: 1;
}
&:before, &:after {
position: absolute;
left: 15px;
content: ' ';
height: 19px;
width: 2px;
background-color: red;
}
&:before {
transform: rotate(45deg);
}
&:after {
transform: rotate(-45deg);
}
`;
return (
<ErrorNotice>
<ErrorMessage>{props.message}</ErrorMessage>
<ErrorButton onClick={props.clearError}></ErrorButton>
</ErrorNotice>
);
}

View File

@ -0,0 +1,75 @@
import React,{useState} from 'react';
import styled from 'styled-components';
import Footer from './Footer';
import NavBar from './NavBar';
const Selector = styled.select`
width: 25%;
`;
const Container = styled.div`
padding: 50px;
`;
const Heading = styled.h1`
color: #66bfbf !important;
`;
const FillingDetails = () => {
const [foodState, setFoodState] = useState(null);
return (
<Container>
<NavBar></NavBar>
<br></br>
<br></br>
<Heading>Details</Heading>
<br></br>
<div>
Source:&nbsp;&nbsp;
<Selector
className="custom-select"
value={foodState}
onChange={(e) => {
const selectedFood = e.target.value;
setFoodState(selectedFood);
}}
>
<option value="source1" >source12</option>
<option value="source2">source2</option>
<option value="source3">source3</option>
</Selector>
<br></br>
{foodState}
<br></br>
<br></br>
<br></br>
Destination: &nbsp;&nbsp;
<Selector
className="custom-select"
value={foodState}
onChange={(e) => {
const selectedFood = e.target.value;
setFoodState(selectedFood);
}}
>
<option value="dest1" >dest1</option>
<option value="dest2">dest2</option>
<option value="dest3">dest3</option>
</Selector>
<br></br>
{foodState}
</div>
<Footer />
</Container>
);
}
export default FillingDetails;

62
src/components/Footer.js Normal file
View File

@ -0,0 +1,62 @@
import React from 'react';
import styled from 'styled-components';
import { Facebook, Twitter, Instagram } from "@styled-icons/fa-brands";
import { Envelope } from "@styled-icons/fa-solid";
import { StyledIconBase } from '@styled-icons/styled-icon'
import {
Container
} from 'react-bootstrap';
const ContainerPadded = styled(Container)`
padding: 7% 15%;
text-align: center;
`;
const WhiteSection = styled.footer`
background: ${props => props.background || "white"};
`;
const ContainerCentered = styled.div`
display:flex;
flex-direction: row;
justify-content: center;
`;
const IconStyler = styled.div`
${StyledIconBase} {
width: ${props => props.width ? props.width : 26}px;
height: ${props => props.height ? props.height : 26};
color: ${props => props.color ? props.color : "white"};
}
margin: 20px 10px;
`;
const Footer = () => {
return (
<WhiteSection>
<ContainerPadded fluid>
<ContainerCentered>
<IconStyler color="#000" width={20} height={20}><Facebook /></IconStyler>
<IconStyler color="#000" width={20} height={20}><Twitter /></IconStyler>
<IconStyler color="#000" width={20} height={20}><Instagram /></IconStyler>
<IconStyler color="#000" width={20} height={20}><Envelope /></IconStyler >
</ContainerCentered>
<p>© Copyright 2020 Locaft</p>
<p><a href="/tc">Terms and Conditions</a></p>
<p><a href="/pp">Privacy Policy</a></p>
</ContainerPadded >
</WhiteSection >
)
}
export default Footer;

249
src/components/HomePage.js Normal file
View File

@ -0,0 +1,249 @@
import React from 'react';
import NavBar from './NavBar';
import Footer from './Footer';
import { useHistory } from "react-router-dom";
import Lottie from 'react-lottie';
import animationData from '../lottie/plane_gif';
import {Container,Row,Col,Carousel, Button} from "react-bootstrap";
import styled from 'styled-components';
import { CheckCircle, Heart, AddressCard, ChartLine } from '@styled-icons/fa-solid';
import { Bullseye } from "@styled-icons/fa-solid";
import { StyledIconBase } from '@styled-icons/styled-icon'
import Sidebar from './Sidebar';
const Body = styled.div`
`;
const IconStyler = styled.div`
${StyledIconBase} {
width: ${props => props.width ? props.width : 26}px;
height: ${props => props.height ? props.height : 26};
color: ${ props => props.color ? props.color: "white"};
}
`;
const defaultOptions = {
loop: true,
autoplay: true,
animationData: animationData,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice"
}
};
const ColoredSection = styled.section`
background-color:#66bfbf;
color: #fff;
background-attachment: fixed;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
`;
const WhiteSection = styled.section`
background:#fff;
`;
const PressSection = styled(ColoredSection)`
padding-bottom: 3%;
align-items:center;
`;
const PressLogo = styled.img`
width: 18%;
height: 18%;
margin: 20px 20px 50px;
`;
const RowFix = styled(Row)`
margin: 0 0px;
`;
const FeatureCol = styled(Col)`
padding: 4.5%;
`;
const ContainerPadded = styled(Container)`
padding: 5% 5%;
text-align: center;
`;
const BigHeading = styled.h1`
font-size: 5rem;
line-height: 1.5;
font-family: "Ubuntu";
color: white;
font-weight: bold;
`;
const FeatureTitle = styled.h3`
font-size: 1.5rem;
color:#8f8f8f;
align-self: center;
`;
const TestimonalTitle = styled.h2`
font-size: 3rem;
color:#fff;
line-height: 1.5;
align-content: center;
padding: 10px 50px;
font-style: italic;
`;
export default function HomePage() {
const history = useHistory();
return (
<Body>
<ColoredSection >
<ContainerPadded fluid>
<Row>
<FeatureCol lg="6">
<BigHeading>Adapt to a new place easy peasy.</BigHeading>
<Button variant="info" onClick={() => {
history.push("/user/login")
}} >Log In</Button> &nbsp;
<Button variant="info" onClick={() => history.push("/user/register")} >Sign Up</Button>
</FeatureCol>
<FeatureCol lg="6">
<Lottie options= { defaultOptions } />
</FeatureCol>
</Row>
</ContainerPadded>
</ColoredSection>
<WhiteSection id="services">
<ContainerPadded fluid>
<Row>
<FeatureCol lg="4">
<IconStyler color="#66bfbf" width={50} height={50}><CheckCircle /></IconStyler>
<br/>
<FeatureTitle>Easy to use.</FeatureTitle>
<p>Get relocated.We'll take care of everything.</p>
</FeatureCol>
<FeatureCol lg="4">
<IconStyler color="#66bfbf" width={50} height={50}><Bullseye /></IconStyler>
<br />
<FeatureTitle>Efficient</FeatureTitle>
<p>Get highest number of services for lowest cost possible.</p>
</FeatureCol>
<FeatureCol lg="4">
<IconStyler color="#66bfbf" width={50} height={50}><Heart /></IconStyler>
<br />
<FeatureTitle>Relax</FeatureTitle>
<p>Sit back , we'll do the dirty work.</p>
</FeatureCol>
</Row>
</ContainerPadded>
</WhiteSection>
<ColoredSection>
<br/>
<br/>
<Carousel>
<Carousel.Item>
<Carousel.Caption>
</Carousel.Caption>
<TestimonalTitle>"I had to shift from Bangalore to Hyderabad. Thanks to Locaft , it was easy to know about this place."</TestimonalTitle>
<p style={{'text-align':'center'}}>Nishant, Pune</p>
</Carousel.Item>
<Carousel.Item >
<Carousel.Caption>
</Carousel.Caption>
<TestimonalTitle>"Relocation took me 3 months previously , but thanks to Locaft , everything was done within 3 days."</TestimonalTitle>
<p style={{'text-align': 'center'}}>Mani, Hyderabad</p>
</Carousel.Item>
</Carousel>
</ColoredSection>
<PressSection>
<ContainerPadded fluid>
<BigHeading>Our Partners</BigHeading>
<PressLogo src="/indigo_optimized.jpg" alt="indigo-brand" />
<PressLogo src="/avasa_optmized.jpg" alt="avassa-brand" />
<PressLogo src="/vrl_optmized.jpg" alt="vrl-brand" />
</ContainerPadded>
</PressSection>
<WhiteSection id="about-us">
<ContainerPadded fluid>
<Row>
<FeatureCol lg="4">
<IconStyler color="#66bfbf" width={50} height={50}><AddressCard /></IconStyler>
<br />
<FeatureTitle>About Us</FeatureTitle>
<p>Adapting to a new place is always hard in any phase of life. We aim to make it easy. </p>
</FeatureCol>
<FeatureCol lg="4">
<IconStyler color="#66bfbf" width={50} height={50}><Bullseye /></IconStyler>
<br />
<FeatureTitle>Vision</FeatureTitle>
<p>Bringing all the basic amenities to the new place before your arrival.</p>
</FeatureCol>
<FeatureCol lg="4">
<IconStyler color="#66bfbf" width={50} height={50}><ChartLine /></IconStyler>
< br/>
<FeatureTitle>Mission</FeatureTitle>
<p>Getting adapted and familiar to the new place made easy.</p>
</FeatureCol>
</Row>
</ContainerPadded>
</WhiteSection>
<ColoredSection>
<ContainerPadded fluid>
<Row>
<FeatureCol lg="12">
<BigHeading>check us out</BigHeading>
<img width="200px" src="google-play-badge.png"></img>
&nbsp;
<img width="160px" src="apple_badge.svg" ></img>
</FeatureCol>
</Row>
</ContainerPadded>
</ColoredSection>
<Sidebar logout="{logout}" />
<NavBar />
<div id="footer">
<Footer />
</div>
</Body>
);
}

103
src/components/HouseCard.js Normal file
View File

@ -0,0 +1,103 @@
import React from 'react';
import styled from 'styled-components';
const Image = styled.img`
display:block;
width: inherit;
height: inherit;
border-radius: 40px;
box-shadow: none;
object-fit:cover;
`;
const Tick = styled.input.attrs(props => ({
type: "radio",
name: "radiobtn"
}))`
`;
const Hover = styled.div`
height: inherit;
width: inherit;
opacity: 0;
transition: opacity 350ms ease;
position: absolute;
`;
const Overlay = styled.div`
height: inherit;
width: inherit;
transition: black 350ms ease;
background-color: transparent;
border-radius: 40px;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
`;
const CardTitle = styled.h2`
margin-top: 10px;
margin-left: 10px;
font-family: sans-serif;
box-shadow: none;
color: #fff;
`;
const Paragraph = styled.p`
margin-top: 10px;
margin-left: 10px;
color: #fff;
`;
const Card = styled.div`
width: 200px;
height: 200px;
border-radius: 40px;
box-shadow: 4px 4px 5px 5px rgba(0,0,0,0.01), -2px -2px 5px 5px rgba(0,0,0,0.22);
cursor: pointer;
transition: 0.4s;
position: relative;
background-image: url("${props => props.img ? props.img : "vrl.jpg"}");
background-size: cover;
&:hover ${Overlay} {
background-color: rgba(0,0,0,0.5);
}
&:hover ${CardTitle}, :hover ${Paragraph}{
transform: translate3d(0,0,0);
}
&:hover ${Hover}{
opacity: 1;
}
`;
const HouseCard = (props) => {
return (
<Card img = {props.img}>
<Overlay>
<Hover>
<CardTitle>{props.title ? props.title : "asdf"}</CardTitle>
<Paragraph>{props.desc ? props.desc: "zxcv"}</Paragraph>
</Hover>
</Overlay>
</Card>
);
}
export default HouseCard;

View File

@ -0,0 +1,16 @@
import React from 'react';
const HouseDetails = (props) => {
const contin = e => {
e.preventDefault();
this.props.nextStep();
};
const back = e => {
e.preventDefault();
this.props.prevStep();
};
const {values, handleChange} = props;
}

View File

@ -0,0 +1,288 @@
import React, {useState, useContext} from 'react';
import { useHistory,BrowserRouter, Route, NavLink, Switch,withRouter } from 'react-router-dom';
import Register from './Register';
import Login from './Login';
import Footer from './Footer';
import styled, {css} from 'styled-components';
import {Button} from './miscellaneous/Styles';
import UserContext from "../context/UserContext";
import {logout} from "./NavBar"
import { GoogleLogin } from 'react-google-login';
import Axios from "axios";
import { Device} from './miscellaneous/Responsive';
const BaseApp = styled.div`
display: flex;
color: white;
height:100vh;
flex-direction: column;
@media ${Device.laptop} {
flex-direction: row;
}
`;
const AppSide = styled.div`
background-color: #66bfbf;
display: grid;
grid-template-columns: repeat(auto-fit, 300px);
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
@media ${Device.laptop} {
width: 50%;
}
`;
const AppForm = styled.div`
background-color: #ffffff;
padding: 25px 40px;
height: 100vh;
width: 100vw;
@media ${Device.laptop} {
width: 50%;
overflow:auto
}
`;
const PageSwitcherContainer = styled.div`
display: flex;
justify-content: flex-end;
margin-bottom: 10%;
`;
const BannerHeading = styled.h1`
position: relative;
text-align: center;
font-family: Ubuntu;
font-size: 5rem;
font-weight: bold;
color: #ffffff;
text-decoration: none;
text-transform: lowercase;
`;
const PlaneContainer = styled.div`
width:100px;
display:flex;
margin-bottom: 50px;
align-content: flex-start;
justify-content: flex-start;
`;
const TextContainer = styled.p`
width: 50%;
background-color: #66bfbf;
display:flex;
flex-direction: column;
justify-content: flex-end;
`;
const BannerText = styled.p`
color:${props => props.colour ? props.colour : "white"};
font-size: 1.25em;
font-style:italic;
`;
const SkyContainer = styled.div`
margin-top: 600px;
width: 100%;
background-size: 100%;
`;
const PageSwitcher = styled(NavLink)`
background-color: #4C5D72;
color: white;
padding: 10px 25px;
cursor: pointer;
font-size: .9em;
border: none;
outline: none;
display: inline-block;
text-decoration: none !important;
&.active{
background-color: #66bfbf;
color: white;
}
&:first-child {
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
}
&:last-child {
border-top-right-radius: 25px;
border-bottom-right-radius: 25px;
}
`;
const FormLink = styled(NavLink)`
color: #707C8B;
text-decoration: none !important;
display: inline-block;
font-size: 1.7em;
margin: 0 10px;
padding-bottom: 5px;
border: none;
&:first-child {
margin-left: 0;
}
&:last-child{
color: #707c8b;
}
&.active{
border-bottom: 1px solid #199087;
}
`;
const FormTitle = styled.div`
color: #000000;
font-weight: 300;
margin-bottom: 50px;
`;
const responseSuccessGoogle = (response) => {
Axios({
method: 'POST',
url: "http://localhost:5000/users/googlelogin",
data: { idToken: response.tokenId }
}).then(response => {
console.log(response);
})
}
const responseFailGoogle = (response) => {
console.log(response)
}
const LogInContainer = () => {
const { userData, setUserData } = useContext(UserContext);
const [error, setError] = useState();
const [hasLogged, setHasLogged] = useState(false);
const history = useHistory();
const responsePassGoogle = async (response) => {
try{
const idToken = response.tokenId;
console.log("id token" + idToken);
const googleres = await Axios.post(
"https://server-locaft.herokuapp.com/users/googlelogin",{
idToken: idToken
}
);
setUserData({
token: googleres.data.token,
user: googleres.data.user
});
localStorage.setItem("auth-token",googleres.data.token);
setHasLogged(true);
} catch (err) {
err.response.data.msg && setError(err.response.data.msg);
}
}
return (
<BaseApp>
<meta name="google-signin-client_id"
content={`${process.env.REACT_APP_CLIENT_ID}.apps.googleusercontent.com`} />
<AppSide>
{!hasLogged ? (
<GoogleLogin
clientId= {process.env.REACT_APP_CLIENT_ID}
buttonText="Login with Google"
onSuccess={responsePassGoogle}
onFailure={responseFailGoogle}
cookiePolicy={'single_host_origin'}
/>
): (
<React.Fragment>
<p> username: {userData.user.username}</p>
<p> email: {userData.user.email}</p>
<p> pricing: {userData.user.pricing}</p>
</React.Fragment>
) }
</AppSide>
<AppForm>
{!userData.user ? (
<BrowserRouter basename="user">
<PageSwitcherContainer>
<PageSwitcher to="/login" >Sign In</PageSwitcher>
<PageSwitcher to="/register" >Sign Up</PageSwitcher>
</PageSwitcherContainer>
<FormTitle>
<FormLink to="/login" >Sign In</FormLink> or <FormLink to="/register">Sign Up</FormLink>
</FormTitle>
<Switch>
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
</Switch>
</BrowserRouter>
) : (
<React.Fragment>
<BannerText colour="black">Log in successful.</BannerText>
<Button
type="submit"
radiuscolor="#009578"
textcolor="#009578"
hovercolor="#009578"
hovertextcolor="white"
onClick={() => { history.push("/")}}
>home</Button>
&nbsp;
<Button
type="submit"
radiuscolor="#009578"
textcolor="#009578"
hovercolor="#009578"
hovertextcolor="white"
onClick={() => {logout(setUserData); history.push("/")}}
>Logout</Button>
</React.Fragment>
)}
</AppForm>
</BaseApp>
);
}
export default withRouter(LogInContainer);

70
src/components/Login.js Normal file
View File

@ -0,0 +1,70 @@
import React, { useState, useContext } from "react";
import UserContext from "../context/UserContext";
import Axios from "axios";
import ErrorNotice from "./ErrorNotice";
import { Link, useHistory, withRouter } from "react-router-dom";
import {Button, FormCenter, FormField, FormLabel, FormInput, FormLink } from './miscellaneous/Styles'
const Login = () => {
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [error, setError] = useState();
const { userData,setUserData } = useContext(UserContext);
const history = useHistory();
const submit = async (e) => {
e.preventDefault();
try {
const loginUser = { email, password };
const loginRes = await Axios.post(
"https://server-locaft.herokuapp.com/users/login",
loginUser
);
console.dir("login res " + loginRes.data.user);
setUserData({
token: loginRes.data.token,
user: loginRes.data.user,
});
localStorage.setItem("auth-token", loginRes.data.token);
history.push("/");
} catch (err) {
err.response.data.msg && setError(err.response.data.msg);
}
};
return (
<FormCenter>
{error && (
<ErrorNotice message={error} clearError={() => setError(undefined)} />
)}
<form className="FormFields" onSubmit={submit}>
<FormField>
<FormLabel htmlFor="email">E-Mail Address</FormLabel>
<FormInput type="email" id="email" value={ email } placeholder="enter your email" name="email" onChange={(e) => setEmail(e.target.value)} />
</FormField>
<FormField>
<FormLabel htmlFor="password">Password</FormLabel>
<FormInput type="password" id="password" value={ password } placeholder="Enter your password" name="password" onChange={(e) => setPassword(e.target.value)} />
</FormField>
<FormField>
<Button
type="submit"
radiuscolor="#009578"
textcolor="#009578"
hovercolor="#009578"
hovertextcolor="white"
>Sign In</Button> <FormLink exact to="/register" className="FormField__Link">Not a member?</FormLink>
</FormField>
</form>
</FormCenter>
);
}
export default withRouter(Login);

146
src/components/NavBar.js Normal file
View File

@ -0,0 +1,146 @@
import React, { useState,useContext,useEffect } from 'react';
import { Link } from "react-router-dom";
import UserContext from "../context/UserContext";
import styled,{ css } from 'styled-components';
const Header = styled.header`
@import url('https://fonts.googleapis.com/css?family=Montserrat|Ubuntu');
background: #66bfbf;
position: fixed;
top: 0;
left: 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
transition: 0.6s;
padding: 5px 15px;
z-index: 100000;
font-family: Ubuntu;
${ props => props.sticky ? css`
${Header};
padding: 3px 45px;
min-height: 3vh;
opacity: 0.85;
display: fixed;
`:css``};
& .logo {
font-family: "Ubuntu";
font-size: 2rem;
font-weight: bold;
position: relative;
color: #fff;
text-decoration: none;
text-transform: lowercase;
transition: 0.6s;
}
@media (max-width: 768px) {
display:none;
}
`;
const List = styled.ul`
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
margin-bottom: 0px !important;
`;
const ListElement = styled.li`
color: #fff;
text-decoration: none;
text-transform: uppercase;
position:relative;
padding:3px 50px;
`;
const Anchor = styled.a`
color: #fff;
text-transform: uppercase;
color: inherit;
letter-spacing: 2px;
font-size: 1.2em;
padding: 3px ;
transition: 0.6s;
white-space: nowrap;
`;
const Linker = styled(Link)`
color:#fff;
text-transform: uppercase;
color: inherit;
letter-spacing: 2px;
font-size: 1.2em;
padding: 3px 0;
transition: 0.6s;
`;
export const logout = (setUserData) => {
setUserData({
token: undefined,
user: undefined,
});
localStorage.setItem("auth-token", "");
};
export default function NavBar() {
const [scrolled, setScrolled] = useState();
const { userData, setUserData } = useContext(UserContext);
const handleScroll=() => {
const offset=window.scrollY;
if(offset > 200 ){
setScrolled(true);
}
else{
setScrolled(false);
}
}
useEffect(() => {
window.addEventListener('scroll',handleScroll)
})
return (
<div className="navbar">
<Header sticky = {scrolled} >
<Anchor href="/" className="logo">locaft</Anchor>
<List>
<ListElement><Anchor href="/">Home</Anchor></ListElement>
<ListElement><Anchor href="/#about-us">About</Anchor></ListElement>
<ListElement><Anchor href="/pricing">Pricing</Anchor></ListElement>
<ListElement><Anchor href="/#footer">Contact us</Anchor></ListElement>
{userData.user ? (
<React.Fragment>
<ListElement><Linker onClick={() => logout(setUserData)}>{userData.user.username}</Linker></ListElement>
</React.Fragment>
) : (
<React.Fragment>
<ListElement><Linker to="/user/register">Register</Linker></ListElement>
<ListElement><Linker to="/user/login">login</Linker></ListElement>
</React.Fragment>
)}
</List>
</Header>
</div>
)
}

111
src/components/Options.js Normal file
View File

@ -0,0 +1,111 @@
import React from 'react';
import '../options.css';
import Card from './HouseCard';
import Footer from "./Footer";
import styled from 'styled-components';
const CardList = styled.div`
display: grid;
position: relative;
margin: 15px;
grid-template-rows: repeat(auto-fill,minmax(200px,1fr));
grid-template-columns: repeat(auto-fill,minmax(200px,1fr));
grid-gap: 30px;
align-items: center;
justify-items: center;
`;
export default function Options() {
document.addEventListener('DOMContentLoaded', () => {
const previousBtn = document.getElementById('previousBtn');
const nextBtn = document.getElementById('nextBtn');
const finishBtn = document.getElementById('finishBtn');
const content = document.getElementById('content');
const bullets = [...document.querySelectorAll('.bullet')];
const MAX_STEPS = 4;
let currentStep = 1;
nextBtn.addEventListener('click', () => {
bullets[currentStep - 1].classList.add('completed');
currentStep += 1;
previousBtn.disabled = false;
if (currentStep === MAX_STEPS) {
nextBtn.disabled = true;
finishBtn.disabled = false;
}
content.innerText = `Step Number ${currentStep}`;
});
previousBtn.addEventListener('click', () => {
bullets[currentStep - 2].classList.remove('completed');
currentStep -= 1;
nextBtn.disabled = false;
finishBtn.disabled = true;
if (currentStep === 1) {
previousBtn.disabled = true;
}
content.innerText = `Step Number ${currentStep}`;
});
finishBtn.addEventListener('click', () => {
window.location.reload();
});
})
return (
<div className="container">
<div id="stepProgressBar">
<div className="step">
<p className="step-text">About</p>
<div className="bullet">1</div>
</div>
<div className="step">
<p className="step-text">Contact</p>
<div className="bullet">2</div>
</div>
<div className="step">
<p className="step-text">Step 3</p>
<div className="bullet">3</div>
</div>
<div className="step">
<p className="step-text">Step 4</p>
<div className="bullet ">4</div>
</div>
</div>
<p id="content" className="text-center">Step Number 1</p>
<div id="main">
<button id="previousBtn" >Previous</button>
<button id="nextBtn">Next</button>
<button id="finishBtn" >Finish</button>
</div>
<CardList>
<Card img="skyscraper.png" title="cardtitle" desc="description"/>
<Card img="skyscraper.png"/>
<Card img="skyscraper.png"/>
<Card img="skyscraper.png"/>
<Card img="indigo.jpg"/>
<Card img="locaft.png"/>
<Card img="skyscraper.png"/>
<Card img="skyscraper.png"/>
<Card img="skyscraper.png"/>
</CardList>
<Footer />
</div>
)
}

21
src/components/Payment.js Normal file
View File

@ -0,0 +1,21 @@
import React,{ useContext } from 'react';
import NavBar from './NavBar';
import Footer from './Footer';
import UserContext from '../context/UserContext'
const Payment = (props) => {
const { userData, setUserData } = useContext(UserContext);
return (
<div>
<h1>{userData.user.username}</h1>
<h2>{props.pricing}</h2>
</div>
);
}
export default Payment;

View File

@ -0,0 +1,304 @@
import React, { useState,useContext } from 'react';
import NavBar from './NavBar';
import Footer from './Footer';
import styled,{css} from 'styled-components';
import UserContext from "../context/UserContext";
import { useHistory } from "react-router-dom";
import Axios from 'axios';
import { Button } from './miscellaneous/Styles';
import { Device} from './miscellaneous/Responsive';
const PricingPlanContainer = styled.div`
display:flex;
align-items: center;
justify-content: center;
padding: 10px;
flex-direction: column;
@media ${Device.laptop} {
flex-direction: row;
}
`;
const Radio = styled.input`
display:none;
`;
const Label = styled.label`
display: relative;
cursor:pointer;
`;
const Pricing = styled.section`
background: white;
border-radius: 25px;
box-shadow: 0 0 5px rgba(0,0,0,0.2);
overflow: hidden;
font-family: sans-serif;
font-size: 16px;
line-height: 1.5;
color: #555555;
margin: 15px;
&:hover {
cursor: pointer;
box-shadow: 0 0 15px rgba(0,0,0,0.4);
transform: scale(1.05);
}
${props => props.pricing_id === props.pricing_plan ? css`
box-shadow: 0 0 15px rgba(0,0,0,0.4);
transform: scale(1.05);
`:css``};
`;
const Text = styled.p`
font-size: 0.9em;
text-align: center;
margin: 0 0 10px 0;
`;
const Currency = styled.p`
margin: 0;
text-align: center;
font-size: 2em;
color:#000000;
`;
const Title = styled.h1`
font-size:1.5em;
font-weight: 400;
`;
const Header = styled.div`
padding:25px;
background: #009578;
color: #ffffff;
`;
const Summary = styled.h2`
font-size: 1em;
font-weight: 300;
`;
const SpecialText = styled.div`
padding: 10px;
text-align: center;
font-weight: bold;
color: #ffffff;
background: #007c64;
box-shadow: 0 0 10px rgba(0,0,0,0.2) inset;
&, ${Title}{
margin: 0;
text-align: center;
font-family: sans-serif;
}
`;
const Description = styled.div`
display:block;
padding: 25px;
`;
const List = styled.ul`
padding: 0;
margin: 0;
text-align: left;
`;
const Feature = styled.li`
margin: 0 0 25px 0;
padding-left: 25px;
position: relative;
font-size: 0.9 em;
&:not(:last-child) {
margin-bottom: 2em;
}
&::before {
content: "✓ ";
color: green;
}
`;
const Actions = styled.div`
padding: 25px;
border-top: 1px solid #eeeeee;
display: flex;
flex-direction: column;
`;
const Heading = styled.h1`
color: #309975;
margin-left: 20px;
margin-top: 100px;
font-weight: bold;
`;
const PricingPlan = () => {
const { userData, setUserData } = useContext(UserContext);
const [ purchased, setPurchased ] = useState(false);
const [ pricing, setPricing ] = useState();
const history = useHistory();
const submit = async (props) => {
props.preventDefault();
try {
const id = userData.user.id;
console.log("Id " + id)
const pricingRes = await Axios.put(
"https://server-locaft.herokuapp.com/users/update", {
id,
pricing
}
);
} catch (err) {
console.log(err);
}
}
return (
<div className="body">
<NavBar />
{ !purchased ? (
<React.Fragment>
<Heading>Pricing Plan</Heading>
<PricingPlanContainer onChange={event => setPricing(event.target.value)}>
<Pricing pricing_plan={pricing} pricing_id="basic">
<Radio type ="radio" value="basic" name="pricing" id = "basic"/>
<Label for="basic">
<Header>
<Title>Basic Package</Title>
<Summary>For those getting started</Summary>
</Header>
<Description>
<List>
<Feature>Feature #1</Feature>
<Feature>Feature #2</Feature>
<Feature>Feature #3</Feature>
<Feature>Feature #4</Feature>
</List>
</Description>
<Actions>
<Currency>$10</Currency>
<Text>per month</Text>
<Text>Minimum sped over 12 months</Text>
</Actions>
</Label>
</Pricing>
<Pricing pricing_plan={pricing} pricing_id="intermediate">
<Radio type="radio" value="intermediate" name="pricing" id="intermediate" />
<Label for="intermediate" >
<SpecialText>Recommended</SpecialText>
<Header>
<Title>Intermediate Package</Title>
<Summary>For those getting started</Summary>
</Header>
<Description>
<List>
<Feature>Feature #1</Feature>
<Feature>Feature #2</Feature>
<Feature>Feature #3</Feature>
<Feature>Feature #4</Feature>
</List>
</Description>
<Actions>
<Currency>$50</Currency>
<Text>per month</Text>
<Text>Minimum spend over 12 months</Text>
</Actions>
</Label>
</Pricing>
<Pricing pricing_plan={pricing} pricing_id="luxury">
<Radio type="radio" value="luxury" name="pricing" id="luxury" />
<Label for="luxury">
<Header>
<Title>Luxury Package</Title>
<Summary>For those getting started</Summary>
</Header>
<Description>
<List>
<Feature>Feature #1</Feature>
<Feature>Feature #2</Feature>
<Feature>Feature #3</Feature>
<Feature>Feature #4</Feature>
</List>
</Description>
<Actions>
<Currency>$100</Currency>
<Text>per month</Text>
<Text>Minimum spend over 12 months</Text>
</Actions>
</Label>
</Pricing>
</PricingPlanContainer>
<PricingPlanContainer>
<Button
radiuscolor="#009578"
textcolor="#009578"
hovercolor="#009578"
hovertextcolor="white"
onClick={() => setPurchased(true)}
>Purchase</Button>
</PricingPlanContainer>
</React.Fragment>
): (
<React.Fragment>
<PricingPlanContainer styles = "{'flex-direction':'column'}">
<Heading>user name: {userData.user.username}</Heading>
<Heading>Plan selected : {pricing}</Heading>
<Button onClick={submit}>Confirm and Pay</Button>
</PricingPlanContainer>
</React.Fragment>
)
}
<Footer />
</div>
)
}
export default PricingPlan;

67
src/components/Radio.js Normal file
View File

@ -0,0 +1,67 @@
import React from "react";
import styled from "styled-components";
const RadioWrapper = styled.div`
`;
const Mark = styled.span`
position: relative;
border: 1px solid #777777;
width: 14px;
height: 14px;
left: 0;
border-radius: 50%;
margin-right: 5px;
vertical-align: middle;
&::after {
content: "";
display: block;
width: 0;
height: 0;
border-radius: 50%;
background-color: #03a9f4;
opacity: 0;
left: 50%;
top: 50%;
position: absolute;
transition: all 110ms;
}
`;
const Input = styled.input`
position: absolute;
visibility: hidden;
display: none;
&:checked + ${Mark} {
&::after {
width: 10px;
height: 10px;
opacity: 1;
left: 12%;
top: 12%;
}
}
`;
const Label = styled.label`
cursor: pointer;
position: relative;
${props =>
props.disabled &&
`
cursor: not-allowed;
opacity: 0.4;
`}
`;
const Radio = ({ name, children }) => (
<RadioWrapper>
<Label>
<Input name={name} type="radio" />
<Mark />
{children}
</Label>
</RadioWrapper>
);
export default Radio;

148
src/components/Register.js Normal file
View File

@ -0,0 +1,148 @@
import React, { useState, useContext } from "react";
import { useHistory, withRouter } from "react-router-dom";
import UserContext from "../context/UserContext";
import Axios from "axios";
import { Link } from "react-router-dom";
import ErrorNotice from "./ErrorNotice";
import styled from 'styled-components';
import {Button, FormCenter, FormField, FormLabel, FormInput, FormLink } from './miscellaneous/Styles'
const CheckBoxLabel = styled.label`
color: #646F7D;
font-size: .9em;
`;
const CheckBox = styled.input`
position: relative;
top: 1.5px;
`;
const TermsLink = styled.a`
color: #646F7D;
border-bottom: 1px solid #199087;
text-decoration: none;
display: inline-block;
padding-bottom: 2px;
margin-left: 5px;
`;
const Register = () => {
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [phonenumber, setPhonenumber] = useState();
const [username, setUsername] = useState();
const [error, setError] = useState();
const [contains8C, setContains8C] = useState(false);
const { setUserData } = useContext(UserContext);
const history = useHistory();
const submit = async (e) => {
e.preventDefault();
try {
const newUser = { username,email,phonenumber,password};
const isEmpty = !Object.values(newUser).some(x => (x !== null && x !== ''));
console.log("isempty: " + isEmpty )
if(isEmpty){
setError("Not all Fields are entered")
return;
}
await Axios.post("https://server-locaft.herokuapp.com/users/register", newUser);
const loginRes = await Axios.post("https://server-locaft.herokuapp.com/users/login", {
email,
password,
});
setUserData({
token: loginRes.data.token,
user: loginRes.data.user,
});
localStorage.setItem("auth-token", loginRes.data.token);
history.push("/");
} catch (err) {
return err.response.data.msg && setError(err.response.data.msg);
}
};
const validatePassword = () => {
if(password.length >= 8) {
setContains8C(true)
setError(null)
}
else { setContains8C(false); setError("The Password needs to be atleast 8 characters") };
}
return (
<FormCenter>
{error && (
<ErrorNotice message={error} clearError={() => setError(undefined)} />
)}
<form className="FormFields" onSubmit={submit}>
<FormField>
<FormLabel htmlFor="name">UserName</FormLabel>
<FormInput
type="text"
id="name"
placeholder="Enter your full name"
onChange={(e) => setUsername(e.target.value)}
/>
</FormField>
<FormField>
<FormLabel htmlFor="password">Password</FormLabel>
<FormInput
type="password"
id="password"
className="FormField__Input"
placeholder="Enter your password"
onChange={(e) => setPassword(e.target.value)}
onKeyUp={validatePassword}
/>
</FormField>
<FormField>
<FormLabel htmlFor="email">E-Mail Address</FormLabel>
<FormInput
type="email"
id="email"
className="FormField__Input"
placeholder="Enter your email"
onChange= { (e) => setEmail(e.target.value)}
/>
</FormField>
<FormField>
<FormLabel htmlFor="phone">Phone number</FormLabel>
<FormInput
type="number"
id="phonenumber"
className="FormField__Input"
placeholder="Enter your Phone no. (+91)"
onChange={(e) => setPhonenumber(parseInt(e.target.value, 10))}
/>
</FormField>
<FormField>
<CheckBoxLabel>
<CheckBox type="checkbox" name="hasAgreed" /> I agree all statements in <a href="/" className="FormField__TermsLink">terms of service</a>
</CheckBoxLabel>
</FormField>
<FormField>
<Button
type="submit"
radiuscolor="#009578"
textcolor="#009578"
hovercolor="#009578"
hovertextcolor="white"
>Sign Up</Button>
<FormLink to="/login">already a member?</FormLink>
</FormField>
</form>
</FormCenter>
);
}
export default withRouter( Register );

179
src/components/Sidebar.js Normal file
View File

@ -0,0 +1,179 @@
import React, {useState, useContext} from 'react';
import { Link } from 'react-router-dom'
import styled from 'styled-components';
import UserContext from '../context/UserContext';
const StyledMenu = styled.nav`
display: flex;
flex-direction: column;
position:fixed !important;
justify-content: center;
background: #EFFFFA;
transform: ${({ open }) => open ? 'translateX(0)' : 'translateX(-100%)'};
height: 100vh;
text-align: left;
padding: 2rem;
top: 0;
left: 0;
transition: transform 0.3s ease-in-out;
@media (max-width: 576px) {
width: 100%;
}
a {
font-size: 2rem;
text-transform: uppercase;
padding: 2rem 0;
font-weight: bold;
letter-spacing: 0.5rem;
color: #0D0C1D;
text-decoration: none;
transition: color 0.3s linear;
@media (max-width: 576px) {
font-size: 1.5rem;
text-align: center;
}
&:hover {
color: #343078;
}
}
`
const Menu = ({open, setOpen}) => {
const { userData, setUserData } = useContext(UserContext);
return (
<StyledMenu open={open} >
<a href="/#about-us"onClick={() => setOpen(false)}>
<span role="img" aria-label="about us">💁🏻</span>
About us
</a>
<a href="/pricing">
<span role="img" aria-label="pricing">💸</span>
Pricing
</a>
<a href="/#footer"onClick={() => setOpen(false)}>
<span role="img" aria-label="contact us">📩</span>
Contact
</a>
{userData.user ? (
<Link >
<span role="img" aria-label="{userData.user.username}">📩</span>
{userData.user.username}
</Link>
):(
<React.Fragment>
<a href="/user/register">
<span role="img" aria-label="Register">📩</span>
Register
</a>
<a href="/user/login">
<span role="img" aria-label="Login">📩</span>
Login
</a>
</React.Fragment>
)
}
</StyledMenu>
)
}
const StyledBurger = styled.button`
position: fixed;
top: 5%;
left: 2rem;
display: flex;
flex-direction: column;
justify-content: space-around;
width: 2rem;
height: 2rem;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;
&:focus {
outline: none;
}
&:hover{
background: transparent;
}
div {
width: 2rem;
height: 0.25rem;
background: ${({ open }) => open ? '#0D0C1D' : '#EFFFFA'};
border-radius: 10px;
transition: all 0.3s linear;
position: relative;
transform-origin: 1px;
:first-child {
transform: ${({ open }) => open ? 'rotate(45deg)' : 'rotate(0)'};
}
:nth-child(2) {
opacity: ${({ open }) => open ? '0' : '1'};
transform: ${({ open }) => open ? 'translateX(20px)' : 'translateX(0)'};
}
:nth-child(3) {
transform: ${({ open }) => open ? 'rotate(-45deg)' : 'rotate(0)'};
}
}
@media(min-width:768px){
display:none;
}
`
const Burger = ({ open, setOpen }) => {
return (
<StyledBurger open={open} onClick={() => setOpen(!open)}>
<div />
<div />
<div />
</StyledBurger>
)
}
const Sidebar = (props) => {
const [open, setOpen] = useState(false);
const node = React.useRef();
return (
<div>
<div ref={node}>
<Burger open={open} setOpen={setOpen} />
<Menu open={open} setOpen={setOpen} logout={props.logout} />
</div>
</div>
)
}
const useOnClickOutside = (ref, handler) => {
React.useEffect(() => {
const listener = event => {
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
return () => {
document.removeEventListener('mousedown', listener);
};
},
[ref, handler],
);
};
export default Sidebar;

70
src/components/Stepper.js Normal file
View File

@ -0,0 +1,70 @@
import React from 'react';
import Footer from './Footer';
import '../stepper.css';
import NavBar from './NavBar';
export default function Stepper() {
document.addEventListener('DOMContentLoaded', () => {
var list = document.getElementById('progress'),
next = document.getElementById('next'),
clear = document.getElementById('clear'),
children = list.children,
completed = 0;
// activating a node button
next.addEventListener('click', function() {
// count the number of completed nodes.
completed = (completed === 0) ? 1 : completed + 2;
if (completed > children.length) return;
// for each node that is completed, reflect the status
// and show a green color!
for (var i = 0; i < completed; i++) {
children[i].children[0].classList.remove('grey');
children[i].children[0].classList.add('green');
// if this child is a node and not divider,
// make it shine a little more
if (i % 2 === 0) {
children[i].children[0].classList.add('activated');
}
}
}, false);
// clear the activated state of the markers
clear.addEventListener('click', function() {
for (var i = 0; i < children.length; i++) {
children[i].children[0].classList.remove('green');
children[i].children[0].classList.remove('activated');
children[i].children[0].classList.add('grey');
}
completed = 0;
}, false);
});
return (
<div className="container">
< NavBar />
<h1 className ="relocheading">Relocation Status</h1>
<br />
<br />
<br />
<ul id="progress">
<li className="ele"><div className="node grey"></div><p>Transport tickets confirmed</p></li>
<li className="ele" ><div className="divider grey"></div></li>
<li className="ele" ><div className="node grey"></div><p>Packers & movers due to come in a day</p></li>
<li className="ele"><div className="divider grey"></div></li>
<li className="ele"><div className="node grey"></div><p>school admission being confirmed</p></li>
<li className = "ele"><div className="divider grey"></div></li>
<li className = "ele"><div className="node grey"></div><p>House is empty</p></li>
</ul>
<input type="button" value="Next" id="next" />
<input type="button" value="Clear" id="clear" />
<Footer />
</div>
)
}

103
src/components/Tracking.js Normal file
View File

@ -0,0 +1,103 @@
import React from 'react';
import Footer from './Footer';
import '../tracking.css';
export default function Tracking() {
document.addEventListener('DOMContentLoaded', () => {
const previousBtn = document.getElementById('previousBtn');
const nextBtn = document.getElementById('nextBtn');
const finishBtn = document.getElementById('finishBtn');
const content = document.getElementById('content');
const nodes = [...document.querySelectorAll('.node')];
const dividers = [...document.querySelectorAll('.divider')];
const MAX_STEPS = 4;
let currentStep = 1;
if (nextBtn) {
nextBtn.addEventListener('click', () => {
nodes[currentStep - 1].classList.add('completed');
currentStep += 1;
previousBtn.disabled = false;
if (currentStep === MAX_STEPS) {
nextBtn.disabled = true;
finishBtn.disabled = false;
}
content.innerText = `Step Number ${currentStep}`;
dividers[currentStep -1 ].classList.add('completed');
});
}
if (previousBtn) {
previousBtn.addEventListener('click', () => {
nodes[currentStep - 2].classList.remove('completed');
currentStep -= 1;
nextBtn.disabled = false;
finishBtn.disabled = true;
if (currentStep === 1) {
previousBtn.disabled = true;
}
content.innerText = `Step Number ${currentStep}`;
});
}
if (finishBtn) {
finishBtn.addEventListener('click', () => {
window.location.reload();
});
}
})
return (
<div class="wrapper">
<ul class="StepProgressBar">
<li class="step">
<p class="step-text">
</p>
<div class="node">
1
</div>
</li>
<li><div class="divider"></div></li>
<li class="step">
<p class="step-text">
</p>
<div class="node">
2
</div>
</li>
<li><div class="divider"></div></li>
<li class="step">
<p class="step-text">
</p>
<div class="node">
3
</div>
</li>
<li><div class="divider"></div></li>
<li class="step">
<p class="step-text">
</p>
<div class="node">
4
</div>
</li>
<li><div class="divider"></div></li>
</ul>
<div class="main">
<p id="content" class="text-center">Step Number 1</p>
<button id="previousBtn" >Previous</button>
<button id="nextBtn">Next</button>
<button id="finishBtn" >Finish</button>
</div>
<Footer />
</div>
)
}

View File

@ -0,0 +1,25 @@
import {Modal, Button} from 'react-bootstrap';
import React, {useState} from 'react';
export const CustomModal = (props) => {
const handleClose = () => props.setShow(false);
const handleShow = () => props.setShow(true);
return (
<>
<Modal show={props.show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>{props.title}</Modal.Title>
</Modal.Header>
<Modal.Body>{props.desc}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Log In
</Button>
</Modal.Footer>
</Modal>
</>
);
}

View File

@ -0,0 +1,19 @@
export const size = {
mobileS: '320px',
mobileM: '375px',
mobileL: '425px',
tablet: '768px',
laptop: '1024px',
laptopL: '1440px',
desktop: '2560px'
}
export const Device = {
mobileS: `(min-width: ${size.mobileS})`,
mobileM: `(min-width: ${size.mobileM})`,
mobileL: `(min-width: ${size.mobileL})`,
tablet: `(min-width: ${size.tablet})`,
laptop: `(min-width: ${size.laptop})`,
laptopL: `(min-width: ${size.laptopL})`,
desktop: `(min-width: ${size.desktop})`,
desktopL: `(min-width: ${size.desktop})`
};

View File

@ -0,0 +1,72 @@
import styled from 'styled-components'
import { Link } from 'react-router-dom'
const FormCenter = styled.div`
margin-bottom: 100px;
`;
const FormField = styled.div`
margin-bottom: 40px;
`;
const FormLabel = styled.div`
display: block;
text-transform: uppercase;
font-size: 1.25em;
color: #4C5D72;
text-align: start;
`;
const FormInput = styled.input`
width: 85%;
background-color: transparent;
border: none;
color: #4C5D72;
outline: none;
border-bottom: 1px solid #445366;
font-size: .9em;
font-weight: 300;
padding-bottom: 10px;
margin-top: 10px;
&:placeholder {
color: #616E7F;
}
`;
const FormLink = styled(Link)`
color: #66707D;
text-decoration: none;
display: inline-block;
padding-bottom: 5px;
margin-left: 12px;
`;
const Button = styled.button`
display: inline-block;
margin: 15px auto;
padding: 8px 20px;
color: ${props => props.textcolor ? props.textcolor : "black"} !important;
background: ${props => props.displaycolor ? props.displaycolor : "white"} ;
border-radius: ${props => props.radius ? props.radius: "5"}px;
border: 1px solid;
border-color: ${props => props.radiuscolor ? props.radiuscolor : "black"};
text-transform: uppercase;
letter-spacing: 0.02em;
font-weight: bold;
text-align: center;
cursor: pointer;
&:hover {
background: ${props => props.hovercolor ? props.hovercolor : "white"} ;
color: ${props => props.hovertextcolor ? props.hovertextcolor : "black"}!important;
}
`;
export { Button, FormCenter, FormField, FormLabel, FormInput, FormLink };

View File

@ -0,0 +1,3 @@
import { createContext } from "react";
export default createContext();

17
src/index.css Normal file
View File

@ -0,0 +1,17 @@
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700');
@import url('https://fonts.googleapis.com/css?family=Montserrat|Ubuntu');
* {
box-sizing: border-box;
font-family: "Roboto", sans-serif;
overflow-x: hidden;
}
body {
margin: 0;
padding: 0;
}
.mr-20 {
margin-right: 20px !important;
}

7
src/index.js Normal file
View File

@ -0,0 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />,document.getElementById('root'));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

89
src/options.css Normal file
View File

@ -0,0 +1,89 @@
#stepProgressBar {
display: flex;
justify-content: space-between;
align-items: flex-end;
width: 300px;
margin: 0 auto;
margin-bottom: 40px;
}
#main {
display:flex;
justify-content: center;
align-items: center;
}
.step {
text-align: center;
}
.step-text {
margin-bottom: 10px;
color: #28a745;
}
.bullet {
border: 1px solid #28a745;
height: 20px;
width: 20px;
border-radius: 100%;
color: #28a745;
display: inline-block;
position: relative;
transition: background-color 500ms;
line-height:20px;
}
.bullet.completed {
color: white;
background-color: #28a745;
}
.bullet.completed::after {
content: '';
position: absolute;
right: -60px;
bottom: 10px;
height: 1px;
width: 54px;
background-color: #28a745;
}
/* Base styles and helper stuff */
.hidden {
display: none;
}
button {
padding: 5px 10px;
border: 1px solid black;
transition: 250ms background-color;
}
button:hover {
cursor: pointer;
background-color: black;
color: white;
}
button:disabled:hover {
opacity: 0.6;
cursor: not-allowed;
}
.text-center {
text-align: center;
}
.container {
max-width: 400px;
margin: 0 auto;
margin-top: 20px;
padding: 40px;
}

13
src/reportWebVitals.js Normal file
View File

@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

5
src/setupTests.js Normal file
View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

60
src/stepper.css Normal file
View File

@ -0,0 +1,60 @@
*, *:after, *:before { margin:0; padding:0; }
body {
font-family: Helvetica, sans-serif;
}
input[type="button"] {
margin-top: 20px;
}
.container{
margin-left:0px;
max-width: 100vw;
}
.relocheading{
font-family: Ubuntu;
text-align: left;
color: #66bfbf !important;
margin-top: 0px;
}
ul{
text-align: left;
}
.node {
height: 12px;
width: 12px;
border-radius: 100%;
display:inline-block;
transition: all 1000ms ease;
}
.activated {
box-shadow: 0px 0px 0px 0px rgba(194, 255, 194, 0.8);
}
.divider {
height: 86px;
width: 2px;
margin-left: 4px;
transition: all 800ms ease;
}
p {
margin-bottom: 0rem;
}
li p {
display:inline-block;
margin-left: 25px;
}
li {
list-style: none;
line-height: 1px;
}
.blue { background-color: rgba(82, 165, 255, 1); }
.green{ background-color: rgba(92, 184, 92, 1) }
.red { background-color: rgba(255, 148, 148, 1); }
.grey { background-color: rgba(201, 201, 201, 1); }

53
src/tracking.css Normal file
View File

@ -0,0 +1,53 @@
*, *:after, *:before { margin:0; padding:0; }
.wrapper{
max-width: 400px;
margin: 0 auto;
margin-top: 20px;
padding: 40px;
}
.stepProgressBar {
display: flex;
justify-content: space-between;
align-items: flex-start;
width: 300px;
margin: 0 auto;
margin-bottom: 40px;
}
li{
list-style-type: none;
}
.node {
border: 1px solid #28a745;
height: 20px;
width: 20px;
border-radius: 100%;
color: #28a745;
display: inline-block;
position: relative;
transition: background-color 500ms;
line-height:20px;
}
.node.completed {
content: "";
color: white;
background-color: #28a745;
}
.node.completed::after {
content: "";
position: absolute;
height: 1px;
width: 54px;
background-color: #28a745;
}
.divider.completed::after{
list-style-type: none;
background-color: grey;
position: relative;
height: 80px;
width: 2px;
margin-left: 134px;
transition: all 800ms ease;
}