-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpage.tsx
More file actions
171 lines (161 loc) · 7.89 KB
/
page.tsx
File metadata and controls
171 lines (161 loc) · 7.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
"use client";
import { useState } from "react";
import ExpenseTable, { useFetchPurchases } from "./expense-table/expense-table";
import TransactionImportModal from "./transaction-import-csv/TransactionImportModal";
import { Button } from "@/components/ui/button";
import RevenueAndExpenses, { RevenueAndExpensesNoData } from "@/components/dashboard/RevenueAndExpenses";
import NetDisasterExpense, { NetDisasterExpenseNoData } from "@/components/dashboard/NetDisasterExpenses";
import { getDashboardBannerData } from "@/api/dashboard";
import { useQuery } from "@tanstack/react-query";
import ReviewExpenses from "./ReviewExpenses";
import { PurchaseLineItemType } from "@/types/purchase";
import { companyHasData } from "@/api/company";
import { GoSync } from "react-icons/go";
import { FiUpload } from "react-icons/fi";
import NoDataPopupWrapper from "@/components/dashboard/NoDataPopupWrapper";
export default function ExpenseTracker() {
const [importModalOpen, setImportModalOpen] = useState<boolean>(false);
const [filterPending, setFilterPending] = useState<boolean>(false);
const onOpenImportModal = () => setImportModalOpen(true);
const onCloseImportModal = () => setImportModalOpen(false);
const { data: hasData, isPending: hasDataLoading } = useQuery({
queryKey: ["company-has-data"],
queryFn: companyHasData,
});
const { data: bannerData } = useQuery({
queryKey: ["banner-data"],
queryFn: getDashboardBannerData,
});
const exExpenses = useFetchPurchases({
pageNumber: 0,
resultsPerPage: 100,
type: PurchaseLineItemType.EXTRANEOUS,
});
const typicalExpenses = useFetchPurchases({
pageNumber: 0,
resultsPerPage: 100,
type: PurchaseLineItemType.TYPICAL,
});
const exExpensesLineItems =
exExpenses.data?.purchases
?.flatMap((purchase) => purchase.lineItems)
.filter((lineItem) => {
return lineItem.type === "extraneous";
}) ?? [];
const typicalExpensesLineItems =
typicalExpenses.data?.purchases
?.flatMap((purchase) => purchase.lineItems)
.filter((lineItem) => {
return lineItem.type === "typical";
}) ?? [];
const lineItems = [...exExpensesLineItems, ...typicalExpensesLineItems];
const expenses = lineItems
? lineItems.map((purchase) => ({
name: purchase.description,
amount: purchase.amountCents / 100.0, // convert cents to dollars
}))
: [];
const totalExpense = expenses.reduce((sum, exp) => sum + exp.amount, 0);
const pendingExpenses = useFetchPurchases({
pageNumber: 0,
resultsPerPage: 100,
type: PurchaseLineItemType.PENDING,
});
const pendingExpensesLineItems =
pendingExpenses.data?.purchases
?.flatMap((purchase) => purchase.lineItems)
.filter((lineItem) => {
return lineItem.type === "pending";
}) ?? [];
const [netDisasterVisisble, setNetDisasterVisible] = useState<boolean>(
pendingExpensesLineItems.length > 0 ? true : false
);
return (
<div className="p-[50px] flex flex-col gap-[23px] bg-[var(--slate)] min-h-screen w-full">
{!hasDataLoading && (
<NoDataPopupWrapper hasData={(hasData?.hasExternalData || hasData?.hasFinancialData) ?? false} />
)}
<div className="flex justify-between">
<h2 className="text-[30px] font-bold">Expense Tracker</h2>
{hasData?.hasFinancialData && (
<div>
<Button
className="h-[34px] w-fit text-white text-[14px] bg-[var(--fuchsia)]"
onClick={onOpenImportModal}
>
{" "}
<FiUpload className="text-white" style={{ width: "14px" }} /> Upload CSV
</Button>
</div>
)}
{!hasData?.hasFinancialData && !hasData?.hasExternalData && (
<div className="flex gap-[8px]">
{!hasData?.hasExternalData && !hasData?.hasFinancialData && (
<Button className="h-[34px] w-fit text-white text-[14px] bg-[var(--fuchsia)]">
{" "}
<GoSync className="text-white" style={{ width: "14px" }} />
Sync Quickbooks
</Button>
)}
<Button
className="h-[34px] w-fit text-white text-[14px] bg-[var(--fuchsia)]"
onClick={onOpenImportModal}
>
{" "}
<FiUpload className="text-white" style={{ width: "14px" }} /> Upload CSV
</Button>
</div>
)}
{/* ---import time---
{hasData?.hasFinancialData &&
<div className="flex justify-between">
<div className="flex gap-[8px] text-[var(--teal)] items-center"> <FiUpload className="text-[var(--teal)]" />Last imported 18 day{true && "s"} ago</div>
<Button className="h-[34px] w-fit text-white text-[14px] bg-[var(--fuchsia)]" onClick={onOpenImportModal}> <FiUpload className="text-white" style={{ width: "14px" }} /> Upload CSV</Button>
</div>
}
{hasData?.hasExternalData &&
<div>
<div className="flex gap-[8px] text-[var(--teal)] items-center"> <GoSync className="text-[var(--teal)]" />Last Synced 18 hours{true && "s"} ago</div>
</div>
} */}
</div>
<div className="flex flex-col w-full gap-[16px]">
<div className="flex gap-[16px] h-[364px]">
<div className="w-[60%]">
{hasData?.hasExternalData || hasData?.hasFinancialData ? (
netDisasterVisisble ? (
<NetDisasterExpense
bannerData={bannerData ?? { status: "no-disaster" }}
onDashboard={false}
handleSwitchToReview={() => setNetDisasterVisible(false)}
/>
) : (
<ReviewExpenses
handleSwitchToNetDisaster={() => setNetDisasterVisible(true)}
lineItemsConfirmed={expenses.length}
lineItemsPending={pendingExpensesLineItems.length}
totalConfirmedExpenses={totalExpense}
filterPending={() => setFilterPending(true)}
/>
)
) : (
<NetDisasterExpenseNoData />
)}
</div>
<div className="w-full">
{hasData ? <RevenueAndExpenses onDashboard={false} /> : <RevenueAndExpensesNoData />}
</div>
</div>
<ExpenseTable
title={"Business Transactions"}
rowOption={"collapsible"}
editableTags={true}
filterPending={filterPending}
setFilterPending={(fp: boolean) => setFilterPending(fp)}
hasData={(hasData?.hasExternalData || hasData?.hasFinancialData) ?? false}
/>
</div>
<TransactionImportModal isOpen={importModalOpen} onClose={onCloseImportModal} />
</div>
);
}