fix: implemented list group view in lead & deal
This commit is contained in:
parent
c86e78267d
commit
ed47d87315
@ -1 +1 @@
|
|||||||
Subproject commit 1394a12b6de105649c8ca5beeead62a38ef1b18e
|
Subproject commit 90c75affe85b2a1abfce68d61c0c5043f093a8a0
|
||||||
@ -29,14 +29,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</ListHeaderItem>
|
</ListHeaderItem>
|
||||||
</ListHeader>
|
</ListHeader>
|
||||||
<ListRows id="list-rows">
|
<ListRows :rows="rows" v-slot="{ idx, column, item }">
|
||||||
<ListRow
|
|
||||||
class="mx-5"
|
|
||||||
v-for="row in rows"
|
|
||||||
:key="row.name"
|
|
||||||
v-slot="{ idx, column, item }"
|
|
||||||
:row="row"
|
|
||||||
>
|
|
||||||
<div v-if="column.key === '_assign'" class="flex items-center">
|
<div v-if="column.key === '_assign'" class="flex items-center">
|
||||||
<MultipleAvatar
|
<MultipleAvatar
|
||||||
:avatars="item"
|
:avatars="item"
|
||||||
@ -85,8 +78,7 @@
|
|||||||
variant="ghosted"
|
variant="ghosted"
|
||||||
:class="isLiked(item) ? 'fill-red-500' : 'fill-white'"
|
:class="isLiked(item) ? 'fill-red-500' : 'fill-white'"
|
||||||
@click.stop.prevent="
|
@click.stop.prevent="
|
||||||
() =>
|
() => emit('likeDoc', { name: row.name, liked: isLiked(item) })
|
||||||
emit('likeDoc', { name: row.name, liked: isLiked(item) })
|
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<HeartIcon class="h-4 w-4" />
|
<HeartIcon class="h-4 w-4" />
|
||||||
@ -168,7 +160,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ListRowItem>
|
</ListRowItem>
|
||||||
</ListRow>
|
|
||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
@ -199,13 +190,12 @@ import MultipleAvatar from '@/components/MultipleAvatar.vue'
|
|||||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||||
import ListBulkActions from '@/components/ListBulkActions.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
|
import ListRows from '@/components/ListViews/ListRows.vue'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
ListHeader,
|
ListHeader,
|
||||||
ListHeaderItem,
|
ListHeaderItem,
|
||||||
ListRows,
|
|
||||||
ListRow,
|
|
||||||
ListRowItem,
|
ListRowItem,
|
||||||
ListSelectBanner,
|
ListSelectBanner,
|
||||||
ListFooter,
|
ListFooter,
|
||||||
|
|||||||
@ -29,14 +29,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</ListHeaderItem>
|
</ListHeaderItem>
|
||||||
</ListHeader>
|
</ListHeader>
|
||||||
<ListRows id="list-rows">
|
<ListRows :rows="rows" v-slot="{ idx, column, item }">
|
||||||
<ListRow
|
|
||||||
class="mx-5"
|
|
||||||
v-for="row in rows"
|
|
||||||
:key="row.name"
|
|
||||||
v-slot="{ idx, column, item }"
|
|
||||||
:row="row"
|
|
||||||
>
|
|
||||||
<div v-if="column.key === '_assign'" class="flex items-center">
|
<div v-if="column.key === '_assign'" class="flex items-center">
|
||||||
<MultipleAvatar
|
<MultipleAvatar
|
||||||
:avatars="item"
|
:avatars="item"
|
||||||
@ -123,7 +116,10 @@
|
|||||||
:class="isLiked(item) ? 'fill-red-500' : 'fill-white'"
|
:class="isLiked(item) ? 'fill-red-500' : 'fill-white'"
|
||||||
@click.stop.prevent="
|
@click.stop.prevent="
|
||||||
() =>
|
() =>
|
||||||
emit('likeDoc', { name: row.name, liked: isLiked(item) })
|
emit('likeDoc', {
|
||||||
|
name: row.name,
|
||||||
|
liked: isLiked(item),
|
||||||
|
})
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<HeartIcon class="h-4 w-4" />
|
<HeartIcon class="h-4 w-4" />
|
||||||
@ -177,7 +173,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ListRowItem>
|
</ListRowItem>
|
||||||
</ListRow>
|
|
||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
@ -208,13 +203,12 @@ import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
|||||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||||
import MultipleAvatar from '@/components/MultipleAvatar.vue'
|
import MultipleAvatar from '@/components/MultipleAvatar.vue'
|
||||||
import ListBulkActions from '@/components/ListBulkActions.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
|
import ListRows from '@/components/ListViews/ListRows.vue'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
ListHeader,
|
ListHeader,
|
||||||
ListHeaderItem,
|
ListHeaderItem,
|
||||||
ListRows,
|
|
||||||
ListRow,
|
|
||||||
ListSelectBanner,
|
ListSelectBanner,
|
||||||
ListRowItem,
|
ListRowItem,
|
||||||
ListFooter,
|
ListFooter,
|
||||||
|
|||||||
64
frontend/src/components/ListViews/ListRows.vue
Normal file
64
frontend/src/components/ListViews/ListRows.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mx-5 mt-2 h-full overflow-y-auto" v-if="showGroupedRows">
|
||||||
|
<div v-for="group in reactivieRows" :key="group.group">
|
||||||
|
<ListGroupHeader :group="group">
|
||||||
|
<div
|
||||||
|
class="my-2 flex items-center gap-2 text-base font-medium text-gray-800"
|
||||||
|
>
|
||||||
|
<div>{{ __('Status') }} -</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<IndicatorIcon :class="group.color" />
|
||||||
|
<div>{{ group.group }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ListGroupHeader>
|
||||||
|
<ListGroupRows :group="group" id="list-rows">
|
||||||
|
<ListRow
|
||||||
|
v-for="row in group.rows"
|
||||||
|
:key="row.name"
|
||||||
|
v-slot="{ idx, column, item }"
|
||||||
|
:row="row"
|
||||||
|
>
|
||||||
|
<slot v-bind="{ idx, column, item }" />
|
||||||
|
</ListRow>
|
||||||
|
</ListGroupRows>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ListRows class="mx-5" v-else id="list-rows">
|
||||||
|
<ListRow
|
||||||
|
v-for="row in reactivieRows"
|
||||||
|
:key="row.name"
|
||||||
|
v-slot="{ idx, column, item }"
|
||||||
|
:row="row"
|
||||||
|
>
|
||||||
|
<slot v-bind="{ idx, column, item }" />
|
||||||
|
</ListRow>
|
||||||
|
</ListRows>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||||
|
import { ListRows, ListRow, ListGroupHeader, ListGroupRows } from 'frappe-ui'
|
||||||
|
|
||||||
|
import { ref, computed, watch } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
rows: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const reactivieRows = ref(props.rows)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.rows,
|
||||||
|
(val) => (reactivieRows.value = val)
|
||||||
|
)
|
||||||
|
|
||||||
|
let showGroupedRows = computed(() => {
|
||||||
|
return props.rows.every(
|
||||||
|
(row) => row.group && row.rows && Array.isArray(row.rows)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -77,6 +77,7 @@ import {
|
|||||||
formatTime,
|
formatTime,
|
||||||
} from '@/utils'
|
} from '@/utils'
|
||||||
import { Breadcrumbs } from 'frappe-ui'
|
import { Breadcrumbs } from 'frappe-ui'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
const breadcrumbs = [{ label: __('Deals'), route: { name: 'Deals' } }]
|
const breadcrumbs = [{ label: __('Deals'), route: { name: 'Deals' } }]
|
||||||
@ -85,6 +86,8 @@ const { getUser } = usersStore()
|
|||||||
const { getOrganization } = organizationsStore()
|
const { getOrganization } = organizationsStore()
|
||||||
const { getDealStatus } = statusesStore()
|
const { getDealStatus } = statusesStore()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const dealsListView = ref(null)
|
const dealsListView = ref(null)
|
||||||
const showDealModal = ref(false)
|
const showDealModal = ref(false)
|
||||||
|
|
||||||
@ -98,7 +101,7 @@ const viewControls = ref(null)
|
|||||||
// Rows
|
// Rows
|
||||||
const rows = computed(() => {
|
const rows = computed(() => {
|
||||||
if (!deals.value?.data?.data) return []
|
if (!deals.value?.data?.data) return []
|
||||||
return deals.value.data.data.map((deal) => {
|
let listRows = deals.value.data.data.map((deal) => {
|
||||||
let _rows = {}
|
let _rows = {}
|
||||||
deals.value.data.rows.forEach((row) => {
|
deals.value.data.rows.forEach((row) => {
|
||||||
_rows[row] = deal[row]
|
_rows[row] = deal[row]
|
||||||
@ -174,5 +177,31 @@ const rows = computed(() => {
|
|||||||
})
|
})
|
||||||
return _rows
|
return _rows
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (route.params.viewType === 'group_by') {
|
||||||
|
return getGroupedByRows(listRows)
|
||||||
|
}
|
||||||
|
return listRows
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function getGroupedByRows(listRows) {
|
||||||
|
let groupedRows = []
|
||||||
|
|
||||||
|
listRows.forEach((row) => {
|
||||||
|
if (!groupedRows.some((group) => group.group === row.status.label)) {
|
||||||
|
groupedRows.push({
|
||||||
|
group: row.status.label,
|
||||||
|
color: getDealStatus(row.status.label)?.iconColorClass,
|
||||||
|
collapsed: false,
|
||||||
|
rows: [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
groupedRows.filter((group) => {
|
||||||
|
if (group.group === row.status.label) {
|
||||||
|
group.rows.push(row)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return groupedRows || listRows
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -78,7 +78,7 @@ import {
|
|||||||
createToast,
|
createToast,
|
||||||
} from '@/utils'
|
} from '@/utils'
|
||||||
import { createResource, Breadcrumbs } from 'frappe-ui'
|
import { createResource, Breadcrumbs } from 'frappe-ui'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { ref, computed, reactive } from 'vue'
|
import { ref, computed, reactive } from 'vue'
|
||||||
|
|
||||||
const breadcrumbs = [{ label: __('Leads'), route: { name: 'Leads' } }]
|
const breadcrumbs = [{ label: __('Leads'), route: { name: 'Leads' } }]
|
||||||
@ -88,6 +88,7 @@ const { getOrganization } = organizationsStore()
|
|||||||
const { getLeadStatus } = statusesStore()
|
const { getLeadStatus } = statusesStore()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const leadsListView = ref(null)
|
const leadsListView = ref(null)
|
||||||
const showLeadModal = ref(false)
|
const showLeadModal = ref(false)
|
||||||
@ -102,7 +103,7 @@ const viewControls = ref(null)
|
|||||||
// Rows
|
// Rows
|
||||||
const rows = computed(() => {
|
const rows = computed(() => {
|
||||||
if (!leads.value?.data?.data) return []
|
if (!leads.value?.data?.data) return []
|
||||||
return leads.value?.data.data.map((lead) => {
|
let listRows = leads.value?.data.data.map((lead) => {
|
||||||
let _rows = {}
|
let _rows = {}
|
||||||
leads.value?.data.rows.forEach((row) => {
|
leads.value?.data.rows.forEach((row) => {
|
||||||
_rows[row] = lead[row]
|
_rows[row] = lead[row]
|
||||||
@ -182,8 +183,33 @@ const rows = computed(() => {
|
|||||||
})
|
})
|
||||||
return _rows
|
return _rows
|
||||||
})
|
})
|
||||||
|
if (route.params.viewType === 'group_by') {
|
||||||
|
return getGroupedByRows(listRows)
|
||||||
|
}
|
||||||
|
return listRows
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function getGroupedByRows(listRows) {
|
||||||
|
let groupedRows = []
|
||||||
|
|
||||||
|
listRows.forEach((row) => {
|
||||||
|
if (!groupedRows.some((group) => group.group === row.status.label)) {
|
||||||
|
groupedRows.push({
|
||||||
|
group: row.status.label,
|
||||||
|
color: getLeadStatus(row.status.label)?.iconColorClass,
|
||||||
|
collapsed: false,
|
||||||
|
rows: [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
groupedRows.filter((group) => {
|
||||||
|
if (group.group === row.status.label) {
|
||||||
|
group.rows.push(row)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return groupedRows || listRows
|
||||||
|
}
|
||||||
|
|
||||||
let newLead = reactive({
|
let newLead = reactive({
|
||||||
salutation: '',
|
salutation: '',
|
||||||
first_name: '',
|
first_name: '',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user