mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2026-04-05 17:15:40 +00:00
252 lines
6.4 KiB
Vue
252 lines
6.4 KiB
Vue
<template>
|
|
<div class="invite-code-list">
|
|
<h2 class="invite-code-list__title">
|
|
{{ $t('invite-codes.my-invite-links') }}
|
|
<span class="invite-code-list__count">({{ validInviteCodes.length }}/{{ maxLinks }})</span>
|
|
</h2>
|
|
<invitation-list
|
|
@generate-invite-code="generateInviteCode"
|
|
@invalidate-invite-code="invalidateInviteCode"
|
|
@open-delete-modal="openDeleteModal"
|
|
:inviteCodes="inviteCodes"
|
|
:copy-message="copyMessage"
|
|
/>
|
|
|
|
<p v-if="!showInvitedUsers && totalInvitedCount > 0" class="invite-code-list__invited-summary">
|
|
{{ $t('invite-codes.invited-count', { count: totalInvitedCount }) }}
|
|
</p>
|
|
|
|
<template v-if="showInvitedUsers">
|
|
<profile-list
|
|
class="invite-code-list__profile-list"
|
|
uniqueName="invitedUsersFilter"
|
|
:title="$t('settings.invites.invited-users') + ' (' + totalInvitedCount + ')'"
|
|
:title-nobody="$t('settings.invites.nobody-invited')"
|
|
:all-profiles-count="totalInvitedCount"
|
|
:profiles="visibleInvitedUsers"
|
|
:loading="loadingAll"
|
|
@fetchAllProfiles="loadAllInvitedUsers"
|
|
/>
|
|
|
|
<div v-if="expiredCodes.length" class="invite-code-list__expired">
|
|
<button
|
|
class="invite-code-list__expired-toggle"
|
|
:aria-expanded="String(showExpired)"
|
|
aria-controls="expired-codes-list"
|
|
@click="showExpired = !showExpired"
|
|
>
|
|
<span>
|
|
{{ $t('settings.invites.expired-codes', { count: expiredCodes.length }) }}
|
|
</span>
|
|
<span class="invite-code-list__expired-chevron" :class="{ open: showExpired }">
|
|
▼
|
|
</span>
|
|
</button>
|
|
<ul v-if="showExpired" id="expired-codes-list" class="invite-code-list__expired-list">
|
|
<li v-for="code in expiredCodes" :key="code.code" class="invite-code-list__expired-code">
|
|
<span class="invite-code-list__expired-code-text">{{ code.code }}</span>
|
|
<span v-if="code.comment" class="invite-code-list__expired-code-comment">
|
|
— {{ code.comment }}
|
|
</span>
|
|
<span class="invite-code-list__expired-code-redeemed">
|
|
{{ $t('invite-codes.redeemed-count', { count: code.redeemedByCount }) }}
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<confirm-modal
|
|
v-if="showConfirmModal"
|
|
:modalData="modalData"
|
|
@close="showConfirmModal = false"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import InvitationList from './InvitationList.vue'
|
|
import ConfirmModal from '~/components/Modal/ConfirmModal'
|
|
import ProfileList, {
|
|
profileListVisibleCount,
|
|
} from '~/components/features/ProfileList/ProfileList.vue'
|
|
import { useInviteCode } from '~/composables/useInviteCode'
|
|
|
|
export default {
|
|
name: 'InviteCodeList',
|
|
components: {
|
|
InvitationList,
|
|
ConfirmModal,
|
|
ProfileList,
|
|
},
|
|
props: {
|
|
inviteCodes: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
copyMessage: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
showInvitedUsers: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
showConfirmModal: false,
|
|
modalData: null,
|
|
showExpired: false,
|
|
showAllInvited: false,
|
|
loadingAll: false,
|
|
}
|
|
},
|
|
computed: {
|
|
validInviteCodes() {
|
|
return this.inviteCodes.filter((c) => c.isValid)
|
|
},
|
|
expiredCodes() {
|
|
return this.inviteCodes.filter((c) => !c.isValid)
|
|
},
|
|
maxLinks() {
|
|
return Number(this.$env.INVITE_LINK_LIMIT)
|
|
},
|
|
totalInvitedCount() {
|
|
return this.inviteCodes.reduce((sum, c) => sum + (c.redeemedByCount || 0), 0)
|
|
},
|
|
allInvitedUsers() {
|
|
const users = []
|
|
this.inviteCodes.forEach((inviteCode) => {
|
|
if (inviteCode.redeemedBy) {
|
|
inviteCode.redeemedBy.forEach((u) => {
|
|
users.push({
|
|
id: u.id,
|
|
name: u.name,
|
|
slug: u.slug,
|
|
avatar: u.avatar,
|
|
})
|
|
})
|
|
}
|
|
})
|
|
return users
|
|
},
|
|
visibleInvitedUsers() {
|
|
if (this.showAllInvited) return this.allInvitedUsers
|
|
return this.allInvitedUsers.slice(0, profileListVisibleCount)
|
|
},
|
|
},
|
|
created() {
|
|
const { generatePersonalInviteCode, invalidateInviteCode } = useInviteCode({
|
|
apollo: this.$apollo,
|
|
toast: this.$toast,
|
|
t: (key, ...args) => this.$t(key, ...args),
|
|
store: this.$store,
|
|
})
|
|
this._generateInviteCode = generatePersonalInviteCode
|
|
this._invalidateInviteCode = invalidateInviteCode
|
|
},
|
|
methods: {
|
|
async generateInviteCode(comment) {
|
|
await this._generateInviteCode(comment)
|
|
},
|
|
async invalidateInviteCode(code) {
|
|
await this._invalidateInviteCode(code)
|
|
},
|
|
openDeleteModal(modalData) {
|
|
this.modalData = modalData
|
|
this.showConfirmModal = true
|
|
},
|
|
loadAllInvitedUsers() {
|
|
this.loadingAll = true
|
|
this.showAllInvited = true
|
|
this.$nextTick(() => {
|
|
this.loadingAll = false
|
|
})
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.invite-code-list__title {
|
|
margin-bottom: $space-small;
|
|
}
|
|
|
|
.invite-code-list__count {
|
|
font-weight: normal;
|
|
color: $text-color-soft;
|
|
}
|
|
|
|
.invite-code-list__invited-summary {
|
|
margin-top: $space-base;
|
|
color: $text-color-soft;
|
|
font-size: $font-size-base;
|
|
}
|
|
|
|
.invite-code-list__profile-list.profile-list.os-card {
|
|
padding: 0 !important;
|
|
margin: $space-large 0 0;
|
|
box-shadow: none !important;
|
|
border: none;
|
|
border-radius: 0;
|
|
background: transparent !important;
|
|
}
|
|
|
|
.invite-code-list__expired {
|
|
margin-top: $space-large;
|
|
}
|
|
|
|
.invite-code-list__expired-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-x-small;
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
color: $text-color-soft;
|
|
padding: $space-x-small 0;
|
|
font-size: $font-size-base;
|
|
|
|
&:hover {
|
|
color: $text-color-base;
|
|
}
|
|
}
|
|
|
|
.invite-code-list__expired-chevron {
|
|
font-size: $font-size-small;
|
|
transition: transform 0.2s;
|
|
|
|
&.open {
|
|
transform: rotate(180deg);
|
|
}
|
|
}
|
|
|
|
.invite-code-list__expired-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
}
|
|
|
|
.invite-code-list__expired-code {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: baseline;
|
|
gap: $space-x-small;
|
|
padding: $space-x-small 0;
|
|
border-bottom: 1px dotted #e5e3e8;
|
|
color: $text-color-soft;
|
|
}
|
|
|
|
.invite-code-list__expired-code-text {
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
.invite-code-list__expired-code-comment {
|
|
font-style: italic;
|
|
}
|
|
|
|
.invite-code-list__expired-code-redeemed {
|
|
font-size: $font-size-small;
|
|
}
|
|
</style>
|