tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
27
pulls
pipelines
analytics date selector
cozylittle.house
1 month ago
68ba2c37
a664db07
+167
-43
4 changed files
expand all
collapse all
unified
split
app
lish
[did]
[publication]
dashboard
PublicationAnalytics.tsx
components
Blocks
DateTimeBlock.tsx
DatePicker.tsx
Pages
Backdater.tsx
+128
-2
app/lish/[did]/[publication]/dashboard/PublicationAnalytics.tsx
···
1
1
+
import { ArrowRightTiny } from "components/Icons/ArrowRightTiny";
1
2
import { UpgradeContent } from "../UpgradeModal";
3
3
+
import { Popover } from "components/Popover";
4
4
+
import { DatePicker } from "components/DatePicker";
5
5
+
import { useState } from "react";
6
6
+
import { useLocalizedDate } from "src/hooks/useLocalizedDate";
7
7
+
import type { DateRange } from "react-day-picker";
8
8
+
import { usePublicationData } from "./PublicationSWRProvider";
2
9
3
10
export const PublicationAnalytics = () => {
11
11
+
let isPro = true;
12
12
+
13
13
+
let { data: publication } = usePublicationData();
14
14
+
let [dateRange, setDateRange] = useState<DateRange>({ from: undefined });
15
15
+
16
16
+
if (!isPro)
17
17
+
return (
18
18
+
<div className="sm:mx-auto pt-4 s">
19
19
+
<UpgradeContent />
20
20
+
</div>
21
21
+
);
22
22
+
4
23
return (
5
5
-
<div className="sm:mx-auto pt-4 s">
6
6
-
<UpgradeContent />
24
24
+
<div className="analytics">
25
25
+
<div className="analyticsViewCount">
26
26
+
<div className="flex justify-between items-center gap-2 pb-2 w-full">
27
27
+
<div className="flex gap-2 items-center">
28
28
+
<h3>Traffic</h3>
29
29
+
<ArrowRightTiny /> <PostSelector />
30
30
+
</div>
31
31
+
<DateRangeSelector
32
32
+
dateRange={dateRange}
33
33
+
setDateRange={setDateRange}
34
34
+
pubStartDate={publication?.publication?.indexed_at}
35
35
+
/>
36
36
+
</div>
37
37
+
<div className="aspect-video w-full border border-border" />
38
38
+
</div>
39
39
+
40
40
+
{/*<div>subscriber count over time</div>
41
41
+
<div>Top Referrers</div>*/}
7
42
</div>
8
43
);
9
44
};
45
45
+
46
46
+
const PostSelector = () => {
47
47
+
return <div>Total</div>;
48
48
+
};
49
49
+
50
50
+
const DateRangeSelector = (props: {
51
51
+
pubStartDate: string | undefined;
52
52
+
dateRange: DateRange;
53
53
+
setDateRange: (dateRange: DateRange) => void;
54
54
+
}) => {
55
55
+
let buttonClass =
56
56
+
"rounded-md px-1 text-sm border border-accent-contrast text-accent-contrast";
57
57
+
58
58
+
let currentDate = new Date();
59
59
+
60
60
+
console.log("dateRange" + props.dateRange.from?.toISOString());
61
61
+
console.log("pubstart" + props.pubStartDate);
62
62
+
63
63
+
let startDate = useLocalizedDate(
64
64
+
props.dateRange.from?.toISOString() ||
65
65
+
props.pubStartDate ||
66
66
+
"2025-01-01T12:00:00.000Z",
67
67
+
{
68
68
+
month: "short",
69
69
+
day: "numeric",
70
70
+
},
71
71
+
);
72
72
+
73
73
+
let endDate = useLocalizedDate(
74
74
+
(props.dateRange.to ?? currentDate).toISOString(),
75
75
+
{
76
76
+
month: "short",
77
77
+
day: "numeric",
78
78
+
},
79
79
+
);
80
80
+
81
81
+
function handleDateChange(range: DateRange | undefined) {
82
82
+
if (range) props.setDateRange(range);
83
83
+
}
84
84
+
85
85
+
return (
86
86
+
<Popover
87
87
+
className={"w-fit"}
88
88
+
trigger={
89
89
+
<div className="text-tertiary ml-0">
90
90
+
{props.dateRange.from === undefined
91
91
+
? "All Time"
92
92
+
: `${startDate} - ${endDate}`}
93
93
+
</div>
94
94
+
}
95
95
+
>
96
96
+
<div className="flex gap-2 pt-1">
97
97
+
<button
98
98
+
onClick={() => {
99
99
+
props.setDateRange({ from: undefined, to: undefined });
100
100
+
}}
101
101
+
className={`${buttonClass}`}
102
102
+
>
103
103
+
All
104
104
+
</button>
105
105
+
<button
106
106
+
onClick={() => {
107
107
+
let from = new Date();
108
108
+
from.setDate(from.getDate() - 7);
109
109
+
props.setDateRange({ from, to: new Date() });
110
110
+
}}
111
111
+
className={`${buttonClass}`}
112
112
+
>
113
113
+
Last Week
114
114
+
</button>
115
115
+
<button
116
116
+
onClick={() => {
117
117
+
let from = new Date();
118
118
+
from.setMonth(from.getMonth() - 1);
119
119
+
props.setDateRange({ from, to: new Date() });
120
120
+
}}
121
121
+
className={`${buttonClass}`}
122
122
+
>
123
123
+
Last Month
124
124
+
</button>
125
125
+
</div>
126
126
+
<hr className="my-2 border-border-light" />
127
127
+
<DatePicker
128
128
+
mode="range"
129
129
+
selected={props.dateRange}
130
130
+
onSelect={handleDateChange}
131
131
+
disabled={(date) => date > new Date()}
132
132
+
/>
133
133
+
</Popover>
134
134
+
);
135
135
+
};
+1
components/Blocks/DateTimeBlock.tsx
···
166
166
>
167
167
<div className="flex flex-col gap-3 ">
168
168
<DatePicker
169
169
+
mode="single"
169
170
selected={dateFact ? selectedDate : undefined}
170
171
onSelect={handleDaySelect}
171
172
/>
+37
-40
components/DatePicker.tsx
···
1
1
-
import { ChevronProps, DayPicker as ReactDayPicker } from "react-day-picker";
1
1
+
import {
2
2
+
ChevronProps,
3
3
+
DayPicker as ReactDayPicker,
4
4
+
DayPickerProps,
5
5
+
} from "react-day-picker";
2
6
import { ArrowRightTiny } from "components/Icons/ArrowRightTiny";
3
7
4
8
const CustomChevron = (props: ChevronProps) => {
···
9
13
);
10
14
};
11
15
12
12
-
interface DayPickerProps {
13
13
-
selected: Date | undefined;
14
14
-
onSelect: (date: Date | undefined) => void;
15
15
-
disabled?: (date: Date) => boolean;
16
16
-
}
16
16
+
export const DatePicker = (props: DayPickerProps) => {
17
17
+
const dayPickerProps = {
18
18
+
...props,
19
19
+
required: props.required ?? false,
20
20
+
mode: props.mode ?? "single",
21
21
+
components: {
22
22
+
Chevron: (chevronProps: ChevronProps) => (
23
23
+
<CustomChevron {...chevronProps} />
24
24
+
),
25
25
+
...props.components,
26
26
+
},
27
27
+
classNames: {
28
28
+
months: "relative",
29
29
+
month_caption:
30
30
+
"font-bold text-center w-full bg-border-light mb-2 py-1 rounded-md",
31
31
+
button_next:
32
32
+
"absolute right-0 top-1 p-1 text-secondary hover:text-accent-contrast flex align-center",
33
33
+
button_previous:
34
34
+
"absolute left-0 top-1 p-1 text-secondary hover:text-accent-contrast rotate-180 flex align-center",
35
35
+
chevron: "text-inherit",
36
36
+
month_grid: "border-separate [border-spacing:2px]",
37
37
+
weekdays: "text-secondary text-sm",
38
38
+
selected: "bg-accent-1 text-accent-2 rounded-md font-bold",
39
39
+
range_middle: "bg-[var(--accent-light)]!",
40
40
+
day: "h-8! w-8! text-center rounded-md sm:hover:bg-border-light",
41
41
+
outside: "text-tertiary",
42
42
+
today: "font-bold",
43
43
+
disabled: "text-border cursor-not-allowed hover:bg-transparent!",
44
44
+
...props.classNames,
45
45
+
},
46
46
+
} as DayPickerProps;
17
47
18
18
-
export const DatePicker = ({
19
19
-
selected,
20
20
-
onSelect,
21
21
-
disabled,
22
22
-
}: DayPickerProps) => {
23
23
-
return (
24
24
-
<ReactDayPicker
25
25
-
components={{
26
26
-
Chevron: (props: ChevronProps) => <CustomChevron {...props} />,
27
27
-
}}
28
28
-
classNames={{
29
29
-
months: "relative",
30
30
-
month_caption:
31
31
-
"font-bold text-center w-full bg-border-light mb-2 py-1 rounded-md",
32
32
-
button_next:
33
33
-
"absolute right-0 top-1 p-1 text-secondary hover:text-accent-contrast flex align-center",
34
34
-
button_previous:
35
35
-
"absolute left-0 top-1 p-1 text-secondary hover:text-accent-contrast rotate-180 flex align-center",
36
36
-
chevron: "text-inherit",
37
37
-
month_grid: "w-full table-fixed",
38
38
-
weekdays: "text-secondary text-sm",
39
39
-
selected: "bg-accent-1! text-accent-2 rounded-md font-bold",
40
40
-
day: "h-[34px] text-center rounded-md sm:hover:bg-border-light",
41
41
-
outside: "text-tertiary",
42
42
-
today: "font-bold",
43
43
-
disabled: "text-border cursor-not-allowed hover:bg-transparent!",
44
44
-
}}
45
45
-
mode="single"
46
46
-
selected={selected}
47
47
-
defaultMonth={selected}
48
48
-
onSelect={onSelect}
49
49
-
disabled={disabled}
50
50
-
/>
51
51
-
);
48
48
+
return <ReactDayPicker {...dayPickerProps} />;
52
49
};
53
50
54
51
export const TimePicker = (props: {
+1
-1
components/Pages/Backdater.tsx
···
61
61
62
62
return (
63
63
<Popover
64
64
-
className="w-64 z-10 px-2!"
64
64
+
className="w-fit z-10 px-2!"
65
65
trigger={
66
66
<div className="underline">
67
67
{timeAgo(localPublishedAt.toISOString())}