diff --git a/data/database.sqlite b/data/database.sqlite new file mode 100644 index 0000000..df90da9 Binary files /dev/null and b/data/database.sqlite differ diff --git a/views/categories.pug b/data/dummy similarity index 100% rename from views/categories.pug rename to data/dummy diff --git a/less/app.less b/less/app.less new file mode 100644 index 0000000..36ddc4b --- /dev/null +++ b/less/app.less @@ -0,0 +1,110 @@ +@dark: #222f3e; +@light-grey: #576574; +@light: #c8d6e5; + +@green: #1dd1a1; +@yellow: #feca57; +@red: #ff6b6b; +@pink: #ff9ff3; +@purple: #5f27cd; +@cyan: #48dbfb; +@blue: #54a0ff; + +:root { + --dark: @dark; + --light-grey: @light-grey; + --light: @light; + + --green: @green; + --yellow: @yellow; + --red: @red; + --pink: @pink; + --purple: @purple; + --cyan: @cyan; + --blue: @blue; + +} + +@font-face { + font-family: 'robotomono-light'; + src: url('/assets/font/RobotoMono-Light.ttf'); +} + +* { + font-family: "robotomono-light"; +} + +body { + background-color: var(--dark); + color: var(--light); +} + +.nav { + width: 1200px; + margin: auto; + padding: 10px; + border: 1px solid; +} + +.container { + width: 1200px; + margin: auto; + padding: 10px; + border: 1px solid; +} + +a { + color: var(--cyan); + padding: 5px; +} + +details { + width: 100%; +} + +form { + display: flex; + flex-wrap: wrap; +} + +form .form-group { + width: 100%; +} + +form .form-group.half { + width: 50%; +} + +form .form-group .text { + width: 200px; + text-align: right; + padding: 5px; + flex-shrink: 0; +} + +form .form-group .input { + width: 100%; + padding: 5px; +} + +form .form-group .input input, +form .form-group .input textarea, +form .form-group .input select { + width: 100%; + box-sizing: border-box; +} + +form .form-group { + display: flex; +} + +input[type="number"],input[type="time"],input[type="date"],select{ + text-align: right; +} +input[type="number"],input[type="time"],input[type="date"],select,input[type="text"],textarea{ + background:@light-grey; + border-color: transparent; +} + +@import "table.less"; +@import "responsive.less"; \ No newline at end of file diff --git a/less/responsive.less b/less/responsive.less new file mode 100644 index 0000000..a309b78 --- /dev/null +++ b/less/responsive.less @@ -0,0 +1,16 @@ +@media (max-width: 1250px) { + + .nav, + .container { + width: 95vw; + margin: auto; + padding: 1vw; + } +} +@media (max-width: 800px) { + form .form-group.half{ + width:100%; + } +} + + diff --git a/less/table.less b/less/table.less new file mode 100644 index 0000000..639e400 --- /dev/null +++ b/less/table.less @@ -0,0 +1,74 @@ +table { + width: 100%; +} + +table td.amount { + text-align: right; +} + +table td.income { + color: var(--green); +} + +table td.expense { + color: var(--red); +} + +table td.transfer { + color: var(--pink); +} + +table td.amount:after { + content: " €"; +} + +th { + text-align: left; +} + +th.middle { + text-align: center; +} + +th.right { + text-align: right +} + +tr:nth-child(3n+2) { + background-color: lighten(@dark, 5%); +} + +tr:nth-child(3n+3) { + background-color: lighten(@dark, 10%); +} + +tr{ + td:nth-child(1){ + border-left:solid transparent 5px; + text-align: right; + padding-right: 5px; + } +} +table.fullList{ + tr.transfer:nth-child(2n+1) { + td:nth-child(1) { + border-top: 1px solid @pink; + border-left: 5px solid @pink; + } + + td:nth-child(2) { + border-top: 1px solid @pink; + } + } + + tr.transfer:nth-child(2n+2) { + td:nth-child(1) { + border-left: 5px solid @pink; + border-bottom: 1px solid @pink; + } + + td:nth-child(2) { + border-bottom: 1px solid @pink; + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 9c2c113..9b58a04 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "rm -rf ./build && tsc", - "start": "npm run build && node build/index.js" + "start": "npm run build && lessc less/app.less public/css/app.css && node build/index.js", + "lessc":"lessc less/app.less public/css/app.css" }, "author": "", "license": "ISC", diff --git a/public/css/app.css b/public/css/app.css index 6a62bdc..0df6cee 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -1,46 +1,151 @@ -:root{ - --dark: #222f3e; - --light-grey: #576574; - --light: #c8d6e5; - - --green: #1dd1a1; - --yellow: #feca57; - --red: #ff6b6b; - --pink: #ff9ff3; - --purple: #5f27cd; - --cyan: #48dbfb; - --blue: #54a0ff; - +:root { + --dark: #222f3e; + --light-grey: #576574; + --light: #c8d6e5; + --green: #1dd1a1; + --yellow: #feca57; + --red: #ff6b6b; + --pink: #ff9ff3; + --purple: #5f27cd; + --cyan: #48dbfb; + --blue: #54a0ff; } @font-face { - font-family: 'robotomono-light'; - src: url('/assets/font/RobotoMono-Light.ttf'); + font-family: 'robotomono-light'; + src: url('/assets/font/RobotoMono-Light.ttf'); } -*{ - font-family: "robotomono-light"; +* { + font-family: "robotomono-light"; } -body{ - background-color: var(--dark); - color:var(--light); +body { + background-color: var(--dark); + color: var(--light); } -.container{ - width: 1200px; +.nav { + width: 1200px; + margin: auto; + padding: 10px; + border: 1px solid; +} +.container { + width: 1200px; + margin: auto; + padding: 10px; + border: 1px solid; +} +a { + color: var(--cyan); + padding: 5px; +} +details { + width: 100%; +} +form { + display: flex; + flex-wrap: wrap; +} +form .form-group { + width: 100%; +} +form .form-group.half { + width: 50%; +} +form .form-group .text { + width: 200px; + text-align: right; + padding: 5px; + flex-shrink: 0; +} +form .form-group .input { + width: 100%; + padding: 5px; +} +form .form-group .input input, +form .form-group .input textarea, +form .form-group .input select { + width: 100%; + box-sizing: border-box; +} +form .form-group { + display: flex; +} +input[type="number"], +input[type="time"], +input[type="date"], +select { + text-align: right; +} +input[type="number"], +input[type="time"], +input[type="date"], +select, +input[type="text"], +textarea { + background: #576574; + border-color: transparent; +} +table { + width: 100%; +} +table td.amount { + text-align: right; +} +table td.income { + color: var(--green); +} +table td.expense { + color: var(--red); +} +table td.transfer { + color: var(--pink); +} +table td.amount:after { + content: " €"; +} +th { + text-align: left; +} +th.middle { + text-align: center; +} +th.right { + text-align: right; +} +tr:nth-child(3n+2) { + background-color: #2b3b4e; +} +tr:nth-child(3n+3) { + background-color: #34485f; +} +tr td:nth-child(1) { + border-left: solid transparent 5px; + text-align: right; + padding-right: 5px; +} +table.fullList tr.transfer:nth-child(2n+1) td:nth-child(1) { + border-top: 1px solid #ff9ff3; + border-left: 5px solid #ff9ff3; +} +table.fullList tr.transfer:nth-child(2n+1) td:nth-child(2) { + border-top: 1px solid #ff9ff3; +} +table.fullList tr.transfer:nth-child(2n+2) td:nth-child(1) { + border-left: 5px solid #ff9ff3; + border-bottom: 1px solid #ff9ff3; +} +table.fullList tr.transfer:nth-child(2n+2) td:nth-child(2) { + border-bottom: 1px solid #ff9ff3; +} +@media (max-width: 1250px) { + .nav, + .container { + width: 95vw; margin: auto; - padding: 10px; - border: 1px solid; + padding: 1vw; + } } -table{ +@media (max-width: 800px) { + form .form-group.half { width: 100%; + } } -table .amount{ - text-align: right; -} -table .income{ - color:var(--green); -} -table .expense{ - color: var(--red); -} -table .transfer{ - color: var(--pink); -} \ No newline at end of file diff --git a/src/controller/helper/dateConversion.ts b/src/controller/helper/dateConversion.ts new file mode 100644 index 0000000..76b0075 --- /dev/null +++ b/src/controller/helper/dateConversion.ts @@ -0,0 +1,14 @@ +import moment from "moment"; +import { Transaction } from "../models"; + +export function convertDateArray(arr1:any):any{ + let arr = []; + for (let index = 0; index < arr1.length; index++) { + let element:Transaction = arr1[index]; + let e:any = element; + e.Date2 = moment(element.Date).format("YYYY-MM-DD HH:MM") + console.log(moment(element.Date).format("YYYY-MM-DD HH:MM")) + arr[index] = e; + } + return arr; +} \ No newline at end of file diff --git a/src/controller/models/Transaction.ts b/src/controller/models/Transaction.ts index c7770b6..4c22f3f 100644 --- a/src/controller/models/Transaction.ts +++ b/src/controller/models/Transaction.ts @@ -16,6 +16,7 @@ interface TransactionAttributes { Amount: number; Type: 'income' | 'expense' | 'transfer'; AccountID: number; + Refound:boolean // Other fields... } @@ -30,6 +31,7 @@ class Transaction extends Model { @@ -32,7 +40,8 @@ export class Router { res.status(500).send('Internal Server Error'); } }); - + let transactionR = TransactionRouter.routes(); + app.use('/transactions', transactionR) app.get('/users', async (req: Request, res: Response) => { try { const users = await User.findAll(); @@ -42,24 +51,18 @@ export class Router { res.status(500).send('Internal Server Error'); } }); - - app.get('/categories', async (req: Request, res: Response) => { - try { - const categories = await Category.findAll(); - res.render('categories', { title: 'Categories', categories }); - } catch (err) { - console.error(err); - res.status(500).send('Internal Server Error'); - } - }); - + let categoriesR = CategoryRouter.routes(); + app.use('/categories', categoriesR) + /* app.get('/transactions', async (req: Request, res: Response) => { try { const transactions = await Transaction.findAll({ include: Account }); + const categories = await Category.findAll({}); + const accounts = await Account.findAll({}); console.log(transactions) - res.render('transactions/transactions', { title: 'Transactions', transactions }); + res.render('transactions/transactions', { title: 'Transactions', transactions, categories, accounts }); } catch (err) { console.error(err); res.status(500).send('Internal Server Error'); @@ -97,7 +100,7 @@ export class Router { } }); - + */ app.listen(PORT, () => { diff --git a/src/controller/router/accounts.ts b/src/controller/router/accounts.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/controller/router/categories.ts b/src/controller/router/categories.ts new file mode 100644 index 0000000..3e7a162 --- /dev/null +++ b/src/controller/router/categories.ts @@ -0,0 +1,71 @@ +import express, { Request, Response } from 'express'; +import { Account, Category, Transaction } from "../models"; +import moment from "moment"; +import { convertDateArray } from '../helper/dateConversion'; + +export class CategoryRouter { + static routes() { + let router = express.Router(); + router.use((req, res, next) => { + console.log("TEST") + next() + }) + router.post('/addCategory',async(req,res)=>{ + let name = req.body.categoryName; + let description = req.body.categoryDescription; + await Category.create({ + Name:name, + Description:description + }) + res.redirect("/categories"); + //res.render('categories/listCategories', { title: 'Categories', categories }); + + }) + router.get('/addCategory',async(req,res)=>{ + try { + res.render('categories/formCategory', { title: 'Add Categories' }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }) + router.post('/modifyCategory/:id',async(req,res)=>{ + let name = req.body.categoryName; + let description = req.body.categoryDescription; + await Category.update({ + Name:name, + Description:description + },{ + where:{ + CategoryID:req.params.id + } + }) + res.redirect("/categories"); + //res.render('categories/listCategories', { title: 'Categories', categories }); + + }) + router.get('/modifyCategory/:id',async(req,res)=>{ + try { + let categoryObj = await Category.findOne({where:{ + CategoryID: req.params.id + }}) + res.render('categories/modifyCategory', { title: 'Add Categories',categoryObj }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }) + router.all('/', async (req, res) => { + try { + const categories = await Category.findAll({}); + const accounts = await Account.findAll({}); + res.render('categories/listCategories', { title: 'Categories', categories }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }) + + return router; + } +} \ No newline at end of file diff --git a/src/controller/router/transactions.ts b/src/controller/router/transactions.ts new file mode 100644 index 0000000..8c22674 --- /dev/null +++ b/src/controller/router/transactions.ts @@ -0,0 +1,160 @@ +import express, { Request, Response } from 'express'; +import { Account, Category, Transaction } from "../models"; +import moment from "moment"; +import { convertDateArray } from '../helper/dateConversion'; + +export class TransactionRouter { + static routes() { + let router = express.Router(); + router.use((req, res, next) => { + console.log("TEST") + next() + }) + + + router.post('/addTransaction', async (req, res, next) => { + console.log(req.body) + + try { + /* + if( + req.body.date == undefined + || req.body.Type == undefined + || req.body.CategoryID == undefined + || req.body.AccountID == undefined + ){throw "ERROR"} + */ + let date = moment(req.body.date).set({ + hour: req.body.time.split(":")[0], + minute:req.body.time.split(":")[1] + }) + console.log(date.toDate()) + await Transaction.create({ + Amount: req.body.amount, + Date: date.toDate(), + Type: req.body.type, + //@ts-ignore + UserID: 1, // Associate the transaction with the user + //@ts-ignore + CategoryID: req.body.category, + AccountID: req.body.account + }) + } catch (e) { + console.log(e) + } + res.redirect("/transactions"); + //next(); + }) + router.post('/addTransfer', async (req, res, next) => { + console.log(req.body) + + try { + /* + if( + req.body.date == undefined + || req.body.Type == undefined + || req.body.CategoryID == undefined + || req.body.AccountID == undefined + ){throw "ERROR"} + */ + let date = moment(req.body.date).set({ + hour: req.body.time.split(":")[0], + minute:req.body.time.split(":")[1] + }) + console.log(date.toDate()) + await Transaction.transferAmountFromTo(1,req.body.fromAccount,req.body.toAccount,req.body.amount,req.body.categoryID) + await Transaction.create({ + Amount: req.body.amount, + Date: date.toDate(), + Type: req.body.type, + //@ts-ignore + UserID: 1, // Associate the transaction with the user + //@ts-ignore + CategoryID: req.body.category, + AccountID: req.body.account + }) + } catch (e) { + console.log(e) + } + res.redirect("/transactions"); + //next(); + }) + router.get('/addTransaction', async (req, res) => { + try { + const transactions = await Transaction.findAll({ + include: Account + }); + const categories = await Category.findAll({order:[["Name","ASC"]]}); + const accounts = await Account.findAll({order:[["Name","ASC"]]}); + //console.log(transactions) + res.render('transactions/formTransaction', { title: 'Transactions', transactions, categories, accounts }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }) + router.get('/addTransfer', async (req, res) => { + try { + const transactions = await Transaction.findAll({ + include: Account + }); + const categories = await Category.findAll({order:[["Name","ASC"]]}); + const accounts = await Account.findAll({order:[["Name","ASC"]]}); + //console.log(transactions) + res.render('transactions/formTransfer', { title: 'Transactions', transactions, categories, accounts }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }) + + router.get('/acc/:acc', async (req: Request, res: Response) => { + try { + const transactions = await Transaction.findAll({ + include: [Account,Category], + where: { + AccountID: req.params.acc + } + }); + let arr = convertDateArray(transactions); + res.render('transactions/listTransactions', { title: 'Transactions', transactions:arr, cssClass:"" }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }); + router.get('/cat/:cat', async (req: Request, res: Response) => { + try { + const transactions = await Transaction.findAll({ + include: [Account, Category], + where: { + //@ts-ignore + CategoryID: req.params.cat + } + }); + let arr = convertDateArray(transactions); + res.render('transactions/listTransactions', { title: 'Transactions', transactions:arr, cssClass:"" }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }); + router.all('/', async (req, res) => { + try { + let transactions:any = await Transaction.findAll({ + include: [Account,Category] + }); + const categories = await Category.findAll({}); + const accounts = await Account.findAll({}); + let arr = convertDateArray(transactions); + console.log(transactions) + res.render('transactions/listTransactions', { title: 'Transactions', transactions: arr, categories, accounts, cssClass:"fullList" }); + } catch (err) { + console.error(err); + res.status(500).send('Internal Server Error'); + } + }) + + return router; + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2d46375..465bbfa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ import path from 'path'; import { fileURLToPath } from 'url'; import { Storage } from './controller/storage'; import { MonthlyReport } from './controller/models/MonthlyReport'; +import { testData } from './test-data'; Storage.__dirname = __dirname @@ -14,12 +15,16 @@ Storage.__dirname = __dirname let init = async () => { // Initialize Sequelize instance and define database connection - const sequelize = new Sequelize('sqlite::memory:', { + /*const sequelize = new Sequelize('sqlite::memory:', { host: 'localhost', dialect: 'sqlite', // Change this to your database dialect // Other options... }); - + */ + const sequelize = new Sequelize({ + dialect: 'sqlite', + storage:`${path.join(__dirname,'../data')}/database.sqlite` + }); User.initialize(sequelize); @@ -41,80 +46,13 @@ let init = async () => { await sequelize.sync({ force: true }); - await User.create({ - Name: "Max Mustermann", - Email: "test@test.de", - Password: "sdfsf" - }) - await Category.create({ - Name: "Allgemein", - Description: null - }) - await Category.create({ - Name:"Games", - Description:"Games" - }) - await Account.create({ - Name:"None" - }) - await Account.create({ - Name:"Bar" - }) - await Account.create({ - Name:"Konto1" - }) - - let z = await Transaction.create({ - Amount:50.0, - Date:new Date(), - Type:"expense", - //@ts-ignore - UserID: 1, // Associate the transaction with the user - //@ts-ignore - CategoryID: 1, - }) - - - await Transaction.create({ - Amount:10.0, - Date:new Date(), - Type:"expense", - //@ts-ignore - UserID: 1, // Associate the transaction with the user - //@ts-ignore - CategoryID: 1, - }) - await Transaction.create({ - Amount:60.0, - Date:new Date(), - Type:"income", - //@ts-ignore - UserID: 1, // Associate the transaction with the user - //@ts-ignore - CategoryID: 1, - }) - await Transaction.create({ - Amount:60.0, - Date:new Date(), - Type:"income", - //@ts-ignore - UserID: 1, // Associate the transaction with the user - //@ts-ignore - CategoryID: 2, - }) - - //await Transaction.transferAmountFromTo(1,1,2,50); - - - let x = await Transaction.getTotalAmountForUser(1) - await Transaction.transferAmountFromTo(1,1,2,50); - console.log(x) + await testData(User,Category,Account,MonthlyReport) new Router(path.join(__dirname,'../public')); - console.log(path.join(__dirname,'../public')) + //console.log(path.join(__dirname,'../public')) - MonthlyReport.generateMonthlyReport(12,2023,2) + //MonthlyReport.generateMonthlyReport(12,2023,2) } init(); \ No newline at end of file diff --git a/src/test-data.ts b/src/test-data.ts new file mode 100644 index 0000000..106a2fa --- /dev/null +++ b/src/test-data.ts @@ -0,0 +1,100 @@ +import { Account, Category, Transaction, User } from "./database" +import { MonthlyReport } from "./controller/models/MonthlyReport" + + + +export async function testData(User:any,Category:any,Account:any,MonthlyReport:any){ + await User.create({ + Name: "Max Mustermann", + Email: "test@test.de", + Password: "sdfsf" + }) + await Category.create({ + Name: "Allgemein", + Description: null + }) + await Category.create({ + Name:"Server", + Description:"Server" + }) + await Category.create({ + Name:"Games", + Description:"Games" + }) + await Category.create({ + Name:"Server/Netcup", + Description:"" + }) + await Category.create({ + Name:"Server/GPortal", + Description:"" + }) + await Category.create({ + Name:"Discord", + Description:"" + }) + await Category.create({ + Name:"Games/WarThunder" + }) + await Category.create({ + Name:"Games/Steam" + }) + await Category.create({ + Name:"Games/League" + }) + await Account.create({ + Name:"None" + }) + await Account.create({ + Name:"Bar" + }) + await Account.create({ + Name:"Girokonto" + }) + + let z = await Transaction.create({ + Amount:50.0, + Date:new Date(), + Type:"expense", + //@ts-ignore + UserID: 1, // Associate the transaction with the user + //@ts-ignore + CategoryID: 1, + }) + + + await Transaction.create({ + Amount:10.0, + Date:new Date(), + Type:"expense", + //@ts-ignore + UserID: 1, // Associate the transaction with the user + //@ts-ignore + CategoryID: 1, + }) + await Transaction.create({ + Amount:60.0, + Date:new Date(), + Type:"income", + //@ts-ignore + UserID: 1, // Associate the transaction with the user + //@ts-ignore + CategoryID: 1, + }) + await Transaction.create({ + Amount:60.0, + Date:new Date(), + Type:"expense", + //@ts-ignore + UserID: 1, // Associate the transaction with the user + //@ts-ignore + CategoryID: 2, + }) + + await Transaction.transferAmountFromTo(1,1,2,50); + + + let x = await Transaction.getTotalAmountForUser(1) + await Transaction.transferAmountFromTo(1,1,2,50); + //console.log(x) +} \ No newline at end of file diff --git a/views/categories/categories.pug b/views/categories/categories.pug new file mode 100644 index 0000000..4e1529a --- /dev/null +++ b/views/categories/categories.pug @@ -0,0 +1,10 @@ +extends ../layout/base.pug + +block nav + a(href="/categories") Categories + a(href="/categories/addCategory") + Category + +block headline + h1 Categories + +block content \ No newline at end of file diff --git a/views/categories/formCategory.pug b/views/categories/formCategory.pug new file mode 100644 index 0000000..6c475c2 --- /dev/null +++ b/views/categories/formCategory.pug @@ -0,0 +1,13 @@ +extends ./categories.pug + +block content + form(action="/categories/addCategory",method="POST") + .form-group + .text Name + .input + input(type="text", name="categoryName") + .form-group + .text Description + .input + textarea(name="categoryDescription", cols="30", rows="10") + button(type="submit") Add Category \ No newline at end of file diff --git a/views/categories/listCategories.pug b/views/categories/listCategories.pug new file mode 100644 index 0000000..3958f71 --- /dev/null +++ b/views/categories/listCategories.pug @@ -0,0 +1,20 @@ +extends ./categories.pug + +block content + table + thead + th.center ID + th Name + th Description + th Transactions + th Modify Category + tbody + each category in categories + tr + td=category.CategoryID + td=category.Name + td=category.Description + td + a(href=`/transactions/cat/${category.CategoryID}`) Transactions by Category + td + a(href=`/categories/ModifyCategory/${category.CategoryID}`) ### diff --git a/views/categories/modifyCategory.pug b/views/categories/modifyCategory.pug new file mode 100644 index 0000000..7f475c2 --- /dev/null +++ b/views/categories/modifyCategory.pug @@ -0,0 +1,13 @@ +extends ./categories.pug + +block content + form(action=`/categories/modifyCategory/${categoryObj.CategoryID}`,method="POST") + .form-group + .text Name + .input + input(type="text", name="categoryName",value=categoryObj.Name) + .form-group + .text Description + .input + textarea(name="categoryDescription", cols="30", rows="10")=categoryObj.Description + button(type="submit") Modify Category \ No newline at end of file diff --git a/views/layout/_navbar.pug b/views/layout/_navbar.pug new file mode 100644 index 0000000..3dd9af8 --- /dev/null +++ b/views/layout/_navbar.pug @@ -0,0 +1,5 @@ +nav + a(href="/") Home + a(href="/transactions") Transactions + a(href="/categories") Categories + a(href="/accounts") Accounts \ No newline at end of file diff --git a/views/layout/base.pug b/views/layout/base.pug index 2b6c4fb..0ca87fc 100644 --- a/views/layout/base.pug +++ b/views/layout/base.pug @@ -7,6 +7,11 @@ html block additionalAssets body + div.nav + include ./_navbar.pug + div.nav + block nav + div.container block headline diff --git a/views/transactions/_addTransactions.pug b/views/transactions/_addTransactions.pug new file mode 100644 index 0000000..948de5b --- /dev/null +++ b/views/transactions/_addTransactions.pug @@ -0,0 +1,41 @@ + +details + summary Create new transaction + + form(action="/transactions",method="POST") + div.form-group + .text Description + .input + textarea(name="description", cols="30", rows="5") Test + div.form-group.half + .text Date + .input + input(type="date",name="date") + div.form-group.half + .text Time + .input + input(type="time",name="time") + div.form-group.half + .text Type + .input + select(name="type") + option(value="income") Income + option(value="expense",select) Expense + option(value="transfer") Transfer + div.form-group.half + .text Amount + .input + input(type="text",name="amount",required) + div.form-group + .text Account + .input + select(name="account") + each account in accounts + option(value=account.AccountID)=account.Name + div.form-group + .text Category + .input + select(name="category") + each category in categories + option(value=category.CategoryID,title=category.Description)=category.Name + button(type="submit") Add Transaction \ No newline at end of file diff --git a/views/transactions/formTransaction.pug b/views/transactions/formTransaction.pug new file mode 100644 index 0000000..2576b88 --- /dev/null +++ b/views/transactions/formTransaction.pug @@ -0,0 +1,39 @@ +extends ./transactions.pug +block content + form(action="/transactions/addTransaction",method="POST") + div.form-group + .text Description + .input + textarea(name="description", cols="30", rows="5") + div.form-group.half + .text Date + .input + input(type="date",name="date") + div.form-group.half + .text Time + .input + input(type="time",name="time") + div.form-group.half + .text Type + .input + select(name="type") + option(value="income") Income + option(value="expense",select) Expense + option(value="transfer") Transfer + div.form-group.half + .text Account + .input + select(name="account") + each account in accounts + option(value=account.AccountID)=account.Name + div.form-group.half + .text Amount + .input + input(type="number",min="0",step="0.01",name="amount",required) + div.form-group.half + .text Category + .input + select(name="category") + each category in categories + option(value=category.CategoryID,title=category.Description)=category.Name + button(type="submit") Add Transaction \ No newline at end of file diff --git a/views/transactions/formTransfer.pug b/views/transactions/formTransfer.pug new file mode 100644 index 0000000..5ecf7df --- /dev/null +++ b/views/transactions/formTransfer.pug @@ -0,0 +1,40 @@ +extends ./transactions.pug + +block content + form(action="/transactions/addTransfer",method="POST") + div.form-group + .text Description + .input + textarea(name="description", cols="30", rows="5") + div.form-group.half + .text Date + .input + input(type="date",name="date") + div.form-group.half + .text Time + .input + input(type="time",name="time") + + div.form-group.half + .text from Account + .input + select(name="fromAccount") + each account in accounts + option(value=account.AccountID)=account.Name + div.form-group.half + .text to Account + .input + select(name="toAccount") + each account in accounts + option(value=account.AccountID)=account.Name + div.form-group.half + .text Amount + .input + input(type="number",min="0",step="0.01",name="amount",required) + div.form-group.half + .text Category + .input + select(name="category") + each category in categories + option(value=category.CategoryID,title=category.Description)=category.Name + button(type="submit") Add Transaction \ No newline at end of file diff --git a/views/transactions/listTransactions.pug b/views/transactions/listTransactions.pug new file mode 100644 index 0000000..cc0c733 --- /dev/null +++ b/views/transactions/listTransactions.pug @@ -0,0 +1,22 @@ +extends ./transactions.pug + +block content + table(class=`${cssClass}`) + thead + th ID + th Date + th Description + th Category + th Account + th.right Amount + tbody + each transaction in transactions + tr(class=`${transaction.Type}`) + td=transaction.TransactionID + td=transaction.Date2 + td=transaction.Description + td + a(href=`/transactions/cat/${transaction.Category.CategoryID}`)=transaction.Category.Name + td + a(href=`/transactions/acc/${transaction.Account.AccountID}`)=transaction.Account.Name + td(class=`${transaction.Type} amount` )=transaction.Amount \ No newline at end of file diff --git a/views/transactions/transactions.pug b/views/transactions/transactions.pug index 4e82d83..efe7c95 100644 --- a/views/transactions/transactions.pug +++ b/views/transactions/transactions.pug @@ -1,24 +1,11 @@ extends ../layout/base.pug +block nav + a(href="/transactions") Transactions + a(href="/transactions/addTransaction") + Transaction + a(href="/transactions/addTransfer") + Transfer + block headline h1 Transactions -block content - form(action="/tansactions",method="POST") - - - table - thead - th ID - th Date - th Description - th Account - th Amount - tbody - each transaction in transactions - tr - td=transaction.TransactionID - td=transaction.Date - td=transaction.Description - td=transaction.Account.Name - td(class=`${transaction.Type} amount` )=transaction.Amount \ No newline at end of file +block content \ No newline at end of file