Skip to content

Commit 5a7d2bf

Browse files
committed
feat(calendar): adds filtering support
1 parent 63f758c commit 5a7d2bf

File tree

8 files changed

+114
-78
lines changed

8 files changed

+114
-78
lines changed

src/components/common/navbar/NavbarSettingsDopdown.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { useI18n } from '~/utils';
2929
3030
import { chromeRuntimeId, createTab } from '~/utils/browser/browser.utils';
3131
32-
const i18n = useI18n('navbar_settings');
32+
const i18n = useI18n('navbar', 'settings');
3333
const router = useRouter();
3434
3535
const { user, userSetting, userSettings } = useUserSettingsStoreRefs();

src/components/views/calendar/CalendarComponent.vue

+3-4
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ import { watchUserChange } from '~/utils/store.utils';
1818
1919
const i18n = useI18n('calendar');
2020
21-
const { calendar, loading, center } = useCalendarStoreRefs();
21+
const { calendar, loading, center, filteredCalendar } = useCalendarStoreRefs();
2222
const { fetchCalendar, clearState } = useCalendarStore();
2323
24-
const list = useListScroll(calendar, 'date');
24+
const list = useListScroll(filteredCalendar, 'date');
2525
2626
const centerItem = computed(() => {
2727
return list.value.find(
@@ -66,7 +66,6 @@ watch(center, () => reload());
6666
watchUserChange({
6767
mounted: reload,
6868
activated: async changed => {
69-
console.info('activated', changed);
7069
if (changed) await reload();
7170
},
7271
userChange: async active => {
@@ -120,7 +119,7 @@ const onScrollBottom = async () => {
120119
</ListScroll>
121120
<FloatingButton
122121
:show="scrolledOut"
123-
width="2.5rem"
122+
:width="centerIsToday ? '2.5rem' : '3.5rem'"
124123
:icon="recenterIcon"
125124
@on-click="onClick"
126125
>

src/components/views/calendar/CalendarNavbar.vue

+23-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { NDatePicker, NFlex, NIcon, NInput } from 'naive-ui';
2+
import { NDatePicker, NFlex, NIcon, NInput, NTooltip } from 'naive-ui';
33
44
import { computed, defineProps, ref } from 'vue';
55
@@ -19,10 +19,10 @@ defineProps({
1919
},
2020
});
2121
22-
const i18n = useI18n('navbar');
22+
const i18n = useI18n('navbar', 'calendar');
2323
2424
const { filter, center } = useCalendarStoreRefs();
25-
const { clearState, fetchCalendar } = useCalendarStore();
25+
const { clearState } = useCalendarStore();
2626
2727
const debouncedSearch = useDebouncedSearch(filter);
2828
@@ -37,12 +37,6 @@ const pickerValue = computed({
3737
});
3838
3939
const open = ref(false);
40-
41-
const onDateChange = (value?: number) => {
42-
console.info('onDateChange', value);
43-
if (!value) return;
44-
console.info('onDateChange', value);
45-
};
4640
</script>
4741

4842
<template>
@@ -62,17 +56,28 @@ const onDateChange = (value?: number) => {
6256
<NIcon :component="open ? IconChevron : IconCalendar" />
6357
</template>
6458
</NDatePicker>
65-
<NInput
66-
v-model:value="debouncedSearch"
67-
class="search-input"
68-
:placeholder="i18n('search')"
69-
autosize
70-
clearable
59+
<NTooltip
60+
:show-arrow="false"
61+
placement="bottom"
62+
:delay="100"
63+
trigger="focus"
64+
:to="parentElement"
7165
>
72-
<template #prefix>
73-
<NIcon :component="IconLoop" />
66+
<span> {{ i18n('fetch_disable') }} </span>
67+
<template #trigger>
68+
<NInput
69+
v-model:value="debouncedSearch"
70+
class="search-input"
71+
:placeholder="i18n('search', 'navbar')"
72+
autosize
73+
clearable
74+
>
75+
<template #prefix>
76+
<NIcon :component="IconLoop" />
77+
</template>
78+
</NInput>
7479
</template>
75-
</NInput>
80+
</NTooltip>
7681
</NFlex>
7782
</template>
7883

src/components/views/watchlist/WatchlistNavbar.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
import { useI18n } from '~/utils';
2020
import { useDebouncedSearch, watchUserChange } from '~/utils/store.utils';
2121
22-
const i18n = useI18n('navbar_list');
22+
const i18n = useI18n('navbar', 'list');
2323
2424
const { pageSize, searchList } = useListStoreRefs();
2525
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"navbar__calendar__fetch_disable": {
3+
"message": "Data fetching is disable while filtering the calendar.",
4+
"description": "Message displayed when the user tries to fetch data while filtering the calendar."
5+
}
6+
}

src/i18n/en/navbar/navbar-list.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
2-
"navbar_list__list_type__watchlist": {
2+
"navbar__list__list_type__watchlist": {
33
"message": "Watchlist",
44
"description": "Label for the watchlist list type"
55
},
6-
"navbar_list__list_type__favorites": {
6+
"navbar__list__list_type__favorites": {
77
"message": "Favorites",
88
"description": "Label for the favorites list type"
99
},
10-
"navbar_list__list_type__collection_movie": {
10+
"navbar__list__list_type__collection_movie": {
1111
"message": "Movie collection",
1212
"description": "Label for the movie collection list type"
1313
},
14-
"navbar_list__list_type__collection_show": {
14+
"navbar__list__list_type__collection_show": {
1515
"message": "Show collection",
1616
"description": "Label for the show collection list type"
1717
}

src/i18n/en/navbar/navbar-settings.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
2-
"navbar_settings__logout": {
2+
"navbar__settings__logout": {
33
"message": "Sign out",
44
"description": "Clear current session."
55
},
6-
"navbar_settings__login": {
6+
"navbar__settings__login": {
77
"message": "Sign in",
88
"description": "Authorize session."
99
},
10-
"navbar_settings__settings": {
10+
"navbar__settings__settings": {
1111
"message": "Settings",
1212
"description": "Settings page."
1313
},
14-
"navbar_settings__trakt": {
14+
"navbar__settings__trakt": {
1515
"message": "Trakt",
1616
"description": "Open trakt website."
1717
}

src/stores/data/calendar.store.ts

+72-46
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { type ListScrollItem, type ListScrollItemTag, ListScrollItemType } from
88
import { TraktService } from '~/services/trakt.service';
99
import { storage } from '~/utils/browser/browser-storage.utils';
1010
import { DateUtils } from '~/utils/date.utils';
11+
import { useSearchFilter } from '~/utils/store.utils';
1112

1213
export type CalendarItem = (TraktCalendarShow | TraktCalendarMovie | Record<never, never>) & {
1314
id: ListScrollItem['id'];
@@ -77,11 +78,65 @@ export const useCalendarStore = defineStore('data.calendar', () => {
7778
if (restored?.endCalendar) endCalendar.value = new Date(restored.endCalendar);
7879
};
7980

81+
const spaceDate = (data: CalendarItem[], startDate: Date, endDate: Date): CalendarItem[] => {
82+
const spacedData: CalendarItem[] = [];
83+
data?.forEach((item, index) => {
84+
if (index === 0) {
85+
// if the first item isn't the start date, add placeholders
86+
if (item.date.getTime() > startDate.getTime() && item.date.toLocaleDateString() !== startDate.toLocaleDateString()) {
87+
let previousDate: Date = item.date;
88+
while (previousDate.toLocaleDateString() !== startDate.toLocaleDateString()) {
89+
previousDate = DateUtils.previous(1, previousDate);
90+
spacedData.push(getPlaceholder(previousDate));
91+
}
92+
}
93+
return spacedData.push(item);
94+
}
95+
96+
if (index === data.length - 1) {
97+
spacedData.push(item);
98+
99+
// if the last item isn't one day before the end date, add placeholders
100+
const dayBeforeEnd = DateUtils.previous(1, endDate);
101+
if (item.date.getTime() < dayBeforeEnd.getTime() && item.date.toLocaleDateString() !== dayBeforeEnd.toLocaleDateString()) {
102+
let nextDate: Date = item.date;
103+
while (nextDate.toLocaleDateString() !== dayBeforeEnd.toLocaleDateString()) {
104+
nextDate = DateUtils.next(1, nextDate);
105+
spacedData.push(getPlaceholder(nextDate));
106+
}
107+
}
108+
return;
109+
}
110+
111+
const previous = data[index - 1];
112+
113+
if (item.date.toLocaleDateString() === previous.date.toLocaleDateString()) return spacedData.push(item);
114+
if (item.date.toLocaleDateString() === DateUtils.next(1, previous.date).toLocaleDateString()) return spacedData.push(item);
115+
116+
// if the item isn't at least 1 day after the previous date, add placeholders
117+
let previousDate: Date = previous.date;
118+
while (item.date.toLocaleDateString() !== DateUtils.next(1, previousDate).toLocaleDateString()) {
119+
previousDate = DateUtils.next(1, previousDate);
120+
spacedData.push(getPlaceholder(previousDate));
121+
}
122+
spacedData.push(item);
123+
});
124+
if (!spacedData.length) spacedData.push(...getEmptyWeeks(startDate));
125+
126+
// if no data in response fill with placeholders
127+
return spacedData;
128+
};
129+
80130
const fetchCalendar = async (mode: 'start' | 'end' | 'reload' = 'reload') => {
81131
if (!firstLoad.value && loading.value) {
82132
console.warn('Already fetching calendar');
83133
return;
84134
}
135+
if (filter.value) {
136+
console.warn('Filtering calendar, fetch is disabled');
137+
return;
138+
}
139+
85140
if (firstLoad.value) firstLoad.value = false;
86141

87142
loading.value = true;
@@ -140,51 +195,7 @@ export const useCalendarStore = defineStore('data.calendar', () => {
140195
}),
141196
].sort((a, b) => a.date.getTime() - b.date.getTime());
142197

143-
const spacedData: CalendarItem[] = [];
144-
newData.forEach((item, index) => {
145-
if (index === 0) {
146-
// if the first item isn't the start date, add placeholders
147-
if (item.date.getTime() > startDate.getTime() && item.date.toLocaleDateString() !== startDate.toLocaleDateString()) {
148-
let previousDate: Date = item.date;
149-
while (previousDate.toLocaleDateString() !== startDate.toLocaleDateString()) {
150-
previousDate = DateUtils.previous(1, previousDate);
151-
spacedData.push(getPlaceholder(previousDate));
152-
}
153-
}
154-
return spacedData.push(item);
155-
}
156-
157-
if (index === newData.length - 1) {
158-
spacedData.push(item);
159-
160-
// if the last item isn't one day before the end date, add placeholders
161-
const dayBeforeEnd = DateUtils.previous(1, endDate);
162-
if (item.date.getTime() < dayBeforeEnd.getTime() && item.date.toLocaleDateString() !== dayBeforeEnd.toLocaleDateString()) {
163-
let nextDate: Date = item.date;
164-
while (nextDate.toLocaleDateString() !== dayBeforeEnd.toLocaleDateString()) {
165-
nextDate = DateUtils.next(1, nextDate);
166-
spacedData.push(getPlaceholder(nextDate));
167-
}
168-
}
169-
return;
170-
}
171-
172-
const previous = newData[index - 1];
173-
174-
if (item.date.toLocaleDateString() === previous.date.toLocaleDateString()) return spacedData.push(item);
175-
if (item.date.toLocaleDateString() === DateUtils.next(1, previous.date).toLocaleDateString()) return spacedData.push(item);
176-
177-
// if the item isn't at least 1 day after the previous date, add placeholders
178-
let previousDate: Date = previous.date;
179-
while (item.date.toLocaleDateString() !== DateUtils.next(1, previousDate).toLocaleDateString()) {
180-
previousDate = DateUtils.next(1, previousDate);
181-
spacedData.push(getPlaceholder(previousDate));
182-
}
183-
spacedData.push(item);
184-
});
185-
186-
// if no data in response fill with placeholders
187-
if (!spacedData.length) spacedData.push(...getEmptyWeeks(startDate));
198+
const spacedData = spaceDate(newData, startDate, endDate);
188199

189200
if (mode === 'reload') {
190201
calendar.value = [...spacedData];
@@ -203,7 +214,22 @@ export const useCalendarStore = defineStore('data.calendar', () => {
203214
}
204215
};
205216

206-
return { clearState, saveState, restoreState, loading, pageSize: weeks, calendar, startCalendar, endCalendar, fetchCalendar, filter, center };
217+
const filteredCalendar = useSearchFilter(calendar, filter, 'date');
218+
219+
return {
220+
clearState,
221+
saveState,
222+
restoreState,
223+
loading,
224+
pageSize: weeks,
225+
calendar,
226+
startCalendar,
227+
endCalendar,
228+
fetchCalendar,
229+
filter,
230+
center,
231+
filteredCalendar,
232+
};
207233
});
208234

209235
export const useCalendarStoreRefs = () => storeToRefs(useCalendarStore());

0 commit comments

Comments
 (0)