Skip to content

Commit 7b3ce27

Browse files
authored
Merge pull request #66 from celenium-io/CLS-257-transactions-by-daterange
CLS-257 Transactions by daterange
2 parents 54df060 + 7164d00 commit 7b3ce27

File tree

8 files changed

+422
-15
lines changed

8 files changed

+422
-15
lines changed

components/DatePicker.vue

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
<script setup>
2+
/** Vendor */
3+
import { DateTime, Info } from "luxon"
4+
5+
/** UI */
6+
import Button from "@/components/ui/Button.vue"
7+
import Popover from "@/components/ui/Popover.vue"
8+
9+
const props = defineProps({
10+
from: {
11+
type: String,
12+
default: '',
13+
},
14+
to: {
15+
type: String,
16+
default: '',
17+
},
18+
minDate: {
19+
type: String,
20+
default: '',
21+
}
22+
})
23+
24+
const emit = defineEmits(["onUpdate"])
25+
26+
const currentDate = ref(DateTime.now())
27+
const limitMinDate = ref(props.minDate ? DateTime.fromISO(props.minDate) : '')
28+
const month = ref(currentDate.value.month)
29+
const year = ref(currentDate.value.year)
30+
const startDate = ref(props.from ? DateTime.fromSeconds(parseInt(props.from)) : {})
31+
const endDate = ref(props.to ? DateTime.fromSeconds(parseInt(props.to)) : {})
32+
const weekdays = ref(Info.weekdays('narrow', { locale: 'en-US' }))
33+
const days = computed(() => {
34+
let rawDays = []
35+
const firstDay = DateTime.local(year.value, month.value).setLocale('en-US')
36+
const lastDay = firstDay.endOf('month')
37+
38+
for (let day = firstDay; day <= lastDay; day = day.plus({ days: 1 })) {
39+
rawDays.push(day)
40+
}
41+
42+
if (firstDay.weekday !== 1) {
43+
let prevDay = firstDay
44+
while (prevDay.weekday !== 1) {
45+
prevDay = prevDay.minus({ days: 1 }).startOf('day')
46+
rawDays.unshift(prevDay)
47+
}
48+
}
49+
50+
if (lastDay.weekday !== 7) {
51+
let nextDay = lastDay
52+
while (nextDay.weekday !== 7) {
53+
nextDay = nextDay.plus({ days: 1 }).startOf('day')
54+
rawDays.push(nextDay)
55+
}
56+
}
57+
58+
let resDays = []
59+
while (rawDays.length) {
60+
resDays.push(rawDays.splice(0, 7))
61+
}
62+
63+
return resDays
64+
})
65+
66+
const selectedRange = ref('')
67+
const updateSelectedRange = (from, to) => {
68+
if (from?.ts) {
69+
if (to?.ts) {
70+
if (from.year === to.year) {
71+
selectedRange.value = from.toFormat('dd LLL') !== to.toFormat('dd LLL') ? `${from.toFormat('dd LLL')} - ${to.toFormat('dd LLL')}` : from.toFormat('dd LLL')
72+
} else {
73+
selectedRange.value = `${from.toFormat('dd LLL yyyy')} - ${to.toFormat('dd LLL yyyy')}`
74+
}
75+
} else {
76+
selectedRange.value = from.toFormat('dd LLL')
77+
}
78+
} else {
79+
selectedRange.value = ''
80+
}
81+
}
82+
updateSelectedRange(startDate.value, endDate.value)
83+
84+
const isNextMonthAvailable = computed(() => !(month.value === currentDate.value.month && year.value === currentDate.value.year))
85+
const isPrevMonthAvailable = computed(() => limitMinDate.value ? limitMinDate.value.ts < days.value[0][0].ts : true)
86+
const isDayAvailable = (d) => {
87+
if (d.startOf('day').ts > currentDate.value.startOf('day').ts) {
88+
return false
89+
} else if (limitMinDate.value) {
90+
return d.startOf('day').ts >= limitMinDate.value.startOf('day').ts
91+
} else {
92+
return true
93+
}
94+
}
95+
96+
const handleSelectDate = (d) => {
97+
if (!startDate.value.ts) {
98+
startDate.value = d
99+
} else if (startDate.value.ts !== d.ts) {
100+
if (!endDate.value.ts) {
101+
if (startDate.value.ts > d.ts) {
102+
endDate.value = startDate.value
103+
startDate.value = d
104+
} else {
105+
endDate.value = d
106+
}
107+
} else {
108+
startDate.value = d
109+
endDate.value = {}
110+
}
111+
} else {
112+
if (!endDate.value.ts) {
113+
startDate.value = {}
114+
} else {
115+
startDate.value = endDate.value
116+
endDate.value = {}
117+
}
118+
}
119+
}
120+
121+
const isInSelectedPeriod = (d) => {
122+
return startDate.value.ts < d.ts && d.ts < endDate.value.ts
123+
}
124+
125+
const isOpen = ref(false)
126+
const handleOpen = () => {
127+
isOpen.value = true
128+
}
129+
const handleClose = () => {
130+
isOpen.value = false
131+
132+
if (!startDate.value.ts) {
133+
month.value = currentDate.value.month
134+
year.value = currentDate.value.year
135+
}
136+
}
137+
138+
const handleApply = () => {
139+
isOpen.value = false
140+
141+
if (!endDate.value.ts) {
142+
endDate.value = startDate.value.endOf('day')
143+
}
144+
145+
emit('onUpdate', { from: parseInt(startDate.value.ts / 1_000), to: parseInt(endDate.value.ts / 1_000) })
146+
}
147+
148+
const handleClear = () => {
149+
isOpen.value = false
150+
151+
startDate.value = {}
152+
endDate.value = {}
153+
154+
emit('onUpdate', { clear: true })
155+
}
156+
157+
const handleMonthChange = (v) => {
158+
switch (month.value + v) {
159+
case 0:
160+
month.value = 12
161+
year.value --
162+
break
163+
case 13:
164+
month.value = 1
165+
year.value ++
166+
break
167+
default:
168+
month.value += v
169+
}
170+
}
171+
172+
watch(
173+
() => props.from,
174+
() => {
175+
updateSelectedRange(DateTime.fromSeconds(parseInt(props.from)), DateTime.fromSeconds(parseInt(props.to)))
176+
},
177+
)
178+
</script>
179+
180+
<template>
181+
<Popover :open="isOpen" @on-close="handleClose" width="250">
182+
<Button @click="handleOpen" type="secondary" size="mini">
183+
<Icon name="plus-circle" size="12" color="tertiary" />
184+
185+
<Text color="secondary">Date Range</Text>
186+
187+
<template v-if="selectedRange">
188+
<div :class="$style.vertical_divider" />
189+
190+
<Text size="12" weight="600" color="primary">
191+
{{ selectedRange }}
192+
</Text>
193+
194+
<Icon @click.stop="handleClear" name="close-circle" size="12" color="secondary" />
195+
</template>
196+
</Button>
197+
198+
<template #content>
199+
<Flex direction="column" gap="12">
200+
<Flex align="center" justify="center" gap="6">
201+
<Icon
202+
@click="handleMonthChange(-1)"
203+
name="chevron"
204+
size="14"
205+
color="tertiary"
206+
:class="!isPrevMonthAvailable && $style.disabled"
207+
:style="{ transform: 'rotate(90deg)' }"
208+
/>
209+
210+
<Text size="12" color="secondary"> {{ `${DateTime.local(year, month).toFormat('LLLL')} ${year}` }} </Text>
211+
212+
<Icon
213+
@click="handleMonthChange(1)"
214+
name="chevron"
215+
size="14"
216+
color="tertiary"
217+
:class="!isNextMonthAvailable && $style.disabled"
218+
:style="{ transform: 'rotate(-90deg)' }"
219+
/>
220+
</Flex>
221+
222+
<Flex direction="column" gap="16" wide :class="$style.table">
223+
<table>
224+
<thead>
225+
<tr>
226+
<th v-for="wd in weekdays">
227+
<Text size="10" color="secondary"> {{ wd }} </Text>
228+
</th>
229+
</tr>
230+
</thead>
231+
232+
<tbody>
233+
<tr v-for="w in days">
234+
<td v-for="d in w" :class="!isDayAvailable(d) && $style.disabled">
235+
<Flex align="center" justify="center"
236+
@click="handleSelectDate(d)"
237+
:class="[
238+
$style.day,
239+
(d.ts === startDate.ts || d.ts === endDate.ts) && $style.edgeDate,
240+
isInSelectedPeriod(d) && $style.inSelectedPeriod
241+
]"
242+
>
243+
<Text size="12" color="primary"
244+
:class="[
245+
d.month !== month && $style.notInCurrentMonth,
246+
(d.ts === startDate.ts || d.ts === endDate.ts || isInSelectedPeriod(d)) && $style.text_primary
247+
]"
248+
> {{ d.day }} </Text>
249+
</Flex>
250+
</td>
251+
</tr>
252+
</tbody>
253+
</table>
254+
</Flex>
255+
256+
<Button @click="handleApply" type="secondary" size="mini" wide>Apply</Button>
257+
</Flex>
258+
</template>
259+
</Popover>
260+
</template>
261+
262+
<style module>
263+
.vertical_divider {
264+
min-width: 2px;
265+
height: 12px;
266+
background: var(--op-10);
267+
}
268+
269+
.table {
270+
transition: all 0.2s ease;
271+
272+
& table {
273+
width: 100%;
274+
height: fit-content;
275+
276+
border-spacing: 0px;
277+
278+
& tbody {
279+
& tr {
280+
transition: all 0.05s ease;
281+
}
282+
}
283+
284+
& tr th {
285+
text-align: center;
286+
padding-bottom: 8px;
287+
}
288+
289+
& tr td {
290+
text-align: center;
291+
292+
cursor: pointer;
293+
}
294+
295+
th:first-child, td:first-child {
296+
border-radius: 3px;
297+
}
298+
299+
th:last-child, td:last-child {
300+
border-radius: 3px;
301+
}
302+
}
303+
}
304+
305+
.day {
306+
min-width: 20px;
307+
min-height: 20px;
308+
309+
border-radius: 3px;
310+
}
311+
312+
.day:hover {
313+
background-color: rgba(51, 168, 83, 70%);
314+
}
315+
316+
.notInCurrentMonth {
317+
color: var(--txt-tertiary);
318+
}
319+
320+
.edgeDate {
321+
background-color: rgba(51, 168, 83, 70%);
322+
}
323+
324+
.inSelectedPeriod {
325+
background-color: var(--btn-secondary-bg);
326+
}
327+
328+
.text_primary {
329+
color: var(--txt-primary);
330+
}
331+
332+
.disabled {
333+
opacity: 0.3;
334+
pointer-events: none;
335+
cursor: default;
336+
}
337+
</style>

