feat: support for subscribing to channels in search results

This commit is contained in:
Bnyro 2024-01-19 15:24:12 +01:00
parent c203f0e110
commit dc63d0b38b
4 changed files with 96 additions and 82 deletions

View file

@ -1,37 +1,72 @@
<template> <template>
<div class="flex flex-col flex-justify-between"> <div class="flex flex-col flex-justify-between">
<router-link :to="props.item.url"> <router-link :to="item.url">
<div class="my-4 flex justify-center"> <div class="my-4 flex justify-center">
<img loading="lazy" class="aspect-square w-[50%] rounded-full" :src="props.item.thumbnail" /> <img loading="lazy" class="aspect-square w-[50%] rounded-full" :src="item.thumbnail" />
</div> </div>
<p> <p>
<span v-text="props.item.name" /> <span v-text="item.name" />
<font-awesome-icon v-if="props.item.verified" class="ml-1.5" icon="check" /> <font-awesome-icon v-if="item.verified" class="ml-1.5" icon="check" />
</p> </p>
</router-link> </router-link>
<p v-if="props.item.description" v-text="props.item.description" /> <p v-if="item.description" v-text="item.description" />
<router-link v-if="props.item.uploaderUrl" class="link" :to="props.item.uploaderUrl"> <router-link v-if="item.uploaderUrl" class="link" :to="item.uploaderUrl">
<p> <p>
<span v-text="props.item.uploader" /> <span v-text="item.uploader" />
<font-awesome-icon v-if="props.item.uploaderVerified" class="ml-1.5" icon="check" /> <font-awesome-icon v-if="item.uploaderVerified" class="ml-1.5" icon="check" />
</p> </p>
</router-link> </router-link>
<a v-if="props.item.uploaderName" class="link" v-text="props.item.uploaderName" /> <a v-if="item.uploaderName" class="link" v-text="item.uploaderName" />
<template v-if="props.item.videos >= 0"> <template v-if="item.videos >= 0">
<br v-if="props.item.uploaderName" /> <br v-if="item.uploaderName" />
<strong v-text="`${props.item.videos} ${$t('video.videos')}`" /> <strong v-text="`${item.videos} ${$t('video.videos')}`" />
</template> </template>
<button
v-if="subscribed != null"
class="btn w-max mt-2"
@click="subscribeHandler"
v-text="
$t('actions.' + (subscribed ? 'unsubscribe' : 'subscribe')) + ' - ' + numberFormat(item.subscribers)
"
/>
<br /> <br />
</div> </div>
</template> </template>
<script setup> <script>
const props = defineProps({ export default {
item: { props: {
type: Object, item: {
required: true, type: Object,
required: true,
},
}, },
}); data() {
return {
subscribed: null,
};
},
computed: {
channelId(_this) {
return _this.item.url.substr(-24);
},
},
mounted() {
this.updateSubscribedStatus();
},
methods: {
async updateSubscribedStatus() {
this.subscribed = await this.fetchSubscriptionStatus(this.channelId);
console.log(this.subscribed);
},
subscribeHandler() {
this.toggleSubscriptionState(this.channelId, this.subscribed).then(success => {
if (success) this.subscribed = !this.subscribed;
});
},
},
};
</script> </script>

View file

@ -127,24 +127,8 @@ export default {
methods: { methods: {
async fetchSubscribedStatus() { async fetchSubscribedStatus() {
if (!this.channel.id) return; if (!this.channel.id) return;
if (!this.authenticated) {
this.subscribed = this.isSubscribedLocally(this.channel.id);
return;
}
this.fetchJson( this.subscribed = await this.fetchSubscriptionStatus(this.channel.id);
this.authApiUrl() + "/subscribed",
{
channelId: this.channel.id,
},
{
headers: {
Authorization: this.getAuthToken(),
},
},
).then(json => {
this.subscribed = json.subscribed;
});
}, },
async fetchChannel() { async fetchChannel() {
const url = this.$route.path.includes("@") const url = this.$route.path.includes("@")
@ -216,21 +200,9 @@ export default {
}); });
}, },
subscribeHandler() { subscribeHandler() {
if (this.authenticated) { this.toggleSubscriptionState(this.channel.id, this.subscribed).then(success => {
this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { if (success) this.subscribed = !this.subscribed;
method: "POST", });
body: JSON.stringify({
channelId: this.channel.id,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
});
} else {
if (!this.handleLocalSubscriptions(this.channel.id)) return;
}
this.subscribed = !this.subscribed;
}, },
getTranslatedTabName(tabName) { getTranslatedTabName(tabName) {
let translatedTabName = tabName; let translatedTabName = tabName;

View file

@ -551,24 +551,8 @@ export default {
}, },
async fetchSubscribedStatus() { async fetchSubscribedStatus() {
if (!this.channelId) return; if (!this.channelId) return;
if (!this.authenticated) {
this.subscribed = this.isSubscribedLocally(this.channelId);
return;
}
this.fetchJson( this.subscribed = await this.fetchSubscriptionStatus(this.channelId);
this.authApiUrl() + "/subscribed",
{
channelId: this.channelId,
},
{
headers: {
Authorization: this.getAuthToken(),
},
},
).then(json => {
this.subscribed = json.subscribed;
});
}, },
rewriteComments(data) { rewriteComments(data) {
data.forEach(comment => { data.forEach(comment => {
@ -588,21 +572,9 @@ export default {
}); });
}, },
subscribeHandler() { subscribeHandler() {
if (this.authenticated) { this.toggleSubscriptionState(this.channelId, this.subscribed).then(success => {
this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { if (success) this.subscribed = !this.subscribed;
method: "POST", });
body: JSON.stringify({
channelId: this.channelId,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
});
} else {
if (!this.handleLocalSubscriptions(this.channelId)) return;
}
this.subscribed = !this.subscribed;
}, },
handleClick(event) { handleClick(event) {
if (!event || !event.target) return; if (!event || !event.target) return;

View file

@ -550,6 +550,41 @@ const mixin = {
}); });
}); });
}, },
async fetchSubscriptionStatus(channelId) {
if (!this.authenticated) {
return this.isSubscribedLocally(channelId);
}
const response = await this.fetchJson(
this.authApiUrl() + "/subscribed",
{
channelId: channelId,
},
{
headers: {
Authorization: this.getAuthToken(),
},
},
);
return response?.subscribed;
},
async toggleSubscriptionState(channelId, subscribed) {
if (!this.authenticated) return this.handleLocalSubscriptions(channelId);
const resp = await this.fetchJson(this.authApiUrl() + (subscribed ? "/unsubscribe" : "/subscribe"), null, {
method: "POST",
body: JSON.stringify({
channelId: channelId,
}),
headers: {
Authorization: this.getAuthToken(),
"Content-Type": "application/json",
},
});
return !resp.error;
},
}, },
computed: { computed: {
authenticated(_this) { authenticated(_this) {