mirror of
https://github.com/frappe/books.git
synced 2024-12-22 02:49:03 +00:00
feat: keyboard-friendly functionalities in POS
This commit is contained in:
parent
f4a3307767
commit
fcaa2927f3
@ -107,6 +107,7 @@ export default {
|
||||
return {
|
||||
showQuickView: false,
|
||||
linkValue: '',
|
||||
focInp: false,
|
||||
isLoading: false,
|
||||
suggestions: [],
|
||||
highlightedIndex: -1,
|
||||
@ -187,6 +188,15 @@ export default {
|
||||
const route = getFormRoute(this.linkSchemaName, name);
|
||||
await routeTo(route);
|
||||
},
|
||||
async focusInputTag() {
|
||||
this.focInp = true;
|
||||
if (this.linkValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$nextTick();
|
||||
this.$refs.input.focus();
|
||||
},
|
||||
setLinkValue(value) {
|
||||
this.linkValue = value;
|
||||
},
|
||||
@ -282,6 +292,14 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.target.value || this.focInp) {
|
||||
e.target.value = null;
|
||||
this.focInp = false;
|
||||
this.toggleDropdown(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleDropdown(true);
|
||||
this.updateSuggestions(e.target.value);
|
||||
},
|
||||
|
@ -21,6 +21,7 @@
|
||||
@blur="onBlur"
|
||||
@focus="(e) => !isReadOnly && $emit('focus', e)"
|
||||
@input="(e) => !isReadOnly && $emit('input', e)"
|
||||
@keydown.enter="setLoyaltyPoints"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -49,6 +50,7 @@ export default defineComponent({
|
||||
border: { type: Boolean, default: false },
|
||||
size: { type: String, default: 'large' },
|
||||
placeholder: String,
|
||||
focusInput: Boolean,
|
||||
showLabel: { type: Boolean, default: false },
|
||||
containerStyles: { type: Object, default: () => ({}) },
|
||||
textRight: {
|
||||
@ -64,6 +66,15 @@ export default defineComponent({
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
if (this.focusInput) {
|
||||
await this.$nextTick();
|
||||
(this.$refs.input as HTMLInputElement).focus();
|
||||
if (this.value == 0) {
|
||||
this.triggerChange('');
|
||||
}
|
||||
}
|
||||
},
|
||||
emits: ['focus', 'input', 'change'],
|
||||
computed: {
|
||||
doc(): Doc | undefined {
|
||||
@ -191,6 +202,12 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setLoyaltyPoints() {
|
||||
const inputElement = this.$refs.input as HTMLInputElement;
|
||||
if (inputElement && inputElement?.value) {
|
||||
this.$emit('change', inputElement.value);
|
||||
}
|
||||
},
|
||||
onBlur(e: FocusEvent) {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
@ -227,7 +244,7 @@ export default defineComponent({
|
||||
triggerChange(value: unknown): void {
|
||||
value = this.parse(value);
|
||||
|
||||
if (value === '') {
|
||||
if (value === '' || value == 0) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,14 @@ export default {
|
||||
this.setLinkValue();
|
||||
}
|
||||
},
|
||||
props: {
|
||||
focusInput: Boolean,
|
||||
},
|
||||
async created() {
|
||||
if (this.focusInput) {
|
||||
this.focusInputTag();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async setLinkValue(newValue, isInput) {
|
||||
if (isInput) {
|
||||
|
@ -63,6 +63,7 @@
|
||||
:show-label="true"
|
||||
:border="true"
|
||||
:value="couponCode"
|
||||
:focus-input="true"
|
||||
:df="coupons.fieldMap.coupons"
|
||||
@change="updateCouponCode"
|
||||
/>
|
||||
@ -161,15 +162,18 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateCouponCode(value: string) {
|
||||
(this.validationError = false), (this.couponCode = value);
|
||||
},
|
||||
async setCouponCode() {
|
||||
async updateCouponCode(value: string | Event) {
|
||||
try {
|
||||
if (!this.couponCode) {
|
||||
throw new Error(t`Must be select a coupon code`);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
this.validationError = false;
|
||||
|
||||
if ((value as Event).type === 'keydown') {
|
||||
value = ((value as Event).target as HTMLInputElement).value;
|
||||
}
|
||||
|
||||
this.couponCode = value as string;
|
||||
const appliedCouponCodes = this.fyo.doc.getNewDoc(
|
||||
ModelNameEnum.AppliedCouponCodes
|
||||
);
|
||||
@ -183,8 +187,6 @@ export default defineComponent({
|
||||
await this.sinvDoc.append('coupons', { coupons: this.couponCode });
|
||||
|
||||
this.$emit('applyPricingRule');
|
||||
this.$emit('toggleModal', 'CouponCode');
|
||||
|
||||
this.couponCode = '';
|
||||
this.validationError = false;
|
||||
} catch (error) {
|
||||
@ -195,6 +197,9 @@ export default defineComponent({
|
||||
message: t`${error as string}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
setCouponCode() {
|
||||
this.$emit('toggleModal', 'CouponCode');
|
||||
},
|
||||
async removeAppliedCoupon(coupon: AppliedCouponCodes) {
|
||||
this.sinvDoc?.items?.map((item: InvoiceItem) => {
|
||||
|
@ -20,13 +20,15 @@
|
||||
<p>{{ loyaltyPoints }}</p>
|
||||
</div>
|
||||
|
||||
<Data
|
||||
<Int
|
||||
v-if="sinvDoc.fieldMap"
|
||||
class="flex-shrink-0 px-10 pb-10"
|
||||
:show-label="true"
|
||||
:border="true"
|
||||
:focus-input="true"
|
||||
:value="sinvDoc.loyaltyPoints"
|
||||
:df="sinvDoc.fieldMap.loyaltyPoints"
|
||||
@keydown.enter="setLoyaltyPoints"
|
||||
@change="updateLoyaltyPoints"
|
||||
/>
|
||||
|
||||
@ -52,7 +54,7 @@
|
||||
<Button
|
||||
class="w-full bg-red-500 dark:bg-red-700"
|
||||
style="padding: 1.35rem"
|
||||
@click="$emit('toggleModal', 'LoyaltyProgram')"
|
||||
@click="cancelLoyaltyProgram"
|
||||
>
|
||||
<slot>
|
||||
<p class="uppercase text-lg text-white font-semibold">
|
||||
@ -67,20 +69,20 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Button from 'src/components/Button.vue';
|
||||
import Data from 'src/components/Controls/Data.vue';
|
||||
import Modal from 'src/components/Modal.vue';
|
||||
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import { t } from 'fyo';
|
||||
import { showToast } from 'src/utils/interactive';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import Int from 'src/components/Controls/Int.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LoyaltyProgramModal',
|
||||
components: {
|
||||
Modal,
|
||||
Button,
|
||||
Data,
|
||||
Int,
|
||||
},
|
||||
props: {
|
||||
loyaltyPoints: {
|
||||
@ -105,6 +107,14 @@ export default defineComponent({
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async keydownEnter(value: number) {
|
||||
await this.updateLoyaltyPoints(value);
|
||||
this.setLoyaltyPoints();
|
||||
},
|
||||
cancelLoyaltyProgram() {
|
||||
this.$emit('setLoyaltyPoints', 0);
|
||||
this.$emit('toggleModal', 'LoyaltyProgram');
|
||||
},
|
||||
async updateLoyaltyPoints(newValue: number) {
|
||||
try {
|
||||
const partyData = await this.fyo.db.get(
|
||||
@ -141,6 +151,12 @@ export default defineComponent({
|
||||
throw new Error(t`no need ${newValue} points to purchase this item`);
|
||||
}
|
||||
|
||||
if (newValue < 0) {
|
||||
throw new Error(t`Points must be greater than 0`);
|
||||
}
|
||||
|
||||
this.$emit('setLoyaltyPoints', this.sinvDoc.loyaltyPoints);
|
||||
|
||||
this.validationError = false;
|
||||
} catch (error) {
|
||||
this.validationError = true;
|
||||
@ -154,23 +170,7 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setLoyaltyPoints() {
|
||||
try {
|
||||
if (!this.sinvDoc.loyaltyPoints || this.sinvDoc.loyaltyPoints < 0) {
|
||||
throw new Error(t`Points must be greater than 0`);
|
||||
}
|
||||
|
||||
this.$emit('setLoyaltyPoints', this.sinvDoc.loyaltyPoints);
|
||||
this.$emit('toggleModal', 'LoyaltyProgram');
|
||||
|
||||
this.validationError = false;
|
||||
} catch (error) {
|
||||
this.validationError = true;
|
||||
|
||||
showToast({
|
||||
type: 'error',
|
||||
message: t`${error as string}`,
|
||||
});
|
||||
}
|
||||
this.$emit('toggleModal', 'LoyaltyProgram');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -276,6 +276,14 @@ export default defineComponent({
|
||||
this.loyaltyProgram = party[0]?.loyaltyProgram as string;
|
||||
this.loyaltyPoints = party[0]?.loyaltyPoints as number;
|
||||
},
|
||||
isModalOpen() {
|
||||
for (const modal of modalNames) {
|
||||
if (modal && this[`open${modal}Modal`]) {
|
||||
this[`open${modal}Modal`] = false;
|
||||
return `open${modal}Modal`;
|
||||
}
|
||||
}
|
||||
},
|
||||
setShortcuts() {
|
||||
this.shortcuts?.shift.set(COMPONENT_NAME, ['KeyS'], async () => {
|
||||
this.routeToSinvList();
|
||||
@ -294,16 +302,9 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
this.shortcuts?.pmodShift.set(COMPONENT_NAME, ['Backspace'], async () => {
|
||||
let anyModalClosed = false;
|
||||
const modalStatus = this.isModalOpen();
|
||||
|
||||
modalNames.forEach((modal: ModalName) => {
|
||||
if (modal && this[`open${modal}Modal`]) {
|
||||
this[`open${modal}Modal`] = false;
|
||||
anyModalClosed = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!anyModalClosed) {
|
||||
if (!modalStatus) {
|
||||
this.clearValues();
|
||||
}
|
||||
});
|
||||
@ -315,7 +316,9 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
this.shortcuts?.pmodShift.set(COMPONENT_NAME, ['KeyS'], async () => {
|
||||
if (this.sinvDoc.party && this.sinvDoc.items?.length) {
|
||||
const modalStatus = this.isModalOpen();
|
||||
|
||||
if (!modalStatus && this.sinvDoc.party && this.sinvDoc.items?.length) {
|
||||
this.saveOrder();
|
||||
}
|
||||
});
|
||||
|
@ -10,9 +10,10 @@
|
||||
v-if="sinvDoc.fieldMap"
|
||||
class="flex-shrink-0 w-full"
|
||||
:border="true"
|
||||
:value="priceList"
|
||||
:value="sinvDoc?.priceList"
|
||||
:focus-input="true"
|
||||
:df="sinvDoc.fieldMap.priceList"
|
||||
@change="(value) => (priceList = value)"
|
||||
@change="(value) => applyPriceList(value)"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-10 flex justify-end items-center">
|
||||
@ -46,7 +47,7 @@
|
||||
<Button
|
||||
class="w-full bg-red-500 dark:bg-red-700"
|
||||
style="padding: 1.35rem"
|
||||
@click="$emit('toggleModal', 'PriceList')"
|
||||
@click="cancelPriceList"
|
||||
>
|
||||
<slot>
|
||||
<p class="uppercase text-lg text-white font-semibold">
|
||||
@ -82,20 +83,17 @@ export default defineComponent({
|
||||
sinvDoc: inject('sinvDoc') as SalesInvoice,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
priceList: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async removePriceList() {
|
||||
this.priceList = '';
|
||||
await this.setPriceList();
|
||||
await this.sinvDoc.set('priceList', '');
|
||||
},
|
||||
async setPriceList() {
|
||||
async applyPriceList(value?: string) {
|
||||
try {
|
||||
await this.sinvDoc.set('priceList', this.priceList);
|
||||
if (!value || value == this.sinvDoc.priceList) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.sinvDoc.set('priceList', value);
|
||||
this.$emit('toggleModal', 'PriceList');
|
||||
} catch (error) {
|
||||
showToast({
|
||||
@ -104,6 +102,12 @@ export default defineComponent({
|
||||
});
|
||||
}
|
||||
},
|
||||
cancelPriceList() {
|
||||
this.$emit('toggleModal', 'PriceList');
|
||||
},
|
||||
async setPriceList() {
|
||||
this.$emit('toggleModal', 'PriceList');
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user