Skip to content

Commit 5986ba7

Browse files
authored
Merge branch 'main' into arbitrum-docs
2 parents 098fbbb + 53d0d74 commit 5986ba7

File tree

60 files changed

+1579
-1019
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1579
-1019
lines changed

.changeset/odd-fans-tickle.md

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

.changeset/short-icons-care.md

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

.changeset/thin-days-add.md

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

apps/dashboard/src/@/analytics/report.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,39 @@ export function reportAssetPageview(properties: {
467467
}) {
468468
posthog.capture("asset pageview", properties);
469469
}
470+
471+
/**
472+
* ### Why do we need to report this event?
473+
* - To track the usage of fund wallet modal
474+
* - To create a funnel "fund wallet modal opened" -> "fund wallet buy successful" to understand the conversion rate
475+
*
476+
* ### Who is responsible for this event?
477+
* @MananTank
478+
*/
479+
export function reportFundWalletOpened() {
480+
posthog.capture("fund wallet opened");
481+
}
482+
483+
/**
484+
* ### Why do we need to report this event?
485+
* - To track the number of successful fund wallet buys
486+
* - To create a funnel "fund wallet modal opened" -> "fund wallet buy successful" to understand the conversion rate
487+
*
488+
* ### Who is responsible for this event?
489+
* @MananTank
490+
*/
491+
export function reportFundWalletSuccessful() {
492+
posthog.capture("fund wallet successful");
493+
}
494+
495+
/**
496+
* ### Why do we need to report this event?
497+
* - To track the number of failed fund wallet buys
498+
* - To track the errors that users encounter when trying to buy from a fund wallet modal
499+
*
500+
* ### Who is responsible for this event?
501+
* @MananTank
502+
*/
503+
export function reportFundWalletFailed(params: { errorMessage: string }) {
504+
posthog.capture("fund wallet failed", params);
505+
}

