Skip to content

Commit

Permalink
Feature: Mobile - Fetch secondary organizations for user view
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Oct 4, 2022
1 parent 46d360f commit a4ea246
Show file tree
Hide file tree
Showing 26 changed files with 304 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ import CommonSectionMenu from '../CommonSectionMenu/CommonSectionMenu.vue'

interface Props {
organizations: (AvatarOrganization & { id: string; internalId: number })[]
totalCount: number
disableShowMore?: boolean
label?: string
}

defineProps<Props>()
withDefaults(defineProps<Props>(), {
disableShowMore: false,
})

const emit = defineEmits<{
(e: 'showMore'): void
}>()
</script>

<template>
Expand All @@ -29,5 +37,17 @@ defineProps<Props>()
{{ organization.name }}
</span>
</CommonLink>
<button
v-if="organizations.length < totalCount"
class="flex min-h-[54px] items-center justify-center gap-2"
:class="{
'cursor-default text-gray-100/50': disableShowMore,
'text-blue': !disableShowMore,
}"
:disabled="disableShowMore"
@click="emit('showMore')"
>
{{ $t('Show %s more', totalCount - organizations.length) }}
</button>
</CommonSectionMenu>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/

import { useObjectAttributes } from '@shared/entities/object-attributes/composables/useObjectAttributes'
import type {
OrganizationUpdatesSubscriptionVariables,
OrganizationUpdatesSubscription,
} from '@shared/graphql/types'
import { EnumObjectManagerObjects } from '@shared/graphql/types'
import { QueryHandler } from '@shared/server/apollo/handler'
import { computed, nextTick, ref, watch } from 'vue'
import { useOrganizationLazyQuery } from '../graphql/queries/organization.api'
import { OrganizationUpdatesDocument } from '../graphql/subscriptions/organizationUpdates.api'

