mirror of
https://github.com/LukasKanka/api_test.git
synced 2026-11-11 06:34:36 +01:00
cicd
This commit is contained in:
1 parent
207c50f51d
commit
e5c6276bab
55 files changed
+28732
No files matched your search
@@ -0,0 +1,39 @@
|
|||||||
|
name: Run Bruno API Tests
|
||||||
|
|
||||||
|
# Pipeline se spustí při každém pushnutí nebo Pull Requestu do hlavní větve
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main", "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main", "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# 1. Krok: Stáhne kód z repozitáře do virtuálního prostředí runneru
|
||||||
|
- name: Checkout repository code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# 2. Krok: Připraví prostředí Node.js (verze 20)
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
# 3. Krok: Nainstaluje závislosti v backendu a spustí ho na pozadí (&)
|
||||||
|
- name: Install dependencies and start Backend
|
||||||
|
run: |
|
||||||
|
cd web/backend
|
||||||
|
npm install
|
||||||
|
npm start &
|
||||||
|
|
||||||
|
# 4. Krok: Vyčká, až server naběhne a bude odpovídat na portu (upravte port podle potřeby, např. 3000)
|
||||||
|
- name: Wait for Backend server to be ready
|
||||||
|
run: npx wait-on http://localhost:3000
|
||||||
|
|
||||||
|
# 5. Krok: Spustí Bruno testy
|
||||||
|
# Pokud nepoužíváte environments, odeberte `--env název_prostředí`
|
||||||
|
- name: Run Bruno API Tests
|
||||||
|
run: npx @usebruno/cli run apiTest --recursive
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Secrets
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
info:
|
||||||
|
name: ShortingHat
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/sortingHat
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
runtime:
|
||||||
|
scripts:
|
||||||
|
- type: tests
|
||||||
|
code: |-
|
||||||
|
const status = res.getStatus()
|
||||||
|
const body = res.getBody()
|
||||||
|
|
||||||
|
test("Status code is 200", function() {
|
||||||
|
expect(status).to.equal(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Response should contain sortingHat key", function(){
|
||||||
|
expect(body).to.contain.key("sortingHatSays")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Message from sorting hat should not be empty", function(){
|
||||||
|
expect(res.getBody().sortingHatSays).not.to.be.empty
|
||||||
|
})
|
||||||
|
|
||||||
|
test("Message from house should not be empty", function(){
|
||||||
|
expect(res.getBody().house).not.to.be.empty
|
||||||
|
})
|
||||||
|
|
||||||
|
test("House is one of Gryffindor, Slytherin, Ravenclaw, Hufflepuff",function(){
|
||||||
|
expect(res.getBody().house).is.oneOf(["Gryffindor", "Slytherin", "Ravenclaw", "Hufflepuff" ])
|
||||||
|
})
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
|
forwardAuthorizationHeader: false
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
opencollection: 1.0.0
|
||||||
|
|
||||||
|
info:
|
||||||
|
name: PotterAPI
|
||||||
|
config:
|
||||||
|
proxy:
|
||||||
|
inherit: true
|
||||||
|
config:
|
||||||
|
protocol: http
|
||||||
|
hostname: ""
|
||||||
|
port: ""
|
||||||
|
auth:
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
bypassProxy: ""
|
||||||
|
|
||||||
|
request:
|
||||||
|
headers:
|
||||||
|
- name: localhost
|
||||||
|
value: http://localhost:3000/
|
||||||
|
bundled: false
|
||||||
|
extensions:
|
||||||
|
bruno:
|
||||||
|
ignore:
|
||||||
|
- node_modules
|
||||||
|
- .git
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/node,visualstudiocode
|
||||||
|
# Edit at https://www.gitignore.io/?templates=node,visualstudiocode
|
||||||
|
|
||||||
|
### Node ###
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# rollup.js default build output
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Uncomment the public line if your project uses Gatsby
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# https://create-react-app.dev/docs/using-the-public-folder/#docsNav
|
||||||
|
# public
|
||||||
|
|
||||||
|
# Storybook build outputs
|
||||||
|
.out
|
||||||
|
.storybook-out
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# Temporary folders
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/node,visualstudiocode
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FROM node:18
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD [ "node", "app.js" ]
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# PotterAPI
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
1. Installed [NodeJS](https://nodejs.org/en/)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. Open terminal and run following commands
|
||||||
|
```
|
||||||
|
git clone https://github.com/skarbala/PotterAPI.git
|
||||||
|
cd PotterAPI
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the API using
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ✅ You should see following message
|
||||||
|
> Harry Potter App listening on port 3000!
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
#### Base url
|
||||||
|
All routes needs to be send to base url `http://localhost:3000`
|
||||||
|
|
||||||
|
#### Response type
|
||||||
|
Default response format is `application/json`
|
||||||
|
|
||||||
|
### Spells service
|
||||||
|
#### Authentication
|
||||||
|
No authentication needed
|
||||||
|
#### Available endpoints
|
||||||
|
``` GET /spells ``` returns list spells
|
||||||
|
|
||||||
|
``` GET /spells/{id} ``` returns specific spell.
|
||||||
|
|
||||||
|
``` DELETE /spells/{id} ``` deletes spell
|
||||||
|
|
||||||
|
```POST /spells``` adds new spell
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var basicAuth = require('express-basic-auth');
|
||||||
|
let jwt = require('jsonwebtoken');
|
||||||
|
var boolParser = require('express-query-boolean');
|
||||||
|
var cors = require('cors');
|
||||||
|
|
||||||
|
module.exports = verifyToken;
|
||||||
|
var app = express();
|
||||||
|
const port = 3000
|
||||||
|
|
||||||
|
app.use(express.json())
|
||||||
|
app.use(boolParser());
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
|
|
||||||
|
const spellRoute = require('./routes/spells.js');
|
||||||
|
app.use('/spells', spellRoute);
|
||||||
|
|
||||||
|
const houseRoute = require('./routes/houses.js');
|
||||||
|
app.use('/houses', houseRoute);
|
||||||
|
|
||||||
|
const characterRoute = require('./routes/characters.js');
|
||||||
|
app.use('/characters', characterRoute)
|
||||||
|
|
||||||
|
const sortingHatRoute = require('./routes/sortinghat.js');
|
||||||
|
app.use('/sortingHat', sortingHatRoute);
|
||||||
|
|
||||||
|
const quote = require('./routes/quote.js');
|
||||||
|
app.use('/quote', quote);
|
||||||
|
|
||||||
|
app.get('/login', basicAuth({
|
||||||
|
users: { 'admin': 'supersecret' },
|
||||||
|
}), (req, res) => {
|
||||||
|
const user = {
|
||||||
|
username: 'furboslav',
|
||||||
|
id: 5,
|
||||||
|
}
|
||||||
|
generateToken(user, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
generateToken = function (user, res) {
|
||||||
|
jwt.sign({ user: user }, 'secretkey', (err, token) => {
|
||||||
|
res.json({
|
||||||
|
token: token
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyToken(req, res, next) {
|
||||||
|
const bearerHeader = req.header('Authorization');
|
||||||
|
if (typeof bearerHeader !== 'undefined') {
|
||||||
|
const bearer = bearerHeader.split(' ');
|
||||||
|
const bearerToken = bearer[1];
|
||||||
|
req.token = bearerToken;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(403)
|
||||||
|
res.json({
|
||||||
|
message: "Sorry Wizard you dont have TOKEN"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.listen(port, () => console.log(`Harry Potter App listening on port ${port}!`))
|
||||||
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,14 @@
|
|||||||
|
const houses = require('../houses.json');
|
||||||
|
|
||||||
|
exports.houses_list = function (req, res) {
|
||||||
|
res.json(houses);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.specific_house = function (req, res) {
|
||||||
|
let result = houses.find(house => house.id == req.params.houseId);
|
||||||
|
if (typeof result == 'undefined') {
|
||||||
|
res.status(404)
|
||||||
|
res.send({ message: "House not found" });
|
||||||
|
}
|
||||||
|
res.send(result);
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
var spells = require('../spells.json');
|
||||||
|
const joi = require('joi');
|
||||||
|
const initialSpells = require('../spells.json');
|
||||||
|
const schema = joi.object().keys({
|
||||||
|
spell: joi.string().min(3).max(30).required().regex(/^\w+(?:\s+\w+)*$/),
|
||||||
|
type: joi.string().valid('Charm', 'Enchantment', 'Curse', 'Spell', 'Hex', 'Jinx'),
|
||||||
|
effect: joi.string().min(4),
|
||||||
|
isUnforgivable: joi.boolean().required(),
|
||||||
|
id: joi.any()
|
||||||
|
});
|
||||||
|
|
||||||
|
const randomId = require('random-id');
|
||||||
|
|
||||||
|
exports.spells_list = function (req, res) {
|
||||||
|
let result = spells;
|
||||||
|
if (typeof req.query.type !== 'undefined') {
|
||||||
|
result = spells.filter(spell => spell.type == req.query.type)
|
||||||
|
}
|
||||||
|
if (typeof req.query.isUnforgivable !== 'undefined') {
|
||||||
|
result = result.filter(spell => spell.isUnforgivable == req.query.isUnforgivable)
|
||||||
|
}
|
||||||
|
if (typeof req.query.limit !== 'undefined') {
|
||||||
|
result = result.slice(0, req.query.limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
return res.json(result);
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
exports.delete_all = function (req, res) {
|
||||||
|
spells = [];
|
||||||
|
res.send({ message: 'Mischief managed' })
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.reset = function (req, res) {
|
||||||
|
spells = initialSpells.slice(0);
|
||||||
|
res.send({ message: 'Aparecium', spells: spells })
|
||||||
|
}
|
||||||
|
exports.specific_spell = function (req, res) {
|
||||||
|
let result = spells.find(spell => spell.id == req.params.spellId);
|
||||||
|
if (typeof result !== 'undefined') {
|
||||||
|
return res.send(result);
|
||||||
|
}
|
||||||
|
return res.status(404).send({ message: "Spell not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.delete_spell = function (req, res) {
|
||||||
|
let result = spells.find(spell => spell.id == req.params.spellId);
|
||||||
|
if (typeof result == 'undefined') {
|
||||||
|
return res.status(404).send({ message: "Spell not found" });
|
||||||
|
}
|
||||||
|
spells = spells.filter(spell => spell.id != req.params.spellId);
|
||||||
|
return res.send({
|
||||||
|
message: 'spell deleted'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.update_spell = function (req, res) {
|
||||||
|
let result = spells.find(spell => spell.id == req.params.spellId);
|
||||||
|
if (typeof result == 'undefined') {
|
||||||
|
return res.status(404).send({ message: "Spell not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var newSpell = {
|
||||||
|
spell: req.body.spell,
|
||||||
|
type: req.body.type,
|
||||||
|
effect: req.body.effect,
|
||||||
|
isUnforgivable: req.body.isUnforgivable,
|
||||||
|
id: result.id
|
||||||
|
}
|
||||||
|
const validation = schema.validate(newSpell);
|
||||||
|
|
||||||
|
|
||||||
|
const { value, error } = validation;
|
||||||
|
const valid = error == null;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
return res.status(422).json({
|
||||||
|
message: 'Wizard, I\'m sory but your request is invalid',
|
||||||
|
data: error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
spells = spells.filter(spell => spell.id != req.params.spellId);
|
||||||
|
spells.push(newSpell);
|
||||||
|
return res.status(201).json({
|
||||||
|
message: "Spell updated",
|
||||||
|
spell: {
|
||||||
|
id: newSpell.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.new_spell = function (req, res) {
|
||||||
|
var len = 30;
|
||||||
|
var pattern = 'aA0'
|
||||||
|
|
||||||
|
var newSpell = {
|
||||||
|
spell: req.body.spell,
|
||||||
|
type: req.body.type,
|
||||||
|
effect: req.body.effect,
|
||||||
|
isUnforgivable: req.body.isUnforgivable,
|
||||||
|
id: randomId(len, pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = spells.find((spell) => spell.spell === newSpell.spell);
|
||||||
|
if (typeof result !== 'undefined') {
|
||||||
|
return res.status(400).send({
|
||||||
|
message: 'Spell ' + newSpell.spell + ' already exists'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const validation = schema.validate(newSpell);
|
||||||
|
|
||||||
|
const { value, error } = validation;
|
||||||
|
const valid = error == null;
|
||||||
|
if (!valid) {
|
||||||
|
return res.status(422).json({
|
||||||
|
message: 'Invalid request',
|
||||||
|
data: error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
spells.push(newSpell);
|
||||||
|
return res.status(201).json({
|
||||||
|
message: "Spell created",
|
||||||
|
spell: {
|
||||||
|
id: newSpell.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "5a05e2b252f721a3cf2ea33f",
|
||||||
|
"name": "Gryffindor",
|
||||||
|
"mascot": "lion",
|
||||||
|
"headOfHouse": "Minerva McGonagall",
|
||||||
|
"houseGhost": "Nearly Headless Nick",
|
||||||
|
"founder": "Goderic Gryffindor",
|
||||||
|
"school": "Hogwarts School of Witchcraft and Wizardry",
|
||||||
|
"members": [
|
||||||
|
"5a0fa648ae5bc100213c2332",
|
||||||
|
"5a0fa67dae5bc100213c2333",
|
||||||
|
"5a0fa7dcae5bc100213c2338",
|
||||||
|
"5a107e1ae0686c0021283b19",
|
||||||
|
"5a10944f3dc2080021cd8755",
|
||||||
|
"5a10947c3dc2080021cd8756",
|
||||||
|
"5a1096b33dc2080021cd8762",
|
||||||
|
"5a1097653dc2080021cd8763",
|
||||||
|
"5a1098fd3dc2080021cd876e",
|
||||||
|
"5a109af13dc2080021cd877a",
|
||||||
|
"5a109bfc3dc2080021cd877f",
|
||||||
|
"5a109c3d3dc2080021cd8780",
|
||||||
|
"5a109cb83dc2080021cd8784",
|
||||||
|
"5a109cd33dc2080021cd8785",
|
||||||
|
"5a109e143dc2080021cd878d",
|
||||||
|
"5a109e1e3dc2080021cd878e",
|
||||||
|
"5a109e253dc2080021cd878f",
|
||||||
|
"5a109e543dc2080021cd8790",
|
||||||
|
"5a109f053dc2080021cd8793",
|
||||||
|
"5a1226520f5ae10021650d76",
|
||||||
|
"5a1226d70f5ae10021650d77",
|
||||||
|
"5a12292a0f5ae10021650d7e",
|
||||||
|
"5a12298d0f5ae10021650d7f",
|
||||||
|
"5a1229e10f5ae10021650d80",
|
||||||
|
"5a122cbe0f5ae10021650d89",
|
||||||
|
"5a1233ff0f5ae10021650d98",
|
||||||
|
"5a1234cb0f5ae10021650d9b",
|
||||||
|
"5a1237480f5ae10021650da3",
|
||||||
|
"5a1237c00f5ae10021650da5",
|
||||||
|
"5a1238070f5ae10021650da6",
|
||||||
|
"5a1238350f5ae10021650da7",
|
||||||
|
"5a12387a0f5ae10021650da8",
|
||||||
|
"5a1238b20f5ae10021650da9",
|
||||||
|
"5a1239130f5ae10021650daa",
|
||||||
|
"5a12393d0f5ae10021650dab",
|
||||||
|
"5a12395f0f5ae10021650dac",
|
||||||
|
"5a1239c80f5ae10021650dad",
|
||||||
|
"5a1239f10f5ae10021650dae",
|
||||||
|
"5a123b450f5ae10021650db7",
|
||||||
|
"5a123f130f5ae10021650dcc"
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"courage",
|
||||||
|
"bravery",
|
||||||
|
"nerve",
|
||||||
|
"chivalry"
|
||||||
|
],
|
||||||
|
"colors": [
|
||||||
|
"scarlet",
|
||||||
|
"gold"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5a05da69d45bd0a11bd5e06f",
|
||||||
|
"name": "Ravenclaw",
|
||||||
|
"mascot": "eagle",
|
||||||
|
"headOfHouse": "Fillius Flitwick",
|
||||||
|
"houseGhost": "The Grey Lady",
|
||||||
|
"founder": "Rowena Ravenclaw",
|
||||||
|
"school": "Hogwarts School of Witchcraft and Wizardry",
|
||||||
|
"members": [
|
||||||
|
"5a0fa8a6ae5bc100213c233b",
|
||||||
|
"5a107ffee0686c0021283b21",
|
||||||
|
"5a108023e0686c0021283b22",
|
||||||
|
"5a108047e0686c0021283b23",
|
||||||
|
"5a1097d53dc2080021cd8769",
|
||||||
|
"5a1099cf3dc2080021cd8772",
|
||||||
|
"5a109a553dc2080021cd8777",
|
||||||
|
"5a109de83dc2080021cd878c",
|
||||||
|
"5a109e943dc2080021cd8791",
|
||||||
|
"5a109ebd3dc2080021cd8792",
|
||||||
|
"5a1225a20f5ae10021650d73",
|
||||||
|
"5a12260f0f5ae10021650d75",
|
||||||
|
"5a122a880f5ae10021650d82",
|
||||||
|
"5a122ac40f5ae10021650d83",
|
||||||
|
"5a122aef0f5ae10021650d84",
|
||||||
|
"5a12368a0f5ae10021650da0",
|
||||||
|
"5a123e450f5ae10021650dc8"
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"intelligence",
|
||||||
|
"creativity",
|
||||||
|
"learning",
|
||||||
|
"wit"
|
||||||
|
],
|
||||||
|
"colors": [
|
||||||
|
"blue",
|
||||||
|
" bronze"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5a05dc8cd45bd0a11bd5e071",
|
||||||
|
"name": "Slytherin",
|
||||||
|
"mascot": "serpent",
|
||||||
|
"headOfHouse": "Severus Snape",
|
||||||
|
"houseGhost": "The Bloody Baron",
|
||||||
|
"founder": "Salazar Slytherin",
|
||||||
|
"members": [
|
||||||
|
"5a0fa6bbae5bc100213c2334",
|
||||||
|
"5a0fa6e8ae5bc100213c2335",
|
||||||
|
"5a0fa74eae5bc100213c2336",
|
||||||
|
"5a0fa772ae5bc100213c2337",
|
||||||
|
"5a107e4ae0686c0021283b1a",
|
||||||
|
"5a1093eb3dc2080021cd8753",
|
||||||
|
"5a10942a3dc2080021cd8754",
|
||||||
|
"5a1099353dc2080021cd876f",
|
||||||
|
"5a109aa03dc2080021cd8779",
|
||||||
|
"5a109d893dc2080021cd8789",
|
||||||
|
"5a109d9f3dc2080021cd878a",
|
||||||
|
"5a109dab3dc2080021cd878b",
|
||||||
|
"5a109f8b3dc2080021cd8795",
|
||||||
|
"5a109fa83dc2080021cd8796",
|
||||||
|
"5a109fde3dc2080021cd8797",
|
||||||
|
"5a1225640f5ae10021650d72",
|
||||||
|
"5a1225e30f5ae10021650d74",
|
||||||
|
"5a122c200f5ae10021650d88",
|
||||||
|
"5a1232600f5ae10021650d93",
|
||||||
|
"5a12327c0f5ae10021650d94",
|
||||||
|
"5a1233bc0f5ae10021650d97",
|
||||||
|
"5a1235060f5ae10021650d9c",
|
||||||
|
"5a1236eb0f5ae10021650da1",
|
||||||
|
"5a123a710f5ae10021650db1",
|
||||||
|
"5a123af40f5ae10021650db5"
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"ambition",
|
||||||
|
"cunning",
|
||||||
|
"leadership",
|
||||||
|
"resourcefulness"
|
||||||
|
],
|
||||||
|
"colors": [
|
||||||
|
"green",
|
||||||
|
"silver"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5a05dc58d45bd0a11bd5e070",
|
||||||
|
"name": "Hufflepuff",
|
||||||
|
"mascot": "badger",
|
||||||
|
"headOfHouse": "Pomona Sprout",
|
||||||
|
"houseGhost": "The Fat Friar",
|
||||||
|
"founder": "Helga Hufflepuff",
|
||||||
|
"school": "Hogwarts School of Witchcraft and Wizardry",
|
||||||
|
"members": [
|
||||||
|
"5a0fa11a4d153d00212c47cc",
|
||||||
|
"5a0fa360ae5bc100213c232c",
|
||||||
|
"5a0fa365ae5bc100213c232d",
|
||||||
|
"5a0fa4daae5bc100213c232e",
|
||||||
|
"5a0fa842ae5bc100213c2339",
|
||||||
|
"5a0fa86dae5bc100213c233a",
|
||||||
|
"5a1096253dc2080021cd875f",
|
||||||
|
"5a1098bd3dc2080021cd876d",
|
||||||
|
"5a109c993dc2080021cd8783",
|
||||||
|
"5a1223720f5ae10021650d6f",
|
||||||
|
"5a1223ed0f5ae10021650d70",
|
||||||
|
"5a122f3d0f5ae10021650d8d",
|
||||||
|
"5a1232b10f5ae10021650d95",
|
||||||
|
"5a12333f0f5ae10021650d96",
|
||||||
|
"5a1234500f5ae10021650d99",
|
||||||
|
"5a1235790f5ae10021650d9d",
|
||||||
|
"5a123cb40f5ae10021650dbc"
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"hard work",
|
||||||
|
"patience",
|
||||||
|
"justice",
|
||||||
|
"loyalty"
|
||||||
|
],
|
||||||
|
"colors": [
|
||||||
|
"yellow",
|
||||||
|
"black"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
let jwt = require('jsonwebtoken');
|
||||||
|
module.exports = checkToken;
|
||||||
|
|
||||||
|
function checkToken(req, res, next) {
|
||||||
|
jwt.verify(req.token, 'secretkey', (err, authData) => {
|
||||||
|
if (err) {
|
||||||
|
res.status(403);
|
||||||
|
res.send(err);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
exports.checkHeader = (req, res, next) => {
|
||||||
|
if (!req.is('application/json')) {
|
||||||
|
res.status(400).send({ message: "Sorry Nick you dont have HEADer" });
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
let spells = require('../controllers/spellsController.js')
|
||||||
|
|
||||||
|
exports.spell_not_found = function (req, res, next) {
|
||||||
|
let result = spells.find(spell => spell._id == req.params.spellId);
|
||||||
|
if (typeof result == 'undefined') {
|
||||||
|
return res.status(404).send({ message: "Spell not found" });
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
Generated
+3263
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "PotterApi",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "nodemon app.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "18.x"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-basic-auth": "^1.2.0",
|
||||||
|
"express-query-boolean": "^2.0.0",
|
||||||
|
"joi": "^17.6.0",
|
||||||
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
"nodemon": "^2.0.2",
|
||||||
|
"random-id": "^1.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"quote": "Mr. and Mrs. Dursley of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much.",
|
||||||
|
"author": "unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I hope you're pleased with yourselves. We could all have been killed — or worse, expelled. Now if you don't mind, I'm going to bed.",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It does not do well to dwell on dreams and forget to live.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "To the well-organized mind, death is but the next great adventure.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You're a little scary sometimes, you know that? Brilliant ... but scary.",
|
||||||
|
"author": "Ron Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There will be no foolish wand-waving or silly incantations in this class. As such, I don't expect many of you to appreciate the subtle science and exact art that is potion-making. However, for those select few who possess the predisposition, I can teach you how to bewitch the mind and ensnare the senses. I can tell you how to bottle fame, brew glory, and even put a stopper in death. Then again, maybe some of you have come to Hogwarts in possession of abilities so formidable that you feel confident enough to not pay attention!",
|
||||||
|
"author": "Severus Snape"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It takes a great deal of bravery to stand up to our enemies, but just as much to stand up to our friends.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Yer a wizard Harry.",
|
||||||
|
"author": "Rubeus Hagrid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There are all kinds of courage. It takes a great deal of bravery to stand up to our enemies, but just as much to stand up to our friends.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The truth. It is a beautiful and terrible thing, and should therefore be treated with great caution.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There are some things you can’t share without ending up liking each other, and knocking out a twelve-foot mountain troll is one of them.",
|
||||||
|
"author": "unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Fear of a name only increases fear of the thing itself.",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Dobby is free.",
|
||||||
|
"author": "Dobby"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Training for the ballet, Potter?",
|
||||||
|
"author": "Draco Malfoy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I’ll be in my bedroom, making no noise and pretending I’m not there.",
|
||||||
|
"author": "Harry Potter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Hearing voices no one else can hear isn’t a good sign, even in the wizarding world.",
|
||||||
|
"author": "Ron Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "When in doubt, go to the library.",
|
||||||
|
"author": "Ron Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Fawkes is a phoenix, Harry. Phoenixes burst into flame when it is time for them to die and are reborn from the ashes.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Fame is a fickle friend, Harry. Celebrity is as celebrity does. Remember that.",
|
||||||
|
"author": "Gilderoy Lockhart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Honestly, if you were any slower, you’d be going backward.",
|
||||||
|
"author": "Draco Malfoy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I solemnly swear I am up to no good.",
|
||||||
|
"author": "Harry Potter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Honestly, am I the only person who's ever bothered to read 'Hogwarts: A History?",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "But you know, happiness can be found even in the darkest of times, if one only remembers to turn on the light.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Don’t let the muggles get you down.",
|
||||||
|
"author": "Ron Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I want to commit the murder I was imprisoned for.",
|
||||||
|
"author": "Sirius Black"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Why, dear boy, we don’t send wizards to Azkaban just for blowing up their aunts.",
|
||||||
|
"author": "Cornelius Fudge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You think the dead we loved truly ever leave us? You think that we don’t recall them more clearly in times of great trouble?",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Mischief Managed!",
|
||||||
|
"author": "Harry Potter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "If you want to know what a man’s like, take a good look at how he treats his inferiors, not his equals.",
|
||||||
|
"author": "Sirius Black"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I am what I am, an' I'm not ashamed. 'Never be ashamed,' my ol' dad used ter say, 'there's some who'll hold it against you, but they're not worth botherin' with.'",
|
||||||
|
"author": "Rubeus Hagrid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It matters not what someone is born, but what they grow to be.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We are only as strong as we are united, as weak as we are divided.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Your devotion is nothing more than cowardice. You would not be here if you had anywhere else to go.",
|
||||||
|
"author": "Voldemort"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Numbing the pain for a while will make it worse when you finally feel it.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Anyone can speak Troll. All you have to do is point and grunt.",
|
||||||
|
"author": "Fred Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Curiosity is not a sin…. But we should exercise caution with our curiosity… yes, indeed.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Twitchy little ferret, aren’t you, Malfoy?",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Just because it’s taken you three years to notice, Ron, doesn’t mean no one else has spotted I’m a girl!",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Differences of habit and language are nothing at all if our aims are identical and our hearts are open.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Give her hell from us, Peeves.' And Peeves, whom Harry had never seen take an order from a student before, swept his belled hat from his head and sprang to a salute as Fred and George wheeled about to tumultuous applause from the students below and sped out of the open front doors into the glorious sunset.",
|
||||||
|
"author": "Harry Potter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I think we've outgrown full-time education ... Time to test our talents in the real world, d'you reckon?,",
|
||||||
|
"author": "Fred Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I think I'll just go down and have some pudding and wait for it all to turn up — it always does in the end.",
|
||||||
|
"author": "Luna Lovegood"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Just because you have the emotional range of a teaspoon doesn't mean we all have.",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You can laugh, but people used to believe there were no such things as the Blibbering Humdinger or the Crumple-Horned Snorkack!",
|
||||||
|
"author": "Luna Lovegood"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I mean, it's sort of exciting, isn't it, breaking the rules?",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We’ve all got both light and dark inside us. What matters is the part we choose to act on. That’s who we really are.",
|
||||||
|
"author": "Sirius Black"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Indifference and neglect often do much more damage than outright dislike.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Youth can not know how age thinks and feels. But old men are guilty if they forget what it was to be young.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Things we lose have a way of coming back to us in the end, if not always in the way we expect.",
|
||||||
|
"author": "Luna Lovegood"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Wit beyond measure is man’s greatest treasure.",
|
||||||
|
"author": "Luna Lovegood"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "'The thing about growing up with Fred and George is that you sort of start thinking anything's possible if you've got enough nerve.'",
|
||||||
|
"author": "Ginny Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "And now, Harry, let us step out into the night and pursue that flighty temptress, adventure.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Dumbledore says people find it far easier to forgive others for being wrong than being right.",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "There is no need to call me ‘sir,’ Professor.",
|
||||||
|
"author": "Harry Potter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "You’re just as sane as I am.",
|
||||||
|
"author": "Luna Lovegood"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I am a wizard, not a baboon brandishing a stick.",
|
||||||
|
"author": "unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Age is foolish and forgetful when it underestimates youth.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Once again, you show all the sensitivity of a blunt axe.",
|
||||||
|
"author": "Nearly Headless Nick"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is the unknown we fear when we look upon death and darkness, nothing more.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is the quality of one’s convictions that determines success, not the number of followers.",
|
||||||
|
"author": "Remus Lupin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Every human life is worth the same, and worth saving.",
|
||||||
|
"author": "Kingsley Shacklebolt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "After all this time? Always.",
|
||||||
|
"author": "Severus Snape"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Words are, in my not-so-humble opinion, our most inexhaustible source of magic. Capable of both inflicting injury, and remedying it.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Not my daughter, you b*tch!",
|
||||||
|
"author": "Molly Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "It is a curious thing, Harry, but perhaps those who are best suited to power are those who have never sought it. Those who, like you, have leadership thrust upon them, and take up the mantle because they must, and find to their own surprise that they wear it well.",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "He can run faster than Severus Snape confronted with shampoo.",
|
||||||
|
"author": "Fred Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Of course it is happening inside your head, Harry, but why on earth should that mean that it is not real?",
|
||||||
|
"author": "Albus Dumbledore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "I've always wanted to use that spell.",
|
||||||
|
"author": "Minerva McGonagall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "No post on Sundays.",
|
||||||
|
"author": "Vernon Dursley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "We could all have been killed—or worse, expelled.",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Never trust anything that can think for itself if you can’t see where it keeps its brain.",
|
||||||
|
"author": "Arthur Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Why couldn’t it be ‘follow the butterflies’?",
|
||||||
|
"author": "Ron Weasley"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Riddikulus",
|
||||||
|
"author": "Remus Lupin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "The ones that love us never really leave us.",
|
||||||
|
"author": "Sirius Black"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Have a biscuit, Potter.",
|
||||||
|
"author": "Minerva McGonagall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Just because you have the emotional range of a teaspoon doesn’t mean we all have.",
|
||||||
|
"author": "Hermione Granger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"quote": "Život je ako rebrík do kurína - krátky a osratý",
|
||||||
|
"author": "Furbyho babka"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
var characters = require('../characters.json');
|
||||||
|
var basicAuth = require('express-basic-auth');
|
||||||
|
|
||||||
|
router.use(basicAuth({
|
||||||
|
users: { 'admin': 'supersecret' },
|
||||||
|
unauthorizedResponse: {
|
||||||
|
message: "Sorry Wizard, can't let you in."
|
||||||
|
}
|
||||||
|
|
||||||
|
}))
|
||||||
|
|
||||||
|
router.get('/',
|
||||||
|
function (req, res) {
|
||||||
|
res.json(characters);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/:characterId', function (req, res) {
|
||||||
|
let result = characters.find(character => character.id == req.params.characterId);
|
||||||
|
res.send(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const houseController = require('../controllers/housesController.js')
|
||||||
|
module.exports = router;
|
||||||
|
const verifyToken = require('../app.js');
|
||||||
|
const checkToken = require('../middleware/auth.js');
|
||||||
|
|
||||||
|
router.use(verifyToken, checkToken);
|
||||||
|
|
||||||
|
router.get('/', houseController.houses_list);
|
||||||
|
|
||||||
|
router.get('/:houseId', houseController.specific_house)
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
module.exports = router;
|
||||||
|
const quotes = require('../quotes.json')
|
||||||
|
|
||||||
|
function getRandomQuote() {
|
||||||
|
return quotes[Math.floor(Math.random() * quotes.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get('/', function (req, res) {
|
||||||
|
res.json(getRandomQuote())
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
module.exports = router;
|
||||||
|
const houses = require('../houses.json')
|
||||||
|
const sortingHatQuotes = require('../sortinghatquotes.json')
|
||||||
|
|
||||||
|
function getRandomHouseName() {
|
||||||
|
let houseNames = houses.map(house => house.name);
|
||||||
|
return houseNames[Math.floor(Math.random() * houseNames.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandomQuote() {
|
||||||
|
return sortingHatQuotes[Math.floor(Math.random() * sortingHatQuotes.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get('/', function (req, res) {
|
||||||
|
let house = getRandomHouseName();
|
||||||
|
setTimeout(() => {
|
||||||
|
return res.json({
|
||||||
|
sortingHatSays: getRandomQuote() + ' ' + house,
|
||||||
|
house: house
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const spells = require('../spells.json');
|
||||||
|
const spellController = require('../controllers/spellsController.js')
|
||||||
|
module.exports = router;
|
||||||
|
const authChecker = require('../middleware/header.js')
|
||||||
|
|
||||||
|
router.get('/', spellController.spells_list);
|
||||||
|
|
||||||
|
router.post('/', authChecker.checkHeader, spellController.new_spell);
|
||||||
|
|
||||||
|
router.get('/:spellId', spellController.specific_spell)
|
||||||
|
|
||||||
|
router.delete('/:spellId', spellController.delete_spell)
|
||||||
|
|
||||||
|
router.delete('/actions/deleteAll', spellController.delete_all)
|
||||||
|
|
||||||
|
router.get('/actions/reset', spellController.reset)
|
||||||
|
|
||||||
|
router.put('/:spellId', authChecker.checkHeader, spellController.update_spell)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
"Move your ass to",
|
||||||
|
"You are a coward without future, your house is",
|
||||||
|
"Your broom is too magnificent, you should study at",
|
||||||
|
"Oh shit, that's right I'm a hat. And your house is",
|
||||||
|
"Stick your wand into",
|
||||||
|
"Hmm, difficult. VERY difficult. Plenty of courage, I see. But where to put you? All right it's",
|
||||||
|
"I'm just a hat. My only task is to pick random house..Like this one."
|
||||||
|
]
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#build
|
||||||
|
FROM node:lts-alpine as build-stage
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
#run
|
||||||
|
FROM nginx:stable-alpine as production-stage
|
||||||
|
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
||||||
|
EXPOSE 80
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# frontend
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
||||||
Generated
+19164
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint",
|
||||||
|
"start": "npm run serve"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.27.0",
|
||||||
|
"core-js": "^3.6.4",
|
||||||
|
"url": "^0.11.0",
|
||||||
|
"vue": "^2.6.14",
|
||||||
|
"vue-router": "^3.5.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/eslint-parser": "^7.5.4",
|
||||||
|
"@vue/cli-plugin-babel": "^5.0.4",
|
||||||
|
"@vue/cli-plugin-eslint": "~5.0.4",
|
||||||
|
"@vue/cli-service": "~5.0.4",
|
||||||
|
"eslint": "^8.14.0",
|
||||||
|
"eslint-plugin-vue": "^8.7.1",
|
||||||
|
"sass": "^1.50.1",
|
||||||
|
"sass-loader": "^12.6.0",
|
||||||
|
"vue-template-compiler": "^2.6.11",
|
||||||
|
"webpack": "^5.72.0"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "@babel/eslint-parser"
|
||||||
|
},
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title>Spelleology</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Kanit:100i" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lora:700" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
|
||||||
|
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Allura&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400&display=swap" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<navigation />
|
||||||
|
<router-view></router-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Navigation from "./components/Navigation";
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
components: {
|
||||||
|
Navigation
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.main {
|
||||||
|
padding: 10px 40px;
|
||||||
|
background-color: #822724;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.2em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
button.main:hover {
|
||||||
|
background-color: #72221f;
|
||||||
|
}
|
||||||
|
div.main {
|
||||||
|
padding-top: 50px;
|
||||||
|
min-height: 1000px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,121 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-2">
|
||||||
|
<img src="../assets/gringottsbanklogo.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<h1>Gringotts Bank</h1>
|
||||||
|
<h2>Investments for witches and wizards</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-5">
|
||||||
|
<div class="col mx-5">
|
||||||
|
<GringottsCalculator @calculation-done="handleCalculationDone" />
|
||||||
|
|
||||||
|
<GringottsForm
|
||||||
|
v-if="newInvestment"
|
||||||
|
:newInvestment="newInvestment"
|
||||||
|
@create-investment="handleCreateInvestment"
|
||||||
|
@reject-offer="handleRejectOffer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col mx-5">
|
||||||
|
<GringottsInvestmentList
|
||||||
|
:investments="investments"
|
||||||
|
@delete-investment="handleDeleteInvestment"
|
||||||
|
/>
|
||||||
|
<div v-if="investments.length === 0" class="no-investments-message">
|
||||||
|
<p>No investments yet. Make your first one!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GringottsCalculator from "../components/gringotts-bank/GringottsCalculator.vue";
|
||||||
|
import GringottsForm from "../components/gringotts-bank/GringottsForm.vue";
|
||||||
|
import GringottsInvestmentList from "../components/gringotts-bank/GringottsInvestmentList.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
GringottsCalculator,
|
||||||
|
GringottsForm,
|
||||||
|
GringottsInvestmentList,
|
||||||
|
},
|
||||||
|
created: function () {
|
||||||
|
if (localStorage.getItem("investments")) {
|
||||||
|
try {
|
||||||
|
this.investments = JSON.parse(localStorage.getItem("investments"));
|
||||||
|
} catch (e) {
|
||||||
|
localStorage.removeItem("investments");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
newInvestment: null,
|
||||||
|
investments: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCalculationDone(newInvestmentData) {
|
||||||
|
this.newInvestment = newInvestmentData;
|
||||||
|
},
|
||||||
|
handleCreateInvestment(customerName) {
|
||||||
|
if (this.newInvestment) {
|
||||||
|
// Create a new investment object with customer name
|
||||||
|
const investment = {
|
||||||
|
...this.newInvestment,
|
||||||
|
customerName,
|
||||||
|
};
|
||||||
|
// Log the new investment to the console
|
||||||
|
console.log("New Investment:", investment);
|
||||||
|
this.investments.push(investment);
|
||||||
|
|
||||||
|
this.saveAppliedSavings();
|
||||||
|
// Optionally, reset the newInvestment data
|
||||||
|
this.newInvestment = null;
|
||||||
|
//this.$refs.calculator.resetInputFields();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleRejectOffer() {
|
||||||
|
this.newInvestment = null;
|
||||||
|
|
||||||
|
// Handle the rejected offer, e.g., log a message or perform other actions
|
||||||
|
console.log("Offer Rejected");
|
||||||
|
},
|
||||||
|
handleDeleteInvestment(index) {
|
||||||
|
// Handle the deletion of the investment in the parent component
|
||||||
|
this.investments.splice(index, 1);
|
||||||
|
this.saveAppliedSavings();
|
||||||
|
},
|
||||||
|
saveAppliedSavings() {
|
||||||
|
const parsed = JSON.stringify(this.investments);
|
||||||
|
localStorage.setItem("investments", parsed);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
div.main {
|
||||||
|
img {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
background-color: #eeedeb;
|
||||||
|
h1,
|
||||||
|
h2 {
|
||||||
|
color: #747264;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: #868475;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modal-mask">
|
||||||
|
<div class="modal-wrapper">
|
||||||
|
<div class="modal-container">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 name="header">{{ spell.spell }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<h3 name="body">{{ spell.effect }}</h3>
|
||||||
|
<h4 class="body">{{ spell.type }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<slot name="footer">
|
||||||
|
<button class="modal-default-button btn-block btn" @click="close">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "ModalComponent",
|
||||||
|
props: ["spell"],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.$emit("close");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped >
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9998;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
display: table;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-wrapper {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
text-align: center;
|
||||||
|
width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 30px;
|
||||||
|
background-color: #822724;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
.modal-header h2 {
|
||||||
|
margin: 0 auto;
|
||||||
|
color: white;
|
||||||
|
font-family: "Harry", serif;
|
||||||
|
font-size: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
margin: 20px 0;
|
||||||
|
color: white;
|
||||||
|
font-family: "Lora", serif;
|
||||||
|
}
|
||||||
|
.modal-body h3 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.modal-body h4 {
|
||||||
|
font-family: "Kanit", serif;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-enter {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-enter .modal-container,
|
||||||
|
.modal-leave-active .modal-container {
|
||||||
|
-webkit-transform: scale(1.5);
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-default-button {
|
||||||
|
font-family: "Harry", serif;
|
||||||
|
font-size: 2em;
|
||||||
|
color: white;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.modal-default-button:active,
|
||||||
|
.modal-default-button:focus {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="navbar navbar-expand-lg">
|
||||||
|
<ul class="navbar-nav mx-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<router-link class="nav-link" to="/">Welcome</router-link>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<router-link class="nav-link" to="/spelleology"
|
||||||
|
>Spelleology</router-link
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<router-link class="nav-link" to="/sortingHat">Sorting Hat</router-link>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<router-link class="nav-link" to="/quotes">Quote Generator</router-link>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<router-link class="nav-link" to="/gringottsBank"
|
||||||
|
>Gringotts Bank</router-link
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "NavigationComponent",
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
a {
|
||||||
|
color: #212529;
|
||||||
|
&:hover {
|
||||||
|
color: #822724;
|
||||||
|
}
|
||||||
|
&.router-link-exact-active {
|
||||||
|
border-bottom: 1px solid #822724;
|
||||||
|
color: #822724;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
<h1 class="title">Potter Quotes</h1>
|
||||||
|
<h2 class="subtitle">Level up by getting some wisdom</h2>
|
||||||
|
|
||||||
|
<div class="quote-controls">
|
||||||
|
<button
|
||||||
|
v-on:click="getQuote"
|
||||||
|
class="main main mx-1"
|
||||||
|
data-test="get-quote"
|
||||||
|
>
|
||||||
|
Get Quote
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="main mx-1"
|
||||||
|
v-on:click="removeQuote"
|
||||||
|
:disabled="quoteList.length === 0"
|
||||||
|
id="remove-quote"
|
||||||
|
>
|
||||||
|
Remove Quote
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="row wisdom-level col-md-10 mx-auto">
|
||||||
|
<div class="col">
|
||||||
|
<p data-test="wisdom-points">
|
||||||
|
wisdom points +{{ this.quoteList.length }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<p data-test="wisdom-level">current level {{ wizardLevel }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 mx-auto">
|
||||||
|
<div class="quote-container">
|
||||||
|
<div v-if="this.qouteCounter == 0" class="empty-list-message">
|
||||||
|
Click the button to get some wisdom
|
||||||
|
</div>
|
||||||
|
<transition-group v-else name="fade" tag="ul" class="quote-list">
|
||||||
|
<li v-for="quoteitem in quoteList" :key="quoteitem.quote">
|
||||||
|
<p>{{ quoteitem.quote }}</p>
|
||||||
|
<p class="author">{{ quoteitem.author }}</p>
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "QuoteGenerator",
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
quote: "",
|
||||||
|
quoteList: [],
|
||||||
|
qouteCounter: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getQuote: function () {
|
||||||
|
this.quote = "";
|
||||||
|
this.$http.get("/quote").then((response) => {
|
||||||
|
this.quote = response.data;
|
||||||
|
this.quoteList.unshift(this.quote);
|
||||||
|
this.qouteCounter++;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeQuote: function () {
|
||||||
|
if (this.quoteList.length > 0) {
|
||||||
|
this.quoteList.shift(); // Remove the newest quote
|
||||||
|
this.qouteCounter--;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
wizardLevel: function () {
|
||||||
|
let level = "";
|
||||||
|
if (this.qouteCounter <= 5) {
|
||||||
|
level = "NOOB";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 5) {
|
||||||
|
level = "ROOKIE wand polisher";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 10) {
|
||||||
|
level = "Experienced broom SUMMONER";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 15) {
|
||||||
|
level = "NIGHTMARE Alchemist";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 20) {
|
||||||
|
level = "Spell OVERLORD";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 25) {
|
||||||
|
level = "Death potion EVANGELIST";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 30) {
|
||||||
|
level = "Dementor the HAPPINESS SPECIALIST";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 35) {
|
||||||
|
level = "Part-Time DEATHEATER";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 40) {
|
||||||
|
level = "First Impression SPOILER";
|
||||||
|
}
|
||||||
|
if (this.qouteCounter > 45) {
|
||||||
|
level = "Azcaban INFLUENCER";
|
||||||
|
}
|
||||||
|
return level;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
$gray-color: #9b9a9a;
|
||||||
|
$red-color: #822724;
|
||||||
|
h1.title {
|
||||||
|
font-family: "Roboto Slab", serif;
|
||||||
|
}
|
||||||
|
h2.subtitle {
|
||||||
|
font-family: "Roboto Slab", serif;
|
||||||
|
color: $gray-color;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px 30px;
|
||||||
|
margin-top: 20px;
|
||||||
|
background-color: $red-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
button#remove-quote {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
button#remove-quote:disabled {
|
||||||
|
background-color: #9b9a9a;
|
||||||
|
|
||||||
|
cursor: not-allowed;
|
||||||
|
&:active {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.quote-container {
|
||||||
|
margin-top: 50px;
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
li {
|
||||||
|
font-family: "Roboto Slab", serif;
|
||||||
|
text-align: left;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
box-shadow: 0px 0px 7px 1px rgba(230, 230, 230, 1);
|
||||||
|
&:nth-child(1) {
|
||||||
|
transform: scale(1.05);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0px 0px 15px 3px #c17f7d;
|
||||||
|
}
|
||||||
|
.author {
|
||||||
|
color: $gray-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fade-enter-to,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
}
|
||||||
|
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quote-controls {
|
||||||
|
p {
|
||||||
|
display: inline-block;
|
||||||
|
color: $red-color;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
transition: all 200ms ease-in;
|
||||||
|
&:active {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wisdom-level {
|
||||||
|
margin-top: 20px;
|
||||||
|
p {
|
||||||
|
color: $gray-color;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="search"
|
||||||
|
placeholder="search for spell effect"
|
||||||
|
id="search"
|
||||||
|
data-test="search-input"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-bind:value="value"
|
||||||
|
v-on="inputListeners"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SearchComponent",
|
||||||
|
props: ["value"],
|
||||||
|
computed: {
|
||||||
|
inputListeners: function() {
|
||||||
|
var vm = this;
|
||||||
|
// `Object.assign` merges objects together to form a new object
|
||||||
|
return Object.assign(
|
||||||
|
{},
|
||||||
|
// We add all the listeners from the parent
|
||||||
|
this.$listeners,
|
||||||
|
// Then we can add custom listeners or override the
|
||||||
|
// behavior of some listeners.
|
||||||
|
{
|
||||||
|
// This ensures that the component works with v-model
|
||||||
|
input: function(event) {
|
||||||
|
vm.$emit("input", event.target.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
input.search {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
font-family: "Lora", serif;
|
||||||
|
border-bottom: 2px solid #dca39e;
|
||||||
|
background-color: #822724;
|
||||||
|
border-radius: 0;
|
||||||
|
font-size: 2em;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
transition: all 200ms ease;
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: #822724;
|
||||||
|
border-radius: 0;
|
||||||
|
border-bottom: 2px solid #fff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
&::placeholder {
|
||||||
|
color: #dca39e;
|
||||||
|
font-family: "Kanit", serif;
|
||||||
|
}
|
||||||
|
&:focus::placeholder {
|
||||||
|
color: #fff;
|
||||||
|
font-family: "Kanit", serif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
<h1 class="title">Sorting Hat</h1>
|
||||||
|
<h2 class="subtitle">Find yourself a new home in Hogwarts</h2>
|
||||||
|
<button
|
||||||
|
class="main"
|
||||||
|
data-test="sort-button"
|
||||||
|
:disabled="disabled"
|
||||||
|
v-on:click="getQuote"
|
||||||
|
>{{sortButtonLabel}}</button>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<img class="hat" src="../assets/sortinghat.jpg" alt />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 my-auto message">
|
||||||
|
<h2 v-if="quote" data-test="result-message">{{quote.sortingHatSays}}</h2>
|
||||||
|
<h1 v-if="quote" data-test="house-result">{{quote.house}}</h1>
|
||||||
|
<h3 class="message" v-else>{{loadingMessage}}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SortingHat",
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
disabled: false,
|
||||||
|
quote: "",
|
||||||
|
isSorted: false,
|
||||||
|
loadingMessage: "Click on sort to get yourself a new home"
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
sortButtonLabel: function() {
|
||||||
|
if (this.isSorted) {
|
||||||
|
return "Sort me again!";
|
||||||
|
}
|
||||||
|
return "Sort me";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getQuote: function() {
|
||||||
|
this.disabled = true;
|
||||||
|
this.loadingMessage = "Let me think...";
|
||||||
|
this.quote = "";
|
||||||
|
this.$http
|
||||||
|
.get("/sortingHat")
|
||||||
|
.then(response => (this.quote = response.data))
|
||||||
|
.then(() => {
|
||||||
|
(this.isSorted = true), (this.disabled = false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped >
|
||||||
|
$gray-color: rgb(155, 154, 154);
|
||||||
|
div.main {
|
||||||
|
font-family: "Roboto Slab", serif;
|
||||||
|
h2.subtitle {
|
||||||
|
color: $gray-color;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
div.message {
|
||||||
|
h1 {
|
||||||
|
margin: 20px 0;
|
||||||
|
text-align: left;
|
||||||
|
color: #3f3f8c;
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 1.9em;
|
||||||
|
text-align: left;
|
||||||
|
color: $gray-color;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
text-align: center;
|
||||||
|
color: $gray-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hat {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin-top: 20px;
|
||||||
|
background-color: #3f3f8c;
|
||||||
|
&:hover {
|
||||||
|
background-color: #333373;
|
||||||
|
}
|
||||||
|
&:disabled {
|
||||||
|
background-color: $gray-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ul class="spells row text-center">
|
||||||
|
<li
|
||||||
|
v-bind:key="spell.id"
|
||||||
|
v-for="spell in spells"
|
||||||
|
v-on:click="$emit('clickOnspell', spell)"
|
||||||
|
>
|
||||||
|
{{ spell.effect }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SpellList",
|
||||||
|
props: ["spells"],
|
||||||
|
methods: {
|
||||||
|
clickOnspell: function () {
|
||||||
|
this.$emit("selectSpell");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.spells {
|
||||||
|
list-style: none;
|
||||||
|
padding: 20px;
|
||||||
|
li {
|
||||||
|
padding: 10px;
|
||||||
|
color: #dca39e;
|
||||||
|
font-family: "Lora", serif;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 2em;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 200ms ease-in-out;
|
||||||
|
&:nth-child(1n + 2) {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
&:nth-child(2n + 3) {
|
||||||
|
font-size: 1.7em;
|
||||||
|
}
|
||||||
|
&:nth-child(3n) {
|
||||||
|
font-size: 2.2em;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: #fffcf9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main spells-main">
|
||||||
|
<h1 class="text-center title">Spelleology</h1>
|
||||||
|
<div class="col-md-12 mx-auto">
|
||||||
|
<div class="col-md-6 row mx-auto">
|
||||||
|
<search-component class="col" v-model="search" />
|
||||||
|
<div class="col-md-4 unforgivable-checkbox">
|
||||||
|
<input type="checkbox" id="unforgivableOnly" v-model="unforgivableOnly" />
|
||||||
|
<label for="unforgivableOnly">Unforgivable only</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="type-filter">
|
||||||
|
<input type="checkbox" id="spell" value="Spell" v-model="checkedSpells" />
|
||||||
|
<label for="spell">Spell</label>
|
||||||
|
<input type="checkbox" id="charm" value="Charm" v-model="checkedSpells" />
|
||||||
|
<label for="charm">Charm</label>
|
||||||
|
<input type="checkbox" id="curse" value="Curse" v-model="checkedSpells" />
|
||||||
|
<label for="curse">Curse</label>
|
||||||
|
<input type="checkbox" id="enchantment" value="Enchantment" v-model="checkedSpells" />
|
||||||
|
<label for="enchantment">Enchantment</label>
|
||||||
|
<input type="checkbox" id="hex" value="Hex" v-model="checkedSpells" />
|
||||||
|
<label for="hex">Hex</label>
|
||||||
|
<input type="checkbox" id="jinx" value="Jinx" v-model="checkedSpells" />
|
||||||
|
<label for="jinx">Jinx</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
v-on:click="clearAll"
|
||||||
|
id="deleteAll"
|
||||||
|
data-test="delete-all"
|
||||||
|
class="spell-button"
|
||||||
|
>Delete all</button>
|
||||||
|
<button v-on:click="reset" id="resetSpells" data-test="reset" class="spell-button">Reset</button>
|
||||||
|
</div>
|
||||||
|
<div class="row col-md-12 mx-auto">
|
||||||
|
<spell-list
|
||||||
|
v-if="spells.length >=1"
|
||||||
|
:spells="filteredList"
|
||||||
|
v-on:clickOnspell="selectSpell"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h1
|
||||||
|
class="subtitle text-center"
|
||||||
|
v-if="spells.length ===0 || filteredList.length ===0"
|
||||||
|
>Mischief managed</h1>
|
||||||
|
<modal :spell="selectedSpell" v-show="showModal" @close="closeModal" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SpellList from "./SpellList.vue";
|
||||||
|
import SearchComponent from "./SearchComponent.vue";
|
||||||
|
import Modal from "./Modal.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SpelleologyComponent",
|
||||||
|
components: {
|
||||||
|
SpellList,
|
||||||
|
SearchComponent,
|
||||||
|
Modal,
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
spells: [],
|
||||||
|
selectedSpell: "",
|
||||||
|
showModal: false,
|
||||||
|
search: "",
|
||||||
|
unforgivableOnly: false,
|
||||||
|
checkedSpells: ["Charm", "Enchantment", "Curse", "Spell", "Hex", "Jinx"],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredList: function () {
|
||||||
|
let spells = this.spells;
|
||||||
|
spells = spells.filter((spell) =>
|
||||||
|
spell.effect.toLowerCase().includes(this.search.toLowerCase())
|
||||||
|
);
|
||||||
|
spells = spells.filter((spell) =>
|
||||||
|
this.checkedSpells.includes(spell.type)
|
||||||
|
);
|
||||||
|
if (this.unforgivableOnly) {
|
||||||
|
spells = spells.filter((spell) => spell.isUnforgivable === true);
|
||||||
|
}
|
||||||
|
return spells;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function () {
|
||||||
|
this.$http.get("/spells").then((response) => (this.spells = response.data));
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectSpell: function (spell) {
|
||||||
|
this.selectedSpell = spell;
|
||||||
|
this.showModal = true;
|
||||||
|
},
|
||||||
|
closeModal() {
|
||||||
|
this.showModal = false;
|
||||||
|
},
|
||||||
|
clearAll: function () {
|
||||||
|
this.$http
|
||||||
|
.delete("spells/actions/deleteAll")
|
||||||
|
.then(() => (this.spells = []));
|
||||||
|
},
|
||||||
|
reset: function () {
|
||||||
|
this.$http.get("spells/actions/reset").then((response) => {
|
||||||
|
this.spells = response.data.spells;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div.spells-main {
|
||||||
|
background-color: #822724;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-family: "Harry", serif;
|
||||||
|
|
||||||
|
&.title {
|
||||||
|
color: white;
|
||||||
|
font-size: 8em;
|
||||||
|
text-shadow: 7px 7px 2px #671e1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.subtitle {
|
||||||
|
margin: 100px;
|
||||||
|
font-size: 6em;
|
||||||
|
color: #dca39e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: white;
|
||||||
|
padding: 0 10px;
|
||||||
|
font-family: "Kanit", serif;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.unforgivable-checkbox {
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-button {
|
||||||
|
padding: 1px 20px;
|
||||||
|
background-color: #822724;
|
||||||
|
font-family: "Kanit", serif;
|
||||||
|
color: #fffcf9;
|
||||||
|
font-size: 2em;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 2px solid #dca39e;
|
||||||
|
margin: 0 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-bottom: 2px solid white;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Harry";
|
||||||
|
src: url("../assets/HARRYP.TTF");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="welcome">
|
||||||
|
<h1>Welcome Wizard</h1><img src=../assets/hogwartslogo.png alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "WelcomeComponent"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div.welcome {
|
||||||
|
margin-top: 50px;
|
||||||
|
h1 {
|
||||||
|
font-size: 8em;
|
||||||
|
color: black;
|
||||||
|
font-family: "Roboto Slab", serif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2>Enter your data muggle!</h2>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<select class="custom-select" id="selectedFund" v-model="selectedFundId">
|
||||||
|
<option disabled value="">Please select fund</option>
|
||||||
|
<option
|
||||||
|
v-for="(product, index) in products"
|
||||||
|
:value="product.id"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
{{ product.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
aria-describedby="inputGroup-sizing-default"
|
||||||
|
type="number"
|
||||||
|
id="oneTimeInvestment"
|
||||||
|
v-model="oneTimeInvestment"
|
||||||
|
step="1000"
|
||||||
|
placeholder="one time investment"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
aria-describedby="inputGroup-sizing-default"
|
||||||
|
type="number"
|
||||||
|
id="years"
|
||||||
|
v-model="years"
|
||||||
|
step="1"
|
||||||
|
placeholder="years"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-block" @click="calculate" data-test="create-offer">
|
||||||
|
Make me an offer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedFundId: "",
|
||||||
|
oneTimeInvestment: null,
|
||||||
|
years: null,
|
||||||
|
products: [
|
||||||
|
{ id: 1, name: "Galleon Guardian Fund", risk: "LOW", interestRate: 4 },
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "Phoenix Feather Portfolio",
|
||||||
|
risk: "MEDIUM",
|
||||||
|
interestRate: 6,
|
||||||
|
},
|
||||||
|
{ id: 3, name: "Basilisk Bonds", risk: "HIGH", interestRate: 9 },
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "Polyjuice Potion Fund",
|
||||||
|
risk: "MEDIUM",
|
||||||
|
interestRate: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "Marauder's Map Mutuals",
|
||||||
|
risk: "HIGH",
|
||||||
|
interestRate: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "Dementor Defense Dividends",
|
||||||
|
risk: "INSANE",
|
||||||
|
interestRate: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "Quidditch Quest Equities",
|
||||||
|
risk: "MEDIUM",
|
||||||
|
interestRate: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: "Hogwarts Heritage Holdings",
|
||||||
|
risk: "HIGH",
|
||||||
|
interestRate: 9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: "Pensieve Prosperity Partners",
|
||||||
|
risk: "LOW",
|
||||||
|
interestRate: 3,
|
||||||
|
},
|
||||||
|
{ id: 10, name: "Owl Post Options", risk: "MEDIUM", interestRate: 5 },
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: "Death Eater Dominance Fund",
|
||||||
|
risk: "INSANE",
|
||||||
|
interestRate: 15,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectedFund() {
|
||||||
|
return this.products.find((fund) => fund.id == this.selectedFundId);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
calculate() {
|
||||||
|
if (this.selectedFund && this.oneTimeInvestment && this.years) {
|
||||||
|
const oneTimeInvestment = parseFloat(this.oneTimeInvestment);
|
||||||
|
const interestRate = this.selectedFund.interestRate / 100;
|
||||||
|
const years = parseInt(this.years);
|
||||||
|
|
||||||
|
// Simple compound interest calculation
|
||||||
|
const totalInvestment =
|
||||||
|
oneTimeInvestment * Math.pow(1 + interestRate, years);
|
||||||
|
const interestIncome = totalInvestment - oneTimeInvestment;
|
||||||
|
const taxes = interestIncome * 0.19;
|
||||||
|
const netIncome = totalInvestment - taxes;
|
||||||
|
|
||||||
|
const calculatedData = {
|
||||||
|
oneTimeInvestment,
|
||||||
|
fund: this.selectedFund,
|
||||||
|
years,
|
||||||
|
totalInvestment,
|
||||||
|
interestIncome,
|
||||||
|
taxes,
|
||||||
|
netIncome,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit("calculation-done", calculatedData);
|
||||||
|
this.oneTimeInvestment = null;
|
||||||
|
this.selectedFundId = "";
|
||||||
|
this.years = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Add your component-specific styles here */
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
button {
|
||||||
|
margin-top: 0px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: #747264;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #747264;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mt-5 offer-detail">
|
||||||
|
<h2>The offer</h2>
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col your-data">
|
||||||
|
<h4>Your data</h4>
|
||||||
|
<p>
|
||||||
|
Investment: <span>{{ formatAsMoneyGBP(newInvestment.oneTimeInvestment) }}</span>
|
||||||
|
</p>
|
||||||
|
<p class="period">Period: <span>{{ newInvestment.years }} years</span></p>
|
||||||
|
<p class="fund">Fund: <span>{{ newInvestment.fund.name }}</span></p>
|
||||||
|
<p class="risk">Risk: <span>{{ newInvestment.fund.risk }}</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col our-calculations">
|
||||||
|
<h4>Our calculations</h4>
|
||||||
|
<p>Net income: <span> {{ formatAsMoneyGBP(newInvestment.netIncome) }}</span></p>
|
||||||
|
<p>
|
||||||
|
Interest income: <span>{{ formatAsMoneyGBP(newInvestment.interestIncome) }}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>
|
||||||
|
Total income:
|
||||||
|
{{
|
||||||
|
formatAsMoneyGBP(
|
||||||
|
newInvestment.netIncome + newInvestment.interestIncome
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input class="form-control" aria-describedby="inputGroup-sizing-default" type="text" id="customerName"
|
||||||
|
data-test="customer-name" v-model="customerName" placeholder="enter your name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-success mx-3" @click="createInvestment" data-test="create-investment">
|
||||||
|
Create Investment
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger mx-3" @click="rejectOffer" data-test="decline-investment">
|
||||||
|
Reject Offer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
newInvestment: Object, // Pass the calculatedData as a prop
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
customerName: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatAsMoneyGBP(number) {
|
||||||
|
// Use Intl.NumberFormat to format the number as GBP
|
||||||
|
const formatter = new Intl.NumberFormat("en-GB", {
|
||||||
|
style: "currency",
|
||||||
|
currency: "GBP",
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return the formatted string
|
||||||
|
return formatter.format(number);
|
||||||
|
},
|
||||||
|
createInvestment() {
|
||||||
|
if (this.customerName) {
|
||||||
|
console.log("emitting");
|
||||||
|
this.$emit("create-investment", this.customerName);
|
||||||
|
// Optionally, clear the input field after creating the investment
|
||||||
|
this.customerName = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rejectOffer() {
|
||||||
|
// Handle the rejection, e.g., emit an event or perform other actions
|
||||||
|
this.$emit("reject-offer");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
div.offer-detail {
|
||||||
|
button {
|
||||||
|
font-weight: 700;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
color: #fff;
|
||||||
|
background-color: #747264;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2>Gringotts Investment List</h2>
|
||||||
|
|
||||||
|
<ul class="investment-list mt-3">
|
||||||
|
<li class="my-2" v-for="(investment, index) in investments" :key="index">
|
||||||
|
<h4>
|
||||||
|
Investment issued for <span>{{ investment.customerName }}</span>
|
||||||
|
<hr />
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<p>
|
||||||
|
Investment:
|
||||||
|
{{ formatAsMoneyGBP(investment.oneTimeInvestment) }}
|
||||||
|
</p>
|
||||||
|
<p>Period: {{ investment.years }} years</p>
|
||||||
|
<p>Fund: {{ investment.fund.name }}</p>
|
||||||
|
<p>Risk: {{ investment.fund.risk }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<p>Net income: {{ formatAsMoneyGBP(investment.netIncome) }}</p>
|
||||||
|
<p>
|
||||||
|
Interest income:
|
||||||
|
{{ formatAsMoneyGBP(investment.interestIncome) }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>
|
||||||
|
Total income:
|
||||||
|
{{
|
||||||
|
formatAsMoneyGBP(
|
||||||
|
investment.netIncome + investment.interestIncome
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button
|
||||||
|
class="btn btn-primary mr-2 float-left"
|
||||||
|
id="showDetail"
|
||||||
|
@click="openInvestmentModal(index)"
|
||||||
|
>
|
||||||
|
View Details
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-danger float-left"
|
||||||
|
id="delete"
|
||||||
|
@click="deleteInvestment(index)"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<GringottsInvestmentModal
|
||||||
|
v-if="selectedInvestment !== null"
|
||||||
|
:investment="selectedInvestment"
|
||||||
|
:is-open="isModalOpen"
|
||||||
|
@close-investment-modal="closeInvestmentModal"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GringottsInvestmentModal from "../gringotts-bank/GringottsInvestmentModal.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
investments: Array, // Array of investments passed as a prop
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
GringottsInvestmentModal,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedInvestment: null,
|
||||||
|
isModalOpen: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatAsMoneyGBP(number) {
|
||||||
|
// Use Intl.NumberFormat to format the number as GBP
|
||||||
|
const formatter = new Intl.NumberFormat("en-GB", {
|
||||||
|
style: "currency",
|
||||||
|
currency: "GBP",
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return the formatted string
|
||||||
|
return formatter.format(number);
|
||||||
|
},
|
||||||
|
deleteInvestment(index) {
|
||||||
|
// Trigger the deletion of the investment at the specified index
|
||||||
|
this.$emit("delete-investment", index);
|
||||||
|
},
|
||||||
|
openInvestmentModal(index) {
|
||||||
|
this.selectedInvestment = this.investments[index];
|
||||||
|
this.isModalOpen = true;
|
||||||
|
},
|
||||||
|
closeInvestmentModal() {
|
||||||
|
this.selectedInvestment = null;
|
||||||
|
this.isModalOpen = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
h2 {
|
||||||
|
color: #747264;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
ul.investment-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
li {
|
||||||
|
hr {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
text-align: left;
|
||||||
|
span {
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color: #fff;
|
||||||
|
background-color: #747264;
|
||||||
|
padding: 20px;
|
||||||
|
button {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
button#showDetail {
|
||||||
|
background-color: #504e44;
|
||||||
|
border: none;
|
||||||
|
&:hover {
|
||||||
|
background-color: #676458;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
text-align: left;
|
||||||
|
span {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h5 {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
transition: all 200ms ease-in;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #817f71;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<!-- GringottsInvestmentModal.vue -->
|
||||||
|
<template>
|
||||||
|
<div v-if="isOpen" class="modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Investment Details</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<p>Fund: {{ investment.fund.name }}</p>
|
||||||
|
<p>Risk: {{ investment.fund.risk }}</p>
|
||||||
|
<p>Name: {{ investment.customerName }}</p>
|
||||||
|
<p>
|
||||||
|
Investment: {{ formatAsMoneyGBP(investment.oneTimeInvestment) }}
|
||||||
|
</p>
|
||||||
|
<p>Years: {{ investment.years }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<p>Net income: {{ formatAsMoneyGBP(investment.netIncome) }}</p>
|
||||||
|
<p>
|
||||||
|
Interest income:
|
||||||
|
{{ formatAsMoneyGBP(investment.interestIncome) }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Total income:
|
||||||
|
{{
|
||||||
|
formatAsMoneyGBP(
|
||||||
|
investment.netIncome + investment.interestIncome
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-secondary"
|
||||||
|
data-dismiss="modal"
|
||||||
|
@click="closeInvestmentModal"
|
||||||
|
id="close"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
investment: Object, // The specific investment object to display details
|
||||||
|
isOpen: Boolean, // Whether the modal is open or not
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeInvestmentModal() {
|
||||||
|
this.$emit("close-investment-modal"); // Emit an event to close the modal
|
||||||
|
},
|
||||||
|
formatAsMoneyGBP(number) {
|
||||||
|
// Use Intl.NumberFormat to format the number as GBP
|
||||||
|
const formatter = new Intl.NumberFormat("en-GB", {
|
||||||
|
style: "currency",
|
||||||
|
currency: "GBP",
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return the formatted string
|
||||||
|
return formatter.format(number);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/* Add your modal styles here */
|
||||||
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
.modal-dialog {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 1200px;
|
||||||
|
.modal-content {
|
||||||
|
color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: #747264;
|
||||||
|
border: none;
|
||||||
|
p {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
button#close {
|
||||||
|
background-color: #504e44;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
&:hover {
|
||||||
|
background-color: #676458;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export default {
|
||||||
|
name: "Modal",
|
||||||
|
props: ["spell"],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.$emit("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import App from "./App.vue";
|
||||||
|
import axios from "axios";
|
||||||
|
import VueRouter from "vue-router";
|
||||||
|
import Spelleology from "../src/components/Spelleology";
|
||||||
|
import SortingHat from "../src/components/SortingHat";
|
||||||
|
import Welcome from "../src/components/Welcome";
|
||||||
|
import QuoteGenerator from "../src/components/QuoteGenerator";
|
||||||
|
import GringottsBank from "../src/components/GringottsBank";
|
||||||
|
|
||||||
|
const axiosconfig = {
|
||||||
|
baseURL: "https://potterapi-tgq2.onrender.com",
|
||||||
|
timeout: 30000,
|
||||||
|
};
|
||||||
|
Vue.prototype.$http = axios.create(axiosconfig);
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
routes: [
|
||||||
|
{ path: "/spelleology", component: Spelleology },
|
||||||
|
{ path: "/sortingHat", component: SortingHat },
|
||||||
|
{ path: "/quotes", component: QuoteGenerator },
|
||||||
|
{ path: "/gringottsBank", component: GringottsBank },
|
||||||
|
{ path: "/", component: Welcome },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
render: (h) => h(App),
|
||||||
|
}).$mount("#app");
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
//...
|
||||||
|
resolve: {
|
||||||
|
fallback: {
|
||||||
|
url: require.resolve("url"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in new issue
Block a user