Skip to content

Commit 261056f

Browse files
committed
feat(progress): adds logout/sign-in prompt
1 parent 92ef9cf commit 261056f

File tree

5 files changed

+206
-91
lines changed

5 files changed

+206
-91
lines changed
+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<script setup lang="ts">
2+
import { NButton, NCard, NFlex, NH4 } from 'naive-ui';
3+
4+
import type { ButtonProps } from 'naive-ui';
5+
6+
import type { PropType } from 'vue';
7+
8+
import { useI18n } from '~/utils';
9+
10+
const i18n = useI18n('login');
11+
12+
defineProps({
13+
logo: {
14+
type: String,
15+
required: false,
16+
},
17+
hideLogo: {
18+
type: Boolean,
19+
required: false,
20+
},
21+
title: {
22+
type: String,
23+
required: false,
24+
},
25+
message: {
26+
type: String,
27+
required: false,
28+
},
29+
buttonText: {
30+
type: String,
31+
required: false,
32+
},
33+
buttonProps: {
34+
type: Object as PropType<ButtonProps & Pick<HTMLAnchorElement, 'href'>>,
35+
required: false,
36+
},
37+
});
38+
39+
const emits = defineEmits<{
40+
(name: 'onSignIn', e: MouseEvent): void;
41+
}>();
42+
</script>
43+
44+
<template>
45+
<NCard class="card" :title="title ?? i18n('title')" hoverable>
46+
<template v-if="!hideLogo" #cover>
47+
<div class="spacer" />
48+
<img
49+
alt="Vue logo"
50+
class="logo"
51+
:src="logo ?? '/assets/logo.svg'"
52+
width="125"
53+
height="125"
54+
/>
55+
</template>
56+
57+
<NFlex class="content" vertical justify="space-evenly">
58+
<slot name="message">
59+
<NH4 class="title" prefix="bar">{{ message ?? i18n('sub_title') }}</NH4>
60+
</slot>
61+
62+
<slot name="button">
63+
<NButton
64+
class="button"
65+
secondary
66+
type="primary"
67+
round
68+
v-bind="buttonProps"
69+
@click="e => emits('onSignIn', e)"
70+
>
71+
{{ buttonText ?? i18n('sign_in') }}
72+
</NButton>
73+
</slot>
74+
75+
<slot />
76+
</NFlex>
77+
</NCard>
78+
</template>
79+
80+
<style lang="scss" scoped>
81+
@use '~/styles/mixin' as mixin;
82+
83+
.card {
84+
@include mixin.hover-background;
85+
86+
height: 100%;
87+
padding: 0 1.75rem;
88+
89+
.spacer {
90+
height: 60px;
91+
}
92+
93+
.logo {
94+
position: absolute;
95+
top: -50px;
96+
left: 0;
97+
}
98+
99+
:deep(.n-card-header) {
100+
font-size: 3em;
101+
text-align: center;
102+
}
103+
104+
.content {
105+
height: 100%;
106+
107+
.title {
108+
margin: 0;
109+
padding: 1rem;
110+
white-space: pre-line;
111+
background: rgb(99 226 184 / 5%);
112+
transition: background 0.5s;
113+
will-change: background;
114+
}
115+
116+
.button {
117+
align-self: center;
118+
width: fit-content;
119+
margin: 2rem;
120+
padding: 1.25rem 1.5rem;
121+
}
122+
}
123+
124+
&:hover {
125+
.title {
126+
background: rgb(99 226 184 / 9%);
127+
}
128+
}
129+
}
130+
</style>
+20-75
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script lang="ts" setup>
2-
import { NButton, NCard, NCheckbox, NFlex, NH4, NText } from 'naive-ui';
2+
import { NCheckbox, NFlex, NText } from 'naive-ui';
33
44
import { onMounted, ref, Transition, watch } from 'vue';
55
66
import { useRoute, useRouter } from 'vue-router';
77
88
import GridBackground from '~/components/common/background/GridBackground.vue';
9+
import LoginCard from '~/components/views/login/LoginCard.vue';
910
import { TraktService } from '~/services/trakt.service';
1011
import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1112
import { useI18n } from '~/utils';
@@ -23,6 +24,7 @@ const onRedirect = (authenticated = isAuthenticated.value) => {
2324
};
2425
2526
const show = ref(false);
27+
2628
onMounted(() => {
2729
onRedirect();
2830
watch(isAuthenticated, authenticated => {
@@ -52,89 +54,32 @@ const onSignIn = async () => {
5254

5355
<Transition name="scale" mode="in-out">
5456
<div v-if="show">
55-
<NCard class="card" :title="i18n('title')" hoverable>
56-
<template #cover>
57-
<div class="spacer" />
58-
<img
59-
alt="Vue logo"
60-
class="logo"
61-
src="/assets/logo.svg"
62-
width="125"
63-
height="125"
64-
/>
65-
</template>
66-
67-
<NFlex vertical>
68-
<NH4 class="title" prefix="bar">{{ i18n('sub_title') }}</NH4>
69-
70-
<NButton class="button" @click="onSignIn">{{ i18n('sign_in') }}</NButton>
71-
72-
<NFlex class="checkboxes" vertical>
73-
<NCheckbox v-model:checked="signUp">
74-
{{ i18n('checkbox__sign_up_for') }}
75-
<NText type="info">{{ i18n('checkbox__new_account') }}</NText>
76-
!
77-
</NCheckbox>
78-
<NCheckbox v-model:checked="useSession">
79-
{{ i18n('checkbox__use') }}
80-
<NText type="info">{{ i18n('checkbox__active_user') }}</NText>
81-
{{ i18n('checkbox__session') }}
82-
</NCheckbox>
83-
</NFlex>
57+
<LoginCard @on-sign-in="onSignIn">
58+
<NFlex class="checkboxes" vertical>
59+
<NCheckbox v-model:checked="signUp">
60+
{{ i18n('checkbox__sign_up_for') }}
61+
<NText type="info">{{ i18n('checkbox__new_account') }}</NText>
62+
!
63+
</NCheckbox>
64+
<NCheckbox v-model:checked="useSession">
65+
{{ i18n('checkbox__use') }}
66+
<NText type="info">{{ i18n('checkbox__active_user') }}</NText>
67+
{{ i18n('checkbox__session') }}
68+
</NCheckbox>
8469
</NFlex>
85-
</NCard>
70+
</LoginCard>
8671
</div>
8772
</Transition>
8873
</NFlex>
8974
</template>
9075

9176
<style lang="scss" scoped>
92-
@use '~/styles/mixin' as mixin;
9377
@use '~/styles/transition' as transition;
9478
@include transition.scale(0.9);
9579
96-
.card {
97-
@include mixin.hover-background;
98-
99-
padding: 0 1.5rem;
100-
101-
.spacer {
102-
height: 60px;
103-
}
104-
105-
.logo {
106-
position: absolute;
107-
top: -50px;
108-
left: 0;
109-
}
110-
111-
:deep(.n-card-header) {
112-
font-size: 3em;
113-
text-align: center;
114-
}
115-
116-
.title {
117-
margin: 0;
118-
padding: 1rem;
119-
background: rgb(99 226 184 / 5%);
120-
transition: background 0.5s;
121-
will-change: background;
122-
}
123-
124-
.button {
125-
margin: 2rem;
126-
}
127-
128-
.checkboxes {
129-
align-self: center;
130-
width: fit-content;
131-
margin-bottom: 1.5rem;
132-
}
133-
134-
&:hover {
135-
.title {
136-
background: rgb(99 226 184 / 9%);
137-
}
138-
}
80+
.checkboxes {
81+
align-self: center;
82+
width: fit-content;
83+
margin-bottom: 1.5rem;
13984
}
14085
</style>
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
<script lang="ts" setup>
2-
import { onMounted } from 'vue';
2+
import { NFlex } from 'naive-ui';
3+
import { onMounted, Transition } from 'vue';
34
45
import FloatingButton from '~/components/common/buttons/FloatingButton.vue';
56
import { useBackToTop } from '~/components/common/buttons/use-back-to-top';
67
import ListScroll from '~/components/common/list/ListScroll.vue';
78
9+
import LoginCard from '~/components/views/login/LoginCard.vue';
10+
import { ExternaLinks } from '~/settings/external.links';
811
import { useProgressStore, useProgressStoreRefs } from '~/stores/data/progress.store';
912
import { useI18n } from '~/utils';
1013
1114
const i18n = useI18n('progress');
1215
13-
const { progress, loading } = useProgressStoreRefs();
16+
const { progress, loading, loggedOut } = useProgressStoreRefs();
1417
const { fetchProgress } = useProgressStore();
1518
1619
onMounted(async () => {
@@ -22,19 +25,33 @@ const { scrolled, listRef, onClick } = useBackToTop();
2225

2326
<template>
2427
<div class="container">
25-
<ListScroll
26-
ref="listRef"
27-
:loading="loading"
28-
:items="progress"
29-
episode
30-
hide-date
31-
@on-scroll="scrolled = true"
32-
@on-scroll-top="scrolled = false"
33-
>
34-
<template #default>
35-
<!-- TODO buttons here-->
36-
</template>
37-
</ListScroll>
28+
<Transition name="fade" mode="out-in">
29+
<NFlex v-if="loggedOut" justify="center" align="center" vertical>
30+
<LoginCard
31+
class="logout"
32+
:message="i18n('logout__cookies') + '\n' + i18n('logout__trakt')"
33+
:button-props="{
34+
tag: 'a',
35+
href: ExternaLinks.trakt.production,
36+
}"
37+
hide-logo
38+
/>
39+
</NFlex>
40+
<ListScroll
41+
v-else
42+
ref="listRef"
43+
:loading="loading"
44+
:items="progress"
45+
episode
46+
hide-date
47+
@on-scroll="scrolled = true"
48+
@on-scroll-top="scrolled = false"
49+
>
50+
<template #default>
51+
<!-- TODO buttons here-->
52+
</template>
53+
</ListScroll>
54+
</Transition>
3855

3956
<FloatingButton :show="scrolled" @on-click="onClick">
4057
{{ i18n('back_to_top', 'common', 'button') }}
@@ -43,8 +60,19 @@ const { scrolled, listRef, onClick } = useBackToTop();
4360
</template>
4461

4562
<style lang="scss" scoped>
63+
@use '~/styles/transition' as transition;
64+
@include transition.fade($transition: 0.5s);
65+
4666
.container {
4767
width: 100%;
4868
height: 100%;
69+
70+
.logout {
71+
width: fit-content;
72+
73+
:deep(.button) {
74+
padding: 0.25rem 1rem;
75+
}
76+
}
4977
}
5078
</style>

src/services/trakt.service.ts

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { LoadingBarService } from '~/services/loading-bar.service';
1717
import { tmdbApi } from '~/services/tmdb-client/api/tmdb-api.endpoints';
1818
import { TmdbClient } from '~/services/tmdb-client/clients/tmdb-client';
1919
import { traktApi } from '~/services/trakt-client/api/trakt-api.endpoints';
20+
import { isResponseOk } from '~/services/trakt-client/clients/base-trakt-client';
2021
import { TraktClient } from '~/services/trakt-client/clients/trakt-client';
2122
import { tvdbApi } from '~/services/tvdb-client/api/tvdb-api.endpoints';
2223
import { TvdbClient } from '~/services/tvdb-client/clients/tvdb-client';
@@ -273,6 +274,8 @@ export class TraktService {
273274
credentials: 'include',
274275
});
275276

277+
isResponseOk(response);
278+
276279
const htmlString = await response.text();
277280
const htmlDoc = new DOMParser().parseFromString(htmlString, 'text/html');
278281
const data = Array.from(htmlDoc.querySelectorAll<HTMLAnchorElement>('a[class="watch"]')).map(
@@ -298,6 +301,7 @@ export class TraktService {
298301

299302
static async progress() {
300303
const response = await this.cachedProgress();
304+
if (!response.ok) throw response;
301305
return response.json();
302306
}
303307
}

0 commit comments

Comments
 (0)