Skip to content

Commit

Permalink
improve posting ui
Browse files Browse the repository at this point in the history
  • Loading branch information
ananthakumaran committed Nov 19, 2023
1 parent 46fac22 commit 0d646f6
Show file tree
Hide file tree
Showing 47 changed files with 962 additions and 630 deletions.
20 changes: 0 additions & 20 deletions flake/node-package.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion internal/accounting/accounting.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ type Point struct {
}

func RunningBalance(db *gorm.DB, postings []posting.Posting) []Point {
sort.Slice(postings, func(i, j int) bool { return postings[i].Date.Before(postings[j].Date) })
SortAsc(postings)
var series []Point

if len(postings) == 0 {
Expand Down Expand Up @@ -186,6 +186,27 @@ func RunningBalance(db *gorm.DB, postings []posting.Posting) []Point {
return series
}

func SortAsc(postings []posting.Posting) []posting.Posting {
sort.Slice(postings, func(i, j int) bool { return postings[i].Date.Before(postings[j].Date) })
return postings
}

func SortDesc(postings []posting.Posting) []posting.Posting {
sort.Slice(postings, func(i, j int) bool { return postings[i].Date.After(postings[j].Date) })
return postings
}

func PopulateBalance(postings []posting.Posting) []posting.Posting {
SortAsc(postings)
accumulator := make(map[string]decimal.Decimal)

for i, p := range postings {
accumulator[p.Account] = accumulator[p.Account].Add(p.Quantity)
postings[i].Balance = accumulator[p.Account]
}
return postings
}

func GroupByAccount(posts []posting.Posting) map[string][]posting.Posting {
return lo.GroupBy(posts, func(post posting.Posting) string {
return post.Account
Expand Down
1 change: 1 addition & 0 deletions internal/model/posting/posting.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Posting struct {
Forecast bool `json:"forecast"`

MarketAmount decimal.Decimal `gorm:"-:all" json:"market_amount"`
Balance decimal.Decimal `gorm:"-:all" json:"balance"`

behaviours []string `gorm:"-:all"`
}
Expand Down
3 changes: 3 additions & 0 deletions internal/server/ledger.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package server

import (
"github.com/ananthakumaran/paisa/internal/accounting"
"github.com/ananthakumaran/paisa/internal/query"
"github.com/ananthakumaran/paisa/internal/service"
"github.com/gin-gonic/gin"
Expand All @@ -10,5 +11,7 @@ import (
func GetLedger(db *gorm.DB) gin.H {
postings := query.Init(db).Desc().All()
postings = service.PopulateMarketPrice(db, postings)
postings = accounting.PopulateBalance(postings)
accounting.SortDesc(postings)
return gin.H{"postings": postings}
}
4 changes: 2 additions & 2 deletions internal/server/liabilities/interest.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package liabilities

import (
"sort"
"time"

"github.com/ananthakumaran/paisa/internal/accounting"
"github.com/ananthakumaran/paisa/internal/model/posting"
"github.com/ananthakumaran/paisa/internal/query"
"github.com/ananthakumaran/paisa/internal/service"
Expand Down Expand Up @@ -43,7 +43,7 @@ func GetInterest(db *gorm.DB) gin.H {
}

func computeOverviewTimeline(db *gorm.DB, postings []posting.Posting) []Overview {
sort.Slice(postings, func(i, j int) bool { return postings[i].Date.Before(postings[j].Date) })
accounting.SortAsc(postings)
netliabilities := []Overview{}

var p posting.Posting
Expand Down
24 changes: 0 additions & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"chroma-js": "^2.4.2",
"chrono-node": "^2.6.6",
"clipboard": "^2.0.11",
"clusterize.js": "^0.19.0",
"codemirror": "^6.0.1",
"compute-cosine-similarity": "^1.0.0",
"d3": "^7.4.0",
Expand Down Expand Up @@ -70,7 +69,6 @@
"@sveltejs/adapter-static": "^1.0.0",
"@sveltejs/kit": "^1.20.4",
"@types/chroma-js": "^2.1.4",
"@types/clusterize.js": "^0.18.1",
"@types/d3": "^7.4.0",
"@types/json-diff": "^1.0.0",
"@types/lodash": "^4.14.194",
Expand Down
11 changes: 11 additions & 0 deletions src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -973,3 +973,14 @@ textarea:invalid {
[data-tippy-root] {
font-family: $family-sans-serif-icon;
}

.posting-row {
grid-template-columns: 6rem 20rem 16rem 8rem 10rem 8rem 6rem 6rem 6rem 6rem;
grid-auto-flow: column;
overflow-x: auto;
border-bottom: 1px solid rgba($grey-lightest, 0.5);
}

div.is-hoverable:hover {
background-color: $white-bis;
}
1 change: 0 additions & 1 deletion src/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@ $fa-font-path: "../node_modules/@fortawesome/fontawesome-free/webfonts";

@import "tippy.js/dist/tippy.css";
@import "tippy.js/themes/light.css";
@import "clusterize.js/clusterize.css";
@import "./theme-switcher.scss";
@import "./responsive.scss";
108 changes: 30 additions & 78 deletions src/lib/posting.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,41 @@
import _ from "lodash";
import Clusturize from "clusterize.js";
import { formatCurrency, formatFloat, postingUrl, type Posting, firstName, now } from "./utils";
import { iconText } from "./icon";
import { accountColorStyle } from "./colors";
import { now, type Posting } from "./utils";

export function renderPostings(postings: Posting[]) {
const rows = _.map(postings, (p) => {
const purchase = formatCurrency(p.amount);
const date = p.date.format("DD MMM YYYY");

let market = "",
change = "",
changePercentage = "",
changeClass = "",
price = "",
units = "";
if (p.commodity !== USER_CONFIG.default_currency) {
units = formatFloat(p.quantity, 4);
price = formatCurrency(Math.abs(p.amount / p.quantity), 4);
const days = now().diff(p.date, "days");
if (p.quantity > 0 && days > 0) {
market = formatCurrency(p.market_amount);
const changeAmount = p.market_amount - p.amount;
if (changeAmount > 0) {
changeClass = "has-text-success";
} else if (changeAmount < 0) {
changeClass = "has-text-danger";
}
const perYear = 365 / days;
changePercentage = formatFloat((changeAmount / p.amount) * 100 * perYear);
change = formatCurrency(changeAmount);
}
}
export interface Change {
class: string;
value: number;
percentage: number;
days: number;
}

let postingStatus = "";
if (p.status == "cleared")
postingStatus = `<span class="icon is-small">
<i class="fa-solid fa-check"></i>
</span>`;
else {
if (p.status == "pending") {
postingStatus = `<span class="icon is-small">
<i class="fa-solid fa-exclamation"></i>
</span>`;
export function change(p: Posting): Change {
let changePercentage = 0,
days = 0,
changeAmount = 0,
changeClass = "";
if (p.commodity !== USER_CONFIG.default_currency) {
days = now().diff(p.date, "days");
if (p.quantity > 0 && days > 0) {
changeAmount = p.market_amount - p.amount;
if (changeAmount > 0) {
changeClass = "has-text-success";
} else if (changeAmount < 0) {
changeClass = "has-text-danger";
}
const perYear = 365 / days;
changePercentage = (changeAmount / p.amount) * 100 * perYear;
}
}

const markup = `
<tr>
<td class='whitespace-nowrap'>${date}</td>
<td class='is-size-7' style='vertical-align: middle'>${postingStatus}<a class="secondary-link" href=${postingUrl(
p
)}>${p.payee}</a></td>
<td class='custom-icon'><span style='${accountColorStyle(firstName(p.account))}'>${iconText(
p.account
)}</span> ${p.account}</td>
<td class='has-text-right'>${purchase}</td>
<td class='has-text-right'>${units}</td>
<td class='has-text-right'>${price}</td>
<td class='has-text-right'>${market}</td>
<td class='${changeClass} has-text-right'>${change}</td>
<td class='${changeClass} has-text-right'>${changePercentage}</td>
</tr>
`;
return {
date: date,
markup: markup,
posting: p
};
});

const clusterTable = new Clusturize({
rows: _.map(rows, (r) => r.markup),
scrollId: "d3-postings-container",
contentId: "d3-postings",
rows_in_block: 100
});

return { rows, clusterTable };
return {
class: changeClass,
value: changeAmount,
percentage: changePercentage,
days
};
}

export function filterPostings(
rows: { date: string; posting: Posting; markup: string }[],
filter: string
) {
export function filterPostings(rows: { date: string; posting: Posting }[], filter: string) {
let filterRegex = new RegExp(".*", "i");
if (filter) {
filterRegex = new RegExp(filter, "i");
Expand Down
4 changes: 3 additions & 1 deletion src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ export interface Posting {
commodity: string;
quantity: number;
amount: number;
market_amount: number;
status: string;
tag_recurring: string;
transaction_begin_line: number;
transaction_end_line: number;
file_name: string;

market_amount: number;
balance: number;
}

export interface CashFlow {
Expand Down
Loading

0 comments on commit 0d646f6

Please sign in to comment.