diff --git a/.codio b/.codio new file mode 100644 index 0000000..53a40d7 --- /dev/null +++ b/.codio @@ -0,0 +1,7 @@ + +{ + "preview": { + "Live Website": "https://{{domain8080}}/{{index}}", + "Heroku Local": "https://{{domain5000}}/{{index}}" + } +} diff --git a/.githooks/README.md b/.githooks/README.md new file mode 100755 index 0000000..b7bfb2f --- /dev/null +++ b/.githooks/README.md @@ -0,0 +1,4 @@ + +# You Need to Add Your Hooks + +They need to be in this directory. diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..c4711fe --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: deno run --allow-all --unstable index.js --port=${PORT} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fee1633 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ + +# Getting Started + +This template is designed to be installed inside a Codio box. To to this, open the terminal and run the following command: + +``` +$ curl -sL https://bit.ly/3yKYBTg | bash +``` + +This will configure the box ready for you to start development. + +> The process can take up to 15 min. Make sure you don't close the browser tab _or let your computer go into sleep mode_. + +To run the server: + +```shell +$ deno run --allow-all --unstable index.js +``` + +The website database has been added with a root password of `p455w0rd` and a single **accounts** table which is pre-configured with a single account: + +username: `doej` + +password: `p455w0rd` + +There is a secure page called **Foo Bar** which can be accessed at the `/foo` route. You will need to delete this and replace with your own secure content. + +# Support Videos + +https://youtu.be/X38dYaNH-HA + +https://youtu.be/gdvKwBpNU7A + +## Pushing to GitHub + +If you can't push to the University GitHub server (you are not prompted for the username/password and the connection times out) please run the following command which will print the Codio box external IP address and send this to your module leader. + +``` +$ dig +short myip.opendns.com @resolver1.opendns.com +``` diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..f790f53 --- /dev/null +++ b/deno.json @@ -0,0 +1,96 @@ +{ + "lint": { + "files": { + "exclude": ["tmp/", "stats.js", "spa/"] + }, + "rules": { + "tags": ["recommended"], + "include": [ + "ban-untagged-todo", + "camelcase", + "constructor-super", + "default-param-last", + "eqeqeq", + "for-direction", + "getter-return", + "no-array-constructor", + "no-async-promise-executor", + "no-await-in-loop", + "no-class-assign", + "no-compare-neg-zero", + "no-cond-assign", + "no-const-assign", + "no-constant-condition", + "no-control-regex", + "no-delete-var", + "no-deprecated-deno-api", + "no-dupe-args", + "no-dupe-class-members", + "no-dupe-else-if", + "no-dupe-keys", + "no-duplicate-case", + "no-empty", + "no-empty-character-class", + "no-empty-enum", + "no-empty-interface", + "no-empty-pattern", + "no-eval", + "no-ex-assign", + "no-explicit-any", + "no-extra-boolean-cast", + "no-extra-non-null-assertion", + "no-extra-semi", + "no-fallthrough", + "no-func-assign", + "no-global-assign", + "no-import-assign", + "no-inferrable-types", + "no-inner-declarations", + "no-invalid-regexp", + "no-invalid-triple-slash-reference", + "no-irregular-whitespace", + "no-misused-new", + "no-namespace", + "no-new-symbol", + "no-obj-calls", + "no-octal", + "no-prototype-builtins", + "no-redeclare", + "no-regex-spaces", + "no-self-assign", + "no-setter-return", + "no-shadow-restricted-names", + "no-this-alias", + "no-this-before-super", + "no-undef", + "no-unreachable", + "no-unsafe-finally", + "no-unsafe-negation", + "no-unused-labels", + "no-unused-vars", + "no-var", + "no-window-prefix", + "no-with", + "prefer-as-const", + "prefer-ascii", + "prefer-const", + "prefer-namespace-keyword", + "require-await", + "require-yield", + "use-isnan" + ] + } + }, + "fmt": { + "files": { + "exclude": ["tmp/", "stats.js"] + }, + "options": { + "useTabs": true, + "lineWidth": 80, + "indentWidth": 2, + "singleQuote": true, + "proseWrap": "preserve" + } + } +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..c00e2c8 --- /dev/null +++ b/index.js @@ -0,0 +1,58 @@ + +/* index.js */ + +import { Application } from 'https://deno.land/x/oak@v6.5.1/mod.ts' +import { Handlebars } from 'https://deno.land/x/handlebars/mod.ts' +import { parse } from 'https://deno.land/std/flags/mod.ts' + +import router from './routes.js' + +const defaultPort = 8080 +const { args } = Deno +const argPort = parse(args).port +const port = argPort ? Number(argPort) : defaultPort + +const app = new Application() +const handle = new Handlebars({ defaultLayout: '' }) + +// error handler +app.use(async (context, next) => { + try { + console.log(context.request.url.href) + console.log(`authorised cookie: ${context.cookies.get('authorised')}`) + await next() + } catch (err) { + console.log(err) + } +}) + +app.use(router.routes()) +app.use(router.allowedMethods()) + +// static content +app.use(async (context, next) => { + const root = `${Deno.cwd()}/public` + try { + await context.send({ root }) + } catch { + next() + } +}) + +// page not found +app.use( async context => { + try { + console.log('404 PAGE NOT FOUND') + const body = await handle.renderView('404') + context.response.body = body +// context.response.body = '404 PAGE NOT FOUND' + } catch(err) { + console.error(err) + } +}) + +app.addEventListener('listen', ({ port }) => { + console.log(`listening on port: ${port}`) +}) + +await app.listen({ port }) diff --git a/modules/accounts.js b/modules/accounts.js new file mode 100644 index 0000000..289abbe --- /dev/null +++ b/modules/accounts.js @@ -0,0 +1,29 @@ + +/* accounts.js */ + +import { compare, genSalt, hash } from 'https://deno.land/x/bcrypt@v0.2.4/mod.ts' + +import { db } from './db.js' + +const saltRounds = 10 +const salt = await genSalt(saltRounds) + +export async function login(data) { + console.log(data) + let sql = `SELECT count(id) AS count FROM accounts WHERE user="${data.username}";` + let records = await db.query(sql) + if(!records[0].count) throw new Error(`username "${data.username}" not found`) + sql = `SELECT pass FROM accounts WHERE user = "${data.username}";` + records = await db.query(sql) + const valid = await compare(data.password, records[0].pass) + if(valid === false) throw new Error(`invalid password for account "${data.username}"`) + return data.username +} + +export async function register(data) { + const password = await hash(data.password, salt) + const sql = `INSERT INTO accounts(user, pass) VALUES("${data.username}", "${password}")` + console.log(sql) + await db.query(sql) + return true +} diff --git a/modules/calculator.js b/modules/calculator.js new file mode 100644 index 0000000..20f4f02 --- /dev/null +++ b/modules/calculator.js @@ -0,0 +1,52 @@ + +/* calculator.js */ + +import { db } from './db.js' + +export async function getMortgageOptions(data) { + + let sql = `SELECT * FROM mortgageOptions where addedBy = "${data}";` + let records = await db.query(sql) + + return records; +} +export async function getFinancialData(data) { + + let sql = `SELECT * FROM FinancialData where user = "${data}";` + let records = await db.query(sql) + + return records; +} + +export async function saveOptions(data) { + + + const sql = `INSERT INTO mortgageOptions(totalAmount, amounttoDeposit, Years , +totalAmountwithIntrestRate,monthlyMortgage , addedBy ) +VALUES(${data.planamount * 1}, ${data.plandeposit * 1}, ${ data.years * 1 } , ${data.totalAmount * 1}, ${data.monthlyAmount * 1}, "${data.addedBy}" )` + console.log(sql) + await db.query(sql) + return true +} + +export async function deleteOption(data) { + + + const sql = `DELETE FROM mortgageOptions WHERE id = ${+data.optionId};` + console.log(sql) + await db.query(sql) + return true +} + +export async function addFinancialData(data) { + +// const sql = `UPDATE mortgageOptions SET monthlyWage = ${+data.Monthlywage} , monthlyOutgoing = ${+data.montlyOutgoings} , monthlyRent = ${+data.monthlyRent} WHERE addedBy = "${data.authorised}";` +// await db.query(sql) + + const sql2 = `INSERT INTO FinancialData(user, monthlyWage, monthlyOutgoing , monthlyRent,wageLeft , amountToDeposit, amounttoBorrow ) +VALUES("${data.authorised}", ${data.Monthlywage}, ${ data.montlyOutgoings } , ${data.monthlyRent}, +${(data.Monthlywage - data.montlyOutgoings) - data.monthlyRent }, ${data.monthlyAmount} , ${data.totalAmount} )`; + console.log(sql2) + await db.query(sql2) + return true +} diff --git a/modules/db.js b/modules/db.js new file mode 100644 index 0000000..83821ee --- /dev/null +++ b/modules/db.js @@ -0,0 +1,29 @@ + +/* db.js */ + +import { Client } from 'https://deno.land/x/mysql/mod.ts' + +const home = Deno.env.get('HOME') +console.log(`HOME: ${home}`) + +const connectionData = { + '/home/codio': { + hostname: '127.0.0.1', + username: 'websiteuser', + password: 'websitepassword', + db: 'website' + }, + '/app': { + hostname: 'HOSTNAME', + username: 'USERNAME', + password: 'PASSWORD', + db: 'DATABASE' + } +} + +const conn = connectionData[home] +console.log(conn) + +const db = await new Client().connect(conn) + +export { db } diff --git a/public/form.css b/public/form.css new file mode 100644 index 0000000..a285c1d --- /dev/null +++ b/public/form.css @@ -0,0 +1,4 @@ +form { + width: 40%; + margin: 0 auto; +} diff --git a/public/images/Banner.jpeg b/public/images/Banner.jpeg new file mode 100644 index 0000000..95aa193 Binary files /dev/null and b/public/images/Banner.jpeg differ diff --git a/public/images/home.png b/public/images/home.png new file mode 100644 index 0000000..f7698bf Binary files /dev/null and b/public/images/home.png differ diff --git a/public/images/logo.jpeg b/public/images/logo.jpeg new file mode 100644 index 0000000..b4f353a Binary files /dev/null and b/public/images/logo.jpeg differ diff --git a/public/main.js b/public/main.js new file mode 100644 index 0000000..c91e6dd --- /dev/null +++ b/public/main.js @@ -0,0 +1,10 @@ + +/* main.js */ + +// deno-lint-ignore-file + +import { file2DataURI } from './util.js' + +window.addEventListener('DOMContentLoaded', () => { + console.log('DOMContentLoaded') +}) diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..6d1baa0 --- /dev/null +++ b/public/style.css @@ -0,0 +1,392 @@ + +body { + font-family: Arial, Helvetica, sans-serif; + margin: 0; + } +h1, h2, h3 { + margin: 0; + padding: 0; + color: #444; +} +/* formats the red message boxes */ +aside { + max-width: 500px; + margin: auto; + background-color: yellow; +} +.msg { + border: 1px solid red; + font-weight: bold; + background-color: white; + color: red; + padding: 1em; + margin: 2em; + position: fixed; + top: 2em; +} + +header { +/* background-color: #0d6efd; */ + border-bottom: 5px solid #0d6efd; + height: 8vw; + + display: flex; + justify-content: space-between; + align-items: center; + +} + +header h1 { + color: #272727 !important; +} + + +h1 { + padding: 2.6vw; + float: left; + font-size: 3vw; + margin-left: 6vw; +} + +h2 { + font-size: 2.5vw; + margin: 1vw; + margin-left: 0.6vw; +} + +h3 { + font-size: 2vw; + margin: 1vw; + margin-left: 0.6vw; +} + +header > a { +/* margin-top: 3vw; */ + margin-right: 3vw; + float: right; + font-size: 1.3vw; +} +header > a { + border: 1px solid #272727; + padding: 6px 10px; + + color: #272727; + border-radius: 3px; + text-decoration: none; + +} +header > img { + width: 7vw; + border-radius: 50%; + height: 40px; + width: 50px; +} + +header nav ul { + display: flex; + list-style-type: none; +} + +header nav ul li { + margin-right: 20px +} +header nav ul li a { + text-decoration: none; + color: #272727; + text-transform: uppercase; + +} + +p, legend { + font-size: 1.5vw; +} + +main { + max-width: 90%; + margin: auto; + margin-top: 1em; + padding: 2em; + box-sizing: border-box; +/* background-color: lightgray; */ +} + +article { + width: 50vw; + /* background-color: grey; + float: left; */ +} + +aside { + /* background-color: yellow; + float: right; */ + width: 50vw; +} + +main a { +background-color: #0d6efd; + border: 2px solid #0d6efd; + color: white; + padding: 0.4vw 0.8vw; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 1.5vw; + border-radius: 2px; +} + +main a:hover { +color: #fff; + background-color: #0b5ed7; + border-color: #0a58ca; +} + +section { + background-color: #DDD; + width: 24vw; + margin-top: 1vw; + padding: 1vw; + border-radius: 1vw; +} + +section > p { + margin: 0; + padding: 0; + margin-bottom: 0.5vw; +} + +section > h3 { + margin: 0; + padding: 0; + font-size: 1.8vw; +} + +small { + display: block; + text-align: right; +} + +/* ===== FORMS ===== */ +main form { + border: 1px solid #272727; + padding: 30px 20px; + border-radius: 5px; +} +main form img { + text-align: center; + margin-left: auto; + width: 40px; + height: 40px; + + display: block; + margin: 0 auto; +} + + +fieldset { + position: relative; + width: 25vw; + border: 1px solid #CCC; + padding-top: 4vw; +} + +legend { + position:absolute; + top:0; + left:0; + width: 25.5vw; + background-color: #ccc; + border-bottom: 5px solid grey; + padding: 0.6vw; +} + +input, textarea { + box-sizing: border-box; +} + +input:focus { + outline:none; +} + +/* input[type="file"] { + display: none; +} */ + +input[type="submit"], label[for="avatar"], button, body > a, .custom-file-upload { + background-color: #0d6efd; + border: 2px solid #0d6efd; + color: white; + padding: 0.4vw 0.8vw; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 1.5vw; + border-radius: 2px; +} + + + +input[type="submit"]:hover, label[for="avatar"]:hover, .custom-file-upload:hover, .add:hover { + color: #fff; + background-color: #0b5ed7; + border-color: #0a58ca +} + +input[type="text"], input[type="email"], input[type="password"], input[type="tel"], textarea, select { + font-size: 1.5vw; + width: 100%; + border: 1px solid #272727; + padding: 0.5vw; + /* margin-bottom: 1vw; */ + border-radius: 5px; + height: 45px; +} + +textarea { + height: 10vw; + resize: none; +} + +input:required, textarea:required { + border-width: 2px; +} + +input:invalid, textarea:invalid { + border-color: red; +} +input:valid, textarea:valid { + border-color: ##272727; +} + + +select { + width: 26.3vw; + -webkit-appearance: none; + -webkit-border-radius: 0px; +} + +form > br { + line-height: 3vw; +} + + + +dl { + width: 35vw; + overflow: hidden; + /* background: #ff0; */ + padding: 0; + margin: 0; + font-size: 1.5vw; +} +dt { + float: left; + width: 10.5vw; + /* adjust the width; make sure the total of both is 100% */ + /* background: #cc0; */ + padding: 0.5vw; + margin: 0 +} +dd { + float: left; + width: 21vw; + /* adjust the width; make sure the total of both is 100% */ + /* background: #dd0; */ + padding: 0.5vw; + margin: 0 +} + +/* ===== TABLES ===== */ + +table { + border-collapse: collapse; + margin: auto; +} + +table img { + width: 100px; +} + +tr:nth-child(odd) { + background: #DDD; +} + +td, th { + /* border: 1px solid grey; */ + padding: 0.5vw; + font-size: 1.5vw; + text-align: left; +} + +td:last-child, th:last-child { + text-align: right; +} + +table td form { + padding: 0px; + border: none; +} +main table { + width: 100%; +} + +/* ===== ADD BUTTON ===== */ + +button#add { + display: block; + position: fixed; + bottom: 1em; + right: 1em; + z-index: 5; + background-color: grey; + color: white; + font-size: 5em; + width: 1.2em; + block-size: border-box; + border-radius: 2em; + border: none; + cursor: pointer; +} + +.add { + display: block; + position: fixed; + bottom: 1em; + right: 1em; + z-index: 5; + padding: 1em; +} + +button#add:hover { + background-color: white; + color: grey; +} + +input[type="file"] { + display: none; +} + +table tr th , td { + font-size: 20px; +} + +table tr td form button { + padding: 6px 20px; + color: #fff; + background-color: #dc3545; + border: 1px solid #dc3545; + margin-bottom: 2px; + text-decoration: none; + height: 90%; +} +div img { + width: 100%; + height:100%; +} + +div ul { + list-style-type: none; +} +div iframe { + width: 50%; + height: 400px; +} \ No newline at end of file diff --git a/public/uploads/README.md b/public/uploads/README.md new file mode 100644 index 0000000..ae95dc3 --- /dev/null +++ b/public/uploads/README.md @@ -0,0 +1,4 @@ + +# Uploads Directory + +This is where any uploaded files will be stored. diff --git a/public/util.js b/public/util.js new file mode 100644 index 0000000..98da03b --- /dev/null +++ b/public/util.js @@ -0,0 +1,16 @@ + +/* util.js */ + +export function file2DataURI(file) { + return new Promise((resolve, reject) => { + try { + const reader = new FileReader() + reader.onload = () => { + resolve(reader.result) + } + reader.readAsDataURL(file) + } catch(err) { + reject(err) + } + }) +} diff --git a/routes.js b/routes.js new file mode 100644 index 0000000..3a0cdd2 --- /dev/null +++ b/routes.js @@ -0,0 +1,170 @@ + +/* routes.js */ + +import { Router } from 'https://deno.land/x/oak@v6.5.1/mod.ts' +import { Handlebars } from 'https://deno.land/x/handlebars/mod.ts' +// import { upload } from 'https://cdn.deno.land/oak_upload_middleware/versions/v2/raw/mod.ts' +// import { parse } from 'https://deno.land/std/flags/mod.ts' + +import { login, register } from './modules/accounts.js'; +import { saveOptions , getMortgageOptions , getFinancialData, deleteOption , addFinancialData } from './modules/calculator.js'; + +const handle = new Handlebars({ defaultLayout: '' }) + +const router = new Router() + +// the routes defined here +router.get('/', async context => { + const authorised = context.cookies.get('authorised') + + const listofOptions = await getMortgageOptions(authorised); + + const data = { authorised, + Options : listofOptions} + const body = await handle.renderView('home', data) + context.response.body = body +}); + +router.get('/fincialData', async context => { + const authorised = context.cookies.get('authorised') + + const listofOptions = await getFinancialData(authorised); + + const data = { authorised, + Options : listofOptions}; + console.log(data) + const body = await handle.renderView('FinancialData', data) + context.response.body = body + + +}); + + +router.get('/contactus', async context => { + const authorised = context.cookies.get('authorised') + + const data = { authorised} + + const body = await handle.renderView('contact', data) + context.response.body = body +}); + +router.get('/aboutus', async context => { + const authorised = context.cookies.get('authorised') + + const data = { authorised} + + const body = await handle.renderView('about', data) + context.response.body = body +}); + +router.get('/login', async context => { + const body = await handle.renderView('login') + context.response.body = body +}) + +router.get('/deleteOption', async context => { + const body = await handle.renderView('removeOption') + context.response.body = body +}) + +router.get('/register', async context => { + const body = await handle.renderView('register') + context.response.body = body +}) + +router.get('/addm', async context => { + const authorised = context.cookies.get('authorised') + + const listofOptions = await getMortgageOptions(authorised); + console.log(listofOptions) + const data = { authorised, + Options : listofOptions} + const body = await handle.renderView('addm', data) + context.response.body = body + + +}) + +router.post('/register', async context => { + console.log('POST /register') + const body = context.request.body({ type: 'form' }) + const value = await body.value + const obj = Object.fromEntries(value) + console.log(obj) + await register(obj) + context.response.redirect('/login') +}) + +router.get('/logout', context => { + // context.cookies.set('authorised', null) // this does the same + context.cookies.delete('authorised') + context.response.redirect('/') +}) + +router.post('/login', async context => { + console.log('POST /login') + const body = context.request.body({ type: 'form' }) + const value = await body.value + const obj = Object.fromEntries(value) + console.log(obj) + try { + const username = await login(obj) + context.cookies.set('authorised', username) + context.response.redirect('/') + } catch(err) { + console.log(err) + context.response.redirect('/login') + } +}) +// saving the option +router.post('/addOption', async context => { + const authorised = context.cookies.get('authorised'); + console.log(authorised) + const body = context.request.body({ type: 'form' }) + const value = await body.value + const obj = Object.fromEntries(value) + + + await saveOptions( + {...obj, + addedBy: authorised + }) +context.response.redirect('/') +}) + + + +router.post('/FinancialData', async context => { + const authorised = context.cookies.get('authorised'); + + const body = context.request.body({ type: 'form' }) + const value = await body.value + const obj = Object.fromEntries(value) + + await addFinancialData( + {...obj, + authorised + }) +context.response.redirect('/') +}) +// delete the option +router.post('/deleteOption', async context => { + + const body = context.request.body({ type: 'form' }) + const value = await body.value + const obj = Object.fromEntries(value) + console.log(obj); + console.log("--------------") + await deleteOption(obj) +context.response.redirect('/') +}) +router.get('/foo', async context => { + const authorised = context.cookies.get('authorised') + if(authorised === undefined) context.response.redirect('/') + const data = { authorised } + const body = await handle.renderView('foo', data) + context.response.body = body +}) + +export default router diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 0000000..6c4fc20 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +v1.7.1 \ No newline at end of file diff --git a/setup.sql b/setup.sql new file mode 100644 index 0000000..63f615d --- /dev/null +++ b/setup.sql @@ -0,0 +1,18 @@ + +-- make sure the websiteuser account is set up and has the correct privileges +CREATE USER IF NOT EXISTS websiteuser IDENTIFIED BY 'websitepassword'; +GRANT INSERT, SELECT, UPDATE, DELETE ON website.* TO websiteuser; + +DROP TABLE IF EXISTS accounts; + +CREATE TABLE IF NOT EXISTS accounts ( + id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + user VARCHAR(25) NOT NULL, + pass VARCHAR(70) NOT NULL +); + +INSERT INTO accounts(user, pass) + VALUES("doej", "$2b$10$gL33obKAFUT5DK3pEbh72OIHztsWBniBBh.PdeKOrF1yr5KFAsdZO"); + + + diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..d680d30 --- /dev/null +++ b/test.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +type=${CODIO_TYPE:-assignment} +echo type + +if [ $type = "lab" ]; +then + echo "YOU ARE TRYING TO RUN THIS IN A CODIO LAB" + echo "script should only be run in your assignment box" + exit 1 +fi + +echo "script running" diff --git a/tmp/README.md b/tmp/README.md new file mode 100644 index 0000000..74ce36a --- /dev/null +++ b/tmp/README.md @@ -0,0 +1,4 @@ + +# Temporary Files + +This is where the OS will store any temporary files. diff --git a/views/404.hbs b/views/404.hbs new file mode 100644 index 0000000..a190393 --- /dev/null +++ b/views/404.hbs @@ -0,0 +1,21 @@ + + + + + + + Home Page + + + + + + +
+

