forked from mirror/pixelfed
246 lines
6.2 KiB
Vue
246 lines
6.2 KiB
Vue
<template>
|
|
<div>
|
|
<b-modal
|
|
ref="likesModal"
|
|
centered
|
|
size="md"
|
|
:scrollable="true"
|
|
hide-footer
|
|
header-class="py-2"
|
|
body-class="p-0"
|
|
title-class="w-100 text-center pl-4 font-weight-bold"
|
|
title-tag="p"
|
|
:title="$t('common.likes')">
|
|
<div v-if="isLoading" class="likes-loader list-group border-top-0" style="max-height: 500px;">
|
|
<like-placeholder />
|
|
</div>
|
|
|
|
<div v-else>
|
|
<div v-if="!likes.length" class="d-flex justify-content-center align-items-center" style="height: 140px;">
|
|
<p class="font-weight-bold mb-0">{{ $t('post.noLikes') }}</p>
|
|
</div>
|
|
|
|
<div v-else class="list-group" style="max-height: 500px;">
|
|
<div v-for="(account, index) in likes" class="list-group-item border-left-0 border-right-0 px-3" :class="[ index === 0 ? 'border-top-0' : '']">
|
|
<div class="media align-items-center">
|
|
<img :src="account.avatar" width="40" height="40" style="border-radius: 8px;" class="mr-3 shadow-sm" onerror="this.src='/storage/avatars/default.jpg?v=0';this.onerror=null;">
|
|
<div class="media-body">
|
|
<p class="mb-0 text-truncate"><a :href="account.url" class="text-dark font-weight-bold text-decoration-none" @click.prevent="goToProfile(account)">{{ getUsername(account) }}</a></p>
|
|
<p class="mb-0 mt-n1 text-dark font-weight-bold small text-break">@{{ account.acct }}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<button
|
|
v-if="account.follows == null || account.id == user.id"
|
|
class="btn btn-outline-muted rounded-pill btn-sm font-weight-bold"
|
|
@click="goToProfile(profile)"
|
|
style="width:110px;">
|
|
View Profile
|
|
</button>
|
|
<button
|
|
v-else-if="account.follows"
|
|
class="btn btn-outline-muted rounded-pill btn-sm font-weight-bold"
|
|
:disabled="isUpdatingFollowState"
|
|
@click="handleUnfollow(index)"
|
|
style="width:110px;">
|
|
<span v-if="isUpdatingFollowState && followStateIndex === index">
|
|
<b-spinner small />
|
|
</span>
|
|
<span v-else>Following</span>
|
|
</button>
|
|
<button
|
|
v-else-if="!account.follows"
|
|
class="btn btn-primary rounded-pill btn-sm font-weight-bold"
|
|
:disabled="isUpdatingFollowState"
|
|
@click="handleFollow(index)"
|
|
style="width:110px;">
|
|
<span v-if="isUpdatingFollowState && followStateIndex === index">
|
|
<b-spinner small />
|
|
</span>
|
|
<span v-else>Follow</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="canLoadMore">
|
|
<intersect @enter="enterIntersect">
|
|
<like-placeholder class="border-top-0" />
|
|
</intersect>
|
|
<like-placeholder />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</b-modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script type="text/javascript">
|
|
import Intersect from 'vue-intersect'
|
|
import LikePlaceholder from './LikeListPlaceholder.vue';
|
|
import { parseLinkHeader } from '@web3-storage/parse-link-header';
|
|
|
|
export default {
|
|
props: {
|
|
status: {
|
|
type: Object
|
|
},
|
|
|
|
profile: {
|
|
type: Object
|
|
}
|
|
},
|
|
|
|
components: {
|
|
"intersect": Intersect,
|
|
"like-placeholder": LikePlaceholder
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
isOpen: false,
|
|
isLoading: true,
|
|
canLoadMore: false,
|
|
isFetchingMore: false,
|
|
likes: [],
|
|
ids: [],
|
|
cursor: undefined,
|
|
isUpdatingFollowState: false,
|
|
followStateIndex: undefined,
|
|
user: window._sharedData.user
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
clear() {
|
|
this.isOpen = false;
|
|
this.isLoading = true;
|
|
this.canLoadMore = false;
|
|
this.isFetchingMore = false;
|
|
this.likes = [];
|
|
this.ids = [];
|
|
this.cursor = undefined;
|
|
},
|
|
|
|
fetchLikes() {
|
|
axios.get('/api/v1/statuses/'+this.status.id+'/favourited_by', {
|
|
params: {
|
|
limit: 40,
|
|
'_pe': 1
|
|
}
|
|
})
|
|
.then(res => {
|
|
this.ids = res.data.map(a => a.id);
|
|
this.likes = res.data;
|
|
if(res.headers && res.headers.link) {
|
|
const links = parseLinkHeader(res.headers.link);
|
|
if(links.prev) {
|
|
this.cursor = links.prev.cursor;
|
|
this.canLoadMore = true;
|
|
} else {
|
|
this.canLoadMore = false;
|
|
}
|
|
} else {
|
|
this.canLoadMore = false;
|
|
}
|
|
this.isLoading = false;
|
|
});
|
|
},
|
|
|
|
open() {
|
|
if(this.cursor) {
|
|
this.clear();
|
|
}
|
|
this.isOpen = true;
|
|
this.fetchLikes();
|
|
this.$refs.likesModal.show();
|
|
},
|
|
|
|
enterIntersect() {
|
|
if(this.isFetchingMore) {
|
|
return;
|
|
}
|
|
|
|
this.isFetchingMore = true;
|
|
|
|
axios.get('/api/v1/statuses/'+this.status.id+'/favourited_by', {
|
|
params: {
|
|
limit: 10,
|
|
cursor: this.cursor,
|
|
'_pe': 1
|
|
}
|
|
}).then(res => {
|
|
if(!res.data || !res.data.length) {
|
|
this.canLoadMore = false;
|
|
this.isFetchingMore = false;
|
|
return;
|
|
}
|
|
res.data.forEach(user => {
|
|
if(this.ids.indexOf(user.id) == -1) {
|
|
this.ids.push(user.id);
|
|
this.likes.push(user);
|
|
}
|
|
})
|
|
if(res.headers && res.headers.link) {
|
|
const links = parseLinkHeader(res.headers.link);
|
|
if(links.prev) {
|
|
this.cursor = links.prev.cursor;
|
|
} else {
|
|
this.canLoadMore = false;
|
|
}
|
|
} else {
|
|
this.canLoadMore = false;
|
|
}
|
|
this.isFetchingMore = false;
|
|
})
|
|
},
|
|
|
|
getUsername(account) {
|
|
return account.display_name ? account.display_name : account.username;
|
|
},
|
|
|
|
goToProfile(account) {
|
|
this.$router.push({
|
|
name: 'profile',
|
|
path: `/i/web/profile/${account.id}`,
|
|
params: {
|
|
id: account.id,
|
|
cachedProfile: account,
|
|
cachedUser: this.profile
|
|
}
|
|
})
|
|
},
|
|
|
|
handleFollow(index) {
|
|
event.currentTarget.blur();
|
|
|
|
this.followStateIndex = index;
|
|
this.isUpdatingFollowState = true;
|
|
|
|
let account = this.likes[index];
|
|
axios.post('/api/v1/accounts/' + account.id + '/follow')
|
|
.then(res => {
|
|
this.likes[index].follows = true;
|
|
this.followStateIndex = undefined;
|
|
this.isUpdatingFollowState = false;
|
|
});
|
|
},
|
|
|
|
handleUnfollow(index) {
|
|
event.currentTarget.blur();
|
|
|
|
this.followStateIndex = index;
|
|
this.isUpdatingFollowState = true;
|
|
|
|
let account = this.likes[index];
|
|
axios.post('/api/v1/accounts/' + account.id + '/unfollow')
|
|
.then(res => {
|
|
this.likes[index].follows = false;
|
|
this.followStateIndex = undefined;
|
|
this.isUpdatingFollowState = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
</script>
|