mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
decouple all and user contributions for better code readability and testability
This commit is contained in:
parent
7aeac5690f
commit
813caa1fac
@ -4,12 +4,29 @@ import { mount } from '@vue/test-utils'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import ContributionList from './ContributionList'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
})
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: { template: '<div>Home</div>' },
|
||||
},
|
||||
{
|
||||
path: '/test',
|
||||
name: 'test',
|
||||
component: ContributionList,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
vi.mock('@/components/Contributions/ContributionListItem.vue', () => ({
|
||||
default: {
|
||||
name: 'ContributionListItem',
|
||||
@ -25,7 +42,7 @@ describe('ContributionList', () => {
|
||||
let wrapper
|
||||
|
||||
const global = {
|
||||
plugins: [i18n],
|
||||
plugins: [i18n, router],
|
||||
mocks: {
|
||||
$filters: {
|
||||
GDD: vi.fn((val) => val),
|
||||
@ -36,9 +53,9 @@ describe('ContributionList', () => {
|
||||
},
|
||||
}
|
||||
|
||||
const contributionsList = {
|
||||
const contributions = {
|
||||
contributionCount: 3,
|
||||
contributionList: [
|
||||
listContributions: [
|
||||
{
|
||||
id: 0,
|
||||
date: '07/06/2022',
|
||||
@ -64,11 +81,13 @@ describe('ContributionList', () => {
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
contributionCount: 3,
|
||||
showPagination: true,
|
||||
pageSize: 25,
|
||||
allContribution: false,
|
||||
items: [
|
||||
emptyText: '',
|
||||
}
|
||||
|
||||
const allContributions = {
|
||||
contributionCount: 3,
|
||||
listAllContributions: [
|
||||
{
|
||||
id: 0,
|
||||
date: '07/06/2022',
|
||||
@ -95,7 +114,7 @@ describe('ContributionList', () => {
|
||||
|
||||
const mountWrapper = () => {
|
||||
return mount(ContributionList, {
|
||||
props: propsData,
|
||||
propsData,
|
||||
global,
|
||||
})
|
||||
}
|
||||
@ -107,10 +126,20 @@ describe('ContributionList', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === listContributions) {
|
||||
return { onResult: mockListContributionsQuery, refetch: vi.fn() }
|
||||
return {
|
||||
result: contributions,
|
||||
loading: vi.fn(),
|
||||
onResult: mockListContributionsQuery,
|
||||
refetch: vi.fn(),
|
||||
}
|
||||
}
|
||||
if (query === listAllContributions) {
|
||||
return { onResult: mockListAllContributionsQuery, refetch: vi.fn() }
|
||||
return {
|
||||
result: allContributions,
|
||||
loading: vi.fn(),
|
||||
onResult: mockListAllContributionsQuery,
|
||||
refetch: vi.fn(),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -152,7 +181,8 @@ describe('ContributionList', () => {
|
||||
|
||||
describe('list count greater than page size', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({ contributionCount: 33 })
|
||||
contributions.contributionCount = 33
|
||||
// await wrapper.setProps({ contributionCount: 33 })
|
||||
})
|
||||
|
||||
it('has pagination buttons', () => {
|
||||
@ -165,7 +195,8 @@ describe('ContributionList', () => {
|
||||
window.scrollTo = scrollToMock
|
||||
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({ contributionCount: 33 })
|
||||
contributions.contributionCount = 33
|
||||
// await wrapper.setProps({ contributionCount: 33 })
|
||||
await wrapper.findComponent({ name: 'BPagination' }).vm.$emit('update:modelValue', 2)
|
||||
})
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="items.length === 0 && !loading">
|
||||
<div v-if="currentPage === 1">
|
||||
{{ emptyText }}
|
||||
{{ t('contribution.noContributions.myContributions') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ t('contribution.noContributions.emptyPage') }}
|
||||
@ -13,7 +13,6 @@
|
||||
<contribution-list-item
|
||||
v-bind="item"
|
||||
:contribution-id="item.id"
|
||||
:all-contribution="allContribution"
|
||||
:messages-visible="openMessagesListId === item.id"
|
||||
@toggle-messages-visible="toggleMessagesVisible(item.id)"
|
||||
@update-contribution-form="updateContributionForm"
|
||||
@ -22,98 +21,71 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BPagination
|
||||
v-if="isPaginationVisible"
|
||||
:model-value="currentPage"
|
||||
class="mt-3"
|
||||
pills
|
||||
size="lg"
|
||||
:per-page="pageSize"
|
||||
:total-rows="contributionCount"
|
||||
align="center"
|
||||
:hide-ellipsis="true"
|
||||
@update:model-value="updatePage"
|
||||
<paginator-route-params-page
|
||||
v-model="currentPage"
|
||||
:page-size="pageSize"
|
||||
:total-count="contributionCount"
|
||||
:loading="loading"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from 'vue'
|
||||
import ContributionListItem from '@/components/Contributions/ContributionListItem.vue'
|
||||
import { listContributions, listAllContributions } from '@/graphql/contributions.graphql'
|
||||
import { listContributions } from '@/graphql/contributions.graphql'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { PAGE_SIZE } from '@/constants'
|
||||
import { useAppToast } from '@/composables/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import CONFIG from '@/config'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
import PaginatorRouteParamsPage from '@/components/PaginatorRouteParamsPage.vue'
|
||||
|
||||
const props = defineProps({
|
||||
allContribution: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const route = useRoute()
|
||||
|
||||
// composables
|
||||
const { toastError, toastSuccess } = useAppToast()
|
||||
const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// constants
|
||||
const pageSize = PAGE_SIZE
|
||||
const pollInterval = CONFIG.AUTO_POLL_INTERVAL || undefined
|
||||
|
||||
// events
|
||||
const emit = defineEmits(['update-contribution-form'])
|
||||
|
||||
// refs
|
||||
const currentPage = computed(() => Number(route.params.page) || 1)
|
||||
const currentPage = ref(1)
|
||||
|
||||
// computed
|
||||
const openMessagesListId = ref(null)
|
||||
|
||||
// queries
|
||||
const { result, loading, refetch, onResult } = useQuery(
|
||||
props.allContribution ? listAllContributions : listContributions,
|
||||
() => ({
|
||||
listContributions,
|
||||
{
|
||||
pagination: {
|
||||
currentPage: currentPage.value,
|
||||
pageSize,
|
||||
order: 'DESC',
|
||||
},
|
||||
messagePagination: !props.allContribution
|
||||
? {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
order: 'ASC',
|
||||
}
|
||||
: undefined,
|
||||
}),
|
||||
{ fetchPolicy: 'cache-and-network', pollInterval },
|
||||
messagePagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
order: 'ASC',
|
||||
},
|
||||
},
|
||||
{
|
||||
fetchPolicy: 'cache-and-network',
|
||||
pollInterval,
|
||||
},
|
||||
)
|
||||
|
||||
// events
|
||||
const emit = defineEmits(['update-contribution-form'])
|
||||
|
||||
// computed
|
||||
const contributionListResult = computed(() => {
|
||||
return props.allContribution
|
||||
? result.value?.listAllContributions
|
||||
: result.value?.listContributions
|
||||
})
|
||||
const contributionCount = computed(() => {
|
||||
return contributionListResult.value?.contributionCount || 0
|
||||
return result.value?.listContributions.contributionCount || 0
|
||||
})
|
||||
const items = computed(() => {
|
||||
return [...(contributionListResult.value?.contributionList || [])]
|
||||
})
|
||||
const isPaginationVisible = computed(() => {
|
||||
return (contributionCount.value > pageSize || currentPage.value > 1) && !loading.value
|
||||
return [...(result.value?.listContributions.contributionList || [])]
|
||||
})
|
||||
|
||||
// callbacks
|
||||
onResult(({ data }) => {
|
||||
onResult(({ _data }) => {
|
||||
nextTick(() => {
|
||||
if (!route.hash) {
|
||||
return
|
||||
@ -136,7 +108,4 @@ const toggleMessagesVisible = (contributionId) => {
|
||||
const updateContributionForm = (item) => {
|
||||
emit('update-contribution-form', { item, page: currentPage.value })
|
||||
}
|
||||
const updatePage = (page) => {
|
||||
router.push({ params: { page } })
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div v-if="items.length === 0 && !loading">
|
||||
<div v-if="currentPage === 1">
|
||||
{{ $t('contribution.noContributions.allContributions') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ $t('contribution.noContributions.emptyPage') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="all-contribution-list">
|
||||
<div v-for="item in items" :key="item.id + 'a'" class="mb-3">
|
||||
<div :id="`contributionListItem-${item.id}`">
|
||||
<contribution-list-all-item v-bind="item" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<paginator-route-params-page
|
||||
v-model="currentPage"
|
||||
:total-count="contributionCount"
|
||||
:loading="loading"
|
||||
:page-size="pageSize"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import ContributionListAllItem from '@/components/Contributions/ContributionListAllItem.vue'
|
||||
import { listAllContributions } from '@/graphql/contributions.graphql'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import CONFIG from '@/config'
|
||||
import PaginatorRouteParamsPage from '@/components/PaginatorRouteParamsPage.vue'
|
||||
import { PAGE_SIZE } from '@/constants'
|
||||
|
||||
// constants
|
||||
const pollInterval = CONFIG.AUTO_POLL_INTERVAL || undefined
|
||||
const pageSize = PAGE_SIZE
|
||||
|
||||
// computed
|
||||
const currentPage = ref(1)
|
||||
|
||||
const { result, loading } = useQuery(
|
||||
listAllContributions,
|
||||
{
|
||||
pagination: {
|
||||
currentPage: currentPage.value,
|
||||
pageSize,
|
||||
order: 'DESC',
|
||||
},
|
||||
},
|
||||
{
|
||||
fetchPolicy: 'cache-and-network',
|
||||
pollInterval,
|
||||
},
|
||||
)
|
||||
|
||||
const contributionCount = computed(() => {
|
||||
return result.value?.listAllContributions.contributionCount || 0
|
||||
})
|
||||
const items = computed(() => {
|
||||
return [...(result.value?.listAllContributions.contributionList || [])]
|
||||
})
|
||||
</script>
|
||||
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="contribution-list-item bg-white app-box-shadow gradido-border-radius pt-3 px-3">
|
||||
<BRow>
|
||||
<BCol cols="3" lg="2" md="2">
|
||||
<app-avatar
|
||||
v-if="username.username"
|
||||
:name="username.username"
|
||||
:initials="username.initials"
|
||||
color="#fff"
|
||||
class="vue3-avatar fw-bold"
|
||||
/>
|
||||
</BCol>
|
||||
<BCol>
|
||||
<div v-if="username.username" class="me-3 fw-bold">
|
||||
{{ username.username }}
|
||||
<variant-icon :icon="icon" :variant="variant" />
|
||||
</div>
|
||||
<div class="small">
|
||||
{{ $d(new Date(contributionDate), 'short') }}
|
||||
</div>
|
||||
<div class="mt-3 fw-bold">{{ $t('contributionText') }}</div>
|
||||
<div class="mb-3 text-break word-break">{{ memo }}</div>
|
||||
<div v-if="updatedBy > 0" class="mt-2 mb-2 small">
|
||||
{{ $t('moderatorChangedMemo') }}
|
||||
</div>
|
||||
</BCol>
|
||||
<BCol cols="9" lg="3" offset="3" offset-md="0" offset-lg="0">
|
||||
<div class="small">
|
||||
{{ $t('creation') }} {{ $t('(') }}{{ hours }} {{ $t('h') }}{{ $t(')') }}
|
||||
</div>
|
||||
<div v-if="contributionStatus === 'DENIED'" class="fw-bold">
|
||||
<variant-icon icon="x-circle" variant="danger" />
|
||||
{{ $t('contribution.alert.denied') }}
|
||||
</div>
|
||||
<div v-if="contributionStatus === 'DELETED'" class="small">
|
||||
{{ $t('contribution.deleted') }}
|
||||
</div>
|
||||
<div v-else class="fw-bold">{{ $filters.GDD(amount) }}</div>
|
||||
</BCol>
|
||||
<BCol cols="12" md="1" lg="1" class="text-end align-items-center" />
|
||||
</BRow>
|
||||
<div class="pb-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import AppAvatar from '@/components/AppAvatar.vue'
|
||||
import { GDD_PER_HOUR } from '../../constants'
|
||||
import { useContributionStatus } from '@/composables/useContributionStatus'
|
||||
|
||||
const props = defineProps({
|
||||
amount: {
|
||||
type: String,
|
||||
},
|
||||
memo: {
|
||||
type: String,
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
contributionDate: {
|
||||
type: String,
|
||||
},
|
||||
updatedBy: {
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
contributionStatus: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const { getVariant, getIcon } = useContributionStatus()
|
||||
const variant = computed(() => getVariant(props.contributionStatus))
|
||||
const icon = computed(() => getIcon(props.contributionStatus))
|
||||
|
||||
const username = computed(() => {
|
||||
if (!props.user) return {}
|
||||
return {
|
||||
username: props.user.alias
|
||||
? props.user.alias
|
||||
: `${props.user.firstName} ${props.user.lastName}`,
|
||||
initials: `${props.user.firstName[0]}${props.user.lastName[0]}`,
|
||||
}
|
||||
})
|
||||
|
||||
const hours = computed(() => parseFloat((props.amount / GDD_PER_HOUR).toFixed(2)))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.b-avatar-custom > svg) {
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
}
|
||||
</style>
|
||||
@ -2,26 +2,15 @@
|
||||
<div>
|
||||
<div
|
||||
class="contribution-list-item bg-white app-box-shadow gradido-border-radius pt-3 px-3"
|
||||
:class="localStatus === 'IN_PROGRESS' && !allContribution ? 'pulse border border-205' : ''"
|
||||
:class="localStatus === 'IN_PROGRESS' ? 'pulse border border-205' : ''"
|
||||
>
|
||||
<BRow>
|
||||
<BCol cols="3" lg="2" md="2">
|
||||
<app-avatar
|
||||
v-if="username.username"
|
||||
:name="username.username"
|
||||
:initials="username.initials"
|
||||
color="#fff"
|
||||
class="vue3-avatar fw-bold"
|
||||
/>
|
||||
<BAvatar v-else rounded="lg" :variant="variant" size="4.55em">
|
||||
<BAvatar rounded="lg" :variant="variant" size="4.55em">
|
||||
<variant-icon :icon="icon" variant="white" />
|
||||
</BAvatar>
|
||||
</BCol>
|
||||
<BCol>
|
||||
<div v-if="username.username" class="me-3 fw-bold">
|
||||
{{ username.username }}
|
||||
<variant-icon :icon="icon" :variant="variant" />
|
||||
</div>
|
||||
<div class="small">
|
||||
{{ $d(new Date(contributionDate), 'short') }}
|
||||
</div>
|
||||
@ -31,7 +20,7 @@
|
||||
{{ $t('moderatorChangedMemo') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="localStatus === 'IN_PROGRESS' && !allContribution"
|
||||
v-if="localStatus === 'IN_PROGRESS'"
|
||||
class="text-danger pointer hover-font-bold"
|
||||
@click="emit('toggle-messages-visible')"
|
||||
>
|
||||
@ -42,10 +31,6 @@
|
||||
<div class="small">
|
||||
{{ $t('creation') }} {{ $t('(') }}{{ hours }} {{ $t('h') }}{{ $t(')') }}
|
||||
</div>
|
||||
<div v-if="localStatus === 'DENIED' && allContribution" class="fw-bold">
|
||||
<variant-icon icon="x-circle" variant="danger" />
|
||||
{{ $t('contribution.alert.denied') }}
|
||||
</div>
|
||||
<div v-if="localStatus === 'DELETED'" class="small">
|
||||
{{ $t('contribution.deleted') }}
|
||||
</div>
|
||||
@ -57,17 +42,10 @@
|
||||
</div>
|
||||
</BCol>
|
||||
</BRow>
|
||||
<BRow
|
||||
v-if="
|
||||
(!['CONFIRMED', 'DELETED'].includes(localStatus) && !allContribution) || messagesCount > 0
|
||||
"
|
||||
class="p-2"
|
||||
>
|
||||
<BRow v-if="!['CONFIRMED', 'DELETED'].includes(localStatus) || messagesCount > 0" class="p-2">
|
||||
<BCol cols="3" class="me-auto text-center">
|
||||
<div
|
||||
v-if="
|
||||
!['CONFIRMED', 'DELETED'].includes(localStatus) && !allContribution && !moderatorId
|
||||
"
|
||||
v-if="!['CONFIRMED', 'DELETED'].includes(localStatus) && !moderatorId"
|
||||
class="test-delete-contribution pointer me-3"
|
||||
@click="processDeleteContribution({ id })"
|
||||
>
|
||||
@ -78,9 +56,7 @@
|
||||
</BCol>
|
||||
<BCol cols="3" class="text-center">
|
||||
<div
|
||||
v-if="
|
||||
!['CONFIRMED', 'DELETED'].includes(localStatus) && !allContribution && !moderatorId
|
||||
"
|
||||
v-if="!['CONFIRMED', 'DELETED'].includes(localStatus) && !moderatorId"
|
||||
class="test-edit-contribution pointer me-3"
|
||||
@click="
|
||||
$emit('update-contribution-form', {
|
||||
@ -111,7 +87,7 @@
|
||||
v-if="messagesCount > 0"
|
||||
:messages="localMessages"
|
||||
:status="localStatus"
|
||||
:contribution-id="contributionId"
|
||||
:contribution-id="id"
|
||||
@close-messages-list="emit('toggle-messages-visible')"
|
||||
@add-contribution-message="addContributionMessage"
|
||||
/>
|
||||
@ -128,9 +104,9 @@ import ContributionMessagesList from '@/components/ContributionMessages/Contribu
|
||||
import { useAppToast } from '@/composables/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useMutation } from '@vue/apollo-composable'
|
||||
import AppAvatar from '@/components/AppAvatar.vue'
|
||||
import { GDD_PER_HOUR } from '../../constants'
|
||||
import { deleteContribution } from '@/graphql/contributions.graphql'
|
||||
import { useContributionStatus } from '@/composables/useContributionStatus'
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
@ -147,36 +123,9 @@ const props = defineProps({
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
createdAt: {
|
||||
type: String,
|
||||
},
|
||||
contributionDate: {
|
||||
type: String,
|
||||
},
|
||||
deletedAt: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
confirmedBy: {
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
confirmedAt: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
deniedBy: {
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
deniedAt: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
updatedBy: {
|
||||
type: Number,
|
||||
required: false,
|
||||
@ -190,15 +139,6 @@ const props = defineProps({
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
contributionId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
allContribution: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
moderatorId: {
|
||||
type: Number,
|
||||
required: false,
|
||||
@ -213,11 +153,14 @@ const props = defineProps({
|
||||
|
||||
const { toastError, toastSuccess } = useAppToast()
|
||||
const { t } = useI18n()
|
||||
const { getVariant, getIcon } = useContributionStatus()
|
||||
|
||||
const { mutate: deleteContributionMutation } = useMutation(deleteContribution)
|
||||
|
||||
const localMessages = ref([])
|
||||
const localStatus = ref(props.contributionStatus)
|
||||
const variant = computed(() => getVariant(props.contributionStatus))
|
||||
const icon = computed(() => getIcon(props.contributionStatus))
|
||||
|
||||
// if parent reload messages, update local messages copy
|
||||
watch(
|
||||
@ -237,32 +180,6 @@ watch(
|
||||
},
|
||||
)
|
||||
|
||||
const statusMapping = {
|
||||
CONFIRMED: { variant: 'success', icon: 'check' },
|
||||
DELETED: { variant: 'danger', icon: 'trash' },
|
||||
DENIED: { variant: 'warning', icon: 'x-circle' },
|
||||
IN_PROGRESS: { variant: '205', icon: 'question' },
|
||||
default: { variant: 'primary', icon: 'bell-fill' },
|
||||
}
|
||||
|
||||
const variant = computed(() => {
|
||||
return (statusMapping[localStatus.value] || statusMapping.default).variant
|
||||
})
|
||||
|
||||
const icon = computed(() => {
|
||||
return (statusMapping[localStatus.value] || statusMapping.default).icon
|
||||
})
|
||||
|
||||
const username = computed(() => {
|
||||
if (!props.user) return {}
|
||||
return {
|
||||
username: props.user.alias
|
||||
? props.user.alias
|
||||
: `${props.user.firstName} ${props.user.lastName}`,
|
||||
initials: `${props.user.firstName[0]}${props.user.lastName[0]}`,
|
||||
}
|
||||
})
|
||||
|
||||
const hours = computed(() => parseFloat((props.amount / GDD_PER_HOUR).toFixed(2)))
|
||||
|
||||
async function processDeleteContribution(item) {
|
||||
|
||||
54
frontend/src/components/PaginatorRouteParamsPage.vue
Normal file
54
frontend/src/components/PaginatorRouteParamsPage.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<BPagination
|
||||
v-if="isPaginationVisible"
|
||||
:model-value="currentPage"
|
||||
class="mt-3"
|
||||
pills
|
||||
size="lg"
|
||||
:per-page="pageSize"
|
||||
:total-rows="totalCount"
|
||||
align="center"
|
||||
:hide-ellipsis="true"
|
||||
@update:model-value="updatePage"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import CONFIG from '@/config'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: CONFIG.PAGE_SIZE,
|
||||
},
|
||||
totalCount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:model-value'])
|
||||
|
||||
const isPaginationVisible = computed(() => {
|
||||
return (props.totalCount > props.pageSize || props.modelValue > 1) && !props.loading
|
||||
})
|
||||
const currentPage = computed(() => Number(route.params.page) || props.modelValue)
|
||||
const updatePage = (page) => {
|
||||
router.push({ params: { page } })
|
||||
emit('update:model-value', page)
|
||||
}
|
||||
</script>
|
||||
22
frontend/src/composables/useContributionStatus.js
Normal file
22
frontend/src/composables/useContributionStatus.js
Normal file
@ -0,0 +1,22 @@
|
||||
export const useContributionStatus = () => {
|
||||
const statusMapping = {
|
||||
CONFIRMED: { variant: 'success', icon: 'check' },
|
||||
DELETED: { variant: 'danger', icon: 'trash' },
|
||||
DENIED: { variant: 'warning', icon: 'x-circle' },
|
||||
IN_PROGRESS: { variant: '205', icon: 'question' },
|
||||
default: { variant: 'primary', icon: 'bell-fill' },
|
||||
}
|
||||
|
||||
const getVariant = (status) => {
|
||||
return (statusMapping[status] || statusMapping.default).variant
|
||||
}
|
||||
|
||||
const getIcon = (status) => {
|
||||
return (statusMapping[status] || statusMapping.default).icon
|
||||
}
|
||||
|
||||
return {
|
||||
getVariant,
|
||||
getIcon,
|
||||
}
|
||||
}
|
||||
@ -35,12 +35,17 @@ query listContributions ($pagination: Paginated!, $messagePagination: Paginated!
|
||||
listContributions(pagination: $pagination, messagePagination: $messagePagination) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
...contributionFields
|
||||
deletedAt
|
||||
moderatorId
|
||||
id
|
||||
amount
|
||||
memo
|
||||
contributionDate
|
||||
contributionStatus
|
||||
messagesCount
|
||||
messages(pagination: $messagePagination) {
|
||||
...contributionMessageFields
|
||||
}
|
||||
updatedBy
|
||||
moderatorId
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,10 +54,14 @@ query listAllContributions ($pagination: Paginated!) {
|
||||
listAllContributions(pagination: $pagination) {
|
||||
contributionCount
|
||||
contributionList {
|
||||
amount
|
||||
memo
|
||||
user {
|
||||
...userFields
|
||||
}
|
||||
...contributionFields
|
||||
}
|
||||
contributionDate
|
||||
updatedBy
|
||||
contributionStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,16 +11,10 @@
|
||||
<contribution-create v-else />
|
||||
</BTab>
|
||||
<BTab no-body lazy>
|
||||
<contribution-list
|
||||
:empty-text="$t('contribution.noContributions.myContributions')"
|
||||
@update-contribution-form="handleUpdateContributionForm"
|
||||
/>
|
||||
<contribution-list @update-contribution-form="handleUpdateContributionForm" />
|
||||
</BTab>
|
||||
<BTab no-body lazy>
|
||||
<contribution-list
|
||||
:empty-text="$t('contribution.noContributions.allContributions')"
|
||||
:all-contribution="true"
|
||||
/>
|
||||
<contribution-list-all />
|
||||
</BTab>
|
||||
</BTabs>
|
||||
</div>
|
||||
@ -28,24 +22,23 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import OpenCreationsAmount from '@/components/Contributions/OpenCreationsAmount'
|
||||
import ContributionEdit from '@/components/Contributions/ContributionEdit'
|
||||
import ContributionCreate from '@/components/Contributions/ContributionCreate'
|
||||
import ContributionList from '@/components/Contributions/ContributionList'
|
||||
import ContributionListAll from '@/components/Contributions/ContributionListAll'
|
||||
import { countContributionsInProgress } from '@/graphql/contributions.graphql'
|
||||
import { useAppToast } from '@/composables/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { GDD_PER_HOUR } from '../constants'
|
||||
|
||||
const COMMUNITY_TABS = ['contribute', 'contributions', 'community']
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const { toastError, toastSuccess, toastInfo } = useAppToast()
|
||||
const { toastInfo } = useAppToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
const tabIndex = ref(0)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user