Skip to content

Commit bc99faf

Browse files
committed
feat(panel): adds movie button, and disable buttons while loading
1 parent 1e0cdb8 commit bc99faf

12 files changed

+483
-77
lines changed

src/components/views/panel/MoviePanel.vue

+29-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import { computed, onMounted, onUnmounted, ref, toRefs, watch } from 'vue';
55
import type { TraktMovieExtended } from '~/models/trakt/trakt-movie.model';
66
77
import TitleLink from '~/components/common/buttons/TitleLink.vue';
8+
import MoviePanelButtons from '~/components/views/panel/MoviePanelButtons.vue';
89
import MoviePanelDetails from '~/components/views/panel/MoviePanelDetails.vue';
910
import MoviePanelOverview from '~/components/views/panel/MoviePanelOverview.vue';
1011
import PanelPoster from '~/components/views/panel/PanelPoster.vue';
1112
1213
import { ResolveExternalLinks } from '~/settings/external.links';
13-
import { useMovieStore } from '~/stores/data/movie.store';
14+
import { useMovieStore, useMovieStoreRefs } from '~/stores/data/movie.store';
1415
import { useExtensionSettingsStore } from '~/stores/settings/extension.store';
1516
import { useI18n } from '~/utils';
1617
import { deCapitalise } from '~/utils/string.utils';
@@ -26,7 +27,25 @@ const { movieId } = toRefs(props);
2627
2728
const movie = ref<TraktMovieExtended>();
2829
29-
const { getMovieRef } = useMovieStore();
30+
const {
31+
getMovieRef,
32+
getMovieWatched,
33+
getMovieCollected,
34+
fetchMovieWatched,
35+
fetchMovieCollected,
36+
} = useMovieStore();
37+
38+
const { loadingCollected, loadingWatched } = useMovieStoreRefs();
39+
40+
const watched = computed(() => {
41+
if (!movieId?.value) return;
42+
return !!getMovieWatched(movieId.value)?.value;
43+
});
44+
45+
const collected = computed(() => {
46+
if (!movieId?.value) return;
47+
return !!getMovieCollected(movieId.value)?.value;
48+
});
3049
3150
const unsub = ref<() => void>();
3251
@@ -37,6 +56,7 @@ onMounted(() =>
3756
unsub.value?.();
3857
if (!id) return;
3958
unsub.value = getMovieRef(id, movie).unsub;
59+
await Promise.all([fetchMovieWatched(), fetchMovieCollected()]);
4060
},
4161
{ immediate: true },
4262
),
@@ -83,6 +103,13 @@ const { openTab } = useExtensionSettingsStore();
83103

84104
<MoviePanelDetails :movie="movie" />
85105

