mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
refactor contribution list, stay open after adding contribution message
This commit is contained in:
parent
9b1e162042
commit
2cabeb87bb
@ -1,13 +1,15 @@
|
||||
import { Contribution as dbContribution } from '@entity/Contribution'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
import { ContributionMessage as dbContributionMessage } from '@entity/ContributionMessage'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
import { ContributionMessage } from './ContributionMessage'
|
||||
import { User } from './User'
|
||||
|
||||
@ObjectType()
|
||||
export class Contribution {
|
||||
constructor(contribution: dbContribution, user?: DbUser | null) {
|
||||
constructor(contribution: dbContribution) {
|
||||
const user = contribution.user
|
||||
this.id = contribution.id
|
||||
this.firstName = user?.firstName ?? null
|
||||
this.lastName = user?.lastName ?? null
|
||||
@ -18,7 +20,7 @@ export class Contribution {
|
||||
this.confirmedBy = contribution.confirmedBy
|
||||
this.contributionDate = contribution.contributionDate
|
||||
this.status = contribution.contributionStatus
|
||||
this.messagesCount = contribution.messages ? contribution.messages.length : 0
|
||||
this.messagesCount = contribution.messages?.length ?? 0
|
||||
this.deniedAt = contribution.deniedAt
|
||||
this.deniedBy = contribution.deniedBy
|
||||
this.deletedAt = contribution.deletedAt
|
||||
@ -28,9 +30,12 @@ export class Contribution {
|
||||
this.moderatorId = contribution.moderatorId
|
||||
this.userId = contribution.userId
|
||||
this.resubmissionAt = contribution.resubmissionAt
|
||||
if (user) {
|
||||
this.user = new User(user)
|
||||
}
|
||||
this.user = user ? new User(user) : null
|
||||
this.messages = contribution.messages
|
||||
? contribution.messages.map(
|
||||
(message: dbContributionMessage) => new ContributionMessage(message),
|
||||
)
|
||||
: null
|
||||
}
|
||||
|
||||
@Field(() => Int)
|
||||
@ -87,6 +92,9 @@ export class Contribution {
|
||||
@Field(() => Int)
|
||||
messagesCount: number
|
||||
|
||||
@Field(() => [ContributionMessage], { nullable: true })
|
||||
messages: ContributionMessage[] | null
|
||||
|
||||
@Field(() => String)
|
||||
status: string
|
||||
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
|
||||
import { User } from '@entity/User'
|
||||
import { Field, Int, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class ContributionMessage {
|
||||
constructor(contributionMessage: DbContributionMessage, user: User) {
|
||||
constructor(contributionMessage: DbContributionMessage) {
|
||||
const user = contributionMessage.user
|
||||
this.id = contributionMessage.id
|
||||
this.message = contributionMessage.message
|
||||
this.createdAt = contributionMessage.createdAt
|
||||
this.updatedAt = contributionMessage.updatedAt
|
||||
this.type = contributionMessage.type
|
||||
this.userFirstName = user.firstName
|
||||
this.userLastName = user.lastName
|
||||
this.userId = user.id
|
||||
this.userFirstName = user?.firstName ?? null
|
||||
this.userLastName = user?.lastName ?? null
|
||||
this.userId = user?.id ?? null
|
||||
this.isModerator = contributionMessage.isModerator
|
||||
}
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ export class ContributionMessageResolver {
|
||||
{ id: contributionId } as DbContribution,
|
||||
finalContributionMessage,
|
||||
)
|
||||
return new ContributionMessage(finalContributionMessage, user)
|
||||
return new ContributionMessage(finalContributionMessage)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.LIST_ALL_CONTRIBUTION_MESSAGES])
|
||||
@ -87,16 +87,12 @@ export class ContributionMessageResolver {
|
||||
): Promise<ContributionMessageListResult> {
|
||||
const [contributionMessages, count] = await findContributionMessages({
|
||||
contributionId,
|
||||
currentPage,
|
||||
pageSize,
|
||||
order,
|
||||
pagination: { currentPage, pageSize, order },
|
||||
})
|
||||
|
||||
return {
|
||||
count,
|
||||
messages: contributionMessages.map(
|
||||
(message) => new ContributionMessage(message, message.user),
|
||||
),
|
||||
messages: contributionMessages.map((message) => new ContributionMessage(message)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,17 +105,13 @@ export class ContributionMessageResolver {
|
||||
): Promise<ContributionMessageListResult> {
|
||||
const [contributionMessages, count] = await findContributionMessages({
|
||||
contributionId,
|
||||
currentPage,
|
||||
pageSize,
|
||||
order,
|
||||
pagination: { currentPage, pageSize, order },
|
||||
showModeratorType: true,
|
||||
})
|
||||
|
||||
return {
|
||||
count,
|
||||
messages: contributionMessages.map(
|
||||
(message) => new ContributionMessage(message, message.user),
|
||||
),
|
||||
messages: contributionMessages.map((message) => new ContributionMessage(message)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,6 +186,6 @@ export class ContributionMessageResolver {
|
||||
finalContribution,
|
||||
finalContributionMessage,
|
||||
)
|
||||
return new ContributionMessage(finalContributionMessage, moderator)
|
||||
return new ContributionMessage(finalContributionMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ import { AdminUpdateContributionArgs } from '@arg/AdminUpdateContributionArgs'
|
||||
import { ContributionArgs } from '@arg/ContributionArgs'
|
||||
import { Paginated } from '@arg/Paginated'
|
||||
import { SearchContributionsFilterArgs } from '@arg/SearchContributionsFilterArgs'
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||
import { ContributionType } from '@enum/ContributionType'
|
||||
import { TransactionTypeId } from '@enum/TransactionTypeId'
|
||||
@ -60,11 +59,15 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
import { fullName } from '@/util/utilities'
|
||||
|
||||
import { ContributionMessage } from '@model/ContributionMessage'
|
||||
import { ContributionMessageType } from '../enum/ContributionMessageType'
|
||||
import { findContribution } from './util/contributions'
|
||||
import { getOpenCreations, getUserCreation, validateContribution } from './util/creations'
|
||||
import { extractGraphQLFields, extractGraphQLFieldsForSelect } from './util/extractGraphQLFields'
|
||||
import { findContributionMessages } from './util/findContributionMessages'
|
||||
import { findContributions } from './util/findContributions'
|
||||
import { getLastTransaction } from './util/getLastTransaction'
|
||||
import { loadAllContributions, loadUserContributions } from './util/loadContributions'
|
||||
import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector'
|
||||
|
||||
@Resolver(() => Contribution)
|
||||
@ -143,46 +146,59 @@ export class ContributionResolver {
|
||||
@Ctx() context: Context,
|
||||
@Args()
|
||||
paginated: Paginated,
|
||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||
statusFilter?: ContributionStatus[] | null,
|
||||
): Promise<ContributionListResult> {
|
||||
const user = getUser(context)
|
||||
const filter = new SearchContributionsFilterArgs()
|
||||
filter.statusFilter = statusFilter
|
||||
filter.userId = user.id
|
||||
const [dbContributions, count] = await findContributions(paginated, filter, true, {
|
||||
messages: true,
|
||||
})
|
||||
const [dbContributions, count] = await loadUserContributions(user.id, paginated)
|
||||
|
||||
// show contributions in progress first
|
||||
const inProgressContributions = dbContributions.filter(
|
||||
(contribution) => contribution.contributionStatus === ContributionStatus.IN_PROGRESS,
|
||||
)
|
||||
const notInProgressContributions = dbContributions.filter(
|
||||
(contribution) => contribution.contributionStatus !== ContributionStatus.IN_PROGRESS,
|
||||
)
|
||||
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
dbContributions.map((contribution) => {
|
||||
// filter out moderator messages for this call
|
||||
[...inProgressContributions, ...notInProgressContributions].map((contribution) => {
|
||||
// we currently expect not much contribution messages for needing pagination
|
||||
// but if we get more than expected, we should get warned
|
||||
if ((contribution.messages?.length || 0) > 10) {
|
||||
logger.warn('more contribution messages as expected, consider pagination', {
|
||||
contributionId: contribution.id,
|
||||
expected: 10,
|
||||
actual: contribution.messages?.length || 0,
|
||||
})
|
||||
}
|
||||
contribution.messages = contribution.messages?.filter(
|
||||
(m) => (m.type as ContributionMessageType) !== ContributionMessageType.MODERATOR,
|
||||
(message) => message.type !== ContributionMessageType.MODERATOR,
|
||||
)
|
||||
return new Contribution(contribution, user)
|
||||
return new Contribution(contribution)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.LIST_CONTRIBUTIONS])
|
||||
@Query(() => Int)
|
||||
async countContributionsInProgress(@Ctx() context: Context): Promise<number> {
|
||||
const user = getUser(context)
|
||||
const count = await DbContribution.count({
|
||||
where: { userId: user.id, contributionStatus: ContributionStatus.IN_PROGRESS },
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.LIST_ALL_CONTRIBUTIONS])
|
||||
@Query(() => ContributionListResult)
|
||||
async listAllContributions(
|
||||
@Args()
|
||||
paginated: Paginated,
|
||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||
statusFilter?: ContributionStatus[] | null,
|
||||
): Promise<ContributionListResult> {
|
||||
const filter = new SearchContributionsFilterArgs()
|
||||
filter.statusFilter = statusFilter
|
||||
const [dbContributions, count] = await findContributions(paginated, filter, false, {
|
||||
user: true,
|
||||
})
|
||||
const [dbContributions, count] = await loadAllContributions(paginated)
|
||||
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||
dbContributions.map((contribution) => new Contribution(contribution)),
|
||||
)
|
||||
}
|
||||
|
||||
@ -370,7 +386,7 @@ export class ContributionResolver {
|
||||
|
||||
return new ContributionListResult(
|
||||
count,
|
||||
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||
dbContributions.map((contribution) => new Contribution(contribution)),
|
||||
)
|
||||
}
|
||||
|
||||
@ -627,4 +643,30 @@ export class ContributionResolver {
|
||||
}
|
||||
return new User(user)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.LIST_ALL_CONTRIBUTION_MESSAGES])
|
||||
@FieldResolver(() => [ContributionMessage], { nullable: true })
|
||||
async messages(
|
||||
@Root() contribution: Contribution,
|
||||
@Arg('pagination', () => Paginated) pagination: Paginated,
|
||||
): Promise<ContributionMessage[] | null> {
|
||||
if (contribution.messagesCount === 0) {
|
||||
return null
|
||||
}
|
||||
const [contributionMessages] = await findContributionMessages({
|
||||
contributionId: contribution.id,
|
||||
pagination,
|
||||
})
|
||||
// we currently expect not much contribution messages for needing pagination
|
||||
// but if we get more than expected, we should get warned
|
||||
if (contributionMessages.length > pagination.pageSize) {
|
||||
logger.warn('more contribution messages as expected, consider pagination', {
|
||||
contributionId: contribution.id,
|
||||
expected: pagination.pageSize,
|
||||
actual: contributionMessages.length,
|
||||
})
|
||||
}
|
||||
|
||||
return contributionMessages.map((message) => new ContributionMessage(message))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,28 +1,26 @@
|
||||
import { In } from '@dbTools/typeorm'
|
||||
import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage'
|
||||
|
||||
import { Paginated } from '@arg/Paginated'
|
||||
import { ContributionMessageType } from '@enum/ContributionMessageType'
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
interface FindContributionMessagesOptions {
|
||||
contributionId: number
|
||||
pageSize: number
|
||||
currentPage: number
|
||||
order: Order
|
||||
pagination: Paginated
|
||||
showModeratorType?: boolean
|
||||
}
|
||||
|
||||
export const findContributionMessages = async (
|
||||
options: FindContributionMessagesOptions,
|
||||
): Promise<[DbContributionMessage[], number]> => {
|
||||
const { contributionId, pageSize, currentPage, order, showModeratorType } = options
|
||||
const { contributionId, pagination, showModeratorType } = options
|
||||
|
||||
const messageTypes = [ContributionMessageType.DIALOG, ContributionMessageType.HISTORY]
|
||||
|
||||
if (showModeratorType) {
|
||||
messageTypes.push(ContributionMessageType.MODERATOR)
|
||||
}
|
||||
|
||||
const { currentPage, pageSize, order } = pagination
|
||||
return DbContributionMessage.findAndCount({
|
||||
where: {
|
||||
contributionId,
|
||||
|
||||
41
backend/src/graphql/resolver/util/loadContributions.ts
Normal file
41
backend/src/graphql/resolver/util/loadContributions.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Paginated } from '@arg/Paginated'
|
||||
import { FindManyOptions } from '@dbTools/typeorm'
|
||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||
|
||||
function buildBaseOptions(paginated: Paginated): FindManyOptions<DbContribution> {
|
||||
const { order, currentPage, pageSize } = paginated
|
||||
return {
|
||||
order: { createdAt: order, id: order },
|
||||
skip: (currentPage - 1) * pageSize,
|
||||
take: pageSize,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load user contributions with messages
|
||||
* @param userId if userId is set, load all contributions of the user, with messages
|
||||
* @param paginated pagination, see {@link Paginated}
|
||||
*/
|
||||
export const loadUserContributions = async (
|
||||
userId: number,
|
||||
paginated: Paginated,
|
||||
): Promise<[DbContribution[], number]> => {
|
||||
return DbContribution.findAndCount({
|
||||
where: { userId },
|
||||
relations: { messages: { user: true } },
|
||||
...buildBaseOptions(paginated),
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Load all contributions
|
||||
* @param paginated pagination, see {@link Paginated}
|
||||
*/
|
||||
export const loadAllContributions = async (
|
||||
paginated: Paginated,
|
||||
): Promise<[DbContribution[], number]> => {
|
||||
return DbContribution.findAndCount({
|
||||
relations: { user: true },
|
||||
...buildBaseOptions(paginated),
|
||||
})
|
||||
}
|
||||
@ -5,10 +5,10 @@
|
||||
<BForm @submit.prevent="onSubmit" @reset="onReset">
|
||||
<BFormTextarea
|
||||
id="textarea"
|
||||
:model-value="form.text"
|
||||
:model-value="formText"
|
||||
:placeholder="$t('form.memo')"
|
||||
:rows="3"
|
||||
@update:model-value="form.text = $event"
|
||||
@update:model-value="formText = $event"
|
||||
/>
|
||||
<BRow class="mt-4 mb-4">
|
||||
<BCol>
|
||||
@ -39,35 +39,37 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['get-list-contribution-messages', 'update-status'])
|
||||
const emit = defineEmits([
|
||||
'get-list-contribution-messages',
|
||||
'update-status',
|
||||
'add-contribution-message',
|
||||
])
|
||||
|
||||
const { t } = useI18n()
|
||||
const { toastSuccess, toastError } = useAppToast()
|
||||
|
||||
const { mutate: createContributionMessageMutation } = useMutation(createContributionMessage)
|
||||
|
||||
const form = ref({
|
||||
text: '',
|
||||
})
|
||||
const formText = ref('')
|
||||
|
||||
const isSubmitting = ref(false)
|
||||
|
||||
const disabled = computed(() => {
|
||||
return form.value.text === '' || isSubmitting.value
|
||||
return formText.value === '' || isSubmitting.value
|
||||
})
|
||||
|
||||
async function onSubmit() {
|
||||
isSubmitting.value = true
|
||||
|
||||
try {
|
||||
await createContributionMessageMutation({
|
||||
const result = await createContributionMessageMutation({
|
||||
contributionId: props.contributionId,
|
||||
message: form.value.text,
|
||||
message: formText.value,
|
||||
})
|
||||
|
||||
emit('get-list-contribution-messages', false)
|
||||
// emit('get-list-contribution-messages', false)
|
||||
formText.value = ''
|
||||
emit('update-status', props.contributionId)
|
||||
form.value.text = ''
|
||||
emit('add-contribution-message', result.data.createContributionMessage)
|
||||
toastSuccess(t('message.reply'))
|
||||
} catch (error) {
|
||||
toastError(error.message)
|
||||
@ -77,6 +79,6 @@ async function onSubmit() {
|
||||
}
|
||||
|
||||
function onReset() {
|
||||
form.value.text = ''
|
||||
formText.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
v-if="['PENDING', 'IN_PROGRESS'].includes(status)"
|
||||
:contribution-id="contributionId"
|
||||
v-bind="$attrs"
|
||||
@update-status="updateStatus"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -46,11 +45,6 @@ export default {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateStatus(id) {
|
||||
this.$emit('update-status', id)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
@ -1,27 +1,16 @@
|
||||
<template>
|
||||
<div class="contribution-list">
|
||||
<div v-if="items.length === 0 && !loading.value">
|
||||
{{ emptyText }}
|
||||
</div>
|
||||
<div v-else class="contribution-list">
|
||||
<div v-for="item in items" :key="item.id + 'a'" class="mb-3">
|
||||
<contribution-list-item
|
||||
v-if="item.status === 'IN_PROGRESS'"
|
||||
v-bind="item"
|
||||
:contribution-id="item.id"
|
||||
:all-contribution="allContribution"
|
||||
@close-all-open-collapse="$emit('close-all-open-collapse')"
|
||||
@update-contribution-form="updateContributionForm"
|
||||
@delete-contribution="deleteContribution"
|
||||
@update-status="updateStatus"
|
||||
/>
|
||||
</div>
|
||||
<div v-for="item2 in items" :key="item2.id" class="mb-3">
|
||||
<contribution-list-item
|
||||
v-if="item2.status !== 'IN_PROGRESS'"
|
||||
v-bind="item2"
|
||||
:contribution-id="item2.id"
|
||||
:all-contribution="allContribution"
|
||||
@close-all-open-collapse="$emit('close-all-open-collapse')"
|
||||
@update-contribution-form="updateContributionForm"
|
||||
@delete-contribution="deleteContribution"
|
||||
@update-status="updateStatus"
|
||||
/>
|
||||
</div>
|
||||
<BPagination
|
||||
@ -39,59 +28,58 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed, watch, watchEffect, onMounted } from 'vue'
|
||||
import ContributionListItem from '@/components/Contributions/ContributionListItem.vue'
|
||||
import { listContributions, listAllContributions } from '@/graphql/contributions.graphql'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { PAGE_SIZE } from '@/constants'
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
contributionCount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
showPagination: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 25,
|
||||
},
|
||||
allContribution: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
'close-all-open-collapse',
|
||||
'update-list-contributions',
|
||||
'update-contribution-form',
|
||||
'delete-contribution',
|
||||
'update-status',
|
||||
])
|
||||
|
||||
const currentPage = ref(1)
|
||||
const messages = ref([])
|
||||
|
||||
const contributionListResult = computed(() => {
|
||||
return props.allContribution
|
||||
? result.value?.listAllContributions
|
||||
: result.value?.listContributions
|
||||
})
|
||||
|
||||
const contributionCount = computed(() => {
|
||||
return contributionListResult.value?.contributionCount || 0
|
||||
})
|
||||
const items = computed(() => {
|
||||
return contributionListResult.value?.contributionList || []
|
||||
})
|
||||
|
||||
const isPaginationVisible = computed(() => {
|
||||
return props.showPagination && props.pageSize < props.contributionCount
|
||||
return PAGE_SIZE < contributionCount.value
|
||||
})
|
||||
|
||||
watch(currentPage, () => {
|
||||
updateListContributions()
|
||||
})
|
||||
|
||||
const updateListContributions = () => {
|
||||
emit('update-list-contributions', {
|
||||
const { result, loading } = useQuery(
|
||||
props.allContribution ? listAllContributions : listContributions,
|
||||
() => ({
|
||||
currentPage: currentPage.value,
|
||||
pageSize: props.pageSize,
|
||||
})
|
||||
window.scrollTo(0, 0)
|
||||
}
|
||||
pageSize: PAGE_SIZE,
|
||||
}),
|
||||
{ fetchPolicy: 'cache-and-network' },
|
||||
)
|
||||
|
||||
const updateContributionForm = (item) => {
|
||||
emit('update-contribution-form', item)
|
||||
@ -100,8 +88,4 @@ const updateContributionForm = (item) => {
|
||||
const deleteContribution = (item) => {
|
||||
emit('delete-contribution', item)
|
||||
}
|
||||
|
||||
const updateStatus = (id) => {
|
||||
emit('update-status', id)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<div
|
||||
class="contribution-list-item bg-white app-box-shadow gradido-border-radius pt-3 px-3"
|
||||
:class="status === 'IN_PROGRESS' && !allContribution ? 'pulse border border-205' : ''"
|
||||
:class="localStatus === 'IN_PROGRESS' && !allContribution ? 'pulse border border-205' : ''"
|
||||
>
|
||||
<BRow>
|
||||
<BCol cols="3" lg="2" md="2">
|
||||
@ -39,7 +39,7 @@
|
||||
{{ $t('moderatorChangedMemo') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="status === 'IN_PROGRESS' && !allContribution"
|
||||
v-if="localStatus === 'IN_PROGRESS' && !allContribution"
|
||||
class="text-danger pointer hover-font-bold"
|
||||
@click="visible = !visible"
|
||||
>
|
||||
@ -50,11 +50,11 @@
|
||||
<div class="small">
|
||||
{{ $t('creation') }} {{ $t('(') }}{{ hours }} {{ $t('h') }}{{ $t(')') }}
|
||||
</div>
|
||||
<div v-if="status === 'DENIED' && allContribution" class="fw-bold">
|
||||
<div v-if="localStatus === 'DENIED' && allContribution" class="fw-bold">
|
||||
<variant-icon icon="x-circle" variant="danger" />
|
||||
{{ $t('contribution.alert.denied') }}
|
||||
</div>
|
||||
<div v-if="status === 'DELETED'" class="small">
|
||||
<div v-if="localStatus === 'DELETED'" class="small">
|
||||
{{ $t('contribution.deleted') }}
|
||||
</div>
|
||||
<div v-else class="fw-bold">{{ $filters.GDD(amount) }}</div>
|
||||
@ -66,12 +66,16 @@
|
||||
</BCol>
|
||||
</BRow>
|
||||
<BRow
|
||||
v-if="(!['CONFIRMED', 'DELETED'].includes(status) && !allContribution) || messagesCount > 0"
|
||||
v-if="
|
||||
(!['CONFIRMED', 'DELETED'].includes(localStatus) && !allContribution) || messagesCount > 0
|
||||
"
|
||||
class="p-2"
|
||||
>
|
||||
<BCol cols="3" class="me-auto text-center">
|
||||
<div
|
||||
v-if="!['CONFIRMED', 'DELETED'].includes(status) && !allContribution && !moderatorId"
|
||||
v-if="
|
||||
!['CONFIRMED', 'DELETED'].includes(localStatus) && !allContribution && !moderatorId
|
||||
"
|
||||
class="test-delete-contribution pointer me-3"
|
||||
@click="deleteContribution({ id })"
|
||||
>
|
||||
@ -82,7 +86,9 @@
|
||||
</BCol>
|
||||
<BCol cols="3" class="text-center">
|
||||
<div
|
||||
v-if="!['CONFIRMED', 'DELETED'].includes(status) && !allContribution && !moderatorId"
|
||||
v-if="
|
||||
!['CONFIRMED', 'DELETED'].includes(localStatus) && !allContribution && !moderatorId
|
||||
"
|
||||
class="test-edit-contribution pointer me-3"
|
||||
@click="
|
||||
$emit('update-contribution-form', {
|
||||
@ -104,14 +110,15 @@
|
||||
</div>
|
||||
</BCol>
|
||||
</BRow>
|
||||
<BCollapse :id="collapseId" :model-value="visible">
|
||||
<BCollapse :model-value="visible">
|
||||
<contribution-messages-list
|
||||
:messages="messagesGet"
|
||||
:status="status"
|
||||
:status="localStatus"
|
||||
:contribution-id="contributionId"
|
||||
@get-list-contribution-messages="getListContributionMessages"
|
||||
@update-status="updateStatus"
|
||||
@close-all-open-collapse="visible = false"
|
||||
@add-contribution-message="addContributionMessage"
|
||||
/>
|
||||
</BCollapse>
|
||||
<div class="pb-3"></div>
|
||||
@ -140,6 +147,10 @@ const props = defineProps({
|
||||
memo: {
|
||||
type: String,
|
||||
},
|
||||
messages: {
|
||||
type: Array,
|
||||
required: false,
|
||||
},
|
||||
firstName: {
|
||||
type: String,
|
||||
required: false,
|
||||
@ -208,6 +219,16 @@ const { t } = useI18n()
|
||||
|
||||
const messagesGet = ref([])
|
||||
const visible = ref(false)
|
||||
const localStatus = ref(props.status)
|
||||
|
||||
watch(
|
||||
() => props.messages,
|
||||
() => {
|
||||
messagesGet.value = props.messages
|
||||
},
|
||||
// parent is loading messages already
|
||||
{ immediate: false },
|
||||
)
|
||||
|
||||
const variant = computed(() => {
|
||||
if (props.deletedAt) return 'danger'
|
||||
@ -266,6 +287,10 @@ function getListContributionMessages(closeCollapse = true) {
|
||||
}
|
||||
}
|
||||
|
||||
function addContributionMessage(message) {
|
||||
messagesGet.value.push(message)
|
||||
}
|
||||
|
||||
onResult((resultValue) => {
|
||||
if (resultValue.data) {
|
||||
messagesGet.value.length = 0
|
||||
@ -279,11 +304,11 @@ onError((err) => {
|
||||
toastError(err.message)
|
||||
})
|
||||
|
||||
function updateStatus(id) {
|
||||
emit('update-status', id)
|
||||
const updateStatus = (id) => {
|
||||
localStatus.value = 'PENDING'
|
||||
}
|
||||
|
||||
const emit = defineEmits(['delete-contribution', 'close-all-open-collapse', 'update-status'])
|
||||
const emit = defineEmits(['delete-contribution', 'close-all-open-collapse'])
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export const GDD_PER_HOUR = 20
|
||||
export const PAGE_SIZE = 25
|
||||
|
||||
59
frontend/src/graphql/contributions.graphql
Normal file
59
frontend/src/graphql/contributions.graphql
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
fragment contributionFields on Contribution {
|
||||
id
|
||||
amount
|
||||
memo
|
||||
createdAt
|
||||
contributionDate
|
||||
confirmedAt
|
||||
confirmedBy
|
||||
status
|
||||
messagesCount
|
||||
deniedAt
|
||||
deniedBy
|
||||
updatedBy
|
||||
updatedAt
|
||||
}
|
||||
|
||||
fragment contributionMessageFields on ContributionMessage {
|
||||
id
|
||||
message
|
||||
createdAt
|
||||
updatedAt
|
||||
type
|
||||
userFirstName
|
||||
userLastName
|
||||
userId
|
||||
}
|
||||
|
||||
query listContributions ($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
|
||||
listContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
...contributionFields
|
||||
deletedAt
|
||||
moderatorId
|
||||
messages(pagination: { currentPage: 1, pageSize: 10, order: DESC }) {
|
||||
...contributionMessageFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query countContributionsInProgress {
|
||||
countContributionsInProgress
|
||||
}
|
||||
|
||||
|
||||
query listAllContributions ($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
|
||||
listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
firstName
|
||||
lastName
|
||||
...contributionFields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -188,18 +188,8 @@ export const listContributionLinks = gql`
|
||||
`
|
||||
|
||||
export const listContributions = gql`
|
||||
query (
|
||||
$currentPage: Int = 1
|
||||
$pageSize: Int = 25
|
||||
$order: Order = DESC
|
||||
$statusFilter: [ContributionStatus!]
|
||||
) {
|
||||
listContributions(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
statusFilter: $statusFilter
|
||||
) {
|
||||
query ($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
|
||||
listContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
id
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="community-page">
|
||||
<div>
|
||||
<BTabs :model-value="tabIndex" no-nav-style borderless align="center">
|
||||
<BTab no-body>
|
||||
<BTab no-body lazy>
|
||||
<open-creations-amount
|
||||
:minimal-date="minimalDate"
|
||||
:max-gdd-last-month="maxForMonths[0]"
|
||||
@ -18,39 +18,18 @@
|
||||
@update-contribution="handleUpdateContribution"
|
||||
/>
|
||||
</BTab>
|
||||
<BTab no-body>
|
||||
<div v-if="items.length === 0">
|
||||
{{ $t('contribution.noContributions.myContributions') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<contribution-list
|
||||
:items="items"
|
||||
:contribution-count="contributionCount"
|
||||
:show-pagination="true"
|
||||
:page-size="pageSize"
|
||||
@close-all-open-collapse="closeAllOpenCollapse"
|
||||
@update-list-contributions="handleUpdateListContributions"
|
||||
@update-contribution-form="handleUpdateContributionForm"
|
||||
@delete-contribution="handleDeleteContribution"
|
||||
@update-status="updateStatus"
|
||||
/>
|
||||
</div>
|
||||
<BTab no-body lazy>
|
||||
<contribution-list
|
||||
:empty-text="$t('contribution.noContributions.myContributions')"
|
||||
@update-contribution-form="handleUpdateContributionForm"
|
||||
@delete-contribution="handleDeleteContribution"
|
||||
/>
|
||||
</BTab>
|
||||
<BTab no-body>
|
||||
<div v-if="itemsAll.length === 0">
|
||||
{{ $t('contribution.noContributions.allContributions') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<contribution-list
|
||||
:items="itemsAll"
|
||||
:contribution-count="contributionCountAll"
|
||||
:show-pagination="true"
|
||||
:page-size="pageSizeAll"
|
||||
:all-contribution="true"
|
||||
@update-list-contributions="handleUpdateListAllContributions"
|
||||
@update-contribution-form="handleUpdateContributionForm"
|
||||
/>
|
||||
</div>
|
||||
<BTab no-body lazy>
|
||||
<contribution-list
|
||||
:empty-text="$t('contribution.noContributions.allContributions')"
|
||||
:all-contribution="true"
|
||||
/>
|
||||
</BTab>
|
||||
</BTabs>
|
||||
</div>
|
||||
@ -65,7 +44,8 @@ import OpenCreationsAmount from '@/components/Contributions/OpenCreationsAmount'
|
||||
import ContributionForm from '@/components/Contributions/ContributionForm'
|
||||
import ContributionList from '@/components/Contributions/ContributionList'
|
||||
import { createContribution, updateContribution, deleteContribution } from '@/graphql/mutations'
|
||||
import { listContributions, listAllContributions, openCreations } from '@/graphql/queries'
|
||||
import { openCreations } from '@/graphql/queries'
|
||||
import { countContributionsInProgress } from '@/graphql/contributions.graphql'
|
||||
import { useAppToast } from '@/composables/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { GDD_PER_HOUR } from '../constants'
|
||||
@ -130,51 +110,30 @@ const { onResult: onOpenCreationsResult, refetch: refetchOpenCreations } = useQu
|
||||
fetchPolicy: 'network-only',
|
||||
},
|
||||
)
|
||||
const { onResult: onListAllContributionsResult, refetch: refetchAllContributions } = useQuery(
|
||||
listAllContributions,
|
||||
() => ({
|
||||
currentPage: currentPageAll.value,
|
||||
pageSize: pageSizeAll.value,
|
||||
}),
|
||||
{ fetchPolicy: 'no-cache' },
|
||||
)
|
||||
const { onResult: onListContributionsResult, refetch: refetchContributions } = useQuery(
|
||||
listContributions,
|
||||
() => ({
|
||||
currentPage: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
}),
|
||||
{ fetchPolicy: 'network-only' },
|
||||
)
|
||||
|
||||
const { mutate: createContributionMutation } = useMutation(createContribution)
|
||||
const { mutate: updateContributionMutation } = useMutation(updateContribution)
|
||||
const { mutate: deleteContributionMutation } = useMutation(deleteContribution)
|
||||
|
||||
const { onResult: handleInProgressContributionFound } = useQuery(
|
||||
countContributionsInProgress,
|
||||
{},
|
||||
{
|
||||
fetchPolicy: 'network-only',
|
||||
},
|
||||
)
|
||||
|
||||
onOpenCreationsResult(({ data }) => {
|
||||
if (data) {
|
||||
openCreationsData.value = data.openCreations
|
||||
}
|
||||
})
|
||||
|
||||
onListAllContributionsResult(({ data }) => {
|
||||
// jump to my contributions if in progress contribution found
|
||||
handleInProgressContributionFound(({ data }) => {
|
||||
if (data) {
|
||||
contributionCountAll.value = data.listAllContributions.contributionCount
|
||||
itemsAll.value.length = 0
|
||||
data.listAllContributions.contributionList.forEach((entry) => {
|
||||
itemsAll.value.push(entry)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
onListContributionsResult(({ data }) => {
|
||||
if (data) {
|
||||
contributionCount.value = data.listContributions.contributionCount
|
||||
items.value.length = 0
|
||||
data.listContributions.contributionList.forEach((entry) => {
|
||||
items.value.push({ ...entry })
|
||||
})
|
||||
if (items.value.find((item) => item.status === 'IN_PROGRESS')) {
|
||||
const count = data.countContributionsInProgress
|
||||
if (count > 0) {
|
||||
tabIndex.value = 1
|
||||
if (route.params.tab !== 'contributions') {
|
||||
router.push({ params: { tab: 'contributions' } })
|
||||
@ -187,19 +146,11 @@ onListContributionsResult(({ data }) => {
|
||||
const updateTabIndex = () => {
|
||||
const index = COMMUNITY_TABS.indexOf(route.params.tab)
|
||||
tabIndex.value = index > -1 ? index : 0
|
||||
closeAllOpenCollapse()
|
||||
}
|
||||
|
||||
const closeAllOpenCollapse = () => {
|
||||
document.querySelectorAll('.collapse.show').forEach((el) => {
|
||||
el.classList.remove('show')
|
||||
})
|
||||
}
|
||||
|
||||
const refetchData = () => {
|
||||
refetchAllContributions()
|
||||
refetchContributions()
|
||||
refetchOpenCreations()
|
||||
handleInProgressContributionFound()
|
||||
}
|
||||
|
||||
const handleSaveContribution = async (data) => {
|
||||
@ -243,21 +194,6 @@ const handleDeleteContribution = async (data) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateListAllContributions = (pagination) => {
|
||||
currentPageAll.value = pagination.currentPage
|
||||
pageSizeAll.value = pagination.pageSize
|
||||
refetchAllContributions({
|
||||
currentPage: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
})
|
||||
}
|
||||
|
||||
const handleUpdateListContributions = (pagination) => {
|
||||
currentPage.value = pagination.currentPage
|
||||
pageSize.value = pagination.pageSize
|
||||
refetchContributions()
|
||||
}
|
||||
|
||||
const handleUpdateContributionForm = (item) => {
|
||||
form.value = {
|
||||
id: item.id,
|
||||
@ -272,13 +208,6 @@ const handleUpdateContributionForm = (item) => {
|
||||
router.push({ params: { tab: 'contribute' } })
|
||||
}
|
||||
|
||||
const updateStatus = (id) => {
|
||||
const item = items.value.find((item) => item.id === id)
|
||||
if (item) {
|
||||
item.status = 'PENDING'
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => route.params.tab, updateTabIndex)
|
||||
|
||||
onMounted(updateTabIndex)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user