You've already forked AstralRinth
forked from didirus/AstralRinth
* sample languages refactor * feat: consistency + dedupe impl of i18n * fix: broken imports * fix: intl formatted component * fix: use relative imports * fix: imports * fix: comment out incomplete locales + fix imports * feat: cleanup * fix: ui imports * fix: lint * fix: admonition import * make footer a component, fix language reactivity * make copyright notice untranslatable --------- Co-authored-by: Calum H. <contact@cal.engineer>
210 lines
5.0 KiB
Vue
210 lines
5.0 KiB
Vue
<template>
|
|
<div v-if="showInvitation" class="universal-card information invited my-4">
|
|
<h2>{{ getFormattedMessage(messages.invitationTitle) }}</h2>
|
|
<p v-if="currentMember?.project_role">
|
|
{{ formatMessage(messages.invitationWithRole, { role: currentMember.project_role }) }}
|
|
</p>
|
|
<p v-else>{{ getFormattedMessage(messages.invitationNoRole) }}</p>
|
|
<div class="input-group">
|
|
<ButtonStyled color="brand">
|
|
<button class="brand-button" @click="acceptInvite()">
|
|
<CheckIcon />
|
|
{{ getFormattedMessage(messages.accept) }}
|
|
</button>
|
|
</ButtonStyled>
|
|
<ButtonStyled color="red">
|
|
<button @click="declineInvite">
|
|
<XIcon />
|
|
{{ getFormattedMessage(messages.decline) }}
|
|
</button>
|
|
</ButtonStyled>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { CheckIcon, XIcon } from '@modrinth/assets'
|
|
import {
|
|
ButtonStyled,
|
|
defineMessages,
|
|
injectNotificationManager,
|
|
type MessageDescriptor,
|
|
useVIntl,
|
|
} from '@modrinth/ui'
|
|
import type { Project, User, Version } from '@modrinth/utils'
|
|
import { computed } from 'vue'
|
|
|
|
import { acceptTeamInvite, removeTeamMember } from '~/helpers/teams.js'
|
|
|
|
const { addNotification } = injectNotificationManager()
|
|
|
|
interface Tags {
|
|
rejectedStatuses: string[]
|
|
}
|
|
|
|
interface Auth {
|
|
user: {
|
|
id: string
|
|
}
|
|
}
|
|
|
|
interface Member {
|
|
accepted?: boolean
|
|
project_role?: string
|
|
user?: Partial<User>
|
|
}
|
|
|
|
interface Props {
|
|
project: Project
|
|
versions?: Version[]
|
|
currentMember?: Member | null
|
|
allMembers?: Member[] | null
|
|
isSettings?: boolean
|
|
auth: Auth
|
|
tags: Tags
|
|
setProcessing?: (processing: boolean) => void
|
|
updateMembers?: () => void | Promise<void>
|
|
}
|
|
|
|
const messages = defineMessages({
|
|
invitationTitle: {
|
|
id: 'project-member-header.invitation-title',
|
|
defaultMessage: 'Invitation to join project',
|
|
},
|
|
invitationWithRole: {
|
|
id: 'project-member-header.invitation-with-role',
|
|
defaultMessage:
|
|
"You've been invited to be a member of this project with the role of ''{role}''.",
|
|
},
|
|
invitationNoRole: {
|
|
id: 'project-member-header.invitation-no-role',
|
|
defaultMessage:
|
|
"You've been invited to join this project. Please accept or decline the invitation.",
|
|
},
|
|
accept: {
|
|
id: 'project-member-header.accept',
|
|
defaultMessage: 'Accept',
|
|
},
|
|
decline: {
|
|
id: 'project-member-header.decline',
|
|
defaultMessage: 'Decline',
|
|
},
|
|
successJoin: {
|
|
id: 'project-member-header.success-join',
|
|
defaultMessage: 'You have joined the project team',
|
|
},
|
|
errorJoin: {
|
|
id: 'project-member-header.error-join',
|
|
defaultMessage: 'Failed to accept team invitation',
|
|
},
|
|
successDecline: {
|
|
id: 'project-member-header.success-decline',
|
|
defaultMessage: 'You have declined the team invitation',
|
|
},
|
|
errorDecline: {
|
|
id: 'project-member-header.error-decline',
|
|
defaultMessage: 'Failed to decline team invitation',
|
|
},
|
|
success: {
|
|
id: 'project-member-header.success',
|
|
defaultMessage: 'Success',
|
|
},
|
|
error: {
|
|
id: 'project-member-header.error',
|
|
defaultMessage: 'Error',
|
|
},
|
|
})
|
|
|
|
const { formatMessage } = useVIntl()
|
|
|
|
function getFormattedMessage(message: string | MessageDescriptor): string {
|
|
if (typeof message === 'string') {
|
|
return message
|
|
}
|
|
return formatMessage(message)
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
versions: () => [],
|
|
currentMember: null,
|
|
allMembers: null,
|
|
isSettings: false,
|
|
collapsed: false,
|
|
setProcessing: () => {},
|
|
toggleCollapsed: () => {},
|
|
updateMembers: async () => {},
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
toggleCollapsed: []
|
|
updateMembers: []
|
|
setProcessing: [processing: boolean]
|
|
}>()
|
|
|
|
const showInvitation = computed<boolean>(() => {
|
|
if (props.allMembers && props.auth) {
|
|
const member = props.allMembers.find((x) => x?.user?.id === props.auth.user.id)
|
|
return !!member && !member.accepted
|
|
}
|
|
return false
|
|
})
|
|
|
|
async function handleUpdateMembers(): Promise<void> {
|
|
if (props.updateMembers) {
|
|
await props.updateMembers()
|
|
} else {
|
|
emit('updateMembers')
|
|
}
|
|
}
|
|
|
|
function handleSetProcessing(processing: boolean): void {
|
|
if (props.setProcessing) {
|
|
props.setProcessing(processing)
|
|
} else {
|
|
emit('setProcessing', processing)
|
|
}
|
|
}
|
|
|
|
async function acceptInvite(): Promise<void> {
|
|
try {
|
|
handleSetProcessing(true)
|
|
await acceptTeamInvite(props.project.team)
|
|
await handleUpdateMembers()
|
|
addNotification({
|
|
title: formatMessage(messages.success),
|
|
text: formatMessage(messages.successJoin),
|
|
type: 'success',
|
|
})
|
|
} catch {
|
|
addNotification({
|
|
title: formatMessage(messages.error),
|
|
text: formatMessage(messages.errorJoin),
|
|
type: 'error',
|
|
})
|
|
} finally {
|
|
handleSetProcessing(false)
|
|
}
|
|
}
|
|
|
|
async function declineInvite(): Promise<void> {
|
|
try {
|
|
handleSetProcessing(true)
|
|
await removeTeamMember(props.project.team, props.auth.user.id)
|
|
await handleUpdateMembers()
|
|
addNotification({
|
|
title: formatMessage(messages.success),
|
|
text: formatMessage(messages.successDecline),
|
|
type: 'success',
|
|
})
|
|
} catch {
|
|
addNotification({
|
|
title: formatMessage(messages.error),
|
|
text: formatMessage(messages.errorDecline),
|
|
type: 'error',
|
|
})
|
|
} finally {
|
|
handleSetProcessing(false)
|
|
}
|
|
}
|
|
</script>
|