404

+
+
+

PAGE NOT FOUND

+
+ + diff --git a/views/FinancialData.hbs b/views/FinancialData.hbs new file mode 100644 index 0000000..7fd0f3d --- /dev/null +++ b/views/FinancialData.hbs @@ -0,0 +1,145 @@ + + + + + + + Home Page + + + + + + +
+ + + + + + {{#if authorised}} + Log out + {{else}} + Log in + {{/if}} +
+
+

Financial Data

+
+ + +
+
+
+ + + +
+
+ + + +
+
+ + + +

+ + +

+ + +

+ + + +
+
+ +
+ + + {{#if authorised}} + + {{#if Options}} + + +
+
+
+ + + + + + + + + + {{#each Options}} + + + + + + + + + + + + {{/each}} + + {{else}} +
+ There is no option saved. + {{/if}} + + + {{else}} + + + + {{/if}} + + + + diff --git a/views/about.hbs b/views/about.hbs new file mode 100644 index 0000000..10633c8 --- /dev/null +++ b/views/about.hbs @@ -0,0 +1,50 @@ + + + + + + + Home Page + + + + + + +
+ + + + + {{#if authorised}} + Log out + {{else}} + Log in + {{/if}} +
+
+

ABOUT US

+ +
+ + Vission +
+

A mortgage company is a specialized financial firm engaged in the business of originating and/or funding mortgages for residential or commercial property. A mortgage company is often just the originator of a loan; it markets itself to potential borrowers and seeks funding from one of several client financial institutions that provide the capital for the mortgage itself.

+ + + + +
+
+ + diff --git a/views/addm.hbs b/views/addm.hbs new file mode 100644 index 0000000..5d99d3e --- /dev/null +++ b/views/addm.hbs @@ -0,0 +1,251 @@ + + + + + + + Home Page + + + + + + +
+ + + + + {{#if authorised}} + Log out + {{else}} + Log in + {{/if}} +
+
+

Mortgate Calculator

+
+ + +
+ + + +
+
+ + +
+
+ + +

+ +

+ + +

0.0

+
+
+ + + + + {{#if authorised}} + + {{#if Options}} + + +
+
+
+
Monthly WageMonthly Outgoings AmountMonthly RentWage LeftAmount To BorrowAmount To Deposit
{{monthlyWage}} £{{monthlyOutgoing}} £{{monthlyRent}} £{{wageLeft}} £{{amountToDeposit}} £{{amounttoBorrow}} £
+ + + + + + + + + {{#each Options}} + + + + + + + + + + + {{/each}} + + {{else}} + + +
+
+
+ + There is no option saved. + {{/if}} + + + {{else}} + + + + {{/if}} + + + + diff --git a/views/contact.hbs b/views/contact.hbs new file mode 100644 index 0000000..2939b71 --- /dev/null +++ b/views/contact.hbs @@ -0,0 +1,54 @@ + + + + + + + Home Page + + + + + + +
+ + + + + {{#if authorised}} + Log out + {{else}} + Log in + {{/if}} +
+
+

CONTACT US

+ +
+

We're on hand to arrange a phone or video call with one of our qualified mortgage professionals.

+

Call Us on +37062652903

+ Opening Hours +
    + +
  • Mon-Fri 8am-6pm
  • +
  • Sat 9am-4pm
  • +
  • Sun Closed
  • +
  • Excluding Public Holidays
  • +
+ + +
+
+ + diff --git a/views/foo.hbs b/views/foo.hbs new file mode 100644 index 0000000..085f091 --- /dev/null +++ b/views/foo.hbs @@ -0,0 +1,25 @@ + + + + + + + Home Page + + + + + + +
+

Foo Bar

+ Log out +
+
+ {{#if auth}} +

Logged in as {{auth}}

+ {{/if}} +

Home page

+
+ + diff --git a/views/home.hbs b/views/home.hbs new file mode 100644 index 0000000..850d16f --- /dev/null +++ b/views/home.hbs @@ -0,0 +1,48 @@ + + + + + + + Home Page + + + + + + +
+ + + + + {{#if authorised}} + Log out + {{else}} + Log in + {{/if}} +
+
+ +
+ +
+ + +
+ + + diff --git a/views/layouts/README.md b/views/layouts/README.md new file mode 100644 index 0000000..a5d82ab --- /dev/null +++ b/views/layouts/README.md @@ -0,0 +1,2 @@ + +# There needs to be a file here to ensure that the directory is created. diff --git a/views/login.hbs b/views/login.hbs new file mode 100644 index 0000000..9f1cb88 --- /dev/null +++ b/views/login.hbs @@ -0,0 +1,36 @@ + + + + + + + Log In + + + + + + + +
+ + Register +
+
+
+ + +

+
+ +

+

+
+ +

+

+ + +
+ + diff --git a/views/partials/README.md b/views/partials/README.md new file mode 100644 index 0000000..a5d82ab --- /dev/null +++ b/views/partials/README.md @@ -0,0 +1,2 @@ + +# There needs to be a file here to ensure that the directory is created. diff --git a/views/register.hbs b/views/register.hbs new file mode 100644 index 0000000..ee0e92d --- /dev/null +++ b/views/register.hbs @@ -0,0 +1,38 @@ + + + + + + + Create an Account + + + + + + + +
+ + Log in +
+
+
+ +

+
+ +

+

+
+ +

+

+
+ +

+

+ +
+ + diff --git a/views/removeOption.hbs b/views/removeOption.hbs new file mode 100644 index 0000000..85730ad --- /dev/null +++ b/views/removeOption.hbs @@ -0,0 +1,26 @@ + + + + + + + Home Page + + + + + + +
+

Home

+ {{#if authorised}} + Log out + {{else}} + Log in + {{/if}} +
+
+

Removing the option...

+
+ +
Planned AmountDeposite AmountMonthly MortgageYearsTotal Amount With Interest
{{totalAmount}} £{{amounttoDeposit}} £{{monthlyMortgage}} £{{Years}}{{totalAmountwithIntrestRate}} +
+ + + + + +
+