export const useOrganizationDetail = () => {
const internalId = ref(0)

const organizationQuery = new QueryHandler(
useOrganizationLazyQuery(
() => ({
organizationInternalId: internalId.value,
membersCount: 3,
}),
() => ({ enabled: internalId.value > 0 }),
),
)

const loadOrganization = (id: number) => {
internalId.value = id
nextTick(() => {
organizationQuery.load()
})
}

const organizationResult = organizationQuery.result()
const loading = organizationQuery.loading()

const organization = computed(() => organizationResult.value?.organization)

const loadAllMembers = () => {
const organizationInternalId = organization.value?.internalId
if (!organizationInternalId) {
return
}

organizationQuery.refetch({
organizationInternalId,
membersCount: null,
})
}

const { attributes: objectAttributes } = useObjectAttributes(
EnumObjectManagerObjects.Organization,
)

watch(
() => organization.value?.id,
(organizationId) => {
if (!organizationId) {
return
}

organizationQuery.subscribeToMore<
OrganizationUpdatesSubscriptionVariables,
OrganizationUpdatesSubscription
>({
document: OrganizationUpdatesDocument,
variables: {
organizationId,
},
})
},
{ immediate: true },
)

return {
loading,
organizationQuery,
organization,
objectAttributes,
loadOrganization,
loadAllMembers,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ export const defaultUser = (): ConfidentTake<UserQuery, 'user'> => {
name: organization.name,
ticketsCount: organization.ticketsCount,
},
secondaryOrganizations: {
__typename: 'OrganizationConnection',
edges: [
{
__typename: 'OrganizationEdge',
node: {
__typename: 'Organization',
id: 'dsa34fsa223d',
name: 'Dammaz',
internalId: 10,
active: true,
},
},
],
totalCount: 1,
},
objectAttributeValues: [
{
attribute: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import type {
UserUpdatesSubscription,
} from '@shared/graphql/types'
import { QueryHandler } from '@shared/server/apollo/handler'
import { whenever } from '@vueuse/shared'
import { computed, nextTick, ref } from 'vue'
import { computed, nextTick, ref, watch } from 'vue'
import { useUserObjectAttributesStore } from '@shared/entities/user/stores/objectAttributes'
import { useUserLazyQuery } from '../graphql/queries/user.api'

Expand All @@ -18,6 +17,7 @@ export const useUserDetail = () => {
useUserLazyQuery(
() => ({
userInternalId: internalId.value,
secondaryOrganizationsCount: 3,
}),
() => ({ enabled: internalId.value > 0 }),
),
Expand All @@ -30,6 +30,13 @@ export const useUserDetail = () => {
})
}

const loadAllSecondaryOrganizations = () => {
userQuery.refetch({
userInternalId: internalId.value,
secondaryOrganizationsCount: null,
})
}

const userResult = userQuery.result()
const loading = userQuery.loading()

Expand All @@ -41,29 +48,29 @@ export const useUserDetail = () => {
() => objectAttributesManager.viewScreenAttributes || [],
)

const stopWatch = whenever(
() => user.value != null,
() => {
if (!user.value) return

stopWatch()
watch(
() => user.value?.id,
(userId) => {
if (!userId) return

userQuery.subscribeToMore<
UserUpdatesSubscriptionVariables,
UserUpdatesSubscription
>({
document: UserUpdatesDocument,
variables: {
userId: user.value.id,
userId,
},
})
},
{ immediate: true },
)

return {
loading,
user,
objectAttributes,
loadAllSecondaryOrganizations,
loadUser,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,20 @@ import * as VueCompositionApi from 'vue';
export type ReactiveFunction<TParam> = () => TParam;

export const UserDocument = gql`
query user($userId: ID, $userInternalId: Int) {
query user($userId: ID, $userInternalId: Int, $secondaryOrganizationsCount: Int) {
user(user: {userId: $userId, userInternalId: $userInternalId}) {
...userDetailAttributes
secondaryOrganizations(first: $secondaryOrganizationsCount) {
edges {
node {
id
internalId
active
name
}
}
totalCount
}
}
}
${UserDetailAttributesFragmentDoc}`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
query user($userId: ID, $userInternalId: Int) {
query user(
$userId: ID
$userInternalId: Int
$secondaryOrganizationsCount: Int
) {
user(user: { userId: $userId, userInternalId: $userInternalId }) {
...userDetailAttributes
secondaryOrganizations(first: $secondaryOrganizationsCount) {
edges {
node {
id
internalId
active
name
}
}
totalCount
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('static organization', () => {
)
mockOrganizationObjectAttributes()

const view = await visitView('/organizations/3423225dsf0')
const view = await visitView(`/organizations/${organization.internalId}`)

await waitUntil(() => mockApi.calls.resolve)

Expand Down Expand Up @@ -85,7 +85,7 @@ describe('static organization', () => {
mockGraphQLSubscription(OrganizationUpdatesDocument)
mockOrganizationObjectAttributes()

const view = await visitView('/organizations/3423225dsf0')
const view = await visitView(`/organizations/${organization.internalId}`)

await waitUntil(() => mockApi.calls.resolve)

Expand Down
4 changes: 2 additions & 2 deletions app/frontend/apps/mobile/pages/organization/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
{
path: '/organizations/:id',
path: '/organizations/:internalId',
name: 'OrganizationDetailView',
props: true,
props: (route) => ({ internalId: Number(route.params.internalId) }),
component: () => import('./views/OrganizationDetailView.vue'),
meta: {
title: __('Organization'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,34 @@
import { useRouter } from 'vue-router'
import { computed } from 'vue'
import CommonOrganizationAvatar from '@shared/components/CommonOrganizationAvatar/CommonOrganizationAvatar.vue'
import { QueryHandler } from '@shared/server/apollo/handler'
import { useHeader } from '@mobile/composables/useHeader'
import CommonLoader from '@mobile/components/CommonLoader/CommonLoader.vue'
import CommonTicketStateList from '@mobile/components/CommonTicketStateList/CommonTicketStateList.vue'
import { redirectToError } from '@mobile/router/error'
import { ErrorStatusCodes } from '@shared/types/error'
import { useOrganizationQuery } from '@mobile/entities/organization/graphql/queries/organization.api'
import { OrganizationUpdatesDocument } from '@mobile/entities/organization/graphql/subscriptions/organizationUpdates.api'
import { useOrganizationEdit } from '@mobile/entities/organization/composables/useOrganizationEdit'
import OrganizationMembersList from '@mobile/components/Organization/OrganizationMembersList.vue'
import { useOrganizationObjectAttributesStore } from '@shared/entities/organization/stores/objectAttributes'
import { AvatarOrganization } from '@shared/components/CommonOrganizationAvatar'
import CommonObjectAttributes from '@mobile/components/CommonObjectAttributes/CommonObjectAttributes.vue'
import { useOrganizationTicketsCount } from '@mobile/entities/organization/composables/useOrganizationTicketsCount'
import { useOrganizationDetail } from '@mobile/entities/organization/composables/useOrganizationDetail'

interface Props {
id: string
internalId: number
}

const props = defineProps<Props>()

const organizationQuery = new QueryHandler(
useOrganizationQuery({
organizationId: props.id,
membersCount: 3,
}),
)
const {
organization,
organizationQuery,
loading,
objectAttributes,
loadAllMembers,
loadOrganization,
} = useOrganizationDetail()

organizationQuery.subscribeToMore({
document: OrganizationUpdatesDocument,
variables: {
organizationId: props.id,
},
})
loadOrganization(props.internalId)

const router = useRouter()

Expand All @@ -49,17 +43,6 @@ organizationQuery.onError(() => {
})
})

const organizationResult = organizationQuery.result()
const loading = organizationQuery.loading()

const organization = computed(() => organizationResult.value?.organization)

const objectAttributesManager = useOrganizationObjectAttributesStore()

const objectAttributes = computed(
() => objectAttributesManager.viewScreenAttributes || [],
)

const { openEditOrganizationDialog } = useOrganizationEdit()

useHeader({
Expand All @@ -72,13 +55,6 @@ useHeader({
},
})

const loadAllMembers = () => {
organizationQuery.refetch({
organizationId: props.id,
membersCount: null,
})
}

const { getTicketData } = useOrganizationTicketsCount()
const ticketData = computed(() => getTicketData(organization.value))
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const defaultTicket = () =>
organization: {
__typename: 'Organization',
id: '3423225dsf0',
internalId: 300,
name: 'Zammad Foundation',
},
state: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ describe('visiting ticket user page', () => {
'href',
expect.stringContaining(`customer.id: ${user.internalId}`),
)

expect(view.getByText('Secondary organizations')).toBeInTheDocument()
expect(view.getByText('Dammaz')).toBeInTheDocument()
})

test('view fully configured user', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const TicketAttributesFragmentDoc = gql`
}
organization {
id
internalId
name
}
state {
Expand Down
Loading

0 comments on commit a4ea246

Please sign in to comment.