components/modules/block/BlockOverview.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ const handleViewRawTransactions = () => {
857857
text-align: left;
858858
padding: 0;
859859
padding-right: 16px;
860-
padding-top: 4px;
860+
padding-top: 8px;
861861
padding-bottom: 8px;
862862
863863
&:first-child {
@@ -905,7 +905,7 @@ const handleViewRawTransactions = () => {
905905
.filters {
906906
border-bottom: 1px dashed var(--op-8);
907907
908-
padding: 12px 8px 12px 8px;
908+
padding: 4px 8px 6px 8px;
909909
}
910910
911911
.empty {

components/widgets/BlobsWidget.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { formatBytes } from "@/services/utils"
1111
/** API */
1212
import { fetchSeries } from "@/services/api/stats"
1313
14+
const router = useRouter()
15+
1416
const days = ref([])
1517
const weeks = ref([])
1618
@@ -80,6 +82,12 @@ const calculateOpacity = (val) => {
8082
8183
return opacity
8284
}
85+
86+
const selectDay = (d) => {
87+
let from = parseInt(DateTime.fromISO(d.time).startOf('day').ts / 1_000)
88+
let to = parseInt(DateTime.fromISO(d.time).endOf('day').ts / 1_000)
89+
router.push(`/txs?message_type=MsgPayForBlobs&from=${from}&to=${to}`)
90+
}
8391
</script>
8492

8593
<template>
@@ -102,6 +110,7 @@ const calculateOpacity = (val) => {
102110
<Flex v-for="week in weeks" direction="column" justify="between">
103111
<Tooltip v-for="day in week" :disabled="!day">
104112
<Flex
113+
@click="selectDay(day)"
105114
:class="[$style.day, day?.value > 0 && $style.shadow]"
106115
:style="{
107116
background: parseInt(day?.value) > 0 ? `rgb(10, 219, 111)` : 'var(--op-10)',

components/widgets/StakingWidget.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,6 @@ onMounted(() => {
258258
height: 4px;
259259
260260
border-radius: 2px;
261-
cursor: pointer;
262261
263262
margin-right: 4px;
264263
margin-bottom: 4px;

0 commit comments

Comments
 (0)