diff --git a/src/components/base/TwoColumnListItemSelectionBase.ts b/src/components/base/TwoColumnListItemSelectionBase.ts index 8caa39d0..2da30ed2 100644 --- a/src/components/base/TwoColumnListItemSelectionBase.ts +++ b/src/components/base/TwoColumnListItemSelectionBase.ts @@ -1,134 +1,39 @@ -import { type Ref, ref, computed } from 'vue'; +import { type Ref } from 'vue'; -import { useI18n } from '@/locales/helpers.ts'; +import { + type TwoLevelItemSelectionBaseProps, + useTwoLevelItemSelectionBase +} from '@/components/base/TwoLevelItemSelectionBase.ts'; import { getItemByKeyValue, getPrimaryValueBySecondaryValue } from '@/lib/common.ts'; -export interface CommonTwoColumnListItemSelectionProps { - modelValue: unknown; - primaryKeyField?: string; +export interface CommonTwoColumnListItemSelectionProps extends TwoLevelItemSelectionBaseProps { primaryValueField?: string; - primaryTitleField?: string; - primaryTitleI18n?: boolean; primaryHeaderField?: string; primaryHeaderI18n?: boolean; primaryFooterField?: string; primaryFooterI18n?: boolean; - primaryIconField?: string; - primaryIconType?: string; - primaryColorField?: string; - primaryHiddenField?: string; - primarySubItemsField: string; - secondaryKeyField?: string; - secondaryValueField?: string; - secondaryTitleField?: string; - secondaryTitleI18n?: boolean; secondaryHeaderField?: string; secondaryHeaderI18n?: boolean; secondaryFooterField?: string; secondaryFooterI18n?: boolean; - secondaryIconField?: string; - secondaryIconType?: string; - secondaryColorField?: string; - secondaryHiddenField?: string; - enableFilter?: boolean; - filterPlaceholder?: string; - filterNoItemsText?: string; - items: Record[]; } export function useTwoColumnListItemSelectionBase(props: CommonTwoColumnListItemSelectionProps) { - const { ti } = useI18n(); - - const filterContent = ref(''); - - const filteredItems = computed[]>(() => { - const finalItems: Record[] = []; - const items = props.items; - - for (const item of items) { - if (props.primaryHiddenField && item[props.primaryHiddenField]) { - continue; - } - - if (!props.enableFilter || !filterContent.value) { - finalItems.push(item); - continue; - } - - if (props.primaryTitleField) { - const title = ti(item[props.primaryTitleField] as string, !!props.primaryTitleI18n); - - if (title.toLowerCase().indexOf(filterContent.value.toLowerCase()) >= 0) { - finalItems.push(item); - continue; - } - } - - if (props.primarySubItemsField) { - if (getFilteredSubItems(item).length > 0) { - finalItems.push(item); - } - } - } - - return finalItems; - }); - - function getFilteredSubItems(selectedPrimaryItem: unknown): Record[] { - const finalItems: Record[] = []; - - if (!selectedPrimaryItem || !props.primarySubItemsField) { - return finalItems; - } - - const subItems = (selectedPrimaryItem as Record)[props.primarySubItemsField] as Record[]; - let primaryTitleHasFilterContent = false; - - if (props.primaryTitleField) { - const title = ti((selectedPrimaryItem as Record)[props.primaryTitleField] as string, !!props.primaryTitleI18n); - primaryTitleHasFilterContent = title.toLowerCase().indexOf(filterContent.value.toLowerCase()) >= 0; - } - - for (const subItem of subItems) { - if (props.secondaryHiddenField && subItem[props.secondaryHiddenField]) { - continue; - } - - if (!props.enableFilter || !filterContent.value) { - finalItems.push(subItem); - continue; - } - - if (primaryTitleHasFilterContent) { - finalItems.push(subItem); - continue; - } - - if (props.secondaryTitleField && filterContent.value) { - const title = ti(subItem[props.secondaryTitleField] as string, !!props.secondaryTitleI18n); - - if (title.toLowerCase().indexOf(filterContent.value.toLowerCase()) >= 0) { - finalItems.push(subItem); - } - } - } - - return finalItems; - } + const { + filterContent, + visibleItemsCount, + filteredItems, + getFilteredSubItems, + isSecondaryValueSelected, + getSelectedSecondaryItem, + updateCurrentSecondaryValue + } = useTwoLevelItemSelectionBase(props); function getCurrentPrimaryValueBySecondaryValue(secondaryValue: unknown): unknown { return getPrimaryValueBySecondaryValue(props.items as Record[]>[], props.primarySubItemsField, props.primaryValueField, props.primaryHiddenField, props.secondaryValueField, props.secondaryHiddenField, secondaryValue); } - function isSecondaryValueSelected(currentSecondaryValue: unknown, subItem: unknown): boolean { - if (props.secondaryValueField) { - return currentSecondaryValue === (subItem as Record)[props.secondaryValueField]; - } else { - return currentSecondaryValue === subItem; - } - } - function getSelectedPrimaryItem(currentPrimaryValue: unknown): unknown { if (props.primaryValueField) { return getItemByKeyValue(props.items, currentPrimaryValue, props.primaryValueField); @@ -137,14 +42,6 @@ export function useTwoColumnListItemSelectionBase(props: CommonTwoColumnListItem } } - function getSelectedSecondaryItem(currentSecondaryValue: unknown, selectedPrimaryItem: unknown): unknown { - if (currentSecondaryValue && selectedPrimaryItem && (selectedPrimaryItem as Record)[props.primarySubItemsField]) { - return getItemByKeyValue((selectedPrimaryItem as Record)[props.primarySubItemsField] as Record[], currentSecondaryValue, props.secondaryValueField as string); - } else { - return null; - } - } - function updateCurrentPrimaryValue(currentPrimaryValue: Ref, item: unknown): void { if (props.primaryValueField) { currentPrimaryValue.value = (item as Record)[props.primaryValueField]; @@ -153,18 +50,11 @@ export function useTwoColumnListItemSelectionBase(props: CommonTwoColumnListItem } } - function updateCurrentSecondaryValue(currentSecondaryValue: Ref, subItem: unknown): void { - if (props.secondaryValueField) { - currentSecondaryValue.value = (subItem as Record)[props.secondaryValueField]; - } else { - currentSecondaryValue.value = subItem; - } - } - return { // states filterContent, // computed states + visibleItemsCount, filteredItems, // functions getFilteredSubItems, diff --git a/src/components/base/TwoLevelItemSelectionBase.ts b/src/components/base/TwoLevelItemSelectionBase.ts new file mode 100644 index 00000000..05c8bd75 --- /dev/null +++ b/src/components/base/TwoLevelItemSelectionBase.ts @@ -0,0 +1,162 @@ +import { type Ref, ref, computed } from 'vue'; + +import { useI18n } from '@/locales/helpers.ts'; + +import { getItemByKeyValue } from '@/lib/common.ts'; + +export interface TwoLevelItemSelectionBaseProps { + modelValue: unknown; + primaryKeyField?: string; + primaryTitleField?: string; + primaryTitleI18n?: boolean; + primaryIconField?: string; + primaryIconType?: string; + primaryColorField?: string; + primaryHiddenField?: string; + primarySubItemsField: string; + secondaryKeyField?: string; + secondaryValueField?: string; + secondaryTitleField?: string; + secondaryTitleI18n?: boolean; + secondaryIconField?: string; + secondaryIconType?: string; + secondaryColorField?: string; + secondaryHiddenField?: string; + enableFilter?: boolean; + filterPlaceholder?: string; + filterNoItemsText?: string; + items: Record[]; +} + +export function useTwoLevelItemSelectionBase(props: TwoLevelItemSelectionBaseProps) { + const { ti } = useI18n(); + + const filterContent = ref(''); + + const visibleItemsCount = computed(() => { + let count = 0; + + for (const item of props.items) { + if (props.primaryHiddenField && item[props.primaryHiddenField]) { + continue; + } + + count++; + } + + return count; + }); + + const filteredItems = computed[]>(() => { + const finalItems: Record[] = []; + const items = props.items; + const lowerCaseFilterContent = filterContent.value?.toLowerCase() ?? ''; + + for (const item of items) { + if (props.primaryHiddenField && item[props.primaryHiddenField]) { + continue; + } + + if (!props.enableFilter || !lowerCaseFilterContent) { + finalItems.push(item); + continue; + } + + if (props.primaryTitleField) { + const title = ti(item[props.primaryTitleField] as string, !!props.primaryTitleI18n); + + if (title.toLowerCase().indexOf(lowerCaseFilterContent) >= 0) { + finalItems.push(item); + continue; + } + } + + if (props.primarySubItemsField) { + if (getFilteredSubItems(item).length > 0) { + finalItems.push(item); + } + } + } + + return finalItems; + }); + + function getFilteredSubItems(selectedPrimaryItem: unknown): Record[] { + const finalItems: Record[] = []; + + if (!selectedPrimaryItem || !props.primarySubItemsField) { + return finalItems; + } + + const subItems = (selectedPrimaryItem as Record)[props.primarySubItemsField] as Record[]; + let primaryTitleHasFilterContent = false; + + if (props.primaryTitleField) { + const title = ti((selectedPrimaryItem as Record)[props.primaryTitleField] as string, !!props.primaryTitleI18n); + primaryTitleHasFilterContent = title.toLowerCase().indexOf(filterContent.value.toLowerCase()) >= 0; + } + + for (const subItem of subItems) { + if (props.secondaryHiddenField && subItem[props.secondaryHiddenField]) { + continue; + } + + if (!props.enableFilter || !filterContent.value) { + finalItems.push(subItem); + continue; + } + + if (primaryTitleHasFilterContent) { + finalItems.push(subItem); + continue; + } + + if (props.secondaryTitleField && filterContent.value) { + const title = ti(subItem[props.secondaryTitleField] as string, !!props.secondaryTitleI18n); + + if (title.toLowerCase().indexOf(filterContent.value.toLowerCase()) >= 0) { + finalItems.push(subItem); + } + } + } + + return finalItems; + } + + function isSecondaryValueSelected(currentSecondaryValue: unknown, subItem: unknown): boolean { + if (props.secondaryValueField) { + return currentSecondaryValue === (subItem as Record)[props.secondaryValueField]; + } else { + return currentSecondaryValue === subItem; + } + } + + function getSelectedSecondaryItem(currentSecondaryValue: unknown, selectedPrimaryItem: unknown): unknown { + if (currentSecondaryValue && selectedPrimaryItem && (selectedPrimaryItem as Record)[props.primarySubItemsField]) { + return getItemByKeyValue((selectedPrimaryItem as Record)[props.primarySubItemsField] as Record[], currentSecondaryValue, props.secondaryValueField as string); + } else { + return null; + } + } + + function updateCurrentSecondaryValue(currentSecondaryValue: Ref, subItem: unknown): void { + if (props.secondaryValueField) { + currentSecondaryValue.value = (subItem as Record)[props.secondaryValueField]; + } else { + currentSecondaryValue.value = subItem; + } + } + + return { + // states + filterContent, + // computed states + visibleItemsCount, + filteredItems, + // functions + getFilteredSubItems, + isSecondaryValueSelected, + getSelectedSecondaryItem, + updateCurrentSecondaryValue + }; +} diff --git a/src/components/mobile/TreeViewSelectionSheet.vue b/src/components/mobile/TreeViewSelectionSheet.vue index 0b19558e..bb5ed069 100644 --- a/src/components/mobile/TreeViewSelectionSheet.vue +++ b/src/components/mobile/TreeViewSelectionSheet.vue @@ -1,7 +1,6 @@