diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 00000000..2785bc1d --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +yarn commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..0cd82b65 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +yarn \ No newline at end of file diff --git a/app/Domains/Transaction/Services/ReportService.php b/app/Domains/Transaction/Services/ReportService.php index 2ee1738c..6457c7d5 100644 --- a/app/Domains/Transaction/Services/ReportService.php +++ b/app/Domains/Transaction/Services/ReportService.php @@ -58,10 +58,27 @@ public static function generateExpensesByPeriod($teamId, $startDate, $timeUnitDi }, $resultGroup)->sortBy('date'); } - public static function getAssignedByPeriod($teamId, $startDate, $timeUnitDiff = 2, $timeUnit = 'month', $categories = null) + public static function generateExpensesByPeriodInDate($teamId, $startDate, $endDate, $categories = null) { - $rangeEndAt = Carbon::createFromFormat('Y-m-d', $startDate)->endOfMonth()->format('Y-m-d'); - $rangeStartAt = Carbon::now()->subMonth($timeUnitDiff)->startOfMonth()->format('Y-m-d'); + $rangeStartAt = Carbon::createFromFormat('Y-m-d', $startDate)->startOfMonth()->format('Y-m-d'); + $rangeEndAt = Carbon::createFromFormat('Y-m-d', $endDate)->endOfMonth()->format('Y-m-d'); + + $results = self::getExpensesByCategoriesInPeriod($teamId, $rangeStartAt, $rangeEndAt, $categories); + $resultGroup = $results->groupBy('date'); + + return $resultGroup->map(function ($monthItems) { + return [ + 'date' => $monthItems->first()->date, + 'data' => $monthItems->sortByDesc('total_amount')->values(), + 'total' => $monthItems->sum('total_amount'), + ]; + }, $resultGroup)->sortBy('date'); + } + + public static function getAssignedByPeriod($teamId, $startDate, $endDate, $categories = null) + { + $rangeStartAt = Carbon::createFromFormat('Y-m-d', $startDate)->startOfMonth()->format('Y-m-d'); + $rangeEndAt = Carbon::createFromFormat('Y-m-d', $endDate)->endOfMonth()->format('Y-m-d'); $results = self::getAssignedByCategoriesInPeriod($teamId, $rangeStartAt, $rangeEndAt, $categories); $resultGroup = $results->groupBy('date'); diff --git a/app/Http/Controllers/Finance/FinanceTrendController.php b/app/Http/Controllers/Finance/FinanceTrendController.php index c5572f04..e2da3832 100644 --- a/app/Http/Controllers/Finance/FinanceTrendController.php +++ b/app/Http/Controllers/Finance/FinanceTrendController.php @@ -210,13 +210,19 @@ public function spendingYear() $excludedAccounts = collect(explode(',', $filters['category']))->map(fn ($id) => "-$id")->all(); } + $endDate = Carbon::createFromFormat('Y-m-d', $startDate)->endOfYear()->format('Y-m-d'); + $startDate = Carbon::createFromFormat('Y-m-d', $startDate)->startOfYear()->format('Y-m-d'); + + $monthlyExpensesInYear = ReportService::generateExpensesByPeriodInDate($teamId, $startDate, $endDate, $excludedAccounts); + return [ - 'data' => ReportService::generateExpensesByPeriod($teamId, $startDate, 12, 'month', $excludedAccounts), + 'data' => $monthlyExpensesInYear, 'metaData' => [ 'name' => 'spendingYear', - 'title' => 'Expenses', + 'title' => 'Expenses this year', 'props' => [ 'headerTemplate' => 'grid', + 'total' => $monthlyExpensesInYear->sum('total'), ], ], ]; @@ -233,13 +239,19 @@ public function assignedInYear() $excludedAccounts = collect(explode(',', $filters['category']))->map(fn ($id) => "-$id")->all(); } + $endDate = Carbon::createFromFormat('Y-m-d', $startDate)->endOfYear()->format('Y-m-d'); + $startDate = Carbon::createFromFormat('Y-m-d', $startDate)->startOfYear()->format('Y-m-d'); + + $assignedInYear = ReportService::getAssignedByPeriod($teamId, $startDate, $endDate, $excludedAccounts); + return [ - 'data' => ReportService::getAssignedByPeriod($teamId, $startDate, 12, 'month', $excludedAccounts), + 'data' => $assignedInYear, 'metaData' => [ 'name' => 'assignedYear', 'title' => 'Assigned in year', 'props' => [ 'headerTemplate' => 'grid', + 'total' => $assignedInYear->sum('total'), ], ], ]; diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..3f5e287f --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1 @@ +export default { extends: ['@commitlint/config-conventional'] }; diff --git a/components.d.ts b/components.d.ts index 285f8b56..fe2a977d 100644 --- a/components.d.ts +++ b/components.d.ts @@ -7,7 +7,6 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { - IFluentFoodApple20Filled: typeof import('~icons/fluent/food-apple20-filled')['default'] IIonEllipsisVertical: typeof import('~icons/ion/ellipsis-vertical')['default'] IMaterialSymbolsBrightnessAlertOutlineRounded: typeof import('~icons/material-symbols/brightness-alert-outline-rounded')['default'] IMdiBankTransfer: typeof import('~icons/mdi/bank-transfer')['default'] @@ -16,11 +15,10 @@ declare module 'vue' { IMdiBell: typeof import('~icons/mdi/bell')['default'] IMdiCallSplit: typeof import('~icons/mdi/call-split')['default'] IMdiCheck: typeof import('~icons/mdi/check')['default'] - IMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] IMdiChevronLeft: typeof import('~icons/mdi/chevron-left')['default'] IMdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] - IMdiChevronUp: typeof import('~icons/mdi/chevron-up')['default'] IMdiClose: typeof import('~icons/mdi/close')['default'] + IMdiEdit: typeof import('~icons/mdi/edit')['default'] IMdiEllipsisVertical: typeof import('~icons/mdi/ellipsis-vertical')['default'] IMdiEmailCheck: typeof import('~icons/mdi/email-check')['default'] IMdiExport: typeof import('~icons/mdi/export')['default'] @@ -31,6 +29,9 @@ declare module 'vue' { IMdiLock: typeof import('~icons/mdi/lock')['default'] IMdiMinus: typeof import('~icons/mdi/minus')['default'] IMdiMoney: typeof import('~icons/mdi/money')['default'] + IMdiPlus: typeof import('~icons/mdi/plus')['default'] + IMdiSearch: typeof import('~icons/mdi/search')['default'] + IMdiSort: typeof import('~icons/mdi/sort')['default'] IMdiStar: typeof import('~icons/mdi/star')['default'] IMdiStarOutline: typeof import('~icons/mdi/star-outline')['default'] IMdiSync: typeof import('~icons/mdi/sync')['default'] diff --git a/package.json b/package.json index 1636835d..d0270787 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,12 @@ "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs", "docs:preview": "vitepress preview docs", - "release": "commit-and-tag-version" + "release": "commit-and-tag-version", + "prepare": "husky" }, "devDependencies": { + "@commitlint/cli": "^19.3.0", + "@commitlint/config-conventional": "^19.2.2", "@headlessui/vue": "^1.7.22", "@iconify-json/clarity": "^1.1.13", "@iconify-json/fluent": "^1.1.59", @@ -58,6 +61,7 @@ "eslint-plugin-vue": "^9.27.0", "exact-math": "^2.2.3", "firebase": "^10.12.4", + "husky": "^9.1.3", "laravel-vite-plugin": "^1.0.5", "lodash": "^4.17.21", "naive-ui": "^2.39.0", diff --git a/resources/js/Components/molecules/WidgetTitleCard.vue b/resources/js/Components/molecules/WidgetTitleCard.vue index 1f07634a..80cf9c34 100644 --- a/resources/js/Components/molecules/WidgetTitleCard.vue +++ b/resources/js/Components/molecules/WidgetTitleCard.vue @@ -3,7 +3,7 @@ import { AtButton } from "atmosphere-ui"; withDefaults(defineProps<{ - title: string; + title?: string; action?: { label: string, iconClass?: string, diff --git a/resources/js/Components/widgets/ChartComparison.vue b/resources/js/Components/widgets/ChartComparison.vue index 2c9866cd..2efa68f1 100644 --- a/resources/js/Components/widgets/ChartComparison.vue +++ b/resources/js/Components/widgets/ChartComparison.vue @@ -10,48 +10,29 @@ import { formatMonth } from "@/utils"; import formatMoney from "@/utils/formatMoney"; import WidgetTitleCard from "../molecules/WidgetTitleCard.vue"; -const props = defineProps({ - title: { - type: String - }, - hideHeader: { - type: Boolean - }, - headerTemplate: { - type: String, - default: 'row' - }, - type: { - type: String, - default: "bar" - }, - data: { - type: Object, - required: true - }, - groupTotal: { - type: String, - default: "total" - }, - dataItemTotal: { - type: String, - default: "total" - }, - dataItemLabel: { - type: Function - }, - hideDivider: { - type: Boolean - }, - headerLabel: { - type: String, - }, - headerTitleDate: { - default: true, - } +const props = withDefaults(defineProps<{ + title: string, + hideHeader: boolean + headerTemplate: "row" | "grid", + type: string, + data: Record, + groupTotal: string, + dataItemTotal: string, + dataItemLabel: Function + hideDivider: boolean + headerLabel: string + headerTitleDate: boolean + withPadding: boolean +}>(), { + headerTemplate: 'row', + type: "bar", + groupTotal: "total", + dataItemTotal: "total", + headerTitleDate: true, + withPadding: true }); -const emit = defineEmits(['click']); +const emit = defineEmits(['click', 'subitem-clicked', 'action']); const selectedDate = ref(null) const currentSeries = computed(() => { @@ -110,7 +91,7 @@ const handleSelection = (index: number) => { :hide-divider="hideDivider" @action="$emit('action', $event)" :border="false" - :with-padding="false" + :with-padding="withPadding" >