106+
<MoviePanelButtons
107+
:watched="watched"
108+
:watched-loading="loadingWatched"
109+
:collected="collected"
110+
:collected-loading="loadingCollected"
111+
/>
112+
86113
<MoviePanelOverview :movie="movie" />
87114
</NFlex>
88115
</template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
<script lang="ts" setup>
2+
import { NButton, NFlex, NIcon } from 'naive-ui';
3+
import { computed, onMounted, type PropType, ref, toRefs } from 'vue';
4+
5+
import IconCheckedList from '~/components/icons/IconCheckedList.vue';
6+
import IconCloseSmall from '~/components/icons/IconCloseSmall.vue';
7+
import IconGrid from '~/components/icons/IconGrid.vue';
8+
import IconGridEmpty from '~/components/icons/IconGridEmpty.vue';
9+
import IconListEmpty from '~/components/icons/IconListEmpty.vue';
10+
import IconPlay from '~/components/icons/IconPlay.vue';
11+
import IconPlayFilled from '~/components/icons/IconPlayFilled.vue';
12+
13+
import IconTrakt from '~/components/icons/IconTrakt.vue';
14+
import PanelButtonProgress from '~/components/views/panel/PanelButtonProgress.vue';
15+
import { usePanelButtons } from '~/components/views/panel/use-panel-buttons';
16+
import {
17+
type ListEntity,
18+
ListType,
19+
useListsStore,
20+
useListsStoreRefs,
21+
} from '~/stores/data/list.store';
22+
import { useI18n } from '~/utils';
23+
24+
const props = defineProps({
25+
watched: {
26+
type: Boolean,
27+
required: false,
28+
},
29+
watchedLoading: {
30+
type: Boolean,
31+
required: false,
32+
},
33+
collected: {
34+
type: Boolean,
35+
required: false,
36+
},
37+
collectedLoading: {
38+
type: Boolean,
39+
required: false,
40+
},
41+
checkin: {
42+
type: Boolean,
43+
required: false,
44+
},
45+
checkinProgress: {
46+
type: Number,
47+
required: false,
48+
},
49+
checkinLoading: {
50+
type: Boolean,
51+
required: false,
52+
},
53+
activeLists: {
54+
type: Array as PropType<ListEntity['id'][]>,
55+
required: false,
56+
},
57+
activeLoading: {
58+
type: Boolean,
59+
required: false,
60+
},
61+
});
62+
63+
const { watched, collected, activeLoading } = toRefs(props);
64+
65+
const i18n = useI18n('panel', 'buttons');
66+
67+
const root = ref<HTMLDivElement>();
68+
69+
const { removeOptions, timeOptions } = usePanelButtons();
70+
71+
const watchedOptions = computed(() => {
72+
if (watched.value) return removeOptions;
73+
return timeOptions;
74+
});
75+
76+
const collectionOptions = computed(() => {
77+
if (collected.value) return removeOptions;
78+
return timeOptions;
79+
});
80+
81+
const { lists, loading } = useListsStoreRefs();
82+
const { fetchLists, getIcon } = useListsStore();
83+
84+
const listsLoading = computed(() => {
85+
return loading.value || activeLoading.value;
86+
});
87+
88+
const listOptions = computed(() => {
89+
return lists.value
90+
?.filter(list => [ListType.List, ListType.Watchlist].map(String).includes(list.type))
91+
.map(list => {
92+
return {
93+
label: list.type === ListType.Watchlist ? i18n(list.name) : list.name,
94+
value: list.id,
95+
icon: getIcon(list),
96+
};
97+
});
98+
});
99+
100+
onMounted(() => {
101+
fetchLists();
102+
});
103+
</script>
104+
105+
<template>
106+
<div ref="root" class="panel-buttons">
107+
<!-- Checkin -->
108+
<NFlex class="button-container checkin" justify="center" align="center">
109+
<NButton round :secondary="!checkin" type="error" :disabled="checkinLoading">
110+
<template #icon>
111+
<NIcon
112+
class="button-icon"
113+
:component="checkin ? IconCloseSmall : IconTrakt"
114+
:style="{
115+
'--trakt-icon-path': 'var(--color-error-lighter)',
116+
'--trakt-icon-circle': 'transparent',
117+
}"
118+
/>
119+
</template>
120+
<span>{{ i18n(`label__${ checkin ? 'cancel_checkin' : 'checkin' }`) }}</span>
121+
</NButton>
122+
</NFlex>
123+
124+
<!-- List -->
125+
<NFlex class="button-container list" justify="center" align="center">
126+
<PanelButtonProgress
127+
:options="listOptions"
128+
:value="activeLists"
129+
:select="{
130+
options: listOptions,
131+
value: activeLists,
132+
multiple: true,
133+
scrollable: true,
134+
}"
135+
:icon="activeLists?.length ? IconCheckedList : IconListEmpty"
136+
:filled="!!activeLists?.length"
137+
:disabled="listsLoading"
138+
type="warning"
139+
>
140+
{{ i18n(`label__list__${ activeLists?.length ? 'update' : 'add' }`) }}
141+
</PanelButtonProgress>
142+
</NFlex>
143+
144+
<!-- Collection -->
145+
<NFlex class="button-container collection" justify="center" align="center">
146+
<PanelButtonProgress
147+
:select="{
148+
options: collectionOptions,
149+
}"
150+
:icon="collected ? IconGrid : IconGridEmpty"
151+
:filled="collected"
152+
:disabled="collectedLoading"
153+
type="info"
154+
>
155+
{{ i18n(`label__collection__${ collected ? 'remove' : 'add' }`) }}
156+
</PanelButtonProgress>
157+
</NFlex>
158+
159+
<!-- History -->
160+
<NFlex class="button-container history" justify="center" align="center">
161+
<PanelButtonProgress
162+
:select="{
163+
options: watchedOptions,
164+
}"
165+
:icon="watched ? IconPlayFilled : IconPlay"
166+
:filled="watched"
167+
:disabled="watchedLoading"
168+
>
169+
{{ i18n(`label__history__${ watched ? 'remove' : 'add' }`) }}
170+
</PanelButtonProgress>
171+
</NFlex>
172+
</div>
173+
</template>
174+
175+
<style lang="scss" scoped>
176+
.panel-buttons {
177+
display: flex;
178+
flex-wrap: wrap;
179+
gap: 1.25rem 1rem;
180+
align-items: center;
181+
justify-content: center;
182+
width: 100%;
183+
margin: 0.75rem 1rem 1.25rem;
184+
185+
.button-container {
186+
i {
187+
margin-left: calc(0% - var(--n-icon-margin));
188+
}
189+
190+
&.history,
191+
&.collection {
192+
min-width: 12.5rem;
193+
}
194+
195+
&.checkin,
196+
&.list {
197+
min-width: 10rem;
198+
}
199+
}
200+
}
201+
202+
@media (width <= 800px) {
203+
.panel-buttons {
204+
width: 80%;
205+
206+
.button-container {
207+
flex: 1 1 40%;
208+
}
209+
}
210+
}
211+
</style>

