mirror of
https://github.com/frappe/books.git
synced 2024-11-08 14:50:56 +00:00
refactor: cleanup provide-injects
- type a bunch of form element .vue files
This commit is contained in:
parent
368714a84a
commit
b618340cec
@ -68,7 +68,7 @@ export interface Action {
|
||||
group?: string;
|
||||
type?: 'primary' | 'secondary';
|
||||
component?: {
|
||||
template?: string;
|
||||
template: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -96,9 +96,6 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
inject: {
|
||||
doc: { default: null },
|
||||
},
|
||||
mounted() {
|
||||
const value = this.linkValue || this.value;
|
||||
this.setLinkValue(this.getLinkValue(value));
|
||||
|
@ -14,10 +14,10 @@
|
||||
:placeholder="inputPlaceholder"
|
||||
:readonly="isReadOnly"
|
||||
:step="step"
|
||||
:max="df.maxvalue"
|
||||
:min="df.minvalue"
|
||||
:max="isNumeric(df) ? df.maxvalue : undefined"
|
||||
:min="isNumeric(df) ? df.minvalue : undefined"
|
||||
:style="containerStyles"
|
||||
@blur="(e) => !isReadOnly && triggerChange(e.target.value)"
|
||||
@blur="onBlur"
|
||||
@focus="(e) => !isReadOnly && $emit('focus', e)"
|
||||
@input="(e) => !isReadOnly && $emit('input', e)"
|
||||
:tabindex="isReadOnly ? '-1' : '0'"
|
||||
@ -25,61 +25,71 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Field } from 'schemas/types';
|
||||
import { isNumeric } from 'src/utils';
|
||||
import { evaluateReadOnly, evaluateRequired } from 'src/utils/doc';
|
||||
import { getIsNullOrUndef } from 'utils/index';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'Base',
|
||||
props: {
|
||||
df: Object,
|
||||
df: { type: Object as PropType<Field>, required: true },
|
||||
step: { type: Number, default: 1 },
|
||||
value: [String, Number, Boolean, Object],
|
||||
inputClass: [Function, String, Object],
|
||||
inputClass: [String, Array] as PropType<string | string[]>,
|
||||
border: { type: Boolean, default: false },
|
||||
size: { type: String, default: 'large' },
|
||||
placeholder: String,
|
||||
size: String,
|
||||
showLabel: Boolean,
|
||||
autofocus: Boolean,
|
||||
showLabel: { type: Boolean, default: false },
|
||||
containerStyles: { type: Object, default: () => ({}) },
|
||||
textRight: { type: [null, Boolean], default: null },
|
||||
readOnly: { type: [null, Boolean], default: null },
|
||||
required: { type: [null, Boolean], default: null },
|
||||
textRight: {
|
||||
type: [null, Boolean] as PropType<boolean | null>,
|
||||
default: null,
|
||||
},
|
||||
readOnly: {
|
||||
type: [null, Boolean] as PropType<boolean | null>,
|
||||
default: null,
|
||||
},
|
||||
required: {
|
||||
type: [null, Boolean] as PropType<boolean | null>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['focus', 'input', 'change'],
|
||||
inject: {
|
||||
schemaName: {
|
||||
default: null,
|
||||
injectedDoc: {
|
||||
from: 'doc',
|
||||
default: undefined,
|
||||
},
|
||||
name: {
|
||||
default: null,
|
||||
},
|
||||
doc: {
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.autofocus) {
|
||||
this.focus();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
inputType() {
|
||||
doc(): Doc | undefined {
|
||||
// @ts-ignore
|
||||
const doc = this.injectedDoc;
|
||||
|
||||
if (doc instanceof Doc) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
inputType(): string {
|
||||
return 'text';
|
||||
},
|
||||
labelClasses() {
|
||||
labelClasses(): string {
|
||||
return 'text-gray-600 text-sm mb-1';
|
||||
},
|
||||
inputClasses() {
|
||||
inputClasses(): string[] {
|
||||
/**
|
||||
* These classes will be used by components that extend Base
|
||||
*/
|
||||
|
||||
const classes = [];
|
||||
const classes: string[] = [];
|
||||
|
||||
classes.push(this.baseInputClasses);
|
||||
classes.push(...this.baseInputClasses);
|
||||
if (this.textRight ?? isNumeric(this.df)) {
|
||||
classes.push('text-end');
|
||||
}
|
||||
@ -89,7 +99,7 @@ export default {
|
||||
|
||||
return this.getInputClassesFromProp(classes).filter(Boolean);
|
||||
},
|
||||
baseInputClasses() {
|
||||
baseInputClasses(): string[] {
|
||||
return [
|
||||
'text-base',
|
||||
'focus:outline-none',
|
||||
@ -97,41 +107,41 @@ export default {
|
||||
'placeholder-gray-500',
|
||||
];
|
||||
},
|
||||
sizeClasses() {
|
||||
sizeClasses(): string {
|
||||
if (this.size === 'small') {
|
||||
return 'px-2 py-1';
|
||||
}
|
||||
return 'px-3 py-2';
|
||||
},
|
||||
inputReadOnlyClasses() {
|
||||
inputReadOnlyClasses(): string {
|
||||
if (this.isReadOnly) {
|
||||
return 'text-gray-800 cursor-default';
|
||||
}
|
||||
|
||||
return 'text-gray-900';
|
||||
},
|
||||
containerClasses() {
|
||||
containerClasses(): string[] {
|
||||
/**
|
||||
* Used to accomodate extending compoents where the input is contained in
|
||||
* a div eg AutoComplete
|
||||
*/
|
||||
const classes = [];
|
||||
classes.push(this.baseContainerClasses);
|
||||
const classes: string[] = [];
|
||||
classes.push(...this.baseContainerClasses);
|
||||
classes.push(this.containerReadOnlyClasses);
|
||||
classes.push(this.borderClasses);
|
||||
return classes.filter(Boolean);
|
||||
},
|
||||
baseContainerClasses() {
|
||||
baseContainerClasses(): string[] {
|
||||
return ['rounded'];
|
||||
},
|
||||
containerReadOnlyClasses() {
|
||||
containerReadOnlyClasses(): string {
|
||||
if (!this.isReadOnly) {
|
||||
return 'focus-within:bg-gray-100';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
borderClasses() {
|
||||
borderClasses(): string {
|
||||
if (!this.border) {
|
||||
return '';
|
||||
}
|
||||
@ -144,13 +154,13 @@ export default {
|
||||
|
||||
return border + ' ' + background;
|
||||
},
|
||||
inputPlaceholder() {
|
||||
inputPlaceholder(): string {
|
||||
return this.placeholder || this.df.placeholder || this.df.label;
|
||||
},
|
||||
showMandatory() {
|
||||
showMandatory(): boolean {
|
||||
return this.isEmpty && this.isRequired;
|
||||
},
|
||||
isEmpty() {
|
||||
isEmpty(): boolean {
|
||||
if (Array.isArray(this.value) && !this.value.length) {
|
||||
return true;
|
||||
}
|
||||
@ -165,14 +175,14 @@ export default {
|
||||
|
||||
return false;
|
||||
},
|
||||
isReadOnly() {
|
||||
isReadOnly(): boolean {
|
||||
if (typeof this.readOnly === 'boolean') {
|
||||
return this.readOnly;
|
||||
}
|
||||
|
||||
return evaluateReadOnly(this.df, this.doc);
|
||||
},
|
||||
isRequired() {
|
||||
isRequired(): boolean {
|
||||
if (typeof this.required === 'boolean') {
|
||||
return this.required;
|
||||
}
|
||||
@ -181,25 +191,40 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getInputClassesFromProp(classes) {
|
||||
onBlur(e: FocusEvent) {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.triggerChange(target.value);
|
||||
},
|
||||
getInputClassesFromProp(classes: string[]) {
|
||||
if (!this.inputClass) {
|
||||
return classes;
|
||||
}
|
||||
|
||||
if (typeof this.inputClass === 'function') {
|
||||
classes = this.inputClass(classes);
|
||||
} else {
|
||||
classes.push(this.inputClass);
|
||||
let inputClass = this.inputClass;
|
||||
if (typeof inputClass === 'string') {
|
||||
inputClass = [inputClass];
|
||||
}
|
||||
|
||||
return classes;
|
||||
inputClass = inputClass.filter((i) => typeof i === 'string');
|
||||
|
||||
return [classes, inputClass].flat();
|
||||
},
|
||||
focus() {
|
||||
if (this.$refs.input && this.$refs.input.focus) {
|
||||
this.$refs.input.focus();
|
||||
focus(): void {
|
||||
const el = this.$refs.input;
|
||||
|
||||
if (el instanceof HTMLInputElement) {
|
||||
el.focus();
|
||||
}
|
||||
},
|
||||
triggerChange(value) {
|
||||
triggerChange(value: unknown): void {
|
||||
value = this.parse(value);
|
||||
|
||||
if (value === '') {
|
||||
@ -208,10 +233,10 @@ export default {
|
||||
|
||||
this.$emit('change', value);
|
||||
},
|
||||
parse(value) {
|
||||
parse(value: unknown): unknown {
|
||||
return value;
|
||||
},
|
||||
isNumeric,
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
@ -12,7 +12,7 @@
|
||||
:class="isReadOnly ? 'cursor-default' : 'cursor-pointer'"
|
||||
>
|
||||
<svg
|
||||
v-if="checked"
|
||||
v-if="value"
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 14 14"
|
||||
@ -60,10 +60,10 @@
|
||||
<input
|
||||
ref="input"
|
||||
type="checkbox"
|
||||
:checked="value"
|
||||
:checked="getChecked(value)"
|
||||
:readonly="isReadOnly"
|
||||
:tabindex="isReadOnly ? '-1' : '0'"
|
||||
@change="(e) => !isReadOnly && triggerChange(e.target.checked)"
|
||||
@change="onChange"
|
||||
@focus="(e) => $emit('focus', e)"
|
||||
/>
|
||||
</div>
|
||||
@ -73,10 +73,11 @@
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Base from './Base';
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import Base from './Base.vue';
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'Check',
|
||||
extends: Base,
|
||||
emits: ['focus'],
|
||||
@ -106,11 +107,25 @@ export default {
|
||||
|
||||
return 'text-gray-600 text-base';
|
||||
},
|
||||
checked() {
|
||||
return this.value;
|
||||
},
|
||||
methods: {
|
||||
getChecked(value: unknown) {
|
||||
return Boolean(value);
|
||||
},
|
||||
onChange(e: Event) {
|
||||
if (this.isReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.triggerChange(target.checked);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -30,11 +30,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { isPesa } from 'fyo/utils';
|
||||
import { Money } from 'pesa';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { safeParseFloat } from 'utils/index';
|
||||
import { safeParsePesa } from 'utils/index';
|
||||
import { defineComponent, nextTick } from 'vue';
|
||||
import Float from './Float.vue';
|
||||
|
||||
@ -49,8 +48,13 @@ export default defineComponent({
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onFocus(e) {
|
||||
e.target.select();
|
||||
onFocus(e: FocusEvent) {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
target.select();
|
||||
this.showInput = true;
|
||||
this.$emit('focus', e);
|
||||
},
|
||||
@ -66,23 +70,7 @@ export default defineComponent({
|
||||
return fyo.pesa(0).round();
|
||||
},
|
||||
parse(value: unknown): Money {
|
||||
if (isPesa(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
value = safeParseFloat(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return fyo.pesa(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'bigint') {
|
||||
return fyo.pesa(value);
|
||||
}
|
||||
|
||||
return fyo.pesa(0);
|
||||
return safeParsePesa(value, this.fyo);
|
||||
},
|
||||
onBlur(e: FocusEvent) {
|
||||
const target = e.target;
|
||||
@ -106,7 +94,8 @@ export default defineComponent({
|
||||
},
|
||||
computed: {
|
||||
formattedValue() {
|
||||
return fyo.format(this.value ?? fyo.pesa(0), this.df, this.doc);
|
||||
const value = this.parse(this.value);
|
||||
return fyo.format(value, this.df, this.doc);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -4,19 +4,17 @@
|
||||
:value="value"
|
||||
@change="onChange"
|
||||
:border="true"
|
||||
:input-class="'rounded py-1.5'"
|
||||
input-class="rounded py-1.5"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { DEFAULT_LANGUAGE } from 'fyo/utils/consts';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { languageCodeMap, setLanguageMap } from 'src/utils/language';
|
||||
import { defineComponent } from 'vue';
|
||||
import FormControl from './FormControl.vue';
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
setLanguageMap,
|
||||
},
|
||||
export default defineComponent({
|
||||
props: {
|
||||
dontReload: {
|
||||
type: Boolean,
|
||||
@ -25,7 +23,11 @@ export default {
|
||||
},
|
||||
components: { FormControl },
|
||||
methods: {
|
||||
onChange(value) {
|
||||
onChange(value: unknown) {
|
||||
if (typeof value !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (languageCodeMap[value] === undefined) {
|
||||
return;
|
||||
}
|
||||
@ -48,5 +50,5 @@ export default {
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
@ -20,7 +20,7 @@
|
||||
'text-gray-500': !value,
|
||||
}"
|
||||
:value="value"
|
||||
@change="(e) => triggerChange(e.target.value)"
|
||||
@change="onChange"
|
||||
@focus="(e) => $emit('focus', e)"
|
||||
>
|
||||
<option
|
||||
@ -61,31 +61,33 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Base from './Base';
|
||||
<script lang="ts">
|
||||
import Base from './Base.vue';
|
||||
|
||||
export default {
|
||||
import { defineComponent } from 'vue';
|
||||
import { SelectOption } from 'schemas/types';
|
||||
export default defineComponent({
|
||||
name: 'Select',
|
||||
extends: Base,
|
||||
emits: ['focus'],
|
||||
methods: {
|
||||
map(v) {
|
||||
if (this.df.map) {
|
||||
return this.df.map[v] ?? v;
|
||||
onChange(e: Event) {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLInputElement)) {
|
||||
return;
|
||||
}
|
||||
return v;
|
||||
|
||||
this.triggerChange(target.value);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
let options = this.df.options;
|
||||
return options.map((o) => {
|
||||
if (typeof o === 'string') {
|
||||
return { label: this.map(o), value: o };
|
||||
options(): SelectOption[] {
|
||||
if (this.df.fieldtype !== 'Select') {
|
||||
return [];
|
||||
}
|
||||
return o;
|
||||
});
|
||||
|
||||
return this.df.options;
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
@ -116,9 +116,6 @@ export default {
|
||||
Row,
|
||||
TableRow,
|
||||
},
|
||||
inject: {
|
||||
doc: { default: null },
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.setMaxHeight();
|
||||
|
@ -60,7 +60,7 @@
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import Row from 'src/components/Row.vue';
|
||||
import { getErrorMessage } from 'src/utils';
|
||||
import { nextTick } from 'vue';
|
||||
import { computed, nextTick } from 'vue';
|
||||
import Button from '../Button.vue';
|
||||
import FormControl from './FormControl.vue';
|
||||
|
||||
@ -90,9 +90,7 @@ export default {
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: this.row.schemaName,
|
||||
name: this.row.name,
|
||||
doc: this.row,
|
||||
doc: computed(() => this.row),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -77,18 +77,10 @@
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Field } from 'schemas/types';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { DropdownItem } from 'src/utils/types';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import Popover from './Popover.vue';
|
||||
|
||||
type DropdownItem = {
|
||||
label: string;
|
||||
value?: string;
|
||||
action?: Function;
|
||||
group?: string;
|
||||
component?: { template: string };
|
||||
isGroup?: boolean;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Dropdown',
|
||||
props: {
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Dropdown
|
||||
v-if="actions && actions.length"
|
||||
class="text-xs"
|
||||
:items="actions"
|
||||
:items="items"
|
||||
:doc="doc"
|
||||
right
|
||||
>
|
||||
@ -16,23 +16,46 @@
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Button from 'src/components/Button';
|
||||
import Dropdown from 'src/components/Dropdown';
|
||||
<script lang="ts">
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Action } from 'fyo/model/types';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import Dropdown from 'src/components/Dropdown.vue';
|
||||
import { DropdownItem } from 'src/utils/types';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'DropdownWithActions',
|
||||
props: {
|
||||
actions: { default: [] },
|
||||
actions: { type: Array as PropType<Action[]>, default: () => [] },
|
||||
type: { type: String, default: 'secondary' },
|
||||
icon: { type: Boolean, default: true },
|
||||
},
|
||||
inject: {
|
||||
doc: { default: null },
|
||||
injectedDoc: { from: 'doc' },
|
||||
},
|
||||
components: {
|
||||
Dropdown,
|
||||
Button,
|
||||
},
|
||||
};
|
||||
computed: {
|
||||
doc() {
|
||||
// @ts-ignore
|
||||
const doc = this.injectedDoc;
|
||||
if (doc instanceof Doc) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
items(): DropdownItem[] {
|
||||
return this.actions.map(({ label, group, component, action }) => ({
|
||||
label,
|
||||
group,
|
||||
action,
|
||||
component,
|
||||
}));
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -81,13 +81,6 @@ export default {
|
||||
errors: {},
|
||||
};
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: this.doc.schemaName,
|
||||
name: this.doc.name,
|
||||
doc: this.doc,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
FormControl,
|
||||
Table,
|
||||
|
@ -163,8 +163,6 @@ export default defineComponent({
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: computed(() => this.docOrNull?.schemaName),
|
||||
name: computed(() => this.docOrNull?.name),
|
||||
doc: computed(() => this.docOrNull),
|
||||
};
|
||||
},
|
||||
|
@ -362,8 +362,6 @@ export default {
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: this.schemaName,
|
||||
name: this.name,
|
||||
doc: computed(() => this.doc),
|
||||
};
|
||||
},
|
||||
|
@ -166,8 +166,6 @@ export default {
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: this.schemaName,
|
||||
name: this.name,
|
||||
doc: computed(() => this.doc),
|
||||
};
|
||||
},
|
||||
|
@ -98,8 +98,6 @@ export default defineComponent({
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: computed(() => this.docOrNull?.schemaName),
|
||||
name: computed(() => this.docOrNull?.name),
|
||||
doc: computed(() => this.docOrNull),
|
||||
};
|
||||
},
|
||||
|
@ -9,8 +9,7 @@ import {
|
||||
DuplicateEntryError,
|
||||
LinkValidationError,
|
||||
} from 'fyo/utils/errors';
|
||||
import { Money } from 'pesa';
|
||||
import { Field, FieldType, FieldTypeEnum } from 'schemas/types';
|
||||
import { Field, FieldType, FieldTypeEnum, NumberField } from 'schemas/types';
|
||||
import { fyo } from 'src/initFyo';
|
||||
|
||||
export function stringifyCircular(
|
||||
@ -112,7 +111,13 @@ export function getErrorMessage(e: Error, doc?: Doc): string {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
export function isNumeric(fieldtype: Field | FieldType): boolean {
|
||||
export function isNumeric(
|
||||
fieldtype: FieldType
|
||||
): fieldtype is NumberField['fieldtype'];
|
||||
export function isNumeric(fieldtype: Field): fieldtype is NumberField;
|
||||
export function isNumeric(
|
||||
fieldtype: Field | FieldType
|
||||
): fieldtype is NumberField | NumberField['fieldtype'] {
|
||||
if (typeof fieldtype !== 'string') {
|
||||
fieldtype = fieldtype?.fieldtype;
|
||||
}
|
||||
|
@ -90,6 +90,15 @@ export type ActionGroup = {
|
||||
actions: Action[];
|
||||
};
|
||||
|
||||
export type DropdownItem = {
|
||||
label: string;
|
||||
value?: string;
|
||||
action?: Function;
|
||||
group?: string;
|
||||
component?: { template: string };
|
||||
isGroup?: boolean;
|
||||
};
|
||||
|
||||
export type UIGroupedFields = Map<string, Map<string, Field[]>>;
|
||||
export type ExportFormat = 'csv' | 'json';
|
||||
export type PeriodKey = 'This Year' | 'This Quarter' | 'This Month';
|
||||
|
@ -1,3 +1,6 @@
|
||||
import type { Fyo } from 'fyo';
|
||||
import { Money } from 'pesa';
|
||||
|
||||
/**
|
||||
* And so should not contain and platforma specific imports.
|
||||
*/
|
||||
@ -187,6 +190,30 @@ export function safeParseInt(value: unknown): number {
|
||||
return safeParseNumber(value, (v: string) => Math.trunc(Number(v)));
|
||||
}
|
||||
|
||||
export function safeParsePesa(value: unknown, fyo: Fyo): Money {
|
||||
if (value instanceof Money) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return fyo.pesa(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'bigint') {
|
||||
return fyo.pesa(value);
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return fyo.pesa(0);
|
||||
}
|
||||
|
||||
try {
|
||||
return fyo.pesa(value);
|
||||
} catch {
|
||||
return fyo.pesa(0);
|
||||
}
|
||||
}
|
||||
|
||||
export function joinMapLists<A, B>(
|
||||
listA: A[],
|
||||
listB: B[],
|
||||
|
Loading…
Reference in New Issue
Block a user