apps/dashboard/src/@/components/analytics/date-range-selector.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export function DateRangeSelector(props: {
1818
}) {
1919
const { range, setRange } = props;
2020
const daysDiff = differenceInCalendarDays(range.to, range.from);
21+
2122
const matchingRange =
2223
normalizeTime(range.to).getTime() === normalizeTime(new Date()).getTime()
2324
? durationPresets.find((preset) => preset.days === daysDiff)
@@ -85,7 +86,7 @@ export function getLastNDaysRange(id: DurationId) {
8586
throw new Error(`Invalid duration id: ${id}`);
8687
}
8788

88-
const todayDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // add 1 day to avoid timezone issues
89+
const todayDate = new Date(Date.now());
8990

9091
const value: Range = {
9192
from: subDays(todayDate, durationInfo.days),

apps/dashboard/src/@/components/analytics/range-selector.tsx

Lines changed: 0 additions & 104 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
3+
import {
4+
useResponsiveSearchParams,
5+
useSetResponsiveSearchParams,
6+
} from "responsive-rsc";
7+
import {
8+
DateRangeSelector,
9+
type DurationId,
10+
} from "@/components/analytics/date-range-selector";
11+
import { IntervalSelector } from "@/components/analytics/interval-selector";
12+
import { getFiltersFromSearchParams, normalizeTimeISOString } from "@/lib/time";
13+
14+
export function ResponsiveTimeFilters(props: { defaultRange: DurationId }) {
15+
const responsiveSearchParams = useResponsiveSearchParams();
16+
const setResponsiveSearchParams = useSetResponsiveSearchParams();
17+
const { range, interval } = getFiltersFromSearchParams({
18+
defaultRange: props.defaultRange,
19+
from: responsiveSearchParams.from,
20+
interval: responsiveSearchParams.interval,
21+
to: responsiveSearchParams.to,
22+
});
23+
24+
return (
25+
<div className="flex justify-end gap-3 flex-col lg:flex-row">
26+
<DateRangeSelector
27+
className="rounded-full"
28+
range={range}
29+
setRange={(newRange) => {
30+
setResponsiveSearchParams((v) => {
31+
const newParams = {
32+
...v,
33+
from: normalizeTimeISOString(newRange.from),
34+
to: normalizeTimeISOString(newRange.to),
35+
};
36+
return newParams;
37+
});
38+
}}
39+
/>
40+
<IntervalSelector
41+
className="bg-card rounded-full"
42+
intervalType={interval}
43+
setIntervalType={(newInterval) => {
44+
setResponsiveSearchParams((v) => {
45+
const newParams = {
46+
...v,
47+
interval: newInterval,
48+
};
49+
return newParams;
50+
});
51+
}}
52+
/>
53+
</div>
54+
);
55+
}

apps/dashboard/src/@/components/blocks/fund-wallets-modal/index.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import type { ThirdwebClient } from "thirdweb";
99
import { defineChain } from "thirdweb/chains";
1010
import { CheckoutWidget, useActiveWalletChain } from "thirdweb/react";
1111
import { z } from "zod";
12+
import {
13+
reportFundWalletFailed,
14+
reportFundWalletSuccessful,
15+
} from "@/analytics/report";
1216
import { SingleNetworkSelector } from "@/components/blocks/NetworkSelectors";
1317
import { TokenSelector } from "@/components/blocks/TokenSelector";
1418
import { Button } from "@/components/ui/button";
@@ -252,6 +256,14 @@ function FundWalletModalContent(props: FundWalletModalProps) {
252256
className="!w-full !max-w-full !min-w-0 !rounded-b-none !border-none"
253257
theme={getSDKTheme(theme === "dark" ? "dark" : "light")}
254258
name={props.checkoutWidgetTitle}
259+
onSuccess={() => {
260+
reportFundWalletSuccessful();
261+
}}
262+
onError={(error) => {
263+
reportFundWalletFailed({
264+
errorMessage: error.message,
265+
});
266+
}}
255267
/>
256268
</div>
257269

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
"use client";
22

3-
import { SearchIcon } from "lucide-react";
3+
import { SearchIcon, XIcon } from "lucide-react";
44
import { useState } from "react";
55
import { Button } from "@/components/ui/button";
66
import { Input } from "@/components/ui/input";
7+
import { Spinner } from "@/components/ui/Spinner/Spinner";
78
import {
89
Select,
910
SelectContent,
1011
SelectItem,
1112
SelectTrigger,
1213
SelectValue,
1314
} from "@/components/ui/select";
14-
1515
import type { SearchType } from "./types";
1616

1717
export function AdvancedSearchInput(props: {
@@ -41,56 +41,57 @@ export function AdvancedSearchInput(props: {
4141
};
4242

4343
return (
44-
<div className="flex flex-col gap-2">
45-
<div className="flex gap-2">
46-
<Select
47-
value={searchType}
48-
onValueChange={(value) => setSearchType(value as SearchType)}
49-
>
50-
<SelectTrigger className="w-[140px] bg-card">
51-
<SelectValue />
52-
</SelectTrigger>
53-
<SelectContent>
54-
<SelectItem value="email">Email</SelectItem>
55-
<SelectItem value="phone">Phone</SelectItem>
56-
<SelectItem value="id">ID</SelectItem>
57-
<SelectItem value="address">Address</SelectItem>
58-
<SelectItem value="externalWallet">External Wallet</SelectItem>
59-
</SelectContent>
60-
</Select>
44+
<div className="flex flex-col md:flex-row gap-3">
45+
<Select
46+
value={searchType}
47+
onValueChange={(value) => setSearchType(value as SearchType)}
48+
>
49+
<SelectTrigger className="w-[140px] bg-card">
50+
<SelectValue />
51+
</SelectTrigger>
52+
<SelectContent>
53+
<SelectItem value="email">Email</SelectItem>
54+
<SelectItem value="phone">Phone</SelectItem>
55+
<SelectItem value="id">ID</SelectItem>
56+
<SelectItem value="address">Address</SelectItem>
57+
<SelectItem value="externalWallet">External Wallet</SelectItem>
58+
</SelectContent>
59+
</Select>
6160

61+
<div className="flex flex-1">
6262
<div className="relative flex-1">
6363
<Input
64-
className="bg-card pl-9"
64+
className="bg-card pl-9 border-r-0 rounded-r-none"
6565
placeholder={`Search by ${searchType}...`}
6666
value={query}
6767
onChange={(e) => setQuery(e.target.value)}
6868
onKeyDown={handleKeyDown}
6969
/>
7070
<SearchIcon className="-translate-y-1/2 absolute top-1/2 left-3 size-4 text-muted-foreground" />
71+
72+
{props.hasResults && (
73+
<div className="absolute top-1/2 -translate-y-1/2 right-2 ">
74+
<Button
75+
variant="ghost"
76+
onClick={handleClear}
77+
className="p-1 h-auto"
78+
>
79+
<XIcon className="size-4 text-muted-foreground" />
80+
</Button>
81+
</div>
82+
)}
7183
</div>
7284

7385
<Button
7486
onClick={handleSearch}
87+
variant="outline"
7588
disabled={!query.trim() || props.isLoading}
76-
size="sm"
89+
className="rounded-l-none gap-2 bg-card disabled:opacity-100"
7790
>
78-
{props.isLoading ? "Searching..." : "Search"}
91+
{props.isLoading && <Spinner className="size-4" />}
92+
Search
7993
</Button>
8094
</div>
81-
82-
{props.hasResults && (
83-
<div className="flex justify-center">
84-
<Button
85-
variant="outline"
86-
size="sm"
87-
onClick={handleClear}
88-
className="gap-2"
89-
>
90-
Clear Search & Return to List
91-
</Button>
92-
</div>
93-
)}
9495
</div>
9596
);
9697
}

0 commit comments

Comments
 (0)