src/components/views/panel/ShowPanel.vue

+20-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import type {
99
import type { TraktShowExtended } from '~/models/trakt/trakt-show.model';
1010
1111
import TitleLink from '~/components/common/buttons/TitleLink.vue';
12-
import PanelButtons from '~/components/views/panel/PanelButtons.vue';
1312
import PanelPoster from '~/components/views/panel/PanelPoster.vue';
13+
import ShowPanelButtons from '~/components/views/panel/ShowPanelButtons.vue';
1414
import ShowPanelDetails from '~/components/views/panel/ShowPanelDetails.vue';
1515
import ShowPanelOverview from '~/components/views/panel/ShowPanelOverview.vue';
1616
import ShowPanelPicker from '~/components/views/panel/ShowPanelPicker.vue';
@@ -42,7 +42,12 @@ const episode = ref<TraktEpisodeExtended>();
4242
4343
const { showId, seasonNumber, episodeNumber } = toRefs(props);
4444
45-
const { getShowWatchedProgress, getShowCollectionProgress } = useShowStore();
45+
const {
46+
getShowWatchedProgress,
47+
getShowCollectionProgress,
48+
getShowProgressLoading,
49+
getShowCollectionLoading,
50+
} = useShowStore();
4651
4752
const i18n = useI18n('panel', 'show');
4853
@@ -51,11 +56,21 @@ const watchedProgress = computed(() => {
5156
return getShowWatchedProgress(showId.value).value;
5257
});
5358
59+
const watchedLoading = computed(() => {
60+
if (!showId?.value) return;
61+
return getShowProgressLoading(showId.value).value;
62+
});
63+
5464
const collectionProgress = computed(() => {
5565
if (!showId?.value) return;
5666
return getShowCollectionProgress(showId.value).value;
5767
});
5868
69+
const collectionLoading = computed(() => {
70+
if (!showId?.value) return;
71+
return getShowCollectionLoading(showId.value).value;
72+
});
73+
5974
const seasonNb = computed(() => {
6075
if (seasonNumber?.value === undefined) return;
6176
const _seasonNumber = Number(seasonNumber.value);
@@ -224,10 +239,12 @@ const { openTab } = useExtensionSettingsStore();
224239
:mode="panelType"
225240
/>
226241

227-
<PanelButtons
242+
<ShowPanelButtons
228243
:mode="panelType"
229244
:watched-progress="watchedProgressEntity"
245+
:watched-loading="watchedLoading"
230246
:collection-progress="collectionProgressEntity"
247+
:collection-loading="collectionLoading"
231248
/>
232249

233250
<ShowPanelPicker

0 commit comments

Comments
 (0)