|
|
|
<script lang="ts" setup>
|
|
|
|
import type { VNodeRef } from '@vue/runtime-core'
|
|
|
|
import { UITypes } from 'nocodb-sdk'
|
|
|
|
import { computed, ref } from '#imports'
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
visible: boolean
|
|
|
|
}>()
|
|
|
|
|
|
|
|
const emit = defineEmits(['expand-record', 'new-record'])
|
|
|
|
|
|
|
|
const INFINITY_SCROLL_THRESHOLD = 100
|
|
|
|
|
|
|
|
const { appInfo } = useGlobal()
|
|
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
|
|
|
const {
|
|
|
|
pageDate,
|
|
|
|
displayField,
|
|
|
|
selectedDate,
|
|
|
|
calendarRange,
|
|
|
|
selectedDateRange,
|
|
|
|
activeDates,
|
|
|
|
activeCalendarView,
|
|
|
|
isSidebarLoading,
|
|
|
|
formattedSideBarData,
|
|
|
|
calDataType,
|
|
|
|
loadMoreSidebarData,
|
|
|
|
searchQuery,
|
|
|
|
sideBarFilterOption,
|
|
|
|
} = useCalendarViewStoreOrThrow()
|
|
|
|
|
|
|
|
const sideBarListRef = ref<VNodeRef | null>(null)
|
|
|
|
|
|
|
|
const options = computed(() => {
|
|
|
|
switch (activeCalendarView.value) {
|
|
|
|
case 'day' as const:
|
|
|
|
if (calDataType.value === UITypes.Date) {
|
|
|
|
return [
|
|
|
|
{ label: 'in this day', value: 'day' },
|
|
|
|
{ label: 'without dates', value: 'withoutDates' },
|
|
|
|
{ label: 'all records', value: 'allRecords' },
|
|
|
|
]
|
|
|
|
} else {
|
|
|
|
return [
|
|
|
|
{ label: 'in this day', value: 'day' },
|
|
|
|
{ label: 'without dates', value: 'withoutDates' },
|
|
|
|
{ label: 'all records', value: 'allRecords' },
|
|
|
|
{ label: 'in selected hours', value: 'selectedHours' },
|
|
|
|
{ label: 'in selected date', value: 'selectedDate' },
|
|
|
|
]
|
|
|
|
}
|
|
|
|
case 'week' as const:
|
|
|
|
return [
|
|
|
|
{ label: 'in this week', value: 'week' },
|
|
|
|
{ label: 'without dates', value: 'withoutDates' },
|
|
|
|
{ label: 'all records', value: 'allRecords' },
|
|
|
|
]
|
|
|
|
case 'month' as const:
|
|
|
|
return [
|
|
|
|
{ label: 'in this month', value: 'month' },
|
|
|
|
{ label: 'without dates', value: 'withoutDates' },
|
|
|
|
{ label: 'all records', value: 'allRecords' },
|
|
|
|
{ label: 'in selected date', value: 'selectedDate' },
|
|
|
|
]
|
|
|
|
case 'year' as const:
|
|
|
|
return [
|
|
|
|
{ label: 'in this year', value: 'year' },
|
|
|
|
{ label: 'without dates', value: 'withoutDates' },
|
|
|
|
{ label: 'all records', value: 'allRecords' },
|
|
|
|
{ label: 'in selected date', value: 'selectedDate' },
|
|
|
|
]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const sideBarListScrollHandle = useDebounceFn(async (e: Event) => {
|
|
|
|
const target = e.target as HTMLElement
|
|
|
|
if (target.clientHeight + target.scrollTop + INFINITY_SCROLL_THRESHOLD >= target.scrollHeight) {
|
|
|
|
const pageSize = appInfo.value?.defaultLimit ?? 25
|
|
|
|
const page = Math.floor(formattedSideBarData.value.length / pageSize)
|
|
|
|
await loadMoreSidebarData({
|
|
|
|
offset: page * pageSize,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<div
|
|
|
|
:class="{
|
|
|
|
'w-0': !props.visible,
|
|
|
|
'w-1/4 min-w-[22.1rem]': props.visible,
|
|
|
|
}"
|
|
|
|
class="h-full border-l-1 border-gray-200 transition-all"
|
|
|
|
>
|
|
|
|
<NcDateWeekSelector
|
|
|
|
v-if="activeCalendarView === ('day' as const)"
|
|
|
|
v-model:active-dates="activeDates"
|
|
|
|
v-model:page-date="pageDate"
|
|
|
|
v-model:selected-date="selectedDate"
|
|
|
|
/>
|
|
|
|
<NcDateWeekSelector
|
|
|
|
v-else-if="activeCalendarView === ('week' as const)"
|
|
|
|
v-model:active-dates="activeDates"
|
|
|
|
v-model:page-date="pageDate"
|
|
|
|
v-model:selected-week="selectedDateRange"
|
|
|
|
week-picker
|
|
|
|
/>
|
|
|
|
<NcMonthYearSelector
|
|
|
|
v-else-if="activeCalendarView === ('month' as const)"
|
|
|
|
v-model:page-date="pageDate"
|
|
|
|
v-model:selected-date="selectedDate"
|
|
|
|
/>
|
|
|
|
<NcMonthYearSelector
|
|
|
|
v-else-if="activeCalendarView === ('year' as const)"
|
|
|
|
v-model:page-date="pageDate"
|
|
|
|
v-model:selected-date="selectedDate"
|
|
|
|
year-picker
|
|
|
|
/>
|
|
|
|
|
|
|
|
<div class="px-4 flex flex-col gap-y-6 pt-4">
|
|
|
|
<div class="flex justify-between items-center">
|
|
|
|
<span class="text-2xl font-bold">{{ t('objects.Records') }}</span>
|
|
|
|
<NcSelect v-model:value="sideBarFilterOption" :options="options" />
|
|
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
<a-input
|
|
|
|
v-model:value="searchQuery.value"
|
|
|
|
class="!rounded-lg !border-gray-200 !px-4 !py-2"
|
|
|
|
placeholder="Search your records"
|
|
|
|
>
|
|
|
|
<template #prefix>
|
|
|
|
<component :is="iconMap.search" class="h-4 w-4 mr-1 text-gray-500" />
|
|
|
|
</template>
|
|
|
|
</a-input>
|
|
|
|
<NcButton type="secondary" @click="emit('new-record')">
|
|
|
|
<div class="px-4 flex items-center gap-2 justify-center">
|
|
|
|
<component :is="iconMap.plus" class="h-4 w-4 text-gray-700" />
|
|
|
|
{{ t('activity.newRecord') }}
|
|
|
|
</div>
|
|
|
|
</NcButton>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div
|
|
|
|
v-if="calendarRange"
|
|
|
|
:ref="sideBarListRef"
|
|
|
|
:class="{
|
|
|
|
'h-[calc(100vh-40rem)]': activeCalendarView === ('day' as const) || activeCalendarView === ('week' as const),
|
|
|
|
'h-[calc(100vh-29rem)]': activeCalendarView === ('month' as const) || activeCalendarView === ('year' as const),
|
|
|
|
}"
|
|
|
|
class="gap-2 flex flex-col nc-scrollbar-md overflow-y-auto nc-calendar-top-height"
|
|
|
|
@scroll="sideBarListScrollHandle"
|
|
|
|
>
|
|
|
|
<div v-if="formattedSideBarData.length === 0 || isSidebarLoading" class="flex h-full items-center justify-center">
|
|
|
|
<GeneralLoader v-if="isSidebarLoading" size="large" />
|
|
|
|
|
|
|
|
<div v-else class="text-gray-500">
|
|
|
|
{{ t('msg.noRecordsFound') }}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<template v-else-if="formattedSideBarData.length > 0">
|
|
|
|
<LazySmartsheetRow v-for="(record, rowIndex) in formattedSideBarData" :key="rowIndex" :row="record">
|
|
|
|
<LazySmartsheetCalendarSideRecordCard
|
|
|
|
:date="record.row[calendarRange[0] ? calendarRange[0].fk_from_col.title : '']"
|
|
|
|
:name="record.row[displayField.title]"
|
|
|
|
color="blue"
|
|
|
|
@click="emit('expand-record', record)"
|
|
|
|
/>
|
|
|
|
</LazySmartsheetRow>
|
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style lang="scss" scoped></style>
|