Skip to content

Commit

Permalink
Merge pull request #307 from letehaha/fix/issues
Browse files Browse the repository at this point in the history
fix: Minor fixes and improvements
  • Loading branch information
letehaha authored Sep 16, 2024
2 parents dadf0a7 + b41cbd5 commit 1b6427c
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 79 deletions.
9 changes: 9 additions & 0 deletions src/common/utils/remove-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function removeNullishValues<T extends object>(obj: T): Partial<T> {
return Object.entries(obj).reduce((acc, [key, value]) => {
if (value === null || value === undefined) {
return acc;
}
acc[key as keyof T] = value;
return acc;
}, {} as Partial<T>);
}
2 changes: 1 addition & 1 deletion src/components/fields/category-select-field.vue
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ onBeforeUnmount(() => {
}
.category-select-field__dropdown-values {
overflow: auto;
max-height: 250px;
max-height: 350px;
}
.category-select-field__dropdown-item {
display: flex;
Expand Down
16 changes: 4 additions & 12 deletions src/components/modals/modify-record/components/account-field.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@
<form-row>
<input-field model-value="No account exists" label="Account" readonly :disabled="disabled">
<template #label-right>
<div class="account-field__create-account" @click="redirectToCreateAccountPage">
<div
class="text-primary cursor-pointer hover:underline"
@click="redirectToCreateAccountPage"
>
Create account
</div>
</template>
Expand Down Expand Up @@ -101,14 +104,3 @@ const updateFormAccount = (account: AccountModel) => {
emit("update:account", account);
};
</script>

<style lang="scss" scoped>
.account-field__create-account {
color: var(--primary-500);
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
</style>
2 changes: 1 addition & 1 deletion src/components/modals/modify-record/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ useEventListener(document, "keydown", (event) => {
/>
<div class="flex items-center justify-between py-3 px-6 mb-4">
<span class="text-2xl">
{{ isFormCreation ? "Add Record" : "Edit Record" }}
{{ isFormCreation ? "Add Transaction" : "Edit Transaction" }}
</span>

<Button variant="ghost" @click="closeModal"> Close </Button>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui-header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="layout-header">
<div class="layout-header__actions">
<div class="layout-header__action">
<ui-button variant="default" size="lg" @click="openFormModal"> New Record </ui-button>
<ui-button variant="default" size="lg" @click="openFormModal"> New Transaction </ui-button>
</div>
</div>

Expand Down
66 changes: 42 additions & 24 deletions src/components/ui-sidebar.vue
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
<template>
<Card class="sidebar">
<CardHeader>
<div class="sidebar__logo">BudgetTracker</div>
<div class="sidebar__logo">
<span class="hidden md:block"> BudgetTracker </span>
<span class="md:hidden"> BT </span>
</div>
</CardHeader>
<CardContent class="sidebar__content">
<CardContent class="px-3 md:px-6 flex flex-col flex-grow">
<nav class="sidebar__navigation">
<router-link v-slot="{ isActive }" :to="{ name: ROUTES_NAMES.home }">
<ui-button
:variant="isActive ? 'default' : 'ghost'"
as="span"
class="justify-start w-full px-3"
class="sidebar__item"
size="lg"
>
Dashboard
<LayoutDashboardIcon />
<span> Dashboard </span>
</ui-button>
</router-link>

<router-link v-slot="{ isActive }" :to="{ name: ROUTES_NAMES.accounts }">
<ui-button
:variant="isActive ? 'default' : 'ghost'"
as="span"
class="justify-start w-full px-3"
class="sidebar__item"
size="lg"
>
Accounts
<LayersIcon />
<span> Accounts </span>
</ui-button>
</router-link>

<router-link v-slot="{ isActive }" :to="{ name: ROUTES_NAMES.records }">
<router-link v-slot="{ isActive }" :to="{ name: ROUTES_NAMES.transactions }">
<ui-button
:variant="isActive ? 'default' : 'ghost'"
as="span"
class="justify-start w-full px-3"
class="sidebar__item"
size="lg"
>
Records
<CreditCardIcon />
<span> Transactions </span>
</ui-button>
</router-link>

Expand All @@ -43,10 +49,11 @@
<ui-button
:variant="isActive ? 'default' : 'ghost'"
as="span"
class="justify-start w-full px-3"
class="sidebar__item"
size="lg"
>
Analytics (dev only)
<ChartAreaIcon />
<span> Analytics (dev only) </span>
</ui-button>
</router-link>
</template>
Expand All @@ -56,27 +63,30 @@
<ui-button
:variant="isActive ? 'default' : 'ghost'"
as="span"
class="justify-start w-full px-3"
class="sidebar__item"
size="lg"
>
Crypto (dev only)
<BitcoinIcon />
<span> Crypto (dev only) </span>
</ui-button>
</router-link>
</template>
<router-link v-slot="{ isActive }" :to="{ name: ROUTES_NAMES.settings }">
<ui-button
:variant="isActive ? 'default' : 'ghost'"
as="span"
class="justify-start w-full px-3"
class="sidebar__item"
size="lg"
>
Settings
<SettingsIcon />
<span> Settings </span>
</ui-button>
</router-link>
</nav>

<ui-button variant="secondary" class="sidebar__logout" @click="logOutHandler">
Logout
<ui-button variant="secondary" class="sidebar__item mt-auto" @click="logOutHandler">
<LogOutIcon />
<span> Logout </span>
</ui-button>
</CardContent>
</Card>
Expand All @@ -88,6 +98,15 @@ import { useRouter } from "vue-router";
import { useAuthStore } from "@/stores";
import { isDevEnv } from "@/common/const";
import { ROUTES_NAMES } from "@/routes";
import {
LayoutDashboardIcon,
CreditCardIcon,
LayersIcon,
ChartAreaIcon,
BitcoinIcon,
SettingsIcon,
LogOutIcon,
} from "lucide-vue-next";
import UiButton from "@/components/lib/ui/button/Button.vue";
import { Card, CardContent, CardHeader } from "@/components/lib/ui/card";
Expand All @@ -111,8 +130,12 @@ const logOutHandler = () => {
text-align: center;
color: var(--abc-text-white-base);
}
.sidebar__content {
@apply flex flex-col flex-grow;
.sidebar__item {
@apply justify-start w-full px-3 gap-2;
span {
@apply hidden md:block;
}
}
.sidebar__navigation {
display: grid;
Expand Down Expand Up @@ -142,9 +165,4 @@ const logOutHandler = () => {
}
}
}
.sidebar__logout {
margin-top: auto;
width: 100%;
justify-content: flex-start;
}
</style>
4 changes: 2 additions & 2 deletions src/components/widgets/expenses-structure.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

<div
:class="{
'text-[var(--app-error)]': expensesDiff < 0,
'text-[var(--app-success)]': expensesDiff > 0,
'text-[var(--app-error)]': expensesDiff > 0,
'text-[var(--app-success)]': expensesDiff < 0,
}"
>
{{ `${expensesDiff}%` }}
Expand Down
7 changes: 5 additions & 2 deletions src/components/widgets/latest-records.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<template>
<WidgetWrapper class="latest-records-widget" title="Latest records" higher>
<WidgetWrapper class="latest-records-widget" title="Latest Transactions" higher>
<template #action>
<template v-if="!isDataEmpty">
<router-link class="latest-records-widget__show-all" :to="{ name: ROUTES_NAMES.records }">
<router-link
class="latest-records-widget__show-all"
:to="{ name: ROUTES_NAMES.transactions }"
>
<ui-button variant="link" as="span" size="sm"> Show all </ui-button>
</router-link>
</template>
Expand Down
42 changes: 26 additions & 16 deletions src/js/helpers/math/calculate-percentage-difference.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,45 @@ import { calculatePercentageDifference } from "./calculate-percentage-difference
describe("calculatePercentageDifference", () => {
test.each([
[0, 0, 0, "returns 0 when both numbers are 0"],
[0, 10, 100, "returns 100 when one number is 0"],
[10, 0, 100, "returns 100 when one number is 0"],
[20, -20, 100, "returns 100 when numbers have opposite signs"],
[-15, 15, 100, "returns 100 when numbers have opposite signs"],
[0, 10, -100, "returns -100 when first number is 0"],
[10, 0, 100, "returns 100 when second number is 0"],
[20, -20, 100, "returns 100 when numbers have opposite signs (positive to negative)"],
[-15, 15, -100, "returns -100 when numbers have opposite signs (negative to positive)"],
[100, 90, 10.53, "calculates correct percentage for positive numbers"],
[90, 100, -10.53, "calculates correct negative percentage for positive numbers"],
[50, 40, 22.22, "calculates correct percentage for positive numbers"],
[-100, -90, 10.53, "calculates correct percentage for negative numbers"],
[-50, -40, 22.22, "calculates correct percentage for negative numbers"],
[-10, 10, 100, "calculates correct percentage for mixed positive and negative numbers"],
[1, 1000000, 100, "returns 100 for very large differences"],
[-1000000, 1, 100, "returns 100 for very large differences"],
[0.1, 0.2, 66.67, "handles floating point numbers"],
[1.5, 2.5, 50, "handles floating point numbers"],
[NaN, 10, 100, "treats NaN as 0"],
[40, 50, -22.22, "calculates correct negative percentage for positive numbers"],
[-100, -90, -10.53, "calculates correct percentage for negative numbers"],
[-90, -100, 10.53, "calculates correct positive percentage for negative numbers"],
[-50, -40, -22.22, "calculates correct percentage for negative numbers"],
[-40, -50, 22.22, "calculates correct positive percentage for negative numbers"],
[-10, 10, -100, "calculates correct percentage for mixed positive and negative numbers"],
[10, -10, 100, "calculates correct percentage for mixed positive and negative numbers"],
[1, 1000000, -99.9998, "calculates percentage for very large differences"],
[-1000000, 1, -100, "returns -100 for very large negative differences"],
[0.1, 0.2, -66.67, "handles floating point numbers"],
[0.2, 0.1, 66.67, "handles floating point numbers (reverse)"],
[1.5, 2.5, -50, "handles floating point numbers"],
[2.5, 1.5, 50, "handles floating point numbers (reverse)"],
[NaN, 10, -100, "treats NaN as 0"],
[10, NaN, 100, "treats NaN as 0"],
[NaN, NaN, 0, "treats NaN as 0 (both NaN)"],
[Infinity, 10, 100, "treats Infinity as 0"],
[Infinity, 10, -100, "treats Infinity as 0"],
[10, Infinity, 100, "treats Infinity as 0"],
[Infinity, Infinity, 0, "treats Infinity as 0 (both Infinity)"],
[-Infinity, 10, 100, "treats -Infinity as 0"],
[-Infinity, 10, -100, "treats -Infinity as 0"],
[10, -Infinity, 100, "treats -Infinity as 0"],
[-Infinity, -Infinity, 0, "treats -Infinity as 0 (both -Infinity)"],
])("(%f, %f) = %f (%s)", (a, b, expected) => {
expect(calculatePercentageDifference(a, b)).toBeCloseTo(expected, 2);
});

test("is symmetric", () => {
test("is not symmetric", () => {
const a = 10;
const b = 20;
expect(calculatePercentageDifference(a, b)).toBeCloseTo(calculatePercentageDifference(b, a), 5);
expect(calculatePercentageDifference(a, b)).toBeCloseTo(
-calculatePercentageDifference(b, a),
5,
);
});
});
9 changes: 5 additions & 4 deletions src/js/helpers/math/calculate-percentage-difference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ export function calculatePercentageDifference(_a: number, _b: number): number {

// If one number is zero and the other isn't, it's a 100% difference
if (a === 0 || b === 0) {
return 100;
return a > b ? 100 : -100;
}

// If the numbers have opposite signs
if ((a > 0 && b < 0) || (a < 0 && b > 0)) {
return 100;
return a > b ? 100 : -100;
}

const difference = Math.abs(a - b);
const difference = a - b;
const average = (Math.abs(a) + Math.abs(b)) / 2;

return Math.min(100, (difference / average) * 100);
const percent = (difference / average) * 100;
return Math.max(-100, Math.min(100, percent));
}
2 changes: 1 addition & 1 deletion src/pages/account/account.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<Card.CardContent>
<Tabs.Tabs default-value="records">
<Tabs.TabsList class="justify-start w-full">
<Tabs.TabsTrigger value="records"> Records </Tabs.TabsTrigger>
<Tabs.TabsTrigger value="records"> Transactions </Tabs.TabsTrigger>
<Tabs.TabsTrigger disabled value="analytics"> Analytics (soon) </Tabs.TabsTrigger>
</Tabs.TabsList>
<Tabs.TabsContent value="records">
Expand Down
6 changes: 3 additions & 3 deletions src/pages/accounts/accounts.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<div class="accounts">
<div class="flex items-center justify-between gap-8 mb-6">
<div class="flex items-center flex-wrap justify-between gap-x-8 gap-y-4 mb-6">
<h1 class="text-2xl tracking-wider">Accounts</h1>

<div class="flex gap-4">
<div class="flex gap-x-4 gap-y-2 flex-wrap">
<router-link :to="{ name: ROUTES_NAMES.createAccount }">
<UiButton as="span"> Create account </UiButton>
</router-link>
Expand Down Expand Up @@ -32,7 +32,7 @@
</div>

<template v-if="formattedAccounts.length">
<div class="accounts__list">
<div class="grid gap-3 mb-6 grid-cols-[repeat(auto-fill,minmax(240px,1fr))]">
<template v-for="account in formattedAccounts" :key="account.id">
<Card :class="cn('relative', !account.isEnabled && 'opacity-40')">
<router-link
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard/accounts-list/accounts-list.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="grid gap-2 grid-cols-[repeat(auto-fit,180px)]">
<div class="grid gap-2 grid-cols-[repeat(auto-fill,minmax(180px,1fr))]">
<template v-if="noAccountsExist">
<Card>
<RouterLink to="/create-account">
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard/dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const selectNextPeriod = () => {
grid-template-areas: "balance-trend spending-categories latest-records";
grid-gap: 24px;
@include below(1200) {
@include below(1300) {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-areas: "balance-trend spending-categories" "latest-records latest-records";
}
Expand Down
14 changes: 7 additions & 7 deletions src/pages/settings/subpages/categories/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import InputField from "@/components/fields/input-field.vue";
import UiButton from "@/components/common/ui-button.vue";
import { type FormattedCategory } from "@/common/types";
import { ApiErrorResponseError } from "@/js/errors";
import { removeNullishValues } from "@/common/utils/remove-keys";
defineOptions({
name: "settings-categories",
Expand Down Expand Up @@ -153,18 +154,17 @@ const applyChanges = async () => {
name: form.name,
});
} else if (isCreating.value) {
let params: Parameters<typeof createCategory>[0] = {
name: form.name,
imageUrl: "",
color: "",
};
type InputParams = Parameters<typeof createCategory>[0];
let params: InputParams = { name: form.name };
if (selectedCategory.value) {
params = {
params = removeNullishValues({
...params,
imageUrl: selectedCategory.value.imageUrl,
color: selectedCategory.value.color,
parentId: selectedCategory.value.id,
};
}) as InputParams;
}
await createCategory(params);
}
Expand Down
Loading

0 comments on commit 1b6427c

Please sign in to comment.