migrate transaction tag sheet to composition API and typescript

This commit is contained in:
MaysWind
2025-01-11 20:12:15 +08:00
parent ffae9e81a7
commit 6cb045453a
3 changed files with 119 additions and 124 deletions
@@ -5,17 +5,17 @@
<f7-toolbar> <f7-toolbar>
<div class="swipe-handler"></div> <div class="swipe-handler"></div>
<div class="left"> <div class="left">
<f7-link sheet-close :text="$t('Cancel')"></f7-link> <f7-link sheet-close :text="tt('Cancel')"></f7-link>
</div> </div>
<div class="right"> <div class="right">
<f7-link :text="$t('Done')" v-if="allTags && allTags.length && !noAvailableTag" @click="save"></f7-link> <f7-link :text="tt('Done')" v-if="allTags && allTags.length && !noAvailableTag" @click="save"></f7-link>
<f7-link :class="{'disabled': newTag}" <f7-link :class="{'disabled': newTag}"
:text="$t('Add')" v-if="!allTags || !allTags.length || noAvailableTag" @click="addNewTag"></f7-link> :text="tt('Add')" v-if="!allTags || !allTags.length || noAvailableTag" @click="addNewTag"></f7-link>
</div> </div>
</f7-toolbar> </f7-toolbar>
<f7-page-content> <f7-page-content>
<f7-list class="no-margin-top no-margin-bottom" v-if="(!allTags || !allTags.length || noAvailableTag) && !newTag"> <f7-list class="no-margin-top no-margin-bottom" v-if="(!allTags || !allTags.length || noAvailableTag) && !newTag">
<f7-list-item :title="$t('No available tag')"></f7-list-item> <f7-list-item :title="tt('No available tag')"></f7-list-item>
</f7-list> </f7-list>
<f7-list dividers class="no-margin-top no-margin-bottom tag-selection-list" v-else-if="(allTags && allTags.length && !noAvailableTag) || newTag"> <f7-list dividers class="no-margin-top no-margin-bottom tag-selection-list" v-else-if="(allTags && allTags.length && !noAvailableTag) || newTag">
<f7-list-item checkbox <f7-list-item checkbox
@@ -37,7 +37,7 @@
</f7-block> </f7-block>
</template> </template>
</f7-list-item> </f7-list-item>
<f7-list-item :title="$t('Add new tag')" <f7-list-item :title="tt('Add new tag')"
v-if="allowAddNewTag && !newTag" v-if="allowAddNewTag && !newTag"
@click="addNewTag()"> @click="addNewTag()">
</f7-list-item> </f7-list-item>
@@ -49,7 +49,7 @@
<div class="display-flex"> <div class="display-flex">
<f7-input class="list-title-input padding-left-half" <f7-input class="list-title-input padding-left-half"
type="text" type="text"
:placeholder="$t('Tag Title')" :placeholder="tt('Tag Title')"
v-model:value="newTag.name" v-model:value="newTag.name"
@keyup.enter="saveNewTag()"> @keyup.enter="saveNewTag()">
</f7-input> </f7-input>
@@ -75,131 +75,126 @@
</f7-sheet> </f7-sheet>
</template> </template>
<script> <script setup lang="ts">
import { mapStores } from 'pinia'; import { ref, computed } from 'vue';
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents, showLoading, hideLoading } from '@/lib/ui/mobile.ts';
import { TransactionTag } from '@/models/transaction_tag.ts'; import { TransactionTag } from '@/models/transaction_tag.ts';
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { copyArrayTo } from '@/lib/common.ts'; import { copyArrayTo } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.ts'; import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
export default { const props = defineProps<{
props: [ modelValue: string[];
'modelValue', allowAddNewTag?: boolean;
'allowAddNewTag', show: boolean;
'show' }>();
], const emit = defineEmits<{
emits: [ (e: 'update:modelValue', value: string[]): void;
'update:modelValue', (e: 'update:show', value: boolean): void;
'update:show' }>();
],
data() {
const self = this;
const transactionTagsStore = useTransactionTagsStore();
return { const { tt } = useI18n();
heightClass: self.getHeightClass(transactionTagsStore.allTransactionTags), const { showToast } = useI18nUIComponents();
selectedItemIds: copyArrayTo(self.modelValue, []),
newTag: null
}
},
computed: {
...mapStores(useTransactionTagsStore),
allTags() {
return this.transactionTagsStore.allTransactionTags;
},
noAvailableTag() {
for (let i = 0; i < this.allTags.length; i++) {
if (!this.allTags[i].hidden) {
return false;
}
}
return true; const transactionTagsStore = useTransactionTagsStore();
}
},
methods: {
save() {
this.$emit('update:modelValue', this.selectedItemIds);
this.$emit('update:show', false);
},
onSheetOpen(event) {
this.selectedItemIds = copyArrayTo(this.modelValue, []);
this.newTag = null;
scrollToSelectedItem(event.$el, '.page-content', 'li.list-item-selected');
},
onSheetClosed() {
this.$emit('update:show', false);
this.heightClass = this.getHeightClass(this.allTags);
},
changeTagSelection(e) {
const tagId = e.target.value;
if (e.target.checked) { const selectedItemIds = ref<string[]>(copyArrayTo(props.modelValue, []));
for (let i = 0; i < this.selectedItemIds.length; i++) { const newTag = ref<TransactionTag | null>(null);
if (this.selectedItemIds[i] === tagId) {
return;
}
}
this.selectedItemIds.push(tagId); const allTags = computed(() => transactionTagsStore.allTransactionTags);
} else {
for (let i = 0; i < this.selectedItemIds.length; i++) {
if (this.selectedItemIds[i] === tagId) {
this.selectedItemIds.splice(i, 1);
break;
}
}
}
},
addNewTag() {
this.newTag = TransactionTag.createNewTag();
},
saveNewTag() {
const self = this;
self.$showLoading(); const noAvailableTag = computed<boolean>(() => {
if (transactionTagsStore.allTransactionTags) {
self.transactionTagsStore.saveTag({ for (let i = 0; i < transactionTagsStore.allTransactionTags.length; i++) {
tag: self.newTag if (!transactionTagsStore.allTransactionTags[i].hidden) {
}).then(tag => { return false;
self.$hideLoading();
self.newTag = null;
if (tag && tag.id) {
self.selectedItemIds.push(tag.id);
}
}).catch(error => {
self.$hideLoading();
if (!error.processed) {
self.$toast(error.message || error);
}
});
},
cancelSaveNewTag() {
this.newTag = null;
},
isChecked(itemId) {
for (let i = 0; i < this.selectedItemIds.length; i++) {
if (this.selectedItemIds[i] === itemId) {
return true;
}
}
return false;
},
getHeightClass(allTags) {
if (allTags && allTags.length > 10) {
return 'tag-selection-huge-sheet';
} else if (allTags && allTags.length > 6) {
return 'tag-selection-large-sheet';
} else {
return '';
} }
} }
} }
return true;
});
const heightClass = computed<string>(() => {
if (transactionTagsStore.allTransactionTags && transactionTagsStore.allTransactionTags.length > 10) {
return 'tag-selection-huge-sheet';
} else if (transactionTagsStore.allTransactionTags && transactionTagsStore.allTransactionTags.length > 6) {
return 'tag-selection-large-sheet';
} else {
return '';
}
});
function isChecked(itemId: string): boolean {
return selectedItemIds.value.indexOf(itemId) >= 0;
}
function changeTagSelection(e: Event): void {
const target = e.target as HTMLInputElement;
const tagId = target.value;
const index = selectedItemIds.value.indexOf(tagId);
if (target.checked) {
if (index < 0) {
selectedItemIds.value.push(tagId);
}
} else {
if (index >= 0) {
selectedItemIds.value.splice(index, 1);
}
}
}
function save(): void {
emit('update:modelValue', selectedItemIds.value);
emit('update:show', false);
}
function addNewTag(): void {
newTag.value = TransactionTag.createNewTag();
}
function saveNewTag(): void {
if (!newTag.value) {
return;
}
showLoading();
transactionTagsStore.saveTag({
tag: newTag.value
}).then(tag => {
hideLoading();
newTag.value = null;
if (tag && tag.id) {
selectedItemIds.value.push(tag.id);
}
}).catch(error => {
hideLoading();
if (!error.processed) {
showToast(error.message || error);
}
});
}
function cancelSaveNewTag(): void {
newTag.value = null;
}
function onSheetOpen(event: { $el: Framework7Dom }): void {
selectedItemIds.value = copyArrayTo(props.modelValue, []);
newTag.value = null;
scrollToSelectedItem(event.$el, '.page-content', 'li.list-item-selected');
}
function onSheetClosed(): void {
emit('update:show', false);
} }
</script> </script>
+5 -5
View File
@@ -394,7 +394,7 @@ export function copyObjectTo(fromObject: Record<string, unknown> | undefined, to
return (toObject as Record<string, unknown>); return (toObject as Record<string, unknown>);
} }
export function copyArrayTo(fromArray: unknown[], toArray: unknown[]): unknown[] { export function copyArrayTo<T>(fromArray: T[], toArray: T[]): T[] {
if (!isArray(fromArray)) { if (!isArray(fromArray)) {
return toArray; return toArray;
} }
@@ -410,9 +410,9 @@ export function copyArrayTo(fromArray: unknown[], toArray: unknown[]): unknown[]
const toValue = toArray[i]; const toValue = toArray[i];
if (isArray(fromValue)) { if (isArray(fromValue)) {
toArray[i] = copyArrayTo(fromValue as unknown[], toValue as unknown[]); toArray[i] = copyArrayTo(fromValue as unknown[], toValue as unknown[]) as T;
} else if (isObject(fromValue)) { } else if (isObject(fromValue)) {
toArray[i] = copyObjectTo(fromValue as Record<string, unknown>, toValue as Record<string, unknown>); toArray[i] = copyObjectTo(fromValue as Record<string, unknown>, toValue as Record<string, unknown>) as T;
} else { } else {
if (fromValue !== toValue) { if (fromValue !== toValue) {
toArray[i] = fromValue; toArray[i] = fromValue;
@@ -420,9 +420,9 @@ export function copyArrayTo(fromArray: unknown[], toArray: unknown[]): unknown[]
} }
} else { } else {
if (isArray(fromValue)) { if (isArray(fromValue)) {
toArray.push(copyArrayTo(fromValue as unknown[], [])); toArray.push(copyArrayTo(fromValue as unknown[], []) as T);
} else if (isObject(fromValue)) { } else if (isObject(fromValue)) {
toArray.push(copyObjectTo(fromValue as Record<string, unknown>, {})); toArray.push(copyObjectTo(fromValue as Record<string, unknown>, {}) as T);
} else { } else {
toArray.push(fromValue); toArray.push(fromValue);
} }
+1 -1
View File
@@ -66,7 +66,7 @@ export function showToast(message: string, timeout: number | undefined, translat
}); });
} }
export function showLoading(delayConditionFunc: () => boolean, delayMills: number): void { export function showLoading(delayConditionFunc?: () => boolean, delayMills?: number): void {
if (!delayConditionFunc) { if (!delayConditionFunc) {
f7ready((f7) => { f7ready((f7) => {
return f7.preloader.show(); return f7.preloader.show();