Skip to content

Commit 1aaf85f

Browse files
committed
Squashed commit of the following:
commit bd93488 Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Thu Sep 11 10:46:42 2025 +0300 chore: Disable BillingMonthSelect when there is no data commit f3ba67b Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Thu Sep 11 10:44:32 2025 +0300 chore: Disable mock invoice drafts commit 728b8c5 Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Tue Sep 9 16:16:58 2025 +0300 fix: Small styling fixes. Rename Billing into Invoicing. commit 77c171f Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Tue Sep 9 12:41:42 2025 +0300 feat: Display invoice drafts in expandable cards commit d538e31 Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Tue Sep 9 12:11:45 2025 +0300 feat: Add mock API, separate BillingMonthSelect commit 48fcfd6 Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Fri Sep 5 15:54:19 2025 +0300 chore: Refactor CardWithHeader, add workflow message in Billing commit 05bb1f1 Author: wzrdx <128477299+wzrdx@users.noreply.github.com> Date: Thu Sep 4 17:30:43 2025 +0300 fix: Overview not displaying number of projects correctly. Refactor some styles
1 parent 86693e2 commit 1aaf85f

File tree

17 files changed

+611
-251
lines changed

17 files changed

+611
-251
lines changed

src/components/account/Billing.tsx

Lines changed: 0 additions & 161 deletions
This file was deleted.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Select, SelectItem } from '@heroui/select';
2+
import { Skeleton } from '@heroui/skeleton';
3+
import { SharedSelection } from '@heroui/system';
4+
import { useEffect, useState } from 'react';
5+
import { RiCalendarEventLine } from 'react-icons/ri';
6+
7+
export default function BillingMonthSelect({
8+
uniqueMonths,
9+
onMonthChange,
10+
}: {
11+
uniqueMonths: string[];
12+
onMonthChange: (month: string) => void;
13+
}) {
14+
const [selectedMonths, setSelectedMonths] = useState<Set<string> | undefined>(undefined);
15+
16+
useEffect(() => {
17+
if (uniqueMonths.length > 0) {
18+
setSelectedMonths(new Set<string>([uniqueMonths[0]]));
19+
}
20+
}, [uniqueMonths]);
21+
22+
useEffect(() => {
23+
if (selectedMonths) {
24+
onMonthChange(Array.from(selectedMonths)[0]);
25+
}
26+
}, [selectedMonths]);
27+
28+
if (!selectedMonths) {
29+
return <Skeleton className="h-10 w-48 rounded-lg" />;
30+
}
31+
32+
return (
33+
<Select
34+
className="max-w-48"
35+
classNames={{
36+
trigger: 'min-h-10 bg-slate-100 data-[hover=true]:bg-slate-150 rounded-lg shadow-none cursor-pointer',
37+
label: 'group-data-[filled=true]:-translate-y-5',
38+
value: 'font-medium text-slate-600!',
39+
selectorIcon: 'mt-0.5 mr-0.5',
40+
}}
41+
listboxProps={{
42+
itemClasses: {
43+
base: [
44+
'rounded-md',
45+
'text-default-600',
46+
'transition-opacity',
47+
'data-[hover=true]:text-foreground',
48+
'data-[hover=true]:bg-slate-100',
49+
'data-[selectable=true]:focus:bg-slate-100',
50+
'data-[pressed=true]:opacity-70',
51+
'data-[focus-visible=true]:ring-default-500',
52+
'px-3',
53+
],
54+
},
55+
}}
56+
popoverProps={{
57+
classNames: {
58+
content: 'p-0 border-small rounded-lg',
59+
},
60+
}}
61+
placeholder="Select a month"
62+
variant="flat"
63+
startContent={<RiCalendarEventLine className="mt-px text-[20px] text-slate-600" />}
64+
selectedKeys={selectedMonths}
65+
onSelectionChange={(value: SharedSelection) => {
66+
if (value.anchorKey) {
67+
setSelectedMonths(new Set<string>([value.anchorKey]));
68+
}
69+
}}
70+
isDisabled={uniqueMonths.length === 0}
71+
>
72+
{uniqueMonths.map((monthAndYear) => (
73+
<SelectItem key={monthAndYear}>
74+
{new Date(monthAndYear).toLocaleString('en-US', { month: 'long', year: 'numeric' })}
75+
</SelectItem>
76+
))}
77+
</Select>
78+
);
79+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { getShortAddressOrHash } from '@lib/utils';
2+
import { BorderedCard } from '@shared/cards/BorderedCard';
3+
import { CopyableValue } from '@shared/CopyableValue';
4+
import ItemWithLabel from '@shared/ItemWithLabel';
5+
import { InvoiceDraft } from '@typedefs/general';
6+
import { RiArrowRightLine } from 'react-icons/ri';
7+
8+
export default function DraftInvoiceCard({
9+
draft,
10+
isExpanded,
11+
toggle,
12+
}: {
13+
draft: InvoiceDraft;
14+
isExpanded: boolean;
15+
toggle: () => void;
16+
}) {
17+
return (
18+
<BorderedCard isHoverable onClick={toggle}>
19+
<div className="col gap-4">
20+
{/* Content */}
21+
<div className="row justify-between gap-3 text-sm lg:gap-6">
22+
<div className="min-w-[62px] font-medium">{draft.invoiceNumber}</div>
23+
24+
<div className="min-w-[122px]">
25+
{new Date(draft.creationTimestamp).toLocaleDateString(undefined, {
26+
month: 'short',
27+
day: 'numeric',
28+
year: 'numeric',
29+
hour: '2-digit',
30+
minute: '2-digit',
31+
})}
32+
</div>
33+
34+
<div className="max-w-[170px] min-w-[170px] truncate">{draft.nodeOwnerName}</div>
35+
36+
<div className="min-w-[118px] font-medium">${draft.totalUsdcAmount.toFixed(2)}</div>
37+
38+
<div
39+
className="min-w-[92px]"
40+
onClick={(e) => {
41+
e.preventDefault();
42+
e.stopPropagation();
43+
44+
console.log('Download', draft.invoiceId);
45+
}}
46+
>
47+
<div className="row cursor-pointer gap-1 hover:opacity-50">
48+
<div className="compact">Download</div>
49+
<RiArrowRightLine className="mt-px text-lg" />
50+
</div>
51+
</div>
52+
</div>
53+
54+
{/* Details */}
55+
{isExpanded && (
56+
<div className="col bg-slate-75 gap-2.5 rounded-lg px-5 py-4">
57+
<div className="text-base font-semibold">Details</div>
58+
59+
<div className="row justify-between gap-2">
60+
<ItemWithLabel
61+
label="Node Operator Addr."
62+
value={
63+
<CopyableValue value={draft.userAddress}>
64+
<div className="text-sm text-slate-400">
65+
{getShortAddressOrHash(draft.userAddress, 4)}
66+
</div>
67+
</CopyableValue>
68+
}
69+
/>
70+
71+
<ItemWithLabel
72+
label="Invoice Series"
73+
value={<div className="font-medium capitalize">{draft.invoiceSeries}</div>}
74+
/>
75+
76+
<ItemWithLabel
77+
label="Invoice ID"
78+
value={
79+
<CopyableValue value={draft.invoiceId}>
80+
<div className="text-sm text-slate-400">
81+
{getShortAddressOrHash(draft.invoiceId, 8)}
82+
</div>
83+
</CopyableValue>
84+
}
85+
/>
86+
</div>
87+
</div>
88+
)}
89+
</div>
90+
</BorderedCard>
91+
);
92+
}

src/components/account/InvoiceCard.